diff options
41 files changed, 1174 insertions, 563 deletions
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index 0796c45d0d4d..01bfe7662751 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c | |||
@@ -144,6 +144,9 @@ int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout) | |||
144 | timeout); | 144 | timeout); |
145 | if (ret < 0) | 145 | if (ret < 0) |
146 | return -ERESTARTSYS; | 146 | return -ERESTARTSYS; |
147 | /* Reset the lock status after a server reboot so we resend */ | ||
148 | if (block->b_status == nlm_lck_denied_grace_period) | ||
149 | block->b_status = nlm_lck_blocked; | ||
147 | req->a_res.status = block->b_status; | 150 | req->a_res.status = block->b_status; |
148 | return 0; | 151 | return 0; |
149 | } | 152 | } |
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 7e529c3c45c0..9760ecb9b60f 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c | |||
@@ -550,9 +550,6 @@ again: | |||
550 | status = nlmclnt_block(block, req, NLMCLNT_POLL_TIMEOUT); | 550 | status = nlmclnt_block(block, req, NLMCLNT_POLL_TIMEOUT); |
551 | if (status < 0) | 551 | if (status < 0) |
552 | break; | 552 | break; |
553 | /* Resend the blocking lock request after a server reboot */ | ||
554 | if (resp->status == nlm_lck_denied_grace_period) | ||
555 | continue; | ||
556 | if (resp->status != nlm_lck_blocked) | 553 | if (resp->status != nlm_lck_blocked) |
557 | break; | 554 | break; |
558 | } | 555 | } |
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 5088b57b078a..cff089a412c7 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
@@ -125,6 +125,9 @@ nfs41_callback_svc(void *vrqstp) | |||
125 | set_freezable(); | 125 | set_freezable(); |
126 | 126 | ||
127 | while (!kthread_should_stop()) { | 127 | while (!kthread_should_stop()) { |
128 | if (try_to_freeze()) | ||
129 | continue; | ||
130 | |||
128 | prepare_to_wait(&serv->sv_cb_waitq, &wq, TASK_INTERRUPTIBLE); | 131 | prepare_to_wait(&serv->sv_cb_waitq, &wq, TASK_INTERRUPTIBLE); |
129 | spin_lock_bh(&serv->sv_cb_lock); | 132 | spin_lock_bh(&serv->sv_cb_lock); |
130 | if (!list_empty(&serv->sv_cb_list)) { | 133 | if (!list_empty(&serv->sv_cb_list)) { |
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index 2960512792c2..a13d26ede254 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
@@ -500,7 +500,7 @@ __be32 nfs4_callback_recallany(struct cb_recallanyargs *args, void *dummy, | |||
500 | &args->craa_type_mask)) | 500 | &args->craa_type_mask)) |
501 | pnfs_recall_all_layouts(cps->clp); | 501 | pnfs_recall_all_layouts(cps->clp); |
502 | if (flags) | 502 | if (flags) |
503 | nfs_expire_all_delegation_types(cps->clp, flags); | 503 | nfs_expire_unused_delegation_types(cps->clp, flags); |
504 | out: | 504 | out: |
505 | dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); | 505 | dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); |
506 | return status; | 506 | return status; |
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 84d8eae203a7..c513b0cc835f 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -593,6 +593,8 @@ int nfs_create_rpc_client(struct nfs_client *clp, | |||
593 | args.flags |= RPC_CLNT_CREATE_DISCRTRY; | 593 | args.flags |= RPC_CLNT_CREATE_DISCRTRY; |
594 | if (test_bit(NFS_CS_NORESVPORT, &clp->cl_flags)) | 594 | if (test_bit(NFS_CS_NORESVPORT, &clp->cl_flags)) |
595 | args.flags |= RPC_CLNT_CREATE_NONPRIVPORT; | 595 | args.flags |= RPC_CLNT_CREATE_NONPRIVPORT; |
596 | if (test_bit(NFS_CS_INFINITE_SLOTS, &clp->cl_flags)) | ||
597 | args.flags |= RPC_CLNT_CREATE_INFINITE_SLOTS; | ||
596 | 598 | ||
597 | if (!IS_ERR(clp->cl_rpcclient)) | 599 | if (!IS_ERR(clp->cl_rpcclient)) |
598 | return 0; | 600 | return 0; |
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 6390a4b5fee7..57db3244f4d9 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
@@ -64,17 +64,15 @@ int nfs4_have_delegation(struct inode *inode, fmode_t flags) | |||
64 | return ret; | 64 | return ret; |
65 | } | 65 | } |
66 | 66 | ||
67 | static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_state *state) | 67 | static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid) |
68 | { | 68 | { |
69 | struct inode *inode = state->inode; | 69 | struct inode *inode = state->inode; |
70 | struct file_lock *fl; | 70 | struct file_lock *fl; |
71 | int status = 0; | 71 | int status = 0; |
72 | 72 | ||
73 | if (inode->i_flock == NULL) | 73 | if (inode->i_flock == NULL) |
74 | return 0; | ||
75 | |||
76 | if (inode->i_flock == NULL) | ||
77 | goto out; | 74 | goto out; |
75 | |||
78 | /* Protect inode->i_flock using the file locks lock */ | 76 | /* Protect inode->i_flock using the file locks lock */ |
79 | lock_flocks(); | 77 | lock_flocks(); |
80 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { | 78 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { |
@@ -83,7 +81,7 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_ | |||
83 | if (nfs_file_open_context(fl->fl_file) != ctx) | 81 | if (nfs_file_open_context(fl->fl_file) != ctx) |
84 | continue; | 82 | continue; |
85 | unlock_flocks(); | 83 | unlock_flocks(); |
86 | status = nfs4_lock_delegation_recall(state, fl); | 84 | status = nfs4_lock_delegation_recall(fl, state, stateid); |
87 | if (status < 0) | 85 | if (status < 0) |
88 | goto out; | 86 | goto out; |
89 | lock_flocks(); | 87 | lock_flocks(); |
@@ -120,7 +118,7 @@ again: | |||
120 | seq = raw_seqcount_begin(&sp->so_reclaim_seqcount); | 118 | seq = raw_seqcount_begin(&sp->so_reclaim_seqcount); |
121 | err = nfs4_open_delegation_recall(ctx, state, stateid); | 119 | err = nfs4_open_delegation_recall(ctx, state, stateid); |
122 | if (!err) | 120 | if (!err) |
123 | err = nfs_delegation_claim_locks(ctx, state); | 121 | err = nfs_delegation_claim_locks(ctx, state, stateid); |
124 | if (!err && read_seqcount_retry(&sp->so_reclaim_seqcount, seq)) | 122 | if (!err && read_seqcount_retry(&sp->so_reclaim_seqcount, seq)) |
125 | err = -EAGAIN; | 123 | err = -EAGAIN; |
126 | mutex_unlock(&sp->so_delegreturn_mutex); | 124 | mutex_unlock(&sp->so_delegreturn_mutex); |
@@ -389,6 +387,24 @@ out: | |||
389 | return err; | 387 | return err; |
390 | } | 388 | } |
391 | 389 | ||
390 | static bool nfs_delegation_need_return(struct nfs_delegation *delegation) | ||
391 | { | ||
392 | bool ret = false; | ||
393 | |||
394 | if (test_and_clear_bit(NFS_DELEGATION_RETURN, &delegation->flags)) | ||
395 | ret = true; | ||
396 | if (test_and_clear_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags) && !ret) { | ||
397 | struct inode *inode; | ||
398 | |||
399 | spin_lock(&delegation->lock); | ||
400 | inode = delegation->inode; | ||
401 | if (inode && list_empty(&NFS_I(inode)->open_files)) | ||
402 | ret = true; | ||
403 | spin_unlock(&delegation->lock); | ||
404 | } | ||
405 | return ret; | ||
406 | } | ||
407 | |||
392 | /** | 408 | /** |
393 | * nfs_client_return_marked_delegations - return previously marked delegations | 409 | * nfs_client_return_marked_delegations - return previously marked delegations |
394 | * @clp: nfs_client to process | 410 | * @clp: nfs_client to process |
@@ -411,8 +427,7 @@ restart: | |||
411 | list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { | 427 | list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { |
412 | list_for_each_entry_rcu(delegation, &server->delegations, | 428 | list_for_each_entry_rcu(delegation, &server->delegations, |
413 | super_list) { | 429 | super_list) { |
414 | if (!test_and_clear_bit(NFS_DELEGATION_RETURN, | 430 | if (!nfs_delegation_need_return(delegation)) |
415 | &delegation->flags)) | ||
416 | continue; | 431 | continue; |
417 | inode = nfs_delegation_grab_inode(delegation); | 432 | inode = nfs_delegation_grab_inode(delegation); |
418 | if (inode == NULL) | 433 | if (inode == NULL) |
@@ -471,6 +486,13 @@ int nfs4_inode_return_delegation(struct inode *inode) | |||
471 | return err; | 486 | return err; |
472 | } | 487 | } |
473 | 488 | ||
489 | static void nfs_mark_return_if_closed_delegation(struct nfs_server *server, | ||
490 | struct nfs_delegation *delegation) | ||
491 | { | ||
492 | set_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags); | ||
493 | set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state); | ||
494 | } | ||
495 | |||
474 | static void nfs_mark_return_delegation(struct nfs_server *server, | 496 | static void nfs_mark_return_delegation(struct nfs_server *server, |
475 | struct nfs_delegation *delegation) | 497 | struct nfs_delegation *delegation) |
476 | { | 498 | { |
@@ -478,6 +500,45 @@ static void nfs_mark_return_delegation(struct nfs_server *server, | |||
478 | set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state); | 500 | set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state); |
479 | } | 501 | } |
480 | 502 | ||
503 | static bool nfs_server_mark_return_all_delegations(struct nfs_server *server) | ||
504 | { | ||
505 | struct nfs_delegation *delegation; | ||
506 | bool ret = false; | ||
507 | |||
508 | list_for_each_entry_rcu(delegation, &server->delegations, super_list) { | ||
509 | nfs_mark_return_delegation(server, delegation); | ||
510 | ret = true; | ||
511 | } | ||
512 | return ret; | ||
513 | } | ||
514 | |||
515 | static void nfs_client_mark_return_all_delegations(struct nfs_client *clp) | ||
516 | { | ||
517 | struct nfs_server *server; | ||
518 | |||
519 | rcu_read_lock(); | ||
520 | list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) | ||
521 | nfs_server_mark_return_all_delegations(server); | ||
522 | rcu_read_unlock(); | ||
523 | } | ||
524 | |||
525 | static void nfs_delegation_run_state_manager(struct nfs_client *clp) | ||
526 | { | ||
527 | if (test_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) | ||
528 | nfs4_schedule_state_manager(clp); | ||
529 | } | ||
530 | |||
531 | /** | ||
532 | * nfs_expire_all_delegations | ||
533 | * @clp: client to process | ||
534 | * | ||
535 | */ | ||
536 | void nfs_expire_all_delegations(struct nfs_client *clp) | ||
537 | { | ||
538 | nfs_client_mark_return_all_delegations(clp); | ||
539 | nfs_delegation_run_state_manager(clp); | ||
540 | } | ||
541 | |||
481 | /** | 542 | /** |
482 | * nfs_super_return_all_delegations - return delegations for one superblock | 543 | * nfs_super_return_all_delegations - return delegations for one superblock |
483 | * @sb: sb to process | 544 | * @sb: sb to process |
@@ -486,24 +547,22 @@ static void nfs_mark_return_delegation(struct nfs_server *server, | |||
486 | void nfs_server_return_all_delegations(struct nfs_server *server) | 547 | void nfs_server_return_all_delegations(struct nfs_server *server) |
487 | { | 548 | { |
488 | struct nfs_client *clp = server->nfs_client; | 549 | struct nfs_client *clp = server->nfs_client; |
489 | struct nfs_delegation *delegation; | 550 | bool need_wait; |
490 | 551 | ||
491 | if (clp == NULL) | 552 | if (clp == NULL) |
492 | return; | 553 | return; |
493 | 554 | ||
494 | rcu_read_lock(); | 555 | rcu_read_lock(); |
495 | list_for_each_entry_rcu(delegation, &server->delegations, super_list) { | 556 | need_wait = nfs_server_mark_return_all_delegations(server); |
496 | spin_lock(&delegation->lock); | ||
497 | set_bit(NFS_DELEGATION_RETURN, &delegation->flags); | ||
498 | spin_unlock(&delegation->lock); | ||
499 | } | ||
500 | rcu_read_unlock(); | 557 | rcu_read_unlock(); |
501 | 558 | ||
502 | if (nfs_client_return_marked_delegations(clp) != 0) | 559 | if (need_wait) { |
503 | nfs4_schedule_state_manager(clp); | 560 | nfs4_schedule_state_manager(clp); |
561 | nfs4_wait_clnt_recover(clp); | ||
562 | } | ||
504 | } | 563 | } |
505 | 564 | ||
506 | static void nfs_mark_return_all_delegation_types(struct nfs_server *server, | 565 | static void nfs_mark_return_unused_delegation_types(struct nfs_server *server, |
507 | fmode_t flags) | 566 | fmode_t flags) |
508 | { | 567 | { |
509 | struct nfs_delegation *delegation; | 568 | struct nfs_delegation *delegation; |
@@ -512,27 +571,21 @@ static void nfs_mark_return_all_delegation_types(struct nfs_server *server, | |||
512 | if ((delegation->type == (FMODE_READ|FMODE_WRITE)) && !(flags & FMODE_WRITE)) | 571 | if ((delegation->type == (FMODE_READ|FMODE_WRITE)) && !(flags & FMODE_WRITE)) |
513 | continue; | 572 | continue; |
514 | if (delegation->type & flags) | 573 | if (delegation->type & flags) |
515 | nfs_mark_return_delegation(server, delegation); | 574 | nfs_mark_return_if_closed_delegation(server, delegation); |
516 | } | 575 | } |
517 | } | 576 | } |
518 | 577 | ||
519 | static void nfs_client_mark_return_all_delegation_types(struct nfs_client *clp, | 578 | static void nfs_client_mark_return_unused_delegation_types(struct nfs_client *clp, |
520 | fmode_t flags) | 579 | fmode_t flags) |
521 | { | 580 | { |
522 | struct nfs_server *server; | 581 | struct nfs_server *server; |
523 | 582 | ||
524 | rcu_read_lock(); | 583 | rcu_read_lock(); |
525 | list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) | 584 | list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) |
526 | nfs_mark_return_all_delegation_types(server, flags); | 585 | nfs_mark_return_unused_delegation_types(server, flags); |
527 | rcu_read_unlock(); | 586 | rcu_read_unlock(); |
528 | } | 587 | } |
529 | 588 | ||
530 | static void nfs_delegation_run_state_manager(struct nfs_client *clp) | ||
531 | { | ||
532 | if (test_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) | ||
533 | nfs4_schedule_state_manager(clp); | ||
534 | } | ||
535 | |||
536 | void nfs_remove_bad_delegation(struct inode *inode) | 589 | void nfs_remove_bad_delegation(struct inode *inode) |
537 | { | 590 | { |
538 | struct nfs_delegation *delegation; | 591 | struct nfs_delegation *delegation; |
@@ -546,27 +599,17 @@ void nfs_remove_bad_delegation(struct inode *inode) | |||
546 | EXPORT_SYMBOL_GPL(nfs_remove_bad_delegation); | 599 | EXPORT_SYMBOL_GPL(nfs_remove_bad_delegation); |
547 | 600 | ||
548 | /** | 601 | /** |
549 | * nfs_expire_all_delegation_types | 602 | * nfs_expire_unused_delegation_types |
550 | * @clp: client to process | 603 | * @clp: client to process |
551 | * @flags: delegation types to expire | 604 | * @flags: delegation types to expire |
552 | * | 605 | * |
553 | */ | 606 | */ |
554 | void nfs_expire_all_delegation_types(struct nfs_client *clp, fmode_t flags) | 607 | void nfs_expire_unused_delegation_types(struct nfs_client *clp, fmode_t flags) |
555 | { | 608 | { |
556 | nfs_client_mark_return_all_delegation_types(clp, flags); | 609 | nfs_client_mark_return_unused_delegation_types(clp, flags); |
557 | nfs_delegation_run_state_manager(clp); | 610 | nfs_delegation_run_state_manager(clp); |
558 | } | 611 | } |
559 | 612 | ||
560 | /** | ||
561 | * nfs_expire_all_delegations | ||
562 | * @clp: client to process | ||
563 | * | ||
564 | */ | ||
565 | void nfs_expire_all_delegations(struct nfs_client *clp) | ||
566 | { | ||
567 | nfs_expire_all_delegation_types(clp, FMODE_READ|FMODE_WRITE); | ||
568 | } | ||
569 | |||
570 | static void nfs_mark_return_unreferenced_delegations(struct nfs_server *server) | 613 | static void nfs_mark_return_unreferenced_delegations(struct nfs_server *server) |
571 | { | 614 | { |
572 | struct nfs_delegation *delegation; | 615 | struct nfs_delegation *delegation; |
@@ -574,7 +617,7 @@ static void nfs_mark_return_unreferenced_delegations(struct nfs_server *server) | |||
574 | list_for_each_entry_rcu(delegation, &server->delegations, super_list) { | 617 | list_for_each_entry_rcu(delegation, &server->delegations, super_list) { |
575 | if (test_and_clear_bit(NFS_DELEGATION_REFERENCED, &delegation->flags)) | 618 | if (test_and_clear_bit(NFS_DELEGATION_REFERENCED, &delegation->flags)) |
576 | continue; | 619 | continue; |
577 | nfs_mark_return_delegation(server, delegation); | 620 | nfs_mark_return_if_closed_delegation(server, delegation); |
578 | } | 621 | } |
579 | } | 622 | } |
580 | 623 | ||
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index d54d4fca6793..9a79c7a99d6d 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h | |||
@@ -28,6 +28,7 @@ struct nfs_delegation { | |||
28 | enum { | 28 | enum { |
29 | NFS_DELEGATION_NEED_RECLAIM = 0, | 29 | NFS_DELEGATION_NEED_RECLAIM = 0, |
30 | NFS_DELEGATION_RETURN, | 30 | NFS_DELEGATION_RETURN, |
31 | NFS_DELEGATION_RETURN_IF_CLOSED, | ||
31 | NFS_DELEGATION_REFERENCED, | 32 | NFS_DELEGATION_REFERENCED, |
32 | NFS_DELEGATION_RETURNING, | 33 | NFS_DELEGATION_RETURNING, |
33 | }; | 34 | }; |
@@ -41,7 +42,7 @@ void nfs_inode_return_delegation_noreclaim(struct inode *inode); | |||
41 | struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle); | 42 | struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle); |
42 | void nfs_server_return_all_delegations(struct nfs_server *); | 43 | void nfs_server_return_all_delegations(struct nfs_server *); |
43 | void nfs_expire_all_delegations(struct nfs_client *clp); | 44 | void nfs_expire_all_delegations(struct nfs_client *clp); |
44 | void nfs_expire_all_delegation_types(struct nfs_client *clp, fmode_t flags); | 45 | void nfs_expire_unused_delegation_types(struct nfs_client *clp, fmode_t flags); |
45 | void nfs_expire_unreferenced_delegations(struct nfs_client *clp); | 46 | void nfs_expire_unreferenced_delegations(struct nfs_client *clp); |
46 | int nfs_client_return_marked_delegations(struct nfs_client *clp); | 47 | int nfs_client_return_marked_delegations(struct nfs_client *clp); |
47 | int nfs_delegations_present(struct nfs_client *clp); | 48 | int nfs_delegations_present(struct nfs_client *clp); |
@@ -53,7 +54,7 @@ void nfs_delegation_reap_unclaimed(struct nfs_client *clp); | |||
53 | /* NFSv4 delegation-related procedures */ | 54 | /* NFSv4 delegation-related procedures */ |
54 | int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid, int issync); | 55 | int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid, int issync); |
55 | int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid); | 56 | int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid); |
56 | int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl); | 57 | int nfs4_lock_delegation_recall(struct file_lock *fl, struct nfs4_state *state, const nfs4_stateid *stateid); |
57 | bool nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode, fmode_t flags); | 58 | bool nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode, fmode_t flags); |
58 | 59 | ||
59 | void nfs_mark_delegation_referenced(struct nfs_delegation *delegation); | 60 | void nfs_mark_delegation_referenced(struct nfs_delegation *delegation); |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index f23f455be42b..e093e73178b7 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -1486,6 +1486,8 @@ static int nfs4_lookup_revalidate(struct dentry *dentry, unsigned int flags) | |||
1486 | goto no_open; | 1486 | goto no_open; |
1487 | if (d_mountpoint(dentry)) | 1487 | if (d_mountpoint(dentry)) |
1488 | goto no_open; | 1488 | goto no_open; |
1489 | if (NFS_SB(dentry->d_sb)->caps & NFS_CAP_ATOMIC_OPEN_V1) | ||
1490 | goto no_open; | ||
1489 | 1491 | ||
1490 | inode = dentry->d_inode; | 1492 | inode = dentry->d_inode; |
1491 | parent = dget_parent(dentry); | 1493 | parent = dget_parent(dentry); |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 29f4a48a0ee6..a87a44f84113 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -744,6 +744,7 @@ static int | |||
744 | do_unlk(struct file *filp, int cmd, struct file_lock *fl, int is_local) | 744 | do_unlk(struct file *filp, int cmd, struct file_lock *fl, int is_local) |
745 | { | 745 | { |
746 | struct inode *inode = filp->f_mapping->host; | 746 | struct inode *inode = filp->f_mapping->host; |
747 | struct nfs_lock_context *l_ctx; | ||
747 | int status; | 748 | int status; |
748 | 749 | ||
749 | /* | 750 | /* |
@@ -752,6 +753,14 @@ do_unlk(struct file *filp, int cmd, struct file_lock *fl, int is_local) | |||
752 | */ | 753 | */ |
753 | nfs_sync_mapping(filp->f_mapping); | 754 | nfs_sync_mapping(filp->f_mapping); |
754 | 755 | ||
756 | l_ctx = nfs_get_lock_context(nfs_file_open_context(filp)); | ||
757 | if (!IS_ERR(l_ctx)) { | ||
758 | status = nfs_iocounter_wait(&l_ctx->io_count); | ||
759 | nfs_put_lock_context(l_ctx); | ||
760 | if (status < 0) | ||
761 | return status; | ||
762 | } | ||
763 | |||
755 | /* NOTE: special case | 764 | /* NOTE: special case |
756 | * If we're signalled while cleaning up locks on process exit, we | 765 | * If we're signalled while cleaning up locks on process exit, we |
757 | * still need to complete the unlock. | 766 | * still need to complete the unlock. |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 1f941674b089..c1c7a9d78722 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -561,20 +561,22 @@ static void nfs_init_lock_context(struct nfs_lock_context *l_ctx) | |||
561 | l_ctx->lockowner.l_owner = current->files; | 561 | l_ctx->lockowner.l_owner = current->files; |
562 | l_ctx->lockowner.l_pid = current->tgid; | 562 | l_ctx->lockowner.l_pid = current->tgid; |
563 | INIT_LIST_HEAD(&l_ctx->list); | 563 | INIT_LIST_HEAD(&l_ctx->list); |
564 | nfs_iocounter_init(&l_ctx->io_count); | ||
564 | } | 565 | } |
565 | 566 | ||
566 | static struct nfs_lock_context *__nfs_find_lock_context(struct nfs_open_context *ctx) | 567 | static struct nfs_lock_context *__nfs_find_lock_context(struct nfs_open_context *ctx) |
567 | { | 568 | { |
568 | struct nfs_lock_context *pos; | 569 | struct nfs_lock_context *head = &ctx->lock_context; |
570 | struct nfs_lock_context *pos = head; | ||
569 | 571 | ||
570 | list_for_each_entry(pos, &ctx->lock_context.list, list) { | 572 | do { |
571 | if (pos->lockowner.l_owner != current->files) | 573 | if (pos->lockowner.l_owner != current->files) |
572 | continue; | 574 | continue; |
573 | if (pos->lockowner.l_pid != current->tgid) | 575 | if (pos->lockowner.l_pid != current->tgid) |
574 | continue; | 576 | continue; |
575 | atomic_inc(&pos->count); | 577 | atomic_inc(&pos->count); |
576 | return pos; | 578 | return pos; |
577 | } | 579 | } while ((pos = list_entry(pos->list.next, typeof(*pos), list)) != head); |
578 | return NULL; | 580 | return NULL; |
579 | } | 581 | } |
580 | 582 | ||
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 541c9ebdbc5a..91e59a39fc08 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -229,6 +229,13 @@ extern void nfs_pgheader_init(struct nfs_pageio_descriptor *desc, | |||
229 | struct nfs_pgio_header *hdr, | 229 | struct nfs_pgio_header *hdr, |
230 | void (*release)(struct nfs_pgio_header *hdr)); | 230 | void (*release)(struct nfs_pgio_header *hdr)); |
231 | void nfs_set_pgio_error(struct nfs_pgio_header *hdr, int error, loff_t pos); | 231 | void nfs_set_pgio_error(struct nfs_pgio_header *hdr, int error, loff_t pos); |
232 | int nfs_iocounter_wait(struct nfs_io_counter *c); | ||
233 | |||
234 | static inline void nfs_iocounter_init(struct nfs_io_counter *c) | ||
235 | { | ||
236 | c->flags = 0; | ||
237 | atomic_set(&c->io_count, 0); | ||
238 | } | ||
232 | 239 | ||
233 | /* nfs2xdr.c */ | 240 | /* nfs2xdr.c */ |
234 | extern struct rpc_procinfo nfs_procedures[]; | 241 | extern struct rpc_procinfo nfs_procedures[]; |
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 944c9a5c1039..553a83cc4106 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -36,6 +36,7 @@ enum nfs4_client_state { | |||
36 | 36 | ||
37 | struct nfs4_minor_version_ops { | 37 | struct nfs4_minor_version_ops { |
38 | u32 minor_version; | 38 | u32 minor_version; |
39 | unsigned init_caps; | ||
39 | 40 | ||
40 | int (*call_sync)(struct rpc_clnt *clnt, | 41 | int (*call_sync)(struct rpc_clnt *clnt, |
41 | struct nfs_server *server, | 42 | struct nfs_server *server, |
@@ -143,12 +144,14 @@ struct nfs4_lock_state { | |||
143 | enum { | 144 | enum { |
144 | LK_STATE_IN_USE, | 145 | LK_STATE_IN_USE, |
145 | NFS_DELEGATED_STATE, /* Current stateid is delegation */ | 146 | NFS_DELEGATED_STATE, /* Current stateid is delegation */ |
147 | NFS_OPEN_STATE, /* OPEN stateid is set */ | ||
146 | NFS_O_RDONLY_STATE, /* OPEN stateid has read-only state */ | 148 | NFS_O_RDONLY_STATE, /* OPEN stateid has read-only state */ |
147 | NFS_O_WRONLY_STATE, /* OPEN stateid has write-only state */ | 149 | NFS_O_WRONLY_STATE, /* OPEN stateid has write-only state */ |
148 | NFS_O_RDWR_STATE, /* OPEN stateid has read/write state */ | 150 | NFS_O_RDWR_STATE, /* OPEN stateid has read/write state */ |
149 | NFS_STATE_RECLAIM_REBOOT, /* OPEN stateid server rebooted */ | 151 | NFS_STATE_RECLAIM_REBOOT, /* OPEN stateid server rebooted */ |
150 | NFS_STATE_RECLAIM_NOGRACE, /* OPEN stateid needs to recover state */ | 152 | NFS_STATE_RECLAIM_NOGRACE, /* OPEN stateid needs to recover state */ |
151 | NFS_STATE_POSIX_LOCKS, /* Posix locks are supported */ | 153 | NFS_STATE_POSIX_LOCKS, /* Posix locks are supported */ |
154 | NFS_STATE_RECOVERY_FAILED, /* OPEN stateid state recovery failed */ | ||
152 | }; | 155 | }; |
153 | 156 | ||
154 | struct nfs4_state { | 157 | struct nfs4_state { |
@@ -233,6 +236,10 @@ extern struct rpc_clnt *nfs4_proc_lookup_mountpoint(struct inode *, struct qstr | |||
233 | extern int nfs4_proc_secinfo(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *); | 236 | extern int nfs4_proc_secinfo(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *); |
234 | extern int nfs4_release_lockowner(struct nfs4_lock_state *); | 237 | extern int nfs4_release_lockowner(struct nfs4_lock_state *); |
235 | extern const struct xattr_handler *nfs4_xattr_handlers[]; | 238 | extern const struct xattr_handler *nfs4_xattr_handlers[]; |
239 | extern int nfs4_set_rw_stateid(nfs4_stateid *stateid, | ||
240 | const struct nfs_open_context *ctx, | ||
241 | const struct nfs_lock_context *l_ctx, | ||
242 | fmode_t fmode); | ||
236 | 243 | ||
237 | #if defined(CONFIG_NFS_V4_1) | 244 | #if defined(CONFIG_NFS_V4_1) |
238 | static inline struct nfs4_session *nfs4_get_session(const struct nfs_server *server) | 245 | static inline struct nfs4_session *nfs4_get_session(const struct nfs_server *server) |
@@ -347,13 +354,13 @@ extern int nfs4_wait_clnt_recover(struct nfs_client *clp); | |||
347 | extern int nfs4_client_recover_expired_lease(struct nfs_client *clp); | 354 | extern int nfs4_client_recover_expired_lease(struct nfs_client *clp); |
348 | extern void nfs4_schedule_state_manager(struct nfs_client *); | 355 | extern void nfs4_schedule_state_manager(struct nfs_client *); |
349 | extern void nfs4_schedule_path_down_recovery(struct nfs_client *clp); | 356 | extern void nfs4_schedule_path_down_recovery(struct nfs_client *clp); |
350 | extern void nfs4_schedule_stateid_recovery(const struct nfs_server *, struct nfs4_state *); | 357 | extern int nfs4_schedule_stateid_recovery(const struct nfs_server *, struct nfs4_state *); |
351 | extern void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags); | 358 | extern void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags); |
352 | extern void nfs41_handle_server_scope(struct nfs_client *, | 359 | extern void nfs41_handle_server_scope(struct nfs_client *, |
353 | struct nfs41_server_scope **); | 360 | struct nfs41_server_scope **); |
354 | extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); | 361 | extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); |
355 | extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); | 362 | extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); |
356 | extern void nfs4_select_rw_stateid(nfs4_stateid *, struct nfs4_state *, | 363 | extern int nfs4_select_rw_stateid(nfs4_stateid *, struct nfs4_state *, |
357 | fmode_t, const struct nfs_lockowner *); | 364 | fmode_t, const struct nfs_lockowner *); |
358 | 365 | ||
359 | extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask); | 366 | extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask); |
@@ -412,6 +419,11 @@ static inline bool nfs4_stateid_match(const nfs4_stateid *dst, const nfs4_statei | |||
412 | return memcmp(dst, src, sizeof(*dst)) == 0; | 419 | return memcmp(dst, src, sizeof(*dst)) == 0; |
413 | } | 420 | } |
414 | 421 | ||
422 | static inline bool nfs4_valid_open_stateid(const struct nfs4_state *state) | ||
423 | { | ||
424 | return test_bit(NFS_STATE_RECOVERY_FAILED, &state->flags) == 0; | ||
425 | } | ||
426 | |||
415 | #else | 427 | #else |
416 | 428 | ||
417 | #define nfs4_close_state(a, b) do { } while (0) | 429 | #define nfs4_close_state(a, b) do { } while (0) |
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index 66b6664dcd4c..947b0c908aa9 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c | |||
@@ -198,8 +198,12 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp, | |||
198 | /* Check NFS protocol revision and initialize RPC op vector */ | 198 | /* Check NFS protocol revision and initialize RPC op vector */ |
199 | clp->rpc_ops = &nfs_v4_clientops; | 199 | clp->rpc_ops = &nfs_v4_clientops; |
200 | 200 | ||
201 | if (clp->cl_minorversion != 0) | ||
202 | __set_bit(NFS_CS_INFINITE_SLOTS, &clp->cl_flags); | ||
201 | __set_bit(NFS_CS_DISCRTRY, &clp->cl_flags); | 203 | __set_bit(NFS_CS_DISCRTRY, &clp->cl_flags); |
202 | error = nfs_create_rpc_client(clp, timeparms, authflavour); | 204 | error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_GSS_KRB5I); |
205 | if (error == -EINVAL) | ||
206 | error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_NULL); | ||
203 | if (error < 0) | 207 | if (error < 0) |
204 | goto error; | 208 | goto error; |
205 | 209 | ||
@@ -730,6 +734,19 @@ static int nfs4_server_common_setup(struct nfs_server *server, | |||
730 | if (error < 0) | 734 | if (error < 0) |
731 | goto out; | 735 | goto out; |
732 | 736 | ||
737 | /* Set the basic capabilities */ | ||
738 | server->caps |= server->nfs_client->cl_mvops->init_caps; | ||
739 | if (server->flags & NFS_MOUNT_NORDIRPLUS) | ||
740 | server->caps &= ~NFS_CAP_READDIRPLUS; | ||
741 | /* | ||
742 | * Don't use NFS uid/gid mapping if we're using AUTH_SYS or lower | ||
743 | * authentication. | ||
744 | */ | ||
745 | if (nfs4_disable_idmapping && | ||
746 | server->client->cl_auth->au_flavor == RPC_AUTH_UNIX) | ||
747 | server->caps |= NFS_CAP_UIDGID_NOMAP; | ||
748 | |||
749 | |||
733 | /* Probe the root fh to retrieve its FSID and filehandle */ | 750 | /* Probe the root fh to retrieve its FSID and filehandle */ |
734 | error = nfs4_get_rootfh(server, mntfh); | 751 | error = nfs4_get_rootfh(server, mntfh); |
735 | if (error < 0) | 752 | if (error < 0) |
@@ -773,9 +790,6 @@ static int nfs4_init_server(struct nfs_server *server, | |||
773 | 790 | ||
774 | /* Initialise the client representation from the mount data */ | 791 | /* Initialise the client representation from the mount data */ |
775 | server->flags = data->flags; | 792 | server->flags = data->flags; |
776 | server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR|NFS_CAP_POSIX_LOCK; | ||
777 | if (!(data->flags & NFS_MOUNT_NORDIRPLUS)) | ||
778 | server->caps |= NFS_CAP_READDIRPLUS; | ||
779 | server->options = data->options; | 793 | server->options = data->options; |
780 | 794 | ||
781 | /* Get a client record */ | 795 | /* Get a client record */ |
@@ -792,13 +806,6 @@ static int nfs4_init_server(struct nfs_server *server, | |||
792 | if (error < 0) | 806 | if (error < 0) |
793 | goto error; | 807 | goto error; |
794 | 808 | ||
795 | /* | ||
796 | * Don't use NFS uid/gid mapping if we're using AUTH_SYS or lower | ||
797 | * authentication. | ||
798 | */ | ||
799 | if (nfs4_disable_idmapping && data->auth_flavors[0] == RPC_AUTH_UNIX) | ||
800 | server->caps |= NFS_CAP_UIDGID_NOMAP; | ||
801 | |||
802 | if (data->rsize) | 809 | if (data->rsize) |
803 | server->rsize = nfs_block_size(data->rsize, NULL); | 810 | server->rsize = nfs_block_size(data->rsize, NULL); |
804 | if (data->wsize) | 811 | if (data->wsize) |
@@ -876,7 +883,6 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
876 | 883 | ||
877 | /* Initialise the client representation from the parent server */ | 884 | /* Initialise the client representation from the parent server */ |
878 | nfs_server_copy_userdata(server, parent_server); | 885 | nfs_server_copy_userdata(server, parent_server); |
879 | server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR; | ||
880 | 886 | ||
881 | /* Get a client representation. | 887 | /* Get a client representation. |
882 | * Note: NFSv4 always uses TCP, */ | 888 | * Note: NFSv4 always uses TCP, */ |
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index 4fb234d3aefb..22d10623f5ee 100644 --- a/fs/nfs/nfs4filelayout.c +++ b/fs/nfs/nfs4filelayout.c | |||
@@ -158,11 +158,14 @@ static int filelayout_async_handle_error(struct rpc_task *task, | |||
158 | case -NFS4ERR_OPENMODE: | 158 | case -NFS4ERR_OPENMODE: |
159 | if (state == NULL) | 159 | if (state == NULL) |
160 | break; | 160 | break; |
161 | nfs4_schedule_stateid_recovery(mds_server, state); | 161 | if (nfs4_schedule_stateid_recovery(mds_server, state) < 0) |
162 | goto out_bad_stateid; | ||
162 | goto wait_on_recovery; | 163 | goto wait_on_recovery; |
163 | case -NFS4ERR_EXPIRED: | 164 | case -NFS4ERR_EXPIRED: |
164 | if (state != NULL) | 165 | if (state != NULL) { |
165 | nfs4_schedule_stateid_recovery(mds_server, state); | 166 | if (nfs4_schedule_stateid_recovery(mds_server, state) < 0) |
167 | goto out_bad_stateid; | ||
168 | } | ||
166 | nfs4_schedule_lease_recovery(mds_client); | 169 | nfs4_schedule_lease_recovery(mds_client); |
167 | goto wait_on_recovery; | 170 | goto wait_on_recovery; |
168 | /* DS session errors */ | 171 | /* DS session errors */ |
@@ -226,6 +229,9 @@ reset: | |||
226 | out: | 229 | out: |
227 | task->tk_status = 0; | 230 | task->tk_status = 0; |
228 | return -EAGAIN; | 231 | return -EAGAIN; |
232 | out_bad_stateid: | ||
233 | task->tk_status = -EIO; | ||
234 | return 0; | ||
229 | wait_on_recovery: | 235 | wait_on_recovery: |
230 | rpc_sleep_on(&mds_client->cl_rpcwaitq, task, NULL); | 236 | rpc_sleep_on(&mds_client->cl_rpcwaitq, task, NULL); |
231 | if (test_bit(NFS4CLNT_MANAGER_RUNNING, &mds_client->cl_state) == 0) | 237 | if (test_bit(NFS4CLNT_MANAGER_RUNNING, &mds_client->cl_state) == 0) |
@@ -299,6 +305,10 @@ static void filelayout_read_prepare(struct rpc_task *task, void *data) | |||
299 | { | 305 | { |
300 | struct nfs_read_data *rdata = data; | 306 | struct nfs_read_data *rdata = data; |
301 | 307 | ||
308 | if (unlikely(test_bit(NFS_CONTEXT_BAD, &rdata->args.context->flags))) { | ||
309 | rpc_exit(task, -EIO); | ||
310 | return; | ||
311 | } | ||
302 | if (filelayout_reset_to_mds(rdata->header->lseg)) { | 312 | if (filelayout_reset_to_mds(rdata->header->lseg)) { |
303 | dprintk("%s task %u reset io to MDS\n", __func__, task->tk_pid); | 313 | dprintk("%s task %u reset io to MDS\n", __func__, task->tk_pid); |
304 | filelayout_reset_read(rdata); | 314 | filelayout_reset_read(rdata); |
@@ -307,10 +317,13 @@ static void filelayout_read_prepare(struct rpc_task *task, void *data) | |||
307 | } | 317 | } |
308 | rdata->read_done_cb = filelayout_read_done_cb; | 318 | rdata->read_done_cb = filelayout_read_done_cb; |
309 | 319 | ||
310 | nfs41_setup_sequence(rdata->ds_clp->cl_session, | 320 | if (nfs41_setup_sequence(rdata->ds_clp->cl_session, |
311 | &rdata->args.seq_args, | 321 | &rdata->args.seq_args, |
312 | &rdata->res.seq_res, | 322 | &rdata->res.seq_res, |
313 | task); | 323 | task)) |
324 | return; | ||
325 | nfs4_set_rw_stateid(&rdata->args.stateid, rdata->args.context, | ||
326 | rdata->args.lock_context, FMODE_READ); | ||
314 | } | 327 | } |
315 | 328 | ||
316 | static void filelayout_read_call_done(struct rpc_task *task, void *data) | 329 | static void filelayout_read_call_done(struct rpc_task *task, void *data) |
@@ -401,16 +414,23 @@ static void filelayout_write_prepare(struct rpc_task *task, void *data) | |||
401 | { | 414 | { |
402 | struct nfs_write_data *wdata = data; | 415 | struct nfs_write_data *wdata = data; |
403 | 416 | ||
417 | if (unlikely(test_bit(NFS_CONTEXT_BAD, &wdata->args.context->flags))) { | ||
418 | rpc_exit(task, -EIO); | ||
419 | return; | ||
420 | } | ||
404 | if (filelayout_reset_to_mds(wdata->header->lseg)) { | 421 | if (filelayout_reset_to_mds(wdata->header->lseg)) { |
405 | dprintk("%s task %u reset io to MDS\n", __func__, task->tk_pid); | 422 | dprintk("%s task %u reset io to MDS\n", __func__, task->tk_pid); |
406 | filelayout_reset_write(wdata); | 423 | filelayout_reset_write(wdata); |
407 | rpc_exit(task, 0); | 424 | rpc_exit(task, 0); |
408 | return; | 425 | return; |
409 | } | 426 | } |
410 | nfs41_setup_sequence(wdata->ds_clp->cl_session, | 427 | if (nfs41_setup_sequence(wdata->ds_clp->cl_session, |
411 | &wdata->args.seq_args, | 428 | &wdata->args.seq_args, |
412 | &wdata->res.seq_res, | 429 | &wdata->res.seq_res, |
413 | task); | 430 | task)) |
431 | return; | ||
432 | nfs4_set_rw_stateid(&wdata->args.stateid, wdata->args.context, | ||
433 | wdata->args.lock_context, FMODE_WRITE); | ||
414 | } | 434 | } |
415 | 435 | ||
416 | static void filelayout_write_call_done(struct rpc_task *task, void *data) | 436 | static void filelayout_write_call_done(struct rpc_task *task, void *data) |
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index 0dd766079e1c..cdb0b41a4810 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c | |||
@@ -134,33 +134,38 @@ static size_t nfs_parse_server_name(char *string, size_t len, | |||
134 | return ret; | 134 | return ret; |
135 | } | 135 | } |
136 | 136 | ||
137 | /** | ||
138 | * nfs_find_best_sec - Find a security mechanism supported locally | ||
139 | * @flavors: List of security tuples returned by SECINFO procedure | ||
140 | * | ||
141 | * Return the pseudoflavor of the first security mechanism in | ||
142 | * "flavors" that is locally supported. Return RPC_AUTH_UNIX if | ||
143 | * no matching flavor is found in the array. The "flavors" array | ||
144 | * is searched in the order returned from the server, per RFC 3530 | ||
145 | * recommendation. | ||
146 | */ | ||
137 | rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors) | 147 | rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors) |
138 | { | 148 | { |
139 | struct gss_api_mech *mech; | 149 | rpc_authflavor_t pseudoflavor; |
140 | struct xdr_netobj oid; | 150 | struct nfs4_secinfo4 *secinfo; |
141 | int i; | 151 | unsigned int i; |
142 | rpc_authflavor_t pseudoflavor = RPC_AUTH_UNIX; | ||
143 | 152 | ||
144 | for (i = 0; i < flavors->num_flavors; i++) { | 153 | for (i = 0; i < flavors->num_flavors; i++) { |
145 | struct nfs4_secinfo_flavor *flavor; | 154 | secinfo = &flavors->flavors[i]; |
146 | flavor = &flavors->flavors[i]; | 155 | |
147 | 156 | switch (secinfo->flavor) { | |
148 | if (flavor->flavor == RPC_AUTH_NULL || flavor->flavor == RPC_AUTH_UNIX) { | 157 | case RPC_AUTH_NULL: |
149 | pseudoflavor = flavor->flavor; | 158 | case RPC_AUTH_UNIX: |
150 | break; | 159 | case RPC_AUTH_GSS: |
151 | } else if (flavor->flavor == RPC_AUTH_GSS) { | 160 | pseudoflavor = rpcauth_get_pseudoflavor(secinfo->flavor, |
152 | oid.len = flavor->gss.sec_oid4.len; | 161 | &secinfo->flavor_info); |
153 | oid.data = flavor->gss.sec_oid4.data; | 162 | if (pseudoflavor != RPC_AUTH_MAXFLAVOR) |
154 | mech = gss_mech_get_by_OID(&oid); | 163 | return pseudoflavor; |
155 | if (!mech) | ||
156 | continue; | ||
157 | pseudoflavor = gss_svc_to_pseudoflavor(mech, flavor->gss.service); | ||
158 | gss_mech_put(mech); | ||
159 | break; | 164 | break; |
160 | } | 165 | } |
161 | } | 166 | } |
162 | 167 | ||
163 | return pseudoflavor; | 168 | return RPC_AUTH_UNIX; |
164 | } | 169 | } |
165 | 170 | ||
166 | static rpc_authflavor_t nfs4_negotiate_security(struct inode *inode, struct qstr *name) | 171 | static rpc_authflavor_t nfs4_negotiate_security(struct inode *inode, struct qstr *name) |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 0ad025eb523b..9da4bd55eb30 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -107,6 +107,8 @@ static int nfs4_map_errors(int err) | |||
107 | return -EPROTONOSUPPORT; | 107 | return -EPROTONOSUPPORT; |
108 | case -NFS4ERR_ACCESS: | 108 | case -NFS4ERR_ACCESS: |
109 | return -EACCES; | 109 | return -EACCES; |
110 | case -NFS4ERR_FILE_OPEN: | ||
111 | return -EBUSY; | ||
110 | default: | 112 | default: |
111 | dprintk("%s could not handle NFSv4 error %d\n", | 113 | dprintk("%s could not handle NFSv4 error %d\n", |
112 | __func__, -err); | 114 | __func__, -err); |
@@ -295,19 +297,30 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc | |||
295 | } | 297 | } |
296 | if (state == NULL) | 298 | if (state == NULL) |
297 | break; | 299 | break; |
298 | nfs4_schedule_stateid_recovery(server, state); | 300 | ret = nfs4_schedule_stateid_recovery(server, state); |
301 | if (ret < 0) | ||
302 | break; | ||
299 | goto wait_on_recovery; | 303 | goto wait_on_recovery; |
300 | case -NFS4ERR_DELEG_REVOKED: | 304 | case -NFS4ERR_DELEG_REVOKED: |
301 | case -NFS4ERR_ADMIN_REVOKED: | 305 | case -NFS4ERR_ADMIN_REVOKED: |
302 | case -NFS4ERR_BAD_STATEID: | 306 | case -NFS4ERR_BAD_STATEID: |
307 | if (inode != NULL && nfs4_have_delegation(inode, FMODE_READ)) { | ||
308 | nfs_remove_bad_delegation(inode); | ||
309 | exception->retry = 1; | ||
310 | break; | ||
311 | } | ||
303 | if (state == NULL) | 312 | if (state == NULL) |
304 | break; | 313 | break; |
305 | nfs_remove_bad_delegation(state->inode); | 314 | ret = nfs4_schedule_stateid_recovery(server, state); |
306 | nfs4_schedule_stateid_recovery(server, state); | 315 | if (ret < 0) |
316 | break; | ||
307 | goto wait_on_recovery; | 317 | goto wait_on_recovery; |
308 | case -NFS4ERR_EXPIRED: | 318 | case -NFS4ERR_EXPIRED: |
309 | if (state != NULL) | 319 | if (state != NULL) { |
310 | nfs4_schedule_stateid_recovery(server, state); | 320 | ret = nfs4_schedule_stateid_recovery(server, state); |
321 | if (ret < 0) | ||
322 | break; | ||
323 | } | ||
311 | case -NFS4ERR_STALE_STATEID: | 324 | case -NFS4ERR_STALE_STATEID: |
312 | case -NFS4ERR_STALE_CLIENTID: | 325 | case -NFS4ERR_STALE_CLIENTID: |
313 | nfs4_schedule_lease_recovery(clp); | 326 | nfs4_schedule_lease_recovery(clp); |
@@ -756,10 +769,40 @@ struct nfs4_opendata { | |||
756 | struct iattr attrs; | 769 | struct iattr attrs; |
757 | unsigned long timestamp; | 770 | unsigned long timestamp; |
758 | unsigned int rpc_done : 1; | 771 | unsigned int rpc_done : 1; |
772 | unsigned int is_recover : 1; | ||
759 | int rpc_status; | 773 | int rpc_status; |
760 | int cancelled; | 774 | int cancelled; |
761 | }; | 775 | }; |
762 | 776 | ||
777 | static bool nfs4_clear_cap_atomic_open_v1(struct nfs_server *server, | ||
778 | int err, struct nfs4_exception *exception) | ||
779 | { | ||
780 | if (err != -EINVAL) | ||
781 | return false; | ||
782 | if (!(server->caps & NFS_CAP_ATOMIC_OPEN_V1)) | ||
783 | return false; | ||
784 | server->caps &= ~NFS_CAP_ATOMIC_OPEN_V1; | ||
785 | exception->retry = 1; | ||
786 | return true; | ||
787 | } | ||
788 | |||
789 | static enum open_claim_type4 | ||
790 | nfs4_map_atomic_open_claim(struct nfs_server *server, | ||
791 | enum open_claim_type4 claim) | ||
792 | { | ||
793 | if (server->caps & NFS_CAP_ATOMIC_OPEN_V1) | ||
794 | return claim; | ||
795 | switch (claim) { | ||
796 | default: | ||
797 | return claim; | ||
798 | case NFS4_OPEN_CLAIM_FH: | ||
799 | return NFS4_OPEN_CLAIM_NULL; | ||
800 | case NFS4_OPEN_CLAIM_DELEG_CUR_FH: | ||
801 | return NFS4_OPEN_CLAIM_DELEGATE_CUR; | ||
802 | case NFS4_OPEN_CLAIM_DELEG_PREV_FH: | ||
803 | return NFS4_OPEN_CLAIM_DELEGATE_PREV; | ||
804 | } | ||
805 | } | ||
763 | 806 | ||
764 | static void nfs4_init_opendata_res(struct nfs4_opendata *p) | 807 | static void nfs4_init_opendata_res(struct nfs4_opendata *p) |
765 | { | 808 | { |
@@ -775,6 +818,7 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p) | |||
775 | static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, | 818 | static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, |
776 | struct nfs4_state_owner *sp, fmode_t fmode, int flags, | 819 | struct nfs4_state_owner *sp, fmode_t fmode, int flags, |
777 | const struct iattr *attrs, | 820 | const struct iattr *attrs, |
821 | enum open_claim_type4 claim, | ||
778 | gfp_t gfp_mask) | 822 | gfp_t gfp_mask) |
779 | { | 823 | { |
780 | struct dentry *parent = dget_parent(dentry); | 824 | struct dentry *parent = dget_parent(dentry); |
@@ -793,7 +837,6 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, | |||
793 | p->dir = parent; | 837 | p->dir = parent; |
794 | p->owner = sp; | 838 | p->owner = sp; |
795 | atomic_inc(&sp->so_count); | 839 | atomic_inc(&sp->so_count); |
796 | p->o_arg.fh = NFS_FH(dir); | ||
797 | p->o_arg.open_flags = flags; | 840 | p->o_arg.open_flags = flags; |
798 | p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE); | 841 | p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE); |
799 | /* don't put an ACCESS op in OPEN compound if O_EXCL, because ACCESS | 842 | /* don't put an ACCESS op in OPEN compound if O_EXCL, because ACCESS |
@@ -811,7 +854,19 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, | |||
811 | p->o_arg.server = server; | 854 | p->o_arg.server = server; |
812 | p->o_arg.bitmask = server->attr_bitmask; | 855 | p->o_arg.bitmask = server->attr_bitmask; |
813 | p->o_arg.open_bitmap = &nfs4_fattr_bitmap[0]; | 856 | p->o_arg.open_bitmap = &nfs4_fattr_bitmap[0]; |
814 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; | 857 | p->o_arg.claim = nfs4_map_atomic_open_claim(server, claim); |
858 | switch (p->o_arg.claim) { | ||
859 | case NFS4_OPEN_CLAIM_NULL: | ||
860 | case NFS4_OPEN_CLAIM_DELEGATE_CUR: | ||
861 | case NFS4_OPEN_CLAIM_DELEGATE_PREV: | ||
862 | p->o_arg.fh = NFS_FH(dir); | ||
863 | break; | ||
864 | case NFS4_OPEN_CLAIM_PREVIOUS: | ||
865 | case NFS4_OPEN_CLAIM_FH: | ||
866 | case NFS4_OPEN_CLAIM_DELEG_CUR_FH: | ||
867 | case NFS4_OPEN_CLAIM_DELEG_PREV_FH: | ||
868 | p->o_arg.fh = NFS_FH(dentry->d_inode); | ||
869 | } | ||
815 | if (attrs != NULL && attrs->ia_valid != 0) { | 870 | if (attrs != NULL && attrs->ia_valid != 0) { |
816 | __be32 verf[2]; | 871 | __be32 verf[2]; |
817 | 872 | ||
@@ -924,6 +979,7 @@ static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid * | |||
924 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) | 979 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) |
925 | nfs4_stateid_copy(&state->stateid, stateid); | 980 | nfs4_stateid_copy(&state->stateid, stateid); |
926 | nfs4_stateid_copy(&state->open_stateid, stateid); | 981 | nfs4_stateid_copy(&state->open_stateid, stateid); |
982 | set_bit(NFS_OPEN_STATE, &state->flags); | ||
927 | switch (fmode) { | 983 | switch (fmode) { |
928 | case FMODE_READ: | 984 | case FMODE_READ: |
929 | set_bit(NFS_O_RDONLY_STATE, &state->flags); | 985 | set_bit(NFS_O_RDONLY_STATE, &state->flags); |
@@ -1047,9 +1103,11 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata) | |||
1047 | nfs4_stateid_copy(&stateid, &delegation->stateid); | 1103 | nfs4_stateid_copy(&stateid, &delegation->stateid); |
1048 | rcu_read_unlock(); | 1104 | rcu_read_unlock(); |
1049 | nfs_release_seqid(opendata->o_arg.seqid); | 1105 | nfs_release_seqid(opendata->o_arg.seqid); |
1050 | ret = nfs_may_open(state->inode, state->owner->so_cred, open_mode); | 1106 | if (!opendata->is_recover) { |
1051 | if (ret != 0) | 1107 | ret = nfs_may_open(state->inode, state->owner->so_cred, open_mode); |
1052 | goto out; | 1108 | if (ret != 0) |
1109 | goto out; | ||
1110 | } | ||
1053 | ret = -EAGAIN; | 1111 | ret = -EAGAIN; |
1054 | 1112 | ||
1055 | /* Try to update the stateid using the delegation */ | 1113 | /* Try to update the stateid using the delegation */ |
@@ -1194,11 +1252,13 @@ static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state * | |||
1194 | return ERR_PTR(-ENOENT); | 1252 | return ERR_PTR(-ENOENT); |
1195 | } | 1253 | } |
1196 | 1254 | ||
1197 | static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context *ctx, struct nfs4_state *state) | 1255 | static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context *ctx, |
1256 | struct nfs4_state *state, enum open_claim_type4 claim) | ||
1198 | { | 1257 | { |
1199 | struct nfs4_opendata *opendata; | 1258 | struct nfs4_opendata *opendata; |
1200 | 1259 | ||
1201 | opendata = nfs4_opendata_alloc(ctx->dentry, state->owner, 0, 0, NULL, GFP_NOFS); | 1260 | opendata = nfs4_opendata_alloc(ctx->dentry, state->owner, 0, 0, |
1261 | NULL, claim, GFP_NOFS); | ||
1202 | if (opendata == NULL) | 1262 | if (opendata == NULL) |
1203 | return ERR_PTR(-ENOMEM); | 1263 | return ERR_PTR(-ENOMEM); |
1204 | opendata->state = state; | 1264 | opendata->state = state; |
@@ -1234,6 +1294,7 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state * | |||
1234 | 1294 | ||
1235 | /* memory barrier prior to reading state->n_* */ | 1295 | /* memory barrier prior to reading state->n_* */ |
1236 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | 1296 | clear_bit(NFS_DELEGATED_STATE, &state->flags); |
1297 | clear_bit(NFS_OPEN_STATE, &state->flags); | ||
1237 | smp_rmb(); | 1298 | smp_rmb(); |
1238 | if (state->n_rdwr != 0) { | 1299 | if (state->n_rdwr != 0) { |
1239 | clear_bit(NFS_O_RDWR_STATE, &state->flags); | 1300 | clear_bit(NFS_O_RDWR_STATE, &state->flags); |
@@ -1284,11 +1345,10 @@ static int _nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state | |||
1284 | fmode_t delegation_type = 0; | 1345 | fmode_t delegation_type = 0; |
1285 | int status; | 1346 | int status; |
1286 | 1347 | ||
1287 | opendata = nfs4_open_recoverdata_alloc(ctx, state); | 1348 | opendata = nfs4_open_recoverdata_alloc(ctx, state, |
1349 | NFS4_OPEN_CLAIM_PREVIOUS); | ||
1288 | if (IS_ERR(opendata)) | 1350 | if (IS_ERR(opendata)) |
1289 | return PTR_ERR(opendata); | 1351 | return PTR_ERR(opendata); |
1290 | opendata->o_arg.claim = NFS4_OPEN_CLAIM_PREVIOUS; | ||
1291 | opendata->o_arg.fh = NFS_FH(state->inode); | ||
1292 | rcu_read_lock(); | 1352 | rcu_read_lock(); |
1293 | delegation = rcu_dereference(NFS_I(state->inode)->delegation); | 1353 | delegation = rcu_dereference(NFS_I(state->inode)->delegation); |
1294 | if (delegation != NULL && test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags) != 0) | 1354 | if (delegation != NULL && test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags) != 0) |
@@ -1307,6 +1367,8 @@ static int nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state | |||
1307 | int err; | 1367 | int err; |
1308 | do { | 1368 | do { |
1309 | err = _nfs4_do_open_reclaim(ctx, state); | 1369 | err = _nfs4_do_open_reclaim(ctx, state); |
1370 | if (nfs4_clear_cap_atomic_open_v1(server, err, &exception)) | ||
1371 | continue; | ||
1310 | if (err != -NFS4ERR_DELAY) | 1372 | if (err != -NFS4ERR_DELAY) |
1311 | break; | 1373 | break; |
1312 | nfs4_handle_exception(server, err, &exception); | 1374 | nfs4_handle_exception(server, err, &exception); |
@@ -1321,71 +1383,72 @@ static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *sta | |||
1321 | 1383 | ||
1322 | ctx = nfs4_state_find_open_context(state); | 1384 | ctx = nfs4_state_find_open_context(state); |
1323 | if (IS_ERR(ctx)) | 1385 | if (IS_ERR(ctx)) |
1324 | return PTR_ERR(ctx); | 1386 | return -EAGAIN; |
1325 | ret = nfs4_do_open_reclaim(ctx, state); | 1387 | ret = nfs4_do_open_reclaim(ctx, state); |
1326 | put_nfs_open_context(ctx); | 1388 | put_nfs_open_context(ctx); |
1327 | return ret; | 1389 | return ret; |
1328 | } | 1390 | } |
1329 | 1391 | ||
1330 | static int _nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid) | 1392 | static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct nfs4_state *state, const nfs4_stateid *stateid, int err) |
1331 | { | 1393 | { |
1332 | struct nfs4_opendata *opendata; | 1394 | switch (err) { |
1333 | int ret; | 1395 | default: |
1334 | 1396 | printk(KERN_ERR "NFS: %s: unhandled error " | |
1335 | opendata = nfs4_open_recoverdata_alloc(ctx, state); | 1397 | "%d.\n", __func__, err); |
1336 | if (IS_ERR(opendata)) | 1398 | case 0: |
1337 | return PTR_ERR(opendata); | 1399 | case -ENOENT: |
1338 | opendata->o_arg.claim = NFS4_OPEN_CLAIM_DELEGATE_CUR; | 1400 | case -ESTALE: |
1339 | nfs4_stateid_copy(&opendata->o_arg.u.delegation, stateid); | 1401 | break; |
1340 | ret = nfs4_open_recover(opendata, state); | 1402 | case -NFS4ERR_BADSESSION: |
1341 | nfs4_opendata_put(opendata); | 1403 | case -NFS4ERR_BADSLOT: |
1342 | return ret; | 1404 | case -NFS4ERR_BAD_HIGH_SLOT: |
1405 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | ||
1406 | case -NFS4ERR_DEADSESSION: | ||
1407 | set_bit(NFS_DELEGATED_STATE, &state->flags); | ||
1408 | nfs4_schedule_session_recovery(server->nfs_client->cl_session, err); | ||
1409 | return -EAGAIN; | ||
1410 | case -NFS4ERR_STALE_CLIENTID: | ||
1411 | case -NFS4ERR_STALE_STATEID: | ||
1412 | set_bit(NFS_DELEGATED_STATE, &state->flags); | ||
1413 | case -NFS4ERR_EXPIRED: | ||
1414 | /* Don't recall a delegation if it was lost */ | ||
1415 | nfs4_schedule_lease_recovery(server->nfs_client); | ||
1416 | return -EAGAIN; | ||
1417 | case -NFS4ERR_DELEG_REVOKED: | ||
1418 | case -NFS4ERR_ADMIN_REVOKED: | ||
1419 | case -NFS4ERR_BAD_STATEID: | ||
1420 | case -NFS4ERR_OPENMODE: | ||
1421 | nfs_inode_find_state_and_recover(state->inode, | ||
1422 | stateid); | ||
1423 | nfs4_schedule_stateid_recovery(server, state); | ||
1424 | return 0; | ||
1425 | case -NFS4ERR_DELAY: | ||
1426 | case -NFS4ERR_GRACE: | ||
1427 | set_bit(NFS_DELEGATED_STATE, &state->flags); | ||
1428 | ssleep(1); | ||
1429 | return -EAGAIN; | ||
1430 | case -ENOMEM: | ||
1431 | case -NFS4ERR_DENIED: | ||
1432 | /* kill_proc(fl->fl_pid, SIGLOST, 1); */ | ||
1433 | return 0; | ||
1434 | } | ||
1435 | return err; | ||
1343 | } | 1436 | } |
1344 | 1437 | ||
1345 | int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid) | 1438 | int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid) |
1346 | { | 1439 | { |
1347 | struct nfs4_exception exception = { }; | ||
1348 | struct nfs_server *server = NFS_SERVER(state->inode); | 1440 | struct nfs_server *server = NFS_SERVER(state->inode); |
1441 | struct nfs4_opendata *opendata; | ||
1349 | int err; | 1442 | int err; |
1350 | do { | 1443 | |
1351 | err = _nfs4_open_delegation_recall(ctx, state, stateid); | 1444 | opendata = nfs4_open_recoverdata_alloc(ctx, state, |
1352 | switch (err) { | 1445 | NFS4_OPEN_CLAIM_DELEG_CUR_FH); |
1353 | case 0: | 1446 | if (IS_ERR(opendata)) |
1354 | case -ENOENT: | 1447 | return PTR_ERR(opendata); |
1355 | case -ESTALE: | 1448 | nfs4_stateid_copy(&opendata->o_arg.u.delegation, stateid); |
1356 | goto out; | 1449 | err = nfs4_open_recover(opendata, state); |
1357 | case -NFS4ERR_BADSESSION: | 1450 | nfs4_opendata_put(opendata); |
1358 | case -NFS4ERR_BADSLOT: | 1451 | return nfs4_handle_delegation_recall_error(server, state, stateid, err); |
1359 | case -NFS4ERR_BAD_HIGH_SLOT: | ||
1360 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | ||
1361 | case -NFS4ERR_DEADSESSION: | ||
1362 | set_bit(NFS_DELEGATED_STATE, &state->flags); | ||
1363 | nfs4_schedule_session_recovery(server->nfs_client->cl_session, err); | ||
1364 | err = -EAGAIN; | ||
1365 | goto out; | ||
1366 | case -NFS4ERR_STALE_CLIENTID: | ||
1367 | case -NFS4ERR_STALE_STATEID: | ||
1368 | set_bit(NFS_DELEGATED_STATE, &state->flags); | ||
1369 | case -NFS4ERR_EXPIRED: | ||
1370 | /* Don't recall a delegation if it was lost */ | ||
1371 | nfs4_schedule_lease_recovery(server->nfs_client); | ||
1372 | err = -EAGAIN; | ||
1373 | goto out; | ||
1374 | case -NFS4ERR_DELEG_REVOKED: | ||
1375 | case -NFS4ERR_ADMIN_REVOKED: | ||
1376 | case -NFS4ERR_BAD_STATEID: | ||
1377 | nfs_inode_find_state_and_recover(state->inode, | ||
1378 | stateid); | ||
1379 | nfs4_schedule_stateid_recovery(server, state); | ||
1380 | case -ENOMEM: | ||
1381 | err = 0; | ||
1382 | goto out; | ||
1383 | } | ||
1384 | set_bit(NFS_DELEGATED_STATE, &state->flags); | ||
1385 | err = nfs4_handle_exception(server, err, &exception); | ||
1386 | } while (exception.retry); | ||
1387 | out: | ||
1388 | return err; | ||
1389 | } | 1452 | } |
1390 | 1453 | ||
1391 | static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata) | 1454 | static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata) |
@@ -1468,6 +1531,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) | |||
1468 | { | 1531 | { |
1469 | struct nfs4_opendata *data = calldata; | 1532 | struct nfs4_opendata *data = calldata; |
1470 | struct nfs4_state_owner *sp = data->owner; | 1533 | struct nfs4_state_owner *sp = data->owner; |
1534 | struct nfs_client *clp = sp->so_server->nfs_client; | ||
1471 | 1535 | ||
1472 | if (nfs_wait_on_sequence(data->o_arg.seqid, task) != 0) | 1536 | if (nfs_wait_on_sequence(data->o_arg.seqid, task) != 0) |
1473 | goto out_wait; | 1537 | goto out_wait; |
@@ -1483,15 +1547,20 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) | |||
1483 | rcu_read_lock(); | 1547 | rcu_read_lock(); |
1484 | delegation = rcu_dereference(NFS_I(data->state->inode)->delegation); | 1548 | delegation = rcu_dereference(NFS_I(data->state->inode)->delegation); |
1485 | if (data->o_arg.claim != NFS4_OPEN_CLAIM_DELEGATE_CUR && | 1549 | if (data->o_arg.claim != NFS4_OPEN_CLAIM_DELEGATE_CUR && |
1550 | data->o_arg.claim != NFS4_OPEN_CLAIM_DELEG_CUR_FH && | ||
1486 | can_open_delegated(delegation, data->o_arg.fmode)) | 1551 | can_open_delegated(delegation, data->o_arg.fmode)) |
1487 | goto unlock_no_action; | 1552 | goto unlock_no_action; |
1488 | rcu_read_unlock(); | 1553 | rcu_read_unlock(); |
1489 | } | 1554 | } |
1490 | /* Update client id. */ | 1555 | /* Update client id. */ |
1491 | data->o_arg.clientid = sp->so_server->nfs_client->cl_clientid; | 1556 | data->o_arg.clientid = clp->cl_clientid; |
1492 | if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) { | 1557 | switch (data->o_arg.claim) { |
1493 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR]; | 1558 | case NFS4_OPEN_CLAIM_PREVIOUS: |
1559 | case NFS4_OPEN_CLAIM_DELEG_CUR_FH: | ||
1560 | case NFS4_OPEN_CLAIM_DELEG_PREV_FH: | ||
1494 | data->o_arg.open_bitmap = &nfs4_open_noattr_bitmap[0]; | 1561 | data->o_arg.open_bitmap = &nfs4_open_noattr_bitmap[0]; |
1562 | case NFS4_OPEN_CLAIM_FH: | ||
1563 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR]; | ||
1495 | nfs_copy_fh(&data->o_res.fh, data->o_arg.fh); | 1564 | nfs_copy_fh(&data->o_res.fh, data->o_arg.fh); |
1496 | } | 1565 | } |
1497 | data->timestamp = jiffies; | 1566 | data->timestamp = jiffies; |
@@ -1500,6 +1569,16 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) | |||
1500 | &data->o_res.seq_res, | 1569 | &data->o_res.seq_res, |
1501 | task) != 0) | 1570 | task) != 0) |
1502 | nfs_release_seqid(data->o_arg.seqid); | 1571 | nfs_release_seqid(data->o_arg.seqid); |
1572 | |||
1573 | /* Set the create mode (note dependency on the session type) */ | ||
1574 | data->o_arg.createmode = NFS4_CREATE_UNCHECKED; | ||
1575 | if (data->o_arg.open_flags & O_EXCL) { | ||
1576 | data->o_arg.createmode = NFS4_CREATE_EXCLUSIVE; | ||
1577 | if (nfs4_has_persistent_session(clp)) | ||
1578 | data->o_arg.createmode = NFS4_CREATE_GUARDED; | ||
1579 | else if (clp->cl_mvops->minor_version > 0) | ||
1580 | data->o_arg.createmode = NFS4_CREATE_EXCLUSIVE4_1; | ||
1581 | } | ||
1503 | return; | 1582 | return; |
1504 | unlock_no_action: | 1583 | unlock_no_action: |
1505 | rcu_read_unlock(); | 1584 | rcu_read_unlock(); |
@@ -1595,8 +1674,11 @@ static int nfs4_run_open_task(struct nfs4_opendata *data, int isrecover) | |||
1595 | data->rpc_done = 0; | 1674 | data->rpc_done = 0; |
1596 | data->rpc_status = 0; | 1675 | data->rpc_status = 0; |
1597 | data->cancelled = 0; | 1676 | data->cancelled = 0; |
1598 | if (isrecover) | 1677 | data->is_recover = 0; |
1678 | if (isrecover) { | ||
1599 | nfs4_set_sequence_privileged(&o_arg->seq_args); | 1679 | nfs4_set_sequence_privileged(&o_arg->seq_args); |
1680 | data->is_recover = 1; | ||
1681 | } | ||
1600 | task = rpc_run_task(&task_setup_data); | 1682 | task = rpc_run_task(&task_setup_data); |
1601 | if (IS_ERR(task)) | 1683 | if (IS_ERR(task)) |
1602 | return PTR_ERR(task); | 1684 | return PTR_ERR(task); |
@@ -1721,7 +1803,8 @@ static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *s | |||
1721 | struct nfs4_opendata *opendata; | 1803 | struct nfs4_opendata *opendata; |
1722 | int ret; | 1804 | int ret; |
1723 | 1805 | ||
1724 | opendata = nfs4_open_recoverdata_alloc(ctx, state); | 1806 | opendata = nfs4_open_recoverdata_alloc(ctx, state, |
1807 | NFS4_OPEN_CLAIM_FH); | ||
1725 | if (IS_ERR(opendata)) | 1808 | if (IS_ERR(opendata)) |
1726 | return PTR_ERR(opendata); | 1809 | return PTR_ERR(opendata); |
1727 | ret = nfs4_open_recover(opendata, state); | 1810 | ret = nfs4_open_recover(opendata, state); |
@@ -1739,6 +1822,8 @@ static int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4_state | |||
1739 | 1822 | ||
1740 | do { | 1823 | do { |
1741 | err = _nfs4_open_expired(ctx, state); | 1824 | err = _nfs4_open_expired(ctx, state); |
1825 | if (nfs4_clear_cap_atomic_open_v1(server, err, &exception)) | ||
1826 | continue; | ||
1742 | switch (err) { | 1827 | switch (err) { |
1743 | default: | 1828 | default: |
1744 | goto out; | 1829 | goto out; |
@@ -1759,7 +1844,7 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta | |||
1759 | 1844 | ||
1760 | ctx = nfs4_state_find_open_context(state); | 1845 | ctx = nfs4_state_find_open_context(state); |
1761 | if (IS_ERR(ctx)) | 1846 | if (IS_ERR(ctx)) |
1762 | return PTR_ERR(ctx); | 1847 | return -EAGAIN; |
1763 | ret = nfs4_do_open_expired(ctx, state); | 1848 | ret = nfs4_do_open_expired(ctx, state); |
1764 | put_nfs_open_context(ctx); | 1849 | put_nfs_open_context(ctx); |
1765 | return ret; | 1850 | return ret; |
@@ -1821,6 +1906,7 @@ static int nfs41_check_open_stateid(struct nfs4_state *state) | |||
1821 | clear_bit(NFS_O_RDONLY_STATE, &state->flags); | 1906 | clear_bit(NFS_O_RDONLY_STATE, &state->flags); |
1822 | clear_bit(NFS_O_WRONLY_STATE, &state->flags); | 1907 | clear_bit(NFS_O_WRONLY_STATE, &state->flags); |
1823 | clear_bit(NFS_O_RDWR_STATE, &state->flags); | 1908 | clear_bit(NFS_O_RDWR_STATE, &state->flags); |
1909 | clear_bit(NFS_OPEN_STATE, &state->flags); | ||
1824 | } | 1910 | } |
1825 | return status; | 1911 | return status; |
1826 | } | 1912 | } |
@@ -1881,10 +1967,8 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata, | |||
1881 | if (ret != 0) | 1967 | if (ret != 0) |
1882 | goto out; | 1968 | goto out; |
1883 | 1969 | ||
1884 | if (read_seqcount_retry(&sp->so_reclaim_seqcount, seq)) { | 1970 | if (read_seqcount_retry(&sp->so_reclaim_seqcount, seq)) |
1885 | nfs4_schedule_stateid_recovery(server, state); | 1971 | nfs4_schedule_stateid_recovery(server, state); |
1886 | nfs4_wait_clnt_recover(server->nfs_client); | ||
1887 | } | ||
1888 | *res = state; | 1972 | *res = state; |
1889 | out: | 1973 | out: |
1890 | return ret; | 1974 | return ret; |
@@ -1906,6 +1990,7 @@ static int _nfs4_do_open(struct inode *dir, | |||
1906 | struct nfs4_state *state = NULL; | 1990 | struct nfs4_state *state = NULL; |
1907 | struct nfs_server *server = NFS_SERVER(dir); | 1991 | struct nfs_server *server = NFS_SERVER(dir); |
1908 | struct nfs4_opendata *opendata; | 1992 | struct nfs4_opendata *opendata; |
1993 | enum open_claim_type4 claim = NFS4_OPEN_CLAIM_NULL; | ||
1909 | int status; | 1994 | int status; |
1910 | 1995 | ||
1911 | /* Protect against reboot recovery conflicts */ | 1996 | /* Protect against reboot recovery conflicts */ |
@@ -1921,7 +2006,10 @@ static int _nfs4_do_open(struct inode *dir, | |||
1921 | if (dentry->d_inode != NULL) | 2006 | if (dentry->d_inode != NULL) |
1922 | nfs4_return_incompatible_delegation(dentry->d_inode, fmode); | 2007 | nfs4_return_incompatible_delegation(dentry->d_inode, fmode); |
1923 | status = -ENOMEM; | 2008 | status = -ENOMEM; |
1924 | opendata = nfs4_opendata_alloc(dentry, sp, fmode, flags, sattr, GFP_KERNEL); | 2009 | if (dentry->d_inode) |
2010 | claim = NFS4_OPEN_CLAIM_FH; | ||
2011 | opendata = nfs4_opendata_alloc(dentry, sp, fmode, flags, sattr, | ||
2012 | claim, GFP_KERNEL); | ||
1925 | if (opendata == NULL) | 2013 | if (opendata == NULL) |
1926 | goto err_put_state_owner; | 2014 | goto err_put_state_owner; |
1927 | 2015 | ||
@@ -1938,7 +2026,8 @@ static int _nfs4_do_open(struct inode *dir, | |||
1938 | if (status != 0) | 2026 | if (status != 0) |
1939 | goto err_opendata_put; | 2027 | goto err_opendata_put; |
1940 | 2028 | ||
1941 | if (opendata->o_arg.open_flags & O_EXCL) { | 2029 | if ((opendata->o_arg.open_flags & O_EXCL) && |
2030 | (opendata->o_arg.createmode != NFS4_CREATE_GUARDED)) { | ||
1942 | nfs4_exclusive_attrset(opendata, sattr); | 2031 | nfs4_exclusive_attrset(opendata, sattr); |
1943 | 2032 | ||
1944 | nfs_fattr_init(opendata->o_res.f_attr); | 2033 | nfs_fattr_init(opendata->o_res.f_attr); |
@@ -1979,6 +2068,7 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, | |||
1979 | struct rpc_cred *cred, | 2068 | struct rpc_cred *cred, |
1980 | struct nfs4_threshold **ctx_th) | 2069 | struct nfs4_threshold **ctx_th) |
1981 | { | 2070 | { |
2071 | struct nfs_server *server = NFS_SERVER(dir); | ||
1982 | struct nfs4_exception exception = { }; | 2072 | struct nfs4_exception exception = { }; |
1983 | struct nfs4_state *res; | 2073 | struct nfs4_state *res; |
1984 | int status; | 2074 | int status; |
@@ -2022,7 +2112,9 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, | |||
2022 | exception.retry = 1; | 2112 | exception.retry = 1; |
2023 | continue; | 2113 | continue; |
2024 | } | 2114 | } |
2025 | res = ERR_PTR(nfs4_handle_exception(NFS_SERVER(dir), | 2115 | if (nfs4_clear_cap_atomic_open_v1(server, status, &exception)) |
2116 | continue; | ||
2117 | res = ERR_PTR(nfs4_handle_exception(server, | ||
2026 | status, &exception)); | 2118 | status, &exception)); |
2027 | } while (exception.retry); | 2119 | } while (exception.retry); |
2028 | return res; | 2120 | return res; |
@@ -2050,20 +2142,25 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, | |||
2050 | .rpc_cred = cred, | 2142 | .rpc_cred = cred, |
2051 | }; | 2143 | }; |
2052 | unsigned long timestamp = jiffies; | 2144 | unsigned long timestamp = jiffies; |
2145 | fmode_t fmode; | ||
2146 | bool truncate; | ||
2053 | int status; | 2147 | int status; |
2054 | 2148 | ||
2055 | nfs_fattr_init(fattr); | 2149 | nfs_fattr_init(fattr); |
2056 | 2150 | ||
2057 | if (state != NULL) { | 2151 | /* Servers should only apply open mode checks for file size changes */ |
2152 | truncate = (sattr->ia_valid & ATTR_SIZE) ? true : false; | ||
2153 | fmode = truncate ? FMODE_WRITE : FMODE_READ; | ||
2154 | |||
2155 | if (nfs4_copy_delegation_stateid(&arg.stateid, inode, fmode)) { | ||
2156 | /* Use that stateid */ | ||
2157 | } else if (truncate && state != NULL && nfs4_valid_open_stateid(state)) { | ||
2058 | struct nfs_lockowner lockowner = { | 2158 | struct nfs_lockowner lockowner = { |
2059 | .l_owner = current->files, | 2159 | .l_owner = current->files, |
2060 | .l_pid = current->tgid, | 2160 | .l_pid = current->tgid, |
2061 | }; | 2161 | }; |
2062 | nfs4_select_rw_stateid(&arg.stateid, state, FMODE_WRITE, | 2162 | nfs4_select_rw_stateid(&arg.stateid, state, FMODE_WRITE, |
2063 | &lockowner); | 2163 | &lockowner); |
2064 | } else if (nfs4_copy_delegation_stateid(&arg.stateid, inode, | ||
2065 | FMODE_WRITE)) { | ||
2066 | /* Use that stateid */ | ||
2067 | } else | 2164 | } else |
2068 | nfs4_stateid_copy(&arg.stateid, &zero_stateid); | 2165 | nfs4_stateid_copy(&arg.stateid, &zero_stateid); |
2069 | 2166 | ||
@@ -2087,6 +2184,13 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, | |||
2087 | err = _nfs4_do_setattr(inode, cred, fattr, sattr, state); | 2184 | err = _nfs4_do_setattr(inode, cred, fattr, sattr, state); |
2088 | switch (err) { | 2185 | switch (err) { |
2089 | case -NFS4ERR_OPENMODE: | 2186 | case -NFS4ERR_OPENMODE: |
2187 | if (!(sattr->ia_valid & ATTR_SIZE)) { | ||
2188 | pr_warn_once("NFSv4: server %s is incorrectly " | ||
2189 | "applying open mode checks to " | ||
2190 | "a SETATTR that is not " | ||
2191 | "changing file size.\n", | ||
2192 | server->nfs_client->cl_hostname); | ||
2193 | } | ||
2090 | if (state && !(state->state & FMODE_WRITE)) { | 2194 | if (state && !(state->state & FMODE_WRITE)) { |
2091 | err = -EBADF; | 2195 | err = -EBADF; |
2092 | if (sattr->ia_valid & ATTR_OPEN) | 2196 | if (sattr->ia_valid & ATTR_OPEN) |
@@ -2130,11 +2234,19 @@ static void nfs4_close_clear_stateid_flags(struct nfs4_state *state, | |||
2130 | fmode_t fmode) | 2234 | fmode_t fmode) |
2131 | { | 2235 | { |
2132 | spin_lock(&state->owner->so_lock); | 2236 | spin_lock(&state->owner->so_lock); |
2133 | if (!(fmode & FMODE_READ)) | 2237 | clear_bit(NFS_O_RDWR_STATE, &state->flags); |
2238 | switch (fmode & (FMODE_READ|FMODE_WRITE)) { | ||
2239 | case FMODE_WRITE: | ||
2134 | clear_bit(NFS_O_RDONLY_STATE, &state->flags); | 2240 | clear_bit(NFS_O_RDONLY_STATE, &state->flags); |
2135 | if (!(fmode & FMODE_WRITE)) | 2241 | break; |
2242 | case FMODE_READ: | ||
2136 | clear_bit(NFS_O_WRONLY_STATE, &state->flags); | 2243 | clear_bit(NFS_O_WRONLY_STATE, &state->flags); |
2137 | clear_bit(NFS_O_RDWR_STATE, &state->flags); | 2244 | break; |
2245 | case 0: | ||
2246 | clear_bit(NFS_O_RDONLY_STATE, &state->flags); | ||
2247 | clear_bit(NFS_O_WRONLY_STATE, &state->flags); | ||
2248 | clear_bit(NFS_OPEN_STATE, &state->flags); | ||
2249 | } | ||
2138 | spin_unlock(&state->owner->so_lock); | 2250 | spin_unlock(&state->owner->so_lock); |
2139 | } | 2251 | } |
2140 | 2252 | ||
@@ -2202,6 +2314,8 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
2202 | calldata->arg.fmode &= ~FMODE_WRITE; | 2314 | calldata->arg.fmode &= ~FMODE_WRITE; |
2203 | } | 2315 | } |
2204 | } | 2316 | } |
2317 | if (!nfs4_valid_open_stateid(state)) | ||
2318 | call_close = 0; | ||
2205 | spin_unlock(&state->owner->so_lock); | 2319 | spin_unlock(&state->owner->so_lock); |
2206 | 2320 | ||
2207 | if (!call_close) { | 2321 | if (!call_close) { |
@@ -2212,8 +2326,10 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
2212 | if (calldata->arg.fmode == 0) { | 2326 | if (calldata->arg.fmode == 0) { |
2213 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE]; | 2327 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE]; |
2214 | if (calldata->roc && | 2328 | if (calldata->roc && |
2215 | pnfs_roc_drain(inode, &calldata->roc_barrier, task)) | 2329 | pnfs_roc_drain(inode, &calldata->roc_barrier, task)) { |
2330 | nfs_release_seqid(calldata->arg.seqid); | ||
2216 | goto out_wait; | 2331 | goto out_wait; |
2332 | } | ||
2217 | } | 2333 | } |
2218 | 2334 | ||
2219 | nfs_fattr_init(calldata->res.fattr); | 2335 | nfs_fattr_init(calldata->res.fattr); |
@@ -2444,7 +2560,7 @@ static int nfs4_lookup_root_sec(struct nfs_server *server, struct nfs_fh *fhandl | |||
2444 | 2560 | ||
2445 | auth = rpcauth_create(flavor, server->client); | 2561 | auth = rpcauth_create(flavor, server->client); |
2446 | if (IS_ERR(auth)) { | 2562 | if (IS_ERR(auth)) { |
2447 | ret = -EIO; | 2563 | ret = -EACCES; |
2448 | goto out; | 2564 | goto out; |
2449 | } | 2565 | } |
2450 | ret = nfs4_lookup_root(server, fhandle, info); | 2566 | ret = nfs4_lookup_root(server, fhandle, info); |
@@ -2452,27 +2568,36 @@ out: | |||
2452 | return ret; | 2568 | return ret; |
2453 | } | 2569 | } |
2454 | 2570 | ||
2571 | /* | ||
2572 | * Retry pseudoroot lookup with various security flavors. We do this when: | ||
2573 | * | ||
2574 | * NFSv4.0: the PUTROOTFH operation returns NFS4ERR_WRONGSEC | ||
2575 | * NFSv4.1: the server does not support the SECINFO_NO_NAME operation | ||
2576 | * | ||
2577 | * Returns zero on success, or a negative NFS4ERR value, or a | ||
2578 | * negative errno value. | ||
2579 | */ | ||
2455 | static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle, | 2580 | static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle, |
2456 | struct nfs_fsinfo *info) | 2581 | struct nfs_fsinfo *info) |
2457 | { | 2582 | { |
2458 | int i, len, status = 0; | 2583 | /* Per 3530bis 15.33.5 */ |
2459 | rpc_authflavor_t flav_array[NFS_MAX_SECFLAVORS]; | 2584 | static const rpc_authflavor_t flav_array[] = { |
2460 | 2585 | RPC_AUTH_GSS_KRB5P, | |
2461 | len = rpcauth_list_flavors(flav_array, ARRAY_SIZE(flav_array)); | 2586 | RPC_AUTH_GSS_KRB5I, |
2462 | if (len < 0) | 2587 | RPC_AUTH_GSS_KRB5, |
2463 | return len; | 2588 | RPC_AUTH_UNIX, /* courtesy */ |
2464 | 2589 | RPC_AUTH_NULL, | |
2465 | for (i = 0; i < len; i++) { | 2590 | }; |
2466 | /* AUTH_UNIX is the default flavor if none was specified, | 2591 | int status = -EPERM; |
2467 | * thus has already been tried. */ | 2592 | size_t i; |
2468 | if (flav_array[i] == RPC_AUTH_UNIX) | ||
2469 | continue; | ||
2470 | 2593 | ||
2594 | for (i = 0; i < ARRAY_SIZE(flav_array); i++) { | ||
2471 | status = nfs4_lookup_root_sec(server, fhandle, info, flav_array[i]); | 2595 | status = nfs4_lookup_root_sec(server, fhandle, info, flav_array[i]); |
2472 | if (status == -NFS4ERR_WRONGSEC || status == -EACCES) | 2596 | if (status == -NFS4ERR_WRONGSEC || status == -EACCES) |
2473 | continue; | 2597 | continue; |
2474 | break; | 2598 | break; |
2475 | } | 2599 | } |
2600 | |||
2476 | /* | 2601 | /* |
2477 | * -EACCESS could mean that the user doesn't have correct permissions | 2602 | * -EACCESS could mean that the user doesn't have correct permissions |
2478 | * to access the mount. It could also mean that we tried to mount | 2603 | * to access the mount. It could also mean that we tried to mount |
@@ -2485,24 +2610,36 @@ static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle, | |||
2485 | return status; | 2610 | return status; |
2486 | } | 2611 | } |
2487 | 2612 | ||
2488 | /* | 2613 | static int nfs4_do_find_root_sec(struct nfs_server *server, |
2489 | * get the file handle for the "/" directory on the server | 2614 | struct nfs_fh *fhandle, struct nfs_fsinfo *info) |
2615 | { | ||
2616 | int mv = server->nfs_client->cl_minorversion; | ||
2617 | return nfs_v4_minor_ops[mv]->find_root_sec(server, fhandle, info); | ||
2618 | } | ||
2619 | |||
2620 | /** | ||
2621 | * nfs4_proc_get_rootfh - get file handle for server's pseudoroot | ||
2622 | * @server: initialized nfs_server handle | ||
2623 | * @fhandle: we fill in the pseudo-fs root file handle | ||
2624 | * @info: we fill in an FSINFO struct | ||
2625 | * | ||
2626 | * Returns zero on success, or a negative errno. | ||
2490 | */ | 2627 | */ |
2491 | int nfs4_proc_get_rootfh(struct nfs_server *server, struct nfs_fh *fhandle, | 2628 | int nfs4_proc_get_rootfh(struct nfs_server *server, struct nfs_fh *fhandle, |
2492 | struct nfs_fsinfo *info) | 2629 | struct nfs_fsinfo *info) |
2493 | { | 2630 | { |
2494 | int minor_version = server->nfs_client->cl_minorversion; | 2631 | int status; |
2495 | int status = nfs4_lookup_root(server, fhandle, info); | 2632 | |
2496 | if ((status == -NFS4ERR_WRONGSEC) && !(server->flags & NFS_MOUNT_SECFLAVOUR)) | 2633 | status = nfs4_lookup_root(server, fhandle, info); |
2497 | /* | 2634 | if ((status == -NFS4ERR_WRONGSEC) && |
2498 | * A status of -NFS4ERR_WRONGSEC will be mapped to -EPERM | 2635 | !(server->flags & NFS_MOUNT_SECFLAVOUR)) |
2499 | * by nfs4_map_errors() as this function exits. | 2636 | status = nfs4_do_find_root_sec(server, fhandle, info); |
2500 | */ | 2637 | |
2501 | status = nfs_v4_minor_ops[minor_version]->find_root_sec(server, fhandle, info); | ||
2502 | if (status == 0) | 2638 | if (status == 0) |
2503 | status = nfs4_server_capabilities(server, fhandle); | 2639 | status = nfs4_server_capabilities(server, fhandle); |
2504 | if (status == 0) | 2640 | if (status == 0) |
2505 | status = nfs4_do_fsinfo(server, fhandle, info); | 2641 | status = nfs4_do_fsinfo(server, fhandle, info); |
2642 | |||
2506 | return nfs4_map_errors(status); | 2643 | return nfs4_map_errors(status); |
2507 | } | 2644 | } |
2508 | 2645 | ||
@@ -3381,12 +3518,21 @@ static int _nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, | |||
3381 | static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo) | 3518 | static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo) |
3382 | { | 3519 | { |
3383 | struct nfs4_exception exception = { }; | 3520 | struct nfs4_exception exception = { }; |
3521 | unsigned long now = jiffies; | ||
3384 | int err; | 3522 | int err; |
3385 | 3523 | ||
3386 | do { | 3524 | do { |
3387 | err = nfs4_handle_exception(server, | 3525 | err = _nfs4_do_fsinfo(server, fhandle, fsinfo); |
3388 | _nfs4_do_fsinfo(server, fhandle, fsinfo), | 3526 | if (err == 0) { |
3389 | &exception); | 3527 | struct nfs_client *clp = server->nfs_client; |
3528 | |||
3529 | spin_lock(&clp->cl_lock); | ||
3530 | clp->cl_lease_time = fsinfo->lease_time * HZ; | ||
3531 | clp->cl_last_renewal = now; | ||
3532 | spin_unlock(&clp->cl_lock); | ||
3533 | break; | ||
3534 | } | ||
3535 | err = nfs4_handle_exception(server, err, &exception); | ||
3390 | } while (exception.retry); | 3536 | } while (exception.retry); |
3391 | return err; | 3537 | return err; |
3392 | } | 3538 | } |
@@ -3446,6 +3592,46 @@ static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, | |||
3446 | return err; | 3592 | return err; |
3447 | } | 3593 | } |
3448 | 3594 | ||
3595 | int nfs4_set_rw_stateid(nfs4_stateid *stateid, | ||
3596 | const struct nfs_open_context *ctx, | ||
3597 | const struct nfs_lock_context *l_ctx, | ||
3598 | fmode_t fmode) | ||
3599 | { | ||
3600 | const struct nfs_lockowner *lockowner = NULL; | ||
3601 | |||
3602 | if (l_ctx != NULL) | ||
3603 | lockowner = &l_ctx->lockowner; | ||
3604 | return nfs4_select_rw_stateid(stateid, ctx->state, fmode, lockowner); | ||
3605 | } | ||
3606 | EXPORT_SYMBOL_GPL(nfs4_set_rw_stateid); | ||
3607 | |||
3608 | static bool nfs4_stateid_is_current(nfs4_stateid *stateid, | ||
3609 | const struct nfs_open_context *ctx, | ||
3610 | const struct nfs_lock_context *l_ctx, | ||
3611 | fmode_t fmode) | ||
3612 | { | ||
3613 | nfs4_stateid current_stateid; | ||
3614 | |||
3615 | if (nfs4_set_rw_stateid(¤t_stateid, ctx, l_ctx, fmode)) | ||
3616 | return false; | ||
3617 | return nfs4_stateid_match(stateid, ¤t_stateid); | ||
3618 | } | ||
3619 | |||
3620 | static bool nfs4_error_stateid_expired(int err) | ||
3621 | { | ||
3622 | switch (err) { | ||
3623 | case -NFS4ERR_DELEG_REVOKED: | ||
3624 | case -NFS4ERR_ADMIN_REVOKED: | ||
3625 | case -NFS4ERR_BAD_STATEID: | ||
3626 | case -NFS4ERR_STALE_STATEID: | ||
3627 | case -NFS4ERR_OLD_STATEID: | ||
3628 | case -NFS4ERR_OPENMODE: | ||
3629 | case -NFS4ERR_EXPIRED: | ||
3630 | return true; | ||
3631 | } | ||
3632 | return false; | ||
3633 | } | ||
3634 | |||
3449 | void __nfs4_read_done_cb(struct nfs_read_data *data) | 3635 | void __nfs4_read_done_cb(struct nfs_read_data *data) |
3450 | { | 3636 | { |
3451 | nfs_invalidate_atime(data->header->inode); | 3637 | nfs_invalidate_atime(data->header->inode); |
@@ -3466,6 +3652,20 @@ static int nfs4_read_done_cb(struct rpc_task *task, struct nfs_read_data *data) | |||
3466 | return 0; | 3652 | return 0; |
3467 | } | 3653 | } |
3468 | 3654 | ||
3655 | static bool nfs4_read_stateid_changed(struct rpc_task *task, | ||
3656 | struct nfs_readargs *args) | ||
3657 | { | ||
3658 | |||
3659 | if (!nfs4_error_stateid_expired(task->tk_status) || | ||
3660 | nfs4_stateid_is_current(&args->stateid, | ||
3661 | args->context, | ||
3662 | args->lock_context, | ||
3663 | FMODE_READ)) | ||
3664 | return false; | ||
3665 | rpc_restart_call_prepare(task); | ||
3666 | return true; | ||
3667 | } | ||
3668 | |||
3469 | static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data) | 3669 | static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data) |
3470 | { | 3670 | { |
3471 | 3671 | ||
@@ -3473,7 +3673,8 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data) | |||
3473 | 3673 | ||
3474 | if (!nfs4_sequence_done(task, &data->res.seq_res)) | 3674 | if (!nfs4_sequence_done(task, &data->res.seq_res)) |
3475 | return -EAGAIN; | 3675 | return -EAGAIN; |
3476 | 3676 | if (nfs4_read_stateid_changed(task, &data->args)) | |
3677 | return -EAGAIN; | ||
3477 | return data->read_done_cb ? data->read_done_cb(task, data) : | 3678 | return data->read_done_cb ? data->read_done_cb(task, data) : |
3478 | nfs4_read_done_cb(task, data); | 3679 | nfs4_read_done_cb(task, data); |
3479 | } | 3680 | } |
@@ -3488,10 +3689,13 @@ static void nfs4_proc_read_setup(struct nfs_read_data *data, struct rpc_message | |||
3488 | 3689 | ||
3489 | static void nfs4_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_data *data) | 3690 | static void nfs4_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_data *data) |
3490 | { | 3691 | { |
3491 | nfs4_setup_sequence(NFS_SERVER(data->header->inode), | 3692 | if (nfs4_setup_sequence(NFS_SERVER(data->header->inode), |
3492 | &data->args.seq_args, | 3693 | &data->args.seq_args, |
3493 | &data->res.seq_res, | 3694 | &data->res.seq_res, |
3494 | task); | 3695 | task)) |
3696 | return; | ||
3697 | nfs4_set_rw_stateid(&data->args.stateid, data->args.context, | ||
3698 | data->args.lock_context, FMODE_READ); | ||
3495 | } | 3699 | } |
3496 | 3700 | ||
3497 | static int nfs4_write_done_cb(struct rpc_task *task, struct nfs_write_data *data) | 3701 | static int nfs4_write_done_cb(struct rpc_task *task, struct nfs_write_data *data) |
@@ -3509,10 +3713,26 @@ static int nfs4_write_done_cb(struct rpc_task *task, struct nfs_write_data *data | |||
3509 | return 0; | 3713 | return 0; |
3510 | } | 3714 | } |
3511 | 3715 | ||
3716 | static bool nfs4_write_stateid_changed(struct rpc_task *task, | ||
3717 | struct nfs_writeargs *args) | ||
3718 | { | ||
3719 | |||
3720 | if (!nfs4_error_stateid_expired(task->tk_status) || | ||
3721 | nfs4_stateid_is_current(&args->stateid, | ||
3722 | args->context, | ||
3723 | args->lock_context, | ||
3724 | FMODE_WRITE)) | ||
3725 | return false; | ||
3726 | rpc_restart_call_prepare(task); | ||
3727 | return true; | ||
3728 | } | ||
3729 | |||
3512 | static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) | 3730 | static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) |
3513 | { | 3731 | { |
3514 | if (!nfs4_sequence_done(task, &data->res.seq_res)) | 3732 | if (!nfs4_sequence_done(task, &data->res.seq_res)) |
3515 | return -EAGAIN; | 3733 | return -EAGAIN; |
3734 | if (nfs4_write_stateid_changed(task, &data->args)) | ||
3735 | return -EAGAIN; | ||
3516 | return data->write_done_cb ? data->write_done_cb(task, data) : | 3736 | return data->write_done_cb ? data->write_done_cb(task, data) : |
3517 | nfs4_write_done_cb(task, data); | 3737 | nfs4_write_done_cb(task, data); |
3518 | } | 3738 | } |
@@ -3552,10 +3772,13 @@ static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_messag | |||
3552 | 3772 | ||
3553 | static void nfs4_proc_write_rpc_prepare(struct rpc_task *task, struct nfs_write_data *data) | 3773 | static void nfs4_proc_write_rpc_prepare(struct rpc_task *task, struct nfs_write_data *data) |
3554 | { | 3774 | { |
3555 | nfs4_setup_sequence(NFS_SERVER(data->header->inode), | 3775 | if (nfs4_setup_sequence(NFS_SERVER(data->header->inode), |
3556 | &data->args.seq_args, | 3776 | &data->args.seq_args, |
3557 | &data->res.seq_res, | 3777 | &data->res.seq_res, |
3558 | task); | 3778 | task)) |
3779 | return; | ||
3780 | nfs4_set_rw_stateid(&data->args.stateid, data->args.context, | ||
3781 | data->args.lock_context, FMODE_WRITE); | ||
3559 | } | 3782 | } |
3560 | 3783 | ||
3561 | static void nfs4_proc_commit_rpc_prepare(struct rpc_task *task, struct nfs_commit_data *data) | 3784 | static void nfs4_proc_commit_rpc_prepare(struct rpc_task *task, struct nfs_commit_data *data) |
@@ -3657,7 +3880,7 @@ static int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred, | |||
3657 | return -ENOMEM; | 3880 | return -ENOMEM; |
3658 | data->client = clp; | 3881 | data->client = clp; |
3659 | data->timestamp = jiffies; | 3882 | data->timestamp = jiffies; |
3660 | return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT, | 3883 | return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT, |
3661 | &nfs4_renew_ops, data); | 3884 | &nfs4_renew_ops, data); |
3662 | } | 3885 | } |
3663 | 3886 | ||
@@ -3671,7 +3894,7 @@ static int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred) | |||
3671 | unsigned long now = jiffies; | 3894 | unsigned long now = jiffies; |
3672 | int status; | 3895 | int status; |
3673 | 3896 | ||
3674 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); | 3897 | status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); |
3675 | if (status < 0) | 3898 | if (status < 0) |
3676 | return status; | 3899 | return status; |
3677 | do_renew_lease(clp, now); | 3900 | do_renew_lease(clp, now); |
@@ -3981,11 +4204,14 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
3981 | case -NFS4ERR_OPENMODE: | 4204 | case -NFS4ERR_OPENMODE: |
3982 | if (state == NULL) | 4205 | if (state == NULL) |
3983 | break; | 4206 | break; |
3984 | nfs4_schedule_stateid_recovery(server, state); | 4207 | if (nfs4_schedule_stateid_recovery(server, state) < 0) |
4208 | goto stateid_invalid; | ||
3985 | goto wait_on_recovery; | 4209 | goto wait_on_recovery; |
3986 | case -NFS4ERR_EXPIRED: | 4210 | case -NFS4ERR_EXPIRED: |
3987 | if (state != NULL) | 4211 | if (state != NULL) { |
3988 | nfs4_schedule_stateid_recovery(server, state); | 4212 | if (nfs4_schedule_stateid_recovery(server, state) < 0) |
4213 | goto stateid_invalid; | ||
4214 | } | ||
3989 | case -NFS4ERR_STALE_STATEID: | 4215 | case -NFS4ERR_STALE_STATEID: |
3990 | case -NFS4ERR_STALE_CLIENTID: | 4216 | case -NFS4ERR_STALE_CLIENTID: |
3991 | nfs4_schedule_lease_recovery(clp); | 4217 | nfs4_schedule_lease_recovery(clp); |
@@ -4017,6 +4243,9 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
4017 | } | 4243 | } |
4018 | task->tk_status = nfs4_map_errors(task->tk_status); | 4244 | task->tk_status = nfs4_map_errors(task->tk_status); |
4019 | return 0; | 4245 | return 0; |
4246 | stateid_invalid: | ||
4247 | task->tk_status = -EIO; | ||
4248 | return 0; | ||
4020 | wait_on_recovery: | 4249 | wait_on_recovery: |
4021 | rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL); | 4250 | rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL); |
4022 | if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0) | 4251 | if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0) |
@@ -4144,27 +4373,17 @@ int nfs4_proc_setclientid_confirm(struct nfs_client *clp, | |||
4144 | struct nfs4_setclientid_res *arg, | 4373 | struct nfs4_setclientid_res *arg, |
4145 | struct rpc_cred *cred) | 4374 | struct rpc_cred *cred) |
4146 | { | 4375 | { |
4147 | struct nfs_fsinfo fsinfo; | ||
4148 | struct rpc_message msg = { | 4376 | struct rpc_message msg = { |
4149 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID_CONFIRM], | 4377 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID_CONFIRM], |
4150 | .rpc_argp = arg, | 4378 | .rpc_argp = arg, |
4151 | .rpc_resp = &fsinfo, | ||
4152 | .rpc_cred = cred, | 4379 | .rpc_cred = cred, |
4153 | }; | 4380 | }; |
4154 | unsigned long now; | ||
4155 | int status; | 4381 | int status; |
4156 | 4382 | ||
4157 | dprintk("NFS call setclientid_confirm auth=%s, (client ID %llx)\n", | 4383 | dprintk("NFS call setclientid_confirm auth=%s, (client ID %llx)\n", |
4158 | clp->cl_rpcclient->cl_auth->au_ops->au_name, | 4384 | clp->cl_rpcclient->cl_auth->au_ops->au_name, |
4159 | clp->cl_clientid); | 4385 | clp->cl_clientid); |
4160 | now = jiffies; | ||
4161 | status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); | 4386 | status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); |
4162 | if (status == 0) { | ||
4163 | spin_lock(&clp->cl_lock); | ||
4164 | clp->cl_lease_time = fsinfo.lease_time * HZ; | ||
4165 | clp->cl_last_renewal = now; | ||
4166 | spin_unlock(&clp->cl_lock); | ||
4167 | } | ||
4168 | dprintk("NFS reply setclientid_confirm: %d\n", status); | 4387 | dprintk("NFS reply setclientid_confirm: %d\n", status); |
4169 | return status; | 4388 | return status; |
4170 | } | 4389 | } |
@@ -4628,17 +4847,23 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) | |||
4628 | if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0) { | 4847 | if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0) { |
4629 | goto out_release_lock_seqid; | 4848 | goto out_release_lock_seqid; |
4630 | } | 4849 | } |
4631 | data->arg.open_stateid = &state->stateid; | 4850 | data->arg.open_stateid = &state->open_stateid; |
4632 | data->arg.new_lock_owner = 1; | 4851 | data->arg.new_lock_owner = 1; |
4633 | data->res.open_seqid = data->arg.open_seqid; | 4852 | data->res.open_seqid = data->arg.open_seqid; |
4634 | } else | 4853 | } else |
4635 | data->arg.new_lock_owner = 0; | 4854 | data->arg.new_lock_owner = 0; |
4855 | if (!nfs4_valid_open_stateid(state)) { | ||
4856 | data->rpc_status = -EBADF; | ||
4857 | task->tk_action = NULL; | ||
4858 | goto out_release_open_seqid; | ||
4859 | } | ||
4636 | data->timestamp = jiffies; | 4860 | data->timestamp = jiffies; |
4637 | if (nfs4_setup_sequence(data->server, | 4861 | if (nfs4_setup_sequence(data->server, |
4638 | &data->arg.seq_args, | 4862 | &data->arg.seq_args, |
4639 | &data->res.seq_res, | 4863 | &data->res.seq_res, |
4640 | task) == 0) | 4864 | task) == 0) |
4641 | return; | 4865 | return; |
4866 | out_release_open_seqid: | ||
4642 | nfs_release_seqid(data->arg.open_seqid); | 4867 | nfs_release_seqid(data->arg.open_seqid); |
4643 | out_release_lock_seqid: | 4868 | out_release_lock_seqid: |
4644 | nfs_release_seqid(data->arg.lock_seqid); | 4869 | nfs_release_seqid(data->arg.lock_seqid); |
@@ -4984,58 +5209,16 @@ nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request) | |||
4984 | return status; | 5209 | return status; |
4985 | } | 5210 | } |
4986 | 5211 | ||
4987 | int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl) | 5212 | int nfs4_lock_delegation_recall(struct file_lock *fl, struct nfs4_state *state, const nfs4_stateid *stateid) |
4988 | { | 5213 | { |
4989 | struct nfs_server *server = NFS_SERVER(state->inode); | 5214 | struct nfs_server *server = NFS_SERVER(state->inode); |
4990 | struct nfs4_exception exception = { }; | ||
4991 | int err; | 5215 | int err; |
4992 | 5216 | ||
4993 | err = nfs4_set_lock_state(state, fl); | 5217 | err = nfs4_set_lock_state(state, fl); |
4994 | if (err != 0) | 5218 | if (err != 0) |
4995 | goto out; | 5219 | return err; |
4996 | do { | 5220 | err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW); |
4997 | err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW); | 5221 | return nfs4_handle_delegation_recall_error(server, state, stateid, err); |
4998 | switch (err) { | ||
4999 | default: | ||
5000 | printk(KERN_ERR "NFS: %s: unhandled error " | ||
5001 | "%d.\n", __func__, err); | ||
5002 | case 0: | ||
5003 | case -ESTALE: | ||
5004 | goto out; | ||
5005 | case -NFS4ERR_STALE_CLIENTID: | ||
5006 | case -NFS4ERR_STALE_STATEID: | ||
5007 | set_bit(NFS_DELEGATED_STATE, &state->flags); | ||
5008 | case -NFS4ERR_EXPIRED: | ||
5009 | nfs4_schedule_lease_recovery(server->nfs_client); | ||
5010 | err = -EAGAIN; | ||
5011 | goto out; | ||
5012 | case -NFS4ERR_BADSESSION: | ||
5013 | case -NFS4ERR_BADSLOT: | ||
5014 | case -NFS4ERR_BAD_HIGH_SLOT: | ||
5015 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | ||
5016 | case -NFS4ERR_DEADSESSION: | ||
5017 | set_bit(NFS_DELEGATED_STATE, &state->flags); | ||
5018 | nfs4_schedule_session_recovery(server->nfs_client->cl_session, err); | ||
5019 | err = -EAGAIN; | ||
5020 | goto out; | ||
5021 | case -NFS4ERR_DELEG_REVOKED: | ||
5022 | case -NFS4ERR_ADMIN_REVOKED: | ||
5023 | case -NFS4ERR_BAD_STATEID: | ||
5024 | case -NFS4ERR_OPENMODE: | ||
5025 | nfs4_schedule_stateid_recovery(server, state); | ||
5026 | err = 0; | ||
5027 | goto out; | ||
5028 | case -ENOMEM: | ||
5029 | case -NFS4ERR_DENIED: | ||
5030 | /* kill_proc(fl->fl_pid, SIGLOST, 1); */ | ||
5031 | err = 0; | ||
5032 | goto out; | ||
5033 | } | ||
5034 | set_bit(NFS_DELEGATED_STATE, &state->flags); | ||
5035 | err = nfs4_handle_exception(server, err, &exception); | ||
5036 | } while (exception.retry); | ||
5037 | out: | ||
5038 | return err; | ||
5039 | } | 5222 | } |
5040 | 5223 | ||
5041 | struct nfs_release_lockowner_data { | 5224 | struct nfs_release_lockowner_data { |
@@ -5849,7 +6032,7 @@ static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, | |||
5849 | .rpc_client = clp->cl_rpcclient, | 6032 | .rpc_client = clp->cl_rpcclient, |
5850 | .rpc_message = &msg, | 6033 | .rpc_message = &msg, |
5851 | .callback_ops = &nfs41_sequence_ops, | 6034 | .callback_ops = &nfs41_sequence_ops, |
5852 | .flags = RPC_TASK_ASYNC | RPC_TASK_SOFT, | 6035 | .flags = RPC_TASK_ASYNC | RPC_TASK_TIMEOUT, |
5853 | }; | 6036 | }; |
5854 | 6037 | ||
5855 | if (!atomic_inc_not_zero(&clp->cl_count)) | 6038 | if (!atomic_inc_not_zero(&clp->cl_count)) |
@@ -6726,6 +6909,10 @@ static const struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = { | |||
6726 | 6909 | ||
6727 | static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = { | 6910 | static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = { |
6728 | .minor_version = 0, | 6911 | .minor_version = 0, |
6912 | .init_caps = NFS_CAP_READDIRPLUS | ||
6913 | | NFS_CAP_ATOMIC_OPEN | ||
6914 | | NFS_CAP_CHANGE_ATTR | ||
6915 | | NFS_CAP_POSIX_LOCK, | ||
6729 | .call_sync = _nfs4_call_sync, | 6916 | .call_sync = _nfs4_call_sync, |
6730 | .match_stateid = nfs4_match_stateid, | 6917 | .match_stateid = nfs4_match_stateid, |
6731 | .find_root_sec = nfs4_find_root_sec, | 6918 | .find_root_sec = nfs4_find_root_sec, |
@@ -6737,6 +6924,12 @@ static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = { | |||
6737 | #if defined(CONFIG_NFS_V4_1) | 6924 | #if defined(CONFIG_NFS_V4_1) |
6738 | static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = { | 6925 | static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = { |
6739 | .minor_version = 1, | 6926 | .minor_version = 1, |
6927 | .init_caps = NFS_CAP_READDIRPLUS | ||
6928 | | NFS_CAP_ATOMIC_OPEN | ||
6929 | | NFS_CAP_CHANGE_ATTR | ||
6930 | | NFS_CAP_POSIX_LOCK | ||
6931 | | NFS_CAP_STATEID_NFSV41 | ||
6932 | | NFS_CAP_ATOMIC_OPEN_V1, | ||
6740 | .call_sync = nfs4_call_sync_sequence, | 6933 | .call_sync = nfs4_call_sync_sequence, |
6741 | .match_stateid = nfs41_match_stateid, | 6934 | .match_stateid = nfs41_match_stateid, |
6742 | .find_root_sec = nfs41_find_root_sec, | 6935 | .find_root_sec = nfs41_find_root_sec, |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index d41a3518509f..0b32f9483b7a 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -154,18 +154,6 @@ struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp) | |||
154 | return cred; | 154 | return cred; |
155 | } | 155 | } |
156 | 156 | ||
157 | static void nfs4_clear_machine_cred(struct nfs_client *clp) | ||
158 | { | ||
159 | struct rpc_cred *cred; | ||
160 | |||
161 | spin_lock(&clp->cl_lock); | ||
162 | cred = clp->cl_machine_cred; | ||
163 | clp->cl_machine_cred = NULL; | ||
164 | spin_unlock(&clp->cl_lock); | ||
165 | if (cred != NULL) | ||
166 | put_rpccred(cred); | ||
167 | } | ||
168 | |||
169 | static struct rpc_cred * | 157 | static struct rpc_cred * |
170 | nfs4_get_renew_cred_server_locked(struct nfs_server *server) | 158 | nfs4_get_renew_cred_server_locked(struct nfs_server *server) |
171 | { | 159 | { |
@@ -699,6 +687,8 @@ __nfs4_find_state_byowner(struct inode *inode, struct nfs4_state_owner *owner) | |||
699 | list_for_each_entry(state, &nfsi->open_states, inode_states) { | 687 | list_for_each_entry(state, &nfsi->open_states, inode_states) { |
700 | if (state->owner != owner) | 688 | if (state->owner != owner) |
701 | continue; | 689 | continue; |
690 | if (!nfs4_valid_open_stateid(state)) | ||
691 | continue; | ||
702 | if (atomic_inc_not_zero(&state->count)) | 692 | if (atomic_inc_not_zero(&state->count)) |
703 | return state; | 693 | return state; |
704 | } | 694 | } |
@@ -987,13 +977,14 @@ int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl) | |||
987 | return 0; | 977 | return 0; |
988 | } | 978 | } |
989 | 979 | ||
990 | static bool nfs4_copy_lock_stateid(nfs4_stateid *dst, struct nfs4_state *state, | 980 | static int nfs4_copy_lock_stateid(nfs4_stateid *dst, |
981 | struct nfs4_state *state, | ||
991 | const struct nfs_lockowner *lockowner) | 982 | const struct nfs_lockowner *lockowner) |
992 | { | 983 | { |
993 | struct nfs4_lock_state *lsp; | 984 | struct nfs4_lock_state *lsp; |
994 | fl_owner_t fl_owner; | 985 | fl_owner_t fl_owner; |
995 | pid_t fl_pid; | 986 | pid_t fl_pid; |
996 | bool ret = false; | 987 | int ret = -ENOENT; |
997 | 988 | ||
998 | 989 | ||
999 | if (lockowner == NULL) | 990 | if (lockowner == NULL) |
@@ -1008,7 +999,10 @@ static bool nfs4_copy_lock_stateid(nfs4_stateid *dst, struct nfs4_state *state, | |||
1008 | lsp = __nfs4_find_lock_state(state, fl_owner, fl_pid, NFS4_ANY_LOCK_TYPE); | 999 | lsp = __nfs4_find_lock_state(state, fl_owner, fl_pid, NFS4_ANY_LOCK_TYPE); |
1009 | if (lsp != NULL && test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) != 0) { | 1000 | if (lsp != NULL && test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) != 0) { |
1010 | nfs4_stateid_copy(dst, &lsp->ls_stateid); | 1001 | nfs4_stateid_copy(dst, &lsp->ls_stateid); |
1011 | ret = true; | 1002 | ret = 0; |
1003 | smp_rmb(); | ||
1004 | if (!list_empty(&lsp->ls_seqid.list)) | ||
1005 | ret = -EWOULDBLOCK; | ||
1012 | } | 1006 | } |
1013 | spin_unlock(&state->state_lock); | 1007 | spin_unlock(&state->state_lock); |
1014 | nfs4_put_lock_state(lsp); | 1008 | nfs4_put_lock_state(lsp); |
@@ -1016,28 +1010,44 @@ out: | |||
1016 | return ret; | 1010 | return ret; |
1017 | } | 1011 | } |
1018 | 1012 | ||
1019 | static void nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state) | 1013 | static int nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state) |
1020 | { | 1014 | { |
1015 | const nfs4_stateid *src; | ||
1016 | int ret; | ||
1021 | int seq; | 1017 | int seq; |
1022 | 1018 | ||
1023 | do { | 1019 | do { |
1020 | src = &zero_stateid; | ||
1024 | seq = read_seqbegin(&state->seqlock); | 1021 | seq = read_seqbegin(&state->seqlock); |
1025 | nfs4_stateid_copy(dst, &state->stateid); | 1022 | if (test_bit(NFS_OPEN_STATE, &state->flags)) |
1023 | src = &state->open_stateid; | ||
1024 | nfs4_stateid_copy(dst, src); | ||
1025 | ret = 0; | ||
1026 | smp_rmb(); | ||
1027 | if (!list_empty(&state->owner->so_seqid.list)) | ||
1028 | ret = -EWOULDBLOCK; | ||
1026 | } while (read_seqretry(&state->seqlock, seq)); | 1029 | } while (read_seqretry(&state->seqlock, seq)); |
1030 | return ret; | ||
1027 | } | 1031 | } |
1028 | 1032 | ||
1029 | /* | 1033 | /* |
1030 | * Byte-range lock aware utility to initialize the stateid of read/write | 1034 | * Byte-range lock aware utility to initialize the stateid of read/write |
1031 | * requests. | 1035 | * requests. |
1032 | */ | 1036 | */ |
1033 | void nfs4_select_rw_stateid(nfs4_stateid *dst, struct nfs4_state *state, | 1037 | int nfs4_select_rw_stateid(nfs4_stateid *dst, struct nfs4_state *state, |
1034 | fmode_t fmode, const struct nfs_lockowner *lockowner) | 1038 | fmode_t fmode, const struct nfs_lockowner *lockowner) |
1035 | { | 1039 | { |
1040 | int ret = 0; | ||
1036 | if (nfs4_copy_delegation_stateid(dst, state->inode, fmode)) | 1041 | if (nfs4_copy_delegation_stateid(dst, state->inode, fmode)) |
1037 | return; | 1042 | goto out; |
1038 | if (nfs4_copy_lock_stateid(dst, state, lockowner)) | 1043 | ret = nfs4_copy_lock_stateid(dst, state, lockowner); |
1039 | return; | 1044 | if (ret != -ENOENT) |
1040 | nfs4_copy_open_stateid(dst, state); | 1045 | goto out; |
1046 | ret = nfs4_copy_open_stateid(dst, state); | ||
1047 | out: | ||
1048 | if (nfs_server_capable(state->inode, NFS_CAP_STATEID_NFSV41)) | ||
1049 | dst->seqid = 0; | ||
1050 | return ret; | ||
1041 | } | 1051 | } |
1042 | 1052 | ||
1043 | struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask) | 1053 | struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask) |
@@ -1286,14 +1296,17 @@ static int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_s | |||
1286 | return 1; | 1296 | return 1; |
1287 | } | 1297 | } |
1288 | 1298 | ||
1289 | void nfs4_schedule_stateid_recovery(const struct nfs_server *server, struct nfs4_state *state) | 1299 | int nfs4_schedule_stateid_recovery(const struct nfs_server *server, struct nfs4_state *state) |
1290 | { | 1300 | { |
1291 | struct nfs_client *clp = server->nfs_client; | 1301 | struct nfs_client *clp = server->nfs_client; |
1292 | 1302 | ||
1303 | if (!nfs4_valid_open_stateid(state)) | ||
1304 | return -EBADF; | ||
1293 | nfs4_state_mark_reclaim_nograce(clp, state); | 1305 | nfs4_state_mark_reclaim_nograce(clp, state); |
1294 | dprintk("%s: scheduling stateid recovery for server %s\n", __func__, | 1306 | dprintk("%s: scheduling stateid recovery for server %s\n", __func__, |
1295 | clp->cl_hostname); | 1307 | clp->cl_hostname); |
1296 | nfs4_schedule_state_manager(clp); | 1308 | nfs4_schedule_state_manager(clp); |
1309 | return 0; | ||
1297 | } | 1310 | } |
1298 | EXPORT_SYMBOL_GPL(nfs4_schedule_stateid_recovery); | 1311 | EXPORT_SYMBOL_GPL(nfs4_schedule_stateid_recovery); |
1299 | 1312 | ||
@@ -1323,6 +1336,27 @@ void nfs_inode_find_state_and_recover(struct inode *inode, | |||
1323 | nfs4_schedule_state_manager(clp); | 1336 | nfs4_schedule_state_manager(clp); |
1324 | } | 1337 | } |
1325 | 1338 | ||
1339 | static void nfs4_state_mark_open_context_bad(struct nfs4_state *state) | ||
1340 | { | ||
1341 | struct inode *inode = state->inode; | ||
1342 | struct nfs_inode *nfsi = NFS_I(inode); | ||
1343 | struct nfs_open_context *ctx; | ||
1344 | |||
1345 | spin_lock(&inode->i_lock); | ||
1346 | list_for_each_entry(ctx, &nfsi->open_files, list) { | ||
1347 | if (ctx->state != state) | ||
1348 | continue; | ||
1349 | set_bit(NFS_CONTEXT_BAD, &ctx->flags); | ||
1350 | } | ||
1351 | spin_unlock(&inode->i_lock); | ||
1352 | } | ||
1353 | |||
1354 | static void nfs4_state_mark_recovery_failed(struct nfs4_state *state, int error) | ||
1355 | { | ||
1356 | set_bit(NFS_STATE_RECOVERY_FAILED, &state->flags); | ||
1357 | nfs4_state_mark_open_context_bad(state); | ||
1358 | } | ||
1359 | |||
1326 | 1360 | ||
1327 | static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_recovery_ops *ops) | 1361 | static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_recovery_ops *ops) |
1328 | { | 1362 | { |
@@ -1398,6 +1432,8 @@ restart: | |||
1398 | list_for_each_entry(state, &sp->so_states, open_states) { | 1432 | list_for_each_entry(state, &sp->so_states, open_states) { |
1399 | if (!test_and_clear_bit(ops->state_flag_bit, &state->flags)) | 1433 | if (!test_and_clear_bit(ops->state_flag_bit, &state->flags)) |
1400 | continue; | 1434 | continue; |
1435 | if (!nfs4_valid_open_stateid(state)) | ||
1436 | continue; | ||
1401 | if (state->state == 0) | 1437 | if (state->state == 0) |
1402 | continue; | 1438 | continue; |
1403 | atomic_inc(&state->count); | 1439 | atomic_inc(&state->count); |
@@ -1430,11 +1466,10 @@ restart: | |||
1430 | * Open state on this file cannot be recovered | 1466 | * Open state on this file cannot be recovered |
1431 | * All we can do is revert to using the zero stateid. | 1467 | * All we can do is revert to using the zero stateid. |
1432 | */ | 1468 | */ |
1433 | memset(&state->stateid, 0, | 1469 | nfs4_state_mark_recovery_failed(state, status); |
1434 | sizeof(state->stateid)); | ||
1435 | /* Mark the file as being 'closed' */ | ||
1436 | state->state = 0; | ||
1437 | break; | 1470 | break; |
1471 | case -EAGAIN: | ||
1472 | ssleep(1); | ||
1438 | case -NFS4ERR_ADMIN_REVOKED: | 1473 | case -NFS4ERR_ADMIN_REVOKED: |
1439 | case -NFS4ERR_STALE_STATEID: | 1474 | case -NFS4ERR_STALE_STATEID: |
1440 | case -NFS4ERR_BAD_STATEID: | 1475 | case -NFS4ERR_BAD_STATEID: |
@@ -1696,6 +1731,10 @@ static int nfs4_check_lease(struct nfs_client *clp) | |||
1696 | } | 1731 | } |
1697 | status = ops->renew_lease(clp, cred); | 1732 | status = ops->renew_lease(clp, cred); |
1698 | put_rpccred(cred); | 1733 | put_rpccred(cred); |
1734 | if (status == -ETIMEDOUT) { | ||
1735 | set_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state); | ||
1736 | return 0; | ||
1737 | } | ||
1699 | out: | 1738 | out: |
1700 | return nfs4_recovery_handle_error(clp, status); | 1739 | return nfs4_recovery_handle_error(clp, status); |
1701 | } | 1740 | } |
@@ -1725,10 +1764,6 @@ static int nfs4_handle_reclaim_lease_error(struct nfs_client *clp, int status) | |||
1725 | clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); | 1764 | clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); |
1726 | return -EPERM; | 1765 | return -EPERM; |
1727 | case -EACCES: | 1766 | case -EACCES: |
1728 | if (clp->cl_machine_cred == NULL) | ||
1729 | return -EACCES; | ||
1730 | /* Handle case where the user hasn't set up machine creds */ | ||
1731 | nfs4_clear_machine_cred(clp); | ||
1732 | case -NFS4ERR_DELAY: | 1767 | case -NFS4ERR_DELAY: |
1733 | case -ETIMEDOUT: | 1768 | case -ETIMEDOUT: |
1734 | case -EAGAIN: | 1769 | case -EAGAIN: |
@@ -1823,31 +1858,18 @@ int nfs4_discover_server_trunking(struct nfs_client *clp, | |||
1823 | { | 1858 | { |
1824 | const struct nfs4_state_recovery_ops *ops = | 1859 | const struct nfs4_state_recovery_ops *ops = |
1825 | clp->cl_mvops->reboot_recovery_ops; | 1860 | clp->cl_mvops->reboot_recovery_ops; |
1826 | rpc_authflavor_t *flavors, flav, save; | ||
1827 | struct rpc_clnt *clnt; | 1861 | struct rpc_clnt *clnt; |
1828 | struct rpc_cred *cred; | 1862 | struct rpc_cred *cred; |
1829 | int i, len, status; | 1863 | int i, status; |
1830 | 1864 | ||
1831 | dprintk("NFS: %s: testing '%s'\n", __func__, clp->cl_hostname); | 1865 | dprintk("NFS: %s: testing '%s'\n", __func__, clp->cl_hostname); |
1832 | 1866 | ||
1833 | len = NFS_MAX_SECFLAVORS; | ||
1834 | flavors = kcalloc(len, sizeof(*flavors), GFP_KERNEL); | ||
1835 | if (flavors == NULL) { | ||
1836 | status = -ENOMEM; | ||
1837 | goto out; | ||
1838 | } | ||
1839 | len = rpcauth_list_flavors(flavors, len); | ||
1840 | if (len < 0) { | ||
1841 | status = len; | ||
1842 | goto out_free; | ||
1843 | } | ||
1844 | clnt = clp->cl_rpcclient; | 1867 | clnt = clp->cl_rpcclient; |
1845 | save = clnt->cl_auth->au_flavor; | ||
1846 | i = 0; | 1868 | i = 0; |
1847 | 1869 | ||
1848 | mutex_lock(&nfs_clid_init_mutex); | 1870 | mutex_lock(&nfs_clid_init_mutex); |
1849 | status = -ENOENT; | ||
1850 | again: | 1871 | again: |
1872 | status = -ENOENT; | ||
1851 | cred = ops->get_clid_cred(clp); | 1873 | cred = ops->get_clid_cred(clp); |
1852 | if (cred == NULL) | 1874 | if (cred == NULL) |
1853 | goto out_unlock; | 1875 | goto out_unlock; |
@@ -1857,12 +1879,6 @@ again: | |||
1857 | switch (status) { | 1879 | switch (status) { |
1858 | case 0: | 1880 | case 0: |
1859 | break; | 1881 | break; |
1860 | |||
1861 | case -EACCES: | ||
1862 | if (clp->cl_machine_cred == NULL) | ||
1863 | break; | ||
1864 | /* Handle case where the user hasn't set up machine creds */ | ||
1865 | nfs4_clear_machine_cred(clp); | ||
1866 | case -NFS4ERR_DELAY: | 1882 | case -NFS4ERR_DELAY: |
1867 | case -ETIMEDOUT: | 1883 | case -ETIMEDOUT: |
1868 | case -EAGAIN: | 1884 | case -EAGAIN: |
@@ -1871,17 +1887,12 @@ again: | |||
1871 | dprintk("NFS: %s after status %d, retrying\n", | 1887 | dprintk("NFS: %s after status %d, retrying\n", |
1872 | __func__, status); | 1888 | __func__, status); |
1873 | goto again; | 1889 | goto again; |
1874 | 1890 | case -EACCES: | |
1891 | if (i++) | ||
1892 | break; | ||
1875 | case -NFS4ERR_CLID_INUSE: | 1893 | case -NFS4ERR_CLID_INUSE: |
1876 | case -NFS4ERR_WRONGSEC: | 1894 | case -NFS4ERR_WRONGSEC: |
1877 | status = -EPERM; | 1895 | clnt = rpc_clone_client_set_auth(clnt, RPC_AUTH_UNIX); |
1878 | if (i >= len) | ||
1879 | break; | ||
1880 | |||
1881 | flav = flavors[i++]; | ||
1882 | if (flav == save) | ||
1883 | flav = flavors[i++]; | ||
1884 | clnt = rpc_clone_client_set_auth(clnt, flav); | ||
1885 | if (IS_ERR(clnt)) { | 1896 | if (IS_ERR(clnt)) { |
1886 | status = PTR_ERR(clnt); | 1897 | status = PTR_ERR(clnt); |
1887 | break; | 1898 | break; |
@@ -1903,13 +1914,15 @@ again: | |||
1903 | case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery | 1914 | case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery |
1904 | * in nfs4_exchange_id */ | 1915 | * in nfs4_exchange_id */ |
1905 | status = -EKEYEXPIRED; | 1916 | status = -EKEYEXPIRED; |
1917 | break; | ||
1918 | default: | ||
1919 | pr_warn("NFS: %s unhandled error %d. Exiting with error EIO\n", | ||
1920 | __func__, status); | ||
1921 | status = -EIO; | ||
1906 | } | 1922 | } |
1907 | 1923 | ||
1908 | out_unlock: | 1924 | out_unlock: |
1909 | mutex_unlock(&nfs_clid_init_mutex); | 1925 | mutex_unlock(&nfs_clid_init_mutex); |
1910 | out_free: | ||
1911 | kfree(flavors); | ||
1912 | out: | ||
1913 | dprintk("NFS: %s: status = %d\n", __func__, status); | 1926 | dprintk("NFS: %s: status = %d\n", __func__, status); |
1914 | return status; | 1927 | return status; |
1915 | } | 1928 | } |
diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c index 569b166cc050..a5e1a3026d48 100644 --- a/fs/nfs/nfs4super.c +++ b/fs/nfs/nfs4super.c | |||
@@ -252,6 +252,8 @@ struct dentry *nfs4_try_mount(int flags, const char *dev_name, | |||
252 | 252 | ||
253 | dfprintk(MOUNT, "--> nfs4_try_mount()\n"); | 253 | dfprintk(MOUNT, "--> nfs4_try_mount()\n"); |
254 | 254 | ||
255 | if (data->auth_flavors[0] == RPC_AUTH_MAXFLAVOR) | ||
256 | data->auth_flavors[0] = RPC_AUTH_UNIX; | ||
255 | export_path = data->nfs_server.export_path; | 257 | export_path = data->nfs_server.export_path; |
256 | data->nfs_server.export_path = "/"; | 258 | data->nfs_server.export_path = "/"; |
257 | root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, mount_info, | 259 | root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, mount_info, |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index e3edda554ac7..3c79c5878c6d 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -530,14 +530,10 @@ static int nfs4_stat_to_errno(int); | |||
530 | decode_setclientid_maxsz) | 530 | decode_setclientid_maxsz) |
531 | #define NFS4_enc_setclientid_confirm_sz \ | 531 | #define NFS4_enc_setclientid_confirm_sz \ |
532 | (compound_encode_hdr_maxsz + \ | 532 | (compound_encode_hdr_maxsz + \ |
533 | encode_setclientid_confirm_maxsz + \ | 533 | encode_setclientid_confirm_maxsz) |
534 | encode_putrootfh_maxsz + \ | ||
535 | encode_fsinfo_maxsz) | ||
536 | #define NFS4_dec_setclientid_confirm_sz \ | 534 | #define NFS4_dec_setclientid_confirm_sz \ |
537 | (compound_decode_hdr_maxsz + \ | 535 | (compound_decode_hdr_maxsz + \ |
538 | decode_setclientid_confirm_maxsz + \ | 536 | decode_setclientid_confirm_maxsz) |
539 | decode_putrootfh_maxsz + \ | ||
540 | decode_fsinfo_maxsz) | ||
541 | #define NFS4_enc_lock_sz (compound_encode_hdr_maxsz + \ | 537 | #define NFS4_enc_lock_sz (compound_encode_hdr_maxsz + \ |
542 | encode_sequence_maxsz + \ | 538 | encode_sequence_maxsz + \ |
543 | encode_putfh_maxsz + \ | 539 | encode_putfh_maxsz + \ |
@@ -1058,8 +1054,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const | |||
1058 | if (iap->ia_valid & ATTR_ATIME_SET) { | 1054 | if (iap->ia_valid & ATTR_ATIME_SET) { |
1059 | bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET; | 1055 | bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET; |
1060 | *p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME); | 1056 | *p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME); |
1061 | *p++ = cpu_to_be32(0); | 1057 | p = xdr_encode_hyper(p, (s64)iap->ia_atime.tv_sec); |
1062 | *p++ = cpu_to_be32(iap->ia_atime.tv_sec); | ||
1063 | *p++ = cpu_to_be32(iap->ia_atime.tv_nsec); | 1058 | *p++ = cpu_to_be32(iap->ia_atime.tv_nsec); |
1064 | } | 1059 | } |
1065 | else if (iap->ia_valid & ATTR_ATIME) { | 1060 | else if (iap->ia_valid & ATTR_ATIME) { |
@@ -1069,8 +1064,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const | |||
1069 | if (iap->ia_valid & ATTR_MTIME_SET) { | 1064 | if (iap->ia_valid & ATTR_MTIME_SET) { |
1070 | bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET; | 1065 | bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET; |
1071 | *p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME); | 1066 | *p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME); |
1072 | *p++ = cpu_to_be32(0); | 1067 | p = xdr_encode_hyper(p, (s64)iap->ia_mtime.tv_sec); |
1073 | *p++ = cpu_to_be32(iap->ia_mtime.tv_sec); | ||
1074 | *p++ = cpu_to_be32(iap->ia_mtime.tv_nsec); | 1068 | *p++ = cpu_to_be32(iap->ia_mtime.tv_nsec); |
1075 | } | 1069 | } |
1076 | else if (iap->ia_valid & ATTR_MTIME) { | 1070 | else if (iap->ia_valid & ATTR_MTIME) { |
@@ -1366,33 +1360,28 @@ static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_opena | |||
1366 | 1360 | ||
1367 | static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_openargs *arg) | 1361 | static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_openargs *arg) |
1368 | { | 1362 | { |
1363 | struct iattr dummy; | ||
1369 | __be32 *p; | 1364 | __be32 *p; |
1370 | struct nfs_client *clp; | ||
1371 | 1365 | ||
1372 | p = reserve_space(xdr, 4); | 1366 | p = reserve_space(xdr, 4); |
1373 | switch(arg->open_flags & O_EXCL) { | 1367 | switch(arg->createmode) { |
1374 | case 0: | 1368 | case NFS4_CREATE_UNCHECKED: |
1375 | *p = cpu_to_be32(NFS4_CREATE_UNCHECKED); | 1369 | *p = cpu_to_be32(NFS4_CREATE_UNCHECKED); |
1376 | encode_attrs(xdr, arg->u.attrs, arg->server); | 1370 | encode_attrs(xdr, arg->u.attrs, arg->server); |
1377 | break; | 1371 | break; |
1378 | default: | 1372 | case NFS4_CREATE_GUARDED: |
1379 | clp = arg->server->nfs_client; | 1373 | *p = cpu_to_be32(NFS4_CREATE_GUARDED); |
1380 | if (clp->cl_mvops->minor_version > 0) { | 1374 | encode_attrs(xdr, arg->u.attrs, arg->server); |
1381 | if (nfs4_has_persistent_session(clp)) { | 1375 | break; |
1382 | *p = cpu_to_be32(NFS4_CREATE_GUARDED); | 1376 | case NFS4_CREATE_EXCLUSIVE: |
1383 | encode_attrs(xdr, arg->u.attrs, arg->server); | 1377 | *p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE); |
1384 | } else { | 1378 | encode_nfs4_verifier(xdr, &arg->u.verifier); |
1385 | struct iattr dummy; | 1379 | break; |
1386 | 1380 | case NFS4_CREATE_EXCLUSIVE4_1: | |
1387 | *p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE4_1); | 1381 | *p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE4_1); |
1388 | encode_nfs4_verifier(xdr, &arg->u.verifier); | 1382 | encode_nfs4_verifier(xdr, &arg->u.verifier); |
1389 | dummy.ia_valid = 0; | 1383 | dummy.ia_valid = 0; |
1390 | encode_attrs(xdr, &dummy, arg->server); | 1384 | encode_attrs(xdr, &dummy, arg->server); |
1391 | } | ||
1392 | } else { | ||
1393 | *p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE); | ||
1394 | encode_nfs4_verifier(xdr, &arg->u.verifier); | ||
1395 | } | ||
1396 | } | 1385 | } |
1397 | } | 1386 | } |
1398 | 1387 | ||
@@ -1459,6 +1448,23 @@ static inline void encode_claim_delegate_cur(struct xdr_stream *xdr, const struc | |||
1459 | encode_string(xdr, name->len, name->name); | 1448 | encode_string(xdr, name->len, name->name); |
1460 | } | 1449 | } |
1461 | 1450 | ||
1451 | static inline void encode_claim_fh(struct xdr_stream *xdr) | ||
1452 | { | ||
1453 | __be32 *p; | ||
1454 | |||
1455 | p = reserve_space(xdr, 4); | ||
1456 | *p = cpu_to_be32(NFS4_OPEN_CLAIM_FH); | ||
1457 | } | ||
1458 | |||
1459 | static inline void encode_claim_delegate_cur_fh(struct xdr_stream *xdr, const nfs4_stateid *stateid) | ||
1460 | { | ||
1461 | __be32 *p; | ||
1462 | |||
1463 | p = reserve_space(xdr, 4); | ||
1464 | *p = cpu_to_be32(NFS4_OPEN_CLAIM_DELEG_CUR_FH); | ||
1465 | encode_nfs4_stateid(xdr, stateid); | ||
1466 | } | ||
1467 | |||
1462 | static void encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg, struct compound_hdr *hdr) | 1468 | static void encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg, struct compound_hdr *hdr) |
1463 | { | 1469 | { |
1464 | encode_op_hdr(xdr, OP_OPEN, decode_open_maxsz, hdr); | 1470 | encode_op_hdr(xdr, OP_OPEN, decode_open_maxsz, hdr); |
@@ -1474,6 +1480,12 @@ static void encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg, | |||
1474 | case NFS4_OPEN_CLAIM_DELEGATE_CUR: | 1480 | case NFS4_OPEN_CLAIM_DELEGATE_CUR: |
1475 | encode_claim_delegate_cur(xdr, arg->name, &arg->u.delegation); | 1481 | encode_claim_delegate_cur(xdr, arg->name, &arg->u.delegation); |
1476 | break; | 1482 | break; |
1483 | case NFS4_OPEN_CLAIM_FH: | ||
1484 | encode_claim_fh(xdr); | ||
1485 | break; | ||
1486 | case NFS4_OPEN_CLAIM_DELEG_CUR_FH: | ||
1487 | encode_claim_delegate_cur_fh(xdr, &arg->u.delegation); | ||
1488 | break; | ||
1477 | default: | 1489 | default: |
1478 | BUG(); | 1490 | BUG(); |
1479 | } | 1491 | } |
@@ -1506,35 +1518,12 @@ static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr) | |||
1506 | encode_op_hdr(xdr, OP_PUTROOTFH, decode_putrootfh_maxsz, hdr); | 1518 | encode_op_hdr(xdr, OP_PUTROOTFH, decode_putrootfh_maxsz, hdr); |
1507 | } | 1519 | } |
1508 | 1520 | ||
1509 | static void encode_open_stateid(struct xdr_stream *xdr, | ||
1510 | const struct nfs_open_context *ctx, | ||
1511 | const struct nfs_lock_context *l_ctx, | ||
1512 | fmode_t fmode, | ||
1513 | int zero_seqid) | ||
1514 | { | ||
1515 | nfs4_stateid stateid; | ||
1516 | |||
1517 | if (ctx->state != NULL) { | ||
1518 | const struct nfs_lockowner *lockowner = NULL; | ||
1519 | |||
1520 | if (l_ctx != NULL) | ||
1521 | lockowner = &l_ctx->lockowner; | ||
1522 | nfs4_select_rw_stateid(&stateid, ctx->state, | ||
1523 | fmode, lockowner); | ||
1524 | if (zero_seqid) | ||
1525 | stateid.seqid = 0; | ||
1526 | encode_nfs4_stateid(xdr, &stateid); | ||
1527 | } else | ||
1528 | encode_nfs4_stateid(xdr, &zero_stateid); | ||
1529 | } | ||
1530 | |||
1531 | static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, struct compound_hdr *hdr) | 1521 | static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, struct compound_hdr *hdr) |
1532 | { | 1522 | { |
1533 | __be32 *p; | 1523 | __be32 *p; |
1534 | 1524 | ||
1535 | encode_op_hdr(xdr, OP_READ, decode_read_maxsz, hdr); | 1525 | encode_op_hdr(xdr, OP_READ, decode_read_maxsz, hdr); |
1536 | encode_open_stateid(xdr, args->context, args->lock_context, | 1526 | encode_nfs4_stateid(xdr, &args->stateid); |
1537 | FMODE_READ, hdr->minorversion); | ||
1538 | 1527 | ||
1539 | p = reserve_space(xdr, 12); | 1528 | p = reserve_space(xdr, 12); |
1540 | p = xdr_encode_hyper(p, args->offset); | 1529 | p = xdr_encode_hyper(p, args->offset); |
@@ -1670,8 +1659,7 @@ static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *arg | |||
1670 | __be32 *p; | 1659 | __be32 *p; |
1671 | 1660 | ||
1672 | encode_op_hdr(xdr, OP_WRITE, decode_write_maxsz, hdr); | 1661 | encode_op_hdr(xdr, OP_WRITE, decode_write_maxsz, hdr); |
1673 | encode_open_stateid(xdr, args->context, args->lock_context, | 1662 | encode_nfs4_stateid(xdr, &args->stateid); |
1674 | FMODE_WRITE, hdr->minorversion); | ||
1675 | 1663 | ||
1676 | p = reserve_space(xdr, 16); | 1664 | p = reserve_space(xdr, 16); |
1677 | p = xdr_encode_hyper(p, args->offset); | 1665 | p = xdr_encode_hyper(p, args->offset); |
@@ -2609,12 +2597,9 @@ static void nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, | |||
2609 | struct compound_hdr hdr = { | 2597 | struct compound_hdr hdr = { |
2610 | .nops = 0, | 2598 | .nops = 0, |
2611 | }; | 2599 | }; |
2612 | const u32 lease_bitmap[3] = { FATTR4_WORD0_LEASE_TIME }; | ||
2613 | 2600 | ||
2614 | encode_compound_hdr(xdr, req, &hdr); | 2601 | encode_compound_hdr(xdr, req, &hdr); |
2615 | encode_setclientid_confirm(xdr, arg, &hdr); | 2602 | encode_setclientid_confirm(xdr, arg, &hdr); |
2616 | encode_putrootfh(xdr, &hdr); | ||
2617 | encode_fsinfo(xdr, lease_bitmap, &hdr); | ||
2618 | encode_nops(&hdr); | 2603 | encode_nops(&hdr); |
2619 | } | 2604 | } |
2620 | 2605 | ||
@@ -3497,8 +3482,11 @@ static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path) | |||
3497 | if (n == 0) | 3482 | if (n == 0) |
3498 | goto root_path; | 3483 | goto root_path; |
3499 | dprintk("pathname4: "); | 3484 | dprintk("pathname4: "); |
3500 | path->ncomponents = 0; | 3485 | if (n > NFS4_PATHNAME_MAXCOMPONENTS) { |
3501 | while (path->ncomponents < n) { | 3486 | dprintk("cannot parse %d components in path\n", n); |
3487 | goto out_eio; | ||
3488 | } | ||
3489 | for (path->ncomponents = 0; path->ncomponents < n; path->ncomponents++) { | ||
3502 | struct nfs4_string *component = &path->components[path->ncomponents]; | 3490 | struct nfs4_string *component = &path->components[path->ncomponents]; |
3503 | status = decode_opaque_inline(xdr, &component->len, &component->data); | 3491 | status = decode_opaque_inline(xdr, &component->len, &component->data); |
3504 | if (unlikely(status != 0)) | 3492 | if (unlikely(status != 0)) |
@@ -3507,12 +3495,6 @@ static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path) | |||
3507 | pr_cont("%s%.*s ", | 3495 | pr_cont("%s%.*s ", |
3508 | (path->ncomponents != n ? "/ " : ""), | 3496 | (path->ncomponents != n ? "/ " : ""), |
3509 | component->len, component->data); | 3497 | component->len, component->data); |
3510 | if (path->ncomponents < NFS4_PATHNAME_MAXCOMPONENTS) | ||
3511 | path->ncomponents++; | ||
3512 | else { | ||
3513 | dprintk("cannot parse %d components in path\n", n); | ||
3514 | goto out_eio; | ||
3515 | } | ||
3516 | } | 3498 | } |
3517 | out: | 3499 | out: |
3518 | return status; | 3500 | return status; |
@@ -3557,27 +3539,23 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st | |||
3557 | n = be32_to_cpup(p); | 3539 | n = be32_to_cpup(p); |
3558 | if (n <= 0) | 3540 | if (n <= 0) |
3559 | goto out_eio; | 3541 | goto out_eio; |
3560 | res->nlocations = 0; | 3542 | for (res->nlocations = 0; res->nlocations < n; res->nlocations++) { |
3561 | while (res->nlocations < n) { | ||
3562 | u32 m; | 3543 | u32 m; |
3563 | struct nfs4_fs_location *loc = &res->locations[res->nlocations]; | 3544 | struct nfs4_fs_location *loc; |
3564 | 3545 | ||
3546 | if (res->nlocations == NFS4_FS_LOCATIONS_MAXENTRIES) | ||
3547 | break; | ||
3548 | loc = &res->locations[res->nlocations]; | ||
3565 | p = xdr_inline_decode(xdr, 4); | 3549 | p = xdr_inline_decode(xdr, 4); |
3566 | if (unlikely(!p)) | 3550 | if (unlikely(!p)) |
3567 | goto out_overflow; | 3551 | goto out_overflow; |
3568 | m = be32_to_cpup(p); | 3552 | m = be32_to_cpup(p); |
3569 | 3553 | ||
3570 | loc->nservers = 0; | ||
3571 | dprintk("%s: servers:\n", __func__); | 3554 | dprintk("%s: servers:\n", __func__); |
3572 | while (loc->nservers < m) { | 3555 | for (loc->nservers = 0; loc->nservers < m; loc->nservers++) { |
3573 | struct nfs4_string *server = &loc->servers[loc->nservers]; | 3556 | struct nfs4_string *server; |
3574 | status = decode_opaque_inline(xdr, &server->len, &server->data); | 3557 | |
3575 | if (unlikely(status != 0)) | 3558 | if (loc->nservers == NFS4_FS_LOCATION_MAXSERVERS) { |
3576 | goto out_eio; | ||
3577 | dprintk("%s ", server->data); | ||
3578 | if (loc->nservers < NFS4_FS_LOCATION_MAXSERVERS) | ||
3579 | loc->nservers++; | ||
3580 | else { | ||
3581 | unsigned int i; | 3559 | unsigned int i; |
3582 | dprintk("%s: using first %u of %u servers " | 3560 | dprintk("%s: using first %u of %u servers " |
3583 | "returned for location %u\n", | 3561 | "returned for location %u\n", |
@@ -3591,13 +3569,17 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st | |||
3591 | if (unlikely(status != 0)) | 3569 | if (unlikely(status != 0)) |
3592 | goto out_eio; | 3570 | goto out_eio; |
3593 | } | 3571 | } |
3572 | break; | ||
3594 | } | 3573 | } |
3574 | server = &loc->servers[loc->nservers]; | ||
3575 | status = decode_opaque_inline(xdr, &server->len, &server->data); | ||
3576 | if (unlikely(status != 0)) | ||
3577 | goto out_eio; | ||
3578 | dprintk("%s ", server->data); | ||
3595 | } | 3579 | } |
3596 | status = decode_pathname(xdr, &loc->rootpath); | 3580 | status = decode_pathname(xdr, &loc->rootpath); |
3597 | if (unlikely(status != 0)) | 3581 | if (unlikely(status != 0)) |
3598 | goto out_eio; | 3582 | goto out_eio; |
3599 | if (res->nlocations < NFS4_FS_LOCATIONS_MAXENTRIES) | ||
3600 | res->nlocations++; | ||
3601 | } | 3583 | } |
3602 | if (res->nlocations != 0) | 3584 | if (res->nlocations != 0) |
3603 | status = NFS_ATTR_FATTR_V4_LOCATIONS; | 3585 | status = NFS_ATTR_FATTR_V4_LOCATIONS; |
@@ -5209,27 +5191,30 @@ static int decode_delegreturn(struct xdr_stream *xdr) | |||
5209 | return decode_op_hdr(xdr, OP_DELEGRETURN); | 5191 | return decode_op_hdr(xdr, OP_DELEGRETURN); |
5210 | } | 5192 | } |
5211 | 5193 | ||
5212 | static int decode_secinfo_gss(struct xdr_stream *xdr, struct nfs4_secinfo_flavor *flavor) | 5194 | static int decode_secinfo_gss(struct xdr_stream *xdr, |
5195 | struct nfs4_secinfo4 *flavor) | ||
5213 | { | 5196 | { |
5197 | u32 oid_len; | ||
5214 | __be32 *p; | 5198 | __be32 *p; |
5215 | 5199 | ||
5216 | p = xdr_inline_decode(xdr, 4); | 5200 | p = xdr_inline_decode(xdr, 4); |
5217 | if (unlikely(!p)) | 5201 | if (unlikely(!p)) |
5218 | goto out_overflow; | 5202 | goto out_overflow; |
5219 | flavor->gss.sec_oid4.len = be32_to_cpup(p); | 5203 | oid_len = be32_to_cpup(p); |
5220 | if (flavor->gss.sec_oid4.len > GSS_OID_MAX_LEN) | 5204 | if (oid_len > GSS_OID_MAX_LEN) |
5221 | goto out_err; | 5205 | goto out_err; |
5222 | 5206 | ||
5223 | p = xdr_inline_decode(xdr, flavor->gss.sec_oid4.len); | 5207 | p = xdr_inline_decode(xdr, oid_len); |
5224 | if (unlikely(!p)) | 5208 | if (unlikely(!p)) |
5225 | goto out_overflow; | 5209 | goto out_overflow; |
5226 | memcpy(flavor->gss.sec_oid4.data, p, flavor->gss.sec_oid4.len); | 5210 | memcpy(flavor->flavor_info.oid.data, p, oid_len); |
5211 | flavor->flavor_info.oid.len = oid_len; | ||
5227 | 5212 | ||
5228 | p = xdr_inline_decode(xdr, 8); | 5213 | p = xdr_inline_decode(xdr, 8); |
5229 | if (unlikely(!p)) | 5214 | if (unlikely(!p)) |
5230 | goto out_overflow; | 5215 | goto out_overflow; |
5231 | flavor->gss.qop4 = be32_to_cpup(p++); | 5216 | flavor->flavor_info.qop = be32_to_cpup(p++); |
5232 | flavor->gss.service = be32_to_cpup(p); | 5217 | flavor->flavor_info.service = be32_to_cpup(p); |
5233 | 5218 | ||
5234 | return 0; | 5219 | return 0; |
5235 | 5220 | ||
@@ -5242,10 +5227,10 @@ out_err: | |||
5242 | 5227 | ||
5243 | static int decode_secinfo_common(struct xdr_stream *xdr, struct nfs4_secinfo_res *res) | 5228 | static int decode_secinfo_common(struct xdr_stream *xdr, struct nfs4_secinfo_res *res) |
5244 | { | 5229 | { |
5245 | struct nfs4_secinfo_flavor *sec_flavor; | 5230 | struct nfs4_secinfo4 *sec_flavor; |
5231 | unsigned int i, num_flavors; | ||
5246 | int status; | 5232 | int status; |
5247 | __be32 *p; | 5233 | __be32 *p; |
5248 | int i, num_flavors; | ||
5249 | 5234 | ||
5250 | p = xdr_inline_decode(xdr, 4); | 5235 | p = xdr_inline_decode(xdr, 4); |
5251 | if (unlikely(!p)) | 5236 | if (unlikely(!p)) |
@@ -6648,8 +6633,7 @@ static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, | |||
6648 | * Decode SETCLIENTID_CONFIRM response | 6633 | * Decode SETCLIENTID_CONFIRM response |
6649 | */ | 6634 | */ |
6650 | static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, | 6635 | static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, |
6651 | struct xdr_stream *xdr, | 6636 | struct xdr_stream *xdr) |
6652 | struct nfs_fsinfo *fsinfo) | ||
6653 | { | 6637 | { |
6654 | struct compound_hdr hdr; | 6638 | struct compound_hdr hdr; |
6655 | int status; | 6639 | int status; |
@@ -6657,10 +6641,6 @@ static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, | |||
6657 | status = decode_compound_hdr(xdr, &hdr); | 6641 | status = decode_compound_hdr(xdr, &hdr); |
6658 | if (!status) | 6642 | if (!status) |
6659 | status = decode_setclientid_confirm(xdr); | 6643 | status = decode_setclientid_confirm(xdr); |
6660 | if (!status) | ||
6661 | status = decode_putrootfh(xdr); | ||
6662 | if (!status) | ||
6663 | status = decode_fsinfo(xdr, fsinfo); | ||
6664 | return status; | 6644 | return status; |
6665 | } | 6645 | } |
6666 | 6646 | ||
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index e56e846e9d2d..29cfb7ade121 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
@@ -84,6 +84,55 @@ nfs_page_free(struct nfs_page *p) | |||
84 | kmem_cache_free(nfs_page_cachep, p); | 84 | kmem_cache_free(nfs_page_cachep, p); |
85 | } | 85 | } |
86 | 86 | ||
87 | static void | ||
88 | nfs_iocounter_inc(struct nfs_io_counter *c) | ||
89 | { | ||
90 | atomic_inc(&c->io_count); | ||
91 | } | ||
92 | |||
93 | static void | ||
94 | nfs_iocounter_dec(struct nfs_io_counter *c) | ||
95 | { | ||
96 | if (atomic_dec_and_test(&c->io_count)) { | ||
97 | clear_bit(NFS_IO_INPROGRESS, &c->flags); | ||
98 | smp_mb__after_clear_bit(); | ||
99 | wake_up_bit(&c->flags, NFS_IO_INPROGRESS); | ||
100 | } | ||
101 | } | ||
102 | |||
103 | static int | ||
104 | __nfs_iocounter_wait(struct nfs_io_counter *c) | ||
105 | { | ||
106 | wait_queue_head_t *wq = bit_waitqueue(&c->flags, NFS_IO_INPROGRESS); | ||
107 | DEFINE_WAIT_BIT(q, &c->flags, NFS_IO_INPROGRESS); | ||
108 | int ret = 0; | ||
109 | |||
110 | do { | ||
111 | prepare_to_wait(wq, &q.wait, TASK_KILLABLE); | ||
112 | set_bit(NFS_IO_INPROGRESS, &c->flags); | ||
113 | if (atomic_read(&c->io_count) == 0) | ||
114 | break; | ||
115 | ret = nfs_wait_bit_killable(&c->flags); | ||
116 | } while (atomic_read(&c->io_count) != 0); | ||
117 | finish_wait(wq, &q.wait); | ||
118 | return ret; | ||
119 | } | ||
120 | |||
121 | /** | ||
122 | * nfs_iocounter_wait - wait for i/o to complete | ||
123 | * @c: nfs_io_counter to use | ||
124 | * | ||
125 | * returns -ERESTARTSYS if interrupted by a fatal signal. | ||
126 | * Otherwise returns 0 once the io_count hits 0. | ||
127 | */ | ||
128 | int | ||
129 | nfs_iocounter_wait(struct nfs_io_counter *c) | ||
130 | { | ||
131 | if (atomic_read(&c->io_count) == 0) | ||
132 | return 0; | ||
133 | return __nfs_iocounter_wait(c); | ||
134 | } | ||
135 | |||
87 | /** | 136 | /** |
88 | * nfs_create_request - Create an NFS read/write request. | 137 | * nfs_create_request - Create an NFS read/write request. |
89 | * @ctx: open context to use | 138 | * @ctx: open context to use |
@@ -104,6 +153,8 @@ nfs_create_request(struct nfs_open_context *ctx, struct inode *inode, | |||
104 | struct nfs_page *req; | 153 | struct nfs_page *req; |
105 | struct nfs_lock_context *l_ctx; | 154 | struct nfs_lock_context *l_ctx; |
106 | 155 | ||
156 | if (test_bit(NFS_CONTEXT_BAD, &ctx->flags)) | ||
157 | return ERR_PTR(-EBADF); | ||
107 | /* try to allocate the request struct */ | 158 | /* try to allocate the request struct */ |
108 | req = nfs_page_alloc(); | 159 | req = nfs_page_alloc(); |
109 | if (req == NULL) | 160 | if (req == NULL) |
@@ -116,6 +167,7 @@ nfs_create_request(struct nfs_open_context *ctx, struct inode *inode, | |||
116 | return ERR_CAST(l_ctx); | 167 | return ERR_CAST(l_ctx); |
117 | } | 168 | } |
118 | req->wb_lock_context = l_ctx; | 169 | req->wb_lock_context = l_ctx; |
170 | nfs_iocounter_inc(&l_ctx->io_count); | ||
119 | 171 | ||
120 | /* Initialize the request struct. Initially, we assume a | 172 | /* Initialize the request struct. Initially, we assume a |
121 | * long write-back delay. This will be adjusted in | 173 | * long write-back delay. This will be adjusted in |
@@ -175,6 +227,7 @@ static void nfs_clear_request(struct nfs_page *req) | |||
175 | req->wb_page = NULL; | 227 | req->wb_page = NULL; |
176 | } | 228 | } |
177 | if (l_ctx != NULL) { | 229 | if (l_ctx != NULL) { |
230 | nfs_iocounter_dec(&l_ctx->io_count); | ||
178 | nfs_put_lock_context(l_ctx); | 231 | nfs_put_lock_context(l_ctx); |
179 | req->wb_lock_context = NULL; | 232 | req->wb_lock_context = NULL; |
180 | } | 233 | } |
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 4bdffe0ba025..c5bd758e5637 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
@@ -718,6 +718,8 @@ pnfs_choose_layoutget_stateid(nfs4_stateid *dst, struct pnfs_layout_hdr *lo, | |||
718 | spin_lock(&lo->plh_inode->i_lock); | 718 | spin_lock(&lo->plh_inode->i_lock); |
719 | if (pnfs_layoutgets_blocked(lo, 1)) { | 719 | if (pnfs_layoutgets_blocked(lo, 1)) { |
720 | status = -EAGAIN; | 720 | status = -EAGAIN; |
721 | } else if (!nfs4_valid_open_stateid(open_state)) { | ||
722 | status = -EBADF; | ||
721 | } else if (list_empty(&lo->plh_segs)) { | 723 | } else if (list_empty(&lo->plh_segs)) { |
722 | int seq; | 724 | int seq; |
723 | 725 | ||
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index a5e5d9899d56..70a26c651f09 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
@@ -514,6 +514,8 @@ void nfs_read_prepare(struct rpc_task *task, void *calldata) | |||
514 | { | 514 | { |
515 | struct nfs_read_data *data = calldata; | 515 | struct nfs_read_data *data = calldata; |
516 | NFS_PROTO(data->header->inode)->read_rpc_prepare(task, data); | 516 | NFS_PROTO(data->header->inode)->read_rpc_prepare(task, data); |
517 | if (unlikely(test_bit(NFS_CONTEXT_BAD, &data->args.context->flags))) | ||
518 | rpc_exit(task, -EIO); | ||
517 | } | 519 | } |
518 | 520 | ||
519 | static const struct rpc_call_ops nfs_read_common_ops = { | 521 | static const struct rpc_call_ops nfs_read_common_ops = { |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 2f8a29db0f1b..eb494f6a4c6b 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -920,7 +920,7 @@ static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(void) | |||
920 | data->mount_server.port = NFS_UNSPEC_PORT; | 920 | data->mount_server.port = NFS_UNSPEC_PORT; |
921 | data->nfs_server.port = NFS_UNSPEC_PORT; | 921 | data->nfs_server.port = NFS_UNSPEC_PORT; |
922 | data->nfs_server.protocol = XPRT_TRANSPORT_TCP; | 922 | data->nfs_server.protocol = XPRT_TRANSPORT_TCP; |
923 | data->auth_flavors[0] = RPC_AUTH_UNIX; | 923 | data->auth_flavors[0] = RPC_AUTH_MAXFLAVOR; |
924 | data->auth_flavor_len = 1; | 924 | data->auth_flavor_len = 1; |
925 | data->minorversion = 0; | 925 | data->minorversion = 0; |
926 | data->need_mount = true; | 926 | data->need_mount = true; |
@@ -1608,49 +1608,57 @@ out_security_failure: | |||
1608 | } | 1608 | } |
1609 | 1609 | ||
1610 | /* | 1610 | /* |
1611 | * Match the requested auth flavors with the list returned by | 1611 | * Select a security flavor for this mount. The selected flavor |
1612 | * the server. Returns zero and sets the mount's authentication | 1612 | * is planted in args->auth_flavors[0]. |
1613 | * flavor on success; returns -EACCES if server does not support | ||
1614 | * the requested flavor. | ||
1615 | */ | 1613 | */ |
1616 | static int nfs_walk_authlist(struct nfs_parsed_mount_data *args, | 1614 | static void nfs_select_flavor(struct nfs_parsed_mount_data *args, |
1617 | struct nfs_mount_request *request) | 1615 | struct nfs_mount_request *request) |
1618 | { | 1616 | { |
1619 | unsigned int i, j, server_authlist_len = *(request->auth_flav_len); | 1617 | unsigned int i, count = *(request->auth_flav_len); |
1618 | rpc_authflavor_t flavor; | ||
1619 | |||
1620 | if (args->auth_flavors[0] != RPC_AUTH_MAXFLAVOR) | ||
1621 | goto out; | ||
1622 | |||
1623 | /* | ||
1624 | * The NFSv2 MNT operation does not return a flavor list. | ||
1625 | */ | ||
1626 | if (args->mount_server.version != NFS_MNT3_VERSION) | ||
1627 | goto out_default; | ||
1620 | 1628 | ||
1621 | /* | 1629 | /* |
1622 | * Certain releases of Linux's mountd return an empty | 1630 | * Certain releases of Linux's mountd return an empty |
1623 | * flavor list. To prevent behavioral regression with | 1631 | * flavor list in some cases. |
1624 | * these servers (ie. rejecting mounts that used to | ||
1625 | * succeed), revert to pre-2.6.32 behavior (no checking) | ||
1626 | * if the returned flavor list is empty. | ||
1627 | */ | 1632 | */ |
1628 | if (server_authlist_len == 0) | 1633 | if (count == 0) |
1629 | return 0; | 1634 | goto out_default; |
1630 | 1635 | ||
1631 | /* | 1636 | /* |
1632 | * We avoid sophisticated negotiating here, as there are | ||
1633 | * plenty of cases where we can get it wrong, providing | ||
1634 | * either too little or too much security. | ||
1635 | * | ||
1636 | * RFC 2623, section 2.7 suggests we SHOULD prefer the | 1637 | * RFC 2623, section 2.7 suggests we SHOULD prefer the |
1637 | * flavor listed first. However, some servers list | 1638 | * flavor listed first. However, some servers list |
1638 | * AUTH_NULL first. Our caller plants AUTH_SYS, the | 1639 | * AUTH_NULL first. Avoid ever choosing AUTH_NULL. |
1639 | * preferred default, in args->auth_flavors[0] if user | ||
1640 | * didn't specify sec= mount option. | ||
1641 | */ | 1640 | */ |
1642 | for (i = 0; i < args->auth_flavor_len; i++) | 1641 | for (i = 0; i < count; i++) { |
1643 | for (j = 0; j < server_authlist_len; j++) | 1642 | struct rpcsec_gss_info info; |
1644 | if (args->auth_flavors[i] == request->auth_flavs[j]) { | 1643 | |
1645 | dfprintk(MOUNT, "NFS: using auth flavor %d\n", | 1644 | flavor = request->auth_flavs[i]; |
1646 | request->auth_flavs[j]); | 1645 | switch (flavor) { |
1647 | args->auth_flavors[0] = request->auth_flavs[j]; | 1646 | case RPC_AUTH_UNIX: |
1648 | return 0; | 1647 | goto out_set; |
1649 | } | 1648 | case RPC_AUTH_NULL: |
1649 | continue; | ||
1650 | default: | ||
1651 | if (rpcauth_get_gssinfo(flavor, &info) == 0) | ||
1652 | goto out_set; | ||
1653 | } | ||
1654 | } | ||
1650 | 1655 | ||
1651 | dfprintk(MOUNT, "NFS: server does not support requested auth flavor\n"); | 1656 | out_default: |
1652 | nfs_umount(request); | 1657 | flavor = RPC_AUTH_UNIX; |
1653 | return -EACCES; | 1658 | out_set: |
1659 | args->auth_flavors[0] = flavor; | ||
1660 | out: | ||
1661 | dfprintk(MOUNT, "NFS: using auth flavor %d\n", args->auth_flavors[0]); | ||
1654 | } | 1662 | } |
1655 | 1663 | ||
1656 | /* | 1664 | /* |
@@ -1713,12 +1721,8 @@ static int nfs_request_mount(struct nfs_parsed_mount_data *args, | |||
1713 | return status; | 1721 | return status; |
1714 | } | 1722 | } |
1715 | 1723 | ||
1716 | /* | 1724 | nfs_select_flavor(args, &request); |
1717 | * MNTv1 (NFSv2) does not support auth flavor negotiation. | 1725 | return 0; |
1718 | */ | ||
1719 | if (args->mount_server.version != NFS_MNT3_VERSION) | ||
1720 | return 0; | ||
1721 | return nfs_walk_authlist(args, &request); | ||
1722 | } | 1726 | } |
1723 | 1727 | ||
1724 | struct dentry *nfs_try_mount(int flags, const char *dev_name, | 1728 | struct dentry *nfs_try_mount(int flags, const char *dev_name, |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index c483cc50b82e..a2c7c28049d5 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -1251,6 +1251,8 @@ void nfs_write_prepare(struct rpc_task *task, void *calldata) | |||
1251 | { | 1251 | { |
1252 | struct nfs_write_data *data = calldata; | 1252 | struct nfs_write_data *data = calldata; |
1253 | NFS_PROTO(data->header->inode)->write_rpc_prepare(task, data); | 1253 | NFS_PROTO(data->header->inode)->write_rpc_prepare(task, data); |
1254 | if (unlikely(test_bit(NFS_CONTEXT_BAD, &data->args.context->flags))) | ||
1255 | rpc_exit(task, -EIO); | ||
1254 | } | 1256 | } |
1255 | 1257 | ||
1256 | void nfs_commit_prepare(struct rpc_task *task, void *calldata) | 1258 | void nfs_commit_prepare(struct rpc_task *task, void *calldata) |
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index a2720071f282..2502951714b1 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -3138,10 +3138,9 @@ nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ | |||
3138 | 3138 | ||
3139 | static __be32 | 3139 | static __be32 |
3140 | nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp, | 3140 | nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp, |
3141 | __be32 nfserr,struct svc_export *exp) | 3141 | __be32 nfserr, struct svc_export *exp) |
3142 | { | 3142 | { |
3143 | int i = 0; | 3143 | u32 i, nflavs; |
3144 | u32 nflavs; | ||
3145 | struct exp_flavor_info *flavs; | 3144 | struct exp_flavor_info *flavs; |
3146 | struct exp_flavor_info def_flavs[2]; | 3145 | struct exp_flavor_info def_flavs[2]; |
3147 | __be32 *p; | 3146 | __be32 *p; |
@@ -3172,30 +3171,29 @@ nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp, | |||
3172 | WRITE32(nflavs); | 3171 | WRITE32(nflavs); |
3173 | ADJUST_ARGS(); | 3172 | ADJUST_ARGS(); |
3174 | for (i = 0; i < nflavs; i++) { | 3173 | for (i = 0; i < nflavs; i++) { |
3175 | u32 flav = flavs[i].pseudoflavor; | 3174 | struct rpcsec_gss_info info; |
3176 | struct gss_api_mech *gm = gss_mech_get_by_pseudoflavor(flav); | ||
3177 | 3175 | ||
3178 | if (gm) { | 3176 | if (rpcauth_get_gssinfo(flavs[i].pseudoflavor, &info) == 0) { |
3179 | RESERVE_SPACE(4); | 3177 | RESERVE_SPACE(4); |
3180 | WRITE32(RPC_AUTH_GSS); | 3178 | WRITE32(RPC_AUTH_GSS); |
3181 | ADJUST_ARGS(); | 3179 | ADJUST_ARGS(); |
3182 | RESERVE_SPACE(4 + gm->gm_oid.len); | 3180 | RESERVE_SPACE(4 + info.oid.len); |
3183 | WRITE32(gm->gm_oid.len); | 3181 | WRITE32(info.oid.len); |
3184 | WRITEMEM(gm->gm_oid.data, gm->gm_oid.len); | 3182 | WRITEMEM(info.oid.data, info.oid.len); |
3185 | ADJUST_ARGS(); | 3183 | ADJUST_ARGS(); |
3186 | RESERVE_SPACE(4); | 3184 | RESERVE_SPACE(4); |
3187 | WRITE32(0); /* qop */ | 3185 | WRITE32(info.qop); |
3188 | ADJUST_ARGS(); | 3186 | ADJUST_ARGS(); |
3189 | RESERVE_SPACE(4); | 3187 | RESERVE_SPACE(4); |
3190 | WRITE32(gss_pseudoflavor_to_service(gm, flav)); | 3188 | WRITE32(info.service); |
3191 | ADJUST_ARGS(); | 3189 | ADJUST_ARGS(); |
3192 | gss_mech_put(gm); | ||
3193 | } else { | 3190 | } else { |
3194 | RESERVE_SPACE(4); | 3191 | RESERVE_SPACE(4); |
3195 | WRITE32(flav); | 3192 | WRITE32(flavs[i].pseudoflavor); |
3196 | ADJUST_ARGS(); | 3193 | ADJUST_ARGS(); |
3197 | } | 3194 | } |
3198 | } | 3195 | } |
3196 | |||
3199 | out: | 3197 | out: |
3200 | if (exp) | 3198 | if (exp) |
3201 | exp_put(exp); | 3199 | exp_put(exp); |
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 1cc25682b20b..fc01d5cb4cf1 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h | |||
@@ -59,11 +59,18 @@ struct nfs_lockowner { | |||
59 | pid_t l_pid; | 59 | pid_t l_pid; |
60 | }; | 60 | }; |
61 | 61 | ||
62 | #define NFS_IO_INPROGRESS 0 | ||
63 | struct nfs_io_counter { | ||
64 | unsigned long flags; | ||
65 | atomic_t io_count; | ||
66 | }; | ||
67 | |||
62 | struct nfs_lock_context { | 68 | struct nfs_lock_context { |
63 | atomic_t count; | 69 | atomic_t count; |
64 | struct list_head list; | 70 | struct list_head list; |
65 | struct nfs_open_context *open_context; | 71 | struct nfs_open_context *open_context; |
66 | struct nfs_lockowner lockowner; | 72 | struct nfs_lockowner lockowner; |
73 | struct nfs_io_counter io_count; | ||
67 | }; | 74 | }; |
68 | 75 | ||
69 | struct nfs4_state; | 76 | struct nfs4_state; |
@@ -77,6 +84,7 @@ struct nfs_open_context { | |||
77 | unsigned long flags; | 84 | unsigned long flags; |
78 | #define NFS_CONTEXT_ERROR_WRITE (0) | 85 | #define NFS_CONTEXT_ERROR_WRITE (0) |
79 | #define NFS_CONTEXT_RESEND_WRITES (1) | 86 | #define NFS_CONTEXT_RESEND_WRITES (1) |
87 | #define NFS_CONTEXT_BAD (2) | ||
80 | int error; | 88 | int error; |
81 | 89 | ||
82 | struct list_head list; | 90 | struct list_head list; |
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 6c6ed153a9b4..3b7fa2abecca 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h | |||
@@ -40,6 +40,7 @@ struct nfs_client { | |||
40 | #define NFS_CS_NORESVPORT 0 /* - use ephemeral src port */ | 40 | #define NFS_CS_NORESVPORT 0 /* - use ephemeral src port */ |
41 | #define NFS_CS_DISCRTRY 1 /* - disconnect on RPC retry */ | 41 | #define NFS_CS_DISCRTRY 1 /* - disconnect on RPC retry */ |
42 | #define NFS_CS_MIGRATION 2 /* - transparent state migr */ | 42 | #define NFS_CS_MIGRATION 2 /* - transparent state migr */ |
43 | #define NFS_CS_INFINITE_SLOTS 3 /* - don't limit TCP slots */ | ||
43 | struct sockaddr_storage cl_addr; /* server identifier */ | 44 | struct sockaddr_storage cl_addr; /* server identifier */ |
44 | size_t cl_addrlen; | 45 | size_t cl_addrlen; |
45 | char * cl_hostname; /* hostname of server */ | 46 | char * cl_hostname; /* hostname of server */ |
@@ -197,5 +198,7 @@ struct nfs_server { | |||
197 | #define NFS_CAP_MTIME (1U << 13) | 198 | #define NFS_CAP_MTIME (1U << 13) |
198 | #define NFS_CAP_POSIX_LOCK (1U << 14) | 199 | #define NFS_CAP_POSIX_LOCK (1U << 14) |
199 | #define NFS_CAP_UIDGID_NOMAP (1U << 15) | 200 | #define NFS_CAP_UIDGID_NOMAP (1U << 15) |
201 | #define NFS_CAP_STATEID_NFSV41 (1U << 16) | ||
202 | #define NFS_CAP_ATOMIC_OPEN_V1 (1U << 17) | ||
200 | 203 | ||
201 | #endif | 204 | #endif |
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 4b993d358dad..766c5bc9d441 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h | |||
@@ -14,9 +14,6 @@ | |||
14 | #define NFS_DEF_FILE_IO_SIZE (4096U) | 14 | #define NFS_DEF_FILE_IO_SIZE (4096U) |
15 | #define NFS_MIN_FILE_IO_SIZE (1024U) | 15 | #define NFS_MIN_FILE_IO_SIZE (1024U) |
16 | 16 | ||
17 | /* Forward declaration for NFS v3 */ | ||
18 | struct nfs4_secinfo_flavors; | ||
19 | |||
20 | struct nfs4_string { | 17 | struct nfs4_string { |
21 | unsigned int len; | 18 | unsigned int len; |
22 | char *data; | 19 | char *data; |
@@ -349,6 +346,7 @@ struct nfs_openargs { | |||
349 | const u32 * bitmask; | 346 | const u32 * bitmask; |
350 | const u32 * open_bitmap; | 347 | const u32 * open_bitmap; |
351 | __u32 claim; | 348 | __u32 claim; |
349 | enum createmode4 createmode; | ||
352 | }; | 350 | }; |
353 | 351 | ||
354 | struct nfs_openres { | 352 | struct nfs_openres { |
@@ -486,6 +484,7 @@ struct nfs_readargs { | |||
486 | struct nfs_fh * fh; | 484 | struct nfs_fh * fh; |
487 | struct nfs_open_context *context; | 485 | struct nfs_open_context *context; |
488 | struct nfs_lock_context *lock_context; | 486 | struct nfs_lock_context *lock_context; |
487 | nfs4_stateid stateid; | ||
489 | __u64 offset; | 488 | __u64 offset; |
490 | __u32 count; | 489 | __u32 count; |
491 | unsigned int pgbase; | 490 | unsigned int pgbase; |
@@ -507,6 +506,7 @@ struct nfs_writeargs { | |||
507 | struct nfs_fh * fh; | 506 | struct nfs_fh * fh; |
508 | struct nfs_open_context *context; | 507 | struct nfs_open_context *context; |
509 | struct nfs_lock_context *lock_context; | 508 | struct nfs_lock_context *lock_context; |
509 | nfs4_stateid stateid; | ||
510 | __u64 offset; | 510 | __u64 offset; |
511 | __u32 count; | 511 | __u32 count; |
512 | enum nfs3_stable_how stable; | 512 | enum nfs3_stable_how stable; |
@@ -1050,25 +1050,14 @@ struct nfs4_fs_locations_res { | |||
1050 | struct nfs4_fs_locations *fs_locations; | 1050 | struct nfs4_fs_locations *fs_locations; |
1051 | }; | 1051 | }; |
1052 | 1052 | ||
1053 | struct nfs4_secinfo_oid { | 1053 | struct nfs4_secinfo4 { |
1054 | unsigned int len; | 1054 | u32 flavor; |
1055 | char data[GSS_OID_MAX_LEN]; | 1055 | struct rpcsec_gss_info flavor_info; |
1056 | }; | ||
1057 | |||
1058 | struct nfs4_secinfo_gss { | ||
1059 | struct nfs4_secinfo_oid sec_oid4; | ||
1060 | unsigned int qop4; | ||
1061 | unsigned int service; | ||
1062 | }; | ||
1063 | |||
1064 | struct nfs4_secinfo_flavor { | ||
1065 | unsigned int flavor; | ||
1066 | struct nfs4_secinfo_gss gss; | ||
1067 | }; | 1056 | }; |
1068 | 1057 | ||
1069 | struct nfs4_secinfo_flavors { | 1058 | struct nfs4_secinfo_flavors { |
1070 | unsigned int num_flavors; | 1059 | unsigned int num_flavors; |
1071 | struct nfs4_secinfo_flavor flavors[0]; | 1060 | struct nfs4_secinfo4 flavors[0]; |
1072 | }; | 1061 | }; |
1073 | 1062 | ||
1074 | struct nfs4_secinfo_arg { | 1063 | struct nfs4_secinfo_arg { |
diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h index 58fda1c3c783..0dd00f4f6810 100644 --- a/include/linux/sunrpc/auth.h +++ b/include/linux/sunrpc/auth.h | |||
@@ -22,6 +22,8 @@ | |||
22 | /* size of the nodename buffer */ | 22 | /* size of the nodename buffer */ |
23 | #define UNX_MAXNODENAME 32 | 23 | #define UNX_MAXNODENAME 32 |
24 | 24 | ||
25 | struct rpcsec_gss_info; | ||
26 | |||
25 | /* Work around the lack of a VFS credential */ | 27 | /* Work around the lack of a VFS credential */ |
26 | struct auth_cred { | 28 | struct auth_cred { |
27 | kuid_t uid; | 29 | kuid_t uid; |
@@ -103,6 +105,9 @@ struct rpc_authops { | |||
103 | int (*pipes_create)(struct rpc_auth *); | 105 | int (*pipes_create)(struct rpc_auth *); |
104 | void (*pipes_destroy)(struct rpc_auth *); | 106 | void (*pipes_destroy)(struct rpc_auth *); |
105 | int (*list_pseudoflavors)(rpc_authflavor_t *, int); | 107 | int (*list_pseudoflavors)(rpc_authflavor_t *, int); |
108 | rpc_authflavor_t (*info2flavor)(struct rpcsec_gss_info *); | ||
109 | int (*flavor2info)(rpc_authflavor_t, | ||
110 | struct rpcsec_gss_info *); | ||
106 | }; | 111 | }; |
107 | 112 | ||
108 | struct rpc_credops { | 113 | struct rpc_credops { |
@@ -137,6 +142,10 @@ int rpcauth_register(const struct rpc_authops *); | |||
137 | int rpcauth_unregister(const struct rpc_authops *); | 142 | int rpcauth_unregister(const struct rpc_authops *); |
138 | struct rpc_auth * rpcauth_create(rpc_authflavor_t, struct rpc_clnt *); | 143 | struct rpc_auth * rpcauth_create(rpc_authflavor_t, struct rpc_clnt *); |
139 | void rpcauth_release(struct rpc_auth *); | 144 | void rpcauth_release(struct rpc_auth *); |
145 | rpc_authflavor_t rpcauth_get_pseudoflavor(rpc_authflavor_t, | ||
146 | struct rpcsec_gss_info *); | ||
147 | int rpcauth_get_gssinfo(rpc_authflavor_t, | ||
148 | struct rpcsec_gss_info *); | ||
140 | int rpcauth_list_flavors(rpc_authflavor_t *, int); | 149 | int rpcauth_list_flavors(rpc_authflavor_t *, int); |
141 | struct rpc_cred * rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *, int); | 150 | struct rpc_cred * rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *, int); |
142 | void rpcauth_init_cred(struct rpc_cred *, const struct auth_cred *, struct rpc_auth *, const struct rpc_credops *); | 151 | void rpcauth_init_cred(struct rpc_cred *, const struct auth_cred *, struct rpc_auth *, const struct rpc_credops *); |
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 2cf4ffaa3cd4..e7d492ce7c18 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h | |||
@@ -124,6 +124,7 @@ struct rpc_create_args { | |||
124 | #define RPC_CLNT_CREATE_NOPING (1UL << 4) | 124 | #define RPC_CLNT_CREATE_NOPING (1UL << 4) |
125 | #define RPC_CLNT_CREATE_DISCRTRY (1UL << 5) | 125 | #define RPC_CLNT_CREATE_DISCRTRY (1UL << 5) |
126 | #define RPC_CLNT_CREATE_QUIET (1UL << 6) | 126 | #define RPC_CLNT_CREATE_QUIET (1UL << 6) |
127 | #define RPC_CLNT_CREATE_INFINITE_SLOTS (1UL << 7) | ||
127 | 128 | ||
128 | struct rpc_clnt *rpc_create(struct rpc_create_args *args); | 129 | struct rpc_clnt *rpc_create(struct rpc_create_args *args); |
129 | struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *, | 130 | struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *, |
diff --git a/include/linux/sunrpc/gss_api.h b/include/linux/sunrpc/gss_api.h index a19e2547ae6a..f32b7a47e13f 100644 --- a/include/linux/sunrpc/gss_api.h +++ b/include/linux/sunrpc/gss_api.h | |||
@@ -25,10 +25,21 @@ struct gss_ctx { | |||
25 | 25 | ||
26 | #define GSS_C_NO_BUFFER ((struct xdr_netobj) 0) | 26 | #define GSS_C_NO_BUFFER ((struct xdr_netobj) 0) |
27 | #define GSS_C_NO_CONTEXT ((struct gss_ctx *) 0) | 27 | #define GSS_C_NO_CONTEXT ((struct gss_ctx *) 0) |
28 | #define GSS_C_NULL_OID ((struct xdr_netobj) 0) | 28 | #define GSS_C_QOP_DEFAULT (0) |
29 | 29 | ||
30 | /*XXX arbitrary length - is this set somewhere? */ | 30 | /*XXX arbitrary length - is this set somewhere? */ |
31 | #define GSS_OID_MAX_LEN 32 | 31 | #define GSS_OID_MAX_LEN 32 |
32 | struct rpcsec_gss_oid { | ||
33 | unsigned int len; | ||
34 | u8 data[GSS_OID_MAX_LEN]; | ||
35 | }; | ||
36 | |||
37 | /* From RFC 3530 */ | ||
38 | struct rpcsec_gss_info { | ||
39 | struct rpcsec_gss_oid oid; | ||
40 | u32 qop; | ||
41 | u32 service; | ||
42 | }; | ||
32 | 43 | ||
33 | /* gss-api prototypes; note that these are somewhat simplified versions of | 44 | /* gss-api prototypes; note that these are somewhat simplified versions of |
34 | * the prototypes specified in RFC 2744. */ | 45 | * the prototypes specified in RFC 2744. */ |
@@ -58,12 +69,14 @@ u32 gss_unwrap( | |||
58 | u32 gss_delete_sec_context( | 69 | u32 gss_delete_sec_context( |
59 | struct gss_ctx **ctx_id); | 70 | struct gss_ctx **ctx_id); |
60 | 71 | ||
61 | u32 gss_svc_to_pseudoflavor(struct gss_api_mech *, u32 service); | 72 | rpc_authflavor_t gss_svc_to_pseudoflavor(struct gss_api_mech *, u32 qop, |
73 | u32 service); | ||
62 | u32 gss_pseudoflavor_to_service(struct gss_api_mech *, u32 pseudoflavor); | 74 | u32 gss_pseudoflavor_to_service(struct gss_api_mech *, u32 pseudoflavor); |
63 | char *gss_service_to_auth_domain_name(struct gss_api_mech *, u32 service); | 75 | char *gss_service_to_auth_domain_name(struct gss_api_mech *, u32 service); |
64 | 76 | ||
65 | struct pf_desc { | 77 | struct pf_desc { |
66 | u32 pseudoflavor; | 78 | u32 pseudoflavor; |
79 | u32 qop; | ||
67 | u32 service; | 80 | u32 service; |
68 | char *name; | 81 | char *name; |
69 | char *auth_domain_name; | 82 | char *auth_domain_name; |
@@ -76,7 +89,7 @@ struct pf_desc { | |||
76 | struct gss_api_mech { | 89 | struct gss_api_mech { |
77 | struct list_head gm_list; | 90 | struct list_head gm_list; |
78 | struct module *gm_owner; | 91 | struct module *gm_owner; |
79 | struct xdr_netobj gm_oid; | 92 | struct rpcsec_gss_oid gm_oid; |
80 | char *gm_name; | 93 | char *gm_name; |
81 | const struct gss_api_ops *gm_ops; | 94 | const struct gss_api_ops *gm_ops; |
82 | /* pseudoflavors supported by this mechanism: */ | 95 | /* pseudoflavors supported by this mechanism: */ |
@@ -117,9 +130,11 @@ struct gss_api_ops { | |||
117 | int gss_mech_register(struct gss_api_mech *); | 130 | int gss_mech_register(struct gss_api_mech *); |
118 | void gss_mech_unregister(struct gss_api_mech *); | 131 | void gss_mech_unregister(struct gss_api_mech *); |
119 | 132 | ||
120 | /* returns a mechanism descriptor given an OID, and increments the mechanism's | 133 | /* Given a GSS security tuple, look up a pseudoflavor */ |
121 | * reference count. */ | 134 | rpc_authflavor_t gss_mech_info2flavor(struct rpcsec_gss_info *); |
122 | struct gss_api_mech * gss_mech_get_by_OID(struct xdr_netobj *); | 135 | |
136 | /* Given a pseudoflavor, look up a GSS security tuple */ | ||
137 | int gss_mech_flavor2info(rpc_authflavor_t, struct rpcsec_gss_info *); | ||
123 | 138 | ||
124 | /* Returns a reference to a mechanism, given a name like "krb5" etc. */ | 139 | /* Returns a reference to a mechanism, given a name like "krb5" etc. */ |
125 | struct gss_api_mech *gss_mech_get_by_name(const char *); | 140 | struct gss_api_mech *gss_mech_get_by_name(const char *); |
@@ -130,9 +145,6 @@ struct gss_api_mech *gss_mech_get_by_pseudoflavor(u32); | |||
130 | /* Fill in an array with a list of supported pseudoflavors */ | 145 | /* Fill in an array with a list of supported pseudoflavors */ |
131 | int gss_mech_list_pseudoflavors(rpc_authflavor_t *, int); | 146 | int gss_mech_list_pseudoflavors(rpc_authflavor_t *, int); |
132 | 147 | ||
133 | /* Just increments the mechanism's reference count and returns its input: */ | ||
134 | struct gss_api_mech * gss_mech_get(struct gss_api_mech *); | ||
135 | |||
136 | /* For every successful gss_mech_get or gss_mech_get_by_* call there must be a | 148 | /* For every successful gss_mech_get or gss_mech_get_by_* call there must be a |
137 | * corresponding call to gss_mech_put. */ | 149 | * corresponding call to gss_mech_put. */ |
138 | void gss_mech_put(struct gss_api_mech *); | 150 | void gss_mech_put(struct gss_api_mech *); |
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 30834be03011..ff5392421cb2 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h | |||
@@ -255,6 +255,8 @@ static inline int bc_prealloc(struct rpc_rqst *req) | |||
255 | } | 255 | } |
256 | #endif /* CONFIG_SUNRPC_BACKCHANNEL */ | 256 | #endif /* CONFIG_SUNRPC_BACKCHANNEL */ |
257 | 257 | ||
258 | #define XPRT_CREATE_INFINITE_SLOTS (1U) | ||
259 | |||
258 | struct xprt_create { | 260 | struct xprt_create { |
259 | int ident; /* XPRT_TRANSPORT identifier */ | 261 | int ident; /* XPRT_TRANSPORT identifier */ |
260 | struct net * net; | 262 | struct net * net; |
@@ -263,6 +265,7 @@ struct xprt_create { | |||
263 | size_t addrlen; | 265 | size_t addrlen; |
264 | const char *servername; | 266 | const char *servername; |
265 | struct svc_xprt *bc_xprt; /* NFSv4.1 backchannel */ | 267 | struct svc_xprt *bc_xprt; /* NFSv4.1 backchannel */ |
268 | unsigned int flags; | ||
266 | }; | 269 | }; |
267 | 270 | ||
268 | struct xprt_class { | 271 | struct xprt_class { |
@@ -279,6 +282,7 @@ struct xprt_class { | |||
279 | struct rpc_xprt *xprt_create_transport(struct xprt_create *args); | 282 | struct rpc_xprt *xprt_create_transport(struct xprt_create *args); |
280 | void xprt_connect(struct rpc_task *task); | 283 | void xprt_connect(struct rpc_task *task); |
281 | void xprt_reserve(struct rpc_task *task); | 284 | void xprt_reserve(struct rpc_task *task); |
285 | void xprt_retry_reserve(struct rpc_task *task); | ||
282 | int xprt_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task); | 286 | int xprt_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task); |
283 | int xprt_reserve_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task); | 287 | int xprt_reserve_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task); |
284 | void xprt_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task); | 288 | void xprt_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task); |
@@ -334,6 +338,7 @@ int xs_swapper(struct rpc_xprt *xprt, int enable); | |||
334 | #define XPRT_CLOSING (6) | 338 | #define XPRT_CLOSING (6) |
335 | #define XPRT_CONNECTION_ABORT (7) | 339 | #define XPRT_CONNECTION_ABORT (7) |
336 | #define XPRT_CONNECTION_CLOSE (8) | 340 | #define XPRT_CONNECTION_CLOSE (8) |
341 | #define XPRT_CONGESTED (9) | ||
337 | 342 | ||
338 | static inline void xprt_set_connected(struct rpc_xprt *xprt) | 343 | static inline void xprt_set_connected(struct rpc_xprt *xprt) |
339 | { | 344 | { |
diff --git a/net/sunrpc/Kconfig b/net/sunrpc/Kconfig index 516fe2caac2c..241b54f30204 100644 --- a/net/sunrpc/Kconfig +++ b/net/sunrpc/Kconfig | |||
@@ -3,6 +3,7 @@ config SUNRPC | |||
3 | 3 | ||
4 | config SUNRPC_GSS | 4 | config SUNRPC_GSS |
5 | tristate | 5 | tristate |
6 | select OID_REGISTRY | ||
6 | 7 | ||
7 | config SUNRPC_BACKCHANNEL | 8 | config SUNRPC_BACKCHANNEL |
8 | bool | 9 | bool |
@@ -24,7 +25,6 @@ config SUNRPC_XPRT_RDMA | |||
24 | config SUNRPC_SWAP | 25 | config SUNRPC_SWAP |
25 | bool | 26 | bool |
26 | depends on SUNRPC | 27 | depends on SUNRPC |
27 | select NETVM | ||
28 | 28 | ||
29 | config RPCSEC_GSS_KRB5 | 29 | config RPCSEC_GSS_KRB5 |
30 | tristate "Secure RPC: Kerberos V mechanism" | 30 | tristate "Secure RPC: Kerberos V mechanism" |
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index f5294047df77..ed2fdd210c0b 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c | |||
@@ -82,7 +82,7 @@ MODULE_PARM_DESC(auth_hashtable_size, "RPC credential cache hashtable size"); | |||
82 | 82 | ||
83 | static u32 | 83 | static u32 |
84 | pseudoflavor_to_flavor(u32 flavor) { | 84 | pseudoflavor_to_flavor(u32 flavor) { |
85 | if (flavor >= RPC_AUTH_MAXFLAVOR) | 85 | if (flavor > RPC_AUTH_MAXFLAVOR) |
86 | return RPC_AUTH_GSS; | 86 | return RPC_AUTH_GSS; |
87 | return flavor; | 87 | return flavor; |
88 | } | 88 | } |
@@ -124,6 +124,79 @@ rpcauth_unregister(const struct rpc_authops *ops) | |||
124 | EXPORT_SYMBOL_GPL(rpcauth_unregister); | 124 | EXPORT_SYMBOL_GPL(rpcauth_unregister); |
125 | 125 | ||
126 | /** | 126 | /** |
127 | * rpcauth_get_pseudoflavor - check if security flavor is supported | ||
128 | * @flavor: a security flavor | ||
129 | * @info: a GSS mech OID, quality of protection, and service value | ||
130 | * | ||
131 | * Verifies that an appropriate kernel module is available or already loaded. | ||
132 | * Returns an equivalent pseudoflavor, or RPC_AUTH_MAXFLAVOR if "flavor" is | ||
133 | * not supported locally. | ||
134 | */ | ||
135 | rpc_authflavor_t | ||
136 | rpcauth_get_pseudoflavor(rpc_authflavor_t flavor, struct rpcsec_gss_info *info) | ||
137 | { | ||
138 | const struct rpc_authops *ops; | ||
139 | rpc_authflavor_t pseudoflavor; | ||
140 | |||
141 | ops = auth_flavors[flavor]; | ||
142 | if (ops == NULL) | ||
143 | request_module("rpc-auth-%u", flavor); | ||
144 | spin_lock(&rpc_authflavor_lock); | ||
145 | ops = auth_flavors[flavor]; | ||
146 | if (ops == NULL || !try_module_get(ops->owner)) { | ||
147 | spin_unlock(&rpc_authflavor_lock); | ||
148 | return RPC_AUTH_MAXFLAVOR; | ||
149 | } | ||
150 | spin_unlock(&rpc_authflavor_lock); | ||
151 | |||
152 | pseudoflavor = flavor; | ||
153 | if (ops->info2flavor != NULL) | ||
154 | pseudoflavor = ops->info2flavor(info); | ||
155 | |||
156 | module_put(ops->owner); | ||
157 | return pseudoflavor; | ||
158 | } | ||
159 | EXPORT_SYMBOL_GPL(rpcauth_get_pseudoflavor); | ||
160 | |||
161 | /** | ||
162 | * rpcauth_get_gssinfo - find GSS tuple matching a GSS pseudoflavor | ||
163 | * @pseudoflavor: GSS pseudoflavor to match | ||
164 | * @info: rpcsec_gss_info structure to fill in | ||
165 | * | ||
166 | * Returns zero and fills in "info" if pseudoflavor matches a | ||
167 | * supported mechanism. | ||
168 | */ | ||
169 | int | ||
170 | rpcauth_get_gssinfo(rpc_authflavor_t pseudoflavor, struct rpcsec_gss_info *info) | ||
171 | { | ||
172 | rpc_authflavor_t flavor = pseudoflavor_to_flavor(pseudoflavor); | ||
173 | const struct rpc_authops *ops; | ||
174 | int result; | ||
175 | |||
176 | if (flavor >= RPC_AUTH_MAXFLAVOR) | ||
177 | return -EINVAL; | ||
178 | |||
179 | ops = auth_flavors[flavor]; | ||
180 | if (ops == NULL) | ||
181 | request_module("rpc-auth-%u", flavor); | ||
182 | spin_lock(&rpc_authflavor_lock); | ||
183 | ops = auth_flavors[flavor]; | ||
184 | if (ops == NULL || !try_module_get(ops->owner)) { | ||
185 | spin_unlock(&rpc_authflavor_lock); | ||
186 | return -ENOENT; | ||
187 | } | ||
188 | spin_unlock(&rpc_authflavor_lock); | ||
189 | |||
190 | result = -ENOENT; | ||
191 | if (ops->flavor2info != NULL) | ||
192 | result = ops->flavor2info(pseudoflavor, info); | ||
193 | |||
194 | module_put(ops->owner); | ||
195 | return result; | ||
196 | } | ||
197 | EXPORT_SYMBOL_GPL(rpcauth_get_gssinfo); | ||
198 | |||
199 | /** | ||
127 | * rpcauth_list_flavors - discover registered flavors and pseudoflavors | 200 | * rpcauth_list_flavors - discover registered flavors and pseudoflavors |
128 | * @array: array to fill in | 201 | * @array: array to fill in |
129 | * @size: size of "array" | 202 | * @size: size of "array" |
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 5257d2982ba5..51415b07174e 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
@@ -1641,6 +1641,8 @@ static const struct rpc_authops authgss_ops = { | |||
1641 | .pipes_create = gss_pipes_dentries_create, | 1641 | .pipes_create = gss_pipes_dentries_create, |
1642 | .pipes_destroy = gss_pipes_dentries_destroy, | 1642 | .pipes_destroy = gss_pipes_dentries_destroy, |
1643 | .list_pseudoflavors = gss_mech_list_pseudoflavors, | 1643 | .list_pseudoflavors = gss_mech_list_pseudoflavors, |
1644 | .info2flavor = gss_mech_info2flavor, | ||
1645 | .flavor2info = gss_mech_flavor2info, | ||
1644 | }; | 1646 | }; |
1645 | 1647 | ||
1646 | static const struct rpc_credops gss_credops = { | 1648 | static const struct rpc_credops gss_credops = { |
@@ -1733,6 +1735,7 @@ static void __exit exit_rpcsec_gss(void) | |||
1733 | rcu_barrier(); /* Wait for completion of call_rcu()'s */ | 1735 | rcu_barrier(); /* Wait for completion of call_rcu()'s */ |
1734 | } | 1736 | } |
1735 | 1737 | ||
1738 | MODULE_ALIAS("rpc-auth-6"); | ||
1736 | MODULE_LICENSE("GPL"); | 1739 | MODULE_LICENSE("GPL"); |
1737 | module_param_named(expired_cred_retry_delay, | 1740 | module_param_named(expired_cred_retry_delay, |
1738 | gss_expired_cred_retry_delay, | 1741 | gss_expired_cred_retry_delay, |
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c index d3611f11a8df..33255ff889c0 100644 --- a/net/sunrpc/auth_gss/gss_krb5_mech.c +++ b/net/sunrpc/auth_gss/gss_krb5_mech.c | |||
@@ -729,16 +729,19 @@ static const struct gss_api_ops gss_kerberos_ops = { | |||
729 | static struct pf_desc gss_kerberos_pfs[] = { | 729 | static struct pf_desc gss_kerberos_pfs[] = { |
730 | [0] = { | 730 | [0] = { |
731 | .pseudoflavor = RPC_AUTH_GSS_KRB5, | 731 | .pseudoflavor = RPC_AUTH_GSS_KRB5, |
732 | .qop = GSS_C_QOP_DEFAULT, | ||
732 | .service = RPC_GSS_SVC_NONE, | 733 | .service = RPC_GSS_SVC_NONE, |
733 | .name = "krb5", | 734 | .name = "krb5", |
734 | }, | 735 | }, |
735 | [1] = { | 736 | [1] = { |
736 | .pseudoflavor = RPC_AUTH_GSS_KRB5I, | 737 | .pseudoflavor = RPC_AUTH_GSS_KRB5I, |
738 | .qop = GSS_C_QOP_DEFAULT, | ||
737 | .service = RPC_GSS_SVC_INTEGRITY, | 739 | .service = RPC_GSS_SVC_INTEGRITY, |
738 | .name = "krb5i", | 740 | .name = "krb5i", |
739 | }, | 741 | }, |
740 | [2] = { | 742 | [2] = { |
741 | .pseudoflavor = RPC_AUTH_GSS_KRB5P, | 743 | .pseudoflavor = RPC_AUTH_GSS_KRB5P, |
744 | .qop = GSS_C_QOP_DEFAULT, | ||
742 | .service = RPC_GSS_SVC_PRIVACY, | 745 | .service = RPC_GSS_SVC_PRIVACY, |
743 | .name = "krb5p", | 746 | .name = "krb5p", |
744 | }, | 747 | }, |
@@ -750,11 +753,12 @@ MODULE_ALIAS("rpc-auth-gss-krb5p"); | |||
750 | MODULE_ALIAS("rpc-auth-gss-390003"); | 753 | MODULE_ALIAS("rpc-auth-gss-390003"); |
751 | MODULE_ALIAS("rpc-auth-gss-390004"); | 754 | MODULE_ALIAS("rpc-auth-gss-390004"); |
752 | MODULE_ALIAS("rpc-auth-gss-390005"); | 755 | MODULE_ALIAS("rpc-auth-gss-390005"); |
756 | MODULE_ALIAS("rpc-auth-gss-1.2.840.113554.1.2.2"); | ||
753 | 757 | ||
754 | static struct gss_api_mech gss_kerberos_mech = { | 758 | static struct gss_api_mech gss_kerberos_mech = { |
755 | .gm_name = "krb5", | 759 | .gm_name = "krb5", |
756 | .gm_owner = THIS_MODULE, | 760 | .gm_owner = THIS_MODULE, |
757 | .gm_oid = {9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"}, | 761 | .gm_oid = { 9, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" }, |
758 | .gm_ops = &gss_kerberos_ops, | 762 | .gm_ops = &gss_kerberos_ops, |
759 | .gm_pf_num = ARRAY_SIZE(gss_kerberos_pfs), | 763 | .gm_pf_num = ARRAY_SIZE(gss_kerberos_pfs), |
760 | .gm_pfs = gss_kerberos_pfs, | 764 | .gm_pfs = gss_kerberos_pfs, |
diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c index f0f4eee63a35..79881d6e68a1 100644 --- a/net/sunrpc/auth_gss/gss_mech_switch.c +++ b/net/sunrpc/auth_gss/gss_mech_switch.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/types.h> | 36 | #include <linux/types.h> |
37 | #include <linux/slab.h> | 37 | #include <linux/slab.h> |
38 | #include <linux/module.h> | 38 | #include <linux/module.h> |
39 | #include <linux/oid_registry.h> | ||
39 | #include <linux/sunrpc/msg_prot.h> | 40 | #include <linux/sunrpc/msg_prot.h> |
40 | #include <linux/sunrpc/gss_asn1.h> | 41 | #include <linux/sunrpc/gss_asn1.h> |
41 | #include <linux/sunrpc/auth_gss.h> | 42 | #include <linux/sunrpc/auth_gss.h> |
@@ -102,8 +103,13 @@ out: | |||
102 | return status; | 103 | return status; |
103 | } | 104 | } |
104 | 105 | ||
105 | int | 106 | /** |
106 | gss_mech_register(struct gss_api_mech *gm) | 107 | * gss_mech_register - register a GSS mechanism |
108 | * @gm: GSS mechanism handle | ||
109 | * | ||
110 | * Returns zero if successful, or a negative errno. | ||
111 | */ | ||
112 | int gss_mech_register(struct gss_api_mech *gm) | ||
107 | { | 113 | { |
108 | int status; | 114 | int status; |
109 | 115 | ||
@@ -116,11 +122,14 @@ gss_mech_register(struct gss_api_mech *gm) | |||
116 | dprintk("RPC: registered gss mechanism %s\n", gm->gm_name); | 122 | dprintk("RPC: registered gss mechanism %s\n", gm->gm_name); |
117 | return 0; | 123 | return 0; |
118 | } | 124 | } |
119 | |||
120 | EXPORT_SYMBOL_GPL(gss_mech_register); | 125 | EXPORT_SYMBOL_GPL(gss_mech_register); |
121 | 126 | ||
122 | void | 127 | /** |
123 | gss_mech_unregister(struct gss_api_mech *gm) | 128 | * gss_mech_unregister - release a GSS mechanism |
129 | * @gm: GSS mechanism handle | ||
130 | * | ||
131 | */ | ||
132 | void gss_mech_unregister(struct gss_api_mech *gm) | ||
124 | { | 133 | { |
125 | spin_lock(®istered_mechs_lock); | 134 | spin_lock(®istered_mechs_lock); |
126 | list_del(&gm->gm_list); | 135 | list_del(&gm->gm_list); |
@@ -128,18 +137,14 @@ gss_mech_unregister(struct gss_api_mech *gm) | |||
128 | dprintk("RPC: unregistered gss mechanism %s\n", gm->gm_name); | 137 | dprintk("RPC: unregistered gss mechanism %s\n", gm->gm_name); |
129 | gss_mech_free(gm); | 138 | gss_mech_free(gm); |
130 | } | 139 | } |
131 | |||
132 | EXPORT_SYMBOL_GPL(gss_mech_unregister); | 140 | EXPORT_SYMBOL_GPL(gss_mech_unregister); |
133 | 141 | ||
134 | struct gss_api_mech * | 142 | static struct gss_api_mech *gss_mech_get(struct gss_api_mech *gm) |
135 | gss_mech_get(struct gss_api_mech *gm) | ||
136 | { | 143 | { |
137 | __module_get(gm->gm_owner); | 144 | __module_get(gm->gm_owner); |
138 | return gm; | 145 | return gm; |
139 | } | 146 | } |
140 | 147 | ||
141 | EXPORT_SYMBOL_GPL(gss_mech_get); | ||
142 | |||
143 | static struct gss_api_mech * | 148 | static struct gss_api_mech * |
144 | _gss_mech_get_by_name(const char *name) | 149 | _gss_mech_get_by_name(const char *name) |
145 | { | 150 | { |
@@ -169,12 +174,16 @@ struct gss_api_mech * gss_mech_get_by_name(const char *name) | |||
169 | } | 174 | } |
170 | return gm; | 175 | return gm; |
171 | } | 176 | } |
172 | EXPORT_SYMBOL_GPL(gss_mech_get_by_name); | ||
173 | 177 | ||
174 | struct gss_api_mech * | 178 | static struct gss_api_mech *gss_mech_get_by_OID(struct rpcsec_gss_oid *obj) |
175 | gss_mech_get_by_OID(struct xdr_netobj *obj) | ||
176 | { | 179 | { |
177 | struct gss_api_mech *pos, *gm = NULL; | 180 | struct gss_api_mech *pos, *gm = NULL; |
181 | char buf[32]; | ||
182 | |||
183 | if (sprint_oid(obj->data, obj->len, buf, sizeof(buf)) < 0) | ||
184 | return NULL; | ||
185 | dprintk("RPC: %s(%s)\n", __func__, buf); | ||
186 | request_module("rpc-auth-gss-%s", buf); | ||
178 | 187 | ||
179 | spin_lock(®istered_mechs_lock); | 188 | spin_lock(®istered_mechs_lock); |
180 | list_for_each_entry(pos, ®istered_mechs, gm_list) { | 189 | list_for_each_entry(pos, ®istered_mechs, gm_list) { |
@@ -188,11 +197,8 @@ gss_mech_get_by_OID(struct xdr_netobj *obj) | |||
188 | } | 197 | } |
189 | spin_unlock(®istered_mechs_lock); | 198 | spin_unlock(®istered_mechs_lock); |
190 | return gm; | 199 | return gm; |
191 | |||
192 | } | 200 | } |
193 | 201 | ||
194 | EXPORT_SYMBOL_GPL(gss_mech_get_by_OID); | ||
195 | |||
196 | static inline int | 202 | static inline int |
197 | mech_supports_pseudoflavor(struct gss_api_mech *gm, u32 pseudoflavor) | 203 | mech_supports_pseudoflavor(struct gss_api_mech *gm, u32 pseudoflavor) |
198 | { | 204 | { |
@@ -237,8 +243,6 @@ gss_mech_get_by_pseudoflavor(u32 pseudoflavor) | |||
237 | return gm; | 243 | return gm; |
238 | } | 244 | } |
239 | 245 | ||
240 | EXPORT_SYMBOL_GPL(gss_mech_get_by_pseudoflavor); | ||
241 | |||
242 | /** | 246 | /** |
243 | * gss_mech_list_pseudoflavors - Discover registered GSS pseudoflavors | 247 | * gss_mech_list_pseudoflavors - Discover registered GSS pseudoflavors |
244 | * @array: array to fill in | 248 | * @array: array to fill in |
@@ -268,19 +272,82 @@ int gss_mech_list_pseudoflavors(rpc_authflavor_t *array_ptr, int size) | |||
268 | return i; | 272 | return i; |
269 | } | 273 | } |
270 | 274 | ||
271 | u32 | 275 | /** |
272 | gss_svc_to_pseudoflavor(struct gss_api_mech *gm, u32 service) | 276 | * gss_svc_to_pseudoflavor - map a GSS service number to a pseudoflavor |
277 | * @gm: GSS mechanism handle | ||
278 | * @qop: GSS quality-of-protection value | ||
279 | * @service: GSS service value | ||
280 | * | ||
281 | * Returns a matching security flavor, or RPC_AUTH_MAXFLAVOR if none is found. | ||
282 | */ | ||
283 | rpc_authflavor_t gss_svc_to_pseudoflavor(struct gss_api_mech *gm, u32 qop, | ||
284 | u32 service) | ||
273 | { | 285 | { |
274 | int i; | 286 | int i; |
275 | 287 | ||
276 | for (i = 0; i < gm->gm_pf_num; i++) { | 288 | for (i = 0; i < gm->gm_pf_num; i++) { |
277 | if (gm->gm_pfs[i].service == service) { | 289 | if (gm->gm_pfs[i].qop == qop && |
290 | gm->gm_pfs[i].service == service) { | ||
278 | return gm->gm_pfs[i].pseudoflavor; | 291 | return gm->gm_pfs[i].pseudoflavor; |
279 | } | 292 | } |
280 | } | 293 | } |
281 | return RPC_AUTH_MAXFLAVOR; /* illegal value */ | 294 | return RPC_AUTH_MAXFLAVOR; |
295 | } | ||
296 | |||
297 | /** | ||
298 | * gss_mech_info2flavor - look up a pseudoflavor given a GSS tuple | ||
299 | * @info: a GSS mech OID, quality of protection, and service value | ||
300 | * | ||
301 | * Returns a matching pseudoflavor, or RPC_AUTH_MAXFLAVOR if the tuple is | ||
302 | * not supported. | ||
303 | */ | ||
304 | rpc_authflavor_t gss_mech_info2flavor(struct rpcsec_gss_info *info) | ||
305 | { | ||
306 | rpc_authflavor_t pseudoflavor; | ||
307 | struct gss_api_mech *gm; | ||
308 | |||
309 | gm = gss_mech_get_by_OID(&info->oid); | ||
310 | if (gm == NULL) | ||
311 | return RPC_AUTH_MAXFLAVOR; | ||
312 | |||
313 | pseudoflavor = gss_svc_to_pseudoflavor(gm, info->qop, info->service); | ||
314 | |||
315 | gss_mech_put(gm); | ||
316 | return pseudoflavor; | ||
317 | } | ||
318 | |||
319 | /** | ||
320 | * gss_mech_flavor2info - look up a GSS tuple for a given pseudoflavor | ||
321 | * @pseudoflavor: GSS pseudoflavor to match | ||
322 | * @info: rpcsec_gss_info structure to fill in | ||
323 | * | ||
324 | * Returns zero and fills in "info" if pseudoflavor matches a | ||
325 | * supported mechanism. Otherwise a negative errno is returned. | ||
326 | */ | ||
327 | int gss_mech_flavor2info(rpc_authflavor_t pseudoflavor, | ||
328 | struct rpcsec_gss_info *info) | ||
329 | { | ||
330 | struct gss_api_mech *gm; | ||
331 | int i; | ||
332 | |||
333 | gm = gss_mech_get_by_pseudoflavor(pseudoflavor); | ||
334 | if (gm == NULL) | ||
335 | return -ENOENT; | ||
336 | |||
337 | for (i = 0; i < gm->gm_pf_num; i++) { | ||
338 | if (gm->gm_pfs[i].pseudoflavor == pseudoflavor) { | ||
339 | memcpy(info->oid.data, gm->gm_oid.data, gm->gm_oid.len); | ||
340 | info->oid.len = gm->gm_oid.len; | ||
341 | info->qop = gm->gm_pfs[i].qop; | ||
342 | info->service = gm->gm_pfs[i].service; | ||
343 | gss_mech_put(gm); | ||
344 | return 0; | ||
345 | } | ||
346 | } | ||
347 | |||
348 | gss_mech_put(gm); | ||
349 | return -ENOENT; | ||
282 | } | 350 | } |
283 | EXPORT_SYMBOL_GPL(gss_svc_to_pseudoflavor); | ||
284 | 351 | ||
285 | u32 | 352 | u32 |
286 | gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor) | 353 | gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor) |
@@ -294,8 +361,6 @@ gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor) | |||
294 | return 0; | 361 | return 0; |
295 | } | 362 | } |
296 | 363 | ||
297 | EXPORT_SYMBOL_GPL(gss_pseudoflavor_to_service); | ||
298 | |||
299 | char * | 364 | char * |
300 | gss_service_to_auth_domain_name(struct gss_api_mech *gm, u32 service) | 365 | gss_service_to_auth_domain_name(struct gss_api_mech *gm, u32 service) |
301 | { | 366 | { |
@@ -308,8 +373,6 @@ gss_service_to_auth_domain_name(struct gss_api_mech *gm, u32 service) | |||
308 | return NULL; | 373 | return NULL; |
309 | } | 374 | } |
310 | 375 | ||
311 | EXPORT_SYMBOL_GPL(gss_service_to_auth_domain_name); | ||
312 | |||
313 | void | 376 | void |
314 | gss_mech_put(struct gss_api_mech * gm) | 377 | gss_mech_put(struct gss_api_mech * gm) |
315 | { | 378 | { |
@@ -317,8 +380,6 @@ gss_mech_put(struct gss_api_mech * gm) | |||
317 | module_put(gm->gm_owner); | 380 | module_put(gm->gm_owner); |
318 | } | 381 | } |
319 | 382 | ||
320 | EXPORT_SYMBOL_GPL(gss_mech_put); | ||
321 | |||
322 | /* The mech could probably be determined from the token instead, but it's just | 383 | /* The mech could probably be determined from the token instead, but it's just |
323 | * as easy for now to pass it in. */ | 384 | * as easy for now to pass it in. */ |
324 | int | 385 | int |
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 5ead60550895..c3ba570222dc 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c | |||
@@ -1220,7 +1220,9 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp) | |||
1220 | svcdata->rsci = rsci; | 1220 | svcdata->rsci = rsci; |
1221 | cache_get(&rsci->h); | 1221 | cache_get(&rsci->h); |
1222 | rqstp->rq_cred.cr_flavor = gss_svc_to_pseudoflavor( | 1222 | rqstp->rq_cred.cr_flavor = gss_svc_to_pseudoflavor( |
1223 | rsci->mechctx->mech_type, gc->gc_svc); | 1223 | rsci->mechctx->mech_type, |
1224 | GSS_C_QOP_DEFAULT, | ||
1225 | gc->gc_svc); | ||
1224 | ret = SVC_OK; | 1226 | ret = SVC_OK; |
1225 | goto out; | 1227 | goto out; |
1226 | } | 1228 | } |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index d5f35f15af98..d259fa966927 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
@@ -411,6 +411,8 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args) | |||
411 | }; | 411 | }; |
412 | char servername[48]; | 412 | char servername[48]; |
413 | 413 | ||
414 | if (args->flags & RPC_CLNT_CREATE_INFINITE_SLOTS) | ||
415 | xprtargs.flags |= XPRT_CREATE_INFINITE_SLOTS; | ||
414 | /* | 416 | /* |
415 | * If the caller chooses not to specify a hostname, whip | 417 | * If the caller chooses not to specify a hostname, whip |
416 | * up a string representation of the passed-in address. | 418 | * up a string representation of the passed-in address. |
@@ -1301,6 +1303,8 @@ call_reserve(struct rpc_task *task) | |||
1301 | xprt_reserve(task); | 1303 | xprt_reserve(task); |
1302 | } | 1304 | } |
1303 | 1305 | ||
1306 | static void call_retry_reserve(struct rpc_task *task); | ||
1307 | |||
1304 | /* | 1308 | /* |
1305 | * 1b. Grok the result of xprt_reserve() | 1309 | * 1b. Grok the result of xprt_reserve() |
1306 | */ | 1310 | */ |
@@ -1342,7 +1346,7 @@ call_reserveresult(struct rpc_task *task) | |||
1342 | case -ENOMEM: | 1346 | case -ENOMEM: |
1343 | rpc_delay(task, HZ >> 2); | 1347 | rpc_delay(task, HZ >> 2); |
1344 | case -EAGAIN: /* woken up; retry */ | 1348 | case -EAGAIN: /* woken up; retry */ |
1345 | task->tk_action = call_reserve; | 1349 | task->tk_action = call_retry_reserve; |
1346 | return; | 1350 | return; |
1347 | case -EIO: /* probably a shutdown */ | 1351 | case -EIO: /* probably a shutdown */ |
1348 | break; | 1352 | break; |
@@ -1355,6 +1359,19 @@ call_reserveresult(struct rpc_task *task) | |||
1355 | } | 1359 | } |
1356 | 1360 | ||
1357 | /* | 1361 | /* |
1362 | * 1c. Retry reserving an RPC call slot | ||
1363 | */ | ||
1364 | static void | ||
1365 | call_retry_reserve(struct rpc_task *task) | ||
1366 | { | ||
1367 | dprint_status(task); | ||
1368 | |||
1369 | task->tk_status = 0; | ||
1370 | task->tk_action = call_reserveresult; | ||
1371 | xprt_retry_reserve(task); | ||
1372 | } | ||
1373 | |||
1374 | /* | ||
1358 | * 2. Bind and/or refresh the credentials | 1375 | * 2. Bind and/or refresh the credentials |
1359 | */ | 1376 | */ |
1360 | static void | 1377 | static void |
@@ -1639,22 +1656,26 @@ call_connect_status(struct rpc_task *task) | |||
1639 | 1656 | ||
1640 | dprint_status(task); | 1657 | dprint_status(task); |
1641 | 1658 | ||
1642 | task->tk_status = 0; | ||
1643 | if (status >= 0 || status == -EAGAIN) { | ||
1644 | clnt->cl_stats->netreconn++; | ||
1645 | task->tk_action = call_transmit; | ||
1646 | return; | ||
1647 | } | ||
1648 | |||
1649 | trace_rpc_connect_status(task, status); | 1659 | trace_rpc_connect_status(task, status); |
1650 | switch (status) { | 1660 | switch (status) { |
1651 | /* if soft mounted, test if we've timed out */ | 1661 | /* if soft mounted, test if we've timed out */ |
1652 | case -ETIMEDOUT: | 1662 | case -ETIMEDOUT: |
1653 | task->tk_action = call_timeout; | 1663 | task->tk_action = call_timeout; |
1654 | break; | 1664 | return; |
1655 | default: | 1665 | case -ECONNREFUSED: |
1656 | rpc_exit(task, -EIO); | 1666 | case -ECONNRESET: |
1667 | case -ENETUNREACH: | ||
1668 | if (RPC_IS_SOFTCONN(task)) | ||
1669 | break; | ||
1670 | /* retry with existing socket, after a delay */ | ||
1671 | case 0: | ||
1672 | case -EAGAIN: | ||
1673 | task->tk_status = 0; | ||
1674 | clnt->cl_stats->netreconn++; | ||
1675 | task->tk_action = call_transmit; | ||
1676 | return; | ||
1657 | } | 1677 | } |
1678 | rpc_exit(task, status); | ||
1658 | } | 1679 | } |
1659 | 1680 | ||
1660 | /* | 1681 | /* |
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index b7478d5e7ffd..745fca3cfd36 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
@@ -948,6 +948,34 @@ void xprt_transmit(struct rpc_task *task) | |||
948 | spin_unlock_bh(&xprt->transport_lock); | 948 | spin_unlock_bh(&xprt->transport_lock); |
949 | } | 949 | } |
950 | 950 | ||
951 | static void xprt_add_backlog(struct rpc_xprt *xprt, struct rpc_task *task) | ||
952 | { | ||
953 | set_bit(XPRT_CONGESTED, &xprt->state); | ||
954 | rpc_sleep_on(&xprt->backlog, task, NULL); | ||
955 | } | ||
956 | |||
957 | static void xprt_wake_up_backlog(struct rpc_xprt *xprt) | ||
958 | { | ||
959 | if (rpc_wake_up_next(&xprt->backlog) == NULL) | ||
960 | clear_bit(XPRT_CONGESTED, &xprt->state); | ||
961 | } | ||
962 | |||
963 | static bool xprt_throttle_congested(struct rpc_xprt *xprt, struct rpc_task *task) | ||
964 | { | ||
965 | bool ret = false; | ||
966 | |||
967 | if (!test_bit(XPRT_CONGESTED, &xprt->state)) | ||
968 | goto out; | ||
969 | spin_lock(&xprt->reserve_lock); | ||
970 | if (test_bit(XPRT_CONGESTED, &xprt->state)) { | ||
971 | rpc_sleep_on(&xprt->backlog, task, NULL); | ||
972 | ret = true; | ||
973 | } | ||
974 | spin_unlock(&xprt->reserve_lock); | ||
975 | out: | ||
976 | return ret; | ||
977 | } | ||
978 | |||
951 | static struct rpc_rqst *xprt_dynamic_alloc_slot(struct rpc_xprt *xprt, gfp_t gfp_flags) | 979 | static struct rpc_rqst *xprt_dynamic_alloc_slot(struct rpc_xprt *xprt, gfp_t gfp_flags) |
952 | { | 980 | { |
953 | struct rpc_rqst *req = ERR_PTR(-EAGAIN); | 981 | struct rpc_rqst *req = ERR_PTR(-EAGAIN); |
@@ -992,7 +1020,7 @@ void xprt_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task) | |||
992 | task->tk_status = -ENOMEM; | 1020 | task->tk_status = -ENOMEM; |
993 | break; | 1021 | break; |
994 | case -EAGAIN: | 1022 | case -EAGAIN: |
995 | rpc_sleep_on(&xprt->backlog, task, NULL); | 1023 | xprt_add_backlog(xprt, task); |
996 | dprintk("RPC: waiting for request slot\n"); | 1024 | dprintk("RPC: waiting for request slot\n"); |
997 | default: | 1025 | default: |
998 | task->tk_status = -EAGAIN; | 1026 | task->tk_status = -EAGAIN; |
@@ -1028,7 +1056,7 @@ static void xprt_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req) | |||
1028 | memset(req, 0, sizeof(*req)); /* mark unused */ | 1056 | memset(req, 0, sizeof(*req)); /* mark unused */ |
1029 | list_add(&req->rq_list, &xprt->free); | 1057 | list_add(&req->rq_list, &xprt->free); |
1030 | } | 1058 | } |
1031 | rpc_wake_up_next(&xprt->backlog); | 1059 | xprt_wake_up_backlog(xprt); |
1032 | spin_unlock(&xprt->reserve_lock); | 1060 | spin_unlock(&xprt->reserve_lock); |
1033 | } | 1061 | } |
1034 | 1062 | ||
@@ -1092,7 +1120,8 @@ EXPORT_SYMBOL_GPL(xprt_free); | |||
1092 | * xprt_reserve - allocate an RPC request slot | 1120 | * xprt_reserve - allocate an RPC request slot |
1093 | * @task: RPC task requesting a slot allocation | 1121 | * @task: RPC task requesting a slot allocation |
1094 | * | 1122 | * |
1095 | * If no more slots are available, place the task on the transport's | 1123 | * If the transport is marked as being congested, or if no more |
1124 | * slots are available, place the task on the transport's | ||
1096 | * backlog queue. | 1125 | * backlog queue. |
1097 | */ | 1126 | */ |
1098 | void xprt_reserve(struct rpc_task *task) | 1127 | void xprt_reserve(struct rpc_task *task) |
@@ -1107,6 +1136,32 @@ void xprt_reserve(struct rpc_task *task) | |||
1107 | task->tk_status = -EAGAIN; | 1136 | task->tk_status = -EAGAIN; |
1108 | rcu_read_lock(); | 1137 | rcu_read_lock(); |
1109 | xprt = rcu_dereference(task->tk_client->cl_xprt); | 1138 | xprt = rcu_dereference(task->tk_client->cl_xprt); |
1139 | if (!xprt_throttle_congested(xprt, task)) | ||
1140 | xprt->ops->alloc_slot(xprt, task); | ||
1141 | rcu_read_unlock(); | ||
1142 | } | ||
1143 | |||
1144 | /** | ||
1145 | * xprt_retry_reserve - allocate an RPC request slot | ||
1146 | * @task: RPC task requesting a slot allocation | ||
1147 | * | ||
1148 | * If no more slots are available, place the task on the transport's | ||
1149 | * backlog queue. | ||
1150 | * Note that the only difference with xprt_reserve is that we now | ||
1151 | * ignore the value of the XPRT_CONGESTED flag. | ||
1152 | */ | ||
1153 | void xprt_retry_reserve(struct rpc_task *task) | ||
1154 | { | ||
1155 | struct rpc_xprt *xprt; | ||
1156 | |||
1157 | task->tk_status = 0; | ||
1158 | if (task->tk_rqstp != NULL) | ||
1159 | return; | ||
1160 | |||
1161 | task->tk_timeout = 0; | ||
1162 | task->tk_status = -EAGAIN; | ||
1163 | rcu_read_lock(); | ||
1164 | xprt = rcu_dereference(task->tk_client->cl_xprt); | ||
1110 | xprt->ops->alloc_slot(xprt, task); | 1165 | xprt->ops->alloc_slot(xprt, task); |
1111 | rcu_read_unlock(); | 1166 | rcu_read_unlock(); |
1112 | } | 1167 | } |
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 3d02130828da..9c2825827dec 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
@@ -2207,10 +2207,6 @@ static void xs_tcp_setup_socket(struct work_struct *work) | |||
2207 | */ | 2207 | */ |
2208 | xs_tcp_force_close(xprt); | 2208 | xs_tcp_force_close(xprt); |
2209 | break; | 2209 | break; |
2210 | case -ECONNREFUSED: | ||
2211 | case -ECONNRESET: | ||
2212 | case -ENETUNREACH: | ||
2213 | /* retry with existing socket, after a delay */ | ||
2214 | case 0: | 2210 | case 0: |
2215 | case -EINPROGRESS: | 2211 | case -EINPROGRESS: |
2216 | case -EALREADY: | 2212 | case -EALREADY: |
@@ -2221,6 +2217,10 @@ static void xs_tcp_setup_socket(struct work_struct *work) | |||
2221 | /* Happens, for instance, if the user specified a link | 2217 | /* Happens, for instance, if the user specified a link |
2222 | * local IPv6 address without a scope-id. | 2218 | * local IPv6 address without a scope-id. |
2223 | */ | 2219 | */ |
2220 | case -ECONNREFUSED: | ||
2221 | case -ECONNRESET: | ||
2222 | case -ENETUNREACH: | ||
2223 | /* retry with existing socket, after a delay */ | ||
2224 | goto out; | 2224 | goto out; |
2225 | } | 2225 | } |
2226 | out_eagain: | 2226 | out_eagain: |
@@ -2767,9 +2767,13 @@ static struct rpc_xprt *xs_setup_tcp(struct xprt_create *args) | |||
2767 | struct rpc_xprt *xprt; | 2767 | struct rpc_xprt *xprt; |
2768 | struct sock_xprt *transport; | 2768 | struct sock_xprt *transport; |
2769 | struct rpc_xprt *ret; | 2769 | struct rpc_xprt *ret; |
2770 | unsigned int max_slot_table_size = xprt_max_tcp_slot_table_entries; | ||
2771 | |||
2772 | if (args->flags & XPRT_CREATE_INFINITE_SLOTS) | ||
2773 | max_slot_table_size = RPC_MAX_SLOT_TABLE_LIMIT; | ||
2770 | 2774 | ||
2771 | xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries, | 2775 | xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries, |
2772 | xprt_max_tcp_slot_table_entries); | 2776 | max_slot_table_size); |
2773 | if (IS_ERR(xprt)) | 2777 | if (IS_ERR(xprt)) |
2774 | return xprt; | 2778 | return xprt; |
2775 | transport = container_of(xprt, struct sock_xprt, xprt); | 2779 | transport = container_of(xprt, struct sock_xprt, xprt); |