2019-09-10 08:09:58

by Trond Myklebust

[permalink] [raw]
Subject: [PATCH 7/9] NFSv4: Fix OPEN_DOWNGRADE error handling

If OPEN_DOWNGRADE returns a state error, then we want to initiate
state recovery in addition to marking the stateid as closed.

Signed-off-by: Trond Myklebust <[email protected]>
---
fs/nfs/nfs4proc.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index cbaf6b7ac128..025dd5efbf34 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -3394,7 +3394,9 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
task->tk_msg.rpc_cred);
/* Fallthrough */
case -NFS4ERR_BAD_STATEID:
- break;
+ if (calldata->arg.fmode == 0)
+ break;
+ /* Fallthrough */
default:
task->tk_status = nfs4_async_handle_exception(task,
server, task->tk_status, &exception);
--
2.21.0


2019-09-10 08:10:42

by Trond Myklebust

[permalink] [raw]
Subject: [PATCH 8/9] NFSv4: Handle NFS4ERR_OLD_STATEID in CLOSE/OPEN_DOWNGRADE

If a CLOSE or OPEN_DOWNGRADE operation receives a NFS4ERR_OLD_STATEID
then bump the seqid before resending. Ensure we only bump the seqid
by 1.

Signed-off-by: Trond Myklebust <[email protected]>
---
fs/nfs/nfs4_fs.h | 2 --
fs/nfs/nfs4proc.c | 41 ++++++++++++++++++++++++++++++++++++++---
fs/nfs/nfs4state.c | 16 ----------------
3 files changed, 38 insertions(+), 21 deletions(-)

diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index e8f74ed98e42..16b2e5cc3e94 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -491,8 +491,6 @@ extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl);
extern int nfs4_select_rw_stateid(struct nfs4_state *, fmode_t,
const struct nfs_lock_context *, nfs4_stateid *,
const struct cred **);
-extern bool nfs4_refresh_open_stateid(nfs4_stateid *dst,
- struct nfs4_state *state);
extern bool nfs4_copy_open_stateid(nfs4_stateid *dst,
struct nfs4_state *state);

diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 025dd5efbf34..49f301198008 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -3308,6 +3308,42 @@ nfs4_wait_on_layoutreturn(struct inode *inode, struct rpc_task *task)
return pnfs_wait_on_layoutreturn(inode, task);
}

+/*
+ * Update the seqid of an open stateid after receiving
+ * NFS4ERR_OLD_STATEID
+ */
+static bool nfs4_refresh_open_old_stateid(nfs4_stateid *dst,
+ struct nfs4_state *state)
+{
+ __be32 seqid_open;
+ u32 dst_seqid;
+ bool ret;
+ int seq;
+
+ for (;;) {
+ ret = false;
+ seq = read_seqbegin(&state->seqlock);
+ if (!nfs4_state_match_open_stateid_other(state, dst)) {
+ if (read_seqretry(&state->seqlock, seq))
+ continue;
+ break;
+ }
+ seqid_open = state->open_stateid.seqid;
+ dst_seqid = be32_to_cpu(dst->seqid);
+
+ if (read_seqretry(&state->seqlock, seq))
+ continue;
+ if ((s32)(dst_seqid - be32_to_cpu(seqid_open)) >= 0)
+ dst->seqid = cpu_to_be32(dst_seqid + 1);
+ else
+ dst->seqid = seqid_open;
+ ret = true;
+ break;
+ }
+
+ return ret;
+}
+
struct nfs4_closedata {
struct inode *inode;
struct nfs4_state *state;
@@ -3382,7 +3418,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
break;
case -NFS4ERR_OLD_STATEID:
/* Did we race with OPEN? */
- if (nfs4_refresh_open_stateid(&calldata->arg.stateid,
+ if (nfs4_refresh_open_old_stateid(&calldata->arg.stateid,
state))
goto out_restart;
goto out_release;
@@ -3451,8 +3487,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
} else if (is_rdwr)
calldata->arg.fmode |= FMODE_READ|FMODE_WRITE;

- if (!nfs4_valid_open_stateid(state) ||
- !nfs4_refresh_open_stateid(&calldata->arg.stateid, state))
+ if (!nfs4_valid_open_stateid(state))
call_close = 0;
spin_unlock(&state->owner->so_lock);

diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index cad4e064b328..e23945174da4 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -1015,22 +1015,6 @@ static int nfs4_copy_lock_stateid(nfs4_stateid *dst,
return ret;
}

-bool nfs4_refresh_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
-{
- bool ret;
- int seq;
-
- do {
- ret = false;
- seq = read_seqbegin(&state->seqlock);
- if (nfs4_state_match_open_stateid_other(state, dst)) {
- dst->seqid = state->open_stateid.seqid;
- ret = true;
- }
- } while (read_seqretry(&state->seqlock, seq));
- return ret;
-}
-
bool nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
{
bool ret;
--
2.21.0

2019-09-11 22:22:42

by Olga Kornievskaia

[permalink] [raw]
Subject: Re: [PATCH 8/9] NFSv4: Handle NFS4ERR_OLD_STATEID in CLOSE/OPEN_DOWNGRADE

Hi Trond,

This patch is causing me "problem" (can be seen using generic/323).
This test creates 100 processes that each want to open the same file,
then close it. Each open gets a stateid with an increasing seqid (the
last received by the client is stateid seqid=100). With the patch,
upon close I see 1st CLOSE use stateid seqid=1 which ends up failing
with ERR_OLD_STATEID and retried until stateid seqid=100 (which was
the current id). Reverting the patch give back sending the CLOSE with
seqid=100. While nothing failing, I don't think the client's behavior
is correct.

On Tue, Sep 10, 2019 at 4:10 AM Trond Myklebust <[email protected]> wrote:
>
> If a CLOSE or OPEN_DOWNGRADE operation receives a NFS4ERR_OLD_STATEID
> then bump the seqid before resending. Ensure we only bump the seqid
> by 1.
>
> Signed-off-by: Trond Myklebust <[email protected]>
> ---
> fs/nfs/nfs4_fs.h | 2 --
> fs/nfs/nfs4proc.c | 41 ++++++++++++++++++++++++++++++++++++++---
> fs/nfs/nfs4state.c | 16 ----------------
> 3 files changed, 38 insertions(+), 21 deletions(-)
>
> diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
> index e8f74ed98e42..16b2e5cc3e94 100644
> --- a/fs/nfs/nfs4_fs.h
> +++ b/fs/nfs/nfs4_fs.h
> @@ -491,8 +491,6 @@ extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl);
> extern int nfs4_select_rw_stateid(struct nfs4_state *, fmode_t,
> const struct nfs_lock_context *, nfs4_stateid *,
> const struct cred **);
> -extern bool nfs4_refresh_open_stateid(nfs4_stateid *dst,
> - struct nfs4_state *state);
> extern bool nfs4_copy_open_stateid(nfs4_stateid *dst,
> struct nfs4_state *state);
>
> diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
> index 025dd5efbf34..49f301198008 100644
> --- a/fs/nfs/nfs4proc.c
> +++ b/fs/nfs/nfs4proc.c
> @@ -3308,6 +3308,42 @@ nfs4_wait_on_layoutreturn(struct inode *inode, struct rpc_task *task)
> return pnfs_wait_on_layoutreturn(inode, task);
> }
>
> +/*
> + * Update the seqid of an open stateid after receiving
> + * NFS4ERR_OLD_STATEID
> + */
> +static bool nfs4_refresh_open_old_stateid(nfs4_stateid *dst,
> + struct nfs4_state *state)
> +{
> + __be32 seqid_open;
> + u32 dst_seqid;
> + bool ret;
> + int seq;
> +
> + for (;;) {
> + ret = false;
> + seq = read_seqbegin(&state->seqlock);
> + if (!nfs4_state_match_open_stateid_other(state, dst)) {
> + if (read_seqretry(&state->seqlock, seq))
> + continue;
> + break;
> + }
> + seqid_open = state->open_stateid.seqid;
> + dst_seqid = be32_to_cpu(dst->seqid);
> +
> + if (read_seqretry(&state->seqlock, seq))
> + continue;
> + if ((s32)(dst_seqid - be32_to_cpu(seqid_open)) >= 0)
> + dst->seqid = cpu_to_be32(dst_seqid + 1);
> + else
> + dst->seqid = seqid_open;
> + ret = true;
> + break;
> + }
> +
> + return ret;
> +}
> +
> struct nfs4_closedata {
> struct inode *inode;
> struct nfs4_state *state;
> @@ -3382,7 +3418,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
> break;
> case -NFS4ERR_OLD_STATEID:
> /* Did we race with OPEN? */
> - if (nfs4_refresh_open_stateid(&calldata->arg.stateid,
> + if (nfs4_refresh_open_old_stateid(&calldata->arg.stateid,
> state))
> goto out_restart;
> goto out_release;
> @@ -3451,8 +3487,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
> } else if (is_rdwr)
> calldata->arg.fmode |= FMODE_READ|FMODE_WRITE;
>
> - if (!nfs4_valid_open_stateid(state) ||
> - !nfs4_refresh_open_stateid(&calldata->arg.stateid, state))
> + if (!nfs4_valid_open_stateid(state))
> call_close = 0;
> spin_unlock(&state->owner->so_lock);
>
> diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
> index cad4e064b328..e23945174da4 100644
> --- a/fs/nfs/nfs4state.c
> +++ b/fs/nfs/nfs4state.c
> @@ -1015,22 +1015,6 @@ static int nfs4_copy_lock_stateid(nfs4_stateid *dst,
> return ret;
> }
>
> -bool nfs4_refresh_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
> -{
> - bool ret;
> - int seq;
> -
> - do {
> - ret = false;
> - seq = read_seqbegin(&state->seqlock);
> - if (nfs4_state_match_open_stateid_other(state, dst)) {
> - dst->seqid = state->open_stateid.seqid;
> - ret = true;
> - }
> - } while (read_seqretry(&state->seqlock, seq));
> - return ret;
> -}
> -
> bool nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
> {
> bool ret;
> --
> 2.21.0
>

2019-09-11 22:30:16

by Trond Myklebust

[permalink] [raw]
Subject: Re: [PATCH 8/9] NFSv4: Handle NFS4ERR_OLD_STATEID in CLOSE/OPEN_DOWNGRADE

Hi Olga

On Wed, 2019-09-11 at 16:13 -0400, Olga Kornievskaia wrote:
> Hi Trond,
>
> This patch is causing me "problem" (can be seen using generic/323).
> This test creates 100 processes that each want to open the same file,
> then close it. Each open gets a stateid with an increasing seqid (the
> last received by the client is stateid seqid=100). With the patch,
> upon close I see 1st CLOSE use stateid seqid=1 which ends up failing
> with ERR_OLD_STATEID and retried until stateid seqid=100 (which was
> the current id). Reverting the patch give back sending the CLOSE with
> seqid=100. While nothing failing, I don't think the client's behavior
> is correct.

Does the following work for you?

Cheers
Trond

8<---------------------------------------------
From 859f6c0f468785770c6e87ae4f62294415018e89 Mon Sep 17 00:00:00 2001
From: Trond Myklebust <[email protected]>
Date: Tue, 3 Sep 2019 17:37:19 -0400
Subject: [PATCH v2] NFSv4: Handle NFS4ERR_OLD_STATEID in CLOSE/OPEN_DOWNGRADE

If a CLOSE or OPEN_DOWNGRADE operation receives a NFS4ERR_OLD_STATEID
then bump the seqid before resending. Ensure we only bump the seqid
by 1.

Signed-off-by: Trond Myklebust <[email protected]>
---
fs/nfs/nfs4_fs.h | 2 --
fs/nfs/nfs4proc.c | 75 ++++++++++++++++++++++++++++++++++++++++++++--
fs/nfs/nfs4state.c | 16 ----------
3 files changed, 72 insertions(+), 21 deletions(-)

diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index e8f74ed98e42..16b2e5cc3e94 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -491,8 +491,6 @@ extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl);
extern int nfs4_select_rw_stateid(struct nfs4_state *, fmode_t,
const struct nfs_lock_context *, nfs4_stateid *,
const struct cred **);
-extern bool nfs4_refresh_open_stateid(nfs4_stateid *dst,
- struct nfs4_state *state);
extern bool nfs4_copy_open_stateid(nfs4_stateid *dst,
struct nfs4_state *state);

diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 025dd5efbf34..c14af2c1c6b6 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -3308,6 +3308,75 @@ nfs4_wait_on_layoutreturn(struct inode *inode, struct rpc_task *task)
return pnfs_wait_on_layoutreturn(inode, task);
}

+/*
+ * Update the seqid of an open stateid
+ */
+static void nfs4_sync_open_stateid(nfs4_stateid *dst,
+ struct nfs4_state *state)
+{
+ __be32 seqid_open;
+ u32 dst_seqid;
+ int seq;
+
+ for (;;) {
+ if (!nfs4_valid_open_stateid(state))
+ break;
+ seq = read_seqbegin(&state->seqlock);
+ if (!nfs4_state_match_open_stateid_other(state, dst)) {
+ nfs4_stateid_copy(dst, &state->open_stateid);
+ if (read_seqretry(&state->seqlock, seq))
+ continue;
+ break;
+ }
+ seqid_open = state->open_stateid.seqid;
+ if (read_seqretry(&state->seqlock, seq))
+ continue;
+
+ dst_seqid = be32_to_cpu(dst->seqid);
+ if ((s32)(dst_seqid - be32_to_cpu(seqid_open)) < 0)
+ dst->seqid = seqid_open;
+ break;
+ }
+}
+
+/*
+ * Update the seqid of an open stateid after receiving
+ * NFS4ERR_OLD_STATEID
+ */
+static bool nfs4_refresh_open_old_stateid(nfs4_stateid *dst,
+ struct nfs4_state *state)
+{
+ __be32 seqid_open;
+ u32 dst_seqid;
+ bool ret;
+ int seq;
+
+ for (;;) {
+ ret = false;
+ if (!nfs4_valid_open_stateid(state))
+ break;
+ seq = read_seqbegin(&state->seqlock);
+ if (!nfs4_state_match_open_stateid_other(state, dst)) {
+ if (read_seqretry(&state->seqlock, seq))
+ continue;
+ break;
+ }
+ seqid_open = state->open_stateid.seqid;
+ if (read_seqretry(&state->seqlock, seq))
+ continue;
+
+ dst_seqid = be32_to_cpu(dst->seqid);
+ if ((s32)(dst_seqid - be32_to_cpu(seqid_open)) >= 0)
+ dst->seqid = cpu_to_be32(dst_seqid + 1);
+ else
+ dst->seqid = seqid_open;
+ ret = true;
+ break;
+ }
+
+ return ret;
+}
+
struct nfs4_closedata {
struct inode *inode;
struct nfs4_state *state;
@@ -3382,7 +3451,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
break;
case -NFS4ERR_OLD_STATEID:
/* Did we race with OPEN? */
- if (nfs4_refresh_open_stateid(&calldata->arg.stateid,
+ if (nfs4_refresh_open_old_stateid(&calldata->arg.stateid,
state))
goto out_restart;
goto out_release;
@@ -3451,8 +3520,8 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
} else if (is_rdwr)
calldata->arg.fmode |= FMODE_READ|FMODE_WRITE;

- if (!nfs4_valid_open_stateid(state) ||
- !nfs4_refresh_open_stateid(&calldata->arg.stateid, state))
+ nfs4_sync_open_stateid(&calldata->arg.stateid, state);
+ if (!nfs4_valid_open_stateid(state))
call_close = 0;
spin_unlock(&state->owner->so_lock);

diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index cad4e064b328..e23945174da4 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -1015,22 +1015,6 @@ static int nfs4_copy_lock_stateid(nfs4_stateid *dst,
return ret;
}

-bool nfs4_refresh_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
-{
- bool ret;
- int seq;
-
- do {
- ret = false;
- seq = read_seqbegin(&state->seqlock);
- if (nfs4_state_match_open_stateid_other(state, dst)) {
- dst->seqid = state->open_stateid.seqid;
- ret = true;
- }
- } while (read_seqretry(&state->seqlock, seq));
- return ret;
-}
-
bool nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
{
bool ret;
--
2.21.0

--
Trond Myklebust
Linux NFS client maintainer, Hammerspace
[email protected]


2019-09-12 15:04:13

by Olga Kornievskaia

[permalink] [raw]
Subject: Re: [PATCH 8/9] NFSv4: Handle NFS4ERR_OLD_STATEID in CLOSE/OPEN_DOWNGRADE

On Wed, Sep 11, 2019 at 4:56 PM Trond Myklebust <[email protected]> wrote:
>
> Hi Olga
>
> On Wed, 2019-09-11 at 16:13 -0400, Olga Kornievskaia wrote:
> > Hi Trond,
> >
> > This patch is causing me "problem" (can be seen using generic/323).
> > This test creates 100 processes that each want to open the same file,
> > then close it. Each open gets a stateid with an increasing seqid (the
> > last received by the client is stateid seqid=100). With the patch,
> > upon close I see 1st CLOSE use stateid seqid=1 which ends up failing
> > with ERR_OLD_STATEID and retried until stateid seqid=100 (which was
> > the current id). Reverting the patch give back sending the CLOSE with
> > seqid=100. While nothing failing, I don't think the client's behavior
> > is correct.
>
> Does the following work for you?

Yes that fixes the stateid usage.

>
> Cheers
> Trond
>
> 8<---------------------------------------------
> From 859f6c0f468785770c6e87ae4f62294415018e89 Mon Sep 17 00:00:00 2001
> From: Trond Myklebust <[email protected]>
> Date: Tue, 3 Sep 2019 17:37:19 -0400
> Subject: [PATCH v2] NFSv4: Handle NFS4ERR_OLD_STATEID in CLOSE/OPEN_DOWNGRADE
>
> If a CLOSE or OPEN_DOWNGRADE operation receives a NFS4ERR_OLD_STATEID
> then bump the seqid before resending. Ensure we only bump the seqid
> by 1.
>
> Signed-off-by: Trond Myklebust <[email protected]>
> ---
> fs/nfs/nfs4_fs.h | 2 --
> fs/nfs/nfs4proc.c | 75 ++++++++++++++++++++++++++++++++++++++++++++--
> fs/nfs/nfs4state.c | 16 ----------
> 3 files changed, 72 insertions(+), 21 deletions(-)
>
> diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
> index e8f74ed98e42..16b2e5cc3e94 100644
> --- a/fs/nfs/nfs4_fs.h
> +++ b/fs/nfs/nfs4_fs.h
> @@ -491,8 +491,6 @@ extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl);
> extern int nfs4_select_rw_stateid(struct nfs4_state *, fmode_t,
> const struct nfs_lock_context *, nfs4_stateid *,
> const struct cred **);
> -extern bool nfs4_refresh_open_stateid(nfs4_stateid *dst,
> - struct nfs4_state *state);
> extern bool nfs4_copy_open_stateid(nfs4_stateid *dst,
> struct nfs4_state *state);
>
> diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
> index 025dd5efbf34..c14af2c1c6b6 100644
> --- a/fs/nfs/nfs4proc.c
> +++ b/fs/nfs/nfs4proc.c
> @@ -3308,6 +3308,75 @@ nfs4_wait_on_layoutreturn(struct inode *inode, struct rpc_task *task)
> return pnfs_wait_on_layoutreturn(inode, task);
> }
>
> +/*
> + * Update the seqid of an open stateid
> + */
> +static void nfs4_sync_open_stateid(nfs4_stateid *dst,
> + struct nfs4_state *state)
> +{
> + __be32 seqid_open;
> + u32 dst_seqid;
> + int seq;
> +
> + for (;;) {
> + if (!nfs4_valid_open_stateid(state))
> + break;
> + seq = read_seqbegin(&state->seqlock);
> + if (!nfs4_state_match_open_stateid_other(state, dst)) {
> + nfs4_stateid_copy(dst, &state->open_stateid);
> + if (read_seqretry(&state->seqlock, seq))
> + continue;
> + break;
> + }
> + seqid_open = state->open_stateid.seqid;
> + if (read_seqretry(&state->seqlock, seq))
> + continue;
> +
> + dst_seqid = be32_to_cpu(dst->seqid);
> + if ((s32)(dst_seqid - be32_to_cpu(seqid_open)) < 0)
> + dst->seqid = seqid_open;
> + break;
> + }
> +}
> +
> +/*
> + * Update the seqid of an open stateid after receiving
> + * NFS4ERR_OLD_STATEID
> + */
> +static bool nfs4_refresh_open_old_stateid(nfs4_stateid *dst,
> + struct nfs4_state *state)
> +{
> + __be32 seqid_open;
> + u32 dst_seqid;
> + bool ret;
> + int seq;
> +
> + for (;;) {
> + ret = false;
> + if (!nfs4_valid_open_stateid(state))
> + break;
> + seq = read_seqbegin(&state->seqlock);
> + if (!nfs4_state_match_open_stateid_other(state, dst)) {
> + if (read_seqretry(&state->seqlock, seq))
> + continue;
> + break;
> + }
> + seqid_open = state->open_stateid.seqid;
> + if (read_seqretry(&state->seqlock, seq))
> + continue;
> +
> + dst_seqid = be32_to_cpu(dst->seqid);
> + if ((s32)(dst_seqid - be32_to_cpu(seqid_open)) >= 0)
> + dst->seqid = cpu_to_be32(dst_seqid + 1);
> + else
> + dst->seqid = seqid_open;
> + ret = true;
> + break;
> + }
> +
> + return ret;
> +}
> +
> struct nfs4_closedata {
> struct inode *inode;
> struct nfs4_state *state;
> @@ -3382,7 +3451,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
> break;
> case -NFS4ERR_OLD_STATEID:
> /* Did we race with OPEN? */
> - if (nfs4_refresh_open_stateid(&calldata->arg.stateid,
> + if (nfs4_refresh_open_old_stateid(&calldata->arg.stateid,
> state))
> goto out_restart;
> goto out_release;
> @@ -3451,8 +3520,8 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
> } else if (is_rdwr)
> calldata->arg.fmode |= FMODE_READ|FMODE_WRITE;
>
> - if (!nfs4_valid_open_stateid(state) ||
> - !nfs4_refresh_open_stateid(&calldata->arg.stateid, state))
> + nfs4_sync_open_stateid(&calldata->arg.stateid, state);
> + if (!nfs4_valid_open_stateid(state))
> call_close = 0;
> spin_unlock(&state->owner->so_lock);
>
> diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
> index cad4e064b328..e23945174da4 100644
> --- a/fs/nfs/nfs4state.c
> +++ b/fs/nfs/nfs4state.c
> @@ -1015,22 +1015,6 @@ static int nfs4_copy_lock_stateid(nfs4_stateid *dst,
> return ret;
> }
>
> -bool nfs4_refresh_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
> -{
> - bool ret;
> - int seq;
> -
> - do {
> - ret = false;
> - seq = read_seqbegin(&state->seqlock);
> - if (nfs4_state_match_open_stateid_other(state, dst)) {
> - dst->seqid = state->open_stateid.seqid;
> - ret = true;
> - }
> - } while (read_seqretry(&state->seqlock, seq));
> - return ret;
> -}
> -
> bool nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
> {
> bool ret;
> --
> 2.21.0
>
> --
> Trond Myklebust
> Linux NFS client maintainer, Hammerspace
> [email protected]
>
>

2019-09-12 15:05:48

by Olga Kornievskaia

[permalink] [raw]
Subject: Re: [PATCH 8/9] NFSv4: Handle NFS4ERR_OLD_STATEID in CLOSE/OPEN_DOWNGRADE

On Thu, Sep 12, 2019 at 11:01 AM Olga Kornievskaia <[email protected]> wrote:
>
> On Wed, Sep 11, 2019 at 4:56 PM Trond Myklebust <[email protected]> wrote:
> >
> > Hi Olga
> >
> > On Wed, 2019-09-11 at 16:13 -0400, Olga Kornievskaia wrote:
> > > Hi Trond,
> > >
> > > This patch is causing me "problem" (can be seen using generic/323).
> > > This test creates 100 processes that each want to open the same file,
> > > then close it. Each open gets a stateid with an increasing seqid (the
> > > last received by the client is stateid seqid=100). With the patch,
> > > upon close I see 1st CLOSE use stateid seqid=1 which ends up failing
> > > with ERR_OLD_STATEID and retried until stateid seqid=100 (which was
> > > the current id). Reverting the patch give back sending the CLOSE with
> > > seqid=100. While nothing failing, I don't think the client's behavior
> > > is correct.
> >
> > Does the following work for you?
>
> Yes that fixes the stateid usage.

Is the same fix needed for the unlock case? I don't have a good test
case for the unlock.

>
> >
> > Cheers
> > Trond
> >
> > 8<---------------------------------------------
> > From 859f6c0f468785770c6e87ae4f62294415018e89 Mon Sep 17 00:00:00 2001
> > From: Trond Myklebust <[email protected]>
> > Date: Tue, 3 Sep 2019 17:37:19 -0400
> > Subject: [PATCH v2] NFSv4: Handle NFS4ERR_OLD_STATEID in CLOSE/OPEN_DOWNGRADE
> >
> > If a CLOSE or OPEN_DOWNGRADE operation receives a NFS4ERR_OLD_STATEID
> > then bump the seqid before resending. Ensure we only bump the seqid
> > by 1.
> >
> > Signed-off-by: Trond Myklebust <[email protected]>
> > ---
> > fs/nfs/nfs4_fs.h | 2 --
> > fs/nfs/nfs4proc.c | 75 ++++++++++++++++++++++++++++++++++++++++++++--
> > fs/nfs/nfs4state.c | 16 ----------
> > 3 files changed, 72 insertions(+), 21 deletions(-)
> >
> > diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
> > index e8f74ed98e42..16b2e5cc3e94 100644
> > --- a/fs/nfs/nfs4_fs.h
> > +++ b/fs/nfs/nfs4_fs.h
> > @@ -491,8 +491,6 @@ extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl);
> > extern int nfs4_select_rw_stateid(struct nfs4_state *, fmode_t,
> > const struct nfs_lock_context *, nfs4_stateid *,
> > const struct cred **);
> > -extern bool nfs4_refresh_open_stateid(nfs4_stateid *dst,
> > - struct nfs4_state *state);
> > extern bool nfs4_copy_open_stateid(nfs4_stateid *dst,
> > struct nfs4_state *state);
> >
> > diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
> > index 025dd5efbf34..c14af2c1c6b6 100644
> > --- a/fs/nfs/nfs4proc.c
> > +++ b/fs/nfs/nfs4proc.c
> > @@ -3308,6 +3308,75 @@ nfs4_wait_on_layoutreturn(struct inode *inode, struct rpc_task *task)
> > return pnfs_wait_on_layoutreturn(inode, task);
> > }
> >
> > +/*
> > + * Update the seqid of an open stateid
> > + */
> > +static void nfs4_sync_open_stateid(nfs4_stateid *dst,
> > + struct nfs4_state *state)
> > +{
> > + __be32 seqid_open;
> > + u32 dst_seqid;
> > + int seq;
> > +
> > + for (;;) {
> > + if (!nfs4_valid_open_stateid(state))
> > + break;
> > + seq = read_seqbegin(&state->seqlock);
> > + if (!nfs4_state_match_open_stateid_other(state, dst)) {
> > + nfs4_stateid_copy(dst, &state->open_stateid);
> > + if (read_seqretry(&state->seqlock, seq))
> > + continue;
> > + break;
> > + }
> > + seqid_open = state->open_stateid.seqid;
> > + if (read_seqretry(&state->seqlock, seq))
> > + continue;
> > +
> > + dst_seqid = be32_to_cpu(dst->seqid);
> > + if ((s32)(dst_seqid - be32_to_cpu(seqid_open)) < 0)
> > + dst->seqid = seqid_open;
> > + break;
> > + }
> > +}
> > +
> > +/*
> > + * Update the seqid of an open stateid after receiving
> > + * NFS4ERR_OLD_STATEID
> > + */
> > +static bool nfs4_refresh_open_old_stateid(nfs4_stateid *dst,
> > + struct nfs4_state *state)
> > +{
> > + __be32 seqid_open;
> > + u32 dst_seqid;
> > + bool ret;
> > + int seq;
> > +
> > + for (;;) {
> > + ret = false;
> > + if (!nfs4_valid_open_stateid(state))
> > + break;
> > + seq = read_seqbegin(&state->seqlock);
> > + if (!nfs4_state_match_open_stateid_other(state, dst)) {
> > + if (read_seqretry(&state->seqlock, seq))
> > + continue;
> > + break;
> > + }
> > + seqid_open = state->open_stateid.seqid;
> > + if (read_seqretry(&state->seqlock, seq))
> > + continue;
> > +
> > + dst_seqid = be32_to_cpu(dst->seqid);
> > + if ((s32)(dst_seqid - be32_to_cpu(seqid_open)) >= 0)
> > + dst->seqid = cpu_to_be32(dst_seqid + 1);
> > + else
> > + dst->seqid = seqid_open;
> > + ret = true;
> > + break;
> > + }
> > +
> > + return ret;
> > +}
> > +
> > struct nfs4_closedata {
> > struct inode *inode;
> > struct nfs4_state *state;
> > @@ -3382,7 +3451,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
> > break;
> > case -NFS4ERR_OLD_STATEID:
> > /* Did we race with OPEN? */
> > - if (nfs4_refresh_open_stateid(&calldata->arg.stateid,
> > + if (nfs4_refresh_open_old_stateid(&calldata->arg.stateid,
> > state))
> > goto out_restart;
> > goto out_release;
> > @@ -3451,8 +3520,8 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
> > } else if (is_rdwr)
> > calldata->arg.fmode |= FMODE_READ|FMODE_WRITE;
> >
> > - if (!nfs4_valid_open_stateid(state) ||
> > - !nfs4_refresh_open_stateid(&calldata->arg.stateid, state))
> > + nfs4_sync_open_stateid(&calldata->arg.stateid, state);
> > + if (!nfs4_valid_open_stateid(state))
> > call_close = 0;
> > spin_unlock(&state->owner->so_lock);
> >
> > diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
> > index cad4e064b328..e23945174da4 100644
> > --- a/fs/nfs/nfs4state.c
> > +++ b/fs/nfs/nfs4state.c
> > @@ -1015,22 +1015,6 @@ static int nfs4_copy_lock_stateid(nfs4_stateid *dst,
> > return ret;
> > }
> >
> > -bool nfs4_refresh_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
> > -{
> > - bool ret;
> > - int seq;
> > -
> > - do {
> > - ret = false;
> > - seq = read_seqbegin(&state->seqlock);
> > - if (nfs4_state_match_open_stateid_other(state, dst)) {
> > - dst->seqid = state->open_stateid.seqid;
> > - ret = true;
> > - }
> > - } while (read_seqretry(&state->seqlock, seq));
> > - return ret;
> > -}
> > -
> > bool nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
> > {
> > bool ret;
> > --
> > 2.21.0
> >
> > --
> > Trond Myklebust
> > Linux NFS client maintainer, Hammerspace
> > [email protected]
> >
> >

2019-09-16 21:44:33

by Olga Kornievskaia

[permalink] [raw]
Subject: Re: [PATCH 8/9] NFSv4: Handle NFS4ERR_OLD_STATEID in CLOSE/OPEN_DOWNGRADE

On Thu, Sep 12, 2019 at 11:01 AM Olga Kornievskaia <[email protected]> wrote:
>
> On Wed, Sep 11, 2019 at 4:56 PM Trond Myklebust <[email protected]> wrote:
> >
> > Hi Olga
> >
> > On Wed, 2019-09-11 at 16:13 -0400, Olga Kornievskaia wrote:
> > > Hi Trond,
> > >
> > > This patch is causing me "problem" (can be seen using generic/323).
> > > This test creates 100 processes that each want to open the same file,
> > > then close it. Each open gets a stateid with an increasing seqid (the
> > > last received by the client is stateid seqid=100). With the patch,
> > > upon close I see 1st CLOSE use stateid seqid=1 which ends up failing
> > > with ERR_OLD_STATEID and retried until stateid seqid=100 (which was
> > > the current id). Reverting the patch give back sending the CLOSE with
> > > seqid=100. While nothing failing, I don't think the client's behavior
> > > is correct.
> >
> > Does the following work for you?
>
> Yes that fixes the stateid usage.

Hi Trond,

Will you be posting the v2 of the patches?

I'm slowly going thru the tests. I have questioned the LAYOUTGET patch
but I haven't figured out a test for it yet. In general, is it
possible to wait on this patch series as I already found 2 issues with
it and need a bit more testing to complete my testing. I don't feel
like patches are ready the way they are.

Thanks.


>
> >
> > Cheers
> > Trond
> >
> > 8<---------------------------------------------
> > From 859f6c0f468785770c6e87ae4f62294415018e89 Mon Sep 17 00:00:00 2001
> > From: Trond Myklebust <[email protected]>
> > Date: Tue, 3 Sep 2019 17:37:19 -0400
> > Subject: [PATCH v2] NFSv4: Handle NFS4ERR_OLD_STATEID in CLOSE/OPEN_DOWNGRADE
> >
> > If a CLOSE or OPEN_DOWNGRADE operation receives a NFS4ERR_OLD_STATEID
> > then bump the seqid before resending. Ensure we only bump the seqid
> > by 1.
> >
> > Signed-off-by: Trond Myklebust <[email protected]>
> > ---
> > fs/nfs/nfs4_fs.h | 2 --
> > fs/nfs/nfs4proc.c | 75 ++++++++++++++++++++++++++++++++++++++++++++--
> > fs/nfs/nfs4state.c | 16 ----------
> > 3 files changed, 72 insertions(+), 21 deletions(-)
> >
> > diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
> > index e8f74ed98e42..16b2e5cc3e94 100644
> > --- a/fs/nfs/nfs4_fs.h
> > +++ b/fs/nfs/nfs4_fs.h
> > @@ -491,8 +491,6 @@ extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl);
> > extern int nfs4_select_rw_stateid(struct nfs4_state *, fmode_t,
> > const struct nfs_lock_context *, nfs4_stateid *,
> > const struct cred **);
> > -extern bool nfs4_refresh_open_stateid(nfs4_stateid *dst,
> > - struct nfs4_state *state);
> > extern bool nfs4_copy_open_stateid(nfs4_stateid *dst,
> > struct nfs4_state *state);
> >
> > diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
> > index 025dd5efbf34..c14af2c1c6b6 100644
> > --- a/fs/nfs/nfs4proc.c
> > +++ b/fs/nfs/nfs4proc.c
> > @@ -3308,6 +3308,75 @@ nfs4_wait_on_layoutreturn(struct inode *inode, struct rpc_task *task)
> > return pnfs_wait_on_layoutreturn(inode, task);
> > }
> >
> > +/*
> > + * Update the seqid of an open stateid
> > + */
> > +static void nfs4_sync_open_stateid(nfs4_stateid *dst,
> > + struct nfs4_state *state)
> > +{
> > + __be32 seqid_open;
> > + u32 dst_seqid;
> > + int seq;
> > +
> > + for (;;) {
> > + if (!nfs4_valid_open_stateid(state))
> > + break;
> > + seq = read_seqbegin(&state->seqlock);
> > + if (!nfs4_state_match_open_stateid_other(state, dst)) {
> > + nfs4_stateid_copy(dst, &state->open_stateid);
> > + if (read_seqretry(&state->seqlock, seq))
> > + continue;
> > + break;
> > + }
> > + seqid_open = state->open_stateid.seqid;
> > + if (read_seqretry(&state->seqlock, seq))
> > + continue;
> > +
> > + dst_seqid = be32_to_cpu(dst->seqid);
> > + if ((s32)(dst_seqid - be32_to_cpu(seqid_open)) < 0)
> > + dst->seqid = seqid_open;
> > + break;
> > + }
> > +}
> > +
> > +/*
> > + * Update the seqid of an open stateid after receiving
> > + * NFS4ERR_OLD_STATEID
> > + */
> > +static bool nfs4_refresh_open_old_stateid(nfs4_stateid *dst,
> > + struct nfs4_state *state)
> > +{
> > + __be32 seqid_open;
> > + u32 dst_seqid;
> > + bool ret;
> > + int seq;
> > +
> > + for (;;) {
> > + ret = false;
> > + if (!nfs4_valid_open_stateid(state))
> > + break;
> > + seq = read_seqbegin(&state->seqlock);
> > + if (!nfs4_state_match_open_stateid_other(state, dst)) {
> > + if (read_seqretry(&state->seqlock, seq))
> > + continue;
> > + break;
> > + }
> > + seqid_open = state->open_stateid.seqid;
> > + if (read_seqretry(&state->seqlock, seq))
> > + continue;
> > +
> > + dst_seqid = be32_to_cpu(dst->seqid);
> > + if ((s32)(dst_seqid - be32_to_cpu(seqid_open)) >= 0)
> > + dst->seqid = cpu_to_be32(dst_seqid + 1);
> > + else
> > + dst->seqid = seqid_open;
> > + ret = true;
> > + break;
> > + }
> > +
> > + return ret;
> > +}
> > +
> > struct nfs4_closedata {
> > struct inode *inode;
> > struct nfs4_state *state;
> > @@ -3382,7 +3451,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
> > break;
> > case -NFS4ERR_OLD_STATEID:
> > /* Did we race with OPEN? */
> > - if (nfs4_refresh_open_stateid(&calldata->arg.stateid,
> > + if (nfs4_refresh_open_old_stateid(&calldata->arg.stateid,
> > state))
> > goto out_restart;
> > goto out_release;
> > @@ -3451,8 +3520,8 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
> > } else if (is_rdwr)
> > calldata->arg.fmode |= FMODE_READ|FMODE_WRITE;
> >
> > - if (!nfs4_valid_open_stateid(state) ||
> > - !nfs4_refresh_open_stateid(&calldata->arg.stateid, state))
> > + nfs4_sync_open_stateid(&calldata->arg.stateid, state);
> > + if (!nfs4_valid_open_stateid(state))
> > call_close = 0;
> > spin_unlock(&state->owner->so_lock);
> >
> > diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
> > index cad4e064b328..e23945174da4 100644
> > --- a/fs/nfs/nfs4state.c
> > +++ b/fs/nfs/nfs4state.c
> > @@ -1015,22 +1015,6 @@ static int nfs4_copy_lock_stateid(nfs4_stateid *dst,
> > return ret;
> > }
> >
> > -bool nfs4_refresh_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
> > -{
> > - bool ret;
> > - int seq;
> > -
> > - do {
> > - ret = false;
> > - seq = read_seqbegin(&state->seqlock);
> > - if (nfs4_state_match_open_stateid_other(state, dst)) {
> > - dst->seqid = state->open_stateid.seqid;
> > - ret = true;
> > - }
> > - } while (read_seqretry(&state->seqlock, seq));
> > - return ret;
> > -}
> > -
> > bool nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
> > {
> > bool ret;
> > --
> > 2.21.0
> >
> > --
> > Trond Myklebust
> > Linux NFS client maintainer, Hammerspace
> > [email protected]
> >
> >