aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/nfs4proc.c
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2012-10-29 19:02:20 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2012-12-05 18:30:50 -0500
commit8fe72bac8de784c4059b41a7dd6bb0151a3ae898 (patch)
tree156f7442bb4b41e804aca666d87690af45fb2ac7 /fs/nfs/nfs4proc.c
parent275e7e20aa8599719729f8ef4c09c9bfc4895642 (diff)
NFSv4: Clean up handling of privileged operations
Privileged rpc calls are those that are run by the state recovery thread, in cases where we're trying to recover the system after a server reboot or a network partition. In those cases, we want to fence off all other rpc calls (see nfs4_begin_drain_session()) so that they don't end up using stateids or clientids that are in the process of being recovered. Prior to this patch, we had to set up special callback functions in order to declare an rpc call as being privileged. By adding a new field to the sequence arguments, this patch simplifies things considerably, and allows us to declare the rpc call as privileged before it is run. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r--fs/nfs/nfs4proc.c114
1 files changed, 42 insertions, 72 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 4b1635ce658d..38a709d78594 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -490,11 +490,17 @@ static void nfs41_init_sequence(struct nfs4_sequence_args *args,
490{ 490{
491 args->sa_slot = NULL; 491 args->sa_slot = NULL;
492 args->sa_cache_this = 0; 492 args->sa_cache_this = 0;
493 args->sa_privileged = 0;
493 if (cache_reply) 494 if (cache_reply)
494 args->sa_cache_this = 1; 495 args->sa_cache_this = 1;
495 res->sr_slot = NULL; 496 res->sr_slot = NULL;
496} 497}
497 498
499static void nfs4_set_sequence_privileged(struct nfs4_sequence_args *args)
500{
501 args->sa_privileged = 1;
502}
503
498int nfs41_setup_sequence(struct nfs4_session *session, 504int nfs41_setup_sequence(struct nfs4_session *session,
499 struct nfs4_sequence_args *args, 505 struct nfs4_sequence_args *args,
500 struct nfs4_sequence_res *res, 506 struct nfs4_sequence_res *res,
@@ -514,7 +520,7 @@ int nfs41_setup_sequence(struct nfs4_session *session,
514 520
515 spin_lock(&tbl->slot_tbl_lock); 521 spin_lock(&tbl->slot_tbl_lock);
516 if (test_bit(NFS4_SESSION_DRAINING, &session->session_state) && 522 if (test_bit(NFS4_SESSION_DRAINING, &session->session_state) &&
517 !rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) { 523 !args->sa_privileged) {
518 /* The state manager will wait until the slot table is empty */ 524 /* The state manager will wait until the slot table is empty */
519 dprintk("%s session is draining\n", __func__); 525 dprintk("%s session is draining\n", __func__);
520 goto out_sleep; 526 goto out_sleep;
@@ -548,6 +554,9 @@ out_success:
548 rpc_call_start(task); 554 rpc_call_start(task);
549 return 0; 555 return 0;
550out_sleep: 556out_sleep:
557 /* Privileged tasks are queued with top priority */
558 if (args->sa_privileged)
559 rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
551 rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); 560 rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL);
552 spin_unlock(&tbl->slot_tbl_lock); 561 spin_unlock(&tbl->slot_tbl_lock);
553 return -EAGAIN; 562 return -EAGAIN;
@@ -593,12 +602,6 @@ static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata)
593 nfs41_setup_sequence(session, data->seq_args, data->seq_res, task); 602 nfs41_setup_sequence(session, data->seq_args, data->seq_res, task);
594} 603}
595 604
596static void nfs41_call_priv_sync_prepare(struct rpc_task *task, void *calldata)
597{
598 rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
599 nfs41_call_sync_prepare(task, calldata);
600}
601
602static void nfs41_call_sync_done(struct rpc_task *task, void *calldata) 605static void nfs41_call_sync_done(struct rpc_task *task, void *calldata)
603{ 606{
604 struct nfs41_call_sync_data *data = calldata; 607 struct nfs41_call_sync_data *data = calldata;
@@ -611,17 +614,11 @@ static const struct rpc_call_ops nfs41_call_sync_ops = {
611 .rpc_call_done = nfs41_call_sync_done, 614 .rpc_call_done = nfs41_call_sync_done,
612}; 615};
613 616
614static const struct rpc_call_ops nfs41_call_priv_sync_ops = {
615 .rpc_call_prepare = nfs41_call_priv_sync_prepare,
616 .rpc_call_done = nfs41_call_sync_done,
617};
618
619static int nfs4_call_sync_sequence(struct rpc_clnt *clnt, 617static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,
620 struct nfs_server *server, 618 struct nfs_server *server,
621 struct rpc_message *msg, 619 struct rpc_message *msg,
622 struct nfs4_sequence_args *args, 620 struct nfs4_sequence_args *args,
623 struct nfs4_sequence_res *res, 621 struct nfs4_sequence_res *res)
624 int privileged)
625{ 622{
626 int ret; 623 int ret;
627 struct rpc_task *task; 624 struct rpc_task *task;
@@ -637,8 +634,6 @@ static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,
637 .callback_data = &data 634 .callback_data = &data
638 }; 635 };
639 636
640 if (privileged)
641 task_setup.callback_ops = &nfs41_call_priv_sync_ops;
642 task = rpc_run_task(&task_setup); 637 task = rpc_run_task(&task_setup);
643 if (IS_ERR(task)) 638 if (IS_ERR(task))
644 ret = PTR_ERR(task); 639 ret = PTR_ERR(task);
@@ -656,16 +651,21 @@ int _nfs4_call_sync_session(struct rpc_clnt *clnt,
656 struct nfs4_sequence_args *args, 651 struct nfs4_sequence_args *args,
657 struct nfs4_sequence_res *res) 652 struct nfs4_sequence_res *res)
658{ 653{
659 return nfs4_call_sync_sequence(clnt, server, msg, args, res, 0); 654 return nfs4_call_sync_sequence(clnt, server, msg, args, res);
660} 655}
661 656
662#else 657#else
663static inline 658static
664void nfs41_init_sequence(struct nfs4_sequence_args *args, 659void nfs41_init_sequence(struct nfs4_sequence_args *args,
665 struct nfs4_sequence_res *res, int cache_reply) 660 struct nfs4_sequence_res *res, int cache_reply)
666{ 661{
667} 662}
668 663
664static void nfs4_set_sequence_privileged(struct nfs4_sequence_args *args)
665{
666}
667
668
669static int nfs4_sequence_done(struct rpc_task *task, 669static int nfs4_sequence_done(struct rpc_task *task,
670 struct nfs4_sequence_res *res) 670 struct nfs4_sequence_res *res)
671{ 671{
@@ -1475,13 +1475,6 @@ unlock_no_action:
1475 rcu_read_unlock(); 1475 rcu_read_unlock();
1476out_no_action: 1476out_no_action:
1477 task->tk_action = NULL; 1477 task->tk_action = NULL;
1478
1479}
1480
1481static void nfs4_recover_open_prepare(struct rpc_task *task, void *calldata)
1482{
1483 rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
1484 nfs4_open_prepare(task, calldata);
1485} 1478}
1486 1479
1487static void nfs4_open_done(struct rpc_task *task, void *calldata) 1480static void nfs4_open_done(struct rpc_task *task, void *calldata)
@@ -1542,12 +1535,6 @@ static const struct rpc_call_ops nfs4_open_ops = {
1542 .rpc_release = nfs4_open_release, 1535 .rpc_release = nfs4_open_release,
1543}; 1536};
1544 1537
1545static const struct rpc_call_ops nfs4_recover_open_ops = {
1546 .rpc_call_prepare = nfs4_recover_open_prepare,
1547 .rpc_call_done = nfs4_open_done,
1548 .rpc_release = nfs4_open_release,
1549};
1550
1551static int nfs4_run_open_task(struct nfs4_opendata *data, int isrecover) 1538static int nfs4_run_open_task(struct nfs4_opendata *data, int isrecover)
1552{ 1539{
1553 struct inode *dir = data->dir->d_inode; 1540 struct inode *dir = data->dir->d_inode;
@@ -1577,7 +1564,7 @@ static int nfs4_run_open_task(struct nfs4_opendata *data, int isrecover)
1577 data->rpc_status = 0; 1564 data->rpc_status = 0;
1578 data->cancelled = 0; 1565 data->cancelled = 0;
1579 if (isrecover) 1566 if (isrecover)
1580 task_setup_data.callback_ops = &nfs4_recover_open_ops; 1567 nfs4_set_sequence_privileged(&o_arg->seq_args);
1581 task = rpc_run_task(&task_setup_data); 1568 task = rpc_run_task(&task_setup_data);
1582 if (IS_ERR(task)) 1569 if (IS_ERR(task))
1583 return PTR_ERR(task); 1570 return PTR_ERR(task);
@@ -4558,8 +4545,9 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
4558 return; 4545 return;
4559 /* Do we need to do an open_to_lock_owner? */ 4546 /* Do we need to do an open_to_lock_owner? */
4560 if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) { 4547 if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) {
4561 if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0) 4548 if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0) {
4562 goto out_release_lock_seqid; 4549 goto out_release_lock_seqid;
4550 }
4563 data->arg.open_stateid = &state->stateid; 4551 data->arg.open_stateid = &state->stateid;
4564 data->arg.new_lock_owner = 1; 4552 data->arg.new_lock_owner = 1;
4565 data->res.open_seqid = data->arg.open_seqid; 4553 data->res.open_seqid = data->arg.open_seqid;
@@ -4574,13 +4562,7 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
4574 nfs_release_seqid(data->arg.open_seqid); 4562 nfs_release_seqid(data->arg.open_seqid);
4575out_release_lock_seqid: 4563out_release_lock_seqid:
4576 nfs_release_seqid(data->arg.lock_seqid); 4564 nfs_release_seqid(data->arg.lock_seqid);
4577 dprintk("%s: done!, ret = %d\n", __func__, task->tk_status); 4565 dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status);
4578}
4579
4580static void nfs4_recover_lock_prepare(struct rpc_task *task, void *calldata)
4581{
4582 rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
4583 nfs4_lock_prepare(task, calldata);
4584} 4566}
4585 4567
4586static void nfs4_lock_done(struct rpc_task *task, void *calldata) 4568static void nfs4_lock_done(struct rpc_task *task, void *calldata)
@@ -4635,12 +4617,6 @@ static const struct rpc_call_ops nfs4_lock_ops = {
4635 .rpc_release = nfs4_lock_release, 4617 .rpc_release = nfs4_lock_release,
4636}; 4618};
4637 4619
4638static const struct rpc_call_ops nfs4_recover_lock_ops = {
4639 .rpc_call_prepare = nfs4_recover_lock_prepare,
4640 .rpc_call_done = nfs4_lock_done,
4641 .rpc_release = nfs4_lock_release,
4642};
4643
4644static void nfs4_handle_setlk_error(struct nfs_server *server, struct nfs4_lock_state *lsp, int new_lock_owner, int error) 4620static void nfs4_handle_setlk_error(struct nfs_server *server, struct nfs4_lock_state *lsp, int new_lock_owner, int error)
4645{ 4621{
4646 switch (error) { 4622 switch (error) {
@@ -4683,15 +4659,15 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f
4683 return -ENOMEM; 4659 return -ENOMEM;
4684 if (IS_SETLKW(cmd)) 4660 if (IS_SETLKW(cmd))
4685 data->arg.block = 1; 4661 data->arg.block = 1;
4686 if (recovery_type > NFS_LOCK_NEW) {
4687 if (recovery_type == NFS_LOCK_RECLAIM)
4688 data->arg.reclaim = NFS_LOCK_RECLAIM;
4689 task_setup_data.callback_ops = &nfs4_recover_lock_ops;
4690 }
4691 nfs41_init_sequence(&data->arg.seq_args, &data->res.seq_res, 1); 4662 nfs41_init_sequence(&data->arg.seq_args, &data->res.seq_res, 1);
4692 msg.rpc_argp = &data->arg; 4663 msg.rpc_argp = &data->arg;
4693 msg.rpc_resp = &data->res; 4664 msg.rpc_resp = &data->res;
4694 task_setup_data.callback_data = data; 4665 task_setup_data.callback_data = data;
4666 if (recovery_type > NFS_LOCK_NEW) {
4667 if (recovery_type == NFS_LOCK_RECLAIM)
4668 data->arg.reclaim = NFS_LOCK_RECLAIM;
4669 nfs4_set_sequence_privileged(&data->arg.seq_args);
4670 }
4695 task = rpc_run_task(&task_setup_data); 4671 task = rpc_run_task(&task_setup_data);
4696 if (IS_ERR(task)) 4672 if (IS_ERR(task))
4697 return PTR_ERR(task); 4673 return PTR_ERR(task);
@@ -5432,7 +5408,6 @@ static void nfs4_get_lease_time_prepare(struct rpc_task *task,
5432 (struct nfs4_get_lease_time_data *)calldata; 5408 (struct nfs4_get_lease_time_data *)calldata;
5433 5409
5434 dprintk("--> %s\n", __func__); 5410 dprintk("--> %s\n", __func__);
5435 rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
5436 /* just setup sequence, do not trigger session recovery 5411 /* just setup sequence, do not trigger session recovery
5437 since we're invoked within one */ 5412 since we're invoked within one */
5438 nfs41_setup_sequence(data->clp->cl_session, 5413 nfs41_setup_sequence(data->clp->cl_session,
@@ -5500,6 +5475,7 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo)
5500 int status; 5475 int status;
5501 5476
5502 nfs41_init_sequence(&args.la_seq_args, &res.lr_seq_res, 0); 5477 nfs41_init_sequence(&args.la_seq_args, &res.lr_seq_res, 0);
5478 nfs4_set_sequence_privileged(&args.la_seq_args);
5503 dprintk("--> %s\n", __func__); 5479 dprintk("--> %s\n", __func__);
5504 task = rpc_run_task(&task_setup); 5480 task = rpc_run_task(&task_setup);
5505 5481
@@ -5775,26 +5751,15 @@ static void nfs41_sequence_prepare(struct rpc_task *task, void *data)
5775 nfs41_setup_sequence(clp->cl_session, args, res, task); 5751 nfs41_setup_sequence(clp->cl_session, args, res, task);
5776} 5752}
5777 5753
5778static void nfs41_sequence_prepare_privileged(struct rpc_task *task, void *data)
5779{
5780 rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
5781 nfs41_sequence_prepare(task, data);
5782}
5783
5784static const struct rpc_call_ops nfs41_sequence_ops = { 5754static const struct rpc_call_ops nfs41_sequence_ops = {
5785 .rpc_call_done = nfs41_sequence_call_done, 5755 .rpc_call_done = nfs41_sequence_call_done,
5786 .rpc_call_prepare = nfs41_sequence_prepare, 5756 .rpc_call_prepare = nfs41_sequence_prepare,
5787 .rpc_release = nfs41_sequence_release, 5757 .rpc_release = nfs41_sequence_release,
5788}; 5758};
5789 5759
5790static const struct rpc_call_ops nfs41_sequence_privileged_ops = { 5760static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp,
5791 .rpc_call_done = nfs41_sequence_call_done, 5761 struct rpc_cred *cred,
5792 .rpc_call_prepare = nfs41_sequence_prepare_privileged, 5762 bool is_privileged)
5793 .rpc_release = nfs41_sequence_release,
5794};
5795
5796static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred,
5797 const struct rpc_call_ops *seq_ops)
5798{ 5763{
5799 struct nfs4_sequence_data *calldata; 5764 struct nfs4_sequence_data *calldata;
5800 struct rpc_message msg = { 5765 struct rpc_message msg = {
@@ -5804,7 +5769,7 @@ static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_
5804 struct rpc_task_setup task_setup_data = { 5769 struct rpc_task_setup task_setup_data = {
5805 .rpc_client = clp->cl_rpcclient, 5770 .rpc_client = clp->cl_rpcclient,
5806 .rpc_message = &msg, 5771 .rpc_message = &msg,
5807 .callback_ops = seq_ops, 5772 .callback_ops = &nfs41_sequence_ops,
5808 .flags = RPC_TASK_ASYNC | RPC_TASK_SOFT, 5773 .flags = RPC_TASK_ASYNC | RPC_TASK_SOFT,
5809 }; 5774 };
5810 5775
@@ -5816,6 +5781,8 @@ static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_
5816 return ERR_PTR(-ENOMEM); 5781 return ERR_PTR(-ENOMEM);
5817 } 5782 }
5818 nfs41_init_sequence(&calldata->args, &calldata->res, 0); 5783 nfs41_init_sequence(&calldata->args, &calldata->res, 0);
5784 if (is_privileged)
5785 nfs4_set_sequence_privileged(&calldata->args);
5819 msg.rpc_argp = &calldata->args; 5786 msg.rpc_argp = &calldata->args;
5820 msg.rpc_resp = &calldata->res; 5787 msg.rpc_resp = &calldata->res;
5821 calldata->clp = clp; 5788 calldata->clp = clp;
@@ -5831,7 +5798,7 @@ static int nfs41_proc_async_sequence(struct nfs_client *clp, struct rpc_cred *cr
5831 5798
5832 if ((renew_flags & NFS4_RENEW_TIMEOUT) == 0) 5799 if ((renew_flags & NFS4_RENEW_TIMEOUT) == 0)
5833 return 0; 5800 return 0;
5834 task = _nfs41_proc_sequence(clp, cred, &nfs41_sequence_ops); 5801 task = _nfs41_proc_sequence(clp, cred, false);
5835 if (IS_ERR(task)) 5802 if (IS_ERR(task))
5836 ret = PTR_ERR(task); 5803 ret = PTR_ERR(task);
5837 else 5804 else
@@ -5845,7 +5812,7 @@ static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred)
5845 struct rpc_task *task; 5812 struct rpc_task *task;
5846 int ret; 5813 int ret;
5847 5814
5848 task = _nfs41_proc_sequence(clp, cred, &nfs41_sequence_privileged_ops); 5815 task = _nfs41_proc_sequence(clp, cred, true);
5849 if (IS_ERR(task)) { 5816 if (IS_ERR(task)) {
5850 ret = PTR_ERR(task); 5817 ret = PTR_ERR(task);
5851 goto out; 5818 goto out;
@@ -5874,7 +5841,6 @@ static void nfs4_reclaim_complete_prepare(struct rpc_task *task, void *data)
5874{ 5841{
5875 struct nfs4_reclaim_complete_data *calldata = data; 5842 struct nfs4_reclaim_complete_data *calldata = data;
5876 5843
5877 rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
5878 nfs41_setup_sequence(calldata->clp->cl_session, 5844 nfs41_setup_sequence(calldata->clp->cl_session,
5879 &calldata->arg.seq_args, 5845 &calldata->arg.seq_args,
5880 &calldata->res.seq_res, 5846 &calldata->res.seq_res,
@@ -5955,6 +5921,7 @@ static int nfs41_proc_reclaim_complete(struct nfs_client *clp)
5955 calldata->arg.one_fs = 0; 5921 calldata->arg.one_fs = 0;
5956 5922
5957 nfs41_init_sequence(&calldata->arg.seq_args, &calldata->res.seq_res, 0); 5923 nfs41_init_sequence(&calldata->arg.seq_args, &calldata->res.seq_res, 0);
5924 nfs4_set_sequence_privileged(&calldata->arg.seq_args);
5958 msg.rpc_argp = &calldata->arg; 5925 msg.rpc_argp = &calldata->arg;
5959 msg.rpc_resp = &calldata->res; 5926 msg.rpc_resp = &calldata->res;
5960 task_setup_data.callback_data = calldata; 5927 task_setup_data.callback_data = calldata;
@@ -6521,7 +6488,9 @@ static int _nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid)
6521 6488
6522 dprintk("NFS call test_stateid %p\n", stateid); 6489 dprintk("NFS call test_stateid %p\n", stateid);
6523 nfs41_init_sequence(&args.seq_args, &res.seq_res, 0); 6490 nfs41_init_sequence(&args.seq_args, &res.seq_res, 0);
6524 status = nfs4_call_sync_sequence(server->client, server, &msg, &args.seq_args, &res.seq_res, 1); 6491 nfs4_set_sequence_privileged(&args.seq_args);
6492 status = nfs4_call_sync_sequence(server->client, server, &msg,
6493 &args.seq_args, &res.seq_res);
6525 if (status != NFS_OK) { 6494 if (status != NFS_OK) {
6526 dprintk("NFS reply test_stateid: failed, %d\n", status); 6495 dprintk("NFS reply test_stateid: failed, %d\n", status);
6527 return status; 6496 return status;
@@ -6568,8 +6537,9 @@ static int _nfs4_free_stateid(struct nfs_server *server, nfs4_stateid *stateid)
6568 6537
6569 dprintk("NFS call free_stateid %p\n", stateid); 6538 dprintk("NFS call free_stateid %p\n", stateid);
6570 nfs41_init_sequence(&args.seq_args, &res.seq_res, 0); 6539 nfs41_init_sequence(&args.seq_args, &res.seq_res, 0);
6540 nfs4_set_sequence_privileged(&args.seq_args);
6571 status = nfs4_call_sync_sequence(server->client, server, &msg, 6541 status = nfs4_call_sync_sequence(server->client, server, &msg,
6572 &args.seq_args, &res.seq_res, 1); 6542 &args.seq_args, &res.seq_res);
6573 dprintk("NFS reply free_stateid: %d\n", status); 6543 dprintk("NFS reply free_stateid: %d\n", status);
6574 return status; 6544 return status;
6575} 6545}