Commit 950ee956 authored by J. Bruce Fields's avatar J. Bruce Fields Committed by Al Viro

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: default avatarChristoph Hellwig <hch@lst.de>
Reported-by: default avatarTrevor Cordes <trevor@tecnopolis.ca>
Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent b7a6ec52
...@@ -215,7 +215,7 @@ struct getdents_callback { ...@@ -215,7 +215,7 @@ struct getdents_callback {
struct dir_context ctx; struct dir_context ctx;
char *name; /* name that was found. It already points to a char *name; /* name that was found. It already points to a
buffer NAME_MAX+1 is size */ buffer NAME_MAX+1 is size */
unsigned long ino; /* the inum we are looking for */ u64 ino; /* the inum we are looking for */
int found; /* inode matched? */ int found; /* inode matched? */
int sequence; /* sequence counter */ int sequence; /* sequence counter */
}; };
...@@ -255,10 +255,14 @@ static int get_name(const struct path *path, char *name, struct dentry *child) ...@@ -255,10 +255,14 @@ static int get_name(const struct path *path, char *name, struct dentry *child)
struct inode *dir = path->dentry->d_inode; struct inode *dir = path->dentry->d_inode;
int error; int error;
struct file *file; struct file *file;
struct kstat stat;
struct path child_path = {
.mnt = path->mnt,
.dentry = child,
};
struct getdents_callback buffer = { struct getdents_callback buffer = {
.ctx.actor = filldir_one, .ctx.actor = filldir_one,
.name = name, .name = name,
.ino = child->d_inode->i_ino
}; };
error = -ENOTDIR; error = -ENOTDIR;
...@@ -267,6 +271,16 @@ static int get_name(const struct path *path, char *name, struct dentry *child) ...@@ -267,6 +271,16 @@ static int get_name(const struct path *path, char *name, struct dentry *child)
error = -EINVAL; error = -EINVAL;
if (!dir->i_fop) if (!dir->i_fop)
goto out; goto out;
/*
* inode->i_ino is unsigned long, kstat->ino is u64, so the
* former would be insufficient on 32-bit hosts when the
* filesystem supports 64-bit inode numbers. So we need to
* actually call ->getattr, not just read i_ino:
*/
error = vfs_getattr_nosec(&child_path, &stat);
if (error)
return error;
buffer.ino = stat.ino;
/* /*
* Open the directory ... * Open the directory ...
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment