diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-03-09 22:17:39 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-03-09 22:17:39 -0400 |
commit | fe9ea91cde29125a3417890678f4d886cec4a71e (patch) | |
tree | ce185a1ef9aedd59a5230e40158cf93559d3db9d /fs/nfs | |
parent | cf8bf7cd13804fcb87b5f9ad026d5b823873e8cc (diff) | |
parent | 2ca310fc4160ed0420da65534a21ae77b24326a8 (diff) |
Merge tag 'nfs-for-3.14-5' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client bugfixes from Trond Myklebust:
"Highlights include:
- Fix another nfs4_sequence corruptor in RELEASE_LOCKOWNER
- Fix an Oopsable delegation callback race
- Fix another bad stateid infinite loop
- Fail the data server I/O is the stateid represents a lost lock
- Fix an Oopsable sunrpc trace event"
* tag 'nfs-for-3.14-5' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
SUNRPC: Fix oops when trace sunrpc_task events in nfs client
NFSv4: Fail the truncate() if the lock/open stateid is invalid
NFSv4.1 Fail data server I/O if stateid represents a lost lock
NFSv4: Fix the return value of nfs4_select_rw_stateid
NFSv4: nfs4_stateid_is_current should return 'true' for an invalid stateid
NFS: Fix a delegation callback race
NFSv4: Fix another nfs4_sequence corruptor
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/delegation.c | 11 | ||||
-rw-r--r-- | fs/nfs/nfs4filelayout.c | 10 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 24 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 14 |
4 files changed, 30 insertions, 29 deletions
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index ef792f29f831..5d8ccecf5f5c 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
@@ -659,16 +659,19 @@ int nfs_async_inode_return_delegation(struct inode *inode, | |||
659 | 659 | ||
660 | rcu_read_lock(); | 660 | rcu_read_lock(); |
661 | delegation = rcu_dereference(NFS_I(inode)->delegation); | 661 | delegation = rcu_dereference(NFS_I(inode)->delegation); |
662 | if (delegation == NULL) | ||
663 | goto out_enoent; | ||
662 | 664 | ||
663 | if (!clp->cl_mvops->match_stateid(&delegation->stateid, stateid)) { | 665 | if (!clp->cl_mvops->match_stateid(&delegation->stateid, stateid)) |
664 | rcu_read_unlock(); | 666 | goto out_enoent; |
665 | return -ENOENT; | ||
666 | } | ||
667 | nfs_mark_return_delegation(server, delegation); | 667 | nfs_mark_return_delegation(server, delegation); |
668 | rcu_read_unlock(); | 668 | rcu_read_unlock(); |
669 | 669 | ||
670 | nfs_delegation_run_state_manager(clp); | 670 | nfs_delegation_run_state_manager(clp); |
671 | return 0; | 671 | return 0; |
672 | out_enoent: | ||
673 | rcu_read_unlock(); | ||
674 | return -ENOENT; | ||
672 | } | 675 | } |
673 | 676 | ||
674 | static struct inode * | 677 | static struct inode * |
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index 12c8132ad408..b9a35c05b60f 100644 --- a/fs/nfs/nfs4filelayout.c +++ b/fs/nfs/nfs4filelayout.c | |||
@@ -324,8 +324,9 @@ static void filelayout_read_prepare(struct rpc_task *task, void *data) | |||
324 | &rdata->res.seq_res, | 324 | &rdata->res.seq_res, |
325 | task)) | 325 | task)) |
326 | return; | 326 | return; |
327 | nfs4_set_rw_stateid(&rdata->args.stateid, rdata->args.context, | 327 | if (nfs4_set_rw_stateid(&rdata->args.stateid, rdata->args.context, |
328 | rdata->args.lock_context, FMODE_READ); | 328 | rdata->args.lock_context, FMODE_READ) == -EIO) |
329 | rpc_exit(task, -EIO); /* lost lock, terminate I/O */ | ||
329 | } | 330 | } |
330 | 331 | ||
331 | static void filelayout_read_call_done(struct rpc_task *task, void *data) | 332 | static void filelayout_read_call_done(struct rpc_task *task, void *data) |
@@ -435,8 +436,9 @@ static void filelayout_write_prepare(struct rpc_task *task, void *data) | |||
435 | &wdata->res.seq_res, | 436 | &wdata->res.seq_res, |
436 | task)) | 437 | task)) |
437 | return; | 438 | return; |
438 | nfs4_set_rw_stateid(&wdata->args.stateid, wdata->args.context, | 439 | if (nfs4_set_rw_stateid(&wdata->args.stateid, wdata->args.context, |
439 | wdata->args.lock_context, FMODE_WRITE); | 440 | wdata->args.lock_context, FMODE_WRITE) == -EIO) |
441 | rpc_exit(task, -EIO); /* lost lock, terminate I/O */ | ||
440 | } | 442 | } |
441 | 443 | ||
442 | static void filelayout_write_call_done(struct rpc_task *task, void *data) | 444 | static void filelayout_write_call_done(struct rpc_task *task, void *data) |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 2da6a698b8f7..450bfedbe2f4 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -2398,13 +2398,16 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, | |||
2398 | 2398 | ||
2399 | if (nfs4_copy_delegation_stateid(&arg.stateid, inode, fmode)) { | 2399 | if (nfs4_copy_delegation_stateid(&arg.stateid, inode, fmode)) { |
2400 | /* Use that stateid */ | 2400 | /* Use that stateid */ |
2401 | } else if (truncate && state != NULL && nfs4_valid_open_stateid(state)) { | 2401 | } else if (truncate && state != NULL) { |
2402 | struct nfs_lockowner lockowner = { | 2402 | struct nfs_lockowner lockowner = { |
2403 | .l_owner = current->files, | 2403 | .l_owner = current->files, |
2404 | .l_pid = current->tgid, | 2404 | .l_pid = current->tgid, |
2405 | }; | 2405 | }; |
2406 | nfs4_select_rw_stateid(&arg.stateid, state, FMODE_WRITE, | 2406 | if (!nfs4_valid_open_stateid(state)) |
2407 | &lockowner); | 2407 | return -EBADF; |
2408 | if (nfs4_select_rw_stateid(&arg.stateid, state, FMODE_WRITE, | ||
2409 | &lockowner) == -EIO) | ||
2410 | return -EBADF; | ||
2408 | } else | 2411 | } else |
2409 | nfs4_stateid_copy(&arg.stateid, &zero_stateid); | 2412 | nfs4_stateid_copy(&arg.stateid, &zero_stateid); |
2410 | 2413 | ||
@@ -4011,8 +4014,9 @@ static bool nfs4_stateid_is_current(nfs4_stateid *stateid, | |||
4011 | { | 4014 | { |
4012 | nfs4_stateid current_stateid; | 4015 | nfs4_stateid current_stateid; |
4013 | 4016 | ||
4014 | if (nfs4_set_rw_stateid(¤t_stateid, ctx, l_ctx, fmode)) | 4017 | /* If the current stateid represents a lost lock, then exit */ |
4015 | return false; | 4018 | if (nfs4_set_rw_stateid(¤t_stateid, ctx, l_ctx, fmode) == -EIO) |
4019 | return true; | ||
4016 | return nfs4_stateid_match(stateid, ¤t_stateid); | 4020 | return nfs4_stateid_match(stateid, ¤t_stateid); |
4017 | } | 4021 | } |
4018 | 4022 | ||
@@ -5828,8 +5832,7 @@ struct nfs_release_lockowner_data { | |||
5828 | struct nfs4_lock_state *lsp; | 5832 | struct nfs4_lock_state *lsp; |
5829 | struct nfs_server *server; | 5833 | struct nfs_server *server; |
5830 | struct nfs_release_lockowner_args args; | 5834 | struct nfs_release_lockowner_args args; |
5831 | struct nfs4_sequence_args seq_args; | 5835 | struct nfs_release_lockowner_res res; |
5832 | struct nfs4_sequence_res seq_res; | ||
5833 | unsigned long timestamp; | 5836 | unsigned long timestamp; |
5834 | }; | 5837 | }; |
5835 | 5838 | ||
@@ -5837,7 +5840,7 @@ static void nfs4_release_lockowner_prepare(struct rpc_task *task, void *calldata | |||
5837 | { | 5840 | { |
5838 | struct nfs_release_lockowner_data *data = calldata; | 5841 | struct nfs_release_lockowner_data *data = calldata; |
5839 | nfs40_setup_sequence(data->server, | 5842 | nfs40_setup_sequence(data->server, |
5840 | &data->seq_args, &data->seq_res, task); | 5843 | &data->args.seq_args, &data->res.seq_res, task); |
5841 | data->timestamp = jiffies; | 5844 | data->timestamp = jiffies; |
5842 | } | 5845 | } |
5843 | 5846 | ||
@@ -5846,7 +5849,7 @@ static void nfs4_release_lockowner_done(struct rpc_task *task, void *calldata) | |||
5846 | struct nfs_release_lockowner_data *data = calldata; | 5849 | struct nfs_release_lockowner_data *data = calldata; |
5847 | struct nfs_server *server = data->server; | 5850 | struct nfs_server *server = data->server; |
5848 | 5851 | ||
5849 | nfs40_sequence_done(task, &data->seq_res); | 5852 | nfs40_sequence_done(task, &data->res.seq_res); |
5850 | 5853 | ||
5851 | switch (task->tk_status) { | 5854 | switch (task->tk_status) { |
5852 | case 0: | 5855 | case 0: |
@@ -5887,7 +5890,6 @@ static int nfs4_release_lockowner(struct nfs_server *server, struct nfs4_lock_st | |||
5887 | data = kmalloc(sizeof(*data), GFP_NOFS); | 5890 | data = kmalloc(sizeof(*data), GFP_NOFS); |
5888 | if (!data) | 5891 | if (!data) |
5889 | return -ENOMEM; | 5892 | return -ENOMEM; |
5890 | nfs4_init_sequence(&data->seq_args, &data->seq_res, 0); | ||
5891 | data->lsp = lsp; | 5893 | data->lsp = lsp; |
5892 | data->server = server; | 5894 | data->server = server; |
5893 | data->args.lock_owner.clientid = server->nfs_client->cl_clientid; | 5895 | data->args.lock_owner.clientid = server->nfs_client->cl_clientid; |
@@ -5895,6 +5897,8 @@ static int nfs4_release_lockowner(struct nfs_server *server, struct nfs4_lock_st | |||
5895 | data->args.lock_owner.s_dev = server->s_dev; | 5897 | data->args.lock_owner.s_dev = server->s_dev; |
5896 | 5898 | ||
5897 | msg.rpc_argp = &data->args; | 5899 | msg.rpc_argp = &data->args; |
5900 | msg.rpc_resp = &data->res; | ||
5901 | nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0); | ||
5898 | rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, data); | 5902 | rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, data); |
5899 | return 0; | 5903 | return 0; |
5900 | } | 5904 | } |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index e1a47217c05e..0deb32105ccf 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -974,9 +974,6 @@ static int nfs4_copy_lock_stateid(nfs4_stateid *dst, | |||
974 | else if (lsp != NULL && test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) != 0) { | 974 | else if (lsp != NULL && test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) != 0) { |
975 | nfs4_stateid_copy(dst, &lsp->ls_stateid); | 975 | nfs4_stateid_copy(dst, &lsp->ls_stateid); |
976 | ret = 0; | 976 | ret = 0; |
977 | smp_rmb(); | ||
978 | if (!list_empty(&lsp->ls_seqid.list)) | ||
979 | ret = -EWOULDBLOCK; | ||
980 | } | 977 | } |
981 | spin_unlock(&state->state_lock); | 978 | spin_unlock(&state->state_lock); |
982 | nfs4_put_lock_state(lsp); | 979 | nfs4_put_lock_state(lsp); |
@@ -984,10 +981,9 @@ out: | |||
984 | return ret; | 981 | return ret; |
985 | } | 982 | } |
986 | 983 | ||
987 | static int nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state) | 984 | static void nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state) |
988 | { | 985 | { |
989 | const nfs4_stateid *src; | 986 | const nfs4_stateid *src; |
990 | int ret; | ||
991 | int seq; | 987 | int seq; |
992 | 988 | ||
993 | do { | 989 | do { |
@@ -996,12 +992,7 @@ static int nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state) | |||
996 | if (test_bit(NFS_OPEN_STATE, &state->flags)) | 992 | if (test_bit(NFS_OPEN_STATE, &state->flags)) |
997 | src = &state->open_stateid; | 993 | src = &state->open_stateid; |
998 | nfs4_stateid_copy(dst, src); | 994 | nfs4_stateid_copy(dst, src); |
999 | ret = 0; | ||
1000 | smp_rmb(); | ||
1001 | if (!list_empty(&state->owner->so_seqid.list)) | ||
1002 | ret = -EWOULDBLOCK; | ||
1003 | } while (read_seqretry(&state->seqlock, seq)); | 995 | } while (read_seqretry(&state->seqlock, seq)); |
1004 | return ret; | ||
1005 | } | 996 | } |
1006 | 997 | ||
1007 | /* | 998 | /* |
@@ -1026,7 +1017,8 @@ int nfs4_select_rw_stateid(nfs4_stateid *dst, struct nfs4_state *state, | |||
1026 | * choose to use. | 1017 | * choose to use. |
1027 | */ | 1018 | */ |
1028 | goto out; | 1019 | goto out; |
1029 | ret = nfs4_copy_open_stateid(dst, state); | 1020 | nfs4_copy_open_stateid(dst, state); |
1021 | ret = 0; | ||
1030 | out: | 1022 | out: |
1031 | if (nfs_server_capable(state->inode, NFS_CAP_STATEID_NFSV41)) | 1023 | if (nfs_server_capable(state->inode, NFS_CAP_STATEID_NFSV41)) |
1032 | dst->seqid = 0; | 1024 | dst->seqid = 0; |