]>
Commit | Line | Data |
---|---|---|
677c3905 GKH |
1 | From 7dc72d5f7a0ec97a53e126c46e2cbd2560757955 Mon Sep 17 00:00:00 2001 |
2 | From: Trond Myklebust <trond.myklebust@primarydata.com> | |
3 | Date: Thu, 22 Sep 2016 13:38:52 -0400 | |
4 | Subject: NFS: Fix inode corruption in nfs_prime_dcache() | |
5 | ||
6 | From: Trond Myklebust <trond.myklebust@primarydata.com> | |
7 | ||
8 | commit 7dc72d5f7a0ec97a53e126c46e2cbd2560757955 upstream. | |
9 | ||
10 | Due to inode number reuse in filesystems, we can end up corrupting the | |
11 | inode on our client if we apply the file attributes without ensuring that | |
12 | the filehandle matches. | |
13 | Typical symptoms include spurious "mode changed" reports in the syslog. | |
14 | ||
15 | We still do want to ensure that we don't invalidate the dentry if the | |
16 | inode number matches, but we don't have a filehandle. | |
17 | ||
18 | Fixes: fa9233699cc1 ("NFS: Don't require a filehandle to refresh...") | |
19 | Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com> | |
20 | Tested-by: Oleg Drokin <green@linuxhacker.ru> | |
21 | Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com> | |
22 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
23 | ||
24 | --- | |
25 | fs/nfs/dir.c | 16 +++++++++++----- | |
26 | 1 file changed, 11 insertions(+), 5 deletions(-) | |
27 | ||
28 | --- a/fs/nfs/dir.c | |
29 | +++ b/fs/nfs/dir.c | |
30 | @@ -435,11 +435,11 @@ int nfs_same_file(struct dentry *dentry, | |
31 | return 0; | |
32 | ||
33 | nfsi = NFS_I(inode); | |
34 | - if (entry->fattr->fileid == nfsi->fileid) | |
35 | - return 1; | |
36 | - if (nfs_compare_fh(entry->fh, &nfsi->fh) == 0) | |
37 | - return 1; | |
38 | - return 0; | |
39 | + if (entry->fattr->fileid != nfsi->fileid) | |
40 | + return 0; | |
41 | + if (entry->fh->size && nfs_compare_fh(entry->fh, &nfsi->fh) != 0) | |
42 | + return 0; | |
43 | + return 1; | |
44 | } | |
45 | ||
46 | static | |
47 | @@ -517,6 +517,8 @@ again: | |
48 | &entry->fattr->fsid)) | |
49 | goto out; | |
50 | if (nfs_same_file(dentry, entry)) { | |
51 | + if (!entry->fh->size) | |
52 | + goto out; | |
53 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | |
54 | status = nfs_refresh_inode(d_inode(dentry), entry->fattr); | |
55 | if (!status) | |
56 | @@ -529,6 +531,10 @@ again: | |
57 | goto again; | |
58 | } | |
59 | } | |
60 | + if (!entry->fh->size) { | |
61 | + d_lookup_done(dentry); | |
62 | + goto out; | |
63 | + } | |
64 | ||
65 | inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr, entry->label); | |
66 | alias = d_splice_alias(inode, dentry); |