Commit 7dc72d5f authored by Trond Myklebust's avatar Trond Myklebust Committed by Anna Schumaker

NFS: Fix inode corruption in nfs_prime_dcache()

Due to inode number reuse in filesystems, we can end up corrupting the
inode on our client if we apply the file attributes without ensuring that
the filehandle matches.
Typical symptoms include spurious "mode changed" reports in the syslog.

We still do want to ensure that we don't invalidate the dentry if the
inode number matches, but we don't have a filehandle.

Fixes: fa923369 ("NFS: Don't require a filehandle to refresh...")
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@primarydata.com>
Cc: stable@vger.kernel.org # v4.0+
Tested-by: default avatarOleg Drokin <green@linuxhacker.ru>
Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
parent 0a014a44
...@@ -435,11 +435,11 @@ int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry) ...@@ -435,11 +435,11 @@ int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry)
return 0; return 0;
nfsi = NFS_I(inode); nfsi = NFS_I(inode);
if (entry->fattr->fileid == nfsi->fileid) if (entry->fattr->fileid != nfsi->fileid)
return 1; return 0;
if (nfs_compare_fh(entry->fh, &nfsi->fh) == 0) if (entry->fh->size && nfs_compare_fh(entry->fh, &nfsi->fh) != 0)
return 1; return 0;
return 0; return 1;
} }
static static
...@@ -525,6 +525,8 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) ...@@ -525,6 +525,8 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
&entry->fattr->fsid)) &entry->fattr->fsid))
goto out; goto out;
if (nfs_same_file(dentry, entry)) { if (nfs_same_file(dentry, entry)) {
if (!entry->fh->size)
goto out;
nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
status = nfs_refresh_inode(d_inode(dentry), entry->fattr); status = nfs_refresh_inode(d_inode(dentry), entry->fattr);
if (!status) if (!status)
...@@ -537,6 +539,10 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) ...@@ -537,6 +539,10 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
goto again; goto again;
} }
} }
if (!entry->fh->size) {
d_lookup_done(dentry);
goto out;
}
inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr, entry->label); inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr, entry->label);
alias = d_splice_alias(inode, dentry); alias = d_splice_alias(inode, dentry);
......
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