aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@primarydata.com>2016-09-22 13:38:52 -0400
committerAnna Schumaker <Anna.Schumaker@Netapp.com>2016-09-27 14:31:52 -0400
commit7dc72d5f7a0ec97a53e126c46e2cbd2560757955 (patch)
tree156b815db4fd3d78958bb3754a57855e02984c11 /fs/nfs
parent0a014a44a50839a8064618e959fae5bbc44c2fd5 (diff)
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: fa9233699cc1 ("NFS: Don't require a filehandle to refresh...") Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com> Cc: stable@vger.kernel.org # v4.0+ Tested-by: Oleg Drokin <green@linuxhacker.ru> Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/dir.c16
1 files changed, 11 insertions, 5 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index eb095f77c39d..2bade7909dec 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -435,11 +435,11 @@ int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry)
435 return 0; 435 return 0;
436 436
437 nfsi = NFS_I(inode); 437 nfsi = NFS_I(inode);
438 if (entry->fattr->fileid == nfsi->fileid) 438 if (entry->fattr->fileid != nfsi->fileid)
439 return 1; 439 return 0;
440 if (nfs_compare_fh(entry->fh, &nfsi->fh) == 0) 440 if (entry->fh->size && nfs_compare_fh(entry->fh, &nfsi->fh) != 0)
441 return 1; 441 return 0;
442 return 0; 442 return 1;
443} 443}
444 444
445static 445static
@@ -525,6 +525,8 @@ again:
525 &entry->fattr->fsid)) 525 &entry->fattr->fsid))
526 goto out; 526 goto out;
527 if (nfs_same_file(dentry, entry)) { 527 if (nfs_same_file(dentry, entry)) {
528 if (!entry->fh->size)
529 goto out;
528 nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); 530 nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
529 status = nfs_refresh_inode(d_inode(dentry), entry->fattr); 531 status = nfs_refresh_inode(d_inode(dentry), entry->fattr);
530 if (!status) 532 if (!status)
@@ -537,6 +539,10 @@ again:
537 goto again; 539 goto again;
538 } 540 }
539 } 541 }
542 if (!entry->fh->size) {
543 d_lookup_done(dentry);
544 goto out;
545 }
540 546
541 inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr, entry->label); 547 inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr, entry->label);
542 alias = d_splice_alias(inode, dentry); 548 alias = d_splice_alias(inode, dentry);