diff options
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r-- | fs/nfs/nfs4proc.c | 633 |
1 files changed, 427 insertions, 206 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 741a562177fc..198d51d17c13 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -64,6 +64,7 @@ | |||
64 | 64 | ||
65 | struct nfs4_opendata; | 65 | struct nfs4_opendata; |
66 | static int _nfs4_proc_open(struct nfs4_opendata *data); | 66 | static int _nfs4_proc_open(struct nfs4_opendata *data); |
67 | static int _nfs4_recover_proc_open(struct nfs4_opendata *data); | ||
67 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); | 68 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); |
68 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *); | 69 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *); |
69 | static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr); | 70 | static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr); |
@@ -270,11 +271,18 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, | |||
270 | case -NFS4ERR_SEQ_MISORDERED: | 271 | case -NFS4ERR_SEQ_MISORDERED: |
271 | dprintk("%s ERROR: %d Reset session\n", __func__, | 272 | dprintk("%s ERROR: %d Reset session\n", __func__, |
272 | errorcode); | 273 | errorcode); |
273 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | 274 | nfs4_schedule_state_recovery(clp); |
274 | exception->retry = 1; | 275 | exception->retry = 1; |
275 | /* FALLTHROUGH */ | 276 | break; |
276 | #endif /* !defined(CONFIG_NFS_V4_1) */ | 277 | #endif /* !defined(CONFIG_NFS_V4_1) */ |
277 | case -NFS4ERR_FILE_OPEN: | 278 | case -NFS4ERR_FILE_OPEN: |
279 | if (exception->timeout > HZ) { | ||
280 | /* We have retried a decent amount, time to | ||
281 | * fail | ||
282 | */ | ||
283 | ret = -EBUSY; | ||
284 | break; | ||
285 | } | ||
278 | case -NFS4ERR_GRACE: | 286 | case -NFS4ERR_GRACE: |
279 | case -NFS4ERR_DELAY: | 287 | case -NFS4ERR_DELAY: |
280 | ret = nfs4_delay(server->client, &exception->timeout); | 288 | ret = nfs4_delay(server->client, &exception->timeout); |
@@ -311,48 +319,67 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp | |||
311 | * so we need to scan down from highest_used_slotid to 0 looking for the now | 319 | * so we need to scan down from highest_used_slotid to 0 looking for the now |
312 | * highest slotid in use. | 320 | * highest slotid in use. |
313 | * If none found, highest_used_slotid is set to -1. | 321 | * If none found, highest_used_slotid is set to -1. |
322 | * | ||
323 | * Must be called while holding tbl->slot_tbl_lock | ||
314 | */ | 324 | */ |
315 | static void | 325 | static void |
316 | nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid) | 326 | nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid) |
317 | { | 327 | { |
318 | int slotid = free_slotid; | 328 | int slotid = free_slotid; |
319 | 329 | ||
320 | spin_lock(&tbl->slot_tbl_lock); | ||
321 | /* clear used bit in bitmap */ | 330 | /* clear used bit in bitmap */ |
322 | __clear_bit(slotid, tbl->used_slots); | 331 | __clear_bit(slotid, tbl->used_slots); |
323 | 332 | ||
324 | /* update highest_used_slotid when it is freed */ | 333 | /* update highest_used_slotid when it is freed */ |
325 | if (slotid == tbl->highest_used_slotid) { | 334 | if (slotid == tbl->highest_used_slotid) { |
326 | slotid = find_last_bit(tbl->used_slots, tbl->max_slots); | 335 | slotid = find_last_bit(tbl->used_slots, tbl->max_slots); |
327 | if (slotid >= 0 && slotid < tbl->max_slots) | 336 | if (slotid < tbl->max_slots) |
328 | tbl->highest_used_slotid = slotid; | 337 | tbl->highest_used_slotid = slotid; |
329 | else | 338 | else |
330 | tbl->highest_used_slotid = -1; | 339 | tbl->highest_used_slotid = -1; |
331 | } | 340 | } |
332 | rpc_wake_up_next(&tbl->slot_tbl_waitq); | ||
333 | spin_unlock(&tbl->slot_tbl_lock); | ||
334 | dprintk("%s: free_slotid %u highest_used_slotid %d\n", __func__, | 341 | dprintk("%s: free_slotid %u highest_used_slotid %d\n", __func__, |
335 | free_slotid, tbl->highest_used_slotid); | 342 | free_slotid, tbl->highest_used_slotid); |
336 | } | 343 | } |
337 | 344 | ||
338 | void nfs41_sequence_free_slot(const struct nfs_client *clp, | 345 | /* |
339 | struct nfs4_sequence_res *res) | 346 | * Signal state manager thread if session is drained |
347 | */ | ||
348 | static void nfs41_check_drain_session_complete(struct nfs4_session *ses) | ||
340 | { | 349 | { |
341 | struct nfs4_slot_table *tbl; | 350 | struct rpc_task *task; |
342 | 351 | ||
343 | if (!nfs4_has_session(clp)) { | 352 | if (!test_bit(NFS4CLNT_SESSION_DRAINING, &ses->clp->cl_state)) { |
344 | dprintk("%s: No session\n", __func__); | 353 | task = rpc_wake_up_next(&ses->fc_slot_table.slot_tbl_waitq); |
354 | if (task) | ||
355 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | ||
345 | return; | 356 | return; |
346 | } | 357 | } |
358 | |||
359 | if (ses->fc_slot_table.highest_used_slotid != -1) | ||
360 | return; | ||
361 | |||
362 | dprintk("%s COMPLETE: Session Drained\n", __func__); | ||
363 | complete(&ses->complete); | ||
364 | } | ||
365 | |||
366 | static void nfs41_sequence_free_slot(const struct nfs_client *clp, | ||
367 | struct nfs4_sequence_res *res) | ||
368 | { | ||
369 | struct nfs4_slot_table *tbl; | ||
370 | |||
347 | tbl = &clp->cl_session->fc_slot_table; | 371 | tbl = &clp->cl_session->fc_slot_table; |
348 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) { | 372 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) { |
349 | dprintk("%s: No slot\n", __func__); | ||
350 | /* just wake up the next guy waiting since | 373 | /* just wake up the next guy waiting since |
351 | * we may have not consumed a slot after all */ | 374 | * we may have not consumed a slot after all */ |
352 | rpc_wake_up_next(&tbl->slot_tbl_waitq); | 375 | dprintk("%s: No slot\n", __func__); |
353 | return; | 376 | return; |
354 | } | 377 | } |
378 | |||
379 | spin_lock(&tbl->slot_tbl_lock); | ||
355 | nfs4_free_slot(tbl, res->sr_slotid); | 380 | nfs4_free_slot(tbl, res->sr_slotid); |
381 | nfs41_check_drain_session_complete(clp->cl_session); | ||
382 | spin_unlock(&tbl->slot_tbl_lock); | ||
356 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | 383 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; |
357 | } | 384 | } |
358 | 385 | ||
@@ -377,10 +404,10 @@ static void nfs41_sequence_done(struct nfs_client *clp, | |||
377 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) | 404 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) |
378 | goto out; | 405 | goto out; |
379 | 406 | ||
380 | tbl = &clp->cl_session->fc_slot_table; | 407 | /* Check the SEQUENCE operation status */ |
381 | slot = tbl->slots + res->sr_slotid; | ||
382 | |||
383 | if (res->sr_status == 0) { | 408 | if (res->sr_status == 0) { |
409 | tbl = &clp->cl_session->fc_slot_table; | ||
410 | slot = tbl->slots + res->sr_slotid; | ||
384 | /* Update the slot's sequence and clientid lease timer */ | 411 | /* Update the slot's sequence and clientid lease timer */ |
385 | ++slot->seq_nr; | 412 | ++slot->seq_nr; |
386 | timestamp = res->sr_renewal_time; | 413 | timestamp = res->sr_renewal_time; |
@@ -388,7 +415,8 @@ static void nfs41_sequence_done(struct nfs_client *clp, | |||
388 | if (time_before(clp->cl_last_renewal, timestamp)) | 415 | if (time_before(clp->cl_last_renewal, timestamp)) |
389 | clp->cl_last_renewal = timestamp; | 416 | clp->cl_last_renewal = timestamp; |
390 | spin_unlock(&clp->cl_lock); | 417 | spin_unlock(&clp->cl_lock); |
391 | return; | 418 | /* Check sequence flags */ |
419 | nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags); | ||
392 | } | 420 | } |
393 | out: | 421 | out: |
394 | /* The session may be reset by one of the error handlers. */ | 422 | /* The session may be reset by one of the error handlers. */ |
@@ -407,7 +435,7 @@ out: | |||
407 | * Note: must be called with under the slot_tbl_lock. | 435 | * Note: must be called with under the slot_tbl_lock. |
408 | */ | 436 | */ |
409 | static u8 | 437 | static u8 |
410 | nfs4_find_slot(struct nfs4_slot_table *tbl, struct rpc_task *task) | 438 | nfs4_find_slot(struct nfs4_slot_table *tbl) |
411 | { | 439 | { |
412 | int slotid; | 440 | int slotid; |
413 | u8 ret_id = NFS4_MAX_SLOT_TABLE; | 441 | u8 ret_id = NFS4_MAX_SLOT_TABLE; |
@@ -429,24 +457,6 @@ out: | |||
429 | return ret_id; | 457 | return ret_id; |
430 | } | 458 | } |
431 | 459 | ||
432 | static int nfs4_recover_session(struct nfs4_session *session) | ||
433 | { | ||
434 | struct nfs_client *clp = session->clp; | ||
435 | unsigned int loop; | ||
436 | int ret; | ||
437 | |||
438 | for (loop = NFS4_MAX_LOOP_ON_RECOVER; loop != 0; loop--) { | ||
439 | ret = nfs4_wait_clnt_recover(clp); | ||
440 | if (ret != 0) | ||
441 | break; | ||
442 | if (!test_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) | ||
443 | break; | ||
444 | nfs4_schedule_state_manager(clp); | ||
445 | ret = -EIO; | ||
446 | } | ||
447 | return ret; | ||
448 | } | ||
449 | |||
450 | static int nfs41_setup_sequence(struct nfs4_session *session, | 460 | static int nfs41_setup_sequence(struct nfs4_session *session, |
451 | struct nfs4_sequence_args *args, | 461 | struct nfs4_sequence_args *args, |
452 | struct nfs4_sequence_res *res, | 462 | struct nfs4_sequence_res *res, |
@@ -455,7 +465,6 @@ static int nfs41_setup_sequence(struct nfs4_session *session, | |||
455 | { | 465 | { |
456 | struct nfs4_slot *slot; | 466 | struct nfs4_slot *slot; |
457 | struct nfs4_slot_table *tbl; | 467 | struct nfs4_slot_table *tbl; |
458 | int status = 0; | ||
459 | u8 slotid; | 468 | u8 slotid; |
460 | 469 | ||
461 | dprintk("--> %s\n", __func__); | 470 | dprintk("--> %s\n", __func__); |
@@ -468,24 +477,27 @@ static int nfs41_setup_sequence(struct nfs4_session *session, | |||
468 | tbl = &session->fc_slot_table; | 477 | tbl = &session->fc_slot_table; |
469 | 478 | ||
470 | spin_lock(&tbl->slot_tbl_lock); | 479 | spin_lock(&tbl->slot_tbl_lock); |
471 | if (test_bit(NFS4CLNT_SESSION_SETUP, &session->clp->cl_state)) { | 480 | if (test_bit(NFS4CLNT_SESSION_DRAINING, &session->clp->cl_state) && |
472 | if (tbl->highest_used_slotid != -1) { | 481 | !rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) { |
473 | rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); | 482 | /* |
474 | spin_unlock(&tbl->slot_tbl_lock); | 483 | * The state manager will wait until the slot table is empty. |
475 | dprintk("<-- %s: Session reset: draining\n", __func__); | 484 | * Schedule the reset thread |
476 | return -EAGAIN; | 485 | */ |
477 | } | 486 | rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); |
487 | spin_unlock(&tbl->slot_tbl_lock); | ||
488 | dprintk("%s Schedule Session Reset\n", __func__); | ||
489 | return -EAGAIN; | ||
490 | } | ||
478 | 491 | ||
479 | /* The slot table is empty; start the reset thread */ | 492 | if (!rpc_queue_empty(&tbl->slot_tbl_waitq) && |
480 | dprintk("%s Session Reset\n", __func__); | 493 | !rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) { |
494 | rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); | ||
481 | spin_unlock(&tbl->slot_tbl_lock); | 495 | spin_unlock(&tbl->slot_tbl_lock); |
482 | status = nfs4_recover_session(session); | 496 | dprintk("%s enforce FIFO order\n", __func__); |
483 | if (status) | 497 | return -EAGAIN; |
484 | return status; | ||
485 | spin_lock(&tbl->slot_tbl_lock); | ||
486 | } | 498 | } |
487 | 499 | ||
488 | slotid = nfs4_find_slot(tbl, task); | 500 | slotid = nfs4_find_slot(tbl); |
489 | if (slotid == NFS4_MAX_SLOT_TABLE) { | 501 | if (slotid == NFS4_MAX_SLOT_TABLE) { |
490 | rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); | 502 | rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); |
491 | spin_unlock(&tbl->slot_tbl_lock); | 503 | spin_unlock(&tbl->slot_tbl_lock); |
@@ -494,6 +506,7 @@ static int nfs41_setup_sequence(struct nfs4_session *session, | |||
494 | } | 506 | } |
495 | spin_unlock(&tbl->slot_tbl_lock); | 507 | spin_unlock(&tbl->slot_tbl_lock); |
496 | 508 | ||
509 | rpc_task_set_priority(task, RPC_PRIORITY_NORMAL); | ||
497 | slot = tbl->slots + slotid; | 510 | slot = tbl->slots + slotid; |
498 | args->sa_session = session; | 511 | args->sa_session = session; |
499 | args->sa_slotid = slotid; | 512 | args->sa_slotid = slotid; |
@@ -527,7 +540,7 @@ int nfs4_setup_sequence(struct nfs_client *clp, | |||
527 | goto out; | 540 | goto out; |
528 | ret = nfs41_setup_sequence(clp->cl_session, args, res, cache_reply, | 541 | ret = nfs41_setup_sequence(clp->cl_session, args, res, cache_reply, |
529 | task); | 542 | task); |
530 | if (ret != -EAGAIN) { | 543 | if (ret && ret != -EAGAIN) { |
531 | /* terminate rpc task */ | 544 | /* terminate rpc task */ |
532 | task->tk_status = ret; | 545 | task->tk_status = ret; |
533 | task->tk_action = NULL; | 546 | task->tk_action = NULL; |
@@ -556,12 +569,17 @@ static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata) | |||
556 | rpc_call_start(task); | 569 | rpc_call_start(task); |
557 | } | 570 | } |
558 | 571 | ||
572 | static void nfs41_call_priv_sync_prepare(struct rpc_task *task, void *calldata) | ||
573 | { | ||
574 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | ||
575 | nfs41_call_sync_prepare(task, calldata); | ||
576 | } | ||
577 | |||
559 | static void nfs41_call_sync_done(struct rpc_task *task, void *calldata) | 578 | static void nfs41_call_sync_done(struct rpc_task *task, void *calldata) |
560 | { | 579 | { |
561 | struct nfs41_call_sync_data *data = calldata; | 580 | struct nfs41_call_sync_data *data = calldata; |
562 | 581 | ||
563 | nfs41_sequence_done(data->clp, data->seq_res, task->tk_status); | 582 | nfs41_sequence_done(data->clp, data->seq_res, task->tk_status); |
564 | nfs41_sequence_free_slot(data->clp, data->seq_res); | ||
565 | } | 583 | } |
566 | 584 | ||
567 | struct rpc_call_ops nfs41_call_sync_ops = { | 585 | struct rpc_call_ops nfs41_call_sync_ops = { |
@@ -569,12 +587,18 @@ struct rpc_call_ops nfs41_call_sync_ops = { | |||
569 | .rpc_call_done = nfs41_call_sync_done, | 587 | .rpc_call_done = nfs41_call_sync_done, |
570 | }; | 588 | }; |
571 | 589 | ||
590 | struct rpc_call_ops nfs41_call_priv_sync_ops = { | ||
591 | .rpc_call_prepare = nfs41_call_priv_sync_prepare, | ||
592 | .rpc_call_done = nfs41_call_sync_done, | ||
593 | }; | ||
594 | |||
572 | static int nfs4_call_sync_sequence(struct nfs_client *clp, | 595 | static int nfs4_call_sync_sequence(struct nfs_client *clp, |
573 | struct rpc_clnt *clnt, | 596 | struct rpc_clnt *clnt, |
574 | struct rpc_message *msg, | 597 | struct rpc_message *msg, |
575 | struct nfs4_sequence_args *args, | 598 | struct nfs4_sequence_args *args, |
576 | struct nfs4_sequence_res *res, | 599 | struct nfs4_sequence_res *res, |
577 | int cache_reply) | 600 | int cache_reply, |
601 | int privileged) | ||
578 | { | 602 | { |
579 | int ret; | 603 | int ret; |
580 | struct rpc_task *task; | 604 | struct rpc_task *task; |
@@ -592,6 +616,8 @@ static int nfs4_call_sync_sequence(struct nfs_client *clp, | |||
592 | }; | 616 | }; |
593 | 617 | ||
594 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | 618 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; |
619 | if (privileged) | ||
620 | task_setup.callback_ops = &nfs41_call_priv_sync_ops; | ||
595 | task = rpc_run_task(&task_setup); | 621 | task = rpc_run_task(&task_setup); |
596 | if (IS_ERR(task)) | 622 | if (IS_ERR(task)) |
597 | ret = PTR_ERR(task); | 623 | ret = PTR_ERR(task); |
@@ -609,7 +635,7 @@ int _nfs4_call_sync_session(struct nfs_server *server, | |||
609 | int cache_reply) | 635 | int cache_reply) |
610 | { | 636 | { |
611 | return nfs4_call_sync_sequence(server->nfs_client, server->client, | 637 | return nfs4_call_sync_sequence(server->nfs_client, server->client, |
612 | msg, args, res, cache_reply); | 638 | msg, args, res, cache_reply, 0); |
613 | } | 639 | } |
614 | 640 | ||
615 | #endif /* CONFIG_NFS_V4_1 */ | 641 | #endif /* CONFIG_NFS_V4_1 */ |
@@ -637,15 +663,6 @@ static void nfs4_sequence_done(const struct nfs_server *server, | |||
637 | #endif /* CONFIG_NFS_V4_1 */ | 663 | #endif /* CONFIG_NFS_V4_1 */ |
638 | } | 664 | } |
639 | 665 | ||
640 | /* no restart, therefore free slot here */ | ||
641 | static void nfs4_sequence_done_free_slot(const struct nfs_server *server, | ||
642 | struct nfs4_sequence_res *res, | ||
643 | int rpc_status) | ||
644 | { | ||
645 | nfs4_sequence_done(server, res, rpc_status); | ||
646 | nfs4_sequence_free_slot(server->nfs_client, res); | ||
647 | } | ||
648 | |||
649 | static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) | 666 | static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) |
650 | { | 667 | { |
651 | struct nfs_inode *nfsi = NFS_I(dir); | 668 | struct nfs_inode *nfsi = NFS_I(dir); |
@@ -720,9 +737,15 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, | |||
720 | p->o_arg.bitmask = server->attr_bitmask; | 737 | p->o_arg.bitmask = server->attr_bitmask; |
721 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; | 738 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; |
722 | if (flags & O_EXCL) { | 739 | if (flags & O_EXCL) { |
723 | u32 *s = (u32 *) p->o_arg.u.verifier.data; | 740 | if (nfs4_has_persistent_session(server->nfs_client)) { |
724 | s[0] = jiffies; | 741 | /* GUARDED */ |
725 | s[1] = current->pid; | 742 | p->o_arg.u.attrs = &p->attrs; |
743 | memcpy(&p->attrs, attrs, sizeof(p->attrs)); | ||
744 | } else { /* EXCLUSIVE4_1 */ | ||
745 | u32 *s = (u32 *) p->o_arg.u.verifier.data; | ||
746 | s[0] = jiffies; | ||
747 | s[1] = current->pid; | ||
748 | } | ||
726 | } else if (flags & O_CREAT) { | 749 | } else if (flags & O_CREAT) { |
727 | p->o_arg.u.attrs = &p->attrs; | 750 | p->o_arg.u.attrs = &p->attrs; |
728 | memcpy(&p->attrs, attrs, sizeof(p->attrs)); | 751 | memcpy(&p->attrs, attrs, sizeof(p->attrs)); |
@@ -776,13 +799,16 @@ static int can_open_cached(struct nfs4_state *state, fmode_t mode, int open_mode | |||
776 | goto out; | 799 | goto out; |
777 | switch (mode & (FMODE_READ|FMODE_WRITE)) { | 800 | switch (mode & (FMODE_READ|FMODE_WRITE)) { |
778 | case FMODE_READ: | 801 | case FMODE_READ: |
779 | ret |= test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0; | 802 | ret |= test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0 |
803 | && state->n_rdonly != 0; | ||
780 | break; | 804 | break; |
781 | case FMODE_WRITE: | 805 | case FMODE_WRITE: |
782 | ret |= test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0; | 806 | ret |= test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0 |
807 | && state->n_wronly != 0; | ||
783 | break; | 808 | break; |
784 | case FMODE_READ|FMODE_WRITE: | 809 | case FMODE_READ|FMODE_WRITE: |
785 | ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0; | 810 | ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0 |
811 | && state->n_rdwr != 0; | ||
786 | } | 812 | } |
787 | out: | 813 | out: |
788 | return ret; | 814 | return ret; |
@@ -1047,7 +1073,7 @@ static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, fmode_t fmod | |||
1047 | memset(&opendata->o_res, 0, sizeof(opendata->o_res)); | 1073 | memset(&opendata->o_res, 0, sizeof(opendata->o_res)); |
1048 | memset(&opendata->c_res, 0, sizeof(opendata->c_res)); | 1074 | memset(&opendata->c_res, 0, sizeof(opendata->c_res)); |
1049 | nfs4_init_opendata_res(opendata); | 1075 | nfs4_init_opendata_res(opendata); |
1050 | ret = _nfs4_proc_open(opendata); | 1076 | ret = _nfs4_recover_proc_open(opendata); |
1051 | if (ret != 0) | 1077 | if (ret != 0) |
1052 | return ret; | 1078 | return ret; |
1053 | newstate = nfs4_opendata_to_nfs4_state(opendata); | 1079 | newstate = nfs4_opendata_to_nfs4_state(opendata); |
@@ -1183,6 +1209,14 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state | |||
1183 | case -ENOENT: | 1209 | case -ENOENT: |
1184 | case -ESTALE: | 1210 | case -ESTALE: |
1185 | goto out; | 1211 | goto out; |
1212 | case -NFS4ERR_BADSESSION: | ||
1213 | case -NFS4ERR_BADSLOT: | ||
1214 | case -NFS4ERR_BAD_HIGH_SLOT: | ||
1215 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | ||
1216 | case -NFS4ERR_DEADSESSION: | ||
1217 | nfs4_schedule_state_recovery( | ||
1218 | server->nfs_client); | ||
1219 | goto out; | ||
1186 | case -NFS4ERR_STALE_CLIENTID: | 1220 | case -NFS4ERR_STALE_CLIENTID: |
1187 | case -NFS4ERR_STALE_STATEID: | 1221 | case -NFS4ERR_STALE_STATEID: |
1188 | case -NFS4ERR_EXPIRED: | 1222 | case -NFS4ERR_EXPIRED: |
@@ -1330,14 +1364,20 @@ out_no_action: | |||
1330 | 1364 | ||
1331 | } | 1365 | } |
1332 | 1366 | ||
1367 | static void nfs4_recover_open_prepare(struct rpc_task *task, void *calldata) | ||
1368 | { | ||
1369 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | ||
1370 | nfs4_open_prepare(task, calldata); | ||
1371 | } | ||
1372 | |||
1333 | static void nfs4_open_done(struct rpc_task *task, void *calldata) | 1373 | static void nfs4_open_done(struct rpc_task *task, void *calldata) |
1334 | { | 1374 | { |
1335 | struct nfs4_opendata *data = calldata; | 1375 | struct nfs4_opendata *data = calldata; |
1336 | 1376 | ||
1337 | data->rpc_status = task->tk_status; | 1377 | data->rpc_status = task->tk_status; |
1338 | 1378 | ||
1339 | nfs4_sequence_done_free_slot(data->o_arg.server, &data->o_res.seq_res, | 1379 | nfs4_sequence_done(data->o_arg.server, &data->o_res.seq_res, |
1340 | task->tk_status); | 1380 | task->tk_status); |
1341 | 1381 | ||
1342 | if (RPC_ASSASSINATED(task)) | 1382 | if (RPC_ASSASSINATED(task)) |
1343 | return; | 1383 | return; |
@@ -1388,10 +1428,13 @@ static const struct rpc_call_ops nfs4_open_ops = { | |||
1388 | .rpc_release = nfs4_open_release, | 1428 | .rpc_release = nfs4_open_release, |
1389 | }; | 1429 | }; |
1390 | 1430 | ||
1391 | /* | 1431 | static const struct rpc_call_ops nfs4_recover_open_ops = { |
1392 | * Note: On error, nfs4_proc_open will free the struct nfs4_opendata | 1432 | .rpc_call_prepare = nfs4_recover_open_prepare, |
1393 | */ | 1433 | .rpc_call_done = nfs4_open_done, |
1394 | static int _nfs4_proc_open(struct nfs4_opendata *data) | 1434 | .rpc_release = nfs4_open_release, |
1435 | }; | ||
1436 | |||
1437 | static int nfs4_run_open_task(struct nfs4_opendata *data, int isrecover) | ||
1395 | { | 1438 | { |
1396 | struct inode *dir = data->dir->d_inode; | 1439 | struct inode *dir = data->dir->d_inode; |
1397 | struct nfs_server *server = NFS_SERVER(dir); | 1440 | struct nfs_server *server = NFS_SERVER(dir); |
@@ -1418,21 +1461,57 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |||
1418 | data->rpc_done = 0; | 1461 | data->rpc_done = 0; |
1419 | data->rpc_status = 0; | 1462 | data->rpc_status = 0; |
1420 | data->cancelled = 0; | 1463 | data->cancelled = 0; |
1464 | if (isrecover) | ||
1465 | task_setup_data.callback_ops = &nfs4_recover_open_ops; | ||
1421 | task = rpc_run_task(&task_setup_data); | 1466 | task = rpc_run_task(&task_setup_data); |
1422 | if (IS_ERR(task)) | 1467 | if (IS_ERR(task)) |
1423 | return PTR_ERR(task); | 1468 | return PTR_ERR(task); |
1424 | status = nfs4_wait_for_completion_rpc_task(task); | 1469 | status = nfs4_wait_for_completion_rpc_task(task); |
1425 | if (status != 0) { | 1470 | if (status != 0) { |
1426 | data->cancelled = 1; | 1471 | data->cancelled = 1; |
1427 | smp_wmb(); | 1472 | smp_wmb(); |
1428 | } else | 1473 | } else |
1429 | status = data->rpc_status; | 1474 | status = data->rpc_status; |
1430 | rpc_put_task(task); | 1475 | rpc_put_task(task); |
1476 | |||
1477 | return status; | ||
1478 | } | ||
1479 | |||
1480 | static int _nfs4_recover_proc_open(struct nfs4_opendata *data) | ||
1481 | { | ||
1482 | struct inode *dir = data->dir->d_inode; | ||
1483 | struct nfs_openres *o_res = &data->o_res; | ||
1484 | int status; | ||
1485 | |||
1486 | status = nfs4_run_open_task(data, 1); | ||
1431 | if (status != 0 || !data->rpc_done) | 1487 | if (status != 0 || !data->rpc_done) |
1432 | return status; | 1488 | return status; |
1433 | 1489 | ||
1434 | if (o_res->fh.size == 0) | 1490 | nfs_refresh_inode(dir, o_res->dir_attr); |
1435 | _nfs4_proc_lookup(dir, o_arg->name, &o_res->fh, o_res->f_attr); | 1491 | |
1492 | if (o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { | ||
1493 | status = _nfs4_proc_open_confirm(data); | ||
1494 | if (status != 0) | ||
1495 | return status; | ||
1496 | } | ||
1497 | |||
1498 | return status; | ||
1499 | } | ||
1500 | |||
1501 | /* | ||
1502 | * Note: On error, nfs4_proc_open will free the struct nfs4_opendata | ||
1503 | */ | ||
1504 | static int _nfs4_proc_open(struct nfs4_opendata *data) | ||
1505 | { | ||
1506 | struct inode *dir = data->dir->d_inode; | ||
1507 | struct nfs_server *server = NFS_SERVER(dir); | ||
1508 | struct nfs_openargs *o_arg = &data->o_arg; | ||
1509 | struct nfs_openres *o_res = &data->o_res; | ||
1510 | int status; | ||
1511 | |||
1512 | status = nfs4_run_open_task(data, 0); | ||
1513 | if (status != 0 || !data->rpc_done) | ||
1514 | return status; | ||
1436 | 1515 | ||
1437 | if (o_arg->open_flags & O_CREAT) { | 1516 | if (o_arg->open_flags & O_CREAT) { |
1438 | update_changeattr(dir, &o_res->cinfo); | 1517 | update_changeattr(dir, &o_res->cinfo); |
@@ -1488,7 +1567,7 @@ static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *s | |||
1488 | return ret; | 1567 | return ret; |
1489 | } | 1568 | } |
1490 | 1569 | ||
1491 | static inline int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4_state *state) | 1570 | static int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4_state *state) |
1492 | { | 1571 | { |
1493 | struct nfs_server *server = NFS_SERVER(state->inode); | 1572 | struct nfs_server *server = NFS_SERVER(state->inode); |
1494 | struct nfs4_exception exception = { }; | 1573 | struct nfs4_exception exception = { }; |
@@ -1496,10 +1575,16 @@ static inline int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4 | |||
1496 | 1575 | ||
1497 | do { | 1576 | do { |
1498 | err = _nfs4_open_expired(ctx, state); | 1577 | err = _nfs4_open_expired(ctx, state); |
1499 | if (err != -NFS4ERR_DELAY) | 1578 | switch (err) { |
1500 | break; | 1579 | default: |
1501 | nfs4_handle_exception(server, err, &exception); | 1580 | goto out; |
1581 | case -NFS4ERR_GRACE: | ||
1582 | case -NFS4ERR_DELAY: | ||
1583 | nfs4_handle_exception(server, err, &exception); | ||
1584 | err = 0; | ||
1585 | } | ||
1502 | } while (exception.retry); | 1586 | } while (exception.retry); |
1587 | out: | ||
1503 | return err; | 1588 | return err; |
1504 | } | 1589 | } |
1505 | 1590 | ||
@@ -1712,6 +1797,18 @@ static void nfs4_free_closedata(void *data) | |||
1712 | kfree(calldata); | 1797 | kfree(calldata); |
1713 | } | 1798 | } |
1714 | 1799 | ||
1800 | static void nfs4_close_clear_stateid_flags(struct nfs4_state *state, | ||
1801 | fmode_t fmode) | ||
1802 | { | ||
1803 | spin_lock(&state->owner->so_lock); | ||
1804 | if (!(fmode & FMODE_READ)) | ||
1805 | clear_bit(NFS_O_RDONLY_STATE, &state->flags); | ||
1806 | if (!(fmode & FMODE_WRITE)) | ||
1807 | clear_bit(NFS_O_WRONLY_STATE, &state->flags); | ||
1808 | clear_bit(NFS_O_RDWR_STATE, &state->flags); | ||
1809 | spin_unlock(&state->owner->so_lock); | ||
1810 | } | ||
1811 | |||
1715 | static void nfs4_close_done(struct rpc_task *task, void *data) | 1812 | static void nfs4_close_done(struct rpc_task *task, void *data) |
1716 | { | 1813 | { |
1717 | struct nfs4_closedata *calldata = data; | 1814 | struct nfs4_closedata *calldata = data; |
@@ -1728,6 +1825,8 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
1728 | case 0: | 1825 | case 0: |
1729 | nfs_set_open_stateid(state, &calldata->res.stateid, 0); | 1826 | nfs_set_open_stateid(state, &calldata->res.stateid, 0); |
1730 | renew_lease(server, calldata->timestamp); | 1827 | renew_lease(server, calldata->timestamp); |
1828 | nfs4_close_clear_stateid_flags(state, | ||
1829 | calldata->arg.fmode); | ||
1731 | break; | 1830 | break; |
1732 | case -NFS4ERR_STALE_STATEID: | 1831 | case -NFS4ERR_STALE_STATEID: |
1733 | case -NFS4ERR_OLD_STATEID: | 1832 | case -NFS4ERR_OLD_STATEID: |
@@ -1736,12 +1835,10 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
1736 | if (calldata->arg.fmode == 0) | 1835 | if (calldata->arg.fmode == 0) |
1737 | break; | 1836 | break; |
1738 | default: | 1837 | default: |
1739 | if (nfs4_async_handle_error(task, server, state) == -EAGAIN) { | 1838 | if (nfs4_async_handle_error(task, server, state) == -EAGAIN) |
1740 | nfs4_restart_rpc(task, server->nfs_client); | 1839 | rpc_restart_call_prepare(task); |
1741 | return; | ||
1742 | } | ||
1743 | } | 1840 | } |
1744 | nfs4_sequence_free_slot(server->nfs_client, &calldata->res.seq_res); | 1841 | nfs_release_seqid(calldata->arg.seqid); |
1745 | nfs_refresh_inode(calldata->inode, calldata->res.fattr); | 1842 | nfs_refresh_inode(calldata->inode, calldata->res.fattr); |
1746 | } | 1843 | } |
1747 | 1844 | ||
@@ -1749,38 +1846,39 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
1749 | { | 1846 | { |
1750 | struct nfs4_closedata *calldata = data; | 1847 | struct nfs4_closedata *calldata = data; |
1751 | struct nfs4_state *state = calldata->state; | 1848 | struct nfs4_state *state = calldata->state; |
1752 | int clear_rd, clear_wr, clear_rdwr; | 1849 | int call_close = 0; |
1753 | 1850 | ||
1754 | if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) | 1851 | if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) |
1755 | return; | 1852 | return; |
1756 | 1853 | ||
1757 | clear_rd = clear_wr = clear_rdwr = 0; | 1854 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; |
1855 | calldata->arg.fmode = FMODE_READ|FMODE_WRITE; | ||
1758 | spin_lock(&state->owner->so_lock); | 1856 | spin_lock(&state->owner->so_lock); |
1759 | /* Calculate the change in open mode */ | 1857 | /* Calculate the change in open mode */ |
1760 | if (state->n_rdwr == 0) { | 1858 | if (state->n_rdwr == 0) { |
1761 | if (state->n_rdonly == 0) { | 1859 | if (state->n_rdonly == 0) { |
1762 | clear_rd |= test_and_clear_bit(NFS_O_RDONLY_STATE, &state->flags); | 1860 | call_close |= test_bit(NFS_O_RDONLY_STATE, &state->flags); |
1763 | clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags); | 1861 | call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags); |
1862 | calldata->arg.fmode &= ~FMODE_READ; | ||
1764 | } | 1863 | } |
1765 | if (state->n_wronly == 0) { | 1864 | if (state->n_wronly == 0) { |
1766 | clear_wr |= test_and_clear_bit(NFS_O_WRONLY_STATE, &state->flags); | 1865 | call_close |= test_bit(NFS_O_WRONLY_STATE, &state->flags); |
1767 | clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags); | 1866 | call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags); |
1867 | calldata->arg.fmode &= ~FMODE_WRITE; | ||
1768 | } | 1868 | } |
1769 | } | 1869 | } |
1770 | spin_unlock(&state->owner->so_lock); | 1870 | spin_unlock(&state->owner->so_lock); |
1771 | if (!clear_rd && !clear_wr && !clear_rdwr) { | 1871 | |
1872 | if (!call_close) { | ||
1772 | /* Note: exit _without_ calling nfs4_close_done */ | 1873 | /* Note: exit _without_ calling nfs4_close_done */ |
1773 | task->tk_action = NULL; | 1874 | task->tk_action = NULL; |
1774 | return; | 1875 | return; |
1775 | } | 1876 | } |
1877 | |||
1878 | if (calldata->arg.fmode == 0) | ||
1879 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE]; | ||
1880 | |||
1776 | nfs_fattr_init(calldata->res.fattr); | 1881 | nfs_fattr_init(calldata->res.fattr); |
1777 | if (test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0) { | ||
1778 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; | ||
1779 | calldata->arg.fmode = FMODE_READ; | ||
1780 | } else if (test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0) { | ||
1781 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; | ||
1782 | calldata->arg.fmode = FMODE_WRITE; | ||
1783 | } | ||
1784 | calldata->timestamp = jiffies; | 1882 | calldata->timestamp = jiffies; |
1785 | if (nfs4_setup_sequence((NFS_SERVER(calldata->inode))->nfs_client, | 1883 | if (nfs4_setup_sequence((NFS_SERVER(calldata->inode))->nfs_client, |
1786 | &calldata->arg.seq_args, &calldata->res.seq_res, | 1884 | &calldata->arg.seq_args, &calldata->res.seq_res, |
@@ -1832,8 +1930,6 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
1832 | calldata->state = state; | 1930 | calldata->state = state; |
1833 | calldata->arg.fh = NFS_FH(state->inode); | 1931 | calldata->arg.fh = NFS_FH(state->inode); |
1834 | calldata->arg.stateid = &state->open_stateid; | 1932 | calldata->arg.stateid = &state->open_stateid; |
1835 | if (nfs4_has_session(server->nfs_client)) | ||
1836 | memset(calldata->arg.stateid->data, 0, 4); /* clear seqid */ | ||
1837 | /* Serialization for the sequence id */ | 1933 | /* Serialization for the sequence id */ |
1838 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); | 1934 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); |
1839 | if (calldata->arg.seqid == NULL) | 1935 | if (calldata->arg.seqid == NULL) |
@@ -1981,7 +2077,7 @@ out_drop: | |||
1981 | return 0; | 2077 | return 0; |
1982 | } | 2078 | } |
1983 | 2079 | ||
1984 | void nfs4_close_context(struct nfs_open_context *ctx, int is_sync) | 2080 | static void nfs4_close_context(struct nfs_open_context *ctx, int is_sync) |
1985 | { | 2081 | { |
1986 | if (ctx->state == NULL) | 2082 | if (ctx->state == NULL) |
1987 | return; | 2083 | return; |
@@ -2532,7 +2628,6 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir) | |||
2532 | nfs4_sequence_done(res->server, &res->seq_res, task->tk_status); | 2628 | nfs4_sequence_done(res->server, &res->seq_res, task->tk_status); |
2533 | if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) | 2629 | if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) |
2534 | return 0; | 2630 | return 0; |
2535 | nfs4_sequence_free_slot(res->server->nfs_client, &res->seq_res); | ||
2536 | update_changeattr(dir, &res->cinfo); | 2631 | update_changeattr(dir, &res->cinfo); |
2537 | nfs_post_op_update_inode(dir, &res->dir_attr); | 2632 | nfs_post_op_update_inode(dir, &res->dir_attr); |
2538 | return 1; | 2633 | return 1; |
@@ -2971,11 +3066,10 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data) | |||
2971 | 3066 | ||
2972 | dprintk("--> %s\n", __func__); | 3067 | dprintk("--> %s\n", __func__); |
2973 | 3068 | ||
2974 | /* nfs4_sequence_free_slot called in the read rpc_call_done */ | ||
2975 | nfs4_sequence_done(server, &data->res.seq_res, task->tk_status); | 3069 | nfs4_sequence_done(server, &data->res.seq_res, task->tk_status); |
2976 | 3070 | ||
2977 | if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { | 3071 | if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { |
2978 | nfs4_restart_rpc(task, server->nfs_client); | 3072 | nfs_restart_rpc(task, server->nfs_client); |
2979 | return -EAGAIN; | 3073 | return -EAGAIN; |
2980 | } | 3074 | } |
2981 | 3075 | ||
@@ -2995,12 +3089,11 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) | |||
2995 | { | 3089 | { |
2996 | struct inode *inode = data->inode; | 3090 | struct inode *inode = data->inode; |
2997 | 3091 | ||
2998 | /* slot is freed in nfs_writeback_done */ | ||
2999 | nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res, | 3092 | nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res, |
3000 | task->tk_status); | 3093 | task->tk_status); |
3001 | 3094 | ||
3002 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { | 3095 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { |
3003 | nfs4_restart_rpc(task, NFS_SERVER(inode)->nfs_client); | 3096 | nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client); |
3004 | return -EAGAIN; | 3097 | return -EAGAIN; |
3005 | } | 3098 | } |
3006 | if (task->tk_status >= 0) { | 3099 | if (task->tk_status >= 0) { |
@@ -3028,11 +3121,9 @@ static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) | |||
3028 | nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res, | 3121 | nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res, |
3029 | task->tk_status); | 3122 | task->tk_status); |
3030 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { | 3123 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { |
3031 | nfs4_restart_rpc(task, NFS_SERVER(inode)->nfs_client); | 3124 | nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client); |
3032 | return -EAGAIN; | 3125 | return -EAGAIN; |
3033 | } | 3126 | } |
3034 | nfs4_sequence_free_slot(NFS_SERVER(inode)->nfs_client, | ||
3035 | &data->res.seq_res); | ||
3036 | nfs_refresh_inode(inode, data->res.fattr); | 3127 | nfs_refresh_inode(inode, data->res.fattr); |
3037 | return 0; | 3128 | return 0; |
3038 | } | 3129 | } |
@@ -3350,7 +3441,7 @@ _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
3350 | case -NFS4ERR_SEQ_MISORDERED: | 3441 | case -NFS4ERR_SEQ_MISORDERED: |
3351 | dprintk("%s ERROR %d, Reset session\n", __func__, | 3442 | dprintk("%s ERROR %d, Reset session\n", __func__, |
3352 | task->tk_status); | 3443 | task->tk_status); |
3353 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | 3444 | nfs4_schedule_state_recovery(clp); |
3354 | task->tk_status = 0; | 3445 | task->tk_status = 0; |
3355 | return -EAGAIN; | 3446 | return -EAGAIN; |
3356 | #endif /* CONFIG_NFS_V4_1 */ | 3447 | #endif /* CONFIG_NFS_V4_1 */ |
@@ -3483,12 +3574,23 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) | |||
3483 | { | 3574 | { |
3484 | struct nfs4_delegreturndata *data = calldata; | 3575 | struct nfs4_delegreturndata *data = calldata; |
3485 | 3576 | ||
3486 | nfs4_sequence_done_free_slot(data->res.server, &data->res.seq_res, | 3577 | nfs4_sequence_done(data->res.server, &data->res.seq_res, |
3487 | task->tk_status); | 3578 | task->tk_status); |
3488 | 3579 | ||
3489 | data->rpc_status = task->tk_status; | 3580 | switch (task->tk_status) { |
3490 | if (data->rpc_status == 0) | 3581 | case -NFS4ERR_STALE_STATEID: |
3582 | case -NFS4ERR_EXPIRED: | ||
3583 | case 0: | ||
3491 | renew_lease(data->res.server, data->timestamp); | 3584 | renew_lease(data->res.server, data->timestamp); |
3585 | break; | ||
3586 | default: | ||
3587 | if (nfs4_async_handle_error(task, data->res.server, NULL) == | ||
3588 | -EAGAIN) { | ||
3589 | nfs_restart_rpc(task, data->res.server->nfs_client); | ||
3590 | return; | ||
3591 | } | ||
3592 | } | ||
3593 | data->rpc_status = task->tk_status; | ||
3492 | } | 3594 | } |
3493 | 3595 | ||
3494 | static void nfs4_delegreturn_release(void *calldata) | 3596 | static void nfs4_delegreturn_release(void *calldata) |
@@ -3741,11 +3843,9 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
3741 | break; | 3843 | break; |
3742 | default: | 3844 | default: |
3743 | if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN) | 3845 | if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN) |
3744 | nfs4_restart_rpc(task, | 3846 | nfs_restart_rpc(task, |
3745 | calldata->server->nfs_client); | 3847 | calldata->server->nfs_client); |
3746 | } | 3848 | } |
3747 | nfs4_sequence_free_slot(calldata->server->nfs_client, | ||
3748 | &calldata->res.seq_res); | ||
3749 | } | 3849 | } |
3750 | 3850 | ||
3751 | static void nfs4_locku_prepare(struct rpc_task *task, void *data) | 3851 | static void nfs4_locku_prepare(struct rpc_task *task, void *data) |
@@ -3921,14 +4021,20 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) | |||
3921 | dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status); | 4021 | dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status); |
3922 | } | 4022 | } |
3923 | 4023 | ||
4024 | static void nfs4_recover_lock_prepare(struct rpc_task *task, void *calldata) | ||
4025 | { | ||
4026 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | ||
4027 | nfs4_lock_prepare(task, calldata); | ||
4028 | } | ||
4029 | |||
3924 | static void nfs4_lock_done(struct rpc_task *task, void *calldata) | 4030 | static void nfs4_lock_done(struct rpc_task *task, void *calldata) |
3925 | { | 4031 | { |
3926 | struct nfs4_lockdata *data = calldata; | 4032 | struct nfs4_lockdata *data = calldata; |
3927 | 4033 | ||
3928 | dprintk("%s: begin!\n", __func__); | 4034 | dprintk("%s: begin!\n", __func__); |
3929 | 4035 | ||
3930 | nfs4_sequence_done_free_slot(data->server, &data->res.seq_res, | 4036 | nfs4_sequence_done(data->server, &data->res.seq_res, |
3931 | task->tk_status); | 4037 | task->tk_status); |
3932 | 4038 | ||
3933 | data->rpc_status = task->tk_status; | 4039 | data->rpc_status = task->tk_status; |
3934 | if (RPC_ASSASSINATED(task)) | 4040 | if (RPC_ASSASSINATED(task)) |
@@ -3976,7 +4082,13 @@ static const struct rpc_call_ops nfs4_lock_ops = { | |||
3976 | .rpc_release = nfs4_lock_release, | 4082 | .rpc_release = nfs4_lock_release, |
3977 | }; | 4083 | }; |
3978 | 4084 | ||
3979 | static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *fl, int reclaim) | 4085 | static const struct rpc_call_ops nfs4_recover_lock_ops = { |
4086 | .rpc_call_prepare = nfs4_recover_lock_prepare, | ||
4087 | .rpc_call_done = nfs4_lock_done, | ||
4088 | .rpc_release = nfs4_lock_release, | ||
4089 | }; | ||
4090 | |||
4091 | static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *fl, int recovery_type) | ||
3980 | { | 4092 | { |
3981 | struct nfs4_lockdata *data; | 4093 | struct nfs4_lockdata *data; |
3982 | struct rpc_task *task; | 4094 | struct rpc_task *task; |
@@ -4000,8 +4112,11 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f | |||
4000 | return -ENOMEM; | 4112 | return -ENOMEM; |
4001 | if (IS_SETLKW(cmd)) | 4113 | if (IS_SETLKW(cmd)) |
4002 | data->arg.block = 1; | 4114 | data->arg.block = 1; |
4003 | if (reclaim != 0) | 4115 | if (recovery_type > NFS_LOCK_NEW) { |
4004 | data->arg.reclaim = 1; | 4116 | if (recovery_type == NFS_LOCK_RECLAIM) |
4117 | data->arg.reclaim = NFS_LOCK_RECLAIM; | ||
4118 | task_setup_data.callback_ops = &nfs4_recover_lock_ops; | ||
4119 | } | ||
4005 | msg.rpc_argp = &data->arg, | 4120 | msg.rpc_argp = &data->arg, |
4006 | msg.rpc_resp = &data->res, | 4121 | msg.rpc_resp = &data->res, |
4007 | task_setup_data.callback_data = data; | 4122 | task_setup_data.callback_data = data; |
@@ -4028,7 +4143,7 @@ static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request | |||
4028 | /* Cache the lock if possible... */ | 4143 | /* Cache the lock if possible... */ |
4029 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0) | 4144 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0) |
4030 | return 0; | 4145 | return 0; |
4031 | err = _nfs4_do_setlk(state, F_SETLK, request, 1); | 4146 | err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_RECLAIM); |
4032 | if (err != -NFS4ERR_DELAY) | 4147 | if (err != -NFS4ERR_DELAY) |
4033 | break; | 4148 | break; |
4034 | nfs4_handle_exception(server, err, &exception); | 4149 | nfs4_handle_exception(server, err, &exception); |
@@ -4048,11 +4163,17 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request | |||
4048 | do { | 4163 | do { |
4049 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0) | 4164 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0) |
4050 | return 0; | 4165 | return 0; |
4051 | err = _nfs4_do_setlk(state, F_SETLK, request, 0); | 4166 | err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_EXPIRED); |
4052 | if (err != -NFS4ERR_DELAY) | 4167 | switch (err) { |
4053 | break; | 4168 | default: |
4054 | nfs4_handle_exception(server, err, &exception); | 4169 | goto out; |
4170 | case -NFS4ERR_GRACE: | ||
4171 | case -NFS4ERR_DELAY: | ||
4172 | nfs4_handle_exception(server, err, &exception); | ||
4173 | err = 0; | ||
4174 | } | ||
4055 | } while (exception.retry); | 4175 | } while (exception.retry); |
4176 | out: | ||
4056 | return err; | 4177 | return err; |
4057 | } | 4178 | } |
4058 | 4179 | ||
@@ -4078,7 +4199,7 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock | |||
4078 | status = do_vfs_lock(request->fl_file, request); | 4199 | status = do_vfs_lock(request->fl_file, request); |
4079 | goto out_unlock; | 4200 | goto out_unlock; |
4080 | } | 4201 | } |
4081 | status = _nfs4_do_setlk(state, cmd, request, 0); | 4202 | status = _nfs4_do_setlk(state, cmd, request, NFS_LOCK_NEW); |
4082 | if (status != 0) | 4203 | if (status != 0) |
4083 | goto out_unlock; | 4204 | goto out_unlock; |
4084 | /* Note: we always want to sleep here! */ | 4205 | /* Note: we always want to sleep here! */ |
@@ -4161,7 +4282,7 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl) | |||
4161 | if (err != 0) | 4282 | if (err != 0) |
4162 | goto out; | 4283 | goto out; |
4163 | do { | 4284 | do { |
4164 | err = _nfs4_do_setlk(state, F_SETLK, fl, 0); | 4285 | err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW); |
4165 | switch (err) { | 4286 | switch (err) { |
4166 | default: | 4287 | default: |
4167 | printk(KERN_ERR "%s: unhandled error %d.\n", | 4288 | printk(KERN_ERR "%s: unhandled error %d.\n", |
@@ -4172,6 +4293,11 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl) | |||
4172 | case -NFS4ERR_EXPIRED: | 4293 | case -NFS4ERR_EXPIRED: |
4173 | case -NFS4ERR_STALE_CLIENTID: | 4294 | case -NFS4ERR_STALE_CLIENTID: |
4174 | case -NFS4ERR_STALE_STATEID: | 4295 | case -NFS4ERR_STALE_STATEID: |
4296 | case -NFS4ERR_BADSESSION: | ||
4297 | case -NFS4ERR_BADSLOT: | ||
4298 | case -NFS4ERR_BAD_HIGH_SLOT: | ||
4299 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | ||
4300 | case -NFS4ERR_DEADSESSION: | ||
4175 | nfs4_schedule_state_recovery(server->nfs_client); | 4301 | nfs4_schedule_state_recovery(server->nfs_client); |
4176 | goto out; | 4302 | goto out; |
4177 | case -ERESTARTSYS: | 4303 | case -ERESTARTSYS: |
@@ -4296,7 +4422,7 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | |||
4296 | * NFS4ERR_BADSESSION in the sequence operation, and will therefore | 4422 | * NFS4ERR_BADSESSION in the sequence operation, and will therefore |
4297 | * be in some phase of session reset. | 4423 | * be in some phase of session reset. |
4298 | */ | 4424 | */ |
4299 | static int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) | 4425 | int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) |
4300 | { | 4426 | { |
4301 | nfs4_verifier verifier; | 4427 | nfs4_verifier verifier; |
4302 | struct nfs41_exchange_id_args args = { | 4428 | struct nfs41_exchange_id_args args = { |
@@ -4318,6 +4444,9 @@ static int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) | |||
4318 | dprintk("--> %s\n", __func__); | 4444 | dprintk("--> %s\n", __func__); |
4319 | BUG_ON(clp == NULL); | 4445 | BUG_ON(clp == NULL); |
4320 | 4446 | ||
4447 | /* Remove server-only flags */ | ||
4448 | args.flags &= ~EXCHGID4_FLAG_CONFIRMED_R; | ||
4449 | |||
4321 | p = (u32 *)verifier.data; | 4450 | p = (u32 *)verifier.data; |
4322 | *p++ = htonl((u32)clp->cl_boot_time.tv_sec); | 4451 | *p++ = htonl((u32)clp->cl_boot_time.tv_sec); |
4323 | *p = htonl((u32)clp->cl_boot_time.tv_nsec); | 4452 | *p = htonl((u32)clp->cl_boot_time.tv_nsec); |
@@ -4361,11 +4490,12 @@ static void nfs4_get_lease_time_prepare(struct rpc_task *task, | |||
4361 | (struct nfs4_get_lease_time_data *)calldata; | 4490 | (struct nfs4_get_lease_time_data *)calldata; |
4362 | 4491 | ||
4363 | dprintk("--> %s\n", __func__); | 4492 | dprintk("--> %s\n", __func__); |
4493 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | ||
4364 | /* just setup sequence, do not trigger session recovery | 4494 | /* just setup sequence, do not trigger session recovery |
4365 | since we're invoked within one */ | 4495 | since we're invoked within one */ |
4366 | ret = nfs41_setup_sequence(data->clp->cl_session, | 4496 | ret = nfs41_setup_sequence(data->clp->cl_session, |
4367 | &data->args->la_seq_args, | 4497 | &data->args->la_seq_args, |
4368 | &data->res->lr_seq_res, 0, task); | 4498 | &data->res->lr_seq_res, 0, task); |
4369 | 4499 | ||
4370 | BUG_ON(ret == -EAGAIN); | 4500 | BUG_ON(ret == -EAGAIN); |
4371 | rpc_call_start(task); | 4501 | rpc_call_start(task); |
@@ -4389,10 +4519,9 @@ static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata) | |||
4389 | dprintk("%s Retry: tk_status %d\n", __func__, task->tk_status); | 4519 | dprintk("%s Retry: tk_status %d\n", __func__, task->tk_status); |
4390 | rpc_delay(task, NFS4_POLL_RETRY_MIN); | 4520 | rpc_delay(task, NFS4_POLL_RETRY_MIN); |
4391 | task->tk_status = 0; | 4521 | task->tk_status = 0; |
4392 | nfs4_restart_rpc(task, data->clp); | 4522 | nfs_restart_rpc(task, data->clp); |
4393 | return; | 4523 | return; |
4394 | } | 4524 | } |
4395 | nfs41_sequence_free_slot(data->clp, &data->res->lr_seq_res); | ||
4396 | dprintk("<-- %s\n", __func__); | 4525 | dprintk("<-- %s\n", __func__); |
4397 | } | 4526 | } |
4398 | 4527 | ||
@@ -4465,7 +4594,6 @@ static int nfs4_reset_slot_table(struct nfs4_slot_table *tbl, int max_slots, | |||
4465 | spin_lock(&tbl->slot_tbl_lock); | 4594 | spin_lock(&tbl->slot_tbl_lock); |
4466 | for (i = 0; i < max_slots; ++i) | 4595 | for (i = 0; i < max_slots; ++i) |
4467 | tbl->slots[i].seq_nr = ivalue; | 4596 | tbl->slots[i].seq_nr = ivalue; |
4468 | tbl->highest_used_slotid = -1; | ||
4469 | spin_unlock(&tbl->slot_tbl_lock); | 4597 | spin_unlock(&tbl->slot_tbl_lock); |
4470 | dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, | 4598 | dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, |
4471 | tbl, tbl->slots, tbl->max_slots); | 4599 | tbl, tbl->slots, tbl->max_slots); |
@@ -4515,7 +4643,6 @@ static void nfs4_destroy_slot_tables(struct nfs4_session *session) | |||
4515 | static int nfs4_init_slot_table(struct nfs4_slot_table *tbl, | 4643 | static int nfs4_init_slot_table(struct nfs4_slot_table *tbl, |
4516 | int max_slots, int ivalue) | 4644 | int max_slots, int ivalue) |
4517 | { | 4645 | { |
4518 | int i; | ||
4519 | struct nfs4_slot *slot; | 4646 | struct nfs4_slot *slot; |
4520 | int ret = -ENOMEM; | 4647 | int ret = -ENOMEM; |
4521 | 4648 | ||
@@ -4526,18 +4653,9 @@ static int nfs4_init_slot_table(struct nfs4_slot_table *tbl, | |||
4526 | slot = kcalloc(max_slots, sizeof(struct nfs4_slot), GFP_KERNEL); | 4653 | slot = kcalloc(max_slots, sizeof(struct nfs4_slot), GFP_KERNEL); |
4527 | if (!slot) | 4654 | if (!slot) |
4528 | goto out; | 4655 | goto out; |
4529 | for (i = 0; i < max_slots; ++i) | ||
4530 | slot[i].seq_nr = ivalue; | ||
4531 | ret = 0; | 4656 | ret = 0; |
4532 | 4657 | ||
4533 | spin_lock(&tbl->slot_tbl_lock); | 4658 | spin_lock(&tbl->slot_tbl_lock); |
4534 | if (tbl->slots != NULL) { | ||
4535 | spin_unlock(&tbl->slot_tbl_lock); | ||
4536 | dprintk("%s: slot table already initialized. tbl=%p slots=%p\n", | ||
4537 | __func__, tbl, tbl->slots); | ||
4538 | WARN_ON(1); | ||
4539 | goto out_free; | ||
4540 | } | ||
4541 | tbl->max_slots = max_slots; | 4659 | tbl->max_slots = max_slots; |
4542 | tbl->slots = slot; | 4660 | tbl->slots = slot; |
4543 | tbl->highest_used_slotid = -1; /* no slot is currently used */ | 4661 | tbl->highest_used_slotid = -1; /* no slot is currently used */ |
@@ -4547,10 +4665,6 @@ static int nfs4_init_slot_table(struct nfs4_slot_table *tbl, | |||
4547 | out: | 4665 | out: |
4548 | dprintk("<-- %s: return %d\n", __func__, ret); | 4666 | dprintk("<-- %s: return %d\n", __func__, ret); |
4549 | return ret; | 4667 | return ret; |
4550 | |||
4551 | out_free: | ||
4552 | kfree(slot); | ||
4553 | goto out; | ||
4554 | } | 4668 | } |
4555 | 4669 | ||
4556 | /* | 4670 | /* |
@@ -4558,17 +4672,24 @@ out_free: | |||
4558 | */ | 4672 | */ |
4559 | static int nfs4_init_slot_tables(struct nfs4_session *session) | 4673 | static int nfs4_init_slot_tables(struct nfs4_session *session) |
4560 | { | 4674 | { |
4561 | int status; | 4675 | struct nfs4_slot_table *tbl; |
4676 | int status = 0; | ||
4562 | 4677 | ||
4563 | status = nfs4_init_slot_table(&session->fc_slot_table, | 4678 | tbl = &session->fc_slot_table; |
4564 | session->fc_attrs.max_reqs, 1); | 4679 | if (tbl->slots == NULL) { |
4565 | if (status) | 4680 | status = nfs4_init_slot_table(tbl, |
4566 | return status; | 4681 | session->fc_attrs.max_reqs, 1); |
4682 | if (status) | ||
4683 | return status; | ||
4684 | } | ||
4567 | 4685 | ||
4568 | status = nfs4_init_slot_table(&session->bc_slot_table, | 4686 | tbl = &session->bc_slot_table; |
4569 | session->bc_attrs.max_reqs, 0); | 4687 | if (tbl->slots == NULL) { |
4570 | if (status) | 4688 | status = nfs4_init_slot_table(tbl, |
4571 | nfs4_destroy_slot_tables(session); | 4689 | session->bc_attrs.max_reqs, 0); |
4690 | if (status) | ||
4691 | nfs4_destroy_slot_tables(session); | ||
4692 | } | ||
4572 | 4693 | ||
4573 | return status; | 4694 | return status; |
4574 | } | 4695 | } |
@@ -4582,7 +4703,6 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp) | |||
4582 | if (!session) | 4703 | if (!session) |
4583 | return NULL; | 4704 | return NULL; |
4584 | 4705 | ||
4585 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
4586 | /* | 4706 | /* |
4587 | * The create session reply races with the server back | 4707 | * The create session reply races with the server back |
4588 | * channel probe. Mark the client NFS_CS_SESSION_INITING | 4708 | * channel probe. Mark the client NFS_CS_SESSION_INITING |
@@ -4590,12 +4710,15 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp) | |||
4590 | * nfs_client struct | 4710 | * nfs_client struct |
4591 | */ | 4711 | */ |
4592 | clp->cl_cons_state = NFS_CS_SESSION_INITING; | 4712 | clp->cl_cons_state = NFS_CS_SESSION_INITING; |
4713 | init_completion(&session->complete); | ||
4593 | 4714 | ||
4594 | tbl = &session->fc_slot_table; | 4715 | tbl = &session->fc_slot_table; |
4716 | tbl->highest_used_slotid = -1; | ||
4595 | spin_lock_init(&tbl->slot_tbl_lock); | 4717 | spin_lock_init(&tbl->slot_tbl_lock); |
4596 | rpc_init_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table"); | 4718 | rpc_init_priority_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table"); |
4597 | 4719 | ||
4598 | tbl = &session->bc_slot_table; | 4720 | tbl = &session->bc_slot_table; |
4721 | tbl->highest_used_slotid = -1; | ||
4599 | spin_lock_init(&tbl->slot_tbl_lock); | 4722 | spin_lock_init(&tbl->slot_tbl_lock); |
4600 | rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table"); | 4723 | rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table"); |
4601 | 4724 | ||
@@ -4747,11 +4870,10 @@ static int _nfs4_proc_create_session(struct nfs_client *clp) | |||
4747 | * It is the responsibility of the caller to verify the session is | 4870 | * It is the responsibility of the caller to verify the session is |
4748 | * expired before calling this routine. | 4871 | * expired before calling this routine. |
4749 | */ | 4872 | */ |
4750 | int nfs4_proc_create_session(struct nfs_client *clp, int reset) | 4873 | int nfs4_proc_create_session(struct nfs_client *clp) |
4751 | { | 4874 | { |
4752 | int status; | 4875 | int status; |
4753 | unsigned *ptr; | 4876 | unsigned *ptr; |
4754 | struct nfs_fsinfo fsinfo; | ||
4755 | struct nfs4_session *session = clp->cl_session; | 4877 | struct nfs4_session *session = clp->cl_session; |
4756 | 4878 | ||
4757 | dprintk("--> %s clp=%p session=%p\n", __func__, clp, session); | 4879 | dprintk("--> %s clp=%p session=%p\n", __func__, clp, session); |
@@ -4760,35 +4882,19 @@ int nfs4_proc_create_session(struct nfs_client *clp, int reset) | |||
4760 | if (status) | 4882 | if (status) |
4761 | goto out; | 4883 | goto out; |
4762 | 4884 | ||
4763 | /* Init or reset the fore channel */ | 4885 | /* Init and reset the fore channel */ |
4764 | if (reset) | 4886 | status = nfs4_init_slot_tables(session); |
4765 | status = nfs4_reset_slot_tables(session); | 4887 | dprintk("slot table initialization returned %d\n", status); |
4766 | else | 4888 | if (status) |
4767 | status = nfs4_init_slot_tables(session); | 4889 | goto out; |
4768 | dprintk("fore channel slot table initialization returned %d\n", status); | 4890 | status = nfs4_reset_slot_tables(session); |
4891 | dprintk("slot table reset returned %d\n", status); | ||
4769 | if (status) | 4892 | if (status) |
4770 | goto out; | 4893 | goto out; |
4771 | 4894 | ||
4772 | ptr = (unsigned *)&session->sess_id.data[0]; | 4895 | ptr = (unsigned *)&session->sess_id.data[0]; |
4773 | dprintk("%s client>seqid %d sessionid %u:%u:%u:%u\n", __func__, | 4896 | dprintk("%s client>seqid %d sessionid %u:%u:%u:%u\n", __func__, |
4774 | clp->cl_seqid, ptr[0], ptr[1], ptr[2], ptr[3]); | 4897 | clp->cl_seqid, ptr[0], ptr[1], ptr[2], ptr[3]); |
4775 | |||
4776 | if (reset) | ||
4777 | /* Lease time is aleady set */ | ||
4778 | goto out; | ||
4779 | |||
4780 | /* Get the lease time */ | ||
4781 | status = nfs4_proc_get_lease_time(clp, &fsinfo); | ||
4782 | if (status == 0) { | ||
4783 | /* Update lease time and schedule renewal */ | ||
4784 | spin_lock(&clp->cl_lock); | ||
4785 | clp->cl_lease_time = fsinfo.lease_time * HZ; | ||
4786 | clp->cl_last_renewal = jiffies; | ||
4787 | clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
4788 | spin_unlock(&clp->cl_lock); | ||
4789 | |||
4790 | nfs4_schedule_state_renewal(clp); | ||
4791 | } | ||
4792 | out: | 4898 | out: |
4793 | dprintk("<-- %s\n", __func__); | 4899 | dprintk("<-- %s\n", __func__); |
4794 | return status; | 4900 | return status; |
@@ -4827,13 +4933,24 @@ int nfs4_proc_destroy_session(struct nfs4_session *session) | |||
4827 | int nfs4_init_session(struct nfs_server *server) | 4933 | int nfs4_init_session(struct nfs_server *server) |
4828 | { | 4934 | { |
4829 | struct nfs_client *clp = server->nfs_client; | 4935 | struct nfs_client *clp = server->nfs_client; |
4936 | struct nfs4_session *session; | ||
4937 | unsigned int rsize, wsize; | ||
4830 | int ret; | 4938 | int ret; |
4831 | 4939 | ||
4832 | if (!nfs4_has_session(clp)) | 4940 | if (!nfs4_has_session(clp)) |
4833 | return 0; | 4941 | return 0; |
4834 | 4942 | ||
4835 | clp->cl_session->fc_attrs.max_rqst_sz = server->wsize; | 4943 | rsize = server->rsize; |
4836 | clp->cl_session->fc_attrs.max_resp_sz = server->rsize; | 4944 | if (rsize == 0) |
4945 | rsize = NFS_MAX_FILE_IO_SIZE; | ||
4946 | wsize = server->wsize; | ||
4947 | if (wsize == 0) | ||
4948 | wsize = NFS_MAX_FILE_IO_SIZE; | ||
4949 | |||
4950 | session = clp->cl_session; | ||
4951 | session->fc_attrs.max_rqst_sz = wsize + nfs41_maxwrite_overhead; | ||
4952 | session->fc_attrs.max_resp_sz = rsize + nfs41_maxread_overhead; | ||
4953 | |||
4837 | ret = nfs4_recover_expired_lease(server); | 4954 | ret = nfs4_recover_expired_lease(server); |
4838 | if (!ret) | 4955 | if (!ret) |
4839 | ret = nfs4_check_client_ready(clp); | 4956 | ret = nfs4_check_client_ready(clp); |
@@ -4858,7 +4975,7 @@ static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred) | |||
4858 | args.sa_cache_this = 0; | 4975 | args.sa_cache_this = 0; |
4859 | 4976 | ||
4860 | return nfs4_call_sync_sequence(clp, clp->cl_rpcclient, &msg, &args, | 4977 | return nfs4_call_sync_sequence(clp, clp->cl_rpcclient, &msg, &args, |
4861 | &res, 0); | 4978 | &res, args.sa_cache_this, 1); |
4862 | } | 4979 | } |
4863 | 4980 | ||
4864 | void nfs41_sequence_call_done(struct rpc_task *task, void *data) | 4981 | void nfs41_sequence_call_done(struct rpc_task *task, void *data) |
@@ -4872,11 +4989,10 @@ void nfs41_sequence_call_done(struct rpc_task *task, void *data) | |||
4872 | 4989 | ||
4873 | if (_nfs4_async_handle_error(task, NULL, clp, NULL) | 4990 | if (_nfs4_async_handle_error(task, NULL, clp, NULL) |
4874 | == -EAGAIN) { | 4991 | == -EAGAIN) { |
4875 | nfs4_restart_rpc(task, clp); | 4992 | nfs_restart_rpc(task, clp); |
4876 | return; | 4993 | return; |
4877 | } | 4994 | } |
4878 | } | 4995 | } |
4879 | nfs41_sequence_free_slot(clp, task->tk_msg.rpc_resp); | ||
4880 | dprintk("%s rpc_cred %p\n", __func__, task->tk_msg.rpc_cred); | 4996 | dprintk("%s rpc_cred %p\n", __func__, task->tk_msg.rpc_cred); |
4881 | 4997 | ||
4882 | kfree(task->tk_msg.rpc_argp); | 4998 | kfree(task->tk_msg.rpc_argp); |
@@ -4931,6 +5047,110 @@ static int nfs41_proc_async_sequence(struct nfs_client *clp, | |||
4931 | &nfs41_sequence_ops, (void *)clp); | 5047 | &nfs41_sequence_ops, (void *)clp); |
4932 | } | 5048 | } |
4933 | 5049 | ||
5050 | struct nfs4_reclaim_complete_data { | ||
5051 | struct nfs_client *clp; | ||
5052 | struct nfs41_reclaim_complete_args arg; | ||
5053 | struct nfs41_reclaim_complete_res res; | ||
5054 | }; | ||
5055 | |||
5056 | static void nfs4_reclaim_complete_prepare(struct rpc_task *task, void *data) | ||
5057 | { | ||
5058 | struct nfs4_reclaim_complete_data *calldata = data; | ||
5059 | |||
5060 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | ||
5061 | if (nfs4_setup_sequence(calldata->clp, &calldata->arg.seq_args, | ||
5062 | &calldata->res.seq_res, 0, task)) | ||
5063 | return; | ||
5064 | |||
5065 | rpc_call_start(task); | ||
5066 | } | ||
5067 | |||
5068 | static void nfs4_reclaim_complete_done(struct rpc_task *task, void *data) | ||
5069 | { | ||
5070 | struct nfs4_reclaim_complete_data *calldata = data; | ||
5071 | struct nfs_client *clp = calldata->clp; | ||
5072 | struct nfs4_sequence_res *res = &calldata->res.seq_res; | ||
5073 | |||
5074 | dprintk("--> %s\n", __func__); | ||
5075 | nfs41_sequence_done(clp, res, task->tk_status); | ||
5076 | switch (task->tk_status) { | ||
5077 | case 0: | ||
5078 | case -NFS4ERR_COMPLETE_ALREADY: | ||
5079 | break; | ||
5080 | case -NFS4ERR_BADSESSION: | ||
5081 | case -NFS4ERR_DEADSESSION: | ||
5082 | /* | ||
5083 | * Handle the session error, but do not retry the operation, as | ||
5084 | * we have no way of telling whether the clientid had to be | ||
5085 | * reset before we got our reply. If reset, a new wave of | ||
5086 | * reclaim operations will follow, containing their own reclaim | ||
5087 | * complete. We don't want our retry to get on the way of | ||
5088 | * recovery by incorrectly indicating to the server that we're | ||
5089 | * done reclaiming state since the process had to be restarted. | ||
5090 | */ | ||
5091 | _nfs4_async_handle_error(task, NULL, clp, NULL); | ||
5092 | break; | ||
5093 | default: | ||
5094 | if (_nfs4_async_handle_error( | ||
5095 | task, NULL, clp, NULL) == -EAGAIN) { | ||
5096 | rpc_restart_call_prepare(task); | ||
5097 | return; | ||
5098 | } | ||
5099 | } | ||
5100 | |||
5101 | dprintk("<-- %s\n", __func__); | ||
5102 | } | ||
5103 | |||
5104 | static void nfs4_free_reclaim_complete_data(void *data) | ||
5105 | { | ||
5106 | struct nfs4_reclaim_complete_data *calldata = data; | ||
5107 | |||
5108 | kfree(calldata); | ||
5109 | } | ||
5110 | |||
5111 | static const struct rpc_call_ops nfs4_reclaim_complete_call_ops = { | ||
5112 | .rpc_call_prepare = nfs4_reclaim_complete_prepare, | ||
5113 | .rpc_call_done = nfs4_reclaim_complete_done, | ||
5114 | .rpc_release = nfs4_free_reclaim_complete_data, | ||
5115 | }; | ||
5116 | |||
5117 | /* | ||
5118 | * Issue a global reclaim complete. | ||
5119 | */ | ||
5120 | static int nfs41_proc_reclaim_complete(struct nfs_client *clp) | ||
5121 | { | ||
5122 | struct nfs4_reclaim_complete_data *calldata; | ||
5123 | struct rpc_task *task; | ||
5124 | struct rpc_message msg = { | ||
5125 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RECLAIM_COMPLETE], | ||
5126 | }; | ||
5127 | struct rpc_task_setup task_setup_data = { | ||
5128 | .rpc_client = clp->cl_rpcclient, | ||
5129 | .rpc_message = &msg, | ||
5130 | .callback_ops = &nfs4_reclaim_complete_call_ops, | ||
5131 | .flags = RPC_TASK_ASYNC, | ||
5132 | }; | ||
5133 | int status = -ENOMEM; | ||
5134 | |||
5135 | dprintk("--> %s\n", __func__); | ||
5136 | calldata = kzalloc(sizeof(*calldata), GFP_KERNEL); | ||
5137 | if (calldata == NULL) | ||
5138 | goto out; | ||
5139 | calldata->clp = clp; | ||
5140 | calldata->arg.one_fs = 0; | ||
5141 | calldata->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
5142 | |||
5143 | msg.rpc_argp = &calldata->arg; | ||
5144 | msg.rpc_resp = &calldata->res; | ||
5145 | task_setup_data.callback_data = calldata; | ||
5146 | task = rpc_run_task(&task_setup_data); | ||
5147 | if (IS_ERR(task)) | ||
5148 | status = PTR_ERR(task); | ||
5149 | rpc_put_task(task); | ||
5150 | out: | ||
5151 | dprintk("<-- %s status=%d\n", __func__, status); | ||
5152 | return status; | ||
5153 | } | ||
4934 | #endif /* CONFIG_NFS_V4_1 */ | 5154 | #endif /* CONFIG_NFS_V4_1 */ |
4935 | 5155 | ||
4936 | struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = { | 5156 | struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = { |
@@ -4948,8 +5168,9 @@ struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = { | |||
4948 | .state_flag_bit = NFS_STATE_RECLAIM_REBOOT, | 5168 | .state_flag_bit = NFS_STATE_RECLAIM_REBOOT, |
4949 | .recover_open = nfs4_open_reclaim, | 5169 | .recover_open = nfs4_open_reclaim, |
4950 | .recover_lock = nfs4_lock_reclaim, | 5170 | .recover_lock = nfs4_lock_reclaim, |
4951 | .establish_clid = nfs4_proc_exchange_id, | 5171 | .establish_clid = nfs41_init_clientid, |
4952 | .get_clid_cred = nfs4_get_exchange_id_cred, | 5172 | .get_clid_cred = nfs4_get_exchange_id_cred, |
5173 | .reclaim_complete = nfs41_proc_reclaim_complete, | ||
4953 | }; | 5174 | }; |
4954 | #endif /* CONFIG_NFS_V4_1 */ | 5175 | #endif /* CONFIG_NFS_V4_1 */ |
4955 | 5176 | ||
@@ -4968,7 +5189,7 @@ struct nfs4_state_recovery_ops nfs41_nograce_recovery_ops = { | |||
4968 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, | 5189 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, |
4969 | .recover_open = nfs4_open_expired, | 5190 | .recover_open = nfs4_open_expired, |
4970 | .recover_lock = nfs4_lock_expired, | 5191 | .recover_lock = nfs4_lock_expired, |
4971 | .establish_clid = nfs4_proc_exchange_id, | 5192 | .establish_clid = nfs41_init_clientid, |
4972 | .get_clid_cred = nfs4_get_exchange_id_cred, | 5193 | .get_clid_cred = nfs4_get_exchange_id_cred, |
4973 | }; | 5194 | }; |
4974 | #endif /* CONFIG_NFS_V4_1 */ | 5195 | #endif /* CONFIG_NFS_V4_1 */ |