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