diff options
author | Andy Adamson <andros@netapp.com> | 2009-12-04 15:55:29 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2009-12-04 15:55:29 -0500 |
commit | e608e79f1bf4b967afcf57777e63b5f0939b00e8 (patch) | |
tree | d649b5714435b7d2d4edd5779fa22122d61ee0c5 /fs | |
parent | 1d9ddde94aed01c4618cf6f70883cc511c3b2b62 (diff) |
nfs41: call free slot from nfs4_restart_rpc
nfs41_sequence_free_slot can be called multiple times on SEQUENCE operation
errors.
No reason to inline nfs4_restart_rpc
Reported-by: Trond Myklebust <trond.myklebust@netapp.com>
nfs_writeback_done and nfs_readpage_retry call nfs4_restart_rpc outside the
error handler, and the slot is not freed prior to restarting in the rpc_prepare
state during session reset.
Fix this by moving the call to nfs41_sequence_free_slot from the error
path of nfs41_sequence_done into nfs4_restart_rpc, and by removing the test
for NFS4CLNT_SESSION_SETUP.
Always free slot and goto the rpc prepare state on async errors.
Signed-off-by: Andy Adamson <andros@netapp.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfs/internal.h | 16 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 29 | ||||
-rw-r--r-- | fs/nfs/read.c | 3 | ||||
-rw-r--r-- | fs/nfs/unlink.c | 4 | ||||
-rw-r--r-- | fs/nfs/write.c | 3 |
5 files changed, 32 insertions, 23 deletions
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index ebcd3795389e..a6f7b6cbfd09 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -177,26 +177,14 @@ extern __be32 * nfs_decode_dirent(__be32 *, struct nfs_entry *, int); | |||
177 | extern struct rpc_procinfo nfs3_procedures[]; | 177 | extern struct rpc_procinfo nfs3_procedures[]; |
178 | extern __be32 *nfs3_decode_dirent(__be32 *, struct nfs_entry *, int); | 178 | extern __be32 *nfs3_decode_dirent(__be32 *, struct nfs_entry *, int); |
179 | 179 | ||
180 | /* nfs4proc.c */ | ||
181 | static inline void nfs4_restart_rpc(struct rpc_task *task, | ||
182 | const struct nfs_client *clp) | ||
183 | { | ||
184 | #ifdef CONFIG_NFS_V4_1 | ||
185 | if (nfs4_has_session(clp) && | ||
186 | test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state)) { | ||
187 | rpc_restart_call_prepare(task); | ||
188 | return; | ||
189 | } | ||
190 | #endif /* CONFIG_NFS_V4_1 */ | ||
191 | rpc_restart_call(task); | ||
192 | } | ||
193 | |||
194 | /* nfs4xdr.c */ | 180 | /* nfs4xdr.c */ |
195 | #ifdef CONFIG_NFS_V4 | 181 | #ifdef CONFIG_NFS_V4 |
196 | extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus); | 182 | extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus); |
197 | #endif | 183 | #endif |
198 | 184 | ||
199 | /* nfs4proc.c */ | 185 | /* nfs4proc.c */ |
186 | extern void nfs4_restart_rpc(struct rpc_task *, const struct nfs_client *, | ||
187 | struct nfs4_sequence_res *); | ||
200 | #ifdef CONFIG_NFS_V4 | 188 | #ifdef CONFIG_NFS_V4 |
201 | extern struct rpc_procinfo nfs4_procedures[]; | 189 | extern struct rpc_procinfo nfs4_procedures[]; |
202 | #endif | 190 | #endif |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index a23110d1d2a9..6ef50aa785d5 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -644,6 +644,19 @@ static void nfs4_sequence_done(const struct nfs_server *server, | |||
644 | #endif /* CONFIG_NFS_V4_1 */ | 644 | #endif /* CONFIG_NFS_V4_1 */ |
645 | } | 645 | } |
646 | 646 | ||
647 | void nfs4_restart_rpc(struct rpc_task *task, const struct nfs_client *clp, | ||
648 | struct nfs4_sequence_res *res) | ||
649 | { | ||
650 | #ifdef CONFIG_NFS_V4_1 | ||
651 | if (nfs4_has_session(clp)) { | ||
652 | nfs41_sequence_free_slot(clp, res); | ||
653 | rpc_restart_call_prepare(task); | ||
654 | return; | ||
655 | } | ||
656 | #endif /* CONFIG_NFS_V4_1 */ | ||
657 | rpc_restart_call(task); | ||
658 | } | ||
659 | |||
647 | /* no restart, therefore free slot here */ | 660 | /* no restart, therefore free slot here */ |
648 | static void nfs4_sequence_done_free_slot(const struct nfs_server *server, | 661 | static void nfs4_sequence_done_free_slot(const struct nfs_server *server, |
649 | struct nfs4_sequence_res *res, | 662 | struct nfs4_sequence_res *res, |
@@ -1750,7 +1763,8 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
1750 | break; | 1763 | break; |
1751 | default: | 1764 | default: |
1752 | if (nfs4_async_handle_error(task, server, state) == -EAGAIN) { | 1765 | if (nfs4_async_handle_error(task, server, state) == -EAGAIN) { |
1753 | nfs4_restart_rpc(task, server->nfs_client); | 1766 | nfs4_restart_rpc(task, server->nfs_client, |
1767 | &calldata->res.seq_res); | ||
1754 | return; | 1768 | return; |
1755 | } | 1769 | } |
1756 | } | 1770 | } |
@@ -2988,7 +3002,7 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data) | |||
2988 | nfs4_sequence_done(server, &data->res.seq_res, task->tk_status); | 3002 | nfs4_sequence_done(server, &data->res.seq_res, task->tk_status); |
2989 | 3003 | ||
2990 | if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { | 3004 | if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { |
2991 | nfs4_restart_rpc(task, server->nfs_client); | 3005 | nfs4_restart_rpc(task, server->nfs_client, &data->res.seq_res); |
2992 | return -EAGAIN; | 3006 | return -EAGAIN; |
2993 | } | 3007 | } |
2994 | 3008 | ||
@@ -3013,7 +3027,8 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) | |||
3013 | task->tk_status); | 3027 | task->tk_status); |
3014 | 3028 | ||
3015 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { | 3029 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { |
3016 | nfs4_restart_rpc(task, NFS_SERVER(inode)->nfs_client); | 3030 | nfs4_restart_rpc(task, NFS_SERVER(inode)->nfs_client, |
3031 | &data->res.seq_res); | ||
3017 | return -EAGAIN; | 3032 | return -EAGAIN; |
3018 | } | 3033 | } |
3019 | if (task->tk_status >= 0) { | 3034 | if (task->tk_status >= 0) { |
@@ -3041,7 +3056,8 @@ static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) | |||
3041 | nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res, | 3056 | nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res, |
3042 | task->tk_status); | 3057 | task->tk_status); |
3043 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { | 3058 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { |
3044 | nfs4_restart_rpc(task, NFS_SERVER(inode)->nfs_client); | 3059 | nfs4_restart_rpc(task, NFS_SERVER(inode)->nfs_client, |
3060 | &data->res.seq_res); | ||
3045 | return -EAGAIN; | 3061 | return -EAGAIN; |
3046 | } | 3062 | } |
3047 | nfs4_sequence_free_slot(NFS_SERVER(inode)->nfs_client, | 3063 | nfs4_sequence_free_slot(NFS_SERVER(inode)->nfs_client, |
@@ -3755,7 +3771,8 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
3755 | default: | 3771 | default: |
3756 | if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN) | 3772 | if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN) |
3757 | nfs4_restart_rpc(task, | 3773 | nfs4_restart_rpc(task, |
3758 | calldata->server->nfs_client); | 3774 | calldata->server->nfs_client, |
3775 | &calldata->res.seq_res); | ||
3759 | } | 3776 | } |
3760 | nfs4_sequence_free_slot(calldata->server->nfs_client, | 3777 | nfs4_sequence_free_slot(calldata->server->nfs_client, |
3761 | &calldata->res.seq_res); | 3778 | &calldata->res.seq_res); |
@@ -4890,7 +4907,7 @@ void nfs41_sequence_call_done(struct rpc_task *task, void *data) | |||
4890 | 4907 | ||
4891 | if (_nfs4_async_handle_error(task, NULL, clp, NULL) | 4908 | if (_nfs4_async_handle_error(task, NULL, clp, NULL) |
4892 | == -EAGAIN) { | 4909 | == -EAGAIN) { |
4893 | nfs4_restart_rpc(task, clp); | 4910 | nfs4_restart_rpc(task, clp, task->tk_msg.rpc_resp); |
4894 | return; | 4911 | return; |
4895 | } | 4912 | } |
4896 | } | 4913 | } |
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 12c9e66d3f1d..3e04fb9ea644 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
@@ -368,7 +368,8 @@ static void nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data | |||
368 | argp->offset += resp->count; | 368 | argp->offset += resp->count; |
369 | argp->pgbase += resp->count; | 369 | argp->pgbase += resp->count; |
370 | argp->count -= resp->count; | 370 | argp->count -= resp->count; |
371 | nfs4_restart_rpc(task, NFS_SERVER(data->inode)->nfs_client); | 371 | nfs4_restart_rpc(task, NFS_SERVER(data->inode)->nfs_client, |
372 | &data->res.seq_res); | ||
372 | return; | 373 | return; |
373 | out: | 374 | out: |
374 | nfs4_sequence_free_slot(NFS_SERVER(data->inode)->nfs_client, | 375 | nfs4_sequence_free_slot(NFS_SERVER(data->inode)->nfs_client, |
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 1064c91ae810..52f7bdb12c83 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c | |||
@@ -81,9 +81,11 @@ static void nfs_async_unlink_done(struct rpc_task *task, void *calldata) | |||
81 | { | 81 | { |
82 | struct nfs_unlinkdata *data = calldata; | 82 | struct nfs_unlinkdata *data = calldata; |
83 | struct inode *dir = data->dir; | 83 | struct inode *dir = data->dir; |
84 | struct nfs_removeres *res = task->tk_msg.rpc_resp; | ||
84 | 85 | ||
85 | if (!NFS_PROTO(dir)->unlink_done(task, dir)) | 86 | if (!NFS_PROTO(dir)->unlink_done(task, dir)) |
86 | nfs4_restart_rpc(task, NFS_SERVER(dir)->nfs_client); | 87 | nfs4_restart_rpc(task, NFS_SERVER(dir)->nfs_client, |
88 | &res->seq_res); | ||
87 | } | 89 | } |
88 | 90 | ||
89 | /** | 91 | /** |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 53eb26c16b50..556668ff0224 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -1216,7 +1216,8 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1216 | */ | 1216 | */ |
1217 | argp->stable = NFS_FILE_SYNC; | 1217 | argp->stable = NFS_FILE_SYNC; |
1218 | } | 1218 | } |
1219 | nfs4_restart_rpc(task, server->nfs_client); | 1219 | nfs4_restart_rpc(task, server->nfs_client, |
1220 | &data->res.seq_res); | ||
1220 | return -EAGAIN; | 1221 | return -EAGAIN; |
1221 | } | 1222 | } |
1222 | if (time_before(complain, jiffies)) { | 1223 | if (time_before(complain, jiffies)) { |