xref: /OK3568_Linux_fs/kernel/fs/xfs/xfs_export.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (c) 2004-2005 Silicon Graphics, Inc.
4*4882a593Smuzhiyun  * All Rights Reserved.
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun #include "xfs.h"
7*4882a593Smuzhiyun #include "xfs_shared.h"
8*4882a593Smuzhiyun #include "xfs_format.h"
9*4882a593Smuzhiyun #include "xfs_log_format.h"
10*4882a593Smuzhiyun #include "xfs_trans_resv.h"
11*4882a593Smuzhiyun #include "xfs_mount.h"
12*4882a593Smuzhiyun #include "xfs_dir2.h"
13*4882a593Smuzhiyun #include "xfs_export.h"
14*4882a593Smuzhiyun #include "xfs_inode.h"
15*4882a593Smuzhiyun #include "xfs_trans.h"
16*4882a593Smuzhiyun #include "xfs_inode_item.h"
17*4882a593Smuzhiyun #include "xfs_icache.h"
18*4882a593Smuzhiyun #include "xfs_pnfs.h"
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun /*
21*4882a593Smuzhiyun  * Note that we only accept fileids which are long enough rather than allow
22*4882a593Smuzhiyun  * the parent generation number to default to zero.  XFS considers zero a
23*4882a593Smuzhiyun  * valid generation number not an invalid/wildcard value.
24*4882a593Smuzhiyun  */
xfs_fileid_length(int fileid_type)25*4882a593Smuzhiyun static int xfs_fileid_length(int fileid_type)
26*4882a593Smuzhiyun {
27*4882a593Smuzhiyun 	switch (fileid_type) {
28*4882a593Smuzhiyun 	case FILEID_INO32_GEN:
29*4882a593Smuzhiyun 		return 2;
30*4882a593Smuzhiyun 	case FILEID_INO32_GEN_PARENT:
31*4882a593Smuzhiyun 		return 4;
32*4882a593Smuzhiyun 	case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG:
33*4882a593Smuzhiyun 		return 3;
34*4882a593Smuzhiyun 	case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
35*4882a593Smuzhiyun 		return 6;
36*4882a593Smuzhiyun 	}
37*4882a593Smuzhiyun 	return FILEID_INVALID;
38*4882a593Smuzhiyun }
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun STATIC int
xfs_fs_encode_fh(struct inode * inode,__u32 * fh,int * max_len,struct inode * parent)41*4882a593Smuzhiyun xfs_fs_encode_fh(
42*4882a593Smuzhiyun 	struct inode	*inode,
43*4882a593Smuzhiyun 	__u32		*fh,
44*4882a593Smuzhiyun 	int		*max_len,
45*4882a593Smuzhiyun 	struct inode	*parent)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun 	struct fid		*fid = (struct fid *)fh;
48*4882a593Smuzhiyun 	struct xfs_fid64	*fid64 = (struct xfs_fid64 *)fh;
49*4882a593Smuzhiyun 	int			fileid_type;
50*4882a593Smuzhiyun 	int			len;
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 	/* Directories don't need their parent encoded, they have ".." */
53*4882a593Smuzhiyun 	if (!parent)
54*4882a593Smuzhiyun 		fileid_type = FILEID_INO32_GEN;
55*4882a593Smuzhiyun 	else
56*4882a593Smuzhiyun 		fileid_type = FILEID_INO32_GEN_PARENT;
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	/*
59*4882a593Smuzhiyun 	 * If the filesystem may contain 64bit inode numbers, we need
60*4882a593Smuzhiyun 	 * to use larger file handles that can represent them.
61*4882a593Smuzhiyun 	 *
62*4882a593Smuzhiyun 	 * While we only allocate inodes that do not fit into 32 bits any
63*4882a593Smuzhiyun 	 * large enough filesystem may contain them, thus the slightly
64*4882a593Smuzhiyun 	 * confusing looking conditional below.
65*4882a593Smuzhiyun 	 */
66*4882a593Smuzhiyun 	if (!(XFS_M(inode->i_sb)->m_flags & XFS_MOUNT_SMALL_INUMS) ||
67*4882a593Smuzhiyun 	    (XFS_M(inode->i_sb)->m_flags & XFS_MOUNT_32BITINODES))
68*4882a593Smuzhiyun 		fileid_type |= XFS_FILEID_TYPE_64FLAG;
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	/*
71*4882a593Smuzhiyun 	 * Only encode if there is enough space given.  In practice
72*4882a593Smuzhiyun 	 * this means we can't export a filesystem with 64bit inodes
73*4882a593Smuzhiyun 	 * over NFSv2 with the subtree_check export option; the other
74*4882a593Smuzhiyun 	 * seven combinations work.  The real answer is "don't use v2".
75*4882a593Smuzhiyun 	 */
76*4882a593Smuzhiyun 	len = xfs_fileid_length(fileid_type);
77*4882a593Smuzhiyun 	if (*max_len < len) {
78*4882a593Smuzhiyun 		*max_len = len;
79*4882a593Smuzhiyun 		return FILEID_INVALID;
80*4882a593Smuzhiyun 	}
81*4882a593Smuzhiyun 	*max_len = len;
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 	switch (fileid_type) {
84*4882a593Smuzhiyun 	case FILEID_INO32_GEN_PARENT:
85*4882a593Smuzhiyun 		fid->i32.parent_ino = XFS_I(parent)->i_ino;
86*4882a593Smuzhiyun 		fid->i32.parent_gen = parent->i_generation;
87*4882a593Smuzhiyun 		/*FALLTHRU*/
88*4882a593Smuzhiyun 	case FILEID_INO32_GEN:
89*4882a593Smuzhiyun 		fid->i32.ino = XFS_I(inode)->i_ino;
90*4882a593Smuzhiyun 		fid->i32.gen = inode->i_generation;
91*4882a593Smuzhiyun 		break;
92*4882a593Smuzhiyun 	case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
93*4882a593Smuzhiyun 		fid64->parent_ino = XFS_I(parent)->i_ino;
94*4882a593Smuzhiyun 		fid64->parent_gen = parent->i_generation;
95*4882a593Smuzhiyun 		/*FALLTHRU*/
96*4882a593Smuzhiyun 	case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG:
97*4882a593Smuzhiyun 		fid64->ino = XFS_I(inode)->i_ino;
98*4882a593Smuzhiyun 		fid64->gen = inode->i_generation;
99*4882a593Smuzhiyun 		break;
100*4882a593Smuzhiyun 	}
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	return fileid_type;
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun STATIC struct inode *
xfs_nfs_get_inode(struct super_block * sb,u64 ino,u32 generation)106*4882a593Smuzhiyun xfs_nfs_get_inode(
107*4882a593Smuzhiyun 	struct super_block	*sb,
108*4882a593Smuzhiyun 	u64			ino,
109*4882a593Smuzhiyun 	u32			generation)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun  	xfs_mount_t		*mp = XFS_M(sb);
112*4882a593Smuzhiyun 	xfs_inode_t		*ip;
113*4882a593Smuzhiyun 	int			error;
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	/*
116*4882a593Smuzhiyun 	 * NFS can sometimes send requests for ino 0.  Fail them gracefully.
117*4882a593Smuzhiyun 	 */
118*4882a593Smuzhiyun 	if (ino == 0)
119*4882a593Smuzhiyun 		return ERR_PTR(-ESTALE);
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	/*
122*4882a593Smuzhiyun 	 * The XFS_IGET_UNTRUSTED means that an invalid inode number is just
123*4882a593Smuzhiyun 	 * fine and not an indication of a corrupted filesystem as clients can
124*4882a593Smuzhiyun 	 * send invalid file handles and we have to handle it gracefully..
125*4882a593Smuzhiyun 	 */
126*4882a593Smuzhiyun 	error = xfs_iget(mp, NULL, ino, XFS_IGET_UNTRUSTED, 0, &ip);
127*4882a593Smuzhiyun 	if (error) {
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 		/*
130*4882a593Smuzhiyun 		 * EINVAL means the inode cluster doesn't exist anymore.
131*4882a593Smuzhiyun 		 * EFSCORRUPTED means the metadata pointing to the inode cluster
132*4882a593Smuzhiyun 		 * or the inode cluster itself is corrupt.  This implies the
133*4882a593Smuzhiyun 		 * filehandle is stale, so we should translate it here.
134*4882a593Smuzhiyun 		 * We don't use ESTALE directly down the chain to not
135*4882a593Smuzhiyun 		 * confuse applications using bulkstat that expect EINVAL.
136*4882a593Smuzhiyun 		 */
137*4882a593Smuzhiyun 		switch (error) {
138*4882a593Smuzhiyun 		case -EINVAL:
139*4882a593Smuzhiyun 		case -ENOENT:
140*4882a593Smuzhiyun 		case -EFSCORRUPTED:
141*4882a593Smuzhiyun 			error = -ESTALE;
142*4882a593Smuzhiyun 			break;
143*4882a593Smuzhiyun 		default:
144*4882a593Smuzhiyun 			break;
145*4882a593Smuzhiyun 		}
146*4882a593Smuzhiyun 		return ERR_PTR(error);
147*4882a593Smuzhiyun 	}
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	if (VFS_I(ip)->i_generation != generation) {
150*4882a593Smuzhiyun 		xfs_irele(ip);
151*4882a593Smuzhiyun 		return ERR_PTR(-ESTALE);
152*4882a593Smuzhiyun 	}
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	return VFS_I(ip);
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun STATIC struct dentry *
xfs_fs_fh_to_dentry(struct super_block * sb,struct fid * fid,int fh_len,int fileid_type)158*4882a593Smuzhiyun xfs_fs_fh_to_dentry(struct super_block *sb, struct fid *fid,
159*4882a593Smuzhiyun 		 int fh_len, int fileid_type)
160*4882a593Smuzhiyun {
161*4882a593Smuzhiyun 	struct xfs_fid64	*fid64 = (struct xfs_fid64 *)fid;
162*4882a593Smuzhiyun 	struct inode		*inode = NULL;
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	if (fh_len < xfs_fileid_length(fileid_type))
165*4882a593Smuzhiyun 		return NULL;
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	switch (fileid_type) {
168*4882a593Smuzhiyun 	case FILEID_INO32_GEN_PARENT:
169*4882a593Smuzhiyun 	case FILEID_INO32_GEN:
170*4882a593Smuzhiyun 		inode = xfs_nfs_get_inode(sb, fid->i32.ino, fid->i32.gen);
171*4882a593Smuzhiyun 		break;
172*4882a593Smuzhiyun 	case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
173*4882a593Smuzhiyun 	case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG:
174*4882a593Smuzhiyun 		inode = xfs_nfs_get_inode(sb, fid64->ino, fid64->gen);
175*4882a593Smuzhiyun 		break;
176*4882a593Smuzhiyun 	}
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	return d_obtain_alias(inode);
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun STATIC struct dentry *
xfs_fs_fh_to_parent(struct super_block * sb,struct fid * fid,int fh_len,int fileid_type)182*4882a593Smuzhiyun xfs_fs_fh_to_parent(struct super_block *sb, struct fid *fid,
183*4882a593Smuzhiyun 		 int fh_len, int fileid_type)
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun 	struct xfs_fid64	*fid64 = (struct xfs_fid64 *)fid;
186*4882a593Smuzhiyun 	struct inode		*inode = NULL;
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	if (fh_len < xfs_fileid_length(fileid_type))
189*4882a593Smuzhiyun 		return NULL;
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	switch (fileid_type) {
192*4882a593Smuzhiyun 	case FILEID_INO32_GEN_PARENT:
193*4882a593Smuzhiyun 		inode = xfs_nfs_get_inode(sb, fid->i32.parent_ino,
194*4882a593Smuzhiyun 					      fid->i32.parent_gen);
195*4882a593Smuzhiyun 		break;
196*4882a593Smuzhiyun 	case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
197*4882a593Smuzhiyun 		inode = xfs_nfs_get_inode(sb, fid64->parent_ino,
198*4882a593Smuzhiyun 					      fid64->parent_gen);
199*4882a593Smuzhiyun 		break;
200*4882a593Smuzhiyun 	}
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	return d_obtain_alias(inode);
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun STATIC struct dentry *
xfs_fs_get_parent(struct dentry * child)206*4882a593Smuzhiyun xfs_fs_get_parent(
207*4882a593Smuzhiyun 	struct dentry		*child)
208*4882a593Smuzhiyun {
209*4882a593Smuzhiyun 	int			error;
210*4882a593Smuzhiyun 	struct xfs_inode	*cip;
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	error = xfs_lookup(XFS_I(d_inode(child)), &xfs_name_dotdot, &cip, NULL);
213*4882a593Smuzhiyun 	if (unlikely(error))
214*4882a593Smuzhiyun 		return ERR_PTR(error);
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	return d_obtain_alias(VFS_I(cip));
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun STATIC int
xfs_fs_nfs_commit_metadata(struct inode * inode)220*4882a593Smuzhiyun xfs_fs_nfs_commit_metadata(
221*4882a593Smuzhiyun 	struct inode		*inode)
222*4882a593Smuzhiyun {
223*4882a593Smuzhiyun 	return xfs_log_force_inode(XFS_I(inode));
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun const struct export_operations xfs_export_operations = {
227*4882a593Smuzhiyun 	.encode_fh		= xfs_fs_encode_fh,
228*4882a593Smuzhiyun 	.fh_to_dentry		= xfs_fs_fh_to_dentry,
229*4882a593Smuzhiyun 	.fh_to_parent		= xfs_fs_fh_to_parent,
230*4882a593Smuzhiyun 	.get_parent		= xfs_fs_get_parent,
231*4882a593Smuzhiyun 	.commit_metadata	= xfs_fs_nfs_commit_metadata,
232*4882a593Smuzhiyun #ifdef CONFIG_EXPORTFS_BLOCK_OPS
233*4882a593Smuzhiyun 	.get_uuid		= xfs_fs_get_uuid,
234*4882a593Smuzhiyun 	.map_blocks		= xfs_fs_map_blocks,
235*4882a593Smuzhiyun 	.commit_blocks		= xfs_fs_commit_blocks,
236*4882a593Smuzhiyun #endif
237*4882a593Smuzhiyun };
238