aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@primarydata.com>2016-08-28 11:50:26 -0400
committerTrond Myklebust <trond.myklebust@primarydata.com>2016-08-28 14:23:27 -0400
commit2e80dbe7ac51a911e8a828407b1a48c5ba938cd2 (patch)
tree696841c4bd2e1c5ef034436ad62ce8082963a730
parent07e8dcbda71ef87e9cbdc42b5bb16a44c1ab839b (diff)
NFSv4.1: Close callback races for OPEN, LAYOUTGET and LAYOUTRETURN
Defer freeing the slot until after we have processed the results from OPEN and LAYOUTGET. This means that the server can rely on the mechanism in RFC5661 Section 2.10.6.3 to ensure that replies to an OPEN or LAYOUTGET/RETURN RPC call don't race with the callbacks that apply to them. Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
-rw-r--r--fs/nfs/nfs4proc.c78
1 files changed, 65 insertions, 13 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index de4a89d3d740..f5aecaabcb7c 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -634,15 +634,11 @@ out_sleep:
634} 634}
635EXPORT_SYMBOL_GPL(nfs40_setup_sequence); 635EXPORT_SYMBOL_GPL(nfs40_setup_sequence);
636 636
637static int nfs40_sequence_done(struct rpc_task *task, 637static void nfs40_sequence_free_slot(struct nfs4_sequence_res *res)
638 struct nfs4_sequence_res *res)
639{ 638{
640 struct nfs4_slot *slot = res->sr_slot; 639 struct nfs4_slot *slot = res->sr_slot;
641 struct nfs4_slot_table *tbl; 640 struct nfs4_slot_table *tbl;
642 641
643 if (slot == NULL)
644 goto out;
645
646 tbl = slot->table; 642 tbl = slot->table;
647 spin_lock(&tbl->slot_tbl_lock); 643 spin_lock(&tbl->slot_tbl_lock);
648 if (!nfs41_wake_and_assign_slot(tbl, slot)) 644 if (!nfs41_wake_and_assign_slot(tbl, slot))
@@ -650,7 +646,13 @@ static int nfs40_sequence_done(struct rpc_task *task,
650 spin_unlock(&tbl->slot_tbl_lock); 646 spin_unlock(&tbl->slot_tbl_lock);
651 647
652 res->sr_slot = NULL; 648 res->sr_slot = NULL;
653out: 649}
650
651static int nfs40_sequence_done(struct rpc_task *task,
652 struct nfs4_sequence_res *res)
653{
654 if (res->sr_slot != NULL)
655 nfs40_sequence_free_slot(res);
654 return 1; 656 return 1;
655} 657}
656 658
@@ -695,7 +697,8 @@ out_unlock:
695 wake_up_all(&tbl->slot_waitq); 697 wake_up_all(&tbl->slot_waitq);
696} 698}
697 699
698int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res) 700static int nfs41_sequence_process(struct rpc_task *task,
701 struct nfs4_sequence_res *res)
699{ 702{
700 struct nfs4_session *session; 703 struct nfs4_session *session;
701 struct nfs4_slot *slot = res->sr_slot; 704 struct nfs4_slot *slot = res->sr_slot;
@@ -781,11 +784,11 @@ int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
781out: 784out:
782 /* The session may be reset by one of the error handlers. */ 785 /* The session may be reset by one of the error handlers. */
783 dprintk("%s: Error %d free the slot \n", __func__, res->sr_status); 786 dprintk("%s: Error %d free the slot \n", __func__, res->sr_status);
784 nfs41_sequence_free_slot(res);
785out_noaction: 787out_noaction:
786 return ret; 788 return ret;
787retry_nowait: 789retry_nowait:
788 if (rpc_restart_call_prepare(task)) { 790 if (rpc_restart_call_prepare(task)) {
791 nfs41_sequence_free_slot(res);
789 task->tk_status = 0; 792 task->tk_status = 0;
790 ret = 0; 793 ret = 0;
791 } 794 }
@@ -796,8 +799,37 @@ out_retry:
796 rpc_delay(task, NFS4_POLL_RETRY_MAX); 799 rpc_delay(task, NFS4_POLL_RETRY_MAX);
797 return 0; 800 return 0;
798} 801}
802
803int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
804{
805 if (!nfs41_sequence_process(task, res))
806 return 0;
807 if (res->sr_slot != NULL)
808 nfs41_sequence_free_slot(res);
809 return 1;
810
811}
799EXPORT_SYMBOL_GPL(nfs41_sequence_done); 812EXPORT_SYMBOL_GPL(nfs41_sequence_done);
800 813
814static int nfs4_sequence_process(struct rpc_task *task, struct nfs4_sequence_res *res)
815{
816 if (res->sr_slot == NULL)
817 return 1;
818 if (res->sr_slot->table->session != NULL)
819 return nfs41_sequence_process(task, res);
820 return nfs40_sequence_done(task, res);
821}
822
823static void nfs4_sequence_free_slot(struct nfs4_sequence_res *res)
824{
825 if (res->sr_slot != NULL) {
826 if (res->sr_slot->table->session != NULL)
827 nfs41_sequence_free_slot(res);
828 else
829 nfs40_sequence_free_slot(res);
830 }
831}
832
801int nfs4_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res) 833int nfs4_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
802{ 834{
803 if (res->sr_slot == NULL) 835 if (res->sr_slot == NULL)
@@ -927,6 +959,17 @@ static int nfs4_setup_sequence(const struct nfs_server *server,
927 args, res, task); 959 args, res, task);
928} 960}
929 961
962static int nfs4_sequence_process(struct rpc_task *task, struct nfs4_sequence_res *res)
963{
964 return nfs40_sequence_done(task, res);
965}
966
967static void nfs4_sequence_free_slot(struct nfs4_sequence_res *res)
968{
969 if (res->sr_slot != NULL)
970 nfs40_sequence_free_slot(res);
971}
972
930int nfs4_sequence_done(struct rpc_task *task, 973int nfs4_sequence_done(struct rpc_task *task,
931 struct nfs4_sequence_res *res) 974 struct nfs4_sequence_res *res)
932{ 975{
@@ -1204,6 +1247,7 @@ static void nfs4_opendata_free(struct kref *kref)
1204 struct super_block *sb = p->dentry->d_sb; 1247 struct super_block *sb = p->dentry->d_sb;
1205 1248
1206 nfs_free_seqid(p->o_arg.seqid); 1249 nfs_free_seqid(p->o_arg.seqid);
1250 nfs4_sequence_free_slot(&p->o_res.seq_res);
1207 if (p->state != NULL) 1251 if (p->state != NULL)
1208 nfs4_put_open_state(p->state); 1252 nfs4_put_open_state(p->state);
1209 nfs4_put_state_owner(p->owner); 1253 nfs4_put_state_owner(p->owner);
@@ -1663,9 +1707,14 @@ err:
1663static struct nfs4_state * 1707static struct nfs4_state *
1664nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data) 1708nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
1665{ 1709{
1710 struct nfs4_state *ret;
1711
1666 if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) 1712 if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS)
1667 return _nfs4_opendata_reclaim_to_nfs4_state(data); 1713 ret =_nfs4_opendata_reclaim_to_nfs4_state(data);
1668 return _nfs4_opendata_to_nfs4_state(data); 1714 else
1715 ret = _nfs4_opendata_to_nfs4_state(data);
1716 nfs4_sequence_free_slot(&data->o_res.seq_res);
1717 return ret;
1669} 1718}
1670 1719
1671static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state *state) 1720static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state *state)
@@ -2063,7 +2112,7 @@ static void nfs4_open_done(struct rpc_task *task, void *calldata)
2063 2112
2064 data->rpc_status = task->tk_status; 2113 data->rpc_status = task->tk_status;
2065 2114
2066 if (!nfs4_sequence_done(task, &data->o_res.seq_res)) 2115 if (!nfs4_sequence_process(task, &data->o_res.seq_res))
2067 return; 2116 return;
2068 2117
2069 if (task->tk_status == 0) { 2118 if (task->tk_status == 0) {
@@ -7871,7 +7920,7 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
7871 struct nfs4_layoutget *lgp = calldata; 7920 struct nfs4_layoutget *lgp = calldata;
7872 7921
7873 dprintk("--> %s\n", __func__); 7922 dprintk("--> %s\n", __func__);
7874 nfs41_sequence_done(task, &lgp->res.seq_res); 7923 nfs41_sequence_process(task, &lgp->res.seq_res);
7875 dprintk("<-- %s\n", __func__); 7924 dprintk("<-- %s\n", __func__);
7876} 7925}
7877 7926
@@ -8087,6 +8136,7 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, long *timeout, gfp_t gfp_flags)
8087 /* if layoutp->len is 0, nfs4_layoutget_prepare called rpc_exit */ 8136 /* if layoutp->len is 0, nfs4_layoutget_prepare called rpc_exit */
8088 if (status == 0 && lgp->res.layoutp->len) 8137 if (status == 0 && lgp->res.layoutp->len)
8089 lseg = pnfs_layout_process(lgp); 8138 lseg = pnfs_layout_process(lgp);
8139 nfs4_sequence_free_slot(&lgp->res.seq_res);
8090 rpc_put_task(task); 8140 rpc_put_task(task);
8091 dprintk("<-- %s status=%d\n", __func__, status); 8141 dprintk("<-- %s status=%d\n", __func__, status);
8092 if (status) 8142 if (status)
@@ -8113,7 +8163,7 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata)
8113 8163
8114 dprintk("--> %s\n", __func__); 8164 dprintk("--> %s\n", __func__);
8115 8165
8116 if (!nfs41_sequence_done(task, &lrp->res.seq_res)) 8166 if (!nfs41_sequence_process(task, &lrp->res.seq_res))
8117 return; 8167 return;
8118 8168
8119 server = NFS_SERVER(lrp->args.inode); 8169 server = NFS_SERVER(lrp->args.inode);
@@ -8125,6 +8175,7 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata)
8125 case -NFS4ERR_DELAY: 8175 case -NFS4ERR_DELAY:
8126 if (nfs4_async_handle_error(task, server, NULL, NULL) != -EAGAIN) 8176 if (nfs4_async_handle_error(task, server, NULL, NULL) != -EAGAIN)
8127 break; 8177 break;
8178 nfs4_sequence_free_slot(&lrp->res.seq_res);
8128 rpc_restart_call_prepare(task); 8179 rpc_restart_call_prepare(task);
8129 return; 8180 return;
8130 } 8181 }
@@ -8145,6 +8196,7 @@ static void nfs4_layoutreturn_release(void *calldata)
8145 pnfs_set_layout_stateid(lo, &lrp->res.stateid, true); 8196 pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);
8146 pnfs_clear_layoutreturn_waitbit(lo); 8197 pnfs_clear_layoutreturn_waitbit(lo);
8147 spin_unlock(&lo->plh_inode->i_lock); 8198 spin_unlock(&lo->plh_inode->i_lock);
8199 nfs4_sequence_free_slot(&lrp->res.seq_res);
8148 pnfs_free_lseg_list(&freeme); 8200 pnfs_free_lseg_list(&freeme);
8149 pnfs_put_layout_hdr(lrp->args.layout); 8201 pnfs_put_layout_hdr(lrp->args.layout);
8150 nfs_iput_and_deactive(lrp->inode); 8202 nfs_iput_and_deactive(lrp->inode);