aboutsummaryrefslogtreecommitdiffstats
path: root/fs/exportfs/expfs.c
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2013-09-10 11:41:12 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2013-11-09 00:16:32 -0500
commit950ee9566a5b6cc45d15f5fe044bab4f1e8b62cb (patch)
tree423998e42ff71313d207f9a6f006d81498547280 /fs/exportfs/expfs.c
parentb7a6ec52dd4eced4a9bcda9ca85b3c8af84d3c90 (diff)
exportfs: fix 32-bit nfsd handling of 64-bit inode numbers
Symptoms were spurious -ENOENTs on stat of an NFS filesystem from a 32-bit NFS server exporting a very large XFS filesystem, when the server's cache is cold (so the inodes in question are not in cache). Reviewed-by: Christoph Hellwig <hch@lst.de> Reported-by: Trevor Cordes <trevor@tecnopolis.ca> Signed-off-by: J. Bruce Fields <bfields@redhat.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/exportfs/expfs.c')
-rw-r--r--fs/exportfs/expfs.c18
1 files changed, 16 insertions, 2 deletions
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
index a235f0016889..c43fe9b39ff2 100644
--- a/fs/exportfs/expfs.c
+++ b/fs/exportfs/expfs.c
@@ -215,7 +215,7 @@ struct getdents_callback {
215 struct dir_context ctx; 215 struct dir_context ctx;
216 char *name; /* name that was found. It already points to a 216 char *name; /* name that was found. It already points to a
217 buffer NAME_MAX+1 is size */ 217 buffer NAME_MAX+1 is size */
218 unsigned long ino; /* the inum we are looking for */ 218 u64 ino; /* the inum we are looking for */
219 int found; /* inode matched? */ 219 int found; /* inode matched? */
220 int sequence; /* sequence counter */ 220 int sequence; /* sequence counter */
221}; 221};
@@ -255,10 +255,14 @@ static int get_name(const struct path *path, char *name, struct dentry *child)
255 struct inode *dir = path->dentry->d_inode; 255 struct inode *dir = path->dentry->d_inode;
256 int error; 256 int error;
257 struct file *file; 257 struct file *file;
258 struct kstat stat;
259 struct path child_path = {
260 .mnt = path->mnt,
261 .dentry = child,
262 };
258 struct getdents_callback buffer = { 263 struct getdents_callback buffer = {
259 .ctx.actor = filldir_one, 264 .ctx.actor = filldir_one,
260 .name = name, 265 .name = name,
261 .ino = child->d_inode->i_ino
262 }; 266 };
263 267
264 error = -ENOTDIR; 268 error = -ENOTDIR;
@@ -268,6 +272,16 @@ static int get_name(const struct path *path, char *name, struct dentry *child)
268 if (!dir->i_fop) 272 if (!dir->i_fop)
269 goto out; 273 goto out;
270 /* 274 /*
275 * inode->i_ino is unsigned long, kstat->ino is u64, so the
276 * former would be insufficient on 32-bit hosts when the
277 * filesystem supports 64-bit inode numbers. So we need to
278 * actually call ->getattr, not just read i_ino:
279 */
280 error = vfs_getattr_nosec(&child_path, &stat);
281 if (error)
282 return error;
283 buffer.ino = stat.ino;
284 /*
271 * Open the directory ... 285 * Open the directory ...
272 */ 286 */
273 file = dentry_open(path, O_RDONLY, cred); 287 file = dentry_open(path, O_RDONLY, cred);