nfs: add memory barriers around NFS_INO_INVALID_DATA and NFS_INO_INVALIDATING

If the setting of NFS_INO_INVALIDATING gets reordered to before the
clearing of NFS_INO_INVALID_DATA, then another task may hit a race
window where both appear to be clear, even though the inode's pages are
still in need of invalidation. Fix this by adding the appropriate memory
barriers.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>

authored by Jeff Layton and committed by Trond Myklebust 4db72b40 17dfeb91

+13 -3
+11 -3
fs/nfs/dir.c
··· 274 274 return -EBADCOOKIE; 275 275 } 276 276 277 + static bool 278 + nfs_readdir_inode_mapping_valid(struct nfs_inode *nfsi) 279 + { 280 + if (nfsi->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA)) 281 + return false; 282 + smp_rmb(); 283 + return !test_bit(NFS_INO_INVALIDATING, &nfsi->flags); 284 + } 285 + 277 286 static 278 287 int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_descriptor_t *desc) 279 288 { ··· 296 287 struct nfs_open_dir_context *ctx = desc->file->private_data; 297 288 298 289 new_pos = desc->current_index + i; 299 - if (ctx->attr_gencount != nfsi->attr_gencount 300 - || (nfsi->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA)) 301 - || test_bit(NFS_INO_INVALIDATING, &nfsi->flags)) { 290 + if (ctx->attr_gencount != nfsi->attr_gencount || 291 + !nfs_readdir_inode_mapping_valid(nfsi)) { 302 292 ctx->duped = 0; 303 293 ctx->attr_gencount = nfsi->attr_gencount; 304 294 } else if (new_pos < desc->ctx->pos) {
+1
fs/nfs/inode.c
··· 1050 1050 } 1051 1051 1052 1052 set_bit(NFS_INO_INVALIDATING, bitlock); 1053 + smp_wmb(); 1053 1054 nfsi->cache_validity &= ~NFS_INO_INVALID_DATA; 1054 1055 spin_unlock(&inode->i_lock); 1055 1056 trace_nfs_invalidate_mapping_enter(inode);
+1
fs/nfs/write.c
··· 915 915 goto out; 916 916 if (nfsi->cache_validity & (NFS_INO_INVALID_DATA|NFS_INO_REVAL_PAGECACHE)) 917 917 return false; 918 + smp_rmb(); 918 919 if (test_bit(NFS_INO_INVALIDATING, &nfsi->flags)) 919 920 return false; 920 921 out: