aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-12-16 13:47:44 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-12-16 13:47:44 -0500
commite4bdda1bc3123a9e65f4dd93a23041fde8ed3dc2 (patch)
treec2f75cc08bb4c5cbd9103e14399ea5ab66ce960d
parent74f3ae743427b87e43b5cb9f4257021ae8ad4267 (diff)
parent380454126f1357db9270f9d1ca05dfe1a6e4ad47 (diff)
Merge branch 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6
* 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6: NFSv4: Fix a regression in the NFSv4 state manager NFSv4: Release the sequence id before restarting a CLOSE rpc call nfs41: fix session fore channel negotiation nfs41: do not zero seqid portion of stateid on close nfs: run state manager in privileged mode nfs: make recovery state manager operations privileged nfs: enforce FIFO ordering of operations trying to acquire slot rpc: add a new priority in RPC task nfs: remove rpc_task argument from nfs4_find_slot rpc: add rpc_queue_empty function nfs: change nfs4_do_setlk params to identify recovery type nfs: do not do a LOOKUP after open nfs: minor cleanup of session draining
-rw-r--r--fs/nfs/nfs4_fs.h5
-rw-r--r--fs/nfs/nfs4proc.c203
-rw-r--r--fs/nfs/nfs4state.c60
-rw-r--r--include/linux/sunrpc/sched.h14
-rw-r--r--net/sunrpc/sched.c15
5 files changed, 223 insertions, 74 deletions
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 7e57b04e4014..865265bdca03 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -108,6 +108,10 @@ enum {
108 NFS_OWNER_RECLAIM_NOGRACE 108 NFS_OWNER_RECLAIM_NOGRACE
109}; 109};
110 110
111#define NFS_LOCK_NEW 0
112#define NFS_LOCK_RECLAIM 1
113#define NFS_LOCK_EXPIRED 2
114
111/* 115/*
112 * struct nfs4_state maintains the client-side state for a given 116 * struct nfs4_state maintains the client-side state for a given
113 * (state_owner,inode) tuple (OPEN) or state_owner (LOCK). 117 * (state_owner,inode) tuple (OPEN) or state_owner (LOCK).
@@ -282,6 +286,7 @@ extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter);
282extern int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task); 286extern int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task);
283extern void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid); 287extern void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid);
284extern void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid); 288extern void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid);
289extern void nfs_release_seqid(struct nfs_seqid *seqid);
285extern void nfs_free_seqid(struct nfs_seqid *seqid); 290extern void nfs_free_seqid(struct nfs_seqid *seqid);
286 291
287extern const nfs4_stateid zero_stateid; 292extern const nfs4_stateid zero_stateid;
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 9f5f11ecfd93..198d51d17c13 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -64,6 +64,7 @@
64 64
65struct nfs4_opendata; 65struct nfs4_opendata;
66static int _nfs4_proc_open(struct nfs4_opendata *data); 66static int _nfs4_proc_open(struct nfs4_opendata *data);
67static int _nfs4_recover_proc_open(struct nfs4_opendata *data);
67static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); 68static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
68static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *); 69static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *);
69static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr); 70static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr);
@@ -341,6 +342,27 @@ nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid)
341 free_slotid, tbl->highest_used_slotid); 342 free_slotid, tbl->highest_used_slotid);
342} 343}
343 344
345/*
346 * Signal state manager thread if session is drained
347 */
348static void nfs41_check_drain_session_complete(struct nfs4_session *ses)
349{
350 struct rpc_task *task;
351
352 if (!test_bit(NFS4CLNT_SESSION_DRAINING, &ses->clp->cl_state)) {
353 task = rpc_wake_up_next(&ses->fc_slot_table.slot_tbl_waitq);
354 if (task)
355 rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
356 return;
357 }
358
359 if (ses->fc_slot_table.highest_used_slotid != -1)
360 return;
361
362 dprintk("%s COMPLETE: Session Drained\n", __func__);
363 complete(&ses->complete);
364}
365
344static void nfs41_sequence_free_slot(const struct nfs_client *clp, 366static void nfs41_sequence_free_slot(const struct nfs_client *clp,
345 struct nfs4_sequence_res *res) 367 struct nfs4_sequence_res *res)
346{ 368{
@@ -356,15 +378,7 @@ static void nfs41_sequence_free_slot(const struct nfs_client *clp,
356 378
357 spin_lock(&tbl->slot_tbl_lock); 379 spin_lock(&tbl->slot_tbl_lock);
358 nfs4_free_slot(tbl, res->sr_slotid); 380 nfs4_free_slot(tbl, res->sr_slotid);
359 381 nfs41_check_drain_session_complete(clp->cl_session);
360 /* Signal state manager thread if session is drained */
361 if (test_bit(NFS4CLNT_SESSION_DRAINING, &clp->cl_state)) {
362 if (tbl->highest_used_slotid == -1) {
363 dprintk("%s COMPLETE: Session Drained\n", __func__);
364 complete(&clp->cl_session->complete);
365 }
366 } else
367 rpc_wake_up_next(&tbl->slot_tbl_waitq);
368 spin_unlock(&tbl->slot_tbl_lock); 382 spin_unlock(&tbl->slot_tbl_lock);
369 res->sr_slotid = NFS4_MAX_SLOT_TABLE; 383 res->sr_slotid = NFS4_MAX_SLOT_TABLE;
370} 384}
@@ -421,7 +435,7 @@ out:
421 * Note: must be called with under the slot_tbl_lock. 435 * Note: must be called with under the slot_tbl_lock.
422 */ 436 */
423static u8 437static u8
424nfs4_find_slot(struct nfs4_slot_table *tbl, struct rpc_task *task) 438nfs4_find_slot(struct nfs4_slot_table *tbl)
425{ 439{
426 int slotid; 440 int slotid;
427 u8 ret_id = NFS4_MAX_SLOT_TABLE; 441 u8 ret_id = NFS4_MAX_SLOT_TABLE;
@@ -463,7 +477,8 @@ static int nfs41_setup_sequence(struct nfs4_session *session,
463 tbl = &session->fc_slot_table; 477 tbl = &session->fc_slot_table;
464 478
465 spin_lock(&tbl->slot_tbl_lock); 479 spin_lock(&tbl->slot_tbl_lock);
466 if (test_bit(NFS4CLNT_SESSION_DRAINING, &session->clp->cl_state)) { 480 if (test_bit(NFS4CLNT_SESSION_DRAINING, &session->clp->cl_state) &&
481 !rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) {
467 /* 482 /*
468 * The state manager will wait until the slot table is empty. 483 * The state manager will wait until the slot table is empty.
469 * Schedule the reset thread 484 * Schedule the reset thread
@@ -474,7 +489,15 @@ static int nfs41_setup_sequence(struct nfs4_session *session,
474 return -EAGAIN; 489 return -EAGAIN;
475 } 490 }
476 491
477 slotid = nfs4_find_slot(tbl, task); 492 if (!rpc_queue_empty(&tbl->slot_tbl_waitq) &&
493 !rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) {
494 rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL);
495 spin_unlock(&tbl->slot_tbl_lock);
496 dprintk("%s enforce FIFO order\n", __func__);
497 return -EAGAIN;
498 }
499
500 slotid = nfs4_find_slot(tbl);
478 if (slotid == NFS4_MAX_SLOT_TABLE) { 501 if (slotid == NFS4_MAX_SLOT_TABLE) {
479 rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); 502 rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL);
480 spin_unlock(&tbl->slot_tbl_lock); 503 spin_unlock(&tbl->slot_tbl_lock);
@@ -483,6 +506,7 @@ static int nfs41_setup_sequence(struct nfs4_session *session,
483 } 506 }
484 spin_unlock(&tbl->slot_tbl_lock); 507 spin_unlock(&tbl->slot_tbl_lock);
485 508
509 rpc_task_set_priority(task, RPC_PRIORITY_NORMAL);
486 slot = tbl->slots + slotid; 510 slot = tbl->slots + slotid;
487 args->sa_session = session; 511 args->sa_session = session;
488 args->sa_slotid = slotid; 512 args->sa_slotid = slotid;
@@ -545,6 +569,12 @@ static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata)
545 rpc_call_start(task); 569 rpc_call_start(task);
546} 570}
547 571
572static void nfs41_call_priv_sync_prepare(struct rpc_task *task, void *calldata)
573{
574 rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
575 nfs41_call_sync_prepare(task, calldata);
576}
577
548static void nfs41_call_sync_done(struct rpc_task *task, void *calldata) 578static void nfs41_call_sync_done(struct rpc_task *task, void *calldata)
549{ 579{
550 struct nfs41_call_sync_data *data = calldata; 580 struct nfs41_call_sync_data *data = calldata;
@@ -557,12 +587,18 @@ struct rpc_call_ops nfs41_call_sync_ops = {
557 .rpc_call_done = nfs41_call_sync_done, 587 .rpc_call_done = nfs41_call_sync_done,
558}; 588};
559 589
590struct rpc_call_ops nfs41_call_priv_sync_ops = {
591 .rpc_call_prepare = nfs41_call_priv_sync_prepare,
592 .rpc_call_done = nfs41_call_sync_done,
593};
594
560static int nfs4_call_sync_sequence(struct nfs_client *clp, 595static int nfs4_call_sync_sequence(struct nfs_client *clp,
561 struct rpc_clnt *clnt, 596 struct rpc_clnt *clnt,
562 struct rpc_message *msg, 597 struct rpc_message *msg,
563 struct nfs4_sequence_args *args, 598 struct nfs4_sequence_args *args,
564 struct nfs4_sequence_res *res, 599 struct nfs4_sequence_res *res,
565 int cache_reply) 600 int cache_reply,
601 int privileged)
566{ 602{
567 int ret; 603 int ret;
568 struct rpc_task *task; 604 struct rpc_task *task;
@@ -580,6 +616,8 @@ static int nfs4_call_sync_sequence(struct nfs_client *clp,
580 }; 616 };
581 617
582 res->sr_slotid = NFS4_MAX_SLOT_TABLE; 618 res->sr_slotid = NFS4_MAX_SLOT_TABLE;
619 if (privileged)
620 task_setup.callback_ops = &nfs41_call_priv_sync_ops;
583 task = rpc_run_task(&task_setup); 621 task = rpc_run_task(&task_setup);
584 if (IS_ERR(task)) 622 if (IS_ERR(task))
585 ret = PTR_ERR(task); 623 ret = PTR_ERR(task);
@@ -597,7 +635,7 @@ int _nfs4_call_sync_session(struct nfs_server *server,
597 int cache_reply) 635 int cache_reply)
598{ 636{
599 return nfs4_call_sync_sequence(server->nfs_client, server->client, 637 return nfs4_call_sync_sequence(server->nfs_client, server->client,
600 msg, args, res, cache_reply); 638 msg, args, res, cache_reply, 0);
601} 639}
602 640
603#endif /* CONFIG_NFS_V4_1 */ 641#endif /* CONFIG_NFS_V4_1 */
@@ -1035,7 +1073,7 @@ static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, fmode_t fmod
1035 memset(&opendata->o_res, 0, sizeof(opendata->o_res)); 1073 memset(&opendata->o_res, 0, sizeof(opendata->o_res));
1036 memset(&opendata->c_res, 0, sizeof(opendata->c_res)); 1074 memset(&opendata->c_res, 0, sizeof(opendata->c_res));
1037 nfs4_init_opendata_res(opendata); 1075 nfs4_init_opendata_res(opendata);
1038 ret = _nfs4_proc_open(opendata); 1076 ret = _nfs4_recover_proc_open(opendata);
1039 if (ret != 0) 1077 if (ret != 0)
1040 return ret; 1078 return ret;
1041 newstate = nfs4_opendata_to_nfs4_state(opendata); 1079 newstate = nfs4_opendata_to_nfs4_state(opendata);
@@ -1326,6 +1364,12 @@ out_no_action:
1326 1364
1327} 1365}
1328 1366
1367static void nfs4_recover_open_prepare(struct rpc_task *task, void *calldata)
1368{
1369 rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
1370 nfs4_open_prepare(task, calldata);
1371}
1372
1329static void nfs4_open_done(struct rpc_task *task, void *calldata) 1373static void nfs4_open_done(struct rpc_task *task, void *calldata)
1330{ 1374{
1331 struct nfs4_opendata *data = calldata; 1375 struct nfs4_opendata *data = calldata;
@@ -1384,10 +1428,13 @@ static const struct rpc_call_ops nfs4_open_ops = {
1384 .rpc_release = nfs4_open_release, 1428 .rpc_release = nfs4_open_release,
1385}; 1429};
1386 1430
1387/* 1431static const struct rpc_call_ops nfs4_recover_open_ops = {
1388 * Note: On error, nfs4_proc_open will free the struct nfs4_opendata 1432 .rpc_call_prepare = nfs4_recover_open_prepare,
1389 */ 1433 .rpc_call_done = nfs4_open_done,
1390static int _nfs4_proc_open(struct nfs4_opendata *data) 1434 .rpc_release = nfs4_open_release,
1435};
1436
1437static int nfs4_run_open_task(struct nfs4_opendata *data, int isrecover)
1391{ 1438{
1392 struct inode *dir = data->dir->d_inode; 1439 struct inode *dir = data->dir->d_inode;
1393 struct nfs_server *server = NFS_SERVER(dir); 1440 struct nfs_server *server = NFS_SERVER(dir);
@@ -1414,21 +1461,57 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
1414 data->rpc_done = 0; 1461 data->rpc_done = 0;
1415 data->rpc_status = 0; 1462 data->rpc_status = 0;
1416 data->cancelled = 0; 1463 data->cancelled = 0;
1464 if (isrecover)
1465 task_setup_data.callback_ops = &nfs4_recover_open_ops;
1417 task = rpc_run_task(&task_setup_data); 1466 task = rpc_run_task(&task_setup_data);
1418 if (IS_ERR(task)) 1467 if (IS_ERR(task))
1419 return PTR_ERR(task); 1468 return PTR_ERR(task);
1420 status = nfs4_wait_for_completion_rpc_task(task); 1469 status = nfs4_wait_for_completion_rpc_task(task);
1421 if (status != 0) { 1470 if (status != 0) {
1422 data->cancelled = 1; 1471 data->cancelled = 1;
1423 smp_wmb(); 1472 smp_wmb();
1424 } else 1473 } else
1425 status = data->rpc_status; 1474 status = data->rpc_status;
1426 rpc_put_task(task); 1475 rpc_put_task(task);
1476
1477 return status;
1478}
1479
1480static int _nfs4_recover_proc_open(struct nfs4_opendata *data)
1481{
1482 struct inode *dir = data->dir->d_inode;
1483 struct nfs_openres *o_res = &data->o_res;
1484 int status;
1485
1486 status = nfs4_run_open_task(data, 1);
1427 if (status != 0 || !data->rpc_done) 1487 if (status != 0 || !data->rpc_done)
1428 return status; 1488 return status;
1429 1489
1430 if (o_res->fh.size == 0) 1490 nfs_refresh_inode(dir, o_res->dir_attr);
1431 _nfs4_proc_lookup(dir, o_arg->name, &o_res->fh, o_res->f_attr); 1491
1492 if (o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) {
1493 status = _nfs4_proc_open_confirm(data);
1494 if (status != 0)
1495 return status;
1496 }
1497
1498 return status;
1499}
1500
1501/*
1502 * Note: On error, nfs4_proc_open will free the struct nfs4_opendata
1503 */
1504static int _nfs4_proc_open(struct nfs4_opendata *data)
1505{
1506 struct inode *dir = data->dir->d_inode;
1507 struct nfs_server *server = NFS_SERVER(dir);
1508 struct nfs_openargs *o_arg = &data->o_arg;
1509 struct nfs_openres *o_res = &data->o_res;
1510 int status;
1511
1512 status = nfs4_run_open_task(data, 0);
1513 if (status != 0 || !data->rpc_done)
1514 return status;
1432 1515
1433 if (o_arg->open_flags & O_CREAT) { 1516 if (o_arg->open_flags & O_CREAT) {
1434 update_changeattr(dir, &o_res->cinfo); 1517 update_changeattr(dir, &o_res->cinfo);
@@ -1752,11 +1835,10 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
1752 if (calldata->arg.fmode == 0) 1835 if (calldata->arg.fmode == 0)
1753 break; 1836 break;
1754 default: 1837 default:
1755 if (nfs4_async_handle_error(task, server, state) == -EAGAIN) { 1838 if (nfs4_async_handle_error(task, server, state) == -EAGAIN)
1756 nfs_restart_rpc(task, server->nfs_client); 1839 rpc_restart_call_prepare(task);
1757 return;
1758 }
1759 } 1840 }
1841 nfs_release_seqid(calldata->arg.seqid);
1760 nfs_refresh_inode(calldata->inode, calldata->res.fattr); 1842 nfs_refresh_inode(calldata->inode, calldata->res.fattr);
1761} 1843}
1762 1844
@@ -1848,8 +1930,6 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait)
1848 calldata->state = state; 1930 calldata->state = state;
1849 calldata->arg.fh = NFS_FH(state->inode); 1931 calldata->arg.fh = NFS_FH(state->inode);
1850 calldata->arg.stateid = &state->open_stateid; 1932 calldata->arg.stateid = &state->open_stateid;
1851 if (nfs4_has_session(server->nfs_client))
1852 memset(calldata->arg.stateid->data, 0, 4); /* clear seqid */
1853 /* Serialization for the sequence id */ 1933 /* Serialization for the sequence id */
1854 calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); 1934 calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid);
1855 if (calldata->arg.seqid == NULL) 1935 if (calldata->arg.seqid == NULL)
@@ -3941,6 +4021,12 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
3941 dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status); 4021 dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status);
3942} 4022}
3943 4023
4024static void nfs4_recover_lock_prepare(struct rpc_task *task, void *calldata)
4025{
4026 rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
4027 nfs4_lock_prepare(task, calldata);
4028}
4029
3944static void nfs4_lock_done(struct rpc_task *task, void *calldata) 4030static void nfs4_lock_done(struct rpc_task *task, void *calldata)
3945{ 4031{
3946 struct nfs4_lockdata *data = calldata; 4032 struct nfs4_lockdata *data = calldata;
@@ -3996,7 +4082,13 @@ static const struct rpc_call_ops nfs4_lock_ops = {
3996 .rpc_release = nfs4_lock_release, 4082 .rpc_release = nfs4_lock_release,
3997}; 4083};
3998 4084
3999static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *fl, int reclaim) 4085static const struct rpc_call_ops nfs4_recover_lock_ops = {
4086 .rpc_call_prepare = nfs4_recover_lock_prepare,
4087 .rpc_call_done = nfs4_lock_done,
4088 .rpc_release = nfs4_lock_release,
4089};
4090
4091static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *fl, int recovery_type)
4000{ 4092{
4001 struct nfs4_lockdata *data; 4093 struct nfs4_lockdata *data;
4002 struct rpc_task *task; 4094 struct rpc_task *task;
@@ -4020,8 +4112,11 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f
4020 return -ENOMEM; 4112 return -ENOMEM;
4021 if (IS_SETLKW(cmd)) 4113 if (IS_SETLKW(cmd))
4022 data->arg.block = 1; 4114 data->arg.block = 1;
4023 if (reclaim != 0) 4115 if (recovery_type > NFS_LOCK_NEW) {
4024 data->arg.reclaim = 1; 4116 if (recovery_type == NFS_LOCK_RECLAIM)
4117 data->arg.reclaim = NFS_LOCK_RECLAIM;
4118 task_setup_data.callback_ops = &nfs4_recover_lock_ops;
4119 }
4025 msg.rpc_argp = &data->arg, 4120 msg.rpc_argp = &data->arg,
4026 msg.rpc_resp = &data->res, 4121 msg.rpc_resp = &data->res,
4027 task_setup_data.callback_data = data; 4122 task_setup_data.callback_data = data;
@@ -4048,7 +4143,7 @@ static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request
4048 /* Cache the lock if possible... */ 4143 /* Cache the lock if possible... */
4049 if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0) 4144 if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
4050 return 0; 4145 return 0;
4051 err = _nfs4_do_setlk(state, F_SETLK, request, 1); 4146 err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_RECLAIM);
4052 if (err != -NFS4ERR_DELAY) 4147 if (err != -NFS4ERR_DELAY)
4053 break; 4148 break;
4054 nfs4_handle_exception(server, err, &exception); 4149 nfs4_handle_exception(server, err, &exception);
@@ -4068,7 +4163,7 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request
4068 do { 4163 do {
4069 if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0) 4164 if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
4070 return 0; 4165 return 0;
4071 err = _nfs4_do_setlk(state, F_SETLK, request, 0); 4166 err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_EXPIRED);
4072 switch (err) { 4167 switch (err) {
4073 default: 4168 default:
4074 goto out; 4169 goto out;
@@ -4104,7 +4199,7 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock
4104 status = do_vfs_lock(request->fl_file, request); 4199 status = do_vfs_lock(request->fl_file, request);
4105 goto out_unlock; 4200 goto out_unlock;
4106 } 4201 }
4107 status = _nfs4_do_setlk(state, cmd, request, 0); 4202 status = _nfs4_do_setlk(state, cmd, request, NFS_LOCK_NEW);
4108 if (status != 0) 4203 if (status != 0)
4109 goto out_unlock; 4204 goto out_unlock;
4110 /* Note: we always want to sleep here! */ 4205 /* Note: we always want to sleep here! */
@@ -4187,7 +4282,7 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl)
4187 if (err != 0) 4282 if (err != 0)
4188 goto out; 4283 goto out;
4189 do { 4284 do {
4190 err = _nfs4_do_setlk(state, F_SETLK, fl, 0); 4285 err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW);
4191 switch (err) { 4286 switch (err) {
4192 default: 4287 default:
4193 printk(KERN_ERR "%s: unhandled error %d.\n", 4288 printk(KERN_ERR "%s: unhandled error %d.\n",
@@ -4395,11 +4490,12 @@ static void nfs4_get_lease_time_prepare(struct rpc_task *task,
4395 (struct nfs4_get_lease_time_data *)calldata; 4490 (struct nfs4_get_lease_time_data *)calldata;
4396 4491
4397 dprintk("--> %s\n", __func__); 4492 dprintk("--> %s\n", __func__);
4493 rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
4398 /* just setup sequence, do not trigger session recovery 4494 /* just setup sequence, do not trigger session recovery
4399 since we're invoked within one */ 4495 since we're invoked within one */
4400 ret = nfs41_setup_sequence(data->clp->cl_session, 4496 ret = nfs41_setup_sequence(data->clp->cl_session,
4401 &data->args->la_seq_args, 4497 &data->args->la_seq_args,
4402 &data->res->lr_seq_res, 0, task); 4498 &data->res->lr_seq_res, 0, task);
4403 4499
4404 BUG_ON(ret == -EAGAIN); 4500 BUG_ON(ret == -EAGAIN);
4405 rpc_call_start(task); 4501 rpc_call_start(task);
@@ -4619,7 +4715,7 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp)
4619 tbl = &session->fc_slot_table; 4715 tbl = &session->fc_slot_table;
4620 tbl->highest_used_slotid = -1; 4716 tbl->highest_used_slotid = -1;
4621 spin_lock_init(&tbl->slot_tbl_lock); 4717 spin_lock_init(&tbl->slot_tbl_lock);
4622 rpc_init_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table"); 4718 rpc_init_priority_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table");
4623 4719
4624 tbl = &session->bc_slot_table; 4720 tbl = &session->bc_slot_table;
4625 tbl->highest_used_slotid = -1; 4721 tbl->highest_used_slotid = -1;
@@ -4838,14 +4934,22 @@ int nfs4_init_session(struct nfs_server *server)
4838{ 4934{
4839 struct nfs_client *clp = server->nfs_client; 4935 struct nfs_client *clp = server->nfs_client;
4840 struct nfs4_session *session; 4936 struct nfs4_session *session;
4937 unsigned int rsize, wsize;
4841 int ret; 4938 int ret;
4842 4939
4843 if (!nfs4_has_session(clp)) 4940 if (!nfs4_has_session(clp))
4844 return 0; 4941 return 0;
4845 4942
4943 rsize = server->rsize;
4944 if (rsize == 0)
4945 rsize = NFS_MAX_FILE_IO_SIZE;
4946 wsize = server->wsize;
4947 if (wsize == 0)
4948 wsize = NFS_MAX_FILE_IO_SIZE;
4949
4846 session = clp->cl_session; 4950 session = clp->cl_session;
4847 session->fc_attrs.max_rqst_sz = server->wsize + nfs41_maxwrite_overhead; 4951 session->fc_attrs.max_rqst_sz = wsize + nfs41_maxwrite_overhead;
4848 session->fc_attrs.max_resp_sz = server->rsize + nfs41_maxread_overhead; 4952 session->fc_attrs.max_resp_sz = rsize + nfs41_maxread_overhead;
4849 4953
4850 ret = nfs4_recover_expired_lease(server); 4954 ret = nfs4_recover_expired_lease(server);
4851 if (!ret) 4955 if (!ret)
@@ -4871,7 +4975,7 @@ static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred)
4871 args.sa_cache_this = 0; 4975 args.sa_cache_this = 0;
4872 4976
4873 return nfs4_call_sync_sequence(clp, clp->cl_rpcclient, &msg, &args, 4977 return nfs4_call_sync_sequence(clp, clp->cl_rpcclient, &msg, &args,
4874 &res, 0); 4978 &res, args.sa_cache_this, 1);
4875} 4979}
4876 4980
4877void nfs41_sequence_call_done(struct rpc_task *task, void *data) 4981void nfs41_sequence_call_done(struct rpc_task *task, void *data)
@@ -4953,6 +5057,7 @@ static void nfs4_reclaim_complete_prepare(struct rpc_task *task, void *data)
4953{ 5057{
4954 struct nfs4_reclaim_complete_data *calldata = data; 5058 struct nfs4_reclaim_complete_data *calldata = data;
4955 5059
5060 rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
4956 if (nfs4_setup_sequence(calldata->clp, &calldata->arg.seq_args, 5061 if (nfs4_setup_sequence(calldata->clp, &calldata->arg.seq_args,
4957 &calldata->res.seq_res, 0, task)) 5062 &calldata->res.seq_res, 0, task))
4958 return; 5063 return;
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index e76427e6346f..6d263ed79e92 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -135,16 +135,30 @@ static int nfs41_setup_state_renewal(struct nfs_client *clp)
135 return status; 135 return status;
136} 136}
137 137
138static void nfs41_end_drain_session(struct nfs_client *clp, 138static void nfs4_end_drain_session(struct nfs_client *clp)
139 struct nfs4_session *ses)
140{ 139{
141 if (test_and_clear_bit(NFS4CLNT_SESSION_DRAINING, &clp->cl_state)) 140 struct nfs4_session *ses = clp->cl_session;
142 rpc_wake_up(&ses->fc_slot_table.slot_tbl_waitq); 141 int max_slots;
142
143 if (test_and_clear_bit(NFS4CLNT_SESSION_DRAINING, &clp->cl_state)) {
144 spin_lock(&ses->fc_slot_table.slot_tbl_lock);
145 max_slots = ses->fc_slot_table.max_slots;
146 while (max_slots--) {
147 struct rpc_task *task;
148
149 task = rpc_wake_up_next(&ses->fc_slot_table.
150 slot_tbl_waitq);
151 if (!task)
152 break;
153 rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
154 }
155 spin_unlock(&ses->fc_slot_table.slot_tbl_lock);
156 }
143} 157}
144 158
145static int nfs41_begin_drain_session(struct nfs_client *clp, 159static int nfs4_begin_drain_session(struct nfs_client *clp)
146 struct nfs4_session *ses)
147{ 160{
161 struct nfs4_session *ses = clp->cl_session;
148 struct nfs4_slot_table *tbl = &ses->fc_slot_table; 162 struct nfs4_slot_table *tbl = &ses->fc_slot_table;
149 163
150 spin_lock(&tbl->slot_tbl_lock); 164 spin_lock(&tbl->slot_tbl_lock);
@@ -162,16 +176,13 @@ int nfs41_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)
162{ 176{
163 int status; 177 int status;
164 178
165 status = nfs41_begin_drain_session(clp, clp->cl_session); 179 nfs4_begin_drain_session(clp);
166 if (status != 0)
167 goto out;
168 status = nfs4_proc_exchange_id(clp, cred); 180 status = nfs4_proc_exchange_id(clp, cred);
169 if (status != 0) 181 if (status != 0)
170 goto out; 182 goto out;
171 status = nfs4_proc_create_session(clp); 183 status = nfs4_proc_create_session(clp);
172 if (status != 0) 184 if (status != 0)
173 goto out; 185 goto out;
174 nfs41_end_drain_session(clp, clp->cl_session);
175 nfs41_setup_state_renewal(clp); 186 nfs41_setup_state_renewal(clp);
176 nfs_mark_client_ready(clp, NFS_CS_READY); 187 nfs_mark_client_ready(clp, NFS_CS_READY);
177out: 188out:
@@ -755,16 +766,21 @@ struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter)
755 return new; 766 return new;
756} 767}
757 768
758void nfs_free_seqid(struct nfs_seqid *seqid) 769void nfs_release_seqid(struct nfs_seqid *seqid)
759{ 770{
760 if (!list_empty(&seqid->list)) { 771 if (!list_empty(&seqid->list)) {
761 struct rpc_sequence *sequence = seqid->sequence->sequence; 772 struct rpc_sequence *sequence = seqid->sequence->sequence;
762 773
763 spin_lock(&sequence->lock); 774 spin_lock(&sequence->lock);
764 list_del(&seqid->list); 775 list_del_init(&seqid->list);
765 spin_unlock(&sequence->lock); 776 spin_unlock(&sequence->lock);
766 rpc_wake_up(&sequence->wait); 777 rpc_wake_up(&sequence->wait);
767 } 778 }
779}
780
781void nfs_free_seqid(struct nfs_seqid *seqid)
782{
783 nfs_release_seqid(seqid);
768 kfree(seqid); 784 kfree(seqid);
769} 785}
770 786
@@ -1257,13 +1273,9 @@ void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags)
1257 1273
1258static int nfs4_reset_session(struct nfs_client *clp) 1274static int nfs4_reset_session(struct nfs_client *clp)
1259{ 1275{
1260 struct nfs4_session *ses = clp->cl_session;
1261 int status; 1276 int status;
1262 1277
1263 status = nfs41_begin_drain_session(clp, ses); 1278 nfs4_begin_drain_session(clp);
1264 if (status != 0)
1265 return status;
1266
1267 status = nfs4_proc_destroy_session(clp->cl_session); 1279 status = nfs4_proc_destroy_session(clp->cl_session);
1268 if (status && status != -NFS4ERR_BADSESSION && 1280 if (status && status != -NFS4ERR_BADSESSION &&
1269 status != -NFS4ERR_DEADSESSION) { 1281 status != -NFS4ERR_DEADSESSION) {
@@ -1279,19 +1291,17 @@ static int nfs4_reset_session(struct nfs_client *clp)
1279out: 1291out:
1280 /* 1292 /*
1281 * Let the state manager reestablish state 1293 * Let the state manager reestablish state
1282 * without waking other tasks yet.
1283 */ 1294 */
1284 if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) { 1295 if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) &&
1285 /* Wake up the next rpc task */ 1296 status == 0)
1286 nfs41_end_drain_session(clp, ses); 1297 nfs41_setup_state_renewal(clp);
1287 if (status == 0) 1298
1288 nfs41_setup_state_renewal(clp);
1289 }
1290 return status; 1299 return status;
1291} 1300}
1292 1301
1293#else /* CONFIG_NFS_V4_1 */ 1302#else /* CONFIG_NFS_V4_1 */
1294static int nfs4_reset_session(struct nfs_client *clp) { return 0; } 1303static int nfs4_reset_session(struct nfs_client *clp) { return 0; }
1304static int nfs4_end_drain_session(struct nfs_client *clp) { return 0; }
1295#endif /* CONFIG_NFS_V4_1 */ 1305#endif /* CONFIG_NFS_V4_1 */
1296 1306
1297/* Set NFS4CLNT_LEASE_EXPIRED for all v4.0 errors and for recoverable errors 1307/* Set NFS4CLNT_LEASE_EXPIRED for all v4.0 errors and for recoverable errors
@@ -1382,6 +1392,7 @@ static void nfs4_state_manager(struct nfs_client *clp)
1382 goto out_error; 1392 goto out_error;
1383 } 1393 }
1384 1394
1395 nfs4_end_drain_session(clp);
1385 if (test_and_clear_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) { 1396 if (test_and_clear_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) {
1386 nfs_client_return_marked_delegations(clp); 1397 nfs_client_return_marked_delegations(clp);
1387 continue; 1398 continue;
@@ -1398,6 +1409,7 @@ static void nfs4_state_manager(struct nfs_client *clp)
1398out_error: 1409out_error:
1399 printk(KERN_WARNING "Error: state manager failed on NFSv4 server %s" 1410 printk(KERN_WARNING "Error: state manager failed on NFSv4 server %s"
1400 " with error %d\n", clp->cl_hostname, -status); 1411 " with error %d\n", clp->cl_hostname, -status);
1412 nfs4_end_drain_session(clp);
1401 nfs4_clear_state_manager_bit(clp); 1413 nfs4_clear_state_manager_bit(clp);
1402} 1414}
1403 1415
diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h
index 1906782ec86b..7bc7fd5291ce 100644
--- a/include/linux/sunrpc/sched.h
+++ b/include/linux/sunrpc/sched.h
@@ -173,7 +173,8 @@ struct rpc_task_setup {
173#define RPC_PRIORITY_LOW (-1) 173#define RPC_PRIORITY_LOW (-1)
174#define RPC_PRIORITY_NORMAL (0) 174#define RPC_PRIORITY_NORMAL (0)
175#define RPC_PRIORITY_HIGH (1) 175#define RPC_PRIORITY_HIGH (1)
176#define RPC_NR_PRIORITY (1 + RPC_PRIORITY_HIGH - RPC_PRIORITY_LOW) 176#define RPC_PRIORITY_PRIVILEGED (2)
177#define RPC_NR_PRIORITY (1 + RPC_PRIORITY_PRIVILEGED - RPC_PRIORITY_LOW)
177 178
178struct rpc_timer { 179struct rpc_timer {
179 struct timer_list timer; 180 struct timer_list timer;
@@ -229,6 +230,7 @@ void rpc_wake_up_queued_task(struct rpc_wait_queue *,
229void rpc_wake_up(struct rpc_wait_queue *); 230void rpc_wake_up(struct rpc_wait_queue *);
230struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *); 231struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *);
231void rpc_wake_up_status(struct rpc_wait_queue *, int); 232void rpc_wake_up_status(struct rpc_wait_queue *, int);
233int rpc_queue_empty(struct rpc_wait_queue *);
232void rpc_delay(struct rpc_task *, unsigned long); 234void rpc_delay(struct rpc_task *, unsigned long);
233void * rpc_malloc(struct rpc_task *, size_t); 235void * rpc_malloc(struct rpc_task *, size_t);
234void rpc_free(void *); 236void rpc_free(void *);
@@ -254,6 +256,16 @@ static inline int rpc_wait_for_completion_task(struct rpc_task *task)
254 return __rpc_wait_for_completion_task(task, NULL); 256 return __rpc_wait_for_completion_task(task, NULL);
255} 257}
256 258
259static inline void rpc_task_set_priority(struct rpc_task *task, unsigned char prio)
260{
261 task->tk_priority = prio - RPC_PRIORITY_LOW;
262}
263
264static inline int rpc_task_has_priority(struct rpc_task *task, unsigned char prio)
265{
266 return (task->tk_priority + RPC_PRIORITY_LOW == prio);
267}
268
257#ifdef RPC_DEBUG 269#ifdef RPC_DEBUG
258static inline const char * rpc_qname(struct rpc_wait_queue *q) 270static inline const char * rpc_qname(struct rpc_wait_queue *q)
259{ 271{
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index cef74ba0666c..aae6907fd546 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -210,6 +210,7 @@ void rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qnam
210{ 210{
211 __rpc_init_priority_wait_queue(queue, qname, RPC_NR_PRIORITY); 211 __rpc_init_priority_wait_queue(queue, qname, RPC_NR_PRIORITY);
212} 212}
213EXPORT_SYMBOL_GPL(rpc_init_priority_wait_queue);
213 214
214void rpc_init_wait_queue(struct rpc_wait_queue *queue, const char *qname) 215void rpc_init_wait_queue(struct rpc_wait_queue *queue, const char *qname)
215{ 216{
@@ -385,6 +386,20 @@ static void rpc_wake_up_task_queue_locked(struct rpc_wait_queue *queue, struct r
385} 386}
386 387
387/* 388/*
389 * Tests whether rpc queue is empty
390 */
391int rpc_queue_empty(struct rpc_wait_queue *queue)
392{
393 int res;
394
395 spin_lock_bh(&queue->lock);
396 res = queue->qlen;
397 spin_unlock_bh(&queue->lock);
398 return (res == 0);
399}
400EXPORT_SYMBOL_GPL(rpc_queue_empty);
401
402/*
388 * Wake up a task on a specific queue 403 * Wake up a task on a specific queue
389 */ 404 */
390void rpc_wake_up_queued_task(struct rpc_wait_queue *queue, struct rpc_task *task) 405void rpc_wake_up_queued_task(struct rpc_wait_queue *queue, struct rpc_task *task)