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 | ||