xref: /kernel/linux/linux-5.10/fs/ocfs2/export.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/* -*- mode: c; c-basic-offset: 8; -*-
38c2ecf20Sopenharmony_ci * vim: noexpandtab sw=8 ts=8 sts=0:
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * export.c
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Functions to facilitate NFS exporting
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Copyright (C) 2002, 2005 Oracle.  All rights reserved.
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/fs.h>
138c2ecf20Sopenharmony_ci#include <linux/types.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include <cluster/masklog.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include "ocfs2.h"
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include "alloc.h"
208c2ecf20Sopenharmony_ci#include "dir.h"
218c2ecf20Sopenharmony_ci#include "dlmglue.h"
228c2ecf20Sopenharmony_ci#include "dcache.h"
238c2ecf20Sopenharmony_ci#include "export.h"
248c2ecf20Sopenharmony_ci#include "inode.h"
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#include "buffer_head_io.h"
278c2ecf20Sopenharmony_ci#include "suballoc.h"
288c2ecf20Sopenharmony_ci#include "ocfs2_trace.h"
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistruct ocfs2_inode_handle
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	u64 ih_blkno;
338c2ecf20Sopenharmony_ci	u32 ih_generation;
348c2ecf20Sopenharmony_ci};
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic struct dentry *ocfs2_get_dentry(struct super_block *sb,
378c2ecf20Sopenharmony_ci		struct ocfs2_inode_handle *handle)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	struct inode *inode;
408c2ecf20Sopenharmony_ci	struct ocfs2_super *osb = OCFS2_SB(sb);
418c2ecf20Sopenharmony_ci	u64 blkno = handle->ih_blkno;
428c2ecf20Sopenharmony_ci	int status, set;
438c2ecf20Sopenharmony_ci	struct dentry *result;
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	trace_ocfs2_get_dentry_begin(sb, handle, (unsigned long long)blkno);
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	if (blkno == 0) {
488c2ecf20Sopenharmony_ci		result = ERR_PTR(-ESTALE);
498c2ecf20Sopenharmony_ci		goto bail;
508c2ecf20Sopenharmony_ci	}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	inode = ocfs2_ilookup(sb, blkno);
538c2ecf20Sopenharmony_ci	/*
548c2ecf20Sopenharmony_ci	 * If the inode exists in memory, we only need to check it's
558c2ecf20Sopenharmony_ci	 * generation number
568c2ecf20Sopenharmony_ci	 */
578c2ecf20Sopenharmony_ci	if (inode)
588c2ecf20Sopenharmony_ci		goto check_gen;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	/*
618c2ecf20Sopenharmony_ci	 * This will synchronize us against ocfs2_delete_inode() on
628c2ecf20Sopenharmony_ci	 * all nodes
638c2ecf20Sopenharmony_ci	 */
648c2ecf20Sopenharmony_ci	status = ocfs2_nfs_sync_lock(osb, 1);
658c2ecf20Sopenharmony_ci	if (status < 0) {
668c2ecf20Sopenharmony_ci		mlog(ML_ERROR, "getting nfs sync lock(EX) failed %d\n", status);
678c2ecf20Sopenharmony_ci		goto check_err;
688c2ecf20Sopenharmony_ci	}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	status = ocfs2_test_inode_bit(osb, blkno, &set);
718c2ecf20Sopenharmony_ci	if (status < 0) {
728c2ecf20Sopenharmony_ci		if (status == -EINVAL) {
738c2ecf20Sopenharmony_ci			/*
748c2ecf20Sopenharmony_ci			 * The blkno NFS gave us doesn't even show up
758c2ecf20Sopenharmony_ci			 * as an inode, we return -ESTALE to be
768c2ecf20Sopenharmony_ci			 * nice
778c2ecf20Sopenharmony_ci			 */
788c2ecf20Sopenharmony_ci			status = -ESTALE;
798c2ecf20Sopenharmony_ci		} else
808c2ecf20Sopenharmony_ci			mlog(ML_ERROR, "test inode bit failed %d\n", status);
818c2ecf20Sopenharmony_ci		goto unlock_nfs_sync;
828c2ecf20Sopenharmony_ci	}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	trace_ocfs2_get_dentry_test_bit(status, set);
858c2ecf20Sopenharmony_ci	/* If the inode allocator bit is clear, this inode must be stale */
868c2ecf20Sopenharmony_ci	if (!set) {
878c2ecf20Sopenharmony_ci		status = -ESTALE;
888c2ecf20Sopenharmony_ci		goto unlock_nfs_sync;
898c2ecf20Sopenharmony_ci	}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	inode = ocfs2_iget(osb, blkno, 0, 0);
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ciunlock_nfs_sync:
948c2ecf20Sopenharmony_ci	ocfs2_nfs_sync_unlock(osb, 1);
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cicheck_err:
978c2ecf20Sopenharmony_ci	if (status < 0) {
988c2ecf20Sopenharmony_ci		if (status == -ESTALE) {
998c2ecf20Sopenharmony_ci			trace_ocfs2_get_dentry_stale((unsigned long long)blkno,
1008c2ecf20Sopenharmony_ci						     handle->ih_generation);
1018c2ecf20Sopenharmony_ci		}
1028c2ecf20Sopenharmony_ci		result = ERR_PTR(status);
1038c2ecf20Sopenharmony_ci		goto bail;
1048c2ecf20Sopenharmony_ci	}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	if (IS_ERR(inode)) {
1078c2ecf20Sopenharmony_ci		mlog_errno(PTR_ERR(inode));
1088c2ecf20Sopenharmony_ci		result = ERR_CAST(inode);
1098c2ecf20Sopenharmony_ci		goto bail;
1108c2ecf20Sopenharmony_ci	}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cicheck_gen:
1138c2ecf20Sopenharmony_ci	if (handle->ih_generation != inode->i_generation) {
1148c2ecf20Sopenharmony_ci		trace_ocfs2_get_dentry_generation((unsigned long long)blkno,
1158c2ecf20Sopenharmony_ci						  handle->ih_generation,
1168c2ecf20Sopenharmony_ci						  inode->i_generation);
1178c2ecf20Sopenharmony_ci		iput(inode);
1188c2ecf20Sopenharmony_ci		result = ERR_PTR(-ESTALE);
1198c2ecf20Sopenharmony_ci		goto bail;
1208c2ecf20Sopenharmony_ci	}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	result = d_obtain_alias(inode);
1238c2ecf20Sopenharmony_ci	if (IS_ERR(result))
1248c2ecf20Sopenharmony_ci		mlog_errno(PTR_ERR(result));
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_cibail:
1278c2ecf20Sopenharmony_ci	trace_ocfs2_get_dentry_end(result);
1288c2ecf20Sopenharmony_ci	return result;
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_cistatic struct dentry *ocfs2_get_parent(struct dentry *child)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	int status;
1348c2ecf20Sopenharmony_ci	u64 blkno;
1358c2ecf20Sopenharmony_ci	struct dentry *parent;
1368c2ecf20Sopenharmony_ci	struct inode *dir = d_inode(child);
1378c2ecf20Sopenharmony_ci	int set;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	trace_ocfs2_get_parent(child, child->d_name.len, child->d_name.name,
1408c2ecf20Sopenharmony_ci			       (unsigned long long)OCFS2_I(dir)->ip_blkno);
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	status = ocfs2_nfs_sync_lock(OCFS2_SB(dir->i_sb), 1);
1438c2ecf20Sopenharmony_ci	if (status < 0) {
1448c2ecf20Sopenharmony_ci		mlog(ML_ERROR, "getting nfs sync lock(EX) failed %d\n", status);
1458c2ecf20Sopenharmony_ci		parent = ERR_PTR(status);
1468c2ecf20Sopenharmony_ci		goto bail;
1478c2ecf20Sopenharmony_ci	}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	status = ocfs2_inode_lock(dir, NULL, 0);
1508c2ecf20Sopenharmony_ci	if (status < 0) {
1518c2ecf20Sopenharmony_ci		if (status != -ENOENT)
1528c2ecf20Sopenharmony_ci			mlog_errno(status);
1538c2ecf20Sopenharmony_ci		parent = ERR_PTR(status);
1548c2ecf20Sopenharmony_ci		goto unlock_nfs_sync;
1558c2ecf20Sopenharmony_ci	}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	status = ocfs2_lookup_ino_from_name(dir, "..", 2, &blkno);
1588c2ecf20Sopenharmony_ci	if (status < 0) {
1598c2ecf20Sopenharmony_ci		parent = ERR_PTR(-ENOENT);
1608c2ecf20Sopenharmony_ci		goto bail_unlock;
1618c2ecf20Sopenharmony_ci	}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	status = ocfs2_test_inode_bit(OCFS2_SB(dir->i_sb), blkno, &set);
1648c2ecf20Sopenharmony_ci	if (status < 0) {
1658c2ecf20Sopenharmony_ci		if (status == -EINVAL) {
1668c2ecf20Sopenharmony_ci			status = -ESTALE;
1678c2ecf20Sopenharmony_ci		} else
1688c2ecf20Sopenharmony_ci			mlog(ML_ERROR, "test inode bit failed %d\n", status);
1698c2ecf20Sopenharmony_ci		parent = ERR_PTR(status);
1708c2ecf20Sopenharmony_ci		goto bail_unlock;
1718c2ecf20Sopenharmony_ci	}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	trace_ocfs2_get_dentry_test_bit(status, set);
1748c2ecf20Sopenharmony_ci	if (!set) {
1758c2ecf20Sopenharmony_ci		status = -ESTALE;
1768c2ecf20Sopenharmony_ci		parent = ERR_PTR(status);
1778c2ecf20Sopenharmony_ci		goto bail_unlock;
1788c2ecf20Sopenharmony_ci	}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	parent = d_obtain_alias(ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0, 0));
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_cibail_unlock:
1838c2ecf20Sopenharmony_ci	ocfs2_inode_unlock(dir, 0);
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ciunlock_nfs_sync:
1868c2ecf20Sopenharmony_ci	ocfs2_nfs_sync_unlock(OCFS2_SB(dir->i_sb), 1);
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_cibail:
1898c2ecf20Sopenharmony_ci	trace_ocfs2_get_parent_end(parent);
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	return parent;
1928c2ecf20Sopenharmony_ci}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_cistatic int ocfs2_encode_fh(struct inode *inode, u32 *fh_in, int *max_len,
1958c2ecf20Sopenharmony_ci			   struct inode *parent)
1968c2ecf20Sopenharmony_ci{
1978c2ecf20Sopenharmony_ci	int len = *max_len;
1988c2ecf20Sopenharmony_ci	int type = 1;
1998c2ecf20Sopenharmony_ci	u64 blkno;
2008c2ecf20Sopenharmony_ci	u32 generation;
2018c2ecf20Sopenharmony_ci	__le32 *fh = (__force __le32 *) fh_in;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci#ifdef TRACE_HOOKS_ARE_NOT_BRAINDEAD_IN_YOUR_OPINION
2048c2ecf20Sopenharmony_ci#error "You go ahead and fix that mess, then.  Somehow"
2058c2ecf20Sopenharmony_ci	trace_ocfs2_encode_fh_begin(dentry, dentry->d_name.len,
2068c2ecf20Sopenharmony_ci				    dentry->d_name.name,
2078c2ecf20Sopenharmony_ci				    fh, len, connectable);
2088c2ecf20Sopenharmony_ci#endif
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	if (parent && (len < 6)) {
2118c2ecf20Sopenharmony_ci		*max_len = 6;
2128c2ecf20Sopenharmony_ci		type = FILEID_INVALID;
2138c2ecf20Sopenharmony_ci		goto bail;
2148c2ecf20Sopenharmony_ci	} else if (len < 3) {
2158c2ecf20Sopenharmony_ci		*max_len = 3;
2168c2ecf20Sopenharmony_ci		type = FILEID_INVALID;
2178c2ecf20Sopenharmony_ci		goto bail;
2188c2ecf20Sopenharmony_ci	}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	blkno = OCFS2_I(inode)->ip_blkno;
2218c2ecf20Sopenharmony_ci	generation = inode->i_generation;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	trace_ocfs2_encode_fh_self((unsigned long long)blkno, generation);
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	len = 3;
2268c2ecf20Sopenharmony_ci	fh[0] = cpu_to_le32((u32)(blkno >> 32));
2278c2ecf20Sopenharmony_ci	fh[1] = cpu_to_le32((u32)(blkno & 0xffffffff));
2288c2ecf20Sopenharmony_ci	fh[2] = cpu_to_le32(generation);
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	if (parent) {
2318c2ecf20Sopenharmony_ci		blkno = OCFS2_I(parent)->ip_blkno;
2328c2ecf20Sopenharmony_ci		generation = parent->i_generation;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci		fh[3] = cpu_to_le32((u32)(blkno >> 32));
2358c2ecf20Sopenharmony_ci		fh[4] = cpu_to_le32((u32)(blkno & 0xffffffff));
2368c2ecf20Sopenharmony_ci		fh[5] = cpu_to_le32(generation);
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci		len = 6;
2398c2ecf20Sopenharmony_ci		type = 2;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci		trace_ocfs2_encode_fh_parent((unsigned long long)blkno,
2428c2ecf20Sopenharmony_ci					     generation);
2438c2ecf20Sopenharmony_ci	}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	*max_len = len;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_cibail:
2488c2ecf20Sopenharmony_ci	trace_ocfs2_encode_fh_type(type);
2498c2ecf20Sopenharmony_ci	return type;
2508c2ecf20Sopenharmony_ci}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_cistatic struct dentry *ocfs2_fh_to_dentry(struct super_block *sb,
2538c2ecf20Sopenharmony_ci		struct fid *fid, int fh_len, int fh_type)
2548c2ecf20Sopenharmony_ci{
2558c2ecf20Sopenharmony_ci	struct ocfs2_inode_handle handle;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	if (fh_len < 3 || fh_type > 2)
2588c2ecf20Sopenharmony_ci		return NULL;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	handle.ih_blkno = (u64)le32_to_cpu(fid->raw[0]) << 32;
2618c2ecf20Sopenharmony_ci	handle.ih_blkno |= (u64)le32_to_cpu(fid->raw[1]);
2628c2ecf20Sopenharmony_ci	handle.ih_generation = le32_to_cpu(fid->raw[2]);
2638c2ecf20Sopenharmony_ci	return ocfs2_get_dentry(sb, &handle);
2648c2ecf20Sopenharmony_ci}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_cistatic struct dentry *ocfs2_fh_to_parent(struct super_block *sb,
2678c2ecf20Sopenharmony_ci		struct fid *fid, int fh_len, int fh_type)
2688c2ecf20Sopenharmony_ci{
2698c2ecf20Sopenharmony_ci	struct ocfs2_inode_handle parent;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	if (fh_type != 2 || fh_len < 6)
2728c2ecf20Sopenharmony_ci		return NULL;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	parent.ih_blkno = (u64)le32_to_cpu(fid->raw[3]) << 32;
2758c2ecf20Sopenharmony_ci	parent.ih_blkno |= (u64)le32_to_cpu(fid->raw[4]);
2768c2ecf20Sopenharmony_ci	parent.ih_generation = le32_to_cpu(fid->raw[5]);
2778c2ecf20Sopenharmony_ci	return ocfs2_get_dentry(sb, &parent);
2788c2ecf20Sopenharmony_ci}
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ciconst struct export_operations ocfs2_export_ops = {
2818c2ecf20Sopenharmony_ci	.encode_fh	= ocfs2_encode_fh,
2828c2ecf20Sopenharmony_ci	.fh_to_dentry	= ocfs2_fh_to_dentry,
2838c2ecf20Sopenharmony_ci	.fh_to_parent	= ocfs2_fh_to_parent,
2848c2ecf20Sopenharmony_ci	.get_parent	= ocfs2_get_parent,
2858c2ecf20Sopenharmony_ci};
286