aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-01-31 18:39:07 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2014-01-31 18:39:07 -0500
commit8a1f006ad302ea178aefb1f8c67e679c696289e9 (patch)
tree8ba312b39070556d2062a9f90b1a7fa394041d78 /fs
parent14864a52cd8189e8567df8351d9fc7e435133abd (diff)
parenta1800acaf7d1c2bf6d68b9a8f4ab8560cc66555a (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')
-rw-r--r--fs/nfs/dir.c13
-rw-r--r--fs/nfs/inode.c51
-rw-r--r--fs/nfs/nfs4_fs.h1
-rw-r--r--fs/nfs/nfs4client.c5
-rw-r--r--fs/nfs/nfs4filelayout.c8
-rw-r--r--fs/nfs/nfs4proc.c31
-rw-r--r--fs/nfs/nfs4xdr.c2
-rw-r--r--fs/nfs/nfstrace.h1
-rw-r--r--fs/nfs/write.c7
9 files changed, 84 insertions, 35 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index b266f734bd53..be38b573495a 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -274,6 +274,15 @@ out_eof:
274 return -EBADCOOKIE; 274 return -EBADCOOKIE;
275} 275}
276 276
277static bool
278nfs_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
277static 286static
278int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_descriptor_t *desc) 287int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_descriptor_t *desc)
279{ 288{
@@ -287,8 +296,8 @@ int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_des
287 struct nfs_open_dir_context *ctx = desc->file->private_data; 296 struct nfs_open_dir_context *ctx = desc->file->private_data;
288 297
289 new_pos = desc->current_index + i; 298 new_pos = desc->current_index + i;
290 if (ctx->attr_gencount != nfsi->attr_gencount 299 if (ctx->attr_gencount != nfsi->attr_gencount ||
291 || (nfsi->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA))) { 300 !nfs_readdir_inode_mapping_valid(nfsi)) {
292 ctx->duped = 0; 301 ctx->duped = 0;
293 ctx->attr_gencount = nfsi->attr_gencount; 302 ctx->attr_gencount = nfsi->attr_gencount;
294 } else if (new_pos < desc->ctx->pos) { 303 } else if (new_pos < desc->ctx->pos) {
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)
1008int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) 1008int 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);
1028out: 1063out:
1029 return ret; 1064 return ret;
1030} 1065}
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 5609edc742a0..a5b27c2d9689 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -270,6 +270,7 @@ static inline struct nfs4_session *nfs4_get_session(const struct nfs_server *ser
270extern int nfs41_setup_sequence(struct nfs4_session *session, 270extern int nfs41_setup_sequence(struct nfs4_session *session,
271 struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, 271 struct nfs4_sequence_args *args, struct nfs4_sequence_res *res,
272 struct rpc_task *task); 272 struct rpc_task *task);
273extern int nfs41_sequence_done(struct rpc_task *, struct nfs4_sequence_res *);
273extern int nfs4_proc_create_session(struct nfs_client *, struct rpc_cred *); 274extern int nfs4_proc_create_session(struct nfs_client *, struct rpc_cred *);
274extern int nfs4_proc_destroy_session(struct nfs4_session *, struct rpc_cred *); 275extern int nfs4_proc_destroy_session(struct nfs4_session *, struct rpc_cred *);
275extern int nfs4_proc_get_lease_time(struct nfs_client *clp, 276extern int nfs4_proc_get_lease_time(struct nfs_client *clp,
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c
index 73d4ecda1e36..dbb3e1f30c68 100644
--- a/fs/nfs/nfs4client.c
+++ b/fs/nfs/nfs4client.c
@@ -372,10 +372,7 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp,
372 __set_bit(NFS_CS_DISCRTRY, &clp->cl_flags); 372 __set_bit(NFS_CS_DISCRTRY, &clp->cl_flags);
373 __set_bit(NFS_CS_NO_RETRANS_TIMEOUT, &clp->cl_flags); 373 __set_bit(NFS_CS_NO_RETRANS_TIMEOUT, &clp->cl_flags);
374 374
375 error = -EINVAL; 375 error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_GSS_KRB5I);
376 if (gssd_running(clp->cl_net))
377 error = nfs_create_rpc_client(clp, timeparms,
378 RPC_AUTH_GSS_KRB5I);
379 if (error == -EINVAL) 376 if (error == -EINVAL)
380 error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_UNIX); 377 error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_UNIX);
381 if (error < 0) 378 if (error < 0)
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c
index 03fd8be8c0c5..12c8132ad408 100644
--- a/fs/nfs/nfs4filelayout.c
+++ b/fs/nfs/nfs4filelayout.c
@@ -335,8 +335,10 @@ static void filelayout_read_call_done(struct rpc_task *task, void *data)
335 dprintk("--> %s task->tk_status %d\n", __func__, task->tk_status); 335 dprintk("--> %s task->tk_status %d\n", __func__, task->tk_status);
336 336
337 if (test_bit(NFS_IOHDR_REDO, &rdata->header->flags) && 337 if (test_bit(NFS_IOHDR_REDO, &rdata->header->flags) &&
338 task->tk_status == 0) 338 task->tk_status == 0) {
339 nfs41_sequence_done(task, &rdata->res.seq_res);
339 return; 340 return;
341 }
340 342
341 /* Note this may cause RPC to be resent */ 343 /* Note this may cause RPC to be resent */
342 rdata->header->mds_ops->rpc_call_done(task, data); 344 rdata->header->mds_ops->rpc_call_done(task, data);
@@ -442,8 +444,10 @@ static void filelayout_write_call_done(struct rpc_task *task, void *data)
442 struct nfs_write_data *wdata = data; 444 struct nfs_write_data *wdata = data;
443 445
444 if (test_bit(NFS_IOHDR_REDO, &wdata->header->flags) && 446 if (test_bit(NFS_IOHDR_REDO, &wdata->header->flags) &&
445 task->tk_status == 0) 447 task->tk_status == 0) {
448 nfs41_sequence_done(task, &wdata->res.seq_res);
446 return; 449 return;
450 }
447 451
448 /* Note this may cause RPC to be resent */ 452 /* Note this may cause RPC to be resent */
449 wdata->header->mds_ops->rpc_call_done(task, data); 453 wdata->header->mds_ops->rpc_call_done(task, data);
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index a1965329a12c..42da6af77587 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -539,7 +539,7 @@ static int nfs40_sequence_done(struct rpc_task *task,
539 struct nfs4_slot *slot = res->sr_slot; 539 struct nfs4_slot *slot = res->sr_slot;
540 struct nfs4_slot_table *tbl; 540 struct nfs4_slot_table *tbl;
541 541
542 if (!RPC_WAS_SENT(task)) 542 if (slot == NULL)
543 goto out; 543 goto out;
544 544
545 tbl = slot->table; 545 tbl = slot->table;
@@ -559,15 +559,10 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
559{ 559{
560 struct nfs4_session *session; 560 struct nfs4_session *session;
561 struct nfs4_slot_table *tbl; 561 struct nfs4_slot_table *tbl;
562 struct nfs4_slot *slot = res->sr_slot;
562 bool send_new_highest_used_slotid = false; 563 bool send_new_highest_used_slotid = false;
563 564
564 if (!res->sr_slot) { 565 tbl = slot->table;
565 /* just wake up the next guy waiting since
566 * we may have not consumed a slot after all */
567 dprintk("%s: No slot\n", __func__);
568 return;
569 }
570 tbl = res->sr_slot->table;
571 session = tbl->session; 566 session = tbl->session;
572 567
573 spin_lock(&tbl->slot_tbl_lock); 568 spin_lock(&tbl->slot_tbl_lock);
@@ -577,11 +572,11 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
577 if (tbl->highest_used_slotid > tbl->target_highest_slotid) 572 if (tbl->highest_used_slotid > tbl->target_highest_slotid)
578 send_new_highest_used_slotid = true; 573 send_new_highest_used_slotid = true;
579 574
580 if (nfs41_wake_and_assign_slot(tbl, res->sr_slot)) { 575 if (nfs41_wake_and_assign_slot(tbl, slot)) {
581 send_new_highest_used_slotid = false; 576 send_new_highest_used_slotid = false;
582 goto out_unlock; 577 goto out_unlock;
583 } 578 }
584 nfs4_free_slot(tbl, res->sr_slot); 579 nfs4_free_slot(tbl, slot);
585 580
586 if (tbl->highest_used_slotid != NFS4_NO_SLOT) 581 if (tbl->highest_used_slotid != NFS4_NO_SLOT)
587 send_new_highest_used_slotid = false; 582 send_new_highest_used_slotid = false;
@@ -592,19 +587,20 @@ out_unlock:
592 nfs41_server_notify_highest_slotid_update(session->clp); 587 nfs41_server_notify_highest_slotid_update(session->clp);
593} 588}
594 589
595static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res) 590int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
596{ 591{
597 struct nfs4_session *session; 592 struct nfs4_session *session;
598 struct nfs4_slot *slot; 593 struct nfs4_slot *slot = res->sr_slot;
599 struct nfs_client *clp; 594 struct nfs_client *clp;
600 bool interrupted = false; 595 bool interrupted = false;
601 int ret = 1; 596 int ret = 1;
602 597
598 if (slot == NULL)
599 goto out_noaction;
603 /* don't increment the sequence number if the task wasn't sent */ 600 /* don't increment the sequence number if the task wasn't sent */
604 if (!RPC_WAS_SENT(task)) 601 if (!RPC_WAS_SENT(task))
605 goto out; 602 goto out;
606 603
607 slot = res->sr_slot;
608 session = slot->table->session; 604 session = slot->table->session;
609 605
610 if (slot->interrupted) { 606 if (slot->interrupted) {
@@ -679,6 +675,7 @@ out:
679 /* The session may be reset by one of the error handlers. */ 675 /* The session may be reset by one of the error handlers. */
680 dprintk("%s: Error %d free the slot \n", __func__, res->sr_status); 676 dprintk("%s: Error %d free the slot \n", __func__, res->sr_status);
681 nfs41_sequence_free_slot(res); 677 nfs41_sequence_free_slot(res);
678out_noaction:
682 return ret; 679 return ret;
683retry_nowait: 680retry_nowait:
684 if (rpc_restart_call_prepare(task)) { 681 if (rpc_restart_call_prepare(task)) {
@@ -692,6 +689,7 @@ out_retry:
692 rpc_delay(task, NFS4_POLL_RETRY_MAX); 689 rpc_delay(task, NFS4_POLL_RETRY_MAX);
693 return 0; 690 return 0;
694} 691}
692EXPORT_SYMBOL_GPL(nfs41_sequence_done);
695 693
696static int nfs4_sequence_done(struct rpc_task *task, 694static int nfs4_sequence_done(struct rpc_task *task,
697 struct nfs4_sequence_res *res) 695 struct nfs4_sequence_res *res)
@@ -2744,7 +2742,8 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
2744 NFS_CAP_OWNER_GROUP|NFS_CAP_ATIME| 2742 NFS_CAP_OWNER_GROUP|NFS_CAP_ATIME|
2745 NFS_CAP_CTIME|NFS_CAP_MTIME| 2743 NFS_CAP_CTIME|NFS_CAP_MTIME|
2746 NFS_CAP_SECURITY_LABEL); 2744 NFS_CAP_SECURITY_LABEL);
2747 if (res.attr_bitmask[0] & FATTR4_WORD0_ACL) 2745 if (res.attr_bitmask[0] & FATTR4_WORD0_ACL &&
2746 res.acl_bitmask & ACL4_SUPPORT_ALLOW_ACL)
2748 server->caps |= NFS_CAP_ACLS; 2747 server->caps |= NFS_CAP_ACLS;
2749 if (res.has_links != 0) 2748 if (res.has_links != 0)
2750 server->caps |= NFS_CAP_HARDLINKS; 2749 server->caps |= NFS_CAP_HARDLINKS;
@@ -4321,9 +4320,7 @@ static int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred)
4321 4320
4322static inline int nfs4_server_supports_acls(struct nfs_server *server) 4321static inline int nfs4_server_supports_acls(struct nfs_server *server)
4323{ 4322{
4324 return (server->caps & NFS_CAP_ACLS) 4323 return server->caps & NFS_CAP_ACLS;
4325 && (server->acl_bitmask & ACL4_SUPPORT_ALLOW_ACL)
4326 && (server->acl_bitmask & ACL4_SUPPORT_DENY_ACL);
4327} 4324}
4328 4325
4329/* Assuming that XATTR_SIZE_MAX is a multiple of PAGE_SIZE, and that 4326/* Assuming that XATTR_SIZE_MAX is a multiple of PAGE_SIZE, and that
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 8c21d69a9dc1..72f3bf1754ef 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -3449,7 +3449,7 @@ static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint
3449{ 3449{
3450 __be32 *p; 3450 __be32 *p;
3451 3451
3452 *res = ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL; 3452 *res = 0;
3453 if (unlikely(bitmap[0] & (FATTR4_WORD0_ACLSUPPORT - 1U))) 3453 if (unlikely(bitmap[0] & (FATTR4_WORD0_ACLSUPPORT - 1U)))
3454 return -EIO; 3454 return -EIO;
3455 if (likely(bitmap[0] & FATTR4_WORD0_ACLSUPPORT)) { 3455 if (likely(bitmap[0] & FATTR4_WORD0_ACLSUPPORT)) {
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..9a3b6a4cd6b9 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -909,9 +909,14 @@ bool nfs_ctx_key_to_expire(struct nfs_open_context *ctx)
909 */ 909 */
910static bool nfs_write_pageuptodate(struct page *page, struct inode *inode) 910static 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 smp_rmb();
919 if (test_bit(NFS_INO_INVALIDATING, &nfsi->flags))
915 return false; 920 return false;
916out: 921out:
917 return PageUptodate(page) != 0; 922 return PageUptodate(page) != 0;