cluster-devel.redhat.com archive mirror
 help / color / mirror / Atom feed
From: Bob Peterson <rpeterso@redhat.com>
To: cluster-devel.redhat.com
Subject: [Cluster-devel] [PATCH 2/2] gfs2: Fix lru_count going negative
Date: Thu, 31 Jan 2019 09:36:37 -0500 (EST)	[thread overview]
Message-ID: <1247235469.68837763.1548945397399.JavaMail.zimbra@redhat.com> (raw)
In-Reply-To: <20190131105543.15421-3-ross.lagerwall@citrix.com>

Hi Ross,

Comments below. Sorry if this is a bit incoherent; it's early and I'm
not properly caffeinated yet.

----- Original Message -----
> Under certain conditions, lru_count may drop below zero resulting in
> a large amount of log spam like this:
> 
> vmscan: shrink_slab: gfs2_dump_glock+0x3b0/0x630 [gfs2] \
>     negative objects to delete nr=-1
> 
> This happens as follows:
> 1) A glock is moved from lru_list to the dispose list and lru_count is
>    decremented.
> 2) The dispose function calls cond_resched() and drops the lru lock.
> 3) Another thread takes the lru lock and tries to add the same glock to
>    lru_list, checking if the glock is on an lru list.
> 4) It is on a list (actually the dispose list) and so it avoids
>    incrementing lru_count.
> 5) The glock is moved to lru_list.
> 5) The original thread doesn't dispose it because it has been re-added
>    to the lru list but the lru_count has still decreased by one.
> 
> Fix by checking if the LRU flag is set on the glock rather than checking
> if the glock is on some list and rearrange the code so that the LRU flag
> is added/removed precisely when the glock is added/removed from lru_list.
> 
> Signed-off-by: Ross Lagerwall <ross.lagerwall@citrix.com>
> ---
>  fs/gfs2/glock.c | 16 +++++++++-------
>  1 file changed, 9 insertions(+), 7 deletions(-)
> 
> diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
> index b92740edc416..53e6c7e0c1b3 100644
> --- a/fs/gfs2/glock.c
> +++ b/fs/gfs2/glock.c
> @@ -185,13 +185,14 @@ void gfs2_glock_add_to_lru(struct gfs2_glock *gl)
>  {
>  	spin_lock(&lru_lock);
>  
> -	if (!list_empty(&gl->gl_lru))
> -		list_del_init(&gl->gl_lru);
> -	else
> +	list_del(&gl->gl_lru);
> +	list_add_tail(&gl->gl_lru, &lru_list);

This looks like a bug, and I like your idea of using the GLF_LRU bit
to determine whether or not to do the manipulation, but I have some
concerns. First, does it work with kernel list debugging turned on?

To me it looks like the list_del (as opposed to list_del_init) above
will set entry->next and prev to LIST_POISON values, then the
list_add_tail() calls __list_add() which checks:
	if (!__list_add_valid(new, prev, next))
		return;
Without list debugging, the value is always returned true, but with
list debugging it checks for circular values of list->prev and list->next
which, since they're LIST_POISON, ought to fail.
So it seems like the original list_del_init is correct.

The intent was: if the glock is already on the lru, take it off
before re-adding it, and the count ought to be okay, because if it's
on the LRU list, it's already been incremented. So taking it off and
adding it back on is a net 0 on the count. But that's only
true if the GLF_LRU bit is set. If it's on a different list (the
dispose list), as you noted, it still needs to be incremented.

If the glock is on the dispose_list, rather than the lru list, we
want to take it off the dispose list and move it to the lru_list,
but in that case, we need to increment the lru count, and not
poison the list_head.

So to me it seems like we should keep the list_del_init, and only
do it if the list isn't empty, but trigger off the GLF_LRU flag
for managing the count. The lru_lock ought to prevent races.

> +
> +	if (!test_bit(GLF_LRU, &gl->gl_flags)) {
> +		set_bit(GLF_LRU, &gl->gl_flags);
>  		atomic_inc(&lru_count);
> +	}

The above may be simplified to something like:
+	if (!test_and_set_bit(GLF_LRU, &gl->gl_flags))
 		atomic_inc(&lru_count);

>  
> -	list_add_tail(&gl->gl_lru, &lru_list);
> -	set_bit(GLF_LRU, &gl->gl_flags);
>  	spin_unlock(&lru_lock);
>  }
>  
> @@ -201,7 +202,7 @@ static void gfs2_glock_remove_from_lru(struct gfs2_glock
> *gl)
>  		return;
>  
>  	spin_lock(&lru_lock);
> -	if (!list_empty(&gl->gl_lru)) {
> +	if (test_bit(GLF_LRU, &gl->gl_flags)) {
>  		list_del_init(&gl->gl_lru);
>  		atomic_dec(&lru_count);
>  		clear_bit(GLF_LRU, &gl->gl_flags);

Here again, we could simplify with test_and_clear_bit above.

> @@ -1456,6 +1457,7 @@ __acquires(&lru_lock)
>  		if (!spin_trylock(&gl->gl_lockref.lock)) {
>  add_back_to_lru:
>  			list_add(&gl->gl_lru, &lru_list);
> +			set_bit(GLF_LRU, &gl->gl_flags);
>  			atomic_inc(&lru_count);
>  			continue;
>  		}
> @@ -1463,7 +1465,6 @@ __acquires(&lru_lock)
>  			spin_unlock(&gl->gl_lockref.lock);
>  			goto add_back_to_lru;
>  		}
> -		clear_bit(GLF_LRU, &gl->gl_flags);
>  		gl->gl_lockref.count++;
>  		if (demote_ok(gl))
>  			handle_callback(gl, LM_ST_UNLOCKED, 0, false);
> @@ -1498,6 +1499,7 @@ static long gfs2_scan_glock_lru(int nr)
>  		if (!test_bit(GLF_LOCK, &gl->gl_flags)) {
>  			list_move(&gl->gl_lru, &dispose);
>  			atomic_dec(&lru_count);
> +			clear_bit(GLF_LRU, &gl->gl_flags);
>  			freed++;
>  			continue;
>  		}
> --
> 2.17.2
> 
> 



  parent reply	other threads:[~2019-01-31 14:36 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-01-31 10:55 [Cluster-devel] [PATCH 0/2] GFS2 counting fixes Ross Lagerwall
2019-01-31 10:55 ` [Cluster-devel] [PATCH 1/2] gfs2: Fix occasional glock use-after-free Ross Lagerwall
2019-01-31 11:23   ` Steven Whitehouse
2019-01-31 14:40   ` Bob Peterson
2019-01-31 17:18   ` Andreas Gruenbacher
2019-02-01  9:23     ` Ross Lagerwall
2019-02-01 14:34       ` Bob Peterson
2019-02-01 14:51       ` Bob Peterson
2019-02-01 15:03       ` [Cluster-devel] [PATCH 1/2] gfs2: Fix occasional glock use-after-free (Another debug patch) Bob Peterson
2019-03-26 18:49     ` [Cluster-devel] [PATCH 1/2] gfs2: Fix occasional glock use-after-free Ross Lagerwall
2019-03-26 19:14       ` Bob Peterson
2019-04-01 22:59         ` Andreas Gruenbacher
2019-04-05 17:50           ` Andreas Gruenbacher
2019-04-09 15:36             ` Ross Lagerwall
2019-04-09 15:41               ` Andreas Gruenbacher
2019-01-31 10:55 ` [Cluster-devel] [PATCH 2/2] gfs2: Fix lru_count going negative Ross Lagerwall
2019-01-31 11:21   ` Steven Whitehouse
2019-01-31 14:36   ` Bob Peterson [this message]
2019-01-31 15:04     ` Bob Peterson
2019-01-31 15:23     ` Ross Lagerwall
2019-01-31 18:32   ` Andreas Gruenbacher

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1247235469.68837763.1548945397399.JavaMail.zimbra@redhat.com \
    --to=rpeterso@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).