From: Steven Whitehouse <swhiteho@redhat.com>
To: cluster-devel.redhat.com
Subject: [Cluster-devel] [PATCH v2 1/4] gfs2: gfs2_glock_get: Wait on freeing glocks
Date: Tue, 4 Jul 2017 13:13:05 +0100 [thread overview]
Message-ID: <cc6bb799-652c-0ec8-baa1-96261052964d@redhat.com> (raw)
In-Reply-To: <1499093770-6017-2-git-send-email-agruenba@redhat.com>
On 03/07/17 15:56, Andreas Gruenbacher wrote:
> Keep glocks in their hash table until they are freed instead of removing
> them when their last reference is dropped. This allows to wait for
> glocks to go away before recreating them in gfs2_glock_get so that the
> previous use of the glock won't overlap with the next.
I did a double take when I looked at this and saw it reintroducing
gl_rcu and I wondered where that had gone in the mean time. Is that a
bug fix that is included alongside this new feature? At least if it is
not required anyway, then I can't quite figure out why - maybe something
hidden in the rhashtable code perhaps?
Steve.
> Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
> ---
> fs/gfs2/glock.c | 135 +++++++++++++++++++++++++++++++++++++++++++++----------
> fs/gfs2/incore.h | 1 +
> 2 files changed, 113 insertions(+), 23 deletions(-)
>
> diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
> index 6cd71c5..8a7944b 100644
> --- a/fs/gfs2/glock.c
> +++ b/fs/gfs2/glock.c
> @@ -15,6 +15,7 @@
> #include <linux/buffer_head.h>
> #include <linux/delay.h>
> #include <linux/sort.h>
> +#include <linux/hash.h>
> #include <linux/jhash.h>
> #include <linux/kallsyms.h>
> #include <linux/gfs2_ondisk.h>
> @@ -80,9 +81,69 @@ static struct rhashtable_params ht_parms = {
>
> static struct rhashtable gl_hash_table;
>
> -void gfs2_glock_free(struct gfs2_glock *gl)
> +#define GLOCK_WAIT_TABLE_BITS 12
> +#define GLOCK_WAIT_TABLE_SIZE (1 << GLOCK_WAIT_TABLE_BITS)
> +static wait_queue_head_t glock_wait_table[GLOCK_WAIT_TABLE_SIZE] __cacheline_aligned;
> +
> +struct wait_glock_queue {
> + struct lm_lockname *name;
> + wait_queue_t wait;
> +};
> +
> +static int glock_wake_function(wait_queue_t *wait, unsigned int mode, int sync,
> + void *key)
> {
> - struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
> + struct wait_glock_queue *wait_glock =
> + container_of(wait, struct wait_glock_queue, wait);
> + struct lm_lockname *wait_name = wait_glock->name;
> + struct lm_lockname *wake_name = key;
> +
> + if (wake_name->ln_sbd != wait_name->ln_sbd ||
> + wake_name->ln_number != wait_name->ln_number ||
> + wake_name->ln_type != wait_name->ln_type)
> + return 0;
> + return autoremove_wake_function(wait, mode, sync, key);
> +}
> +
> +static wait_queue_head_t *glock_waitqueue(struct lm_lockname *name)
> +{
> + u32 hash = jhash2((u32 *)name, sizeof(*name) / 4, 0);
> +
> + return glock_wait_table + hash_32(hash, GLOCK_WAIT_TABLE_BITS);
> +}
> +
> +static void prepare_to_wait_on_glock(wait_queue_head_t **wq,
> + struct wait_glock_queue *wait,
> + struct lm_lockname *name)
> +{
> + wait->name = name;
> + init_wait(&wait->wait);
> + wait->wait.func = glock_wake_function;
> + *wq = glock_waitqueue(name);
> + prepare_to_wait(*wq, &wait->wait, TASK_UNINTERRUPTIBLE);
> +}
> +
> +static void finish_wait_on_glock(wait_queue_head_t *wq,
> + struct wait_glock_queue *wait)
> +{
> + finish_wait(wq, &wait->wait);
> +}
> +
> +/**
> + * wake_up_glock - Wake up waiters on a glock
> + * @gl: the glock
> + */
> +static void wake_up_glock(struct gfs2_glock *gl)
> +{
> + wait_queue_head_t *wq = glock_waitqueue(&gl->gl_name);
> +
> + if (waitqueue_active(wq))
> + __wake_up(wq, TASK_NORMAL, 1, &gl->gl_name);
> +}
> +
> +static void gfs2_glock_dealloc(struct rcu_head *rcu)
> +{
> + struct gfs2_glock *gl = container_of(rcu, struct gfs2_glock, gl_rcu);
>
> if (gl->gl_ops->go_flags & GLOF_ASPACE) {
> kmem_cache_free(gfs2_glock_aspace_cachep, gl);
> @@ -90,6 +151,15 @@ void gfs2_glock_free(struct gfs2_glock *gl)
> kfree(gl->gl_lksb.sb_lvbptr);
> kmem_cache_free(gfs2_glock_cachep, gl);
> }
> +}
> +
> +void gfs2_glock_free(struct gfs2_glock *gl)
> +{
> + struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
> +
> + rhashtable_remove_fast(&gl_hash_table, &gl->gl_node, ht_parms);
> + wake_up_glock(gl);
> + call_rcu(&gl->gl_rcu, gfs2_glock_dealloc);
> if (atomic_dec_and_test(&sdp->sd_glock_disposal))
> wake_up(&sdp->sd_glock_wait);
> }
> @@ -184,7 +254,6 @@ static void __gfs2_glock_put(struct gfs2_glock *gl)
>
> gfs2_glock_remove_from_lru(gl);
> spin_unlock(&gl->gl_lockref.lock);
> - rhashtable_remove_fast(&gl_hash_table, &gl->gl_node, ht_parms);
> GLOCK_BUG_ON(gl, !list_empty(&gl->gl_holders));
> GLOCK_BUG_ON(gl, mapping && mapping->nrpages);
> trace_gfs2_glock_put(gl);
> @@ -669,6 +738,36 @@ static void glock_work_func(struct work_struct *work)
> spin_unlock(&gl->gl_lockref.lock);
> }
>
> +static struct gfs2_glock *find_insert_glock(struct lm_lockname *name,
> + struct gfs2_glock *new)
> +{
> + struct wait_glock_queue wait;
> + wait_queue_head_t *wq;
> + struct gfs2_glock *gl;
> +
> +again:
> + prepare_to_wait_on_glock(&wq, &wait, name);
> + rcu_read_lock();
> + if (new) {
> + gl = rhashtable_lookup_get_insert_fast(&gl_hash_table,
> + &new->gl_node, ht_parms);
> + if (IS_ERR(gl))
> + goto out;
> + } else {
> + gl = rhashtable_lookup_fast(&gl_hash_table,
> + name, ht_parms);
> + }
> + if (gl && !lockref_get_not_dead(&gl->gl_lockref)) {
> + rcu_read_unlock();
> + schedule();
> + goto again;
> + }
> +out:
> + rcu_read_unlock();
> + finish_wait_on_glock(wq, &wait);
> + return gl;
> +}
> +
> /**
> * gfs2_glock_get() - Get a glock, or create one if one doesn't exist
> * @sdp: The GFS2 superblock
> @@ -695,15 +794,11 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
> struct kmem_cache *cachep;
> int ret = 0;
>
> - rcu_read_lock();
> - gl = rhashtable_lookup_fast(&gl_hash_table, &name, ht_parms);
> - if (gl && !lockref_get_not_dead(&gl->gl_lockref))
> - gl = NULL;
> - rcu_read_unlock();
> -
> - *glp = gl;
> - if (gl)
> + gl = find_insert_glock(&name, NULL);
> + if (gl) {
> + *glp = gl;
> return 0;
> + }
> if (!create)
> return -ENOENT;
>
> @@ -757,10 +852,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
> mapping->writeback_index = 0;
> }
>
> -again:
> - rcu_read_lock();
> - tmp = rhashtable_lookup_get_insert_fast(&gl_hash_table, &gl->gl_node,
> - ht_parms);
> + tmp = find_insert_glock(&name, gl);
> if (!tmp) {
> *glp = gl;
> goto out;
> @@ -769,13 +861,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
> ret = PTR_ERR(tmp);
> goto out_free;
> }
> - if (lockref_get_not_dead(&tmp->gl_lockref)) {
> - *glp = tmp;
> - goto out_free;
> - }
> - rcu_read_unlock();
> - cond_resched();
> - goto again;
> + *glp = tmp;
>
> out_free:
> kfree(gl->gl_lksb.sb_lvbptr);
> @@ -1796,7 +1882,7 @@ static int gfs2_sbstats_seq_show(struct seq_file *seq, void *iter_ptr)
>
> int __init gfs2_glock_init(void)
> {
> - int ret;
> + int i, ret;
>
> ret = rhashtable_init(&gl_hash_table, &ht_parms);
> if (ret < 0)
> @@ -1825,6 +1911,9 @@ int __init gfs2_glock_init(void)
> return ret;
> }
>
> + for (i = 0; i < GLOCK_WAIT_TABLE_SIZE; i++)
> + init_waitqueue_head(glock_wait_table + i);
> +
> return 0;
> }
>
> diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
> index de42384..2ba9403 100644
> --- a/fs/gfs2/incore.h
> +++ b/fs/gfs2/incore.h
> @@ -373,6 +373,7 @@ struct gfs2_glock {
> loff_t end;
> } gl_vm;
> };
> + struct rcu_head gl_rcu;
> struct rhash_head gl_node;
> };
>
next prev parent reply other threads:[~2017-07-04 12:13 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-07-03 14:56 [Cluster-devel] [PATCH v2 0/4] GFS2 shrinker deadlock Andreas Gruenbacher
2017-07-03 14:56 ` [Cluster-devel] [PATCH v2 1/4] gfs2: gfs2_glock_get: Wait on freeing glocks Andreas Gruenbacher
2017-07-04 12:13 ` Steven Whitehouse [this message]
2017-07-05 14:22 ` Andreas Gruenbacher
2017-07-05 14:28 ` Steven Whitehouse
2017-07-03 14:56 ` [Cluster-devel] [PATCH v2 2/4] gfs2: Get rid of gfs2_set_nlink Andreas Gruenbacher
2017-07-03 14:56 ` [Cluster-devel] [PATCH v2 3/4] gfs2: gfs2_evict_inode: Put glocks asynchronously Andreas Gruenbacher
2017-07-04 12:16 ` Steven Whitehouse
2017-07-03 14:56 ` [Cluster-devel] [PATCH v2 4/4] gfs2: Defer deleting inodes under memory pressure Andreas Gruenbacher
2017-07-04 12:17 ` Steven Whitehouse
2017-07-04 12:11 ` [Cluster-devel] [PATCH v2 0/4] GFS2 shrinker deadlock Steven Whitehouse
2017-07-05 9:57 ` 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=cc6bb799-652c-0ec8-baa1-96261052964d@redhat.com \
--to=swhiteho@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).