All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] dcache: per-sb LRU locks
@ 2011-08-08  7:03 Dave Chinner
  2011-08-08  7:03 ` [PATCH 1/2] dcache: convert dentry_stat.nr_unused to per-cpu counters Dave Chinner
  2011-08-08  7:03 ` [PATCH 2/2] dentry: move to per-sb LRU locks Dave Chinner
  0 siblings, 2 replies; 10+ messages in thread
From: Dave Chinner @ 2011-08-08  7:03 UTC (permalink / raw)
  To: viro; +Cc: linux-kernel, linux-fsdevel

Hi Al,

This is the missing piece of the per-sb shrinker patchset - I
dropped it because it was causing problems. Now that you've fixed a
bunch of problems in the dcache code, the conversion to per-sb LRU
locks for the dcache no longer causes my systems to crash and burn.
It's been stable for the past couple of weeks, so it's time for more
review and wider testing....

Cheers,

Dave.

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

* [PATCH 1/2] dcache: convert dentry_stat.nr_unused to per-cpu counters
  2011-08-08  7:03 [PATCH 0/2] dcache: per-sb LRU locks Dave Chinner
@ 2011-08-08  7:03 ` Dave Chinner
  2011-08-08  7:08     ` Pekka Enberg
  2011-08-08  7:03 ` [PATCH 2/2] dentry: move to per-sb LRU locks Dave Chinner
  1 sibling, 1 reply; 10+ messages in thread
From: Dave Chinner @ 2011-08-08  7:03 UTC (permalink / raw)
  To: viro; +Cc: linux-kernel, linux-fsdevel

From: Dave Chinner <dchinner@redhat.com>

Before we split up the dcache_lru_lock, the unused dentry counter
needs to be made independent of the global dcache_lru_lock. Convert
it to per-cpu counters to do this.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
---
 fs/dcache.c |   17 ++++++++++++++---
 1 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/fs/dcache.c b/fs/dcache.c
index b05aac3..5e5208d 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -116,6 +116,7 @@ struct dentry_stat_t dentry_stat = {
 };
 
 static DEFINE_PER_CPU(unsigned int, nr_dentry);
+static DEFINE_PER_CPU(unsigned int, nr_dentry_unused);
 
 #if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS)
 static int get_nr_dentry(void)
@@ -127,10 +128,20 @@ static int get_nr_dentry(void)
 	return sum < 0 ? 0 : sum;
 }
 
+static int get_nr_dentry_unused(void)
+{
+	int i;
+	int sum = 0;
+	for_each_possible_cpu(i)
+		sum += per_cpu(nr_dentry_unused, i);
+	return sum < 0 ? 0 : sum;
+}
+
 int proc_nr_dentry(ctl_table *table, int write, void __user *buffer,
 		   size_t *lenp, loff_t *ppos)
 {
 	dentry_stat.nr_dentry = get_nr_dentry();
+	dentry_stat.nr_unused = get_nr_dentry_unused();
 	return proc_dointvec(table, write, buffer, lenp, ppos);
 }
 #endif
@@ -233,7 +244,7 @@ static void dentry_lru_add(struct dentry *dentry)
 		spin_lock(&dcache_lru_lock);
 		list_add(&dentry->d_lru, &dentry->d_sb->s_dentry_lru);
 		dentry->d_sb->s_nr_dentry_unused++;
-		dentry_stat.nr_unused++;
+		this_cpu_inc(nr_dentry_unused);
 		spin_unlock(&dcache_lru_lock);
 	}
 }
@@ -242,7 +253,7 @@ static void __dentry_lru_del(struct dentry *dentry)
 {
 	list_del_init(&dentry->d_lru);
 	dentry->d_sb->s_nr_dentry_unused--;
-	dentry_stat.nr_unused--;
+	this_cpu_dec(nr_dentry_unused);
 }
 
 static void dentry_lru_del(struct dentry *dentry)
@@ -260,7 +271,7 @@ static void dentry_lru_move_tail(struct dentry *dentry)
 	if (list_empty(&dentry->d_lru)) {
 		list_add_tail(&dentry->d_lru, &dentry->d_sb->s_dentry_lru);
 		dentry->d_sb->s_nr_dentry_unused++;
-		dentry_stat.nr_unused++;
+		this_cpu_inc(nr_dentry_unused);
 	} else {
 		list_move_tail(&dentry->d_lru, &dentry->d_sb->s_dentry_lru);
 	}
-- 
1.7.5.4


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

* [PATCH 2/2] dentry: move to per-sb LRU locks
  2011-08-08  7:03 [PATCH 0/2] dcache: per-sb LRU locks Dave Chinner
  2011-08-08  7:03 ` [PATCH 1/2] dcache: convert dentry_stat.nr_unused to per-cpu counters Dave Chinner
@ 2011-08-08  7:03 ` Dave Chinner
  2011-08-08 13:02   ` Peter Zijlstra
  1 sibling, 1 reply; 10+ messages in thread
From: Dave Chinner @ 2011-08-08  7:03 UTC (permalink / raw)
  To: viro; +Cc: linux-kernel, linux-fsdevel

From: Dave Chinner <dchinner@redhat.com>

With the dentry LRUs being per-sb structures, there is no real need
for a global dentry_lru_lock. The locking can be made more
fine-grained by moving to a per-sb LRU lock, isolating the LRU
operations of different filesytsems completely from each other.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
---
 fs/dcache.c        |   33 ++++++++++++++++-----------------
 fs/super.c         |    1 +
 include/linux/fs.h |    3 ++-
 3 files changed, 19 insertions(+), 18 deletions(-)

diff --git a/fs/dcache.c b/fs/dcache.c
index 5e5208d..0503f32 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -46,7 +46,7 @@
  *   - the dcache hash table
  * s_anon bl list spinlock protects:
  *   - the s_anon list (see __d_drop)
- * dcache_lru_lock protects:
+ * dentry->d_sb->s_dentry_lru_lock protects:
  *   - the dcache lru lists and counters
  * d_lock protects:
  *   - d_flags
@@ -61,7 +61,7 @@
  * Ordering:
  * dentry->d_inode->i_lock
  *   dentry->d_lock
- *     dcache_lru_lock
+ *     dentry->d_sb->s_dentry_lru_lock
  *     dcache_hash_bucket lock
  *     s_anon lock
  *
@@ -79,7 +79,6 @@
 int sysctl_vfs_cache_pressure __read_mostly = 100;
 EXPORT_SYMBOL_GPL(sysctl_vfs_cache_pressure);
 
-static __cacheline_aligned_in_smp DEFINE_SPINLOCK(dcache_lru_lock);
 __cacheline_aligned_in_smp DEFINE_SEQLOCK(rename_lock);
 
 EXPORT_SYMBOL(rename_lock);
@@ -241,11 +240,11 @@ static void dentry_unlink_inode(struct dentry * dentry)
 static void dentry_lru_add(struct dentry *dentry)
 {
 	if (list_empty(&dentry->d_lru)) {
-		spin_lock(&dcache_lru_lock);
+		spin_lock(&dentry->d_sb->s_dentry_lru_lock);
 		list_add(&dentry->d_lru, &dentry->d_sb->s_dentry_lru);
 		dentry->d_sb->s_nr_dentry_unused++;
 		this_cpu_inc(nr_dentry_unused);
-		spin_unlock(&dcache_lru_lock);
+		spin_unlock(&dentry->d_sb->s_dentry_lru_lock);
 	}
 }
 
@@ -259,15 +258,15 @@ static void __dentry_lru_del(struct dentry *dentry)
 static void dentry_lru_del(struct dentry *dentry)
 {
 	if (!list_empty(&dentry->d_lru)) {
-		spin_lock(&dcache_lru_lock);
+		spin_lock(&dentry->d_sb->s_dentry_lru_lock);
 		__dentry_lru_del(dentry);
-		spin_unlock(&dcache_lru_lock);
+		spin_unlock(&dentry->d_sb->s_dentry_lru_lock);
 	}
 }
 
 static void dentry_lru_move_tail(struct dentry *dentry)
 {
-	spin_lock(&dcache_lru_lock);
+	spin_lock(&dentry->d_sb->s_dentry_lru_lock);
 	if (list_empty(&dentry->d_lru)) {
 		list_add_tail(&dentry->d_lru, &dentry->d_sb->s_dentry_lru);
 		dentry->d_sb->s_nr_dentry_unused++;
@@ -275,7 +274,7 @@ static void dentry_lru_move_tail(struct dentry *dentry)
 	} else {
 		list_move_tail(&dentry->d_lru, &dentry->d_sb->s_dentry_lru);
 	}
-	spin_unlock(&dcache_lru_lock);
+	spin_unlock(&dentry->d_sb->s_dentry_lru_lock);
 }
 
 /**
@@ -756,14 +755,14 @@ static void __shrink_dcache_sb(struct super_block *sb, int count, int flags)
 	LIST_HEAD(tmp);
 
 relock:
-	spin_lock(&dcache_lru_lock);
+	spin_lock(&sb->s_dentry_lru_lock);
 	while (!list_empty(&sb->s_dentry_lru)) {
 		dentry = list_entry(sb->s_dentry_lru.prev,
 				struct dentry, d_lru);
 		BUG_ON(dentry->d_sb != sb);
 
 		if (!spin_trylock(&dentry->d_lock)) {
-			spin_unlock(&dcache_lru_lock);
+			spin_unlock(&sb->s_dentry_lru_lock);
 			cpu_relax();
 			goto relock;
 		}
@@ -784,11 +783,11 @@ relock:
 			if (!--count)
 				break;
 		}
-		cond_resched_lock(&dcache_lru_lock);
+		cond_resched_lock(&sb->s_dentry_lru_lock);
 	}
 	if (!list_empty(&referenced))
 		list_splice(&referenced, &sb->s_dentry_lru);
-	spin_unlock(&dcache_lru_lock);
+	spin_unlock(&sb->s_dentry_lru_lock);
 
 	shrink_dentry_list(&tmp);
 }
@@ -820,14 +819,14 @@ void shrink_dcache_sb(struct super_block *sb)
 {
 	LIST_HEAD(tmp);
 
-	spin_lock(&dcache_lru_lock);
+	spin_lock(&sb->s_dentry_lru_lock);
 	while (!list_empty(&sb->s_dentry_lru)) {
 		list_splice_init(&sb->s_dentry_lru, &tmp);
-		spin_unlock(&dcache_lru_lock);
+		spin_unlock(&sb->s_dentry_lru_lock);
 		shrink_dentry_list(&tmp);
-		spin_lock(&dcache_lru_lock);
+		spin_lock(&sb->s_dentry_lru_lock);
 	}
-	spin_unlock(&dcache_lru_lock);
+	spin_unlock(&sb->s_dentry_lru_lock);
 }
 EXPORT_SYMBOL(shrink_dcache_sb);
 
diff --git a/fs/super.c b/fs/super.c
index 3f56a26..6a72693 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -140,6 +140,7 @@ static struct super_block *alloc_super(struct file_system_type *type)
 		INIT_HLIST_BL_HEAD(&s->s_anon);
 		INIT_LIST_HEAD(&s->s_inodes);
 		INIT_LIST_HEAD(&s->s_dentry_lru);
+		spin_lock_init(&s->s_dentry_lru_lock);
 		INIT_LIST_HEAD(&s->s_inode_lru);
 		spin_lock_init(&s->s_inode_lru_lock);
 		init_rwsem(&s->s_umount);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index f23bcb7..556fd90 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1395,7 +1395,8 @@ struct super_block {
 #else
 	struct list_head	s_files;
 #endif
-	/* s_dentry_lru, s_nr_dentry_unused protected by dcache.c lru locks */
+	/* s_dentry_lru_lock protects s_dentry_lru, s_nr_dentry_unused */
+	spinlock_t		s_dentry_lru_lock ____cacheline_aligned_in_smp;
 	struct list_head	s_dentry_lru;	/* unused dentry lru */
 	int			s_nr_dentry_unused;	/* # of dentry on lru */
 
-- 
1.7.5.4


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

* Re: [PATCH 1/2] dcache: convert dentry_stat.nr_unused to per-cpu counters
  2011-08-08  7:03 ` [PATCH 1/2] dcache: convert dentry_stat.nr_unused to per-cpu counters Dave Chinner
@ 2011-08-08  7:08     ` Pekka Enberg
  0 siblings, 0 replies; 10+ messages in thread
From: Pekka Enberg @ 2011-08-08  7:08 UTC (permalink / raw)
  To: Dave Chinner; +Cc: viro, linux-kernel, linux-fsdevel

On Mon, Aug 8, 2011 at 10:03 AM, Dave Chinner <david@fromorbit.com> wrote:
> From: Dave Chinner <dchinner@redhat.com>
>
> Before we split up the dcache_lru_lock, the unused dentry counter
> needs to be made independent of the global dcache_lru_lock. Convert
> it to per-cpu counters to do this.
>
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> ---
>  fs/dcache.c |   17 ++++++++++++++---
>  1 files changed, 14 insertions(+), 3 deletions(-)
>
> diff --git a/fs/dcache.c b/fs/dcache.c
> index b05aac3..5e5208d 100644
> --- a/fs/dcache.c
> +++ b/fs/dcache.c
> @@ -116,6 +116,7 @@ struct dentry_stat_t dentry_stat = {
>  };
>
>  static DEFINE_PER_CPU(unsigned int, nr_dentry);
> +static DEFINE_PER_CPU(unsigned int, nr_dentry_unused);
>
>  #if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS)
>  static int get_nr_dentry(void)
> @@ -127,10 +128,20 @@ static int get_nr_dentry(void)
>        return sum < 0 ? 0 : sum;
>  }
>
> +static int get_nr_dentry_unused(void)
> +{
> +       int i;
> +       int sum = 0;
> +       for_each_possible_cpu(i)
> +               sum += per_cpu(nr_dentry_unused, i);
> +       return sum < 0 ? 0 : sum;
> +}

Why not use struct percpu_counter and percpu_counter_sum_positive() for this?

> +
>  int proc_nr_dentry(ctl_table *table, int write, void __user *buffer,
>                   size_t *lenp, loff_t *ppos)
>  {
>        dentry_stat.nr_dentry = get_nr_dentry();
> +       dentry_stat.nr_unused = get_nr_dentry_unused();
>        return proc_dointvec(table, write, buffer, lenp, ppos);
>  }
>  #endif
> @@ -233,7 +244,7 @@ static void dentry_lru_add(struct dentry *dentry)
>                spin_lock(&dcache_lru_lock);
>                list_add(&dentry->d_lru, &dentry->d_sb->s_dentry_lru);
>                dentry->d_sb->s_nr_dentry_unused++;
> -               dentry_stat.nr_unused++;
> +               this_cpu_inc(nr_dentry_unused);
>                spin_unlock(&dcache_lru_lock);
>        }
>  }
> @@ -242,7 +253,7 @@ static void __dentry_lru_del(struct dentry *dentry)
>  {
>        list_del_init(&dentry->d_lru);
>        dentry->d_sb->s_nr_dentry_unused--;
> -       dentry_stat.nr_unused--;
> +       this_cpu_dec(nr_dentry_unused);
>  }
>
>  static void dentry_lru_del(struct dentry *dentry)
> @@ -260,7 +271,7 @@ static void dentry_lru_move_tail(struct dentry *dentry)
>        if (list_empty(&dentry->d_lru)) {
>                list_add_tail(&dentry->d_lru, &dentry->d_sb->s_dentry_lru);
>                dentry->d_sb->s_nr_dentry_unused++;
> -               dentry_stat.nr_unused++;
> +               this_cpu_inc(nr_dentry_unused);
>        } else {
>                list_move_tail(&dentry->d_lru, &dentry->d_sb->s_dentry_lru);
>        }
> --
> 1.7.5.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
>

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

* Re: [PATCH 1/2] dcache: convert dentry_stat.nr_unused to per-cpu counters
@ 2011-08-08  7:08     ` Pekka Enberg
  0 siblings, 0 replies; 10+ messages in thread
From: Pekka Enberg @ 2011-08-08  7:08 UTC (permalink / raw)
  To: Dave Chinner; +Cc: viro, linux-kernel, linux-fsdevel

On Mon, Aug 8, 2011 at 10:03 AM, Dave Chinner <david@fromorbit.com> wrote:
> From: Dave Chinner <dchinner@redhat.com>
>
> Before we split up the dcache_lru_lock, the unused dentry counter
> needs to be made independent of the global dcache_lru_lock. Convert
> it to per-cpu counters to do this.
>
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> ---
>  fs/dcache.c |   17 ++++++++++++++---
>  1 files changed, 14 insertions(+), 3 deletions(-)
>
> diff --git a/fs/dcache.c b/fs/dcache.c
> index b05aac3..5e5208d 100644
> --- a/fs/dcache.c
> +++ b/fs/dcache.c
> @@ -116,6 +116,7 @@ struct dentry_stat_t dentry_stat = {
>  };
>
>  static DEFINE_PER_CPU(unsigned int, nr_dentry);
> +static DEFINE_PER_CPU(unsigned int, nr_dentry_unused);
>
>  #if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS)
>  static int get_nr_dentry(void)
> @@ -127,10 +128,20 @@ static int get_nr_dentry(void)
>        return sum < 0 ? 0 : sum;
>  }
>
> +static int get_nr_dentry_unused(void)
> +{
> +       int i;
> +       int sum = 0;
> +       for_each_possible_cpu(i)
> +               sum += per_cpu(nr_dentry_unused, i);
> +       return sum < 0 ? 0 : sum;
> +}

Why not use struct percpu_counter and percpu_counter_sum_positive() for this?

> +
>  int proc_nr_dentry(ctl_table *table, int write, void __user *buffer,
>                   size_t *lenp, loff_t *ppos)
>  {
>        dentry_stat.nr_dentry = get_nr_dentry();
> +       dentry_stat.nr_unused = get_nr_dentry_unused();
>        return proc_dointvec(table, write, buffer, lenp, ppos);
>  }
>  #endif
> @@ -233,7 +244,7 @@ static void dentry_lru_add(struct dentry *dentry)
>                spin_lock(&dcache_lru_lock);
>                list_add(&dentry->d_lru, &dentry->d_sb->s_dentry_lru);
>                dentry->d_sb->s_nr_dentry_unused++;
> -               dentry_stat.nr_unused++;
> +               this_cpu_inc(nr_dentry_unused);
>                spin_unlock(&dcache_lru_lock);
>        }
>  }
> @@ -242,7 +253,7 @@ static void __dentry_lru_del(struct dentry *dentry)
>  {
>        list_del_init(&dentry->d_lru);
>        dentry->d_sb->s_nr_dentry_unused--;
> -       dentry_stat.nr_unused--;
> +       this_cpu_dec(nr_dentry_unused);
>  }
>
>  static void dentry_lru_del(struct dentry *dentry)
> @@ -260,7 +271,7 @@ static void dentry_lru_move_tail(struct dentry *dentry)
>        if (list_empty(&dentry->d_lru)) {
>                list_add_tail(&dentry->d_lru, &dentry->d_sb->s_dentry_lru);
>                dentry->d_sb->s_nr_dentry_unused++;
> -               dentry_stat.nr_unused++;
> +               this_cpu_inc(nr_dentry_unused);
>        } else {
>                list_move_tail(&dentry->d_lru, &dentry->d_sb->s_dentry_lru);
>        }
> --
> 1.7.5.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
>
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 2/2] dentry: move to per-sb LRU locks
  2011-08-08  7:03 ` [PATCH 2/2] dentry: move to per-sb LRU locks Dave Chinner
@ 2011-08-08 13:02   ` Peter Zijlstra
  2011-08-09 11:04     ` Dave Chinner
  0 siblings, 1 reply; 10+ messages in thread
From: Peter Zijlstra @ 2011-08-08 13:02 UTC (permalink / raw)
  To: Dave Chinner; +Cc: viro, linux-kernel, linux-fsdevel

On Mon, 2011-08-08 at 17:03 +1000, Dave Chinner wrote:
> +       /* s_dentry_lru_lock protects s_dentry_lru, s_nr_dentry_unused */
> +       spinlock_t              s_dentry_lru_lock ____cacheline_aligned_in_smp;
>         struct list_head        s_dentry_lru;   /* unused dentry lru */ 

Wouldn't it make sense to have both those on the same cacheline?

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

* Re: [PATCH 1/2] dcache: convert dentry_stat.nr_unused to per-cpu counters
  2011-08-08  7:08     ` Pekka Enberg
  (?)
@ 2011-08-09 10:48     ` Dave Chinner
  -1 siblings, 0 replies; 10+ messages in thread
From: Dave Chinner @ 2011-08-09 10:48 UTC (permalink / raw)
  To: Pekka Enberg; +Cc: viro, linux-kernel, linux-fsdevel

On Mon, Aug 08, 2011 at 10:08:20AM +0300, Pekka Enberg wrote:
> On Mon, Aug 8, 2011 at 10:03 AM, Dave Chinner <david@fromorbit.com> wrote:
> > From: Dave Chinner <dchinner@redhat.com>
> >
> > Before we split up the dcache_lru_lock, the unused dentry counter
> > needs to be made independent of the global dcache_lru_lock. Convert
> > it to per-cpu counters to do this.
> >
> > Signed-off-by: Dave Chinner <dchinner@redhat.com>
> > ---
> >  fs/dcache.c |   17 ++++++++++++++---
> >  1 files changed, 14 insertions(+), 3 deletions(-)
> >
> > diff --git a/fs/dcache.c b/fs/dcache.c
> > index b05aac3..5e5208d 100644
> > --- a/fs/dcache.c
> > +++ b/fs/dcache.c
> > @@ -116,6 +116,7 @@ struct dentry_stat_t dentry_stat = {
> >  };
> >
> >  static DEFINE_PER_CPU(unsigned int, nr_dentry);
> > +static DEFINE_PER_CPU(unsigned int, nr_dentry_unused);
> >
> >  #if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS)
> >  static int get_nr_dentry(void)
> > @@ -127,10 +128,20 @@ static int get_nr_dentry(void)
> >        return sum < 0 ? 0 : sum;
> >  }
> >
> > +static int get_nr_dentry_unused(void)
> > +{
> > +       int i;
> > +       int sum = 0;
> > +       for_each_possible_cpu(i)
> > +               sum += per_cpu(nr_dentry_unused, i);
> > +       return sum < 0 ? 0 : sum;
> > +}
> 
> Why not use struct percpu_counter and percpu_counter_sum_positive() for this?

That's what I originally implemented for all these VFS per-cpu
counters. e.g:

cffbc8a fs: Convert nr_inodes and nr_unused to per-cpu counters

but then this happened:

commit 86c8749ede0c59e590de9267066932a26f1ce796
Author: Nick Piggin <npiggin@kernel.dk>
Date:   Fri Jan 7 17:49:18 2011 +1100

    vfs: revert per-cpu nr_unused counters for dentry and inodes
    
    The nr_unused counters count the number of objects on an LRU, and as such they
    are synchronized with LRU object insertion and removal and scanning, and
    protected under the LRU lock.
    
    Making it per-cpu does not actually get any concurrency improvements because o
    this lock, and summing the counter is much slower, and
    incrementing/decrementing it costs more code size and is slower too.
    
    These counters should stay per-LRU, which currently means global.
    
    Signed-off-by: Nick Piggin <npiggin@kernel.dk>

and then, because the per-cpu counters were actually necessary,
a couple of patches later in the series per-cpu counters were
re-introduced:

commit 3e880fb5e4bb6a012035e3edd0586ee2817c2e24
Author: Nick Piggin <npiggin@kernel.dk>
Date:   Fri Jan 7 17:49:19 2011 +1100

    fs: use fast counters for vfs caches
    
    percpu_counter library generates quite nasty code, so unless you need
    to dynamically allocate counters or take fast approximate value, a
    simple per cpu set of counters is much better.
    
    The percpu_counter can never be made to work as well, because it has an
    indirection from pointer to percpu memory, and it can't use direct
    this_cpu_inc interfaces because it doesn't use static PER_CPU data, so
    code will always be worse.

....

No point in making arguments about how using and improving the
generic counter helps everyone, the maintenance is lower as well,
or that we are summing the counters on every single shrinker call
(i.e. could be thousands of times a second) so we need fast
approximate values to be taken.

The change to per-sb LRUs actually takes away the need to sum the
VFS inode and dentry counters on every shrinker call, so now the use
of the roll-your-own counter structure makes a bit of sense because
they are only read when someone read /proc/sys/fs/dentry-state. It
sure as hell didn't make sense back when this code was merged,
though....

Cheers,

Dave.

-- 
Dave Chinner
david@fromorbit.com

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

* Re: [PATCH 2/2] dentry: move to per-sb LRU locks
  2011-08-08 13:02   ` Peter Zijlstra
@ 2011-08-09 11:04     ` Dave Chinner
  2011-08-09 11:21       ` Peter Zijlstra
  2011-08-10  5:35       ` Dave Chinner
  0 siblings, 2 replies; 10+ messages in thread
From: Dave Chinner @ 2011-08-09 11:04 UTC (permalink / raw)
  To: Peter Zijlstra; +Cc: viro, linux-kernel, linux-fsdevel

On Mon, Aug 08, 2011 at 03:02:24PM +0200, Peter Zijlstra wrote:
> On Mon, 2011-08-08 at 17:03 +1000, Dave Chinner wrote:
> > +       /* s_dentry_lru_lock protects s_dentry_lru, s_nr_dentry_unused */
> > +       spinlock_t              s_dentry_lru_lock ____cacheline_aligned_in_smp;
> >         struct list_head        s_dentry_lru;   /* unused dentry lru */ 
> 
> Wouldn't it make sense to have both those on the same cacheline?

Um, they are, aren't they? The annotation moves s_dentry_lru_lock to
the start of a new cacheline, and everything packs in after that?

$ pahole fs/dcache.o
....
        /* --- cacheline 8 boundary (512 bytes) --- */
        spinlock_t                 s_dentry_lru_lock;    /*   512    72 */
        /* --- cacheline 9 boundary (576 bytes) was 8 bytes ago --- */
        struct list_head           s_dentry_lru;         /*   584    16 */
        int                        s_nr_dentry_unused;   /*   600     4 */

Oh, bloody hell. When did that change? (let me guess - gcc changed
the implementation of attribute __aligned__ to affect the size of 
variables for packing as well as alignment at some point?)

Ok, so how do I it move the lock to the start of the next cache line
and have the following variables pack tightly against it so they are
all on the same cache line? And on a different cacheline to the
s_inode_lru* variables that also have the same
____cacheline_aligned_in_smp annotations....

/me sees a patch to other XFS structures in the not-to-distant future

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

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

* Re: [PATCH 2/2] dentry: move to per-sb LRU locks
  2011-08-09 11:04     ` Dave Chinner
@ 2011-08-09 11:21       ` Peter Zijlstra
  2011-08-10  5:35       ` Dave Chinner
  1 sibling, 0 replies; 10+ messages in thread
From: Peter Zijlstra @ 2011-08-09 11:21 UTC (permalink / raw)
  To: Dave Chinner; +Cc: viro, linux-kernel, linux-fsdevel

On Tue, 2011-08-09 at 21:04 +1000, Dave Chinner wrote:

> Ok, so how do I it move the lock to the start of the next cache line
> and have the following variables pack tightly against it so they are
> all on the same cache line? 

Anonymous struct ?

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

* Re: [PATCH 2/2] dentry: move to per-sb LRU locks
  2011-08-09 11:04     ` Dave Chinner
  2011-08-09 11:21       ` Peter Zijlstra
@ 2011-08-10  5:35       ` Dave Chinner
  1 sibling, 0 replies; 10+ messages in thread
From: Dave Chinner @ 2011-08-10  5:35 UTC (permalink / raw)
  To: Peter Zijlstra; +Cc: viro, linux-kernel, linux-fsdevel

On Tue, Aug 09, 2011 at 09:04:21PM +1000, Dave Chinner wrote:
> On Mon, Aug 08, 2011 at 03:02:24PM +0200, Peter Zijlstra wrote:
> > On Mon, 2011-08-08 at 17:03 +1000, Dave Chinner wrote:
> > > +       /* s_dentry_lru_lock protects s_dentry_lru, s_nr_dentry_unused */
> > > +       spinlock_t              s_dentry_lru_lock ____cacheline_aligned_in_smp;
> > >         struct list_head        s_dentry_lru;   /* unused dentry lru */ 
> > 
> > Wouldn't it make sense to have both those on the same cacheline?
> 
> Um, they are, aren't they? The annotation moves s_dentry_lru_lock to
> the start of a new cacheline, and everything packs in after that?
> 
> $ pahole fs/dcache.o
> ....
>         /* --- cacheline 8 boundary (512 bytes) --- */
>         spinlock_t                 s_dentry_lru_lock;    /*   512    72 */
>         /* --- cacheline 9 boundary (576 bytes) was 8 bytes ago --- */
>         struct list_head           s_dentry_lru;         /*   584    16 */
>         int                        s_nr_dentry_unused;   /*   600     4 */
> 
> Oh, bloody hell. When did that change?

Actually, it hasn't. The problem here is that when you build with
lockdep and all the associated checking, a spinlock grows from 4
bytes to 72 bytes, pushing anything after it onto the next
cacheline. I didn't notice that until I just did a build with a
non-lockdep kernel and saw the structure change size significantly.
So the struct superblock looks like this without lockdep:

....
        struct list_head *         s_files;              /*   216     8 */

        /* XXX 32 bytes hole, try to pack */

        /* --- cacheline 4 boundary (256 bytes) --- */
        spinlock_t                 s_dentry_lru_lock;    /*   256     4 */

        /* XXX 4 bytes hole, try to pack */

        struct list_head           s_dentry_lru;         /*   264    16 */
        int                        s_nr_dentry_unused;   /*   280     4 */

        /* XXX 36 bytes hole, try to pack */

        /* --- cacheline 5 boundary (320 bytes) --- */
        spinlock_t                 s_inode_lru_lock;     /*   320     4 */

        /* XXX 4 bytes hole, try to pack */

        struct list_head           s_inode_lru;          /*   328    16 */
        int                        s_nr_inodes_unused;   /*   344     4 */

        /* XXX 4 bytes hole, try to pack */

        struct block_device *      s_bdev;               /*   352     8 */
        struct backing_dev_info *  s_bdi;                /*   360     8 */
        struct mtd_info *          s_mtd;                /*   368     8 */
        struct list_head           s_instances;          /*   376    16 */
        /* --- cacheline 6 boundary (384 bytes) was 8 bytes ago --- */
        struct quota_info          s_dquot;              /*   392   280 */
....

So we see the dentry LRU lock, list and counter on it's own cache
line, and the inode LRU lock, list and counter on the next cache
line.

But what is does point out is that we should actually also add a
____cacheline_aligned_in_smp annotation to the variable -after- the
variables we want on their own cacheline so that they don't get
packed tightly into the cacheline we want for the LRU variables.
That's not something I'm going to fix in this patch...

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

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

end of thread, other threads:[~2011-08-10  5:36 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-08-08  7:03 [PATCH 0/2] dcache: per-sb LRU locks Dave Chinner
2011-08-08  7:03 ` [PATCH 1/2] dcache: convert dentry_stat.nr_unused to per-cpu counters Dave Chinner
2011-08-08  7:08   ` Pekka Enberg
2011-08-08  7:08     ` Pekka Enberg
2011-08-09 10:48     ` Dave Chinner
2011-08-08  7:03 ` [PATCH 2/2] dentry: move to per-sb LRU locks Dave Chinner
2011-08-08 13:02   ` Peter Zijlstra
2011-08-09 11:04     ` Dave Chinner
2011-08-09 11:21       ` Peter Zijlstra
2011-08-10  5:35       ` Dave Chinner

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.