diff mbox series

[8/9] NFSv4: Handle NFS4ERR_OLD_STATEID in CLOSE/OPEN_DOWNGRADE

Message ID 20190909140104.78818-8-trond.myklebust@hammerspace.com (mailing list archive)
State New, archived
Headers show
Series [1/9] pNFS: Ensure we do clear the return-on-close layout stateid on fatal errors | expand

Commit Message

Trond Myklebust Sept. 9, 2019, 2:01 p.m. UTC
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 <trond.myklebust@hammerspace.com>
---
 fs/nfs/nfs4_fs.h   |  2 --
 fs/nfs/nfs4proc.c  | 41 ++++++++++++++++++++++++++++++++++++++---
 fs/nfs/nfs4state.c | 16 ----------------
 3 files changed, 38 insertions(+), 21 deletions(-)

Comments

Olga Kornievskaia Sept. 11, 2019, 8:13 p.m. UTC | #1
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 <trondmy@gmail.com> 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 <trond.myklebust@hammerspace.com>
> ---
>  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
>
Trond Myklebust Sept. 11, 2019, 8:56 p.m. UTC | #2
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 <trond.myklebust@hammerspace.com>
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 <trond.myklebust@hammerspace.com>
---
 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;
Olga Kornievskaia Sept. 12, 2019, 3:01 p.m. UTC | #3
On Wed, Sep 11, 2019 at 4:56 PM Trond Myklebust <trondmy@hammerspace.com> 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 <trond.myklebust@hammerspace.com>
> 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 <trond.myklebust@hammerspace.com>
> ---
>  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
> trond.myklebust@hammerspace.com
>
>
Olga Kornievskaia Sept. 12, 2019, 3:04 p.m. UTC | #4
On Thu, Sep 12, 2019 at 11:01 AM Olga Kornievskaia <aglo@umich.edu> wrote:
>
> On Wed, Sep 11, 2019 at 4:56 PM Trond Myklebust <trondmy@hammerspace.com> 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 <trond.myklebust@hammerspace.com>
> > 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 <trond.myklebust@hammerspace.com>
> > ---
> >  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
> > trond.myklebust@hammerspace.com
> >
> >
Olga Kornievskaia Sept. 16, 2019, 7:39 p.m. UTC | #5
On Thu, Sep 12, 2019 at 11:01 AM Olga Kornievskaia <aglo@umich.edu> wrote:
>
> On Wed, Sep 11, 2019 at 4:56 PM Trond Myklebust <trondmy@hammerspace.com> 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 <trond.myklebust@hammerspace.com>
> > 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 <trond.myklebust@hammerspace.com>
> > ---
> >  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
> > trond.myklebust@hammerspace.com
> >
> >
diff mbox series

Patch

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;