All of lore.kernel.org
 help / color / mirror / Atom feed
* [Cluster-devel] [GFS2 PATCH 0/3] Fix how gfs2 handles timed-out dlm requests
@ 2022-01-24 17:23 Bob Peterson
  2022-01-24 17:23 ` [Cluster-devel] [GFS2 PATCH 1/3] gfs2: cancel timed-out glock requests Bob Peterson
                   ` (3 more replies)
  0 siblings, 4 replies; 8+ messages in thread
From: Bob Peterson @ 2022-01-24 17:23 UTC (permalink / raw)
  To: cluster-devel.redhat.com

Recently, we introduced patches to time out lock requests that take too long,
specifically for iopen glocks during ABBA deadlocks during evict. Before
this patch set, gfs2 never canceled the failed requests that timed out,
which can lead to deadlocks to due dlm keeping the requests on its
Conversion queue.

To deal with the timed-out requests properly, and have dlm remove them from
its Conversion queue, gfs2 must send dlm an unlock request with the dlm
"cancel" flag, and then it also must deal with the AST that dlm sends back.
This AST may be a successful response to the Cancel request, or it may be
a successful AST from the original lock request. Either way, gfs2 had
bugs dealing with the situation.

This patch set attempts to fix the problem by sending DLM a cancel and
reacting to its AST. Some ABBA deadlocks were avoided by switching the
order in which gfs2 takes its inode and iopen glocks, which was different
between some lookups and evicts.

In the process of debugging this, we discovered a problem whereby dlm
will reject lock requests with -EBUSY while the request is being canceled.
We want dlm to wait until it's not busy, but until we find a proper dlm
based solution, we need to retry the request.

Andreas Gruenbacher (2):
  gfs2: cancel timed-out glock requests
  gfs2: Switch lock order of inode and iopen glock

Bob Peterson (1):
  gfs2: Retry on dlm -EBUSY (stop gap)

 fs/gfs2/glock.c    | 11 +++++++++++
 fs/gfs2/inode.c    | 49 +++++++++++++++++++++++++---------------------
 fs/gfs2/lock_dlm.c | 22 ++++++++++++++-------
 3 files changed, 53 insertions(+), 29 deletions(-)

-- 
2.34.1



^ permalink raw reply	[flat|nested] 8+ messages in thread

* [Cluster-devel] [GFS2 PATCH 1/3] gfs2: cancel timed-out glock requests
  2022-01-24 17:23 [Cluster-devel] [GFS2 PATCH 0/3] Fix how gfs2 handles timed-out dlm requests Bob Peterson
@ 2022-01-24 17:23 ` Bob Peterson
  2022-01-24 17:23 ` [Cluster-devel] [GFS2 PATCH 2/3] gfs2: Retry on dlm -EBUSY (stop gap) Bob Peterson
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 8+ messages in thread
From: Bob Peterson @ 2022-01-24 17:23 UTC (permalink / raw)
  To: cluster-devel.redhat.com

From: Andreas Gruenbacher <agruenba@redhat.com>

In the gfs2 evict code it tries to upgrade the iopen glock from SH to
EX. If the attempt to upgrade times out, gfs2 needs to tell dlm to
cancel the lock request or it can deadlock. We also need to wake up
the process waiting for the lock when dlm sends its AST back to gfs2.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
---
 fs/gfs2/glock.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index b7ab8430333c..78b0dc04c38a 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -672,6 +672,8 @@ static void finish_xmote(struct gfs2_glock *gl, unsigned int ret)
 
 	/* Check for state != intended state */
 	if (unlikely(state != gl->gl_target)) {
+		if (gh && (ret & LM_OUT_CANCELED))
+			gfs2_holder_wake(gh);
 		if (gh && !test_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags)) {
 			/* move to back of queue and try next entry */
 			if (ret & LM_OUT_CANCELED) {
@@ -1281,6 +1283,7 @@ void gfs2_holder_reinit(unsigned int state, u16 flags, struct gfs2_holder *gh)
 {
 	gh->gh_state = state;
 	gh->gh_flags = flags;
+	gh->gh_error = 0;
 	gh->gh_iflags = 0;
 	gh->gh_ip = _RET_IP_;
 	put_pid(gh->gh_owner_pid);
@@ -1694,6 +1697,14 @@ void gfs2_glock_dq(struct gfs2_holder *gh)
 	struct gfs2_glock *gl = gh->gh_gl;
 
 	spin_lock(&gl->gl_lockref.lock);
+	if (list_is_first(&gh->gh_list, &gl->gl_holders) &&
+	    !test_bit(HIF_HOLDER, &gh->gh_iflags)) {
+		spin_unlock(&gl->gl_lockref.lock);
+		gl->gl_name.ln_sbd->sd_lockstruct.ls_ops->lm_cancel(gl);
+		wait_on_bit(&gh->gh_iflags, HIF_WAIT, TASK_UNINTERRUPTIBLE);
+		spin_lock(&gl->gl_lockref.lock);
+	}
+
 	__gfs2_glock_dq(gh);
 	spin_unlock(&gl->gl_lockref.lock);
 }
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Cluster-devel] [GFS2 PATCH 2/3] gfs2: Retry on dlm -EBUSY (stop gap)
  2022-01-24 17:23 [Cluster-devel] [GFS2 PATCH 0/3] Fix how gfs2 handles timed-out dlm requests Bob Peterson
  2022-01-24 17:23 ` [Cluster-devel] [GFS2 PATCH 1/3] gfs2: cancel timed-out glock requests Bob Peterson
@ 2022-01-24 17:23 ` Bob Peterson
  2022-02-02 15:47   ` Andreas Gruenbacher
  2022-01-24 17:23 ` [Cluster-devel] [GFS2 PATCH 3/3] gfs2: Switch lock order of inode and iopen glock Bob Peterson
  2022-02-02 15:55 ` [Cluster-devel] [PATCH] gfs2: Expect -EBUSY after canceling dlm locking requests Andreas Gruenbacher
  3 siblings, 1 reply; 8+ messages in thread
From: Bob Peterson @ 2022-01-24 17:23 UTC (permalink / raw)
  To: cluster-devel.redhat.com

Sometimes when gfs2 cancels a glock request, dlm needs time to take the
request off its Conversion queue. During that time, we get -EBUSY from
dlm, which confuses the glock state machine. Ideally we want dlm to
not return -EBUSY but wait until the operation has completed. This is
a stop-gap measure until dlm has a solution in place.

Signed-off-by: Bob Peterson <rpeterso@redhat.com>
---
 fs/gfs2/lock_dlm.c | 22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/fs/gfs2/lock_dlm.c b/fs/gfs2/lock_dlm.c
index 50578f881e6d..bf03c77b6757 100644
--- a/fs/gfs2/lock_dlm.c
+++ b/fs/gfs2/lock_dlm.c
@@ -258,7 +258,7 @@ static int gdlm_lock(struct gfs2_glock *gl, unsigned int req_state,
 		     unsigned int flags)
 {
 	struct lm_lockstruct *ls = &gl->gl_name.ln_sbd->sd_lockstruct;
-	int req;
+	int req, ret;
 	u32 lkf;
 	char strname[GDLM_STRNAME_BYTES] = "";
 
@@ -278,9 +278,12 @@ static int gdlm_lock(struct gfs2_glock *gl, unsigned int req_state,
 	/*
 	 * Submit the actual lock request.
 	 */
-
-	return dlm_lock(ls->ls_dlm, req, &gl->gl_lksb, lkf, strname,
-			GDLM_STRNAME_BYTES - 1, 0, gdlm_ast, gl, gdlm_bast);
+	do {
+		ret = dlm_lock(ls->ls_dlm, req, &gl->gl_lksb, lkf, strname,
+			       GDLM_STRNAME_BYTES - 1, 0, gdlm_ast, gl,
+			       gdlm_bast);
+	} while (ret == -EBUSY);
+	return ret;
 }
 
 static void gdlm_put_lock(struct gfs2_glock *gl)
@@ -312,8 +315,11 @@ static void gdlm_put_lock(struct gfs2_glock *gl)
 		return;
 	}
 
-	error = dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid, DLM_LKF_VALBLK,
-			   NULL, gl);
+	do {
+		error = dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid,
+				   DLM_LKF_VALBLK, NULL, gl);
+	} while (error == -EBUSY);
+
 	if (error) {
 		fs_err(sdp, "gdlm_unlock %x,%llx err=%d\n",
 		       gl->gl_name.ln_type,
@@ -506,7 +512,9 @@ static int sync_unlock(struct gfs2_sbd *sdp, struct dlm_lksb *lksb, char *name)
 	struct lm_lockstruct *ls = &sdp->sd_lockstruct;
 	int error;
 
-	error = dlm_unlock(ls->ls_dlm, lksb->sb_lkid, 0, lksb, ls);
+	do {
+		error = dlm_unlock(ls->ls_dlm, lksb->sb_lkid, 0, lksb, ls);
+	} while (error == -EBUSY);
 	if (error) {
 		fs_err(sdp, "%s lkid %x error %d\n",
 		       name, lksb->sb_lkid, error);
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Cluster-devel] [GFS2 PATCH 3/3] gfs2: Switch lock order of inode and iopen glock
  2022-01-24 17:23 [Cluster-devel] [GFS2 PATCH 0/3] Fix how gfs2 handles timed-out dlm requests Bob Peterson
  2022-01-24 17:23 ` [Cluster-devel] [GFS2 PATCH 1/3] gfs2: cancel timed-out glock requests Bob Peterson
  2022-01-24 17:23 ` [Cluster-devel] [GFS2 PATCH 2/3] gfs2: Retry on dlm -EBUSY (stop gap) Bob Peterson
@ 2022-01-24 17:23 ` Bob Peterson
  2022-02-02 15:55 ` [Cluster-devel] [PATCH] gfs2: Expect -EBUSY after canceling dlm locking requests Andreas Gruenbacher
  3 siblings, 0 replies; 8+ messages in thread
From: Bob Peterson @ 2022-01-24 17:23 UTC (permalink / raw)
  To: cluster-devel.redhat.com

From: Andreas Gruenbacher <agruenba@redhat.com>

This patch tries to fix the continual ABBA deadlocks we keep having
between the iopen and inode glocks. This switches the lock order in
gfs2_inode_lookup and gfs2_create_inode so the iopen glock is always
locked first.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
---
 fs/gfs2/inode.c | 49 +++++++++++++++++++++++++++----------------------
 1 file changed, 27 insertions(+), 22 deletions(-)

diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 89905f4f29bb..b30ff50d17f3 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -131,7 +131,21 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
 		struct gfs2_sbd *sdp = GFS2_SB(inode);
 		struct gfs2_glock *io_gl;
 
-		error = gfs2_glock_get(sdp, no_addr, &gfs2_inode_glops, CREATE, &ip->i_gl);
+		error = gfs2_glock_get(sdp, no_addr, &gfs2_inode_glops, CREATE,
+				       &ip->i_gl);
+		if (unlikely(error))
+			goto fail;
+
+		error = gfs2_glock_get(sdp, no_addr, &gfs2_iopen_glops, CREATE,
+				       &io_gl);
+		if (unlikely(error))
+			goto fail;
+
+		if (blktype != GFS2_BLKST_UNLINKED)
+			gfs2_cancel_delete_work(io_gl);
+		error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT,
+					   &ip->i_iopen_gh);
+		gfs2_glock_put(io_gl);
 		if (unlikely(error))
 			goto fail;
 
@@ -161,16 +175,6 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
 
 		set_bit(GLF_INSTANTIATE_NEEDED, &ip->i_gl->gl_flags);
 
-		error = gfs2_glock_get(sdp, no_addr, &gfs2_iopen_glops, CREATE, &io_gl);
-		if (unlikely(error))
-			goto fail;
-		if (blktype != GFS2_BLKST_UNLINKED)
-			gfs2_cancel_delete_work(io_gl);
-		error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh);
-		gfs2_glock_put(io_gl);
-		if (unlikely(error))
-			goto fail;
-
 		/* Lowest possible timestamp; will be overwritten in gfs2_dinode_in. */
 		inode->i_atime.tv_sec = 1LL << (8 * sizeof(inode->i_atime.tv_sec) - 1);
 		inode->i_atime.tv_nsec = 0;
@@ -716,13 +720,17 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
 	error = insert_inode_locked4(inode, ip->i_no_addr, iget_test, &ip->i_no_addr);
 	BUG_ON(error);
 
-	error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_SKIP, ghs + 1);
+	error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh);
 	if (error)
 		goto fail_gunlock2;
 
+	error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_SKIP, ghs + 1);
+	if (error)
+		goto fail_gunlock3;
+
 	error = gfs2_trans_begin(sdp, blocks, 0);
 	if (error)
-		goto fail_gunlock2;
+		goto fail_gunlock3;
 
 	if (blocks > 1) {
 		ip->i_eattr = ip->i_no_addr + 1;
@@ -731,10 +739,6 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
 	init_dinode(dip, ip, symname);
 	gfs2_trans_end(sdp);
 
-	error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh);
-	if (error)
-		goto fail_gunlock2;
-
 	glock_set_object(ip->i_gl, ip);
 	glock_set_object(io_gl, ip);
 	gfs2_set_iop(inode);
@@ -745,14 +749,14 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
 	if (default_acl) {
 		error = __gfs2_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
 		if (error)
-			goto fail_gunlock3;
+			goto fail_gunlock4;
 		posix_acl_release(default_acl);
 		default_acl = NULL;
 	}
 	if (acl) {
 		error = __gfs2_set_acl(inode, acl, ACL_TYPE_ACCESS);
 		if (error)
-			goto fail_gunlock3;
+			goto fail_gunlock4;
 		posix_acl_release(acl);
 		acl = NULL;
 	}
@@ -760,11 +764,11 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
 	error = security_inode_init_security(&ip->i_inode, &dip->i_inode, name,
 					     &gfs2_initxattrs, NULL);
 	if (error)
-		goto fail_gunlock3;
+		goto fail_gunlock4;
 
 	error = link_dinode(dip, name, ip, &da);
 	if (error)
-		goto fail_gunlock3;
+		goto fail_gunlock4;
 
 	mark_inode_dirty(inode);
 	d_instantiate(dentry, inode);
@@ -782,9 +786,10 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
 	unlock_new_inode(inode);
 	return error;
 
-fail_gunlock3:
+fail_gunlock4:
 	glock_clear_object(ip->i_gl, ip);
 	glock_clear_object(io_gl, ip);
+fail_gunlock3:
 	gfs2_glock_dq_uninit(&ip->i_iopen_gh);
 fail_gunlock2:
 	gfs2_glock_put(io_gl);
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Cluster-devel] [GFS2 PATCH 2/3] gfs2: Retry on dlm -EBUSY (stop gap)
  2022-01-24 17:23 ` [Cluster-devel] [GFS2 PATCH 2/3] gfs2: Retry on dlm -EBUSY (stop gap) Bob Peterson
@ 2022-02-02 15:47   ` Andreas Gruenbacher
  0 siblings, 0 replies; 8+ messages in thread
From: Andreas Gruenbacher @ 2022-02-02 15:47 UTC (permalink / raw)
  To: cluster-devel.redhat.com

Hi Bob,

On Mon, Jan 24, 2022 at 6:28 PM Bob Peterson <rpeterso@redhat.com> wrote:
> Sometimes when gfs2 cancels a glock request, dlm needs time to take the
> request off its Conversion queue. During that time, we get -EBUSY from
> dlm, which confuses the glock state machine. Ideally we want dlm to
> not return -EBUSY but wait until the operation has completed. This is
> a stop-gap measure until dlm has a solution in place.

I'm not going to hold my breath until then. We can do better with a
more in-depth patch description here.

Also,

> Signed-off-by: Bob Peterson <rpeterso@redhat.com>
> ---
>  fs/gfs2/lock_dlm.c | 22 +++++++++++++++-------
>  1 file changed, 15 insertions(+), 7 deletions(-)
>
> diff --git a/fs/gfs2/lock_dlm.c b/fs/gfs2/lock_dlm.c
> index 50578f881e6d..bf03c77b6757 100644
> --- a/fs/gfs2/lock_dlm.c
> +++ b/fs/gfs2/lock_dlm.c
> @@ -258,7 +258,7 @@ static int gdlm_lock(struct gfs2_glock *gl, unsigned int req_state,
>                      unsigned int flags)
>  {
>         struct lm_lockstruct *ls = &gl->gl_name.ln_sbd->sd_lockstruct;
> -       int req;
> +       int req, ret;
>         u32 lkf;
>         char strname[GDLM_STRNAME_BYTES] = "";
>
> @@ -278,9 +278,12 @@ static int gdlm_lock(struct gfs2_glock *gl, unsigned int req_state,
>         /*
>          * Submit the actual lock request.
>          */
> -
> -       return dlm_lock(ls->ls_dlm, req, &gl->gl_lksb, lkf, strname,
> -                       GDLM_STRNAME_BYTES - 1, 0, gdlm_ast, gl, gdlm_bast);
> +       do {
> +               ret = dlm_lock(ls->ls_dlm, req, &gl->gl_lksb, lkf, strname,
> +                              GDLM_STRNAME_BYTES - 1, 0, gdlm_ast, gl,
> +                              gdlm_bast);

we should sleep here and in gdlm_put_lock() so that in the rare cases
when dlm ends up in that busy state, we won't eat up 100% cpu time at
least.

> +       } while (ret == -EBUSY);
> +       return ret;
>  }
>
>  static void gdlm_put_lock(struct gfs2_glock *gl)
> @@ -312,8 +315,11 @@ static void gdlm_put_lock(struct gfs2_glock *gl)
>                 return;
>         }
>
> -       error = dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid, DLM_LKF_VALBLK,
> -                          NULL, gl);
> +       do {
> +               error = dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid,
> +                                  DLM_LKF_VALBLK, NULL, gl);
> +       } while (error == -EBUSY);
> +
>         if (error) {
>                 fs_err(sdp, "gdlm_unlock %x,%llx err=%d\n",
>                        gl->gl_name.ln_type,
> @@ -506,7 +512,9 @@ static int sync_unlock(struct gfs2_sbd *sdp, struct dlm_lksb *lksb, char *name)
>         struct lm_lockstruct *ls = &sdp->sd_lockstruct;
>         int error;
>
> -       error = dlm_unlock(ls->ls_dlm, lksb->sb_lkid, 0, lksb, ls);
> +       do {
> +               error = dlm_unlock(ls->ls_dlm, lksb->sb_lkid, 0, lksb, ls);
> +       } while (error == -EBUSY);

There's a sync_lock() as well as a sync_unlock(). But those locks are
never canceled, so we don't really bother about -EBUSY.

>         if (error) {
>                 fs_err(sdp, "%s lkid %x error %d\n",
>                        name, lksb->sb_lkid, error);
> --
> 2.34.1

Let me post an updated version.

Thanks,
Andreas



^ permalink raw reply	[flat|nested] 8+ messages in thread

* [Cluster-devel] [PATCH] gfs2: Expect -EBUSY after canceling dlm locking requests
  2022-01-24 17:23 [Cluster-devel] [GFS2 PATCH 0/3] Fix how gfs2 handles timed-out dlm requests Bob Peterson
                   ` (2 preceding siblings ...)
  2022-01-24 17:23 ` [Cluster-devel] [GFS2 PATCH 3/3] gfs2: Switch lock order of inode and iopen glock Bob Peterson
@ 2022-02-02 15:55 ` Andreas Gruenbacher
  2022-02-02 16:04   ` Bob Peterson
  3 siblings, 1 reply; 8+ messages in thread
From: Andreas Gruenbacher @ 2022-02-02 15:55 UTC (permalink / raw)
  To: cluster-devel.redhat.com

Due to the asynchronous nature of the dlm api, when we request a pending
locking request to be canceled with dlm_unlock(DLM_LKF_CANCEL), the
locking request will either complete before it could be canceled, or the
cancellation will succeed.  In either case, gdlm_ast will be called once
and the status will indicate the outcome of the locking request, with
-DLM_ECANCEL indicating a canceled request.

Inside dlm, when a locking request completes before its cancel request
could be processed, gdlm_ast will be called, but the lock will still be
considered busy until a DLM_MSG_CANCEL_REPLY message completes the
cancel request.  During that time, successive dlm_lock() or dlm_unlock()
requests for that lock will return -EBUSY.  In other words, waiting for
the gdlm_ast call before issuing the next locking request is not enough.
There is no way of waiting for a cancel request to actually complete,
either.

We rarely cancel locking requests, but when we do, we don't know when
the next locking request for that lock will occur.  This means that any
dlm_lock() or dlm_unlock() call can potentially return -EBUSY.  When
that happens, this patch simply repeats the request after a short pause.

This workaround could be improved upon by tracking for which dlm locks
cancel requests have been issued, but that isn't strictly necessary and
it would complicate the code.  We haven't seen -EBUSY errors from dlm
without cancel requests.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
 fs/gfs2/lock_dlm.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/fs/gfs2/lock_dlm.c b/fs/gfs2/lock_dlm.c
index 50578f881e6d..2559a79cf14b 100644
--- a/fs/gfs2/lock_dlm.c
+++ b/fs/gfs2/lock_dlm.c
@@ -261,6 +261,7 @@ static int gdlm_lock(struct gfs2_glock *gl, unsigned int req_state,
 	int req;
 	u32 lkf;
 	char strname[GDLM_STRNAME_BYTES] = "";
+	int error;
 
 	req = make_mode(gl->gl_name.ln_sbd, req_state);
 	lkf = make_flags(gl, flags, req);
@@ -279,8 +280,14 @@ static int gdlm_lock(struct gfs2_glock *gl, unsigned int req_state,
 	 * Submit the actual lock request.
 	 */
 
-	return dlm_lock(ls->ls_dlm, req, &gl->gl_lksb, lkf, strname,
+again:
+	error = dlm_lock(ls->ls_dlm, req, &gl->gl_lksb, lkf, strname,
 			GDLM_STRNAME_BYTES - 1, 0, gdlm_ast, gl, gdlm_bast);
+	if (error == -EBUSY) {
+		msleep(20);
+		goto again;
+	}
+	return error;
 }
 
 static void gdlm_put_lock(struct gfs2_glock *gl)
@@ -312,8 +319,14 @@ static void gdlm_put_lock(struct gfs2_glock *gl)
 		return;
 	}
 
+again:
 	error = dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid, DLM_LKF_VALBLK,
 			   NULL, gl);
+	if (error == -EBUSY) {
+		msleep(20);
+		goto again;
+	}
+
 	if (error) {
 		fs_err(sdp, "gdlm_unlock %x,%llx err=%d\n",
 		       gl->gl_name.ln_type,
-- 
2.33.1



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Cluster-devel] [PATCH] gfs2: Expect -EBUSY after canceling dlm locking requests
  2022-02-02 15:55 ` [Cluster-devel] [PATCH] gfs2: Expect -EBUSY after canceling dlm locking requests Andreas Gruenbacher
@ 2022-02-02 16:04   ` Bob Peterson
  2022-02-02 16:26     ` Andreas Gruenbacher
  0 siblings, 1 reply; 8+ messages in thread
From: Bob Peterson @ 2022-02-02 16:04 UTC (permalink / raw)
  To: cluster-devel.redhat.com

On 2/2/22 10:55 AM, Andreas Gruenbacher wrote:
> Due to the asynchronous nature of the dlm api, when we request a pending
> locking request to be canceled with dlm_unlock(DLM_LKF_CANCEL), the
> locking request will either complete before it could be canceled, or the
> cancellation will succeed.  In either case, gdlm_ast will be called once
> and the status will indicate the outcome of the locking request, with
> -DLM_ECANCEL indicating a canceled request.
> 
> Inside dlm, when a locking request completes before its cancel request
> could be processed, gdlm_ast will be called, but the lock will still be
> considered busy until a DLM_MSG_CANCEL_REPLY message completes the
> cancel request.  During that time, successive dlm_lock() or dlm_unlock()
> requests for that lock will return -EBUSY.  In other words, waiting for
> the gdlm_ast call before issuing the next locking request is not enough.
> There is no way of waiting for a cancel request to actually complete,
> either.
> 
> We rarely cancel locking requests, but when we do, we don't know when
> the next locking request for that lock will occur.  This means that any
> dlm_lock() or dlm_unlock() call can potentially return -EBUSY.  When
> that happens, this patch simply repeats the request after a short pause.
> 
> This workaround could be improved upon by tracking for which dlm locks
> cancel requests have been issued, but that isn't strictly necessary and
> it would complicate the code.  We haven't seen -EBUSY errors from dlm
> without cancel requests.
> 
> Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
> ---
>   fs/gfs2/lock_dlm.c | 15 ++++++++++++++-
>   1 file changed, 14 insertions(+), 1 deletion(-)
> 
> diff --git a/fs/gfs2/lock_dlm.c b/fs/gfs2/lock_dlm.c
> index 50578f881e6d..2559a79cf14b 100644
> --- a/fs/gfs2/lock_dlm.c
> +++ b/fs/gfs2/lock_dlm.c
> @@ -261,6 +261,7 @@ static int gdlm_lock(struct gfs2_glock *gl, unsigned int req_state,
>   	int req;
>   	u32 lkf;
>   	char strname[GDLM_STRNAME_BYTES] = "";
> +	int error;
>   
>   	req = make_mode(gl->gl_name.ln_sbd, req_state);
>   	lkf = make_flags(gl, flags, req);
> @@ -279,8 +280,14 @@ static int gdlm_lock(struct gfs2_glock *gl, unsigned int req_state,
>   	 * Submit the actual lock request.
>   	 */
>   
> -	return dlm_lock(ls->ls_dlm, req, &gl->gl_lksb, lkf, strname,
> +again:
> +	error = dlm_lock(ls->ls_dlm, req, &gl->gl_lksb, lkf, strname,
>   			GDLM_STRNAME_BYTES - 1, 0, gdlm_ast, gl, gdlm_bast);
> +	if (error == -EBUSY) {
> +		msleep(20);
> +		goto again;
> +	}
> +	return error;
>   }
>   
>   static void gdlm_put_lock(struct gfs2_glock *gl)
> @@ -312,8 +319,14 @@ static void gdlm_put_lock(struct gfs2_glock *gl)
>   		return;
>   	}
>   
> +again:
>   	error = dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid, DLM_LKF_VALBLK,
>   			   NULL, gl);
> +	if (error == -EBUSY) {
> +		msleep(20);
> +		goto again;
> +	}
> +
>   	if (error) {
>   		fs_err(sdp, "gdlm_unlock %x,%llx err=%d\n",
>   		       gl->gl_name.ln_type,
Hi,

Looks good. If you push it to a temp branch I'll test it.

Bob Peterson



^ permalink raw reply	[flat|nested] 8+ messages in thread

* [Cluster-devel] [PATCH] gfs2: Expect -EBUSY after canceling dlm locking requests
  2022-02-02 16:04   ` Bob Peterson
@ 2022-02-02 16:26     ` Andreas Gruenbacher
  0 siblings, 0 replies; 8+ messages in thread
From: Andreas Gruenbacher @ 2022-02-02 16:26 UTC (permalink / raw)
  To: cluster-devel.redhat.com

On Wed, Feb 2, 2022 at 5:04 PM Bob Peterson <rpeterso@redhat.com> wrote:
> Looks good. If you push it to a temp branch I'll test it.

The for-next branch fell a bit behind lately, but I've updated it now.

Thanks,
Andreas



^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2022-02-02 16:26 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-01-24 17:23 [Cluster-devel] [GFS2 PATCH 0/3] Fix how gfs2 handles timed-out dlm requests Bob Peterson
2022-01-24 17:23 ` [Cluster-devel] [GFS2 PATCH 1/3] gfs2: cancel timed-out glock requests Bob Peterson
2022-01-24 17:23 ` [Cluster-devel] [GFS2 PATCH 2/3] gfs2: Retry on dlm -EBUSY (stop gap) Bob Peterson
2022-02-02 15:47   ` Andreas Gruenbacher
2022-01-24 17:23 ` [Cluster-devel] [GFS2 PATCH 3/3] gfs2: Switch lock order of inode and iopen glock Bob Peterson
2022-02-02 15:55 ` [Cluster-devel] [PATCH] gfs2: Expect -EBUSY after canceling dlm locking requests Andreas Gruenbacher
2022-02-02 16:04   ` Bob Peterson
2022-02-02 16:26     ` Andreas Gruenbacher

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.