diff options
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r-- | fs/nfs/nfs4proc.c | 196 |
1 files changed, 135 insertions, 61 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 198d51d17c13..638067007c65 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -39,6 +39,7 @@ | |||
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/slab.h> | ||
42 | #include <linux/sunrpc/clnt.h> | 43 | #include <linux/sunrpc/clnt.h> |
43 | #include <linux/nfs.h> | 44 | #include <linux/nfs.h> |
44 | #include <linux/nfs4.h> | 45 | #include <linux/nfs4.h> |
@@ -249,19 +250,15 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, | |||
249 | if (state == NULL) | 250 | if (state == NULL) |
250 | break; | 251 | break; |
251 | nfs4_state_mark_reclaim_nograce(clp, state); | 252 | nfs4_state_mark_reclaim_nograce(clp, state); |
252 | case -NFS4ERR_STALE_CLIENTID: | 253 | goto do_state_recovery; |
253 | case -NFS4ERR_STALE_STATEID: | 254 | case -NFS4ERR_STALE_STATEID: |
254 | case -NFS4ERR_EXPIRED: | 255 | if (state == NULL) |
255 | nfs4_schedule_state_recovery(clp); | ||
256 | ret = nfs4_wait_clnt_recover(clp); | ||
257 | if (ret == 0) | ||
258 | exception->retry = 1; | ||
259 | #if !defined(CONFIG_NFS_V4_1) | ||
260 | break; | ||
261 | #else /* !defined(CONFIG_NFS_V4_1) */ | ||
262 | if (!nfs4_has_session(server->nfs_client)) | ||
263 | break; | 256 | break; |
264 | /* FALLTHROUGH */ | 257 | nfs4_state_mark_reclaim_reboot(clp, state); |
258 | case -NFS4ERR_STALE_CLIENTID: | ||
259 | case -NFS4ERR_EXPIRED: | ||
260 | goto do_state_recovery; | ||
261 | #if defined(CONFIG_NFS_V4_1) | ||
265 | case -NFS4ERR_BADSESSION: | 262 | case -NFS4ERR_BADSESSION: |
266 | case -NFS4ERR_BADSLOT: | 263 | case -NFS4ERR_BADSLOT: |
267 | case -NFS4ERR_BAD_HIGH_SLOT: | 264 | case -NFS4ERR_BAD_HIGH_SLOT: |
@@ -274,7 +271,7 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, | |||
274 | nfs4_schedule_state_recovery(clp); | 271 | nfs4_schedule_state_recovery(clp); |
275 | exception->retry = 1; | 272 | exception->retry = 1; |
276 | break; | 273 | break; |
277 | #endif /* !defined(CONFIG_NFS_V4_1) */ | 274 | #endif /* defined(CONFIG_NFS_V4_1) */ |
278 | case -NFS4ERR_FILE_OPEN: | 275 | case -NFS4ERR_FILE_OPEN: |
279 | if (exception->timeout > HZ) { | 276 | if (exception->timeout > HZ) { |
280 | /* We have retried a decent amount, time to | 277 | /* We have retried a decent amount, time to |
@@ -285,6 +282,7 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, | |||
285 | } | 282 | } |
286 | case -NFS4ERR_GRACE: | 283 | case -NFS4ERR_GRACE: |
287 | case -NFS4ERR_DELAY: | 284 | case -NFS4ERR_DELAY: |
285 | case -EKEYEXPIRED: | ||
288 | ret = nfs4_delay(server->client, &exception->timeout); | 286 | ret = nfs4_delay(server->client, &exception->timeout); |
289 | if (ret != 0) | 287 | if (ret != 0) |
290 | break; | 288 | break; |
@@ -293,6 +291,12 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, | |||
293 | } | 291 | } |
294 | /* We failed to handle the error */ | 292 | /* We failed to handle the error */ |
295 | return nfs4_map_errors(ret); | 293 | return nfs4_map_errors(ret); |
294 | do_state_recovery: | ||
295 | nfs4_schedule_state_recovery(clp); | ||
296 | ret = nfs4_wait_clnt_recover(clp); | ||
297 | if (ret == 0) | ||
298 | exception->retry = 1; | ||
299 | return ret; | ||
296 | } | 300 | } |
297 | 301 | ||
298 | 302 | ||
@@ -416,7 +420,8 @@ static void nfs41_sequence_done(struct nfs_client *clp, | |||
416 | clp->cl_last_renewal = timestamp; | 420 | clp->cl_last_renewal = timestamp; |
417 | spin_unlock(&clp->cl_lock); | 421 | spin_unlock(&clp->cl_lock); |
418 | /* Check sequence flags */ | 422 | /* Check sequence flags */ |
419 | nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags); | 423 | if (atomic_read(&clp->cl_count) > 1) |
424 | nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags); | ||
420 | } | 425 | } |
421 | out: | 426 | out: |
422 | /* The session may be reset by one of the error handlers. */ | 427 | /* The session may be reset by one of the error handlers. */ |
@@ -722,8 +727,8 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, | |||
722 | p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); | 727 | p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); |
723 | if (p->o_arg.seqid == NULL) | 728 | if (p->o_arg.seqid == NULL) |
724 | goto err_free; | 729 | goto err_free; |
725 | p->path.mnt = mntget(path->mnt); | 730 | path_get(path); |
726 | p->path.dentry = dget(path->dentry); | 731 | p->path = *path; |
727 | p->dir = parent; | 732 | p->dir = parent; |
728 | p->owner = sp; | 733 | p->owner = sp; |
729 | atomic_inc(&sp->so_count); | 734 | atomic_inc(&sp->so_count); |
@@ -1161,7 +1166,7 @@ static int nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state | |||
1161 | int err; | 1166 | int err; |
1162 | do { | 1167 | do { |
1163 | err = _nfs4_do_open_reclaim(ctx, state); | 1168 | err = _nfs4_do_open_reclaim(ctx, state); |
1164 | if (err != -NFS4ERR_DELAY) | 1169 | if (err != -NFS4ERR_DELAY && err != -EKEYEXPIRED) |
1165 | break; | 1170 | break; |
1166 | nfs4_handle_exception(server, err, &exception); | 1171 | nfs4_handle_exception(server, err, &exception); |
1167 | } while (exception.retry); | 1172 | } while (exception.retry); |
@@ -1518,6 +1523,8 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |||
1518 | nfs_post_op_update_inode(dir, o_res->dir_attr); | 1523 | nfs_post_op_update_inode(dir, o_res->dir_attr); |
1519 | } else | 1524 | } else |
1520 | nfs_refresh_inode(dir, o_res->dir_attr); | 1525 | nfs_refresh_inode(dir, o_res->dir_attr); |
1526 | if ((o_res->rflags & NFS4_OPEN_RESULT_LOCKTYPE_POSIX) == 0) | ||
1527 | server->caps &= ~NFS_CAP_POSIX_LOCK; | ||
1521 | if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { | 1528 | if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { |
1522 | status = _nfs4_proc_open_confirm(data); | 1529 | status = _nfs4_proc_open_confirm(data); |
1523 | if (status != 0) | 1530 | if (status != 0) |
@@ -1580,6 +1587,7 @@ static int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4_state | |||
1580 | goto out; | 1587 | goto out; |
1581 | case -NFS4ERR_GRACE: | 1588 | case -NFS4ERR_GRACE: |
1582 | case -NFS4ERR_DELAY: | 1589 | case -NFS4ERR_DELAY: |
1590 | case -EKEYEXPIRED: | ||
1583 | nfs4_handle_exception(server, err, &exception); | 1591 | nfs4_handle_exception(server, err, &exception); |
1584 | err = 0; | 1592 | err = 0; |
1585 | } | 1593 | } |
@@ -1658,6 +1666,8 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, fmode_t fmode, in | |||
1658 | status = PTR_ERR(state); | 1666 | status = PTR_ERR(state); |
1659 | if (IS_ERR(state)) | 1667 | if (IS_ERR(state)) |
1660 | goto err_opendata_put; | 1668 | goto err_opendata_put; |
1669 | if (server->caps & NFS_CAP_POSIX_LOCK) | ||
1670 | set_bit(NFS_STATE_POSIX_LOCKS, &state->flags); | ||
1661 | nfs4_opendata_put(opendata); | 1671 | nfs4_opendata_put(opendata); |
1662 | nfs4_put_state_owner(sp); | 1672 | nfs4_put_state_owner(sp); |
1663 | *res = state; | 1673 | *res = state; |
@@ -1940,8 +1950,8 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
1940 | calldata->res.seqid = calldata->arg.seqid; | 1950 | calldata->res.seqid = calldata->arg.seqid; |
1941 | calldata->res.server = server; | 1951 | calldata->res.server = server; |
1942 | calldata->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | 1952 | calldata->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; |
1943 | calldata->path.mnt = mntget(path->mnt); | 1953 | path_get(path); |
1944 | calldata->path.dentry = dget(path->dentry); | 1954 | calldata->path = *path; |
1945 | 1955 | ||
1946 | msg.rpc_argp = &calldata->arg, | 1956 | msg.rpc_argp = &calldata->arg, |
1947 | msg.rpc_resp = &calldata->res, | 1957 | msg.rpc_resp = &calldata->res, |
@@ -2060,8 +2070,7 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st | |||
2060 | case -EDQUOT: | 2070 | case -EDQUOT: |
2061 | case -ENOSPC: | 2071 | case -ENOSPC: |
2062 | case -EROFS: | 2072 | case -EROFS: |
2063 | lookup_instantiate_filp(nd, (struct dentry *)state, NULL); | 2073 | return PTR_ERR(state); |
2064 | return 1; | ||
2065 | default: | 2074 | default: |
2066 | goto out_drop; | 2075 | goto out_drop; |
2067 | } | 2076 | } |
@@ -3141,10 +3150,19 @@ static void nfs4_proc_commit_setup(struct nfs_write_data *data, struct rpc_messa | |||
3141 | * nfs4_proc_async_renew(): This is not one of the nfs_rpc_ops; it is a special | 3150 | * nfs4_proc_async_renew(): This is not one of the nfs_rpc_ops; it is a special |
3142 | * standalone procedure for queueing an asynchronous RENEW. | 3151 | * standalone procedure for queueing an asynchronous RENEW. |
3143 | */ | 3152 | */ |
3153 | static void nfs4_renew_release(void *data) | ||
3154 | { | ||
3155 | struct nfs_client *clp = data; | ||
3156 | |||
3157 | if (atomic_read(&clp->cl_count) > 1) | ||
3158 | nfs4_schedule_state_renewal(clp); | ||
3159 | nfs_put_client(clp); | ||
3160 | } | ||
3161 | |||
3144 | static void nfs4_renew_done(struct rpc_task *task, void *data) | 3162 | static void nfs4_renew_done(struct rpc_task *task, void *data) |
3145 | { | 3163 | { |
3146 | struct nfs_client *clp = (struct nfs_client *)task->tk_msg.rpc_argp; | 3164 | struct nfs_client *clp = data; |
3147 | unsigned long timestamp = (unsigned long)data; | 3165 | unsigned long timestamp = task->tk_start; |
3148 | 3166 | ||
3149 | if (task->tk_status < 0) { | 3167 | if (task->tk_status < 0) { |
3150 | /* Unless we're shutting down, schedule state recovery! */ | 3168 | /* Unless we're shutting down, schedule state recovery! */ |
@@ -3160,6 +3178,7 @@ static void nfs4_renew_done(struct rpc_task *task, void *data) | |||
3160 | 3178 | ||
3161 | static const struct rpc_call_ops nfs4_renew_ops = { | 3179 | static const struct rpc_call_ops nfs4_renew_ops = { |
3162 | .rpc_call_done = nfs4_renew_done, | 3180 | .rpc_call_done = nfs4_renew_done, |
3181 | .rpc_release = nfs4_renew_release, | ||
3163 | }; | 3182 | }; |
3164 | 3183 | ||
3165 | int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred) | 3184 | int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred) |
@@ -3170,8 +3189,10 @@ int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred) | |||
3170 | .rpc_cred = cred, | 3189 | .rpc_cred = cred, |
3171 | }; | 3190 | }; |
3172 | 3191 | ||
3192 | if (!atomic_inc_not_zero(&clp->cl_count)) | ||
3193 | return -EIO; | ||
3173 | return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT, | 3194 | return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT, |
3174 | &nfs4_renew_ops, (void *)jiffies); | 3195 | &nfs4_renew_ops, clp); |
3175 | } | 3196 | } |
3176 | 3197 | ||
3177 | int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred) | 3198 | int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred) |
@@ -3422,15 +3443,14 @@ _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
3422 | if (state == NULL) | 3443 | if (state == NULL) |
3423 | break; | 3444 | break; |
3424 | nfs4_state_mark_reclaim_nograce(clp, state); | 3445 | nfs4_state_mark_reclaim_nograce(clp, state); |
3425 | case -NFS4ERR_STALE_CLIENTID: | 3446 | goto do_state_recovery; |
3426 | case -NFS4ERR_STALE_STATEID: | 3447 | case -NFS4ERR_STALE_STATEID: |
3448 | if (state == NULL) | ||
3449 | break; | ||
3450 | nfs4_state_mark_reclaim_reboot(clp, state); | ||
3451 | case -NFS4ERR_STALE_CLIENTID: | ||
3427 | case -NFS4ERR_EXPIRED: | 3452 | case -NFS4ERR_EXPIRED: |
3428 | rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL); | 3453 | goto do_state_recovery; |
3429 | nfs4_schedule_state_recovery(clp); | ||
3430 | if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0) | ||
3431 | rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task); | ||
3432 | task->tk_status = 0; | ||
3433 | return -EAGAIN; | ||
3434 | #if defined(CONFIG_NFS_V4_1) | 3454 | #if defined(CONFIG_NFS_V4_1) |
3435 | case -NFS4ERR_BADSESSION: | 3455 | case -NFS4ERR_BADSESSION: |
3436 | case -NFS4ERR_BADSLOT: | 3456 | case -NFS4ERR_BADSLOT: |
@@ -3449,6 +3469,7 @@ _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
3449 | if (server) | 3469 | if (server) |
3450 | nfs_inc_server_stats(server, NFSIOS_DELAY); | 3470 | nfs_inc_server_stats(server, NFSIOS_DELAY); |
3451 | case -NFS4ERR_GRACE: | 3471 | case -NFS4ERR_GRACE: |
3472 | case -EKEYEXPIRED: | ||
3452 | rpc_delay(task, NFS4_POLL_RETRY_MAX); | 3473 | rpc_delay(task, NFS4_POLL_RETRY_MAX); |
3453 | task->tk_status = 0; | 3474 | task->tk_status = 0; |
3454 | return -EAGAIN; | 3475 | return -EAGAIN; |
@@ -3458,6 +3479,13 @@ _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
3458 | } | 3479 | } |
3459 | task->tk_status = nfs4_map_errors(task->tk_status); | 3480 | task->tk_status = nfs4_map_errors(task->tk_status); |
3460 | return 0; | 3481 | return 0; |
3482 | do_state_recovery: | ||
3483 | rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL); | ||
3484 | nfs4_schedule_state_recovery(clp); | ||
3485 | if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0) | ||
3486 | rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task); | ||
3487 | task->tk_status = 0; | ||
3488 | return -EAGAIN; | ||
3461 | } | 3489 | } |
3462 | 3490 | ||
3463 | static int | 3491 | static int |
@@ -3554,6 +3582,7 @@ int nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cred *cred) | |||
3554 | case -NFS4ERR_RESOURCE: | 3582 | case -NFS4ERR_RESOURCE: |
3555 | /* The IBM lawyers misread another document! */ | 3583 | /* The IBM lawyers misread another document! */ |
3556 | case -NFS4ERR_DELAY: | 3584 | case -NFS4ERR_DELAY: |
3585 | case -EKEYEXPIRED: | ||
3557 | err = nfs4_delay(clp->cl_rpcclient, &timeout); | 3586 | err = nfs4_delay(clp->cl_rpcclient, &timeout); |
3558 | } | 3587 | } |
3559 | } while (err == 0); | 3588 | } while (err == 0); |
@@ -4088,6 +4117,28 @@ static const struct rpc_call_ops nfs4_recover_lock_ops = { | |||
4088 | .rpc_release = nfs4_lock_release, | 4117 | .rpc_release = nfs4_lock_release, |
4089 | }; | 4118 | }; |
4090 | 4119 | ||
4120 | static void nfs4_handle_setlk_error(struct nfs_server *server, struct nfs4_lock_state *lsp, int new_lock_owner, int error) | ||
4121 | { | ||
4122 | struct nfs_client *clp = server->nfs_client; | ||
4123 | struct nfs4_state *state = lsp->ls_state; | ||
4124 | |||
4125 | switch (error) { | ||
4126 | case -NFS4ERR_ADMIN_REVOKED: | ||
4127 | case -NFS4ERR_BAD_STATEID: | ||
4128 | case -NFS4ERR_EXPIRED: | ||
4129 | if (new_lock_owner != 0 || | ||
4130 | (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) | ||
4131 | nfs4_state_mark_reclaim_nograce(clp, state); | ||
4132 | lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED; | ||
4133 | break; | ||
4134 | case -NFS4ERR_STALE_STATEID: | ||
4135 | if (new_lock_owner != 0 || | ||
4136 | (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) | ||
4137 | nfs4_state_mark_reclaim_reboot(clp, state); | ||
4138 | lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED; | ||
4139 | }; | ||
4140 | } | ||
4141 | |||
4091 | static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *fl, int recovery_type) | 4142 | static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *fl, int recovery_type) |
4092 | { | 4143 | { |
4093 | struct nfs4_lockdata *data; | 4144 | struct nfs4_lockdata *data; |
@@ -4126,6 +4177,9 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f | |||
4126 | ret = nfs4_wait_for_completion_rpc_task(task); | 4177 | ret = nfs4_wait_for_completion_rpc_task(task); |
4127 | if (ret == 0) { | 4178 | if (ret == 0) { |
4128 | ret = data->rpc_status; | 4179 | ret = data->rpc_status; |
4180 | if (ret) | ||
4181 | nfs4_handle_setlk_error(data->server, data->lsp, | ||
4182 | data->arg.new_lock_owner, ret); | ||
4129 | } else | 4183 | } else |
4130 | data->cancelled = 1; | 4184 | data->cancelled = 1; |
4131 | rpc_put_task(task); | 4185 | rpc_put_task(task); |
@@ -4144,7 +4198,7 @@ static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request | |||
4144 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0) | 4198 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0) |
4145 | return 0; | 4199 | return 0; |
4146 | err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_RECLAIM); | 4200 | err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_RECLAIM); |
4147 | if (err != -NFS4ERR_DELAY) | 4201 | if (err != -NFS4ERR_DELAY && err != -EKEYEXPIRED) |
4148 | break; | 4202 | break; |
4149 | nfs4_handle_exception(server, err, &exception); | 4203 | nfs4_handle_exception(server, err, &exception); |
4150 | } while (exception.retry); | 4204 | } while (exception.retry); |
@@ -4169,6 +4223,7 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request | |||
4169 | goto out; | 4223 | goto out; |
4170 | case -NFS4ERR_GRACE: | 4224 | case -NFS4ERR_GRACE: |
4171 | case -NFS4ERR_DELAY: | 4225 | case -NFS4ERR_DELAY: |
4226 | case -EKEYEXPIRED: | ||
4172 | nfs4_handle_exception(server, err, &exception); | 4227 | nfs4_handle_exception(server, err, &exception); |
4173 | err = 0; | 4228 | err = 0; |
4174 | } | 4229 | } |
@@ -4181,8 +4236,11 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock | |||
4181 | { | 4236 | { |
4182 | struct nfs_inode *nfsi = NFS_I(state->inode); | 4237 | struct nfs_inode *nfsi = NFS_I(state->inode); |
4183 | unsigned char fl_flags = request->fl_flags; | 4238 | unsigned char fl_flags = request->fl_flags; |
4184 | int status; | 4239 | int status = -ENOLCK; |
4185 | 4240 | ||
4241 | if ((fl_flags & FL_POSIX) && | ||
4242 | !test_bit(NFS_STATE_POSIX_LOCKS, &state->flags)) | ||
4243 | goto out; | ||
4186 | /* Is this a delegated open? */ | 4244 | /* Is this a delegated open? */ |
4187 | status = nfs4_set_lock_state(state, request); | 4245 | status = nfs4_set_lock_state(state, request); |
4188 | if (status != 0) | 4246 | if (status != 0) |
@@ -4317,6 +4375,7 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl) | |||
4317 | err = 0; | 4375 | err = 0; |
4318 | goto out; | 4376 | goto out; |
4319 | case -NFS4ERR_DELAY: | 4377 | case -NFS4ERR_DELAY: |
4378 | case -EKEYEXPIRED: | ||
4320 | break; | 4379 | break; |
4321 | } | 4380 | } |
4322 | err = nfs4_handle_exception(server, err, &exception); | 4381 | err = nfs4_handle_exception(server, err, &exception); |
@@ -4462,7 +4521,7 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) | |||
4462 | 4521 | ||
4463 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); | 4522 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); |
4464 | 4523 | ||
4465 | if (status != NFS4ERR_CLID_INUSE) | 4524 | if (status != -NFS4ERR_CLID_INUSE) |
4466 | break; | 4525 | break; |
4467 | 4526 | ||
4468 | if (signalled()) | 4527 | if (signalled()) |
@@ -4516,6 +4575,7 @@ static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata) | |||
4516 | switch (task->tk_status) { | 4575 | switch (task->tk_status) { |
4517 | case -NFS4ERR_DELAY: | 4576 | case -NFS4ERR_DELAY: |
4518 | case -NFS4ERR_GRACE: | 4577 | case -NFS4ERR_GRACE: |
4578 | case -EKEYEXPIRED: | ||
4519 | dprintk("%s Retry: tk_status %d\n", __func__, task->tk_status); | 4579 | dprintk("%s Retry: tk_status %d\n", __func__, task->tk_status); |
4520 | rpc_delay(task, NFS4_POLL_RETRY_MIN); | 4580 | rpc_delay(task, NFS4_POLL_RETRY_MIN); |
4521 | task->tk_status = 0; | 4581 | task->tk_status = 0; |
@@ -4573,26 +4633,32 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo) | |||
4573 | /* | 4633 | /* |
4574 | * Reset a slot table | 4634 | * Reset a slot table |
4575 | */ | 4635 | */ |
4576 | static int nfs4_reset_slot_table(struct nfs4_slot_table *tbl, int max_slots, | 4636 | static int nfs4_reset_slot_table(struct nfs4_slot_table *tbl, u32 max_reqs, |
4577 | int old_max_slots, int ivalue) | 4637 | int ivalue) |
4578 | { | 4638 | { |
4639 | struct nfs4_slot *new = NULL; | ||
4579 | int i; | 4640 | int i; |
4580 | int ret = 0; | 4641 | int ret = 0; |
4581 | 4642 | ||
4582 | dprintk("--> %s: max_reqs=%u, tbl %p\n", __func__, max_slots, tbl); | 4643 | dprintk("--> %s: max_reqs=%u, tbl->max_slots %d\n", __func__, |
4644 | max_reqs, tbl->max_slots); | ||
4583 | 4645 | ||
4584 | /* | 4646 | /* Does the newly negotiated max_reqs match the existing slot table? */ |
4585 | * Until we have dynamic slot table adjustment, insist | 4647 | if (max_reqs != tbl->max_slots) { |
4586 | * upon the same slot table size | 4648 | ret = -ENOMEM; |
4587 | */ | 4649 | new = kmalloc(max_reqs * sizeof(struct nfs4_slot), |
4588 | if (max_slots != old_max_slots) { | 4650 | GFP_KERNEL); |
4589 | dprintk("%s reset slot table does't match old\n", | 4651 | if (!new) |
4590 | __func__); | 4652 | goto out; |
4591 | ret = -EINVAL; /*XXX NFS4ERR_REQ_TOO_BIG ? */ | 4653 | ret = 0; |
4592 | goto out; | 4654 | kfree(tbl->slots); |
4593 | } | 4655 | } |
4594 | spin_lock(&tbl->slot_tbl_lock); | 4656 | spin_lock(&tbl->slot_tbl_lock); |
4595 | for (i = 0; i < max_slots; ++i) | 4657 | if (new) { |
4658 | tbl->slots = new; | ||
4659 | tbl->max_slots = max_reqs; | ||
4660 | } | ||
4661 | for (i = 0; i < tbl->max_slots; ++i) | ||
4596 | tbl->slots[i].seq_nr = ivalue; | 4662 | tbl->slots[i].seq_nr = ivalue; |
4597 | spin_unlock(&tbl->slot_tbl_lock); | 4663 | spin_unlock(&tbl->slot_tbl_lock); |
4598 | dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, | 4664 | dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, |
@@ -4610,16 +4676,12 @@ static int nfs4_reset_slot_tables(struct nfs4_session *session) | |||
4610 | int status; | 4676 | int status; |
4611 | 4677 | ||
4612 | status = nfs4_reset_slot_table(&session->fc_slot_table, | 4678 | status = nfs4_reset_slot_table(&session->fc_slot_table, |
4613 | session->fc_attrs.max_reqs, | 4679 | session->fc_attrs.max_reqs, 1); |
4614 | session->fc_slot_table.max_slots, | ||
4615 | 1); | ||
4616 | if (status) | 4680 | if (status) |
4617 | return status; | 4681 | return status; |
4618 | 4682 | ||
4619 | status = nfs4_reset_slot_table(&session->bc_slot_table, | 4683 | status = nfs4_reset_slot_table(&session->bc_slot_table, |
4620 | session->bc_attrs.max_reqs, | 4684 | session->bc_attrs.max_reqs, 0); |
4621 | session->bc_slot_table.max_slots, | ||
4622 | 0); | ||
4623 | return status; | 4685 | return status; |
4624 | } | 4686 | } |
4625 | 4687 | ||
@@ -4760,16 +4822,14 @@ static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args) | |||
4760 | args->fc_attrs.headerpadsz = 0; | 4822 | args->fc_attrs.headerpadsz = 0; |
4761 | args->fc_attrs.max_rqst_sz = mxrqst_sz; | 4823 | args->fc_attrs.max_rqst_sz = mxrqst_sz; |
4762 | args->fc_attrs.max_resp_sz = mxresp_sz; | 4824 | args->fc_attrs.max_resp_sz = mxresp_sz; |
4763 | args->fc_attrs.max_resp_sz_cached = mxresp_sz; | ||
4764 | args->fc_attrs.max_ops = NFS4_MAX_OPS; | 4825 | args->fc_attrs.max_ops = NFS4_MAX_OPS; |
4765 | args->fc_attrs.max_reqs = session->clp->cl_rpcclient->cl_xprt->max_reqs; | 4826 | args->fc_attrs.max_reqs = session->clp->cl_rpcclient->cl_xprt->max_reqs; |
4766 | 4827 | ||
4767 | dprintk("%s: Fore Channel : max_rqst_sz=%u max_resp_sz=%u " | 4828 | dprintk("%s: Fore Channel : max_rqst_sz=%u max_resp_sz=%u " |
4768 | "max_resp_sz_cached=%u max_ops=%u max_reqs=%u\n", | 4829 | "max_ops=%u max_reqs=%u\n", |
4769 | __func__, | 4830 | __func__, |
4770 | args->fc_attrs.max_rqst_sz, args->fc_attrs.max_resp_sz, | 4831 | args->fc_attrs.max_rqst_sz, args->fc_attrs.max_resp_sz, |
4771 | args->fc_attrs.max_resp_sz_cached, args->fc_attrs.max_ops, | 4832 | args->fc_attrs.max_ops, args->fc_attrs.max_reqs); |
4772 | args->fc_attrs.max_reqs); | ||
4773 | 4833 | ||
4774 | /* Back channel attributes */ | 4834 | /* Back channel attributes */ |
4775 | args->bc_attrs.headerpadsz = 0; | 4835 | args->bc_attrs.headerpadsz = 0; |
@@ -4978,7 +5038,16 @@ static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred) | |||
4978 | &res, args.sa_cache_this, 1); | 5038 | &res, args.sa_cache_this, 1); |
4979 | } | 5039 | } |
4980 | 5040 | ||
4981 | void nfs41_sequence_call_done(struct rpc_task *task, void *data) | 5041 | static void nfs41_sequence_release(void *data) |
5042 | { | ||
5043 | struct nfs_client *clp = (struct nfs_client *)data; | ||
5044 | |||
5045 | if (atomic_read(&clp->cl_count) > 1) | ||
5046 | nfs4_schedule_state_renewal(clp); | ||
5047 | nfs_put_client(clp); | ||
5048 | } | ||
5049 | |||
5050 | static void nfs41_sequence_call_done(struct rpc_task *task, void *data) | ||
4982 | { | 5051 | { |
4983 | struct nfs_client *clp = (struct nfs_client *)data; | 5052 | struct nfs_client *clp = (struct nfs_client *)data; |
4984 | 5053 | ||
@@ -4986,6 +5055,8 @@ void nfs41_sequence_call_done(struct rpc_task *task, void *data) | |||
4986 | 5055 | ||
4987 | if (task->tk_status < 0) { | 5056 | if (task->tk_status < 0) { |
4988 | dprintk("%s ERROR %d\n", __func__, task->tk_status); | 5057 | dprintk("%s ERROR %d\n", __func__, task->tk_status); |
5058 | if (atomic_read(&clp->cl_count) == 1) | ||
5059 | goto out; | ||
4989 | 5060 | ||
4990 | if (_nfs4_async_handle_error(task, NULL, clp, NULL) | 5061 | if (_nfs4_async_handle_error(task, NULL, clp, NULL) |
4991 | == -EAGAIN) { | 5062 | == -EAGAIN) { |
@@ -4994,7 +5065,7 @@ void nfs41_sequence_call_done(struct rpc_task *task, void *data) | |||
4994 | } | 5065 | } |
4995 | } | 5066 | } |
4996 | dprintk("%s rpc_cred %p\n", __func__, task->tk_msg.rpc_cred); | 5067 | dprintk("%s rpc_cred %p\n", __func__, task->tk_msg.rpc_cred); |
4997 | 5068 | out: | |
4998 | kfree(task->tk_msg.rpc_argp); | 5069 | kfree(task->tk_msg.rpc_argp); |
4999 | kfree(task->tk_msg.rpc_resp); | 5070 | kfree(task->tk_msg.rpc_resp); |
5000 | 5071 | ||
@@ -5019,6 +5090,7 @@ static void nfs41_sequence_prepare(struct rpc_task *task, void *data) | |||
5019 | static const struct rpc_call_ops nfs41_sequence_ops = { | 5090 | static const struct rpc_call_ops nfs41_sequence_ops = { |
5020 | .rpc_call_done = nfs41_sequence_call_done, | 5091 | .rpc_call_done = nfs41_sequence_call_done, |
5021 | .rpc_call_prepare = nfs41_sequence_prepare, | 5092 | .rpc_call_prepare = nfs41_sequence_prepare, |
5093 | .rpc_release = nfs41_sequence_release, | ||
5022 | }; | 5094 | }; |
5023 | 5095 | ||
5024 | static int nfs41_proc_async_sequence(struct nfs_client *clp, | 5096 | static int nfs41_proc_async_sequence(struct nfs_client *clp, |
@@ -5031,12 +5103,14 @@ static int nfs41_proc_async_sequence(struct nfs_client *clp, | |||
5031 | .rpc_cred = cred, | 5103 | .rpc_cred = cred, |
5032 | }; | 5104 | }; |
5033 | 5105 | ||
5106 | if (!atomic_inc_not_zero(&clp->cl_count)) | ||
5107 | return -EIO; | ||
5034 | args = kzalloc(sizeof(*args), GFP_KERNEL); | 5108 | args = kzalloc(sizeof(*args), GFP_KERNEL); |
5035 | if (!args) | ||
5036 | return -ENOMEM; | ||
5037 | res = kzalloc(sizeof(*res), GFP_KERNEL); | 5109 | res = kzalloc(sizeof(*res), GFP_KERNEL); |
5038 | if (!res) { | 5110 | if (!args || !res) { |
5039 | kfree(args); | 5111 | kfree(args); |
5112 | kfree(res); | ||
5113 | nfs_put_client(clp); | ||
5040 | return -ENOMEM; | 5114 | return -ENOMEM; |
5041 | } | 5115 | } |
5042 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | 5116 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; |