Skip to content

Commit 2e80dbe

Browse files
committed
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 <[email protected]>
1 parent 07e8dcb commit 2e80dbe

File tree

1 file changed

+65
-13
lines changed

1 file changed

+65
-13
lines changed

fs/nfs/nfs4proc.c

Lines changed: 65 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -634,23 +634,25 @@ int nfs40_setup_sequence(struct nfs4_slot_table *tbl,
634634
}
635635
EXPORT_SYMBOL_GPL(nfs40_setup_sequence);
636636

637-
static int nfs40_sequence_done(struct rpc_task *task,
638-
struct nfs4_sequence_res *res)
637+
static void nfs40_sequence_free_slot(struct nfs4_sequence_res *res)
639638
{
640639
struct nfs4_slot *slot = res->sr_slot;
641640
struct nfs4_slot_table *tbl;
642641

643-
if (slot == NULL)
644-
goto out;
645-
646642
tbl = slot->table;
647643
spin_lock(&tbl->slot_tbl_lock);
648644
if (!nfs41_wake_and_assign_slot(tbl, slot))
649645
nfs4_free_slot(tbl, slot);
650646
spin_unlock(&tbl->slot_tbl_lock);
651647

652648
res->sr_slot = NULL;
653-
out:
649+
}
650+
651+
static 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);
654656
return 1;
655657
}
656658

@@ -695,7 +697,8 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
695697
wake_up_all(&tbl->slot_waitq);
696698
}
697699

698-
int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
700+
static int nfs41_sequence_process(struct rpc_task *task,
701+
struct nfs4_sequence_res *res)
699702
{
700703
struct nfs4_session *session;
701704
struct nfs4_slot *slot = res->sr_slot;
@@ -781,11 +784,11 @@ int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
781784
out:
782785
/* The session may be reset by one of the error handlers. */
783786
dprintk("%s: Error %d free the slot \n", __func__, res->sr_status);
784-
nfs41_sequence_free_slot(res);
785787
out_noaction:
786788
return ret;
787789
retry_nowait:
788790
if (rpc_restart_call_prepare(task)) {
791+
nfs41_sequence_free_slot(res);
789792
task->tk_status = 0;
790793
ret = 0;
791794
}
@@ -796,8 +799,37 @@ int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
796799
rpc_delay(task, NFS4_POLL_RETRY_MAX);
797800
return 0;
798801
}
802+
803+
int 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+
}
799812
EXPORT_SYMBOL_GPL(nfs41_sequence_done);
800813

814+
static 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+
823+
static 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+
801833
int nfs4_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
802834
{
803835
if (res->sr_slot == NULL)
@@ -927,6 +959,17 @@ static int nfs4_setup_sequence(const struct nfs_server *server,
927959
args, res, task);
928960
}
929961

962+
static int nfs4_sequence_process(struct rpc_task *task, struct nfs4_sequence_res *res)
963+
{
964+
return nfs40_sequence_done(task, res);
965+
}
966+
967+
static 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+
930973
int nfs4_sequence_done(struct rpc_task *task,
931974
struct nfs4_sequence_res *res)
932975
{
@@ -1204,6 +1247,7 @@ static void nfs4_opendata_free(struct kref *kref)
12041247
struct super_block *sb = p->dentry->d_sb;
12051248

12061249
nfs_free_seqid(p->o_arg.seqid);
1250+
nfs4_sequence_free_slot(&p->o_res.seq_res);
12071251
if (p->state != NULL)
12081252
nfs4_put_open_state(p->state);
12091253
nfs4_put_state_owner(p->owner);
@@ -1663,9 +1707,14 @@ _nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
16631707
static struct nfs4_state *
16641708
nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
16651709
{
1710+
struct nfs4_state *ret;
1711+
16661712
if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS)
1667-
return _nfs4_opendata_reclaim_to_nfs4_state(data);
1668-
return _nfs4_opendata_to_nfs4_state(data);
1713+
ret =_nfs4_opendata_reclaim_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;
16691718
}
16701719

16711720
static 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)
20632112

20642113
data->rpc_status = task->tk_status;
20652114

2066-
if (!nfs4_sequence_done(task, &data->o_res.seq_res))
2115+
if (!nfs4_sequence_process(task, &data->o_res.seq_res))
20672116
return;
20682117

20692118
if (task->tk_status == 0) {
@@ -7871,7 +7920,7 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
78717920
struct nfs4_layoutget *lgp = calldata;
78727921

78737922
dprintk("--> %s\n", __func__);
7874-
nfs41_sequence_done(task, &lgp->res.seq_res);
7923+
nfs41_sequence_process(task, &lgp->res.seq_res);
78757924
dprintk("<-- %s\n", __func__);
78767925
}
78777926

@@ -8087,6 +8136,7 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, long *timeout, gfp_t gfp_flags)
80878136
/* if layoutp->len is 0, nfs4_layoutget_prepare called rpc_exit */
80888137
if (status == 0 && lgp->res.layoutp->len)
80898138
lseg = pnfs_layout_process(lgp);
8139+
nfs4_sequence_free_slot(&lgp->res.seq_res);
80908140
rpc_put_task(task);
80918141
dprintk("<-- %s status=%d\n", __func__, status);
80928142
if (status)
@@ -8113,7 +8163,7 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata)
81138163

81148164
dprintk("--> %s\n", __func__);
81158165

8116-
if (!nfs41_sequence_done(task, &lrp->res.seq_res))
8166+
if (!nfs41_sequence_process(task, &lrp->res.seq_res))
81178167
return;
81188168

81198169
server = NFS_SERVER(lrp->args.inode);
@@ -8125,6 +8175,7 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata)
81258175
case -NFS4ERR_DELAY:
81268176
if (nfs4_async_handle_error(task, server, NULL, NULL) != -EAGAIN)
81278177
break;
8178+
nfs4_sequence_free_slot(&lrp->res.seq_res);
81288179
rpc_restart_call_prepare(task);
81298180
return;
81308181
}
@@ -8145,6 +8196,7 @@ static void nfs4_layoutreturn_release(void *calldata)
81458196
pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);
81468197
pnfs_clear_layoutreturn_waitbit(lo);
81478198
spin_unlock(&lo->plh_inode->i_lock);
8199+
nfs4_sequence_free_slot(&lrp->res.seq_res);
81488200
pnfs_free_lseg_list(&freeme);
81498201
pnfs_put_layout_hdr(lrp->args.layout);
81508202
nfs_iput_and_deactive(lrp->inode);

0 commit comments

Comments
 (0)