diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-12-20 14:31:56 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-12-20 14:31:56 -0500 |
commit | 822a5d313197c059924d394e6851be3cb312caa7 (patch) | |
tree | 7f93e12fc7f204f3ef6856e4912f2c5d0856ffdd | |
parent | 929e8d4a888cd15df486e5964c8e2021581a8a0f (diff) | |
parent | 6c52961743f38747401b47127b82159ab6d8a7a4 (diff) |
Merge branch 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
* 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
NFS: Fix a regression in nfs_file_llseek()
NFSv4: Do not accept delegated opens when a delegation recall is in effect
NFSv4: Ensure correct locking when accessing the 'lock_states' list
NFSv4.1: Ensure that we handle _all_ SEQUENCE status bits.
NFSv4: Don't error if we handled it in nfs4_recovery_handle_error
SUNRPC: Ensure we always bump the backlog queue in xprt_free_slot
SUNRPC: Fix the execution time statistics in the face of RPC restarts
-rw-r--r-- | fs/nfs/file.c | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 24 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 33 | ||||
-rw-r--r-- | net/sunrpc/sched.c | 30 | ||||
-rw-r--r-- | net/sunrpc/xprt.c | 10 |
5 files changed, 65 insertions, 34 deletions
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index eca56d4b39c0..606ef0f20aed 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -147,7 +147,7 @@ static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin) | |||
147 | * origin == SEEK_END || SEEK_DATA || SEEK_HOLE => we must revalidate | 147 | * origin == SEEK_END || SEEK_DATA || SEEK_HOLE => we must revalidate |
148 | * the cached file length | 148 | * the cached file length |
149 | */ | 149 | */ |
150 | if (origin != SEEK_SET || origin != SEEK_CUR) { | 150 | if (origin != SEEK_SET && origin != SEEK_CUR) { |
151 | struct inode *inode = filp->f_mapping->host; | 151 | struct inode *inode = filp->f_mapping->host; |
152 | 152 | ||
153 | int retval = nfs_revalidate_file_size(inode, filp); | 153 | int retval = nfs_revalidate_file_size(inode, filp); |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index be2bbac13817..d9f4d78c3413 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -39,6 +39,8 @@ | |||
39 | #include <linux/delay.h> | 39 | #include <linux/delay.h> |
40 | #include <linux/errno.h> | 40 | #include <linux/errno.h> |
41 | #include <linux/string.h> | 41 | #include <linux/string.h> |
42 | #include <linux/ratelimit.h> | ||
43 | #include <linux/printk.h> | ||
42 | #include <linux/slab.h> | 44 | #include <linux/slab.h> |
43 | #include <linux/sunrpc/clnt.h> | 45 | #include <linux/sunrpc/clnt.h> |
44 | #include <linux/sunrpc/gss_api.h> | 46 | #include <linux/sunrpc/gss_api.h> |
@@ -894,6 +896,8 @@ out: | |||
894 | 896 | ||
895 | static int can_open_delegated(struct nfs_delegation *delegation, fmode_t fmode) | 897 | static int can_open_delegated(struct nfs_delegation *delegation, fmode_t fmode) |
896 | { | 898 | { |
899 | if (delegation == NULL) | ||
900 | return 0; | ||
897 | if ((delegation->type & fmode) != fmode) | 901 | if ((delegation->type & fmode) != fmode) |
898 | return 0; | 902 | return 0; |
899 | if (test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags)) | 903 | if (test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags)) |
@@ -1036,8 +1040,7 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata) | |||
1036 | } | 1040 | } |
1037 | rcu_read_lock(); | 1041 | rcu_read_lock(); |
1038 | delegation = rcu_dereference(nfsi->delegation); | 1042 | delegation = rcu_dereference(nfsi->delegation); |
1039 | if (delegation == NULL || | 1043 | if (!can_open_delegated(delegation, fmode)) { |
1040 | !can_open_delegated(delegation, fmode)) { | ||
1041 | rcu_read_unlock(); | 1044 | rcu_read_unlock(); |
1042 | break; | 1045 | break; |
1043 | } | 1046 | } |
@@ -1091,7 +1094,12 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data | |||
1091 | if (delegation) | 1094 | if (delegation) |
1092 | delegation_flags = delegation->flags; | 1095 | delegation_flags = delegation->flags; |
1093 | rcu_read_unlock(); | 1096 | rcu_read_unlock(); |
1094 | if ((delegation_flags & 1UL<<NFS_DELEGATION_NEED_RECLAIM) == 0) | 1097 | if (data->o_arg.claim == NFS4_OPEN_CLAIM_DELEGATE_CUR) { |
1098 | pr_err_ratelimited("NFS: Broken NFSv4 server %s is " | ||
1099 | "returning a delegation for " | ||
1100 | "OPEN(CLAIM_DELEGATE_CUR)\n", | ||
1101 | NFS_CLIENT(inode)->cl_server); | ||
1102 | } else if ((delegation_flags & 1UL<<NFS_DELEGATION_NEED_RECLAIM) == 0) | ||
1095 | nfs_inode_set_delegation(state->inode, | 1103 | nfs_inode_set_delegation(state->inode, |
1096 | data->owner->so_cred, | 1104 | data->owner->so_cred, |
1097 | &data->o_res); | 1105 | &data->o_res); |
@@ -1423,11 +1431,9 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) | |||
1423 | goto out_no_action; | 1431 | goto out_no_action; |
1424 | rcu_read_lock(); | 1432 | rcu_read_lock(); |
1425 | delegation = rcu_dereference(NFS_I(data->state->inode)->delegation); | 1433 | delegation = rcu_dereference(NFS_I(data->state->inode)->delegation); |
1426 | if (delegation != NULL && | 1434 | if (data->o_arg.claim != NFS4_OPEN_CLAIM_DELEGATE_CUR && |
1427 | test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags) == 0) { | 1435 | can_open_delegated(delegation, data->o_arg.fmode)) |
1428 | rcu_read_unlock(); | 1436 | goto unlock_no_action; |
1429 | goto out_no_action; | ||
1430 | } | ||
1431 | rcu_read_unlock(); | 1437 | rcu_read_unlock(); |
1432 | } | 1438 | } |
1433 | /* Update sequence id. */ | 1439 | /* Update sequence id. */ |
@@ -1444,6 +1450,8 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) | |||
1444 | return; | 1450 | return; |
1445 | rpc_call_start(task); | 1451 | rpc_call_start(task); |
1446 | return; | 1452 | return; |
1453 | unlock_no_action: | ||
1454 | rcu_read_unlock(); | ||
1447 | out_no_action: | 1455 | out_no_action: |
1448 | task->tk_action = NULL; | 1456 | task->tk_action = NULL; |
1449 | 1457 | ||
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 39914be40b03..6a7107ae6b72 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -1156,11 +1156,13 @@ restart: | |||
1156 | if (status >= 0) { | 1156 | if (status >= 0) { |
1157 | status = nfs4_reclaim_locks(state, ops); | 1157 | status = nfs4_reclaim_locks(state, ops); |
1158 | if (status >= 0) { | 1158 | if (status >= 0) { |
1159 | spin_lock(&state->state_lock); | ||
1159 | list_for_each_entry(lock, &state->lock_states, ls_locks) { | 1160 | list_for_each_entry(lock, &state->lock_states, ls_locks) { |
1160 | if (!(lock->ls_flags & NFS_LOCK_INITIALIZED)) | 1161 | if (!(lock->ls_flags & NFS_LOCK_INITIALIZED)) |
1161 | printk("%s: Lock reclaim failed!\n", | 1162 | printk("%s: Lock reclaim failed!\n", |
1162 | __func__); | 1163 | __func__); |
1163 | } | 1164 | } |
1165 | spin_unlock(&state->state_lock); | ||
1164 | nfs4_put_open_state(state); | 1166 | nfs4_put_open_state(state); |
1165 | goto restart; | 1167 | goto restart; |
1166 | } | 1168 | } |
@@ -1224,10 +1226,12 @@ static void nfs4_clear_open_state(struct nfs4_state *state) | |||
1224 | clear_bit(NFS_O_RDONLY_STATE, &state->flags); | 1226 | clear_bit(NFS_O_RDONLY_STATE, &state->flags); |
1225 | clear_bit(NFS_O_WRONLY_STATE, &state->flags); | 1227 | clear_bit(NFS_O_WRONLY_STATE, &state->flags); |
1226 | clear_bit(NFS_O_RDWR_STATE, &state->flags); | 1228 | clear_bit(NFS_O_RDWR_STATE, &state->flags); |
1229 | spin_lock(&state->state_lock); | ||
1227 | list_for_each_entry(lock, &state->lock_states, ls_locks) { | 1230 | list_for_each_entry(lock, &state->lock_states, ls_locks) { |
1228 | lock->ls_seqid.flags = 0; | 1231 | lock->ls_seqid.flags = 0; |
1229 | lock->ls_flags &= ~NFS_LOCK_INITIALIZED; | 1232 | lock->ls_flags &= ~NFS_LOCK_INITIALIZED; |
1230 | } | 1233 | } |
1234 | spin_unlock(&state->state_lock); | ||
1231 | } | 1235 | } |
1232 | 1236 | ||
1233 | static void nfs4_reset_seqids(struct nfs_server *server, | 1237 | static void nfs4_reset_seqids(struct nfs_server *server, |
@@ -1350,12 +1354,14 @@ static void nfs4_warn_keyexpired(const char *s) | |||
1350 | static int nfs4_recovery_handle_error(struct nfs_client *clp, int error) | 1354 | static int nfs4_recovery_handle_error(struct nfs_client *clp, int error) |
1351 | { | 1355 | { |
1352 | switch (error) { | 1356 | switch (error) { |
1357 | case 0: | ||
1358 | break; | ||
1353 | case -NFS4ERR_CB_PATH_DOWN: | 1359 | case -NFS4ERR_CB_PATH_DOWN: |
1354 | nfs_handle_cb_pathdown(clp); | 1360 | nfs_handle_cb_pathdown(clp); |
1355 | return 0; | 1361 | break; |
1356 | case -NFS4ERR_NO_GRACE: | 1362 | case -NFS4ERR_NO_GRACE: |
1357 | nfs4_state_end_reclaim_reboot(clp); | 1363 | nfs4_state_end_reclaim_reboot(clp); |
1358 | return 0; | 1364 | break; |
1359 | case -NFS4ERR_STALE_CLIENTID: | 1365 | case -NFS4ERR_STALE_CLIENTID: |
1360 | case -NFS4ERR_LEASE_MOVED: | 1366 | case -NFS4ERR_LEASE_MOVED: |
1361 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | 1367 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); |
@@ -1375,13 +1381,15 @@ static int nfs4_recovery_handle_error(struct nfs_client *clp, int error) | |||
1375 | case -NFS4ERR_SEQ_MISORDERED: | 1381 | case -NFS4ERR_SEQ_MISORDERED: |
1376 | set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state); | 1382 | set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state); |
1377 | /* Zero session reset errors */ | 1383 | /* Zero session reset errors */ |
1378 | return 0; | 1384 | break; |
1379 | case -EKEYEXPIRED: | 1385 | case -EKEYEXPIRED: |
1380 | /* Nothing we can do */ | 1386 | /* Nothing we can do */ |
1381 | nfs4_warn_keyexpired(clp->cl_hostname); | 1387 | nfs4_warn_keyexpired(clp->cl_hostname); |
1382 | return 0; | 1388 | break; |
1389 | default: | ||
1390 | return error; | ||
1383 | } | 1391 | } |
1384 | return error; | 1392 | return 0; |
1385 | } | 1393 | } |
1386 | 1394 | ||
1387 | static int nfs4_do_reclaim(struct nfs_client *clp, const struct nfs4_state_recovery_ops *ops) | 1395 | static int nfs4_do_reclaim(struct nfs_client *clp, const struct nfs4_state_recovery_ops *ops) |
@@ -1428,7 +1436,7 @@ static int nfs4_check_lease(struct nfs_client *clp) | |||
1428 | struct rpc_cred *cred; | 1436 | struct rpc_cred *cred; |
1429 | const struct nfs4_state_maintenance_ops *ops = | 1437 | const struct nfs4_state_maintenance_ops *ops = |
1430 | clp->cl_mvops->state_renewal_ops; | 1438 | clp->cl_mvops->state_renewal_ops; |
1431 | int status = -NFS4ERR_EXPIRED; | 1439 | int status; |
1432 | 1440 | ||
1433 | /* Is the client already known to have an expired lease? */ | 1441 | /* Is the client already known to have an expired lease? */ |
1434 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) | 1442 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) |
@@ -1438,6 +1446,7 @@ static int nfs4_check_lease(struct nfs_client *clp) | |||
1438 | spin_unlock(&clp->cl_lock); | 1446 | spin_unlock(&clp->cl_lock); |
1439 | if (cred == NULL) { | 1447 | if (cred == NULL) { |
1440 | cred = nfs4_get_setclientid_cred(clp); | 1448 | cred = nfs4_get_setclientid_cred(clp); |
1449 | status = -ENOKEY; | ||
1441 | if (cred == NULL) | 1450 | if (cred == NULL) |
1442 | goto out; | 1451 | goto out; |
1443 | } | 1452 | } |
@@ -1525,16 +1534,16 @@ void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags) | |||
1525 | { | 1534 | { |
1526 | if (!flags) | 1535 | if (!flags) |
1527 | return; | 1536 | return; |
1528 | else if (flags & SEQ4_STATUS_RESTART_RECLAIM_NEEDED) | 1537 | if (flags & SEQ4_STATUS_RESTART_RECLAIM_NEEDED) |
1529 | nfs41_handle_server_reboot(clp); | 1538 | nfs41_handle_server_reboot(clp); |
1530 | else if (flags & (SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED | | 1539 | if (flags & (SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED | |
1531 | SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED | | 1540 | SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED | |
1532 | SEQ4_STATUS_ADMIN_STATE_REVOKED | | 1541 | SEQ4_STATUS_ADMIN_STATE_REVOKED | |
1533 | SEQ4_STATUS_LEASE_MOVED)) | 1542 | SEQ4_STATUS_LEASE_MOVED)) |
1534 | nfs41_handle_state_revoked(clp); | 1543 | nfs41_handle_state_revoked(clp); |
1535 | else if (flags & SEQ4_STATUS_RECALLABLE_STATE_REVOKED) | 1544 | if (flags & SEQ4_STATUS_RECALLABLE_STATE_REVOKED) |
1536 | nfs41_handle_recallable_state_revoked(clp); | 1545 | nfs41_handle_recallable_state_revoked(clp); |
1537 | else if (flags & (SEQ4_STATUS_CB_PATH_DOWN | | 1546 | if (flags & (SEQ4_STATUS_CB_PATH_DOWN | |
1538 | SEQ4_STATUS_BACKCHANNEL_FAULT | | 1547 | SEQ4_STATUS_BACKCHANNEL_FAULT | |
1539 | SEQ4_STATUS_CB_PATH_DOWN_SESSION)) | 1548 | SEQ4_STATUS_CB_PATH_DOWN_SESSION)) |
1540 | nfs41_handle_cb_path_down(clp); | 1549 | nfs41_handle_cb_path_down(clp); |
@@ -1662,10 +1671,10 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
1662 | 1671 | ||
1663 | if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) { | 1672 | if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) { |
1664 | status = nfs4_check_lease(clp); | 1673 | status = nfs4_check_lease(clp); |
1674 | if (status < 0) | ||
1675 | goto out_error; | ||
1665 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) | 1676 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) |
1666 | continue; | 1677 | continue; |
1667 | if (status < 0 && status != -NFS4ERR_CB_PATH_DOWN) | ||
1668 | goto out_error; | ||
1669 | } | 1678 | } |
1670 | 1679 | ||
1671 | /* Initialize or reset the session */ | 1680 | /* Initialize or reset the session */ |
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index d12ffa545811..00a1a2acd587 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c | |||
@@ -590,6 +590,27 @@ void rpc_prepare_task(struct rpc_task *task) | |||
590 | task->tk_ops->rpc_call_prepare(task, task->tk_calldata); | 590 | task->tk_ops->rpc_call_prepare(task, task->tk_calldata); |
591 | } | 591 | } |
592 | 592 | ||
593 | static void | ||
594 | rpc_init_task_statistics(struct rpc_task *task) | ||
595 | { | ||
596 | /* Initialize retry counters */ | ||
597 | task->tk_garb_retry = 2; | ||
598 | task->tk_cred_retry = 2; | ||
599 | task->tk_rebind_retry = 2; | ||
600 | |||
601 | /* starting timestamp */ | ||
602 | task->tk_start = ktime_get(); | ||
603 | } | ||
604 | |||
605 | static void | ||
606 | rpc_reset_task_statistics(struct rpc_task *task) | ||
607 | { | ||
608 | task->tk_timeouts = 0; | ||
609 | task->tk_flags &= ~(RPC_CALL_MAJORSEEN|RPC_TASK_KILLED|RPC_TASK_SENT); | ||
610 | |||
611 | rpc_init_task_statistics(task); | ||
612 | } | ||
613 | |||
593 | /* | 614 | /* |
594 | * Helper that calls task->tk_ops->rpc_call_done if it exists | 615 | * Helper that calls task->tk_ops->rpc_call_done if it exists |
595 | */ | 616 | */ |
@@ -602,6 +623,7 @@ void rpc_exit_task(struct rpc_task *task) | |||
602 | WARN_ON(RPC_ASSASSINATED(task)); | 623 | WARN_ON(RPC_ASSASSINATED(task)); |
603 | /* Always release the RPC slot and buffer memory */ | 624 | /* Always release the RPC slot and buffer memory */ |
604 | xprt_release(task); | 625 | xprt_release(task); |
626 | rpc_reset_task_statistics(task); | ||
605 | } | 627 | } |
606 | } | 628 | } |
607 | } | 629 | } |
@@ -804,11 +826,6 @@ static void rpc_init_task(struct rpc_task *task, const struct rpc_task_setup *ta | |||
804 | task->tk_calldata = task_setup_data->callback_data; | 826 | task->tk_calldata = task_setup_data->callback_data; |
805 | INIT_LIST_HEAD(&task->tk_task); | 827 | INIT_LIST_HEAD(&task->tk_task); |
806 | 828 | ||
807 | /* Initialize retry counters */ | ||
808 | task->tk_garb_retry = 2; | ||
809 | task->tk_cred_retry = 2; | ||
810 | task->tk_rebind_retry = 2; | ||
811 | |||
812 | task->tk_priority = task_setup_data->priority - RPC_PRIORITY_LOW; | 829 | task->tk_priority = task_setup_data->priority - RPC_PRIORITY_LOW; |
813 | task->tk_owner = current->tgid; | 830 | task->tk_owner = current->tgid; |
814 | 831 | ||
@@ -818,8 +835,7 @@ static void rpc_init_task(struct rpc_task *task, const struct rpc_task_setup *ta | |||
818 | if (task->tk_ops->rpc_call_prepare != NULL) | 835 | if (task->tk_ops->rpc_call_prepare != NULL) |
819 | task->tk_action = rpc_prepare_task; | 836 | task->tk_action = rpc_prepare_task; |
820 | 837 | ||
821 | /* starting timestamp */ | 838 | rpc_init_task_statistics(task); |
822 | task->tk_start = ktime_get(); | ||
823 | 839 | ||
824 | dprintk("RPC: new task initialized, procpid %u\n", | 840 | dprintk("RPC: new task initialized, procpid %u\n", |
825 | task_pid_nr(current)); | 841 | task_pid_nr(current)); |
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index f4385e45a5fc..c64c0ef519b5 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
@@ -995,13 +995,11 @@ out_init_req: | |||
995 | 995 | ||
996 | static void xprt_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req) | 996 | static void xprt_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req) |
997 | { | 997 | { |
998 | if (xprt_dynamic_free_slot(xprt, req)) | ||
999 | return; | ||
1000 | |||
1001 | memset(req, 0, sizeof(*req)); /* mark unused */ | ||
1002 | |||
1003 | spin_lock(&xprt->reserve_lock); | 998 | spin_lock(&xprt->reserve_lock); |
1004 | list_add(&req->rq_list, &xprt->free); | 999 | if (!xprt_dynamic_free_slot(xprt, req)) { |
1000 | memset(req, 0, sizeof(*req)); /* mark unused */ | ||
1001 | list_add(&req->rq_list, &xprt->free); | ||
1002 | } | ||
1005 | rpc_wake_up_next(&xprt->backlog); | 1003 | rpc_wake_up_next(&xprt->backlog); |
1006 | spin_unlock(&xprt->reserve_lock); | 1004 | spin_unlock(&xprt->reserve_lock); |
1007 | } | 1005 | } |