diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-01-31 18:39:07 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-01-31 18:39:07 -0500 |
commit | 8a1f006ad302ea178aefb1f8c67e679c696289e9 (patch) | |
tree | 8ba312b39070556d2062a9f90b1a7fa394041d78 /fs/nfs/inode.c | |
parent | 14864a52cd8189e8567df8351d9fc7e435133abd (diff) | |
parent | a1800acaf7d1c2bf6d68b9a8f4ab8560cc66555a (diff) |
Merge tag 'nfs-for-3.14-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client bugfixes from Trond Myklebust:
"Highlights:
- Fix several races in nfs_revalidate_mapping
- NFSv4.1 slot leakage in the pNFS files driver
- Stable fix for a slot leak in nfs40_sequence_done
- Don't reject NFSv4 servers that support ACLs with only ALLOW aces"
* tag 'nfs-for-3.14-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
nfs: initialize the ACL support bits to zero.
NFSv4.1: Cleanup
NFSv4.1: Clean up nfs41_sequence_done
NFSv4: Fix a slot leak in nfs40_sequence_done
NFSv4.1 free slot before resending I/O to MDS
nfs: add memory barriers around NFS_INO_INVALID_DATA and NFS_INO_INVALIDATING
NFS: Fix races in nfs_revalidate_mapping
sunrpc: turn warn_gssd() log message into a dprintk()
NFS: fix the handling of NFS_INO_INVALID_DATA flag in nfs_revalidate_mapping
nfs: handle servers that support only ALLOW ACE type.
Diffstat (limited to 'fs/nfs/inode.c')
-rw-r--r-- | fs/nfs/inode.c | 51 |
1 files changed, 43 insertions, 8 deletions
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index ea00b34ff071..28a0a3cbd3b7 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -977,11 +977,11 @@ static int nfs_invalidate_mapping(struct inode *inode, struct address_space *map | |||
977 | if (ret < 0) | 977 | if (ret < 0) |
978 | return ret; | 978 | return ret; |
979 | } | 979 | } |
980 | spin_lock(&inode->i_lock); | 980 | if (S_ISDIR(inode->i_mode)) { |
981 | nfsi->cache_validity &= ~NFS_INO_INVALID_DATA; | 981 | spin_lock(&inode->i_lock); |
982 | if (S_ISDIR(inode->i_mode)) | ||
983 | memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf)); | 982 | memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf)); |
984 | spin_unlock(&inode->i_lock); | 983 | spin_unlock(&inode->i_lock); |
984 | } | ||
985 | nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE); | 985 | nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE); |
986 | nfs_fscache_wait_on_invalidate(inode); | 986 | nfs_fscache_wait_on_invalidate(inode); |
987 | 987 | ||
@@ -1008,6 +1008,7 @@ static bool nfs_mapping_need_revalidate_inode(struct inode *inode) | |||
1008 | int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) | 1008 | int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) |
1009 | { | 1009 | { |
1010 | struct nfs_inode *nfsi = NFS_I(inode); | 1010 | struct nfs_inode *nfsi = NFS_I(inode); |
1011 | unsigned long *bitlock = &nfsi->flags; | ||
1011 | int ret = 0; | 1012 | int ret = 0; |
1012 | 1013 | ||
1013 | /* swapfiles are not supposed to be shared. */ | 1014 | /* swapfiles are not supposed to be shared. */ |
@@ -1019,12 +1020,46 @@ int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) | |||
1019 | if (ret < 0) | 1020 | if (ret < 0) |
1020 | goto out; | 1021 | goto out; |
1021 | } | 1022 | } |
1022 | if (nfsi->cache_validity & NFS_INO_INVALID_DATA) { | 1023 | |
1023 | trace_nfs_invalidate_mapping_enter(inode); | 1024 | /* |
1024 | ret = nfs_invalidate_mapping(inode, mapping); | 1025 | * We must clear NFS_INO_INVALID_DATA first to ensure that |
1025 | trace_nfs_invalidate_mapping_exit(inode, ret); | 1026 | * invalidations that come in while we're shooting down the mappings |
1027 | * are respected. But, that leaves a race window where one revalidator | ||
1028 | * can clear the flag, and then another checks it before the mapping | ||
1029 | * gets invalidated. Fix that by serializing access to this part of | ||
1030 | * the function. | ||
1031 | * | ||
1032 | * At the same time, we need to allow other tasks to see whether we | ||
1033 | * might be in the middle of invalidating the pages, so we only set | ||
1034 | * the bit lock here if it looks like we're going to be doing that. | ||
1035 | */ | ||
1036 | for (;;) { | ||
1037 | ret = wait_on_bit(bitlock, NFS_INO_INVALIDATING, | ||
1038 | nfs_wait_bit_killable, TASK_KILLABLE); | ||
1039 | if (ret) | ||
1040 | goto out; | ||
1041 | spin_lock(&inode->i_lock); | ||
1042 | if (test_bit(NFS_INO_INVALIDATING, bitlock)) { | ||
1043 | spin_unlock(&inode->i_lock); | ||
1044 | continue; | ||
1045 | } | ||
1046 | if (nfsi->cache_validity & NFS_INO_INVALID_DATA) | ||
1047 | break; | ||
1048 | spin_unlock(&inode->i_lock); | ||
1049 | goto out; | ||
1026 | } | 1050 | } |
1027 | 1051 | ||
1052 | set_bit(NFS_INO_INVALIDATING, bitlock); | ||
1053 | smp_wmb(); | ||
1054 | nfsi->cache_validity &= ~NFS_INO_INVALID_DATA; | ||
1055 | spin_unlock(&inode->i_lock); | ||
1056 | trace_nfs_invalidate_mapping_enter(inode); | ||
1057 | ret = nfs_invalidate_mapping(inode, mapping); | ||
1058 | trace_nfs_invalidate_mapping_exit(inode, ret); | ||
1059 | |||
1060 | clear_bit_unlock(NFS_INO_INVALIDATING, bitlock); | ||
1061 | smp_mb__after_clear_bit(); | ||
1062 | wake_up_bit(bitlock, NFS_INO_INVALIDATING); | ||
1028 | out: | 1063 | out: |
1029 | return ret; | 1064 | return ret; |
1030 | } | 1065 | } |