diff options
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r-- | fs/nfs/nfs4proc.c | 64 |
1 files changed, 61 insertions, 3 deletions
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 | } |