diff options
Diffstat (limited to 'fs/nfs/nfs4proc.c')
| -rw-r--r-- | fs/nfs/nfs4proc.c | 474 |
1 files changed, 270 insertions, 204 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 70015dd60a98..7ffbb98ddec3 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
| @@ -303,15 +303,19 @@ do_state_recovery: | |||
| 303 | } | 303 | } |
| 304 | 304 | ||
| 305 | 305 | ||
| 306 | static void renew_lease(const struct nfs_server *server, unsigned long timestamp) | 306 | static void do_renew_lease(struct nfs_client *clp, unsigned long timestamp) |
| 307 | { | 307 | { |
| 308 | struct nfs_client *clp = server->nfs_client; | ||
| 309 | spin_lock(&clp->cl_lock); | 308 | spin_lock(&clp->cl_lock); |
| 310 | if (time_before(clp->cl_last_renewal,timestamp)) | 309 | if (time_before(clp->cl_last_renewal,timestamp)) |
| 311 | clp->cl_last_renewal = timestamp; | 310 | clp->cl_last_renewal = timestamp; |
| 312 | spin_unlock(&clp->cl_lock); | 311 | spin_unlock(&clp->cl_lock); |
| 313 | } | 312 | } |
| 314 | 313 | ||
| 314 | static void renew_lease(const struct nfs_server *server, unsigned long timestamp) | ||
| 315 | { | ||
| 316 | do_renew_lease(server->nfs_client, timestamp); | ||
| 317 | } | ||
| 318 | |||
| 315 | #if defined(CONFIG_NFS_V4_1) | 319 | #if defined(CONFIG_NFS_V4_1) |
| 316 | 320 | ||
| 317 | /* | 321 | /* |
| @@ -356,7 +360,7 @@ static void nfs41_check_drain_session_complete(struct nfs4_session *ses) | |||
| 356 | { | 360 | { |
| 357 | struct rpc_task *task; | 361 | struct rpc_task *task; |
| 358 | 362 | ||
| 359 | if (!test_bit(NFS4CLNT_SESSION_DRAINING, &ses->clp->cl_state)) { | 363 | if (!test_bit(NFS4_SESSION_DRAINING, &ses->session_state)) { |
| 360 | task = rpc_wake_up_next(&ses->fc_slot_table.slot_tbl_waitq); | 364 | task = rpc_wake_up_next(&ses->fc_slot_table.slot_tbl_waitq); |
| 361 | if (task) | 365 | if (task) |
| 362 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | 366 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); |
| @@ -370,12 +374,11 @@ static void nfs41_check_drain_session_complete(struct nfs4_session *ses) | |||
| 370 | complete(&ses->complete); | 374 | complete(&ses->complete); |
| 371 | } | 375 | } |
| 372 | 376 | ||
| 373 | static void nfs41_sequence_free_slot(const struct nfs_client *clp, | 377 | static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) |
| 374 | struct nfs4_sequence_res *res) | ||
| 375 | { | 378 | { |
| 376 | struct nfs4_slot_table *tbl; | 379 | struct nfs4_slot_table *tbl; |
| 377 | 380 | ||
| 378 | tbl = &clp->cl_session->fc_slot_table; | 381 | tbl = &res->sr_session->fc_slot_table; |
| 379 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) { | 382 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) { |
| 380 | /* just wake up the next guy waiting since | 383 | /* just wake up the next guy waiting since |
| 381 | * we may have not consumed a slot after all */ | 384 | * we may have not consumed a slot after all */ |
| @@ -385,18 +388,17 @@ static void nfs41_sequence_free_slot(const struct nfs_client *clp, | |||
| 385 | 388 | ||
| 386 | spin_lock(&tbl->slot_tbl_lock); | 389 | spin_lock(&tbl->slot_tbl_lock); |
| 387 | nfs4_free_slot(tbl, res->sr_slotid); | 390 | nfs4_free_slot(tbl, res->sr_slotid); |
| 388 | nfs41_check_drain_session_complete(clp->cl_session); | 391 | nfs41_check_drain_session_complete(res->sr_session); |
| 389 | spin_unlock(&tbl->slot_tbl_lock); | 392 | spin_unlock(&tbl->slot_tbl_lock); |
| 390 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | 393 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; |
| 391 | } | 394 | } |
| 392 | 395 | ||
| 393 | static void nfs41_sequence_done(struct nfs_client *clp, | 396 | static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res) |
| 394 | struct nfs4_sequence_res *res, | ||
| 395 | int rpc_status) | ||
| 396 | { | 397 | { |
| 397 | unsigned long timestamp; | 398 | unsigned long timestamp; |
| 398 | struct nfs4_slot_table *tbl; | 399 | struct nfs4_slot_table *tbl; |
| 399 | struct nfs4_slot *slot; | 400 | struct nfs4_slot *slot; |
| 401 | struct nfs_client *clp; | ||
| 400 | 402 | ||
| 401 | /* | 403 | /* |
| 402 | * sr_status remains 1 if an RPC level error occurred. The server | 404 | * sr_status remains 1 if an RPC level error occurred. The server |
| @@ -411,25 +413,51 @@ static void nfs41_sequence_done(struct nfs_client *clp, | |||
| 411 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) | 413 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) |
| 412 | goto out; | 414 | goto out; |
| 413 | 415 | ||
| 416 | tbl = &res->sr_session->fc_slot_table; | ||
| 417 | slot = tbl->slots + res->sr_slotid; | ||
| 418 | |||
| 414 | /* Check the SEQUENCE operation status */ | 419 | /* Check the SEQUENCE operation status */ |
| 415 | if (res->sr_status == 0) { | 420 | switch (res->sr_status) { |
| 416 | tbl = &clp->cl_session->fc_slot_table; | 421 | case 0: |
| 417 | slot = tbl->slots + res->sr_slotid; | ||
| 418 | /* Update the slot's sequence and clientid lease timer */ | 422 | /* Update the slot's sequence and clientid lease timer */ |
| 419 | ++slot->seq_nr; | 423 | ++slot->seq_nr; |
| 420 | timestamp = res->sr_renewal_time; | 424 | timestamp = res->sr_renewal_time; |
| 421 | spin_lock(&clp->cl_lock); | 425 | clp = res->sr_session->clp; |
| 422 | if (time_before(clp->cl_last_renewal, timestamp)) | 426 | do_renew_lease(clp, timestamp); |
| 423 | clp->cl_last_renewal = timestamp; | ||
| 424 | spin_unlock(&clp->cl_lock); | ||
| 425 | /* Check sequence flags */ | 427 | /* Check sequence flags */ |
| 426 | if (atomic_read(&clp->cl_count) > 1) | 428 | if (atomic_read(&clp->cl_count) > 1) |
| 427 | nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags); | 429 | nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags); |
| 430 | break; | ||
| 431 | case -NFS4ERR_DELAY: | ||
| 432 | /* The server detected a resend of the RPC call and | ||
| 433 | * returned NFS4ERR_DELAY as per Section 2.10.6.2 | ||
| 434 | * of RFC5661. | ||
| 435 | */ | ||
| 436 | dprintk("%s: slot=%d seq=%d: Operation in progress\n", | ||
| 437 | __func__, res->sr_slotid, slot->seq_nr); | ||
| 438 | goto out_retry; | ||
| 439 | default: | ||
| 440 | /* Just update the slot sequence no. */ | ||
| 441 | ++slot->seq_nr; | ||
| 428 | } | 442 | } |
| 429 | out: | 443 | out: |
| 430 | /* The session may be reset by one of the error handlers. */ | 444 | /* The session may be reset by one of the error handlers. */ |
| 431 | dprintk("%s: Error %d free the slot \n", __func__, res->sr_status); | 445 | dprintk("%s: Error %d free the slot \n", __func__, res->sr_status); |
| 432 | nfs41_sequence_free_slot(clp, res); | 446 | nfs41_sequence_free_slot(res); |
| 447 | return 1; | ||
| 448 | out_retry: | ||
| 449 | if (!rpc_restart_call(task)) | ||
| 450 | goto out; | ||
| 451 | rpc_delay(task, NFS4_POLL_RETRY_MAX); | ||
| 452 | return 0; | ||
| 453 | } | ||
| 454 | |||
| 455 | static int nfs4_sequence_done(struct rpc_task *task, | ||
| 456 | struct nfs4_sequence_res *res) | ||
| 457 | { | ||
| 458 | if (res->sr_session == NULL) | ||
| 459 | return 1; | ||
| 460 | return nfs41_sequence_done(task, res); | ||
| 433 | } | 461 | } |
| 434 | 462 | ||
| 435 | /* | 463 | /* |
| @@ -480,12 +508,11 @@ static int nfs41_setup_sequence(struct nfs4_session *session, | |||
| 480 | if (res->sr_slotid != NFS4_MAX_SLOT_TABLE) | 508 | if (res->sr_slotid != NFS4_MAX_SLOT_TABLE) |
| 481 | return 0; | 509 | return 0; |
| 482 | 510 | ||
| 483 | memset(res, 0, sizeof(*res)); | ||
| 484 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | 511 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; |
| 485 | tbl = &session->fc_slot_table; | 512 | tbl = &session->fc_slot_table; |
| 486 | 513 | ||
| 487 | spin_lock(&tbl->slot_tbl_lock); | 514 | spin_lock(&tbl->slot_tbl_lock); |
| 488 | if (test_bit(NFS4CLNT_SESSION_DRAINING, &session->clp->cl_state) && | 515 | if (test_bit(NFS4_SESSION_DRAINING, &session->session_state) && |
| 489 | !rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) { | 516 | !rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) { |
| 490 | /* | 517 | /* |
| 491 | * The state manager will wait until the slot table is empty. | 518 | * The state manager will wait until the slot table is empty. |
| @@ -525,6 +552,7 @@ static int nfs41_setup_sequence(struct nfs4_session *session, | |||
| 525 | res->sr_session = session; | 552 | res->sr_session = session; |
| 526 | res->sr_slotid = slotid; | 553 | res->sr_slotid = slotid; |
| 527 | res->sr_renewal_time = jiffies; | 554 | res->sr_renewal_time = jiffies; |
| 555 | res->sr_status_flags = 0; | ||
| 528 | /* | 556 | /* |
| 529 | * sr_status is only set in decode_sequence, and so will remain | 557 | * sr_status is only set in decode_sequence, and so will remain |
| 530 | * set to 1 if an rpc level failure occurs. | 558 | * set to 1 if an rpc level failure occurs. |
| @@ -533,33 +561,33 @@ static int nfs41_setup_sequence(struct nfs4_session *session, | |||
| 533 | return 0; | 561 | return 0; |
| 534 | } | 562 | } |
| 535 | 563 | ||
| 536 | int nfs4_setup_sequence(struct nfs_client *clp, | 564 | int nfs4_setup_sequence(const struct nfs_server *server, |
| 537 | struct nfs4_sequence_args *args, | 565 | struct nfs4_sequence_args *args, |
| 538 | struct nfs4_sequence_res *res, | 566 | struct nfs4_sequence_res *res, |
| 539 | int cache_reply, | 567 | int cache_reply, |
| 540 | struct rpc_task *task) | 568 | struct rpc_task *task) |
| 541 | { | 569 | { |
| 570 | struct nfs4_session *session = nfs4_get_session(server); | ||
| 542 | int ret = 0; | 571 | int ret = 0; |
| 543 | 572 | ||
| 573 | if (session == NULL) { | ||
| 574 | args->sa_session = NULL; | ||
| 575 | res->sr_session = NULL; | ||
| 576 | goto out; | ||
| 577 | } | ||
| 578 | |||
| 544 | dprintk("--> %s clp %p session %p sr_slotid %d\n", | 579 | dprintk("--> %s clp %p session %p sr_slotid %d\n", |
| 545 | __func__, clp, clp->cl_session, res->sr_slotid); | 580 | __func__, session->clp, session, res->sr_slotid); |
| 546 | 581 | ||
| 547 | if (!nfs4_has_session(clp)) | 582 | ret = nfs41_setup_sequence(session, args, res, cache_reply, |
| 548 | goto out; | ||
| 549 | ret = nfs41_setup_sequence(clp->cl_session, args, res, cache_reply, | ||
| 550 | task); | 583 | task); |
| 551 | if (ret && ret != -EAGAIN) { | ||
| 552 | /* terminate rpc task */ | ||
| 553 | task->tk_status = ret; | ||
| 554 | task->tk_action = NULL; | ||
| 555 | } | ||
| 556 | out: | 584 | out: |
| 557 | dprintk("<-- %s status=%d\n", __func__, ret); | 585 | dprintk("<-- %s status=%d\n", __func__, ret); |
| 558 | return ret; | 586 | return ret; |
| 559 | } | 587 | } |
| 560 | 588 | ||
| 561 | struct nfs41_call_sync_data { | 589 | struct nfs41_call_sync_data { |
| 562 | struct nfs_client *clp; | 590 | const struct nfs_server *seq_server; |
| 563 | struct nfs4_sequence_args *seq_args; | 591 | struct nfs4_sequence_args *seq_args; |
| 564 | struct nfs4_sequence_res *seq_res; | 592 | struct nfs4_sequence_res *seq_res; |
| 565 | int cache_reply; | 593 | int cache_reply; |
| @@ -569,9 +597,9 @@ static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata) | |||
| 569 | { | 597 | { |
| 570 | struct nfs41_call_sync_data *data = calldata; | 598 | struct nfs41_call_sync_data *data = calldata; |
| 571 | 599 | ||
| 572 | dprintk("--> %s data->clp->cl_session %p\n", __func__, | 600 | dprintk("--> %s data->seq_server %p\n", __func__, data->seq_server); |
| 573 | data->clp->cl_session); | 601 | |
| 574 | if (nfs4_setup_sequence(data->clp, data->seq_args, | 602 | if (nfs4_setup_sequence(data->seq_server, data->seq_args, |
| 575 | data->seq_res, data->cache_reply, task)) | 603 | data->seq_res, data->cache_reply, task)) |
| 576 | return; | 604 | return; |
| 577 | rpc_call_start(task); | 605 | rpc_call_start(task); |
| @@ -587,7 +615,7 @@ static void nfs41_call_sync_done(struct rpc_task *task, void *calldata) | |||
| 587 | { | 615 | { |
| 588 | struct nfs41_call_sync_data *data = calldata; | 616 | struct nfs41_call_sync_data *data = calldata; |
| 589 | 617 | ||
| 590 | nfs41_sequence_done(data->clp, data->seq_res, task->tk_status); | 618 | nfs41_sequence_done(task, data->seq_res); |
| 591 | } | 619 | } |
| 592 | 620 | ||
| 593 | struct rpc_call_ops nfs41_call_sync_ops = { | 621 | struct rpc_call_ops nfs41_call_sync_ops = { |
| @@ -600,8 +628,7 @@ struct rpc_call_ops nfs41_call_priv_sync_ops = { | |||
| 600 | .rpc_call_done = nfs41_call_sync_done, | 628 | .rpc_call_done = nfs41_call_sync_done, |
| 601 | }; | 629 | }; |
| 602 | 630 | ||
| 603 | static int nfs4_call_sync_sequence(struct nfs_client *clp, | 631 | static int nfs4_call_sync_sequence(struct nfs_server *server, |
| 604 | struct rpc_clnt *clnt, | ||
| 605 | struct rpc_message *msg, | 632 | struct rpc_message *msg, |
| 606 | struct nfs4_sequence_args *args, | 633 | struct nfs4_sequence_args *args, |
| 607 | struct nfs4_sequence_res *res, | 634 | struct nfs4_sequence_res *res, |
| @@ -611,13 +638,13 @@ static int nfs4_call_sync_sequence(struct nfs_client *clp, | |||
| 611 | int ret; | 638 | int ret; |
| 612 | struct rpc_task *task; | 639 | struct rpc_task *task; |
| 613 | struct nfs41_call_sync_data data = { | 640 | struct nfs41_call_sync_data data = { |
| 614 | .clp = clp, | 641 | .seq_server = server, |
| 615 | .seq_args = args, | 642 | .seq_args = args, |
| 616 | .seq_res = res, | 643 | .seq_res = res, |
| 617 | .cache_reply = cache_reply, | 644 | .cache_reply = cache_reply, |
| 618 | }; | 645 | }; |
| 619 | struct rpc_task_setup task_setup = { | 646 | struct rpc_task_setup task_setup = { |
| 620 | .rpc_client = clnt, | 647 | .rpc_client = server->client, |
| 621 | .rpc_message = msg, | 648 | .rpc_message = msg, |
| 622 | .callback_ops = &nfs41_call_sync_ops, | 649 | .callback_ops = &nfs41_call_sync_ops, |
| 623 | .callback_data = &data | 650 | .callback_data = &data |
| @@ -642,10 +669,15 @@ int _nfs4_call_sync_session(struct nfs_server *server, | |||
| 642 | struct nfs4_sequence_res *res, | 669 | struct nfs4_sequence_res *res, |
| 643 | int cache_reply) | 670 | int cache_reply) |
| 644 | { | 671 | { |
| 645 | return nfs4_call_sync_sequence(server->nfs_client, server->client, | 672 | return nfs4_call_sync_sequence(server, msg, args, res, cache_reply, 0); |
| 646 | msg, args, res, cache_reply, 0); | ||
| 647 | } | 673 | } |
| 648 | 674 | ||
| 675 | #else | ||
| 676 | static int nfs4_sequence_done(struct rpc_task *task, | ||
| 677 | struct nfs4_sequence_res *res) | ||
| 678 | { | ||
| 679 | return 1; | ||
| 680 | } | ||
| 649 | #endif /* CONFIG_NFS_V4_1 */ | 681 | #endif /* CONFIG_NFS_V4_1 */ |
| 650 | 682 | ||
| 651 | int _nfs4_call_sync(struct nfs_server *server, | 683 | int _nfs4_call_sync(struct nfs_server *server, |
| @@ -659,18 +691,9 @@ int _nfs4_call_sync(struct nfs_server *server, | |||
| 659 | } | 691 | } |
| 660 | 692 | ||
| 661 | #define nfs4_call_sync(server, msg, args, res, cache_reply) \ | 693 | #define nfs4_call_sync(server, msg, args, res, cache_reply) \ |
| 662 | (server)->nfs_client->cl_call_sync((server), (msg), &(args)->seq_args, \ | 694 | (server)->nfs_client->cl_mvops->call_sync((server), (msg), &(args)->seq_args, \ |
| 663 | &(res)->seq_res, (cache_reply)) | 695 | &(res)->seq_res, (cache_reply)) |
| 664 | 696 | ||
| 665 | static void nfs4_sequence_done(const struct nfs_server *server, | ||
| 666 | struct nfs4_sequence_res *res, int rpc_status) | ||
| 667 | { | ||
| 668 | #ifdef CONFIG_NFS_V4_1 | ||
| 669 | if (nfs4_has_session(server->nfs_client)) | ||
| 670 | nfs41_sequence_done(server->nfs_client, res, rpc_status); | ||
| 671 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 672 | } | ||
| 673 | |||
| 674 | static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) | 697 | static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) |
| 675 | { | 698 | { |
| 676 | struct nfs_inode *nfsi = NFS_I(dir); | 699 | struct nfs_inode *nfsi = NFS_I(dir); |
| @@ -745,19 +768,14 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, | |||
| 745 | p->o_arg.server = server; | 768 | p->o_arg.server = server; |
| 746 | p->o_arg.bitmask = server->attr_bitmask; | 769 | p->o_arg.bitmask = server->attr_bitmask; |
| 747 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; | 770 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; |
| 748 | if (flags & O_EXCL) { | 771 | if (flags & O_CREAT) { |
| 749 | if (nfs4_has_persistent_session(server->nfs_client)) { | 772 | u32 *s; |
| 750 | /* GUARDED */ | 773 | |
| 751 | p->o_arg.u.attrs = &p->attrs; | ||
| 752 | memcpy(&p->attrs, attrs, sizeof(p->attrs)); | ||
| 753 | } else { /* EXCLUSIVE4_1 */ | ||
| 754 | u32 *s = (u32 *) p->o_arg.u.verifier.data; | ||
| 755 | s[0] = jiffies; | ||
| 756 | s[1] = current->pid; | ||
| 757 | } | ||
| 758 | } else if (flags & O_CREAT) { | ||
| 759 | p->o_arg.u.attrs = &p->attrs; | 774 | p->o_arg.u.attrs = &p->attrs; |
| 760 | memcpy(&p->attrs, attrs, sizeof(p->attrs)); | 775 | memcpy(&p->attrs, attrs, sizeof(p->attrs)); |
| 776 | s = (u32 *) p->o_arg.u.verifier.data; | ||
| 777 | s[0] = jiffies; | ||
| 778 | s[1] = current->pid; | ||
| 761 | } | 779 | } |
| 762 | p->c_arg.fh = &p->o_res.fh; | 780 | p->c_arg.fh = &p->o_res.fh; |
| 763 | p->c_arg.stateid = &p->o_res.stateid; | 781 | p->c_arg.stateid = &p->o_res.stateid; |
| @@ -1255,8 +1273,6 @@ static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata) | |||
| 1255 | struct nfs4_opendata *data = calldata; | 1273 | struct nfs4_opendata *data = calldata; |
| 1256 | 1274 | ||
| 1257 | data->rpc_status = task->tk_status; | 1275 | data->rpc_status = task->tk_status; |
| 1258 | if (RPC_ASSASSINATED(task)) | ||
| 1259 | return; | ||
| 1260 | if (data->rpc_status == 0) { | 1276 | if (data->rpc_status == 0) { |
| 1261 | memcpy(data->o_res.stateid.data, data->c_res.stateid.data, | 1277 | memcpy(data->o_res.stateid.data, data->c_res.stateid.data, |
| 1262 | sizeof(data->o_res.stateid.data)); | 1278 | sizeof(data->o_res.stateid.data)); |
| @@ -1356,13 +1372,13 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) | |||
| 1356 | } | 1372 | } |
| 1357 | /* Update sequence id. */ | 1373 | /* Update sequence id. */ |
| 1358 | data->o_arg.id = sp->so_owner_id.id; | 1374 | data->o_arg.id = sp->so_owner_id.id; |
| 1359 | data->o_arg.clientid = sp->so_client->cl_clientid; | 1375 | data->o_arg.clientid = sp->so_server->nfs_client->cl_clientid; |
| 1360 | if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) { | 1376 | if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) { |
| 1361 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR]; | 1377 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR]; |
| 1362 | nfs_copy_fh(&data->o_res.fh, data->o_arg.fh); | 1378 | nfs_copy_fh(&data->o_res.fh, data->o_arg.fh); |
| 1363 | } | 1379 | } |
| 1364 | data->timestamp = jiffies; | 1380 | data->timestamp = jiffies; |
| 1365 | if (nfs4_setup_sequence(data->o_arg.server->nfs_client, | 1381 | if (nfs4_setup_sequence(data->o_arg.server, |
| 1366 | &data->o_arg.seq_args, | 1382 | &data->o_arg.seq_args, |
| 1367 | &data->o_res.seq_res, 1, task)) | 1383 | &data->o_res.seq_res, 1, task)) |
| 1368 | return; | 1384 | return; |
| @@ -1385,11 +1401,9 @@ static void nfs4_open_done(struct rpc_task *task, void *calldata) | |||
| 1385 | 1401 | ||
| 1386 | data->rpc_status = task->tk_status; | 1402 | data->rpc_status = task->tk_status; |
| 1387 | 1403 | ||
| 1388 | nfs4_sequence_done(data->o_arg.server, &data->o_res.seq_res, | 1404 | if (!nfs4_sequence_done(task, &data->o_res.seq_res)) |
| 1389 | task->tk_status); | ||
| 1390 | |||
| 1391 | if (RPC_ASSASSINATED(task)) | ||
| 1392 | return; | 1405 | return; |
| 1406 | |||
| 1393 | if (task->tk_status == 0) { | 1407 | if (task->tk_status == 0) { |
| 1394 | switch (data->o_res.f_attr->mode & S_IFMT) { | 1408 | switch (data->o_res.f_attr->mode & S_IFMT) { |
| 1395 | case S_IFREG: | 1409 | case S_IFREG: |
| @@ -1773,7 +1787,7 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, | |||
| 1773 | if (nfs4_copy_delegation_stateid(&arg.stateid, inode)) { | 1787 | if (nfs4_copy_delegation_stateid(&arg.stateid, inode)) { |
| 1774 | /* Use that stateid */ | 1788 | /* Use that stateid */ |
| 1775 | } else if (state != NULL) { | 1789 | } else if (state != NULL) { |
| 1776 | nfs4_copy_stateid(&arg.stateid, state, current->files); | 1790 | nfs4_copy_stateid(&arg.stateid, state, current->files, current->tgid); |
| 1777 | } else | 1791 | } else |
| 1778 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); | 1792 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); |
| 1779 | 1793 | ||
| @@ -1838,8 +1852,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
| 1838 | struct nfs4_state *state = calldata->state; | 1852 | struct nfs4_state *state = calldata->state; |
| 1839 | struct nfs_server *server = NFS_SERVER(calldata->inode); | 1853 | struct nfs_server *server = NFS_SERVER(calldata->inode); |
| 1840 | 1854 | ||
| 1841 | nfs4_sequence_done(server, &calldata->res.seq_res, task->tk_status); | 1855 | if (!nfs4_sequence_done(task, &calldata->res.seq_res)) |
| 1842 | if (RPC_ASSASSINATED(task)) | ||
| 1843 | return; | 1856 | return; |
| 1844 | /* hmm. we are done with the inode, and in the process of freeing | 1857 | /* hmm. we are done with the inode, and in the process of freeing |
| 1845 | * the state_owner. we keep this around to process errors | 1858 | * the state_owner. we keep this around to process errors |
| @@ -1903,7 +1916,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
| 1903 | 1916 | ||
| 1904 | nfs_fattr_init(calldata->res.fattr); | 1917 | nfs_fattr_init(calldata->res.fattr); |
| 1905 | calldata->timestamp = jiffies; | 1918 | calldata->timestamp = jiffies; |
| 1906 | if (nfs4_setup_sequence((NFS_SERVER(calldata->inode))->nfs_client, | 1919 | if (nfs4_setup_sequence(NFS_SERVER(calldata->inode), |
| 1907 | &calldata->arg.seq_args, &calldata->res.seq_res, | 1920 | &calldata->arg.seq_args, &calldata->res.seq_res, |
| 1908 | 1, task)) | 1921 | 1, task)) |
| 1909 | return; | 1922 | return; |
| @@ -2648,7 +2661,8 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir) | |||
| 2648 | { | 2661 | { |
| 2649 | struct nfs_removeres *res = task->tk_msg.rpc_resp; | 2662 | struct nfs_removeres *res = task->tk_msg.rpc_resp; |
| 2650 | 2663 | ||
| 2651 | nfs4_sequence_done(res->server, &res->seq_res, task->tk_status); | 2664 | if (!nfs4_sequence_done(task, &res->seq_res)) |
| 2665 | return 0; | ||
| 2652 | if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) | 2666 | if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) |
| 2653 | return 0; | 2667 | return 0; |
| 2654 | update_changeattr(dir, &res->cinfo); | 2668 | update_changeattr(dir, &res->cinfo); |
| @@ -3093,7 +3107,8 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data) | |||
| 3093 | 3107 | ||
| 3094 | dprintk("--> %s\n", __func__); | 3108 | dprintk("--> %s\n", __func__); |
| 3095 | 3109 | ||
| 3096 | nfs4_sequence_done(server, &data->res.seq_res, task->tk_status); | 3110 | if (!nfs4_sequence_done(task, &data->res.seq_res)) |
| 3111 | return -EAGAIN; | ||
| 3097 | 3112 | ||
| 3098 | if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { | 3113 | if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { |
| 3099 | nfs_restart_rpc(task, server->nfs_client); | 3114 | nfs_restart_rpc(task, server->nfs_client); |
| @@ -3116,8 +3131,8 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) | |||
| 3116 | { | 3131 | { |
| 3117 | struct inode *inode = data->inode; | 3132 | struct inode *inode = data->inode; |
| 3118 | 3133 | ||
| 3119 | nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res, | 3134 | if (!nfs4_sequence_done(task, &data->res.seq_res)) |
| 3120 | task->tk_status); | 3135 | return -EAGAIN; |
| 3121 | 3136 | ||
| 3122 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { | 3137 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { |
| 3123 | nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client); | 3138 | nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client); |
| @@ -3145,8 +3160,9 @@ static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) | |||
| 3145 | { | 3160 | { |
| 3146 | struct inode *inode = data->inode; | 3161 | struct inode *inode = data->inode; |
| 3147 | 3162 | ||
| 3148 | nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res, | 3163 | if (!nfs4_sequence_done(task, &data->res.seq_res)) |
| 3149 | task->tk_status); | 3164 | return -EAGAIN; |
| 3165 | |||
| 3150 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { | 3166 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { |
| 3151 | nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client); | 3167 | nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client); |
| 3152 | return -EAGAIN; | 3168 | return -EAGAIN; |
| @@ -3196,10 +3212,7 @@ static void nfs4_renew_done(struct rpc_task *task, void *calldata) | |||
| 3196 | nfs4_schedule_state_recovery(clp); | 3212 | nfs4_schedule_state_recovery(clp); |
| 3197 | return; | 3213 | return; |
| 3198 | } | 3214 | } |
| 3199 | spin_lock(&clp->cl_lock); | 3215 | do_renew_lease(clp, timestamp); |
| 3200 | if (time_before(clp->cl_last_renewal,timestamp)) | ||
| 3201 | clp->cl_last_renewal = timestamp; | ||
| 3202 | spin_unlock(&clp->cl_lock); | ||
| 3203 | } | 3216 | } |
| 3204 | 3217 | ||
| 3205 | static const struct rpc_call_ops nfs4_renew_ops = { | 3218 | static const struct rpc_call_ops nfs4_renew_ops = { |
| @@ -3240,10 +3253,7 @@ int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred) | |||
| 3240 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); | 3253 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); |
| 3241 | if (status < 0) | 3254 | if (status < 0) |
| 3242 | return status; | 3255 | return status; |
| 3243 | spin_lock(&clp->cl_lock); | 3256 | do_renew_lease(clp, now); |
| 3244 | if (time_before(clp->cl_last_renewal,now)) | ||
| 3245 | clp->cl_last_renewal = now; | ||
| 3246 | spin_unlock(&clp->cl_lock); | ||
| 3247 | return 0; | 3257 | return 0; |
| 3248 | } | 3258 | } |
| 3249 | 3259 | ||
| @@ -3464,9 +3474,11 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen | |||
| 3464 | } | 3474 | } |
| 3465 | 3475 | ||
| 3466 | static int | 3476 | static int |
| 3467 | _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs_client *clp, struct nfs4_state *state) | 3477 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state) |
| 3468 | { | 3478 | { |
| 3469 | if (!clp || task->tk_status >= 0) | 3479 | struct nfs_client *clp = server->nfs_client; |
| 3480 | |||
| 3481 | if (task->tk_status >= 0) | ||
| 3470 | return 0; | 3482 | return 0; |
| 3471 | switch(task->tk_status) { | 3483 | switch(task->tk_status) { |
| 3472 | case -NFS4ERR_ADMIN_REVOKED: | 3484 | case -NFS4ERR_ADMIN_REVOKED: |
| @@ -3498,8 +3510,7 @@ _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
| 3498 | return -EAGAIN; | 3510 | return -EAGAIN; |
| 3499 | #endif /* CONFIG_NFS_V4_1 */ | 3511 | #endif /* CONFIG_NFS_V4_1 */ |
| 3500 | case -NFS4ERR_DELAY: | 3512 | case -NFS4ERR_DELAY: |
| 3501 | if (server) | 3513 | nfs_inc_server_stats(server, NFSIOS_DELAY); |
| 3502 | nfs_inc_server_stats(server, NFSIOS_DELAY); | ||
| 3503 | case -NFS4ERR_GRACE: | 3514 | case -NFS4ERR_GRACE: |
| 3504 | case -EKEYEXPIRED: | 3515 | case -EKEYEXPIRED: |
| 3505 | rpc_delay(task, NFS4_POLL_RETRY_MAX); | 3516 | rpc_delay(task, NFS4_POLL_RETRY_MAX); |
| @@ -3520,12 +3531,6 @@ do_state_recovery: | |||
| 3520 | return -EAGAIN; | 3531 | return -EAGAIN; |
| 3521 | } | 3532 | } |
| 3522 | 3533 | ||
| 3523 | static int | ||
| 3524 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state) | ||
| 3525 | { | ||
| 3526 | return _nfs4_async_handle_error(task, server, server->nfs_client, state); | ||
| 3527 | } | ||
| 3528 | |||
| 3529 | int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, | 3534 | int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, |
| 3530 | unsigned short port, struct rpc_cred *cred, | 3535 | unsigned short port, struct rpc_cred *cred, |
| 3531 | struct nfs4_setclientid_res *res) | 3536 | struct nfs4_setclientid_res *res) |
| @@ -3641,8 +3646,8 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) | |||
| 3641 | { | 3646 | { |
| 3642 | struct nfs4_delegreturndata *data = calldata; | 3647 | struct nfs4_delegreturndata *data = calldata; |
| 3643 | 3648 | ||
| 3644 | nfs4_sequence_done(data->res.server, &data->res.seq_res, | 3649 | if (!nfs4_sequence_done(task, &data->res.seq_res)) |
| 3645 | task->tk_status); | 3650 | return; |
| 3646 | 3651 | ||
| 3647 | switch (task->tk_status) { | 3652 | switch (task->tk_status) { |
| 3648 | case -NFS4ERR_STALE_STATEID: | 3653 | case -NFS4ERR_STALE_STATEID: |
| @@ -3672,7 +3677,7 @@ static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data) | |||
| 3672 | 3677 | ||
| 3673 | d_data = (struct nfs4_delegreturndata *)data; | 3678 | d_data = (struct nfs4_delegreturndata *)data; |
| 3674 | 3679 | ||
| 3675 | if (nfs4_setup_sequence(d_data->res.server->nfs_client, | 3680 | if (nfs4_setup_sequence(d_data->res.server, |
| 3676 | &d_data->args.seq_args, | 3681 | &d_data->args.seq_args, |
| 3677 | &d_data->res.seq_res, 1, task)) | 3682 | &d_data->res.seq_res, 1, task)) |
| 3678 | return; | 3683 | return; |
| @@ -3892,9 +3897,7 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
| 3892 | { | 3897 | { |
| 3893 | struct nfs4_unlockdata *calldata = data; | 3898 | struct nfs4_unlockdata *calldata = data; |
| 3894 | 3899 | ||
| 3895 | nfs4_sequence_done(calldata->server, &calldata->res.seq_res, | 3900 | if (!nfs4_sequence_done(task, &calldata->res.seq_res)) |
| 3896 | task->tk_status); | ||
| 3897 | if (RPC_ASSASSINATED(task)) | ||
| 3898 | return; | 3901 | return; |
| 3899 | switch (task->tk_status) { | 3902 | switch (task->tk_status) { |
| 3900 | case 0: | 3903 | case 0: |
| @@ -3927,7 +3930,7 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data) | |||
| 3927 | return; | 3930 | return; |
| 3928 | } | 3931 | } |
| 3929 | calldata->timestamp = jiffies; | 3932 | calldata->timestamp = jiffies; |
| 3930 | if (nfs4_setup_sequence(calldata->server->nfs_client, | 3933 | if (nfs4_setup_sequence(calldata->server, |
| 3931 | &calldata->arg.seq_args, | 3934 | &calldata->arg.seq_args, |
| 3932 | &calldata->res.seq_res, 1, task)) | 3935 | &calldata->res.seq_res, 1, task)) |
| 3933 | return; | 3936 | return; |
| @@ -4082,7 +4085,8 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) | |||
| 4082 | } else | 4085 | } else |
| 4083 | data->arg.new_lock_owner = 0; | 4086 | data->arg.new_lock_owner = 0; |
| 4084 | data->timestamp = jiffies; | 4087 | data->timestamp = jiffies; |
| 4085 | if (nfs4_setup_sequence(data->server->nfs_client, &data->arg.seq_args, | 4088 | if (nfs4_setup_sequence(data->server, |
| 4089 | &data->arg.seq_args, | ||
| 4086 | &data->res.seq_res, 1, task)) | 4090 | &data->res.seq_res, 1, task)) |
| 4087 | return; | 4091 | return; |
| 4088 | rpc_call_start(task); | 4092 | rpc_call_start(task); |
| @@ -4101,12 +4105,10 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata) | |||
| 4101 | 4105 | ||
| 4102 | dprintk("%s: begin!\n", __func__); | 4106 | dprintk("%s: begin!\n", __func__); |
| 4103 | 4107 | ||
| 4104 | nfs4_sequence_done(data->server, &data->res.seq_res, | 4108 | if (!nfs4_sequence_done(task, &data->res.seq_res)) |
| 4105 | task->tk_status); | 4109 | return; |
| 4106 | 4110 | ||
| 4107 | data->rpc_status = task->tk_status; | 4111 | data->rpc_status = task->tk_status; |
| 4108 | if (RPC_ASSASSINATED(task)) | ||
| 4109 | goto out; | ||
| 4110 | if (data->arg.new_lock_owner != 0) { | 4112 | if (data->arg.new_lock_owner != 0) { |
| 4111 | if (data->rpc_status == 0) | 4113 | if (data->rpc_status == 0) |
| 4112 | nfs_confirm_seqid(&data->lsp->ls_seqid, 0); | 4114 | nfs_confirm_seqid(&data->lsp->ls_seqid, 0); |
| @@ -4424,6 +4426,34 @@ out: | |||
| 4424 | return err; | 4426 | return err; |
| 4425 | } | 4427 | } |
| 4426 | 4428 | ||
| 4429 | static void nfs4_release_lockowner_release(void *calldata) | ||
| 4430 | { | ||
| 4431 | kfree(calldata); | ||
| 4432 | } | ||
| 4433 | |||
| 4434 | const struct rpc_call_ops nfs4_release_lockowner_ops = { | ||
| 4435 | .rpc_release = nfs4_release_lockowner_release, | ||
| 4436 | }; | ||
| 4437 | |||
| 4438 | void nfs4_release_lockowner(const struct nfs4_lock_state *lsp) | ||
| 4439 | { | ||
| 4440 | struct nfs_server *server = lsp->ls_state->owner->so_server; | ||
| 4441 | struct nfs_release_lockowner_args *args; | ||
| 4442 | struct rpc_message msg = { | ||
| 4443 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RELEASE_LOCKOWNER], | ||
| 4444 | }; | ||
| 4445 | |||
| 4446 | if (server->nfs_client->cl_mvops->minor_version != 0) | ||
| 4447 | return; | ||
| 4448 | args = kmalloc(sizeof(*args), GFP_NOFS); | ||
| 4449 | if (!args) | ||
| 4450 | return; | ||
| 4451 | args->lock_owner.clientid = server->nfs_client->cl_clientid; | ||
| 4452 | args->lock_owner.id = lsp->ls_id.id; | ||
| 4453 | msg.rpc_argp = args; | ||
| 4454 | rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, args); | ||
| 4455 | } | ||
| 4456 | |||
| 4427 | #define XATTR_NAME_NFSV4_ACL "system.nfs4_acl" | 4457 | #define XATTR_NAME_NFSV4_ACL "system.nfs4_acl" |
| 4428 | 4458 | ||
| 4429 | int nfs4_setxattr(struct dentry *dentry, const char *key, const void *buf, | 4459 | int nfs4_setxattr(struct dentry *dentry, const char *key, const void *buf, |
| @@ -4611,7 +4641,8 @@ static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata) | |||
| 4611 | (struct nfs4_get_lease_time_data *)calldata; | 4641 | (struct nfs4_get_lease_time_data *)calldata; |
| 4612 | 4642 | ||
| 4613 | dprintk("--> %s\n", __func__); | 4643 | dprintk("--> %s\n", __func__); |
| 4614 | nfs41_sequence_done(data->clp, &data->res->lr_seq_res, task->tk_status); | 4644 | if (!nfs41_sequence_done(task, &data->res->lr_seq_res)) |
| 4645 | return; | ||
| 4615 | switch (task->tk_status) { | 4646 | switch (task->tk_status) { |
| 4616 | case -NFS4ERR_DELAY: | 4647 | case -NFS4ERR_DELAY: |
| 4617 | case -NFS4ERR_GRACE: | 4648 | case -NFS4ERR_GRACE: |
| @@ -4805,13 +4836,6 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp) | |||
| 4805 | if (!session) | 4836 | if (!session) |
| 4806 | return NULL; | 4837 | return NULL; |
| 4807 | 4838 | ||
| 4808 | /* | ||
| 4809 | * The create session reply races with the server back | ||
| 4810 | * channel probe. Mark the client NFS_CS_SESSION_INITING | ||
| 4811 | * so that the client back channel can find the | ||
| 4812 | * nfs_client struct | ||
| 4813 | */ | ||
| 4814 | clp->cl_cons_state = NFS_CS_SESSION_INITING; | ||
| 4815 | init_completion(&session->complete); | 4839 | init_completion(&session->complete); |
| 4816 | 4840 | ||
| 4817 | tbl = &session->fc_slot_table; | 4841 | tbl = &session->fc_slot_table; |
| @@ -4824,6 +4848,8 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp) | |||
| 4824 | spin_lock_init(&tbl->slot_tbl_lock); | 4848 | spin_lock_init(&tbl->slot_tbl_lock); |
| 4825 | rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table"); | 4849 | rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table"); |
| 4826 | 4850 | ||
| 4851 | session->session_state = 1<<NFS4_SESSION_INITING; | ||
| 4852 | |||
| 4827 | session->clp = clp; | 4853 | session->clp = clp; |
| 4828 | return session; | 4854 | return session; |
| 4829 | } | 4855 | } |
| @@ -5040,6 +5066,10 @@ int nfs4_init_session(struct nfs_server *server) | |||
| 5040 | if (!nfs4_has_session(clp)) | 5066 | if (!nfs4_has_session(clp)) |
| 5041 | return 0; | 5067 | return 0; |
| 5042 | 5068 | ||
| 5069 | session = clp->cl_session; | ||
| 5070 | if (!test_and_clear_bit(NFS4_SESSION_INITING, &session->session_state)) | ||
| 5071 | return 0; | ||
| 5072 | |||
| 5043 | rsize = server->rsize; | 5073 | rsize = server->rsize; |
| 5044 | if (rsize == 0) | 5074 | if (rsize == 0) |
| 5045 | rsize = NFS_MAX_FILE_IO_SIZE; | 5075 | rsize = NFS_MAX_FILE_IO_SIZE; |
| @@ -5047,7 +5077,6 @@ int nfs4_init_session(struct nfs_server *server) | |||
| 5047 | if (wsize == 0) | 5077 | if (wsize == 0) |
| 5048 | wsize = NFS_MAX_FILE_IO_SIZE; | 5078 | wsize = NFS_MAX_FILE_IO_SIZE; |
| 5049 | 5079 | ||
| 5050 | session = clp->cl_session; | ||
| 5051 | session->fc_attrs.max_rqst_sz = wsize + nfs41_maxwrite_overhead; | 5080 | session->fc_attrs.max_rqst_sz = wsize + nfs41_maxwrite_overhead; |
| 5052 | session->fc_attrs.max_resp_sz = rsize + nfs41_maxread_overhead; | 5081 | session->fc_attrs.max_resp_sz = rsize + nfs41_maxread_overhead; |
| 5053 | 5082 | ||
| @@ -5060,69 +5089,70 @@ int nfs4_init_session(struct nfs_server *server) | |||
| 5060 | /* | 5089 | /* |
| 5061 | * Renew the cl_session lease. | 5090 | * Renew the cl_session lease. |
| 5062 | */ | 5091 | */ |
| 5063 | static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred) | 5092 | struct nfs4_sequence_data { |
| 5064 | { | 5093 | struct nfs_client *clp; |
| 5065 | struct nfs4_sequence_args args; | 5094 | struct nfs4_sequence_args args; |
| 5066 | struct nfs4_sequence_res res; | 5095 | struct nfs4_sequence_res res; |
| 5067 | 5096 | }; | |
| 5068 | struct rpc_message msg = { | ||
| 5069 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE], | ||
| 5070 | .rpc_argp = &args, | ||
| 5071 | .rpc_resp = &res, | ||
| 5072 | .rpc_cred = cred, | ||
| 5073 | }; | ||
| 5074 | |||
| 5075 | args.sa_cache_this = 0; | ||
| 5076 | |||
| 5077 | return nfs4_call_sync_sequence(clp, clp->cl_rpcclient, &msg, &args, | ||
| 5078 | &res, args.sa_cache_this, 1); | ||
| 5079 | } | ||
| 5080 | 5097 | ||
| 5081 | static void nfs41_sequence_release(void *data) | 5098 | static void nfs41_sequence_release(void *data) |
| 5082 | { | 5099 | { |
| 5083 | struct nfs_client *clp = (struct nfs_client *)data; | 5100 | struct nfs4_sequence_data *calldata = data; |
| 5101 | struct nfs_client *clp = calldata->clp; | ||
| 5084 | 5102 | ||
| 5085 | if (atomic_read(&clp->cl_count) > 1) | 5103 | if (atomic_read(&clp->cl_count) > 1) |
| 5086 | nfs4_schedule_state_renewal(clp); | 5104 | nfs4_schedule_state_renewal(clp); |
| 5087 | nfs_put_client(clp); | 5105 | nfs_put_client(clp); |
| 5106 | kfree(calldata); | ||
| 5107 | } | ||
| 5108 | |||
| 5109 | static int nfs41_sequence_handle_errors(struct rpc_task *task, struct nfs_client *clp) | ||
| 5110 | { | ||
| 5111 | switch(task->tk_status) { | ||
| 5112 | case -NFS4ERR_DELAY: | ||
| 5113 | case -EKEYEXPIRED: | ||
| 5114 | rpc_delay(task, NFS4_POLL_RETRY_MAX); | ||
| 5115 | return -EAGAIN; | ||
| 5116 | default: | ||
| 5117 | nfs4_schedule_state_recovery(clp); | ||
| 5118 | } | ||
| 5119 | return 0; | ||
| 5088 | } | 5120 | } |
| 5089 | 5121 | ||
| 5090 | static void nfs41_sequence_call_done(struct rpc_task *task, void *data) | 5122 | static void nfs41_sequence_call_done(struct rpc_task *task, void *data) |
| 5091 | { | 5123 | { |
| 5092 | struct nfs_client *clp = (struct nfs_client *)data; | 5124 | struct nfs4_sequence_data *calldata = data; |
| 5125 | struct nfs_client *clp = calldata->clp; | ||
| 5093 | 5126 | ||
| 5094 | nfs41_sequence_done(clp, task->tk_msg.rpc_resp, task->tk_status); | 5127 | if (!nfs41_sequence_done(task, task->tk_msg.rpc_resp)) |
| 5128 | return; | ||
| 5095 | 5129 | ||
| 5096 | if (task->tk_status < 0) { | 5130 | if (task->tk_status < 0) { |
| 5097 | dprintk("%s ERROR %d\n", __func__, task->tk_status); | 5131 | dprintk("%s ERROR %d\n", __func__, task->tk_status); |
| 5098 | if (atomic_read(&clp->cl_count) == 1) | 5132 | if (atomic_read(&clp->cl_count) == 1) |
| 5099 | goto out; | 5133 | goto out; |
| 5100 | 5134 | ||
| 5101 | if (_nfs4_async_handle_error(task, NULL, clp, NULL) | 5135 | if (nfs41_sequence_handle_errors(task, clp) == -EAGAIN) { |
| 5102 | == -EAGAIN) { | 5136 | rpc_restart_call_prepare(task); |
| 5103 | nfs_restart_rpc(task, clp); | ||
| 5104 | return; | 5137 | return; |
| 5105 | } | 5138 | } |
| 5106 | } | 5139 | } |
| 5107 | dprintk("%s rpc_cred %p\n", __func__, task->tk_msg.rpc_cred); | 5140 | dprintk("%s rpc_cred %p\n", __func__, task->tk_msg.rpc_cred); |
| 5108 | out: | 5141 | out: |
| 5109 | kfree(task->tk_msg.rpc_argp); | ||
| 5110 | kfree(task->tk_msg.rpc_resp); | ||
| 5111 | |||
| 5112 | dprintk("<-- %s\n", __func__); | 5142 | dprintk("<-- %s\n", __func__); |
| 5113 | } | 5143 | } |
| 5114 | 5144 | ||
| 5115 | static void nfs41_sequence_prepare(struct rpc_task *task, void *data) | 5145 | static void nfs41_sequence_prepare(struct rpc_task *task, void *data) |
| 5116 | { | 5146 | { |
| 5117 | struct nfs_client *clp; | 5147 | struct nfs4_sequence_data *calldata = data; |
| 5148 | struct nfs_client *clp = calldata->clp; | ||
| 5118 | struct nfs4_sequence_args *args; | 5149 | struct nfs4_sequence_args *args; |
| 5119 | struct nfs4_sequence_res *res; | 5150 | struct nfs4_sequence_res *res; |
| 5120 | 5151 | ||
| 5121 | clp = (struct nfs_client *)data; | ||
| 5122 | args = task->tk_msg.rpc_argp; | 5152 | args = task->tk_msg.rpc_argp; |
| 5123 | res = task->tk_msg.rpc_resp; | 5153 | res = task->tk_msg.rpc_resp; |
| 5124 | 5154 | ||
| 5125 | if (nfs4_setup_sequence(clp, args, res, 0, task)) | 5155 | if (nfs41_setup_sequence(clp->cl_session, args, res, 0, task)) |
| 5126 | return; | 5156 | return; |
| 5127 | rpc_call_start(task); | 5157 | rpc_call_start(task); |
| 5128 | } | 5158 | } |
| @@ -5133,32 +5163,67 @@ static const struct rpc_call_ops nfs41_sequence_ops = { | |||
| 5133 | .rpc_release = nfs41_sequence_release, | 5163 | .rpc_release = nfs41_sequence_release, |
| 5134 | }; | 5164 | }; |
| 5135 | 5165 | ||
| 5136 | static int nfs41_proc_async_sequence(struct nfs_client *clp, | 5166 | static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred) |
| 5137 | struct rpc_cred *cred) | ||
| 5138 | { | 5167 | { |
| 5139 | struct nfs4_sequence_args *args; | 5168 | struct nfs4_sequence_data *calldata; |
| 5140 | struct nfs4_sequence_res *res; | ||
| 5141 | struct rpc_message msg = { | 5169 | struct rpc_message msg = { |
| 5142 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE], | 5170 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE], |
| 5143 | .rpc_cred = cred, | 5171 | .rpc_cred = cred, |
| 5144 | }; | 5172 | }; |
| 5173 | struct rpc_task_setup task_setup_data = { | ||
| 5174 | .rpc_client = clp->cl_rpcclient, | ||
| 5175 | .rpc_message = &msg, | ||
| 5176 | .callback_ops = &nfs41_sequence_ops, | ||
| 5177 | .flags = RPC_TASK_ASYNC | RPC_TASK_SOFT, | ||
| 5178 | }; | ||
| 5145 | 5179 | ||
| 5146 | if (!atomic_inc_not_zero(&clp->cl_count)) | 5180 | if (!atomic_inc_not_zero(&clp->cl_count)) |
| 5147 | return -EIO; | 5181 | return ERR_PTR(-EIO); |
| 5148 | args = kzalloc(sizeof(*args), GFP_NOFS); | 5182 | calldata = kmalloc(sizeof(*calldata), GFP_NOFS); |
| 5149 | res = kzalloc(sizeof(*res), GFP_NOFS); | 5183 | if (calldata == NULL) { |
| 5150 | if (!args || !res) { | ||
| 5151 | kfree(args); | ||
| 5152 | kfree(res); | ||
| 5153 | nfs_put_client(clp); | 5184 | nfs_put_client(clp); |
| 5154 | return -ENOMEM; | 5185 | return ERR_PTR(-ENOMEM); |
| 5155 | } | 5186 | } |
| 5156 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | 5187 | calldata->res.sr_slotid = NFS4_MAX_SLOT_TABLE; |
| 5157 | msg.rpc_argp = args; | 5188 | msg.rpc_argp = &calldata->args; |
| 5158 | msg.rpc_resp = res; | 5189 | msg.rpc_resp = &calldata->res; |
| 5190 | calldata->clp = clp; | ||
| 5191 | task_setup_data.callback_data = calldata; | ||
| 5159 | 5192 | ||
| 5160 | return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT, | 5193 | return rpc_run_task(&task_setup_data); |
| 5161 | &nfs41_sequence_ops, (void *)clp); | 5194 | } |
| 5195 | |||
| 5196 | static int nfs41_proc_async_sequence(struct nfs_client *clp, struct rpc_cred *cred) | ||
| 5197 | { | ||
| 5198 | struct rpc_task *task; | ||
| 5199 | int ret = 0; | ||
| 5200 | |||
| 5201 | task = _nfs41_proc_sequence(clp, cred); | ||
| 5202 | if (IS_ERR(task)) | ||
| 5203 | ret = PTR_ERR(task); | ||
| 5204 | else | ||
| 5205 | rpc_put_task(task); | ||
| 5206 | dprintk("<-- %s status=%d\n", __func__, ret); | ||
| 5207 | return ret; | ||
| 5208 | } | ||
| 5209 | |||
| 5210 | static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred) | ||
| 5211 | { | ||
| 5212 | struct rpc_task *task; | ||
| 5213 | int ret; | ||
| 5214 | |||
| 5215 | task = _nfs41_proc_sequence(clp, cred); | ||
| 5216 | if (IS_ERR(task)) { | ||
| 5217 | ret = PTR_ERR(task); | ||
| 5218 | goto out; | ||
| 5219 | } | ||
| 5220 | ret = rpc_wait_for_completion_task(task); | ||
| 5221 | if (!ret) | ||
| 5222 | ret = task->tk_status; | ||
| 5223 | rpc_put_task(task); | ||
| 5224 | out: | ||
| 5225 | dprintk("<-- %s status=%d\n", __func__, ret); | ||
| 5226 | return ret; | ||
| 5162 | } | 5227 | } |
| 5163 | 5228 | ||
| 5164 | struct nfs4_reclaim_complete_data { | 5229 | struct nfs4_reclaim_complete_data { |
| @@ -5172,13 +5237,31 @@ static void nfs4_reclaim_complete_prepare(struct rpc_task *task, void *data) | |||
| 5172 | struct nfs4_reclaim_complete_data *calldata = data; | 5237 | struct nfs4_reclaim_complete_data *calldata = data; |
| 5173 | 5238 | ||
| 5174 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | 5239 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); |
| 5175 | if (nfs4_setup_sequence(calldata->clp, &calldata->arg.seq_args, | 5240 | if (nfs41_setup_sequence(calldata->clp->cl_session, |
| 5241 | &calldata->arg.seq_args, | ||
| 5176 | &calldata->res.seq_res, 0, task)) | 5242 | &calldata->res.seq_res, 0, task)) |
| 5177 | return; | 5243 | return; |
| 5178 | 5244 | ||
| 5179 | rpc_call_start(task); | 5245 | rpc_call_start(task); |
| 5180 | } | 5246 | } |
| 5181 | 5247 | ||
| 5248 | static int nfs41_reclaim_complete_handle_errors(struct rpc_task *task, struct nfs_client *clp) | ||
| 5249 | { | ||
| 5250 | switch(task->tk_status) { | ||
| 5251 | case 0: | ||
| 5252 | case -NFS4ERR_COMPLETE_ALREADY: | ||
| 5253 | case -NFS4ERR_WRONG_CRED: /* What to do here? */ | ||
| 5254 | break; | ||
| 5255 | case -NFS4ERR_DELAY: | ||
| 5256 | case -EKEYEXPIRED: | ||
| 5257 | rpc_delay(task, NFS4_POLL_RETRY_MAX); | ||
| 5258 | return -EAGAIN; | ||
| 5259 | default: | ||
| 5260 | nfs4_schedule_state_recovery(clp); | ||
| 5261 | } | ||
| 5262 | return 0; | ||
| 5263 | } | ||
| 5264 | |||
| 5182 | static void nfs4_reclaim_complete_done(struct rpc_task *task, void *data) | 5265 | static void nfs4_reclaim_complete_done(struct rpc_task *task, void *data) |
| 5183 | { | 5266 | { |
| 5184 | struct nfs4_reclaim_complete_data *calldata = data; | 5267 | struct nfs4_reclaim_complete_data *calldata = data; |
| @@ -5186,32 +5269,13 @@ static void nfs4_reclaim_complete_done(struct rpc_task *task, void *data) | |||
| 5186 | struct nfs4_sequence_res *res = &calldata->res.seq_res; | 5269 | struct nfs4_sequence_res *res = &calldata->res.seq_res; |
| 5187 | 5270 | ||
| 5188 | dprintk("--> %s\n", __func__); | 5271 | dprintk("--> %s\n", __func__); |
| 5189 | nfs41_sequence_done(clp, res, task->tk_status); | 5272 | if (!nfs41_sequence_done(task, res)) |
| 5190 | switch (task->tk_status) { | 5273 | return; |
| 5191 | case 0: | ||
| 5192 | case -NFS4ERR_COMPLETE_ALREADY: | ||
| 5193 | break; | ||
| 5194 | case -NFS4ERR_BADSESSION: | ||
| 5195 | case -NFS4ERR_DEADSESSION: | ||
| 5196 | /* | ||
| 5197 | * Handle the session error, but do not retry the operation, as | ||
| 5198 | * we have no way of telling whether the clientid had to be | ||
| 5199 | * reset before we got our reply. If reset, a new wave of | ||
| 5200 | * reclaim operations will follow, containing their own reclaim | ||
| 5201 | * complete. We don't want our retry to get on the way of | ||
| 5202 | * recovery by incorrectly indicating to the server that we're | ||
| 5203 | * done reclaiming state since the process had to be restarted. | ||
| 5204 | */ | ||
| 5205 | _nfs4_async_handle_error(task, NULL, clp, NULL); | ||
| 5206 | break; | ||
| 5207 | default: | ||
| 5208 | if (_nfs4_async_handle_error( | ||
| 5209 | task, NULL, clp, NULL) == -EAGAIN) { | ||
| 5210 | rpc_restart_call_prepare(task); | ||
| 5211 | return; | ||
| 5212 | } | ||
| 5213 | } | ||
| 5214 | 5274 | ||
| 5275 | if (nfs41_reclaim_complete_handle_errors(task, clp) == -EAGAIN) { | ||
| 5276 | rpc_restart_call_prepare(task); | ||
| 5277 | return; | ||
| 5278 | } | ||
| 5215 | dprintk("<-- %s\n", __func__); | 5279 | dprintk("<-- %s\n", __func__); |
| 5216 | } | 5280 | } |
| 5217 | 5281 | ||
| @@ -5325,28 +5389,30 @@ struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = { | |||
| 5325 | }; | 5389 | }; |
| 5326 | #endif | 5390 | #endif |
| 5327 | 5391 | ||
| 5328 | /* | 5392 | static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = { |
| 5329 | * Per minor version reboot and network partition recovery ops | 5393 | .minor_version = 0, |
| 5330 | */ | 5394 | .call_sync = _nfs4_call_sync, |
| 5331 | 5395 | .validate_stateid = nfs4_validate_delegation_stateid, | |
| 5332 | struct nfs4_state_recovery_ops *nfs4_reboot_recovery_ops[] = { | 5396 | .reboot_recovery_ops = &nfs40_reboot_recovery_ops, |
| 5333 | &nfs40_reboot_recovery_ops, | 5397 | .nograce_recovery_ops = &nfs40_nograce_recovery_ops, |
| 5334 | #if defined(CONFIG_NFS_V4_1) | 5398 | .state_renewal_ops = &nfs40_state_renewal_ops, |
| 5335 | &nfs41_reboot_recovery_ops, | ||
| 5336 | #endif | ||
| 5337 | }; | 5399 | }; |
| 5338 | 5400 | ||
| 5339 | struct nfs4_state_recovery_ops *nfs4_nograce_recovery_ops[] = { | ||
| 5340 | &nfs40_nograce_recovery_ops, | ||
| 5341 | #if defined(CONFIG_NFS_V4_1) | 5401 | #if defined(CONFIG_NFS_V4_1) |
| 5342 | &nfs41_nograce_recovery_ops, | 5402 | static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = { |
| 5343 | #endif | 5403 | .minor_version = 1, |
| 5404 | .call_sync = _nfs4_call_sync_session, | ||
| 5405 | .validate_stateid = nfs41_validate_delegation_stateid, | ||
| 5406 | .reboot_recovery_ops = &nfs41_reboot_recovery_ops, | ||
| 5407 | .nograce_recovery_ops = &nfs41_nograce_recovery_ops, | ||
| 5408 | .state_renewal_ops = &nfs41_state_renewal_ops, | ||
| 5344 | }; | 5409 | }; |
| 5410 | #endif | ||
| 5345 | 5411 | ||
| 5346 | struct nfs4_state_maintenance_ops *nfs4_state_renewal_ops[] = { | 5412 | const struct nfs4_minor_version_ops *nfs_v4_minor_ops[] = { |
| 5347 | &nfs40_state_renewal_ops, | 5413 | [0] = &nfs_v4_0_minor_ops, |
| 5348 | #if defined(CONFIG_NFS_V4_1) | 5414 | #if defined(CONFIG_NFS_V4_1) |
| 5349 | &nfs41_state_renewal_ops, | 5415 | [1] = &nfs_v4_1_minor_ops, |
| 5350 | #endif | 5416 | #endif |
| 5351 | }; | 5417 | }; |
| 5352 | 5418 | ||
