diff options
-rw-r--r-- | fs/nfs/dir.c | 3 | ||||
-rw-r--r-- | fs/nfs/inode.c | 42 | ||||
-rw-r--r-- | fs/nfs/nfstrace.h | 1 | ||||
-rw-r--r-- | fs/nfs/write.c | 6 | ||||
-rw-r--r-- | include/linux/nfs_fs.h | 1 |
5 files changed, 47 insertions, 6 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index b266f734bd53..b39a0468829b 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -288,7 +288,8 @@ int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_des | |||
288 | 288 | ||
289 | new_pos = desc->current_index + i; | 289 | new_pos = desc->current_index + i; |
290 | if (ctx->attr_gencount != nfsi->attr_gencount | 290 | if (ctx->attr_gencount != nfsi->attr_gencount |
291 | || (nfsi->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA))) { | 291 | || (nfsi->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA)) |
292 | || test_bit(NFS_INO_INVALIDATING, &nfsi->flags)) { | ||
292 | ctx->duped = 0; | 293 | ctx->duped = 0; |
293 | ctx->attr_gencount = nfsi->attr_gencount; | 294 | ctx->attr_gencount = nfsi->attr_gencount; |
294 | } else if (new_pos < desc->ctx->pos) { | 295 | } else if (new_pos < desc->ctx->pos) { |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index c63e15224466..0a972ee9ccc1 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,45 @@ 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 | } |
1023 | |||
1024 | /* | ||
1025 | * We must clear NFS_INO_INVALID_DATA first to ensure that | ||
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 | if (!(nfsi->cache_validity & NFS_INO_INVALID_DATA)) | ||
1042 | goto out; | ||
1043 | if (!test_and_set_bit_lock(NFS_INO_INVALIDATING, bitlock)) | ||
1044 | break; | ||
1045 | } | ||
1046 | |||
1047 | spin_lock(&inode->i_lock); | ||
1022 | if (nfsi->cache_validity & NFS_INO_INVALID_DATA) { | 1048 | if (nfsi->cache_validity & NFS_INO_INVALID_DATA) { |
1049 | nfsi->cache_validity &= ~NFS_INO_INVALID_DATA; | ||
1050 | spin_unlock(&inode->i_lock); | ||
1023 | trace_nfs_invalidate_mapping_enter(inode); | 1051 | trace_nfs_invalidate_mapping_enter(inode); |
1024 | ret = nfs_invalidate_mapping(inode, mapping); | 1052 | ret = nfs_invalidate_mapping(inode, mapping); |
1025 | trace_nfs_invalidate_mapping_exit(inode, ret); | 1053 | trace_nfs_invalidate_mapping_exit(inode, ret); |
1054 | } else { | ||
1055 | /* something raced in and cleared the flag */ | ||
1056 | spin_unlock(&inode->i_lock); | ||
1026 | } | 1057 | } |
1027 | 1058 | ||
1059 | clear_bit_unlock(NFS_INO_INVALIDATING, bitlock); | ||
1060 | smp_mb__after_clear_bit(); | ||
1061 | wake_up_bit(bitlock, NFS_INO_INVALIDATING); | ||
1028 | out: | 1062 | out: |
1029 | return ret; | 1063 | return ret; |
1030 | } | 1064 | } |
diff --git a/fs/nfs/nfstrace.h b/fs/nfs/nfstrace.h index 89fe741e58b1..59f838cdc009 100644 --- a/fs/nfs/nfstrace.h +++ b/fs/nfs/nfstrace.h | |||
@@ -36,6 +36,7 @@ | |||
36 | __print_flags(v, "|", \ | 36 | __print_flags(v, "|", \ |
37 | { 1 << NFS_INO_ADVISE_RDPLUS, "ADVISE_RDPLUS" }, \ | 37 | { 1 << NFS_INO_ADVISE_RDPLUS, "ADVISE_RDPLUS" }, \ |
38 | { 1 << NFS_INO_STALE, "STALE" }, \ | 38 | { 1 << NFS_INO_STALE, "STALE" }, \ |
39 | { 1 << NFS_INO_INVALIDATING, "INVALIDATING" }, \ | ||
39 | { 1 << NFS_INO_FLUSHING, "FLUSHING" }, \ | 40 | { 1 << NFS_INO_FLUSHING, "FLUSHING" }, \ |
40 | { 1 << NFS_INO_FSCACHE, "FSCACHE" }, \ | 41 | { 1 << NFS_INO_FSCACHE, "FSCACHE" }, \ |
41 | { 1 << NFS_INO_COMMIT, "COMMIT" }, \ | 42 | { 1 << NFS_INO_COMMIT, "COMMIT" }, \ |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index a44a87268a6e..5511a4247190 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -909,9 +909,13 @@ bool nfs_ctx_key_to_expire(struct nfs_open_context *ctx) | |||
909 | */ | 909 | */ |
910 | static bool nfs_write_pageuptodate(struct page *page, struct inode *inode) | 910 | static bool nfs_write_pageuptodate(struct page *page, struct inode *inode) |
911 | { | 911 | { |
912 | struct nfs_inode *nfsi = NFS_I(inode); | ||
913 | |||
912 | if (nfs_have_delegated_attributes(inode)) | 914 | if (nfs_have_delegated_attributes(inode)) |
913 | goto out; | 915 | goto out; |
914 | if (NFS_I(inode)->cache_validity & (NFS_INO_INVALID_DATA|NFS_INO_REVAL_PAGECACHE)) | 916 | if (nfsi->cache_validity & (NFS_INO_INVALID_DATA|NFS_INO_REVAL_PAGECACHE)) |
917 | return false; | ||
918 | if (test_bit(NFS_INO_INVALIDATING, &nfsi->flags)) | ||
915 | return false; | 919 | return false; |
916 | out: | 920 | out: |
917 | return PageUptodate(page) != 0; | 921 | return PageUptodate(page) != 0; |
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 48997374eaf0..18fb16f4b939 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h | |||
@@ -215,6 +215,7 @@ struct nfs_inode { | |||
215 | #define NFS_INO_ADVISE_RDPLUS (0) /* advise readdirplus */ | 215 | #define NFS_INO_ADVISE_RDPLUS (0) /* advise readdirplus */ |
216 | #define NFS_INO_STALE (1) /* possible stale inode */ | 216 | #define NFS_INO_STALE (1) /* possible stale inode */ |
217 | #define NFS_INO_ACL_LRU_SET (2) /* Inode is on the LRU list */ | 217 | #define NFS_INO_ACL_LRU_SET (2) /* Inode is on the LRU list */ |
218 | #define NFS_INO_INVALIDATING (3) /* inode is being invalidated */ | ||
218 | #define NFS_INO_FLUSHING (4) /* inode is flushing out data */ | 219 | #define NFS_INO_FLUSHING (4) /* inode is flushing out data */ |
219 | #define NFS_INO_FSCACHE (5) /* inode can be cached by FS-Cache */ | 220 | #define NFS_INO_FSCACHE (5) /* inode can be cached by FS-Cache */ |
220 | #define NFS_INO_FSCACHE_LOCK (6) /* FS-Cache cookie management lock */ | 221 | #define NFS_INO_FSCACHE_LOCK (6) /* FS-Cache cookie management lock */ |