diff options
author | Dave Chinner <dchinner@redhat.com> | 2013-08-27 20:17:55 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2013-09-10 18:56:30 -0400 |
commit | 19156840e33a23eeb1a749c0f991dab6588b077d (patch) | |
tree | 460675d21b0d6a5de3c179b951d18fec24e77cc8 | |
parent | 62d36c77035219ac776d1882ed3a662f2b75f258 (diff) |
dentry: move to per-sb LRU locks
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. The need for this is independent
of any performance consideration that may arise: in the interest of
abstracting the lru operations away, it is mandatory that each lru works
around its own lock instead of a global lock for all of them.
[glommer@openvz.org: updated changelog ]
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Glauber Costa <glommer@openvz.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Acked-by: Mel Gorman <mgorman@suse.de>
Cc: "Theodore Ts'o" <tytso@mit.edu>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Cc: Arve Hjønnevåg <arve@android.com>
Cc: Carlos Maiolino <cmaiolino@redhat.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Chuck Lever <chuck.lever@oracle.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: David Rientjes <rientjes@google.com>
Cc: Gleb Natapov <gleb@redhat.com>
Cc: Greg Thelen <gthelen@google.com>
Cc: J. Bruce Fields <bfields@redhat.com>
Cc: Jan Kara <jack@suse.cz>
Cc: Jerome Glisse <jglisse@redhat.com>
Cc: John Stultz <john.stultz@linaro.org>
Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Cc: Kent Overstreet <koverstreet@google.com>
Cc: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Cc: Mel Gorman <mgorman@suse.de>
Cc: Steven Whitehouse <swhiteho@redhat.com>
Cc: Thomas Hellstrom <thellstrom@vmware.com>
Cc: Trond Myklebust <Trond.Myklebust@netapp.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | fs/dcache.c | 33 | ||||
-rw-r--r-- | fs/super.c | 1 | ||||
-rw-r--r-- | include/linux/fs.h | 4 |
3 files changed, 20 insertions, 18 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 03161240e744..e989ecb44a65 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -48,7 +48,7 @@ | |||
48 | * - the dcache hash table | 48 | * - the dcache hash table |
49 | * s_anon bl list spinlock protects: | 49 | * s_anon bl list spinlock protects: |
50 | * - the s_anon list (see __d_drop) | 50 | * - the s_anon list (see __d_drop) |
51 | * dcache_lru_lock protects: | 51 | * dentry->d_sb->s_dentry_lru_lock protects: |
52 | * - the dcache lru lists and counters | 52 | * - the dcache lru lists and counters |
53 | * d_lock protects: | 53 | * d_lock protects: |
54 | * - d_flags | 54 | * - d_flags |
@@ -63,7 +63,7 @@ | |||
63 | * Ordering: | 63 | * Ordering: |
64 | * dentry->d_inode->i_lock | 64 | * dentry->d_inode->i_lock |
65 | * dentry->d_lock | 65 | * dentry->d_lock |
66 | * dcache_lru_lock | 66 | * dentry->d_sb->s_dentry_lru_lock |
67 | * dcache_hash_bucket lock | 67 | * dcache_hash_bucket lock |
68 | * s_anon lock | 68 | * s_anon lock |
69 | * | 69 | * |
@@ -81,7 +81,6 @@ | |||
81 | int sysctl_vfs_cache_pressure __read_mostly = 100; | 81 | int sysctl_vfs_cache_pressure __read_mostly = 100; |
82 | EXPORT_SYMBOL_GPL(sysctl_vfs_cache_pressure); | 82 | EXPORT_SYMBOL_GPL(sysctl_vfs_cache_pressure); |
83 | 83 | ||
84 | static __cacheline_aligned_in_smp DEFINE_SPINLOCK(dcache_lru_lock); | ||
85 | __cacheline_aligned_in_smp DEFINE_SEQLOCK(rename_lock); | 84 | __cacheline_aligned_in_smp DEFINE_SEQLOCK(rename_lock); |
86 | 85 | ||
87 | EXPORT_SYMBOL(rename_lock); | 86 | EXPORT_SYMBOL(rename_lock); |
@@ -362,12 +361,12 @@ static void dentry_unlink_inode(struct dentry * dentry) | |||
362 | static void dentry_lru_add(struct dentry *dentry) | 361 | static void dentry_lru_add(struct dentry *dentry) |
363 | { | 362 | { |
364 | if (unlikely(!(dentry->d_flags & DCACHE_LRU_LIST))) { | 363 | if (unlikely(!(dentry->d_flags & DCACHE_LRU_LIST))) { |
365 | spin_lock(&dcache_lru_lock); | 364 | spin_lock(&dentry->d_sb->s_dentry_lru_lock); |
366 | dentry->d_flags |= DCACHE_LRU_LIST; | 365 | dentry->d_flags |= DCACHE_LRU_LIST; |
367 | list_add(&dentry->d_lru, &dentry->d_sb->s_dentry_lru); | 366 | list_add(&dentry->d_lru, &dentry->d_sb->s_dentry_lru); |
368 | dentry->d_sb->s_nr_dentry_unused++; | 367 | dentry->d_sb->s_nr_dentry_unused++; |
369 | this_cpu_inc(nr_dentry_unused); | 368 | this_cpu_inc(nr_dentry_unused); |
370 | spin_unlock(&dcache_lru_lock); | 369 | spin_unlock(&dentry->d_sb->s_dentry_lru_lock); |
371 | } | 370 | } |
372 | } | 371 | } |
373 | 372 | ||
@@ -385,15 +384,15 @@ static void __dentry_lru_del(struct dentry *dentry) | |||
385 | static void dentry_lru_del(struct dentry *dentry) | 384 | static void dentry_lru_del(struct dentry *dentry) |
386 | { | 385 | { |
387 | if (!list_empty(&dentry->d_lru)) { | 386 | if (!list_empty(&dentry->d_lru)) { |
388 | spin_lock(&dcache_lru_lock); | 387 | spin_lock(&dentry->d_sb->s_dentry_lru_lock); |
389 | __dentry_lru_del(dentry); | 388 | __dentry_lru_del(dentry); |
390 | spin_unlock(&dcache_lru_lock); | 389 | spin_unlock(&dentry->d_sb->s_dentry_lru_lock); |
391 | } | 390 | } |
392 | } | 391 | } |
393 | 392 | ||
394 | static void dentry_lru_move_list(struct dentry *dentry, struct list_head *list) | 393 | static void dentry_lru_move_list(struct dentry *dentry, struct list_head *list) |
395 | { | 394 | { |
396 | spin_lock(&dcache_lru_lock); | 395 | spin_lock(&dentry->d_sb->s_dentry_lru_lock); |
397 | if (list_empty(&dentry->d_lru)) { | 396 | if (list_empty(&dentry->d_lru)) { |
398 | dentry->d_flags |= DCACHE_LRU_LIST; | 397 | dentry->d_flags |= DCACHE_LRU_LIST; |
399 | list_add_tail(&dentry->d_lru, list); | 398 | list_add_tail(&dentry->d_lru, list); |
@@ -402,7 +401,7 @@ static void dentry_lru_move_list(struct dentry *dentry, struct list_head *list) | |||
402 | } else { | 401 | } else { |
403 | list_move_tail(&dentry->d_lru, list); | 402 | list_move_tail(&dentry->d_lru, list); |
404 | } | 403 | } |
405 | spin_unlock(&dcache_lru_lock); | 404 | spin_unlock(&dentry->d_sb->s_dentry_lru_lock); |
406 | } | 405 | } |
407 | 406 | ||
408 | /** | 407 | /** |
@@ -895,14 +894,14 @@ void prune_dcache_sb(struct super_block *sb, int count) | |||
895 | LIST_HEAD(tmp); | 894 | LIST_HEAD(tmp); |
896 | 895 | ||
897 | relock: | 896 | relock: |
898 | spin_lock(&dcache_lru_lock); | 897 | spin_lock(&sb->s_dentry_lru_lock); |
899 | while (!list_empty(&sb->s_dentry_lru)) { | 898 | while (!list_empty(&sb->s_dentry_lru)) { |
900 | dentry = list_entry(sb->s_dentry_lru.prev, | 899 | dentry = list_entry(sb->s_dentry_lru.prev, |
901 | struct dentry, d_lru); | 900 | struct dentry, d_lru); |
902 | BUG_ON(dentry->d_sb != sb); | 901 | BUG_ON(dentry->d_sb != sb); |
903 | 902 | ||
904 | if (!spin_trylock(&dentry->d_lock)) { | 903 | if (!spin_trylock(&dentry->d_lock)) { |
905 | spin_unlock(&dcache_lru_lock); | 904 | spin_unlock(&sb->s_dentry_lru_lock); |
906 | cpu_relax(); | 905 | cpu_relax(); |
907 | goto relock; | 906 | goto relock; |
908 | } | 907 | } |
@@ -918,11 +917,11 @@ relock: | |||
918 | if (!--count) | 917 | if (!--count) |
919 | break; | 918 | break; |
920 | } | 919 | } |
921 | cond_resched_lock(&dcache_lru_lock); | 920 | cond_resched_lock(&sb->s_dentry_lru_lock); |
922 | } | 921 | } |
923 | if (!list_empty(&referenced)) | 922 | if (!list_empty(&referenced)) |
924 | list_splice(&referenced, &sb->s_dentry_lru); | 923 | list_splice(&referenced, &sb->s_dentry_lru); |
925 | spin_unlock(&dcache_lru_lock); | 924 | spin_unlock(&sb->s_dentry_lru_lock); |
926 | 925 | ||
927 | shrink_dentry_list(&tmp); | 926 | shrink_dentry_list(&tmp); |
928 | } | 927 | } |
@@ -938,14 +937,14 @@ void shrink_dcache_sb(struct super_block *sb) | |||
938 | { | 937 | { |
939 | LIST_HEAD(tmp); | 938 | LIST_HEAD(tmp); |
940 | 939 | ||
941 | spin_lock(&dcache_lru_lock); | 940 | spin_lock(&sb->s_dentry_lru_lock); |
942 | while (!list_empty(&sb->s_dentry_lru)) { | 941 | while (!list_empty(&sb->s_dentry_lru)) { |
943 | list_splice_init(&sb->s_dentry_lru, &tmp); | 942 | list_splice_init(&sb->s_dentry_lru, &tmp); |
944 | spin_unlock(&dcache_lru_lock); | 943 | spin_unlock(&sb->s_dentry_lru_lock); |
945 | shrink_dentry_list(&tmp); | 944 | shrink_dentry_list(&tmp); |
946 | spin_lock(&dcache_lru_lock); | 945 | spin_lock(&sb->s_dentry_lru_lock); |
947 | } | 946 | } |
948 | spin_unlock(&dcache_lru_lock); | 947 | spin_unlock(&sb->s_dentry_lru_lock); |
949 | } | 948 | } |
950 | EXPORT_SYMBOL(shrink_dcache_sb); | 949 | EXPORT_SYMBOL(shrink_dcache_sb); |
951 | 950 | ||
diff --git a/fs/super.c b/fs/super.c index 63b6863bac7b..3c5318694ccd 100644 --- a/fs/super.c +++ b/fs/super.c | |||
@@ -176,6 +176,7 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags) | |||
176 | INIT_HLIST_BL_HEAD(&s->s_anon); | 176 | INIT_HLIST_BL_HEAD(&s->s_anon); |
177 | INIT_LIST_HEAD(&s->s_inodes); | 177 | INIT_LIST_HEAD(&s->s_inodes); |
178 | INIT_LIST_HEAD(&s->s_dentry_lru); | 178 | INIT_LIST_HEAD(&s->s_dentry_lru); |
179 | spin_lock_init(&s->s_dentry_lru_lock); | ||
179 | INIT_LIST_HEAD(&s->s_inode_lru); | 180 | INIT_LIST_HEAD(&s->s_inode_lru); |
180 | spin_lock_init(&s->s_inode_lru_lock); | 181 | spin_lock_init(&s->s_inode_lru_lock); |
181 | INIT_LIST_HEAD(&s->s_mounts); | 182 | INIT_LIST_HEAD(&s->s_mounts); |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 3b3edac75df2..14a90f6886fa 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -1269,7 +1269,9 @@ struct super_block { | |||
1269 | struct list_head s_files; | 1269 | struct list_head s_files; |
1270 | #endif | 1270 | #endif |
1271 | struct list_head s_mounts; /* list of mounts; _not_ for fs use */ | 1271 | struct list_head s_mounts; /* list of mounts; _not_ for fs use */ |
1272 | /* s_dentry_lru, s_nr_dentry_unused protected by dcache.c lru locks */ | 1272 | |
1273 | /* s_dentry_lru_lock protects s_dentry_lru and s_nr_dentry_unused */ | ||
1274 | spinlock_t s_dentry_lru_lock ____cacheline_aligned_in_smp; | ||
1273 | struct list_head s_dentry_lru; /* unused dentry lru */ | 1275 | struct list_head s_dentry_lru; /* unused dentry lru */ |
1274 | long s_nr_dentry_unused; /* # of dentry on lru */ | 1276 | long s_nr_dentry_unused; /* # of dentry on lru */ |
1275 | 1277 | ||