xref: /openbmc/linux/fs/ocfs2/export.c (revision fa60ce2c)
1328970deSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2*fa60ce2cSMasahiro Yamada /*
3ccd979bdSMark Fasheh  * export.c
4ccd979bdSMark Fasheh  *
5ccd979bdSMark Fasheh  * Functions to facilitate NFS exporting
6ccd979bdSMark Fasheh  *
7ccd979bdSMark Fasheh  * Copyright (C) 2002, 2005 Oracle.  All rights reserved.
8ccd979bdSMark Fasheh  */
9ccd979bdSMark Fasheh 
10ccd979bdSMark Fasheh #include <linux/fs.h>
11ccd979bdSMark Fasheh #include <linux/types.h>
12ccd979bdSMark Fasheh 
13ccd979bdSMark Fasheh #include <cluster/masklog.h>
14ccd979bdSMark Fasheh 
15ccd979bdSMark Fasheh #include "ocfs2.h"
16ccd979bdSMark Fasheh 
176ca497a8Swengang wang #include "alloc.h"
18ccd979bdSMark Fasheh #include "dir.h"
19ccd979bdSMark Fasheh #include "dlmglue.h"
20379dfe9dSMark Fasheh #include "dcache.h"
21ccd979bdSMark Fasheh #include "export.h"
22ccd979bdSMark Fasheh #include "inode.h"
23ccd979bdSMark Fasheh 
24ccd979bdSMark Fasheh #include "buffer_head_io.h"
256ca497a8Swengang wang #include "suballoc.h"
26781f200cSTao Ma #include "ocfs2_trace.h"
27ccd979bdSMark Fasheh 
28ccd979bdSMark Fasheh struct ocfs2_inode_handle
29ccd979bdSMark Fasheh {
30ccd979bdSMark Fasheh 	u64 ih_blkno;
31ccd979bdSMark Fasheh 	u32 ih_generation;
32ccd979bdSMark Fasheh };
33ccd979bdSMark Fasheh 
ocfs2_get_dentry(struct super_block * sb,struct ocfs2_inode_handle * handle)34644f9ab3SChristoph Hellwig static struct dentry *ocfs2_get_dentry(struct super_block *sb,
35644f9ab3SChristoph Hellwig 		struct ocfs2_inode_handle *handle)
36ccd979bdSMark Fasheh {
37ccd979bdSMark Fasheh 	struct inode *inode;
386ca497a8Swengang wang 	struct ocfs2_super *osb = OCFS2_SB(sb);
396ca497a8Swengang wang 	u64 blkno = handle->ih_blkno;
406ca497a8Swengang wang 	int status, set;
41ccd979bdSMark Fasheh 	struct dentry *result;
42ccd979bdSMark Fasheh 
43781f200cSTao Ma 	trace_ocfs2_get_dentry_begin(sb, handle, (unsigned long long)blkno);
44ccd979bdSMark Fasheh 
456ca497a8Swengang wang 	if (blkno == 0) {
466ca497a8Swengang wang 		result = ERR_PTR(-ESTALE);
476ca497a8Swengang wang 		goto bail;
48ccd979bdSMark Fasheh 	}
49ccd979bdSMark Fasheh 
506ca497a8Swengang wang 	inode = ocfs2_ilookup(sb, blkno);
516ca497a8Swengang wang 	/*
526ca497a8Swengang wang 	 * If the inode exists in memory, we only need to check it's
536ca497a8Swengang wang 	 * generation number
546ca497a8Swengang wang 	 */
556ca497a8Swengang wang 	if (inode)
566ca497a8Swengang wang 		goto check_gen;
57ccd979bdSMark Fasheh 
586ca497a8Swengang wang 	/*
596ca497a8Swengang wang 	 * This will synchronize us against ocfs2_delete_inode() on
606ca497a8Swengang wang 	 * all nodes
616ca497a8Swengang wang 	 */
626ca497a8Swengang wang 	status = ocfs2_nfs_sync_lock(osb, 1);
636ca497a8Swengang wang 	if (status < 0) {
646ca497a8Swengang wang 		mlog(ML_ERROR, "getting nfs sync lock(EX) failed %d\n", status);
656ca497a8Swengang wang 		goto check_err;
666ca497a8Swengang wang 	}
67ccd979bdSMark Fasheh 
686ca497a8Swengang wang 	status = ocfs2_test_inode_bit(osb, blkno, &set);
696ca497a8Swengang wang 	if (status < 0) {
706ca497a8Swengang wang 		if (status == -EINVAL) {
716ca497a8Swengang wang 			/*
726ca497a8Swengang wang 			 * The blkno NFS gave us doesn't even show up
736ca497a8Swengang wang 			 * as an inode, we return -ESTALE to be
746ca497a8Swengang wang 			 * nice
756ca497a8Swengang wang 			 */
766ca497a8Swengang wang 			status = -ESTALE;
77781f200cSTao Ma 		} else
786ca497a8Swengang wang 			mlog(ML_ERROR, "test inode bit failed %d\n", status);
796ca497a8Swengang wang 		goto unlock_nfs_sync;
806ca497a8Swengang wang 	}
816ca497a8Swengang wang 
82023d4ea3SJoseph Qi 	trace_ocfs2_get_dentry_test_bit(status, set);
836ca497a8Swengang wang 	/* If the inode allocator bit is clear, this inode must be stale */
846ca497a8Swengang wang 	if (!set) {
856ca497a8Swengang wang 		status = -ESTALE;
866ca497a8Swengang wang 		goto unlock_nfs_sync;
876ca497a8Swengang wang 	}
886ca497a8Swengang wang 
896ca497a8Swengang wang 	inode = ocfs2_iget(osb, blkno, 0, 0);
906ca497a8Swengang wang 
916ca497a8Swengang wang unlock_nfs_sync:
926ca497a8Swengang wang 	ocfs2_nfs_sync_unlock(osb, 1);
936ca497a8Swengang wang 
946ca497a8Swengang wang check_err:
956ca497a8Swengang wang 	if (status < 0) {
966ca497a8Swengang wang 		if (status == -ESTALE) {
97781f200cSTao Ma 			trace_ocfs2_get_dentry_stale((unsigned long long)blkno,
98781f200cSTao Ma 						     handle->ih_generation);
996ca497a8Swengang wang 		}
1006ca497a8Swengang wang 		result = ERR_PTR(status);
1016ca497a8Swengang wang 		goto bail;
1026ca497a8Swengang wang 	}
1036ca497a8Swengang wang 
1046ca497a8Swengang wang 	if (IS_ERR(inode)) {
1056ca497a8Swengang wang 		mlog_errno(PTR_ERR(inode));
1067585d12fSKees Cook 		result = ERR_CAST(inode);
1076ca497a8Swengang wang 		goto bail;
1086ca497a8Swengang wang 	}
1096ca497a8Swengang wang 
1106ca497a8Swengang wang check_gen:
111ccd979bdSMark Fasheh 	if (handle->ih_generation != inode->i_generation) {
112781f200cSTao Ma 		trace_ocfs2_get_dentry_generation((unsigned long long)blkno,
113781f200cSTao Ma 						  handle->ih_generation,
114781f200cSTao Ma 						  inode->i_generation);
115164f7e58SPan Bian 		iput(inode);
1166ca497a8Swengang wang 		result = ERR_PTR(-ESTALE);
1176ca497a8Swengang wang 		goto bail;
118ccd979bdSMark Fasheh 	}
119ccd979bdSMark Fasheh 
12044003728SChristoph Hellwig 	result = d_obtain_alias(inode);
121ba87167cSAl Viro 	if (IS_ERR(result))
1226ca497a8Swengang wang 		mlog_errno(PTR_ERR(result));
123ccd979bdSMark Fasheh 
1246ca497a8Swengang wang bail:
125781f200cSTao Ma 	trace_ocfs2_get_dentry_end(result);
126ccd979bdSMark Fasheh 	return result;
127ccd979bdSMark Fasheh }
128ccd979bdSMark Fasheh 
ocfs2_get_parent(struct dentry * child)129ccd979bdSMark Fasheh static struct dentry *ocfs2_get_parent(struct dentry *child)
130ccd979bdSMark Fasheh {
131ccd979bdSMark Fasheh 	int status;
132ccd979bdSMark Fasheh 	u64 blkno;
133ccd979bdSMark Fasheh 	struct dentry *parent;
1342b0143b5SDavid Howells 	struct inode *dir = d_inode(child);
135e091eab0SShuning Zhang 	int set;
136ccd979bdSMark Fasheh 
137781f200cSTao Ma 	trace_ocfs2_get_parent(child, child->d_name.len, child->d_name.name,
138b0697053SMark Fasheh 			       (unsigned long long)OCFS2_I(dir)->ip_blkno);
139ccd979bdSMark Fasheh 
140e091eab0SShuning Zhang 	status = ocfs2_nfs_sync_lock(OCFS2_SB(dir->i_sb), 1);
141e091eab0SShuning Zhang 	if (status < 0) {
142e091eab0SShuning Zhang 		mlog(ML_ERROR, "getting nfs sync lock(EX) failed %d\n", status);
143e091eab0SShuning Zhang 		parent = ERR_PTR(status);
144e091eab0SShuning Zhang 		goto bail;
145e091eab0SShuning Zhang 	}
146e091eab0SShuning Zhang 
147e63aecb6SMark Fasheh 	status = ocfs2_inode_lock(dir, NULL, 0);
148ccd979bdSMark Fasheh 	if (status < 0) {
149ccd979bdSMark Fasheh 		if (status != -ENOENT)
150ccd979bdSMark Fasheh 			mlog_errno(status);
151ccd979bdSMark Fasheh 		parent = ERR_PTR(status);
152e091eab0SShuning Zhang 		goto unlock_nfs_sync;
153ccd979bdSMark Fasheh 	}
154ccd979bdSMark Fasheh 
155be94d117SMark Fasheh 	status = ocfs2_lookup_ino_from_name(dir, "..", 2, &blkno);
156ccd979bdSMark Fasheh 	if (status < 0) {
157ccd979bdSMark Fasheh 		parent = ERR_PTR(-ENOENT);
158ccd979bdSMark Fasheh 		goto bail_unlock;
159ccd979bdSMark Fasheh 	}
160ccd979bdSMark Fasheh 
161e091eab0SShuning Zhang 	status = ocfs2_test_inode_bit(OCFS2_SB(dir->i_sb), blkno, &set);
162e091eab0SShuning Zhang 	if (status < 0) {
163e091eab0SShuning Zhang 		if (status == -EINVAL) {
164e091eab0SShuning Zhang 			status = -ESTALE;
165e091eab0SShuning Zhang 		} else
166e091eab0SShuning Zhang 			mlog(ML_ERROR, "test inode bit failed %d\n", status);
167e091eab0SShuning Zhang 		parent = ERR_PTR(status);
168e091eab0SShuning Zhang 		goto bail_unlock;
169e091eab0SShuning Zhang 	}
170e091eab0SShuning Zhang 
171e091eab0SShuning Zhang 	trace_ocfs2_get_dentry_test_bit(status, set);
172e091eab0SShuning Zhang 	if (!set) {
173e091eab0SShuning Zhang 		status = -ESTALE;
174e091eab0SShuning Zhang 		parent = ERR_PTR(status);
175e091eab0SShuning Zhang 		goto bail_unlock;
176e091eab0SShuning Zhang 	}
177e091eab0SShuning Zhang 
17844003728SChristoph Hellwig 	parent = d_obtain_alias(ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0, 0));
179379dfe9dSMark Fasheh 
180ccd979bdSMark Fasheh bail_unlock:
181e63aecb6SMark Fasheh 	ocfs2_inode_unlock(dir, 0);
182ccd979bdSMark Fasheh 
183e091eab0SShuning Zhang unlock_nfs_sync:
184e091eab0SShuning Zhang 	ocfs2_nfs_sync_unlock(OCFS2_SB(dir->i_sb), 1);
185e091eab0SShuning Zhang 
186ccd979bdSMark Fasheh bail:
187781f200cSTao Ma 	trace_ocfs2_get_parent_end(parent);
188ccd979bdSMark Fasheh 
189ccd979bdSMark Fasheh 	return parent;
190ccd979bdSMark Fasheh }
191ccd979bdSMark Fasheh 
ocfs2_encode_fh(struct inode * inode,u32 * fh_in,int * max_len,struct inode * parent)192b0b0382bSAl Viro static int ocfs2_encode_fh(struct inode *inode, u32 *fh_in, int *max_len,
193b0b0382bSAl Viro 			   struct inode *parent)
194ccd979bdSMark Fasheh {
195ccd979bdSMark Fasheh 	int len = *max_len;
196ccd979bdSMark Fasheh 	int type = 1;
197ccd979bdSMark Fasheh 	u64 blkno;
198ccd979bdSMark Fasheh 	u32 generation;
1991ca1a111SMark Fasheh 	__le32 *fh = (__force __le32 *) fh_in;
200ccd979bdSMark Fasheh 
201b0b0382bSAl Viro #ifdef TRACE_HOOKS_ARE_NOT_BRAINDEAD_IN_YOUR_OPINION
202b0b0382bSAl Viro #error "You go ahead and fix that mess, then.  Somehow"
203781f200cSTao Ma 	trace_ocfs2_encode_fh_begin(dentry, dentry->d_name.len,
204781f200cSTao Ma 				    dentry->d_name.name,
205ccd979bdSMark Fasheh 				    fh, len, connectable);
206b0b0382bSAl Viro #endif
207ccd979bdSMark Fasheh 
208b0b0382bSAl Viro 	if (parent && (len < 6)) {
2095fe0c237SAneesh Kumar K.V 		*max_len = 6;
21094e07a75SNamjae Jeon 		type = FILEID_INVALID;
2115fe0c237SAneesh Kumar K.V 		goto bail;
2125fe0c237SAneesh Kumar K.V 	} else if (len < 3) {
2135fe0c237SAneesh Kumar K.V 		*max_len = 3;
21494e07a75SNamjae Jeon 		type = FILEID_INVALID;
215ccd979bdSMark Fasheh 		goto bail;
216ccd979bdSMark Fasheh 	}
217ccd979bdSMark Fasheh 
218ccd979bdSMark Fasheh 	blkno = OCFS2_I(inode)->ip_blkno;
219ccd979bdSMark Fasheh 	generation = inode->i_generation;
220ccd979bdSMark Fasheh 
221781f200cSTao Ma 	trace_ocfs2_encode_fh_self((unsigned long long)blkno, generation);
222ccd979bdSMark Fasheh 
223ccd979bdSMark Fasheh 	len = 3;
224ccd979bdSMark Fasheh 	fh[0] = cpu_to_le32((u32)(blkno >> 32));
225ccd979bdSMark Fasheh 	fh[1] = cpu_to_le32((u32)(blkno & 0xffffffff));
226ccd979bdSMark Fasheh 	fh[2] = cpu_to_le32(generation);
227ccd979bdSMark Fasheh 
228b0b0382bSAl Viro 	if (parent) {
229ccd979bdSMark Fasheh 		blkno = OCFS2_I(parent)->ip_blkno;
230ccd979bdSMark Fasheh 		generation = parent->i_generation;
231ccd979bdSMark Fasheh 
232ccd979bdSMark Fasheh 		fh[3] = cpu_to_le32((u32)(blkno >> 32));
233ccd979bdSMark Fasheh 		fh[4] = cpu_to_le32((u32)(blkno & 0xffffffff));
234ccd979bdSMark Fasheh 		fh[5] = cpu_to_le32(generation);
235ccd979bdSMark Fasheh 
236ccd979bdSMark Fasheh 		len = 6;
237ccd979bdSMark Fasheh 		type = 2;
238ccd979bdSMark Fasheh 
239781f200cSTao Ma 		trace_ocfs2_encode_fh_parent((unsigned long long)blkno,
240781f200cSTao Ma 					     generation);
241ccd979bdSMark Fasheh 	}
242ccd979bdSMark Fasheh 
243ccd979bdSMark Fasheh 	*max_len = len;
244ccd979bdSMark Fasheh 
245ccd979bdSMark Fasheh bail:
246781f200cSTao Ma 	trace_ocfs2_encode_fh_type(type);
247ccd979bdSMark Fasheh 	return type;
248ccd979bdSMark Fasheh }
249ccd979bdSMark Fasheh 
ocfs2_fh_to_dentry(struct super_block * sb,struct fid * fid,int fh_len,int fh_type)250644f9ab3SChristoph Hellwig static struct dentry *ocfs2_fh_to_dentry(struct super_block *sb,
251644f9ab3SChristoph Hellwig 		struct fid *fid, int fh_len, int fh_type)
252ccd979bdSMark Fasheh {
253644f9ab3SChristoph Hellwig 	struct ocfs2_inode_handle handle;
254ccd979bdSMark Fasheh 
255644f9ab3SChristoph Hellwig 	if (fh_len < 3 || fh_type > 2)
256644f9ab3SChristoph Hellwig 		return NULL;
257ccd979bdSMark Fasheh 
258644f9ab3SChristoph Hellwig 	handle.ih_blkno = (u64)le32_to_cpu(fid->raw[0]) << 32;
259644f9ab3SChristoph Hellwig 	handle.ih_blkno |= (u64)le32_to_cpu(fid->raw[1]);
260644f9ab3SChristoph Hellwig 	handle.ih_generation = le32_to_cpu(fid->raw[2]);
261644f9ab3SChristoph Hellwig 	return ocfs2_get_dentry(sb, &handle);
262ccd979bdSMark Fasheh }
263ccd979bdSMark Fasheh 
ocfs2_fh_to_parent(struct super_block * sb,struct fid * fid,int fh_len,int fh_type)264644f9ab3SChristoph Hellwig static struct dentry *ocfs2_fh_to_parent(struct super_block *sb,
265644f9ab3SChristoph Hellwig 		struct fid *fid, int fh_len, int fh_type)
266644f9ab3SChristoph Hellwig {
267644f9ab3SChristoph Hellwig 	struct ocfs2_inode_handle parent;
268ccd979bdSMark Fasheh 
269644f9ab3SChristoph Hellwig 	if (fh_type != 2 || fh_len < 6)
270644f9ab3SChristoph Hellwig 		return NULL;
271ccd979bdSMark Fasheh 
272644f9ab3SChristoph Hellwig 	parent.ih_blkno = (u64)le32_to_cpu(fid->raw[3]) << 32;
273644f9ab3SChristoph Hellwig 	parent.ih_blkno |= (u64)le32_to_cpu(fid->raw[4]);
274644f9ab3SChristoph Hellwig 	parent.ih_generation = le32_to_cpu(fid->raw[5]);
275644f9ab3SChristoph Hellwig 	return ocfs2_get_dentry(sb, &parent);
276ccd979bdSMark Fasheh }
277ccd979bdSMark Fasheh 
27839655164SChristoph Hellwig const struct export_operations ocfs2_export_ops = {
279ccd979bdSMark Fasheh 	.encode_fh	= ocfs2_encode_fh,
280644f9ab3SChristoph Hellwig 	.fh_to_dentry	= ocfs2_fh_to_dentry,
281644f9ab3SChristoph Hellwig 	.fh_to_parent	= ocfs2_fh_to_parent,
282ccd979bdSMark Fasheh 	.get_parent	= ocfs2_get_parent,
283ccd979bdSMark Fasheh };
284