diff options
-rw-r--r-- | fs/nfs/nfs4_fs.h | 4 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 64 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 32 |
3 files changed, 86 insertions, 14 deletions
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 8309e98c44f9..627a74f0e248 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -234,7 +234,7 @@ extern struct rpc_clnt *nfs4_proc_lookup_mountpoint(struct inode *, struct qstr | |||
234 | extern int nfs4_proc_secinfo(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *); | 234 | extern int nfs4_proc_secinfo(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *); |
235 | extern int nfs4_release_lockowner(struct nfs4_lock_state *); | 235 | extern int nfs4_release_lockowner(struct nfs4_lock_state *); |
236 | extern const struct xattr_handler *nfs4_xattr_handlers[]; | 236 | extern const struct xattr_handler *nfs4_xattr_handlers[]; |
237 | extern void nfs4_set_rw_stateid(nfs4_stateid *stateid, | 237 | extern int nfs4_set_rw_stateid(nfs4_stateid *stateid, |
238 | const struct nfs_open_context *ctx, | 238 | const struct nfs_open_context *ctx, |
239 | const struct nfs_lock_context *l_ctx, | 239 | const struct nfs_lock_context *l_ctx, |
240 | fmode_t fmode); | 240 | fmode_t fmode); |
@@ -358,7 +358,7 @@ extern void nfs41_handle_server_scope(struct nfs_client *, | |||
358 | struct nfs41_server_scope **); | 358 | struct nfs41_server_scope **); |
359 | extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); | 359 | extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); |
360 | extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); | 360 | extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); |
361 | extern void nfs4_select_rw_stateid(nfs4_stateid *, struct nfs4_state *, | 361 | extern int nfs4_select_rw_stateid(nfs4_stateid *, struct nfs4_state *, |
362 | fmode_t, const struct nfs_lockowner *); | 362 | fmode_t, const struct nfs_lockowner *); |
363 | 363 | ||
364 | extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask); | 364 | extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask); |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 26176ce3d96a..6ad06121d88c 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -3454,7 +3454,7 @@ static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, | |||
3454 | return err; | 3454 | return err; |
3455 | } | 3455 | } |
3456 | 3456 | ||
3457 | void nfs4_set_rw_stateid(nfs4_stateid *stateid, | 3457 | int nfs4_set_rw_stateid(nfs4_stateid *stateid, |
3458 | const struct nfs_open_context *ctx, | 3458 | const struct nfs_open_context *ctx, |
3459 | const struct nfs_lock_context *l_ctx, | 3459 | const struct nfs_lock_context *l_ctx, |
3460 | fmode_t fmode) | 3460 | fmode_t fmode) |
@@ -3463,10 +3463,37 @@ void nfs4_set_rw_stateid(nfs4_stateid *stateid, | |||
3463 | 3463 | ||
3464 | if (l_ctx != NULL) | 3464 | if (l_ctx != NULL) |
3465 | lockowner = &l_ctx->lockowner; | 3465 | lockowner = &l_ctx->lockowner; |
3466 | nfs4_select_rw_stateid(stateid, ctx->state, fmode, lockowner); | 3466 | return nfs4_select_rw_stateid(stateid, ctx->state, fmode, lockowner); |
3467 | } | 3467 | } |
3468 | EXPORT_SYMBOL_GPL(nfs4_set_rw_stateid); | 3468 | EXPORT_SYMBOL_GPL(nfs4_set_rw_stateid); |
3469 | 3469 | ||
3470 | static bool nfs4_stateid_is_current(nfs4_stateid *stateid, | ||
3471 | const struct nfs_open_context *ctx, | ||
3472 | const struct nfs_lock_context *l_ctx, | ||
3473 | fmode_t fmode) | ||
3474 | { | ||
3475 | nfs4_stateid current_stateid; | ||
3476 | |||
3477 | if (nfs4_set_rw_stateid(¤t_stateid, ctx, l_ctx, fmode)) | ||
3478 | return false; | ||
3479 | return nfs4_stateid_match(stateid, ¤t_stateid); | ||
3480 | } | ||
3481 | |||
3482 | static bool nfs4_error_stateid_expired(int err) | ||
3483 | { | ||
3484 | switch (err) { | ||
3485 | case -NFS4ERR_DELEG_REVOKED: | ||
3486 | case -NFS4ERR_ADMIN_REVOKED: | ||
3487 | case -NFS4ERR_BAD_STATEID: | ||
3488 | case -NFS4ERR_STALE_STATEID: | ||
3489 | case -NFS4ERR_OLD_STATEID: | ||
3490 | case -NFS4ERR_OPENMODE: | ||
3491 | case -NFS4ERR_EXPIRED: | ||
3492 | return true; | ||
3493 | } | ||
3494 | return false; | ||
3495 | } | ||
3496 | |||
3470 | void __nfs4_read_done_cb(struct nfs_read_data *data) | 3497 | void __nfs4_read_done_cb(struct nfs_read_data *data) |
3471 | { | 3498 | { |
3472 | nfs_invalidate_atime(data->header->inode); | 3499 | nfs_invalidate_atime(data->header->inode); |
@@ -3487,6 +3514,20 @@ static int nfs4_read_done_cb(struct rpc_task *task, struct nfs_read_data *data) | |||
3487 | return 0; | 3514 | return 0; |
3488 | } | 3515 | } |
3489 | 3516 | ||
3517 | static bool nfs4_read_stateid_changed(struct rpc_task *task, | ||
3518 | struct nfs_readargs *args) | ||
3519 | { | ||
3520 | |||
3521 | if (!nfs4_error_stateid_expired(task->tk_status) || | ||
3522 | nfs4_stateid_is_current(&args->stateid, | ||
3523 | args->context, | ||
3524 | args->lock_context, | ||
3525 | FMODE_READ)) | ||
3526 | return false; | ||
3527 | rpc_restart_call_prepare(task); | ||
3528 | return true; | ||
3529 | } | ||
3530 | |||
3490 | static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data) | 3531 | static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data) |
3491 | { | 3532 | { |
3492 | 3533 | ||
@@ -3494,7 +3535,8 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data) | |||
3494 | 3535 | ||
3495 | if (!nfs4_sequence_done(task, &data->res.seq_res)) | 3536 | if (!nfs4_sequence_done(task, &data->res.seq_res)) |
3496 | return -EAGAIN; | 3537 | return -EAGAIN; |
3497 | 3538 | if (nfs4_read_stateid_changed(task, &data->args)) | |
3539 | return -EAGAIN; | ||
3498 | return data->read_done_cb ? data->read_done_cb(task, data) : | 3540 | return data->read_done_cb ? data->read_done_cb(task, data) : |
3499 | nfs4_read_done_cb(task, data); | 3541 | nfs4_read_done_cb(task, data); |
3500 | } | 3542 | } |
@@ -3533,10 +3575,26 @@ static int nfs4_write_done_cb(struct rpc_task *task, struct nfs_write_data *data | |||
3533 | return 0; | 3575 | return 0; |
3534 | } | 3576 | } |
3535 | 3577 | ||
3578 | static bool nfs4_write_stateid_changed(struct rpc_task *task, | ||
3579 | struct nfs_writeargs *args) | ||
3580 | { | ||
3581 | |||
3582 | if (!nfs4_error_stateid_expired(task->tk_status) || | ||
3583 | nfs4_stateid_is_current(&args->stateid, | ||
3584 | args->context, | ||
3585 | args->lock_context, | ||
3586 | FMODE_WRITE)) | ||
3587 | return false; | ||
3588 | rpc_restart_call_prepare(task); | ||
3589 | return true; | ||
3590 | } | ||
3591 | |||
3536 | static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) | 3592 | static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) |
3537 | { | 3593 | { |
3538 | if (!nfs4_sequence_done(task, &data->res.seq_res)) | 3594 | if (!nfs4_sequence_done(task, &data->res.seq_res)) |
3539 | return -EAGAIN; | 3595 | return -EAGAIN; |
3596 | if (nfs4_write_stateid_changed(task, &data->args)) | ||
3597 | return -EAGAIN; | ||
3540 | return data->write_done_cb ? data->write_done_cb(task, data) : | 3598 | return data->write_done_cb ? data->write_done_cb(task, data) : |
3541 | nfs4_write_done_cb(task, data); | 3599 | nfs4_write_done_cb(task, data); |
3542 | } | 3600 | } |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 8db102c7add6..4e95bd72f480 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -989,13 +989,14 @@ int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl) | |||
989 | return 0; | 989 | return 0; |
990 | } | 990 | } |
991 | 991 | ||
992 | static bool nfs4_copy_lock_stateid(nfs4_stateid *dst, struct nfs4_state *state, | 992 | static int nfs4_copy_lock_stateid(nfs4_stateid *dst, |
993 | struct nfs4_state *state, | ||
993 | const struct nfs_lockowner *lockowner) | 994 | const struct nfs_lockowner *lockowner) |
994 | { | 995 | { |
995 | struct nfs4_lock_state *lsp; | 996 | struct nfs4_lock_state *lsp; |
996 | fl_owner_t fl_owner; | 997 | fl_owner_t fl_owner; |
997 | pid_t fl_pid; | 998 | pid_t fl_pid; |
998 | bool ret = false; | 999 | int ret = -ENOENT; |
999 | 1000 | ||
1000 | 1001 | ||
1001 | if (lockowner == NULL) | 1002 | if (lockowner == NULL) |
@@ -1010,7 +1011,10 @@ static bool nfs4_copy_lock_stateid(nfs4_stateid *dst, struct nfs4_state *state, | |||
1010 | lsp = __nfs4_find_lock_state(state, fl_owner, fl_pid, NFS4_ANY_LOCK_TYPE); | 1011 | lsp = __nfs4_find_lock_state(state, fl_owner, fl_pid, NFS4_ANY_LOCK_TYPE); |
1011 | if (lsp != NULL && test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) != 0) { | 1012 | if (lsp != NULL && test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) != 0) { |
1012 | nfs4_stateid_copy(dst, &lsp->ls_stateid); | 1013 | nfs4_stateid_copy(dst, &lsp->ls_stateid); |
1013 | ret = true; | 1014 | ret = 0; |
1015 | smp_rmb(); | ||
1016 | if (!list_empty(&lsp->ls_seqid.list)) | ||
1017 | ret = -EWOULDBLOCK; | ||
1014 | } | 1018 | } |
1015 | spin_unlock(&state->state_lock); | 1019 | spin_unlock(&state->state_lock); |
1016 | nfs4_put_lock_state(lsp); | 1020 | nfs4_put_lock_state(lsp); |
@@ -1018,28 +1022,38 @@ out: | |||
1018 | return ret; | 1022 | return ret; |
1019 | } | 1023 | } |
1020 | 1024 | ||
1021 | static void nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state) | 1025 | static int nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state) |
1022 | { | 1026 | { |
1027 | int ret; | ||
1023 | int seq; | 1028 | int seq; |
1024 | 1029 | ||
1025 | do { | 1030 | do { |
1026 | seq = read_seqbegin(&state->seqlock); | 1031 | seq = read_seqbegin(&state->seqlock); |
1027 | nfs4_stateid_copy(dst, &state->stateid); | 1032 | nfs4_stateid_copy(dst, &state->stateid); |
1033 | ret = 0; | ||
1034 | smp_rmb(); | ||
1035 | if (!list_empty(&state->owner->so_seqid.list)) | ||
1036 | ret = -EWOULDBLOCK; | ||
1028 | } while (read_seqretry(&state->seqlock, seq)); | 1037 | } while (read_seqretry(&state->seqlock, seq)); |
1038 | return ret; | ||
1029 | } | 1039 | } |
1030 | 1040 | ||
1031 | /* | 1041 | /* |
1032 | * Byte-range lock aware utility to initialize the stateid of read/write | 1042 | * Byte-range lock aware utility to initialize the stateid of read/write |
1033 | * requests. | 1043 | * requests. |
1034 | */ | 1044 | */ |
1035 | void nfs4_select_rw_stateid(nfs4_stateid *dst, struct nfs4_state *state, | 1045 | int nfs4_select_rw_stateid(nfs4_stateid *dst, struct nfs4_state *state, |
1036 | fmode_t fmode, const struct nfs_lockowner *lockowner) | 1046 | fmode_t fmode, const struct nfs_lockowner *lockowner) |
1037 | { | 1047 | { |
1048 | int ret = 0; | ||
1038 | if (nfs4_copy_delegation_stateid(dst, state->inode, fmode)) | 1049 | if (nfs4_copy_delegation_stateid(dst, state->inode, fmode)) |
1039 | return; | 1050 | goto out; |
1040 | if (nfs4_copy_lock_stateid(dst, state, lockowner)) | 1051 | ret = nfs4_copy_lock_stateid(dst, state, lockowner); |
1041 | return; | 1052 | if (ret != -ENOENT) |
1042 | nfs4_copy_open_stateid(dst, state); | 1053 | goto out; |
1054 | ret = nfs4_copy_open_stateid(dst, state); | ||
1055 | out: | ||
1056 | return ret; | ||
1043 | } | 1057 | } |
1044 | 1058 | ||
1045 | struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask) | 1059 | struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask) |