diff options
-rw-r--r-- | fs/nfs/callback.h | 3 | ||||
-rw-r--r-- | fs/nfs/callback_proc.c | 69 | ||||
-rw-r--r-- | fs/nfs/callback_xdr.c | 12 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4session.c | 54 | ||||
-rw-r--r-- | fs/nfs/nfs4session.h | 8 |
6 files changed, 97 insertions, 51 deletions
diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h index ff8195bd75ea..5fe1cecbf9f0 100644 --- a/fs/nfs/callback.h +++ b/fs/nfs/callback.h | |||
@@ -37,10 +37,11 @@ enum nfs4_callback_opnum { | |||
37 | OP_CB_ILLEGAL = 10044, | 37 | OP_CB_ILLEGAL = 10044, |
38 | }; | 38 | }; |
39 | 39 | ||
40 | struct nfs4_slot; | ||
40 | struct cb_process_state { | 41 | struct cb_process_state { |
41 | __be32 drc_status; | 42 | __be32 drc_status; |
42 | struct nfs_client *clp; | 43 | struct nfs_client *clp; |
43 | u32 slotid; | 44 | struct nfs4_slot *slot; |
44 | u32 minorversion; | 45 | u32 minorversion; |
45 | struct net *net; | 46 | struct net *net; |
46 | }; | 47 | }; |
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index f0939d097406..618ced381a14 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
@@ -354,47 +354,38 @@ out: | |||
354 | * a single outstanding callback request at a time. | 354 | * a single outstanding callback request at a time. |
355 | */ | 355 | */ |
356 | static __be32 | 356 | static __be32 |
357 | validate_seqid(struct nfs4_slot_table *tbl, struct cb_sequenceargs * args) | 357 | validate_seqid(const struct nfs4_slot_table *tbl, const struct nfs4_slot *slot, |
358 | const struct cb_sequenceargs * args) | ||
358 | { | 359 | { |
359 | struct nfs4_slot *slot; | 360 | dprintk("%s enter. slotid %u seqid %u, slot table seqid: %u\n", |
360 | 361 | __func__, args->csa_slotid, args->csa_sequenceid, slot->seq_nr); | |
361 | dprintk("%s enter. slotid %u seqid %u\n", | ||
362 | __func__, args->csa_slotid, args->csa_sequenceid); | ||
363 | 362 | ||
364 | if (args->csa_slotid >= NFS41_BC_MAX_CALLBACKS) | 363 | if (args->csa_slotid > tbl->server_highest_slotid) |
365 | return htonl(NFS4ERR_BADSLOT); | 364 | return htonl(NFS4ERR_BADSLOT); |
366 | 365 | ||
367 | slot = tbl->slots + args->csa_slotid; | ||
368 | dprintk("%s slot table seqid: %u\n", __func__, slot->seq_nr); | ||
369 | |||
370 | /* Normal */ | ||
371 | if (likely(args->csa_sequenceid == slot->seq_nr + 1)) | ||
372 | goto out_ok; | ||
373 | |||
374 | /* Replay */ | 366 | /* Replay */ |
375 | if (args->csa_sequenceid == slot->seq_nr) { | 367 | if (args->csa_sequenceid == slot->seq_nr) { |
376 | dprintk("%s seqid %u is a replay\n", | 368 | dprintk("%s seqid %u is a replay\n", |
377 | __func__, args->csa_sequenceid); | 369 | __func__, args->csa_sequenceid); |
370 | if (nfs4_test_locked_slot(tbl, slot->slot_nr)) | ||
371 | return htonl(NFS4ERR_DELAY); | ||
378 | /* Signal process_op to set this error on next op */ | 372 | /* Signal process_op to set this error on next op */ |
379 | if (args->csa_cachethis == 0) | 373 | if (args->csa_cachethis == 0) |
380 | return htonl(NFS4ERR_RETRY_UNCACHED_REP); | 374 | return htonl(NFS4ERR_RETRY_UNCACHED_REP); |
381 | 375 | ||
382 | /* The ca_maxresponsesize_cached is 0 with no DRC */ | 376 | /* Liar! We never allowed you to set csa_cachethis != 0 */ |
383 | else if (args->csa_cachethis == 1) | 377 | return htonl(NFS4ERR_SEQ_FALSE_RETRY); |
384 | return htonl(NFS4ERR_REP_TOO_BIG_TO_CACHE); | ||
385 | } | 378 | } |
386 | 379 | ||
387 | /* Wraparound */ | 380 | /* Wraparound */ |
388 | if (args->csa_sequenceid == 1 && (slot->seq_nr + 1) == 0) { | 381 | if (unlikely(slot->seq_nr == 0xFFFFFFFFU)) { |
389 | slot->seq_nr = 1; | 382 | if (args->csa_sequenceid == 1) |
390 | goto out_ok; | 383 | return htonl(NFS4_OK); |
391 | } | 384 | } else if (likely(args->csa_sequenceid == slot->seq_nr + 1)) |
385 | return htonl(NFS4_OK); | ||
392 | 386 | ||
393 | /* Misordered request */ | 387 | /* Misordered request */ |
394 | return htonl(NFS4ERR_SEQ_MISORDERED); | 388 | return htonl(NFS4ERR_SEQ_MISORDERED); |
395 | out_ok: | ||
396 | tbl->highest_used_slotid = args->csa_slotid; | ||
397 | return htonl(NFS4_OK); | ||
398 | } | 389 | } |
399 | 390 | ||
400 | /* | 391 | /* |
@@ -473,6 +464,12 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args, | |||
473 | tbl = &clp->cl_session->bc_slot_table; | 464 | tbl = &clp->cl_session->bc_slot_table; |
474 | slot = tbl->slots + args->csa_slotid; | 465 | slot = tbl->slots + args->csa_slotid; |
475 | 466 | ||
467 | /* Set up res before grabbing the spinlock */ | ||
468 | memcpy(&res->csr_sessionid, &args->csa_sessionid, | ||
469 | sizeof(res->csr_sessionid)); | ||
470 | res->csr_sequenceid = args->csa_sequenceid; | ||
471 | res->csr_slotid = args->csa_slotid; | ||
472 | |||
476 | spin_lock(&tbl->slot_tbl_lock); | 473 | spin_lock(&tbl->slot_tbl_lock); |
477 | /* state manager is resetting the session */ | 474 | /* state manager is resetting the session */ |
478 | if (test_bit(NFS4_SLOT_TBL_DRAINING, &tbl->slot_tbl_state)) { | 475 | if (test_bit(NFS4_SLOT_TBL_DRAINING, &tbl->slot_tbl_state)) { |
@@ -485,18 +482,26 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args, | |||
485 | goto out_unlock; | 482 | goto out_unlock; |
486 | } | 483 | } |
487 | 484 | ||
488 | memcpy(&res->csr_sessionid, &args->csa_sessionid, | 485 | status = htonl(NFS4ERR_BADSLOT); |
489 | sizeof(res->csr_sessionid)); | 486 | slot = nfs4_lookup_slot(tbl, args->csa_slotid); |
490 | res->csr_sequenceid = args->csa_sequenceid; | 487 | if (IS_ERR(slot)) |
491 | res->csr_slotid = args->csa_slotid; | 488 | goto out_unlock; |
492 | res->csr_highestslotid = NFS41_BC_MAX_CALLBACKS - 1; | 489 | |
493 | res->csr_target_highestslotid = NFS41_BC_MAX_CALLBACKS - 1; | 490 | res->csr_highestslotid = tbl->server_highest_slotid; |
491 | res->csr_target_highestslotid = tbl->target_highest_slotid; | ||
494 | 492 | ||
495 | status = validate_seqid(tbl, args); | 493 | status = validate_seqid(tbl, slot, args); |
496 | if (status) | 494 | if (status) |
497 | goto out_unlock; | 495 | goto out_unlock; |
496 | if (!nfs4_try_to_lock_slot(tbl, slot)) { | ||
497 | status = htonl(NFS4ERR_DELAY); | ||
498 | goto out_unlock; | ||
499 | } | ||
500 | cps->slot = slot; | ||
498 | 501 | ||
499 | cps->slotid = args->csa_slotid; | 502 | /* The ca_maxresponsesize_cached is 0 with no DRC */ |
503 | if (args->csa_cachethis != 0) | ||
504 | return htonl(NFS4ERR_REP_TOO_BIG_TO_CACHE); | ||
500 | 505 | ||
501 | /* | 506 | /* |
502 | * Check for pending referring calls. If a match is found, a | 507 | * Check for pending referring calls. If a match is found, a |
@@ -513,7 +518,7 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args, | |||
513 | * If CB_SEQUENCE returns an error, then the state of the slot | 518 | * If CB_SEQUENCE returns an error, then the state of the slot |
514 | * (sequence ID, cached reply) MUST NOT change. | 519 | * (sequence ID, cached reply) MUST NOT change. |
515 | */ | 520 | */ |
516 | slot->seq_nr++; | 521 | slot->seq_nr = args->csa_sequenceid; |
517 | out_unlock: | 522 | out_unlock: |
518 | spin_unlock(&tbl->slot_tbl_lock); | 523 | spin_unlock(&tbl->slot_tbl_lock); |
519 | 524 | ||
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index 646cdac73488..976c90608e56 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c | |||
@@ -752,7 +752,8 @@ preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op) | |||
752 | return htonl(NFS_OK); | 752 | return htonl(NFS_OK); |
753 | } | 753 | } |
754 | 754 | ||
755 | static void nfs4_callback_free_slot(struct nfs4_session *session) | 755 | static void nfs4_callback_free_slot(struct nfs4_session *session, |
756 | struct nfs4_slot *slot) | ||
756 | { | 757 | { |
757 | struct nfs4_slot_table *tbl = &session->bc_slot_table; | 758 | struct nfs4_slot_table *tbl = &session->bc_slot_table; |
758 | 759 | ||
@@ -761,15 +762,17 @@ static void nfs4_callback_free_slot(struct nfs4_session *session) | |||
761 | * Let the state manager know callback processing done. | 762 | * Let the state manager know callback processing done. |
762 | * A single slot, so highest used slotid is either 0 or -1 | 763 | * A single slot, so highest used slotid is either 0 or -1 |
763 | */ | 764 | */ |
764 | tbl->highest_used_slotid = NFS4_NO_SLOT; | 765 | nfs4_free_slot(tbl, slot); |
765 | nfs4_slot_tbl_drain_complete(tbl); | 766 | nfs4_slot_tbl_drain_complete(tbl); |
766 | spin_unlock(&tbl->slot_tbl_lock); | 767 | spin_unlock(&tbl->slot_tbl_lock); |
767 | } | 768 | } |
768 | 769 | ||
769 | static void nfs4_cb_free_slot(struct cb_process_state *cps) | 770 | static void nfs4_cb_free_slot(struct cb_process_state *cps) |
770 | { | 771 | { |
771 | if (cps->slotid != NFS4_NO_SLOT) | 772 | if (cps->slot) { |
772 | nfs4_callback_free_slot(cps->clp->cl_session); | 773 | nfs4_callback_free_slot(cps->clp->cl_session, cps->slot); |
774 | cps->slot = NULL; | ||
775 | } | ||
773 | } | 776 | } |
774 | 777 | ||
775 | #else /* CONFIG_NFS_V4_1 */ | 778 | #else /* CONFIG_NFS_V4_1 */ |
@@ -893,7 +896,6 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r | |||
893 | struct cb_process_state cps = { | 896 | struct cb_process_state cps = { |
894 | .drc_status = 0, | 897 | .drc_status = 0, |
895 | .clp = NULL, | 898 | .clp = NULL, |
896 | .slotid = NFS4_NO_SLOT, | ||
897 | .net = SVC_NET(rqstp), | 899 | .net = SVC_NET(rqstp), |
898 | }; | 900 | }; |
899 | unsigned int nops = 0; | 901 | unsigned int nops = 0; |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 14881594dd07..1e103b4f4ad7 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -7319,7 +7319,7 @@ static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args) | |||
7319 | args->bc_attrs.max_resp_sz = PAGE_SIZE; | 7319 | args->bc_attrs.max_resp_sz = PAGE_SIZE; |
7320 | args->bc_attrs.max_resp_sz_cached = 0; | 7320 | args->bc_attrs.max_resp_sz_cached = 0; |
7321 | args->bc_attrs.max_ops = NFS4_MAX_BACK_CHANNEL_OPS; | 7321 | args->bc_attrs.max_ops = NFS4_MAX_BACK_CHANNEL_OPS; |
7322 | args->bc_attrs.max_reqs = 1; | 7322 | args->bc_attrs.max_reqs = NFS41_BC_MAX_CALLBACKS; |
7323 | 7323 | ||
7324 | dprintk("%s: Back Channel : max_rqst_sz=%u max_resp_sz=%u " | 7324 | dprintk("%s: Back Channel : max_rqst_sz=%u max_resp_sz=%u " |
7325 | "max_resp_sz_cached=%u max_ops=%u max_reqs=%u\n", | 7325 | "max_resp_sz_cached=%u max_ops=%u max_reqs=%u\n", |
diff --git a/fs/nfs/nfs4session.c b/fs/nfs/nfs4session.c index e23366effcfb..332d06e64fa9 100644 --- a/fs/nfs/nfs4session.c +++ b/fs/nfs/nfs4session.c | |||
@@ -135,6 +135,43 @@ static struct nfs4_slot *nfs4_find_or_create_slot(struct nfs4_slot_table *tbl, | |||
135 | return ERR_PTR(-ENOMEM); | 135 | return ERR_PTR(-ENOMEM); |
136 | } | 136 | } |
137 | 137 | ||
138 | static void nfs4_lock_slot(struct nfs4_slot_table *tbl, | ||
139 | struct nfs4_slot *slot) | ||
140 | { | ||
141 | u32 slotid = slot->slot_nr; | ||
142 | |||
143 | __set_bit(slotid, tbl->used_slots); | ||
144 | if (slotid > tbl->highest_used_slotid || | ||
145 | tbl->highest_used_slotid == NFS4_NO_SLOT) | ||
146 | tbl->highest_used_slotid = slotid; | ||
147 | slot->generation = tbl->generation; | ||
148 | } | ||
149 | |||
150 | /* | ||
151 | * nfs4_try_to_lock_slot - Given a slot try to allocate it | ||
152 | * | ||
153 | * Note: must be called with the slot_tbl_lock held. | ||
154 | */ | ||
155 | bool nfs4_try_to_lock_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot) | ||
156 | { | ||
157 | if (nfs4_test_locked_slot(tbl, slot->slot_nr)) | ||
158 | return false; | ||
159 | nfs4_lock_slot(tbl, slot); | ||
160 | return true; | ||
161 | } | ||
162 | |||
163 | /* | ||
164 | * nfs4_lookup_slot - Find a slot but don't allocate it | ||
165 | * | ||
166 | * Note: must be called with the slot_tbl_lock held. | ||
167 | */ | ||
168 | struct nfs4_slot *nfs4_lookup_slot(struct nfs4_slot_table *tbl, u32 slotid) | ||
169 | { | ||
170 | if (slotid <= tbl->max_slotid) | ||
171 | return nfs4_find_or_create_slot(tbl, slotid, 1, GFP_NOWAIT); | ||
172 | return ERR_PTR(-E2BIG); | ||
173 | } | ||
174 | |||
138 | /* | 175 | /* |
139 | * nfs4_alloc_slot - efficiently look for a free slot | 176 | * nfs4_alloc_slot - efficiently look for a free slot |
140 | * | 177 | * |
@@ -153,18 +190,11 @@ struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl) | |||
153 | __func__, tbl->used_slots[0], tbl->highest_used_slotid, | 190 | __func__, tbl->used_slots[0], tbl->highest_used_slotid, |
154 | tbl->max_slotid + 1); | 191 | tbl->max_slotid + 1); |
155 | slotid = find_first_zero_bit(tbl->used_slots, tbl->max_slotid + 1); | 192 | slotid = find_first_zero_bit(tbl->used_slots, tbl->max_slotid + 1); |
156 | if (slotid > tbl->max_slotid) | 193 | if (slotid <= tbl->max_slotid) { |
157 | goto out; | 194 | ret = nfs4_find_or_create_slot(tbl, slotid, 1, GFP_NOWAIT); |
158 | ret = nfs4_find_or_create_slot(tbl, slotid, 1, GFP_NOWAIT); | 195 | if (!IS_ERR(ret)) |
159 | if (IS_ERR(ret)) | 196 | nfs4_lock_slot(tbl, ret); |
160 | goto out; | 197 | } |
161 | __set_bit(slotid, tbl->used_slots); | ||
162 | if (slotid > tbl->highest_used_slotid || | ||
163 | tbl->highest_used_slotid == NFS4_NO_SLOT) | ||
164 | tbl->highest_used_slotid = slotid; | ||
165 | ret->generation = tbl->generation; | ||
166 | |||
167 | out: | ||
168 | dprintk("<-- %s used_slots=%04lx highest_used=%u slotid=%u\n", | 198 | dprintk("<-- %s used_slots=%04lx highest_used=%u slotid=%u\n", |
169 | __func__, tbl->used_slots[0], tbl->highest_used_slotid, | 199 | __func__, tbl->used_slots[0], tbl->highest_used_slotid, |
170 | !IS_ERR(ret) ? ret->slot_nr : NFS4_NO_SLOT); | 200 | !IS_ERR(ret) ? ret->slot_nr : NFS4_NO_SLOT); |
diff --git a/fs/nfs/nfs4session.h b/fs/nfs/nfs4session.h index e3ea2c5324d6..5b51298d1d03 100644 --- a/fs/nfs/nfs4session.h +++ b/fs/nfs/nfs4session.h | |||
@@ -77,6 +77,8 @@ extern int nfs4_setup_slot_table(struct nfs4_slot_table *tbl, | |||
77 | unsigned int max_reqs, const char *queue); | 77 | unsigned int max_reqs, const char *queue); |
78 | extern void nfs4_shutdown_slot_table(struct nfs4_slot_table *tbl); | 78 | extern void nfs4_shutdown_slot_table(struct nfs4_slot_table *tbl); |
79 | extern struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl); | 79 | extern struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl); |
80 | extern struct nfs4_slot *nfs4_lookup_slot(struct nfs4_slot_table *tbl, u32 slotid); | ||
81 | extern bool nfs4_try_to_lock_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot); | ||
80 | extern void nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot); | 82 | extern void nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot); |
81 | extern void nfs4_slot_tbl_drain_complete(struct nfs4_slot_table *tbl); | 83 | extern void nfs4_slot_tbl_drain_complete(struct nfs4_slot_table *tbl); |
82 | bool nfs41_wake_and_assign_slot(struct nfs4_slot_table *tbl, | 84 | bool nfs41_wake_and_assign_slot(struct nfs4_slot_table *tbl, |
@@ -88,6 +90,12 @@ static inline bool nfs4_slot_tbl_draining(struct nfs4_slot_table *tbl) | |||
88 | return !!test_bit(NFS4_SLOT_TBL_DRAINING, &tbl->slot_tbl_state); | 90 | return !!test_bit(NFS4_SLOT_TBL_DRAINING, &tbl->slot_tbl_state); |
89 | } | 91 | } |
90 | 92 | ||
93 | static inline bool nfs4_test_locked_slot(const struct nfs4_slot_table *tbl, | ||
94 | u32 slotid) | ||
95 | { | ||
96 | return !!test_bit(slotid, tbl->used_slots); | ||
97 | } | ||
98 | |||
91 | #if defined(CONFIG_NFS_V4_1) | 99 | #if defined(CONFIG_NFS_V4_1) |
92 | extern void nfs41_set_target_slotid(struct nfs4_slot_table *tbl, | 100 | extern void nfs41_set_target_slotid(struct nfs4_slot_table *tbl, |
93 | u32 target_highest_slotid); | 101 | u32 target_highest_slotid); |