1193326Sed// SPDX-License-Identifier: GPL-2.0
2193326Sed/*
3193326Sed * Copyright (c) 2004-2005 Silicon Graphics, Inc.
4193326Sed * All Rights Reserved.
5193326Sed */
6193326Sed#include "xfs.h"
7193326Sed#include "xfs_shared.h"
8193326Sed#include "xfs_format.h"
9193326Sed#include "xfs_log_format.h"
10193326Sed#include "xfs_trans_resv.h"
11193326Sed#include "xfs_mount.h"
12193326Sed#include "xfs_dir2.h"
13193326Sed#include "xfs_export.h"
14221345Sdim#include "xfs_inode.h"
15193326Sed#include "xfs_trans.h"
16199482Srdivacky#include "xfs_inode_item.h"
17193326Sed#include "xfs_icache.h"
18193326Sed#include "xfs_pnfs.h"
19218893Sdim
20193326Sed/*
21193326Sed * Note that we only accept fileids which are long enough rather than allow
22193326Sed * the parent generation number to default to zero.  XFS considers zero a
23221345Sdim * valid generation number not an invalid/wildcard value.
24221345Sdim */
25193326Sedstatic int xfs_fileid_length(int fileid_type)
26193326Sed{
27207619Srdivacky	switch (fileid_type) {
28207619Srdivacky	case FILEID_INO32_GEN:
29193326Sed		return 2;
30207619Srdivacky	case FILEID_INO32_GEN_PARENT:
31193326Sed		return 4;
32218893Sdim	case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG:
33193326Sed		return 3;
34193326Sed	case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
35193326Sed		return 6;
36193326Sed	}
37193326Sed	return FILEID_INVALID;
38193326Sed}
39193326Sed
40193326SedSTATIC int
41193326Sedxfs_fs_encode_fh(
42210299Sed	struct inode	*inode,
43210299Sed	__u32		*fh,
44193326Sed	int		*max_len,
45193326Sed	struct inode	*parent)
46193326Sed{
47193326Sed	struct xfs_mount	*mp = XFS_M(inode->i_sb);
48193326Sed	struct fid		*fid = (struct fid *)fh;
49193326Sed	struct xfs_fid64	*fid64 = (struct xfs_fid64 *)fh;
50198398Srdivacky	int			fileid_type;
51198092Srdivacky	int			len;
52198092Srdivacky
53195341Sed	/* Directories don't need their parent encoded, they have ".." */
54199990Srdivacky	if (!parent)
55207619Srdivacky		fileid_type = FILEID_INO32_GEN;
56193326Sed	else
57193326Sed		fileid_type = FILEID_INO32_GEN_PARENT;
58193326Sed
59193326Sed	/*
60199482Srdivacky	 * If the filesystem may contain 64bit inode numbers, we need
61193326Sed	 * to use larger file handles that can represent them.
62218893Sdim	 *
63208600Srdivacky	 * While we only allocate inodes that do not fit into 32 bits any
64210299Sed	 * large enough filesystem may contain them, thus the slightly
65210299Sed	 * confusing looking conditional below.
66210299Sed	 */
67212904Sdim	if (!xfs_has_small_inums(mp) || xfs_is_inode32(mp))
68212904Sdim		fileid_type |= XFS_FILEID_TYPE_64FLAG;
69212904Sdim
70221345Sdim	/*
71221345Sdim	 * Only encode if there is enough space given.  In practice
72221345Sdim	 * this means we can't export a filesystem with 64bit inodes
73221345Sdim	 * over NFSv2 with the subtree_check export option; the other
74221345Sdim	 * seven combinations work.  The real answer is "don't use v2".
75221345Sdim	 */
76221345Sdim	len = xfs_fileid_length(fileid_type);
77193326Sed	if (*max_len < len) {
78193326Sed		*max_len = len;
79193326Sed		return FILEID_INVALID;
80193326Sed	}
81193326Sed	*max_len = len;
82193326Sed
83193326Sed	switch (fileid_type) {
84193326Sed	case FILEID_INO32_GEN_PARENT:
85193326Sed		fid->i32.parent_ino = XFS_I(parent)->i_ino;
86193326Sed		fid->i32.parent_gen = parent->i_generation;
87193326Sed		fallthrough;
88193326Sed	case FILEID_INO32_GEN:
89193326Sed		fid->i32.ino = XFS_I(inode)->i_ino;
90193326Sed		fid->i32.gen = inode->i_generation;
91193326Sed		break;
92193326Sed	case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
93193326Sed		fid64->parent_ino = XFS_I(parent)->i_ino;
94193326Sed		fid64->parent_gen = parent->i_generation;
95193326Sed		fallthrough;
96193326Sed	case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG:
97193326Sed		fid64->ino = XFS_I(inode)->i_ino;
98198398Srdivacky		fid64->gen = inode->i_generation;
99198398Srdivacky		break;
100198398Srdivacky	}
101198398Srdivacky
102198398Srdivacky	return fileid_type;
103198398Srdivacky}
104198398Srdivacky
105198398Srdivackystruct inode *
106198398Srdivackyxfs_nfs_get_inode(
107198398Srdivacky	struct super_block	*sb,
108198398Srdivacky	u64			ino,
109198398Srdivacky	u32			generation)
110198398Srdivacky{
111198398Srdivacky 	xfs_mount_t		*mp = XFS_M(sb);
112198398Srdivacky	xfs_inode_t		*ip;
113198398Srdivacky	int			error;
114218893Sdim
115198398Srdivacky	/*
116198398Srdivacky	 * NFS can sometimes send requests for ino 0.  Fail them gracefully.
117198398Srdivacky	 */
118198398Srdivacky	if (ino == 0)
119199482Srdivacky		return ERR_PTR(-ESTALE);
120198398Srdivacky
121199482Srdivacky	/*
122198398Srdivacky	 * The XFS_IGET_UNTRUSTED means that an invalid inode number is just
123199482Srdivacky	 * fine and not an indication of a corrupted filesystem as clients can
124198398Srdivacky	 * send invalid file handles and we have to handle it gracefully..
125199482Srdivacky	 */
126198398Srdivacky	error = xfs_iget(mp, NULL, ino, XFS_IGET_UNTRUSTED, 0, &ip);
127198398Srdivacky	if (error) {
128198398Srdivacky
129198398Srdivacky		/*
130218893Sdim		 * EINVAL means the inode cluster doesn't exist anymore.
131199482Srdivacky		 * EFSCORRUPTED means the metadata pointing to the inode cluster
132199482Srdivacky		 * or the inode cluster itself is corrupt.  This implies the
133199482Srdivacky		 * filehandle is stale, so we should translate it here.
134199482Srdivacky		 * We don't use ESTALE directly down the chain to not
135199482Srdivacky		 * confuse applications using bulkstat that expect EINVAL.
136199482Srdivacky		 */
137199482Srdivacky		switch (error) {
138199482Srdivacky		case -EINVAL:
139199482Srdivacky		case -ENOENT:
140199482Srdivacky		case -EFSCORRUPTED:
141199482Srdivacky			error = -ESTALE;
142199482Srdivacky			break;
143199482Srdivacky		default:
144199482Srdivacky			break;
145199482Srdivacky		}
146198893Srdivacky		return ERR_PTR(error);
147198398Srdivacky	}
148218893Sdim
149198398Srdivacky	/*
150198398Srdivacky	 * Reload the incore unlinked list to avoid failure in inodegc.
151198398Srdivacky	 * Use an unlocked check here because unrecovered unlinked inodes
152198398Srdivacky	 * should be somewhat rare.
153198398Srdivacky	 */
154218893Sdim	if (xfs_inode_unlinked_incomplete(ip)) {
155198398Srdivacky		error = xfs_inode_reload_unlinked(ip);
156198398Srdivacky		if (error) {
157198398Srdivacky			xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
158198398Srdivacky			xfs_irele(ip);
159218893Sdim			return ERR_PTR(error);
160198398Srdivacky		}
161198398Srdivacky	}
162198398Srdivacky
163198398Srdivacky	if (VFS_I(ip)->i_generation != generation || IS_PRIVATE(VFS_I(ip))) {
164199482Srdivacky		xfs_irele(ip);
165199482Srdivacky		return ERR_PTR(-ESTALE);
166199482Srdivacky	}
167199482Srdivacky
168207619Srdivacky	return VFS_I(ip);
169207619Srdivacky}
170207619Srdivacky
171199482SrdivackySTATIC struct dentry *
172199482Srdivackyxfs_fs_fh_to_dentry(struct super_block *sb, struct fid *fid,
173198398Srdivacky		 int fh_len, int fileid_type)
174193326Sed{
175193326Sed	struct xfs_fid64	*fid64 = (struct xfs_fid64 *)fid;
176193326Sed	struct inode		*inode = NULL;
177203955Srdivacky
178193326Sed	if (fh_len < xfs_fileid_length(fileid_type))
179203955Srdivacky		return NULL;
180218893Sdim
181203955Srdivacky	switch (fileid_type) {
182193326Sed	case FILEID_INO32_GEN_PARENT:
183193326Sed	case FILEID_INO32_GEN:
184193326Sed		inode = xfs_nfs_get_inode(sb, fid->i32.ino, fid->i32.gen);
185193326Sed		break;
186193326Sed	case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
187203955Srdivacky	case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG:
188203955Srdivacky		inode = xfs_nfs_get_inode(sb, fid64->ino, fid64->gen);
189203955Srdivacky		break;
190218893Sdim	}
191193326Sed
192193326Sed	return d_obtain_alias(inode);
193198092Srdivacky}
194193326Sed
195203955SrdivackySTATIC struct dentry *
196193326Sedxfs_fs_fh_to_parent(struct super_block *sb, struct fid *fid,
197203955Srdivacky		 int fh_len, int fileid_type)
198193326Sed{
199198092Srdivacky	struct xfs_fid64	*fid64 = (struct xfs_fid64 *)fid;
200193326Sed	struct inode		*inode = NULL;
201198092Srdivacky
202193326Sed	if (fh_len < xfs_fileid_length(fileid_type))
203193326Sed		return NULL;
204203955Srdivacky
205203955Srdivacky	switch (fileid_type) {
206193326Sed	case FILEID_INO32_GEN_PARENT:
207193326Sed		inode = xfs_nfs_get_inode(sb, fid->i32.parent_ino,
208193326Sed					      fid->i32.parent_gen);
209193326Sed		break;
210193326Sed	case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
211203955Srdivacky		inode = xfs_nfs_get_inode(sb, fid64->parent_ino,
212193326Sed					      fid64->parent_gen);
213193326Sed		break;
214198092Srdivacky	}
215193326Sed
216193326Sed	return d_obtain_alias(inode);
217193326Sed}
218198092Srdivacky
219193326SedSTATIC struct dentry *
220193326Sedxfs_fs_get_parent(
221193326Sed	struct dentry		*child)
222193326Sed{
223193326Sed	int			error;
224203955Srdivacky	struct xfs_inode	*cip;
225193326Sed
226193326Sed	error = xfs_lookup(XFS_I(d_inode(child)), &xfs_name_dotdot, &cip, NULL);
227193326Sed	if (unlikely(error))
228198092Srdivacky		return ERR_PTR(error);
229193326Sed
230193326Sed	return d_obtain_alias(VFS_I(cip));
231193326Sed}
232218893Sdim
233203955SrdivackySTATIC int
234193326Sedxfs_fs_nfs_commit_metadata(
235198092Srdivacky	struct inode		*inode)
236203955Srdivacky{
237203955Srdivacky	return xfs_log_force_inode(XFS_I(inode));
238198092Srdivacky}
239193326Sed
240193326Sedconst struct export_operations xfs_export_operations = {
241193326Sed	.encode_fh		= xfs_fs_encode_fh,
242193326Sed	.fh_to_dentry		= xfs_fs_fh_to_dentry,
243193326Sed	.fh_to_parent		= xfs_fs_fh_to_parent,
244193326Sed	.get_parent		= xfs_fs_get_parent,
245193326Sed	.commit_metadata	= xfs_fs_nfs_commit_metadata,
246203955Srdivacky#ifdef CONFIG_EXPORTFS_BLOCK_OPS
247203955Srdivacky	.get_uuid		= xfs_fs_get_uuid,
248198092Srdivacky	.map_blocks		= xfs_fs_map_blocks,
249193326Sed	.commit_blocks		= xfs_fs_commit_blocks,
250193326Sed#endif
251193326Sed};
252193326Sed