diff options
Diffstat (limited to 'fs/nfs/callback_proc.c')
-rw-r--r-- | fs/nfs/callback_proc.c | 69 |
1 files changed, 37 insertions, 32 deletions
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 | ||