aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/nfs4_fs.h4
-rw-r--r--fs/nfs/nfs4proc.c64
-rw-r--r--fs/nfs/nfs4state.c32
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
234extern int nfs4_proc_secinfo(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *); 234extern int nfs4_proc_secinfo(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *);
235extern int nfs4_release_lockowner(struct nfs4_lock_state *); 235extern int nfs4_release_lockowner(struct nfs4_lock_state *);
236extern const struct xattr_handler *nfs4_xattr_handlers[]; 236extern const struct xattr_handler *nfs4_xattr_handlers[];
237extern void nfs4_set_rw_stateid(nfs4_stateid *stateid, 237extern 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 **);
359extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); 359extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp);
360extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); 360extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl);
361extern void nfs4_select_rw_stateid(nfs4_stateid *, struct nfs4_state *, 361extern 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
364extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask); 364extern 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
3457void nfs4_set_rw_stateid(nfs4_stateid *stateid, 3457int 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}
3468EXPORT_SYMBOL_GPL(nfs4_set_rw_stateid); 3468EXPORT_SYMBOL_GPL(nfs4_set_rw_stateid);
3469 3469
3470static 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(&current_stateid, ctx, l_ctx, fmode))
3478 return false;
3479 return nfs4_stateid_match(stateid, &current_stateid);
3480}
3481
3482static 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
3470void __nfs4_read_done_cb(struct nfs_read_data *data) 3497void __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
3517static 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
3490static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data) 3531static 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
3578static 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
3536static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) 3592static 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
992static bool nfs4_copy_lock_stateid(nfs4_stateid *dst, struct nfs4_state *state, 992static 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
1021static void nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state) 1025static 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 */
1035void nfs4_select_rw_stateid(nfs4_stateid *dst, struct nfs4_state *state, 1045int 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);
1055out:
1056 return ret;
1043} 1057}
1044 1058
1045struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask) 1059struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask)