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 |
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 >
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;
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 > >
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 > > > >
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 --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;
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(-)