diff options
author | Dave Chinner <dchinner@redhat.com> | 2013-08-27 20:17:57 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2013-09-10 18:56:30 -0400 |
commit | 0a234c6dcb79a270803f5c9773ed650b78730962 (patch) | |
tree | 8f93bd04d5c01a32dc78617c04dc770dc4b86883 /fs | |
parent | 24f7c6b981fb70084757382da464ea85d72af300 (diff) |
shrinker: convert superblock shrinkers to new API
Convert superblock shrinker to use the new count/scan API, and propagate
the API changes through to the filesystem callouts. The filesystem
callouts already use a count/scan API, so it's just changing counters to
longs to match the VM API.
This requires the dentry and inode shrinker callouts to be converted to
the count/scan API. This is mainly a mechanical change.
[glommer@openvz.org: use mult_frac for fractional proportions, build fixes]
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Glauber Costa <glommer@openvz.org>
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>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/dcache.c | 7 | ||||
-rw-r--r-- | fs/inode.c | 7 | ||||
-rw-r--r-- | fs/internal.h | 2 | ||||
-rw-r--r-- | fs/super.c | 80 | ||||
-rw-r--r-- | fs/xfs/xfs_icache.c | 4 | ||||
-rw-r--r-- | fs/xfs/xfs_icache.h | 2 | ||||
-rw-r--r-- | fs/xfs/xfs_super.c | 8 |
7 files changed, 68 insertions, 42 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 509b49410943..77d466b13fef 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -913,11 +913,12 @@ static void shrink_dentry_list(struct list_head *list) | |||
913 | * This function may fail to free any resources if all the dentries are in | 913 | * This function may fail to free any resources if all the dentries are in |
914 | * use. | 914 | * use. |
915 | */ | 915 | */ |
916 | void prune_dcache_sb(struct super_block *sb, int count) | 916 | long prune_dcache_sb(struct super_block *sb, unsigned long nr_to_scan) |
917 | { | 917 | { |
918 | struct dentry *dentry; | 918 | struct dentry *dentry; |
919 | LIST_HEAD(referenced); | 919 | LIST_HEAD(referenced); |
920 | LIST_HEAD(tmp); | 920 | LIST_HEAD(tmp); |
921 | long freed = 0; | ||
921 | 922 | ||
922 | relock: | 923 | relock: |
923 | spin_lock(&sb->s_dentry_lru_lock); | 924 | spin_lock(&sb->s_dentry_lru_lock); |
@@ -942,7 +943,8 @@ relock: | |||
942 | this_cpu_dec(nr_dentry_unused); | 943 | this_cpu_dec(nr_dentry_unused); |
943 | sb->s_nr_dentry_unused--; | 944 | sb->s_nr_dentry_unused--; |
944 | spin_unlock(&dentry->d_lock); | 945 | spin_unlock(&dentry->d_lock); |
945 | if (!--count) | 946 | freed++; |
947 | if (!--nr_to_scan) | ||
946 | break; | 948 | break; |
947 | } | 949 | } |
948 | cond_resched_lock(&sb->s_dentry_lru_lock); | 950 | cond_resched_lock(&sb->s_dentry_lru_lock); |
@@ -952,6 +954,7 @@ relock: | |||
952 | spin_unlock(&sb->s_dentry_lru_lock); | 954 | spin_unlock(&sb->s_dentry_lru_lock); |
953 | 955 | ||
954 | shrink_dentry_list(&tmp); | 956 | shrink_dentry_list(&tmp); |
957 | return freed; | ||
955 | } | 958 | } |
956 | 959 | ||
957 | /* | 960 | /* |
diff --git a/fs/inode.c b/fs/inode.c index 2a3c37ea823d..021d64768a55 100644 --- a/fs/inode.c +++ b/fs/inode.c | |||
@@ -706,10 +706,11 @@ static int can_unuse(struct inode *inode) | |||
706 | * LRU does not have strict ordering. Hence we don't want to reclaim inodes | 706 | * LRU does not have strict ordering. Hence we don't want to reclaim inodes |
707 | * with this flag set because they are the inodes that are out of order. | 707 | * with this flag set because they are the inodes that are out of order. |
708 | */ | 708 | */ |
709 | void prune_icache_sb(struct super_block *sb, int nr_to_scan) | 709 | long prune_icache_sb(struct super_block *sb, unsigned long nr_to_scan) |
710 | { | 710 | { |
711 | LIST_HEAD(freeable); | 711 | LIST_HEAD(freeable); |
712 | int nr_scanned; | 712 | long nr_scanned; |
713 | long freed = 0; | ||
713 | unsigned long reap = 0; | 714 | unsigned long reap = 0; |
714 | 715 | ||
715 | spin_lock(&sb->s_inode_lru_lock); | 716 | spin_lock(&sb->s_inode_lru_lock); |
@@ -779,6 +780,7 @@ void prune_icache_sb(struct super_block *sb, int nr_to_scan) | |||
779 | list_move(&inode->i_lru, &freeable); | 780 | list_move(&inode->i_lru, &freeable); |
780 | sb->s_nr_inodes_unused--; | 781 | sb->s_nr_inodes_unused--; |
781 | this_cpu_dec(nr_unused); | 782 | this_cpu_dec(nr_unused); |
783 | freed++; | ||
782 | } | 784 | } |
783 | if (current_is_kswapd()) | 785 | if (current_is_kswapd()) |
784 | __count_vm_events(KSWAPD_INODESTEAL, reap); | 786 | __count_vm_events(KSWAPD_INODESTEAL, reap); |
@@ -789,6 +791,7 @@ void prune_icache_sb(struct super_block *sb, int nr_to_scan) | |||
789 | current->reclaim_state->reclaimed_slab += reap; | 791 | current->reclaim_state->reclaimed_slab += reap; |
790 | 792 | ||
791 | dispose_list(&freeable); | 793 | dispose_list(&freeable); |
794 | return freed; | ||
792 | } | 795 | } |
793 | 796 | ||
794 | static void __wait_on_freeing_inode(struct inode *inode); | 797 | static void __wait_on_freeing_inode(struct inode *inode); |
diff --git a/fs/internal.h b/fs/internal.h index b6495659d6e8..cb83a3417a68 100644 --- a/fs/internal.h +++ b/fs/internal.h | |||
@@ -114,6 +114,7 @@ extern int open_check_o_direct(struct file *f); | |||
114 | * inode.c | 114 | * inode.c |
115 | */ | 115 | */ |
116 | extern spinlock_t inode_sb_list_lock; | 116 | extern spinlock_t inode_sb_list_lock; |
117 | extern long prune_icache_sb(struct super_block *sb, unsigned long nr_to_scan); | ||
117 | extern void inode_add_lru(struct inode *inode); | 118 | extern void inode_add_lru(struct inode *inode); |
118 | 119 | ||
119 | /* | 120 | /* |
@@ -130,6 +131,7 @@ extern int invalidate_inodes(struct super_block *, bool); | |||
130 | */ | 131 | */ |
131 | extern struct dentry *__d_alloc(struct super_block *, const struct qstr *); | 132 | extern struct dentry *__d_alloc(struct super_block *, const struct qstr *); |
132 | extern int d_set_mounted(struct dentry *dentry); | 133 | extern int d_set_mounted(struct dentry *dentry); |
134 | extern long prune_dcache_sb(struct super_block *sb, unsigned long nr_to_scan); | ||
133 | 135 | ||
134 | /* | 136 | /* |
135 | * read_write.c | 137 | * read_write.c |
diff --git a/fs/super.c b/fs/super.c index 3c5318694ccd..8aa2660642b9 100644 --- a/fs/super.c +++ b/fs/super.c | |||
@@ -53,11 +53,15 @@ static char *sb_writers_name[SB_FREEZE_LEVELS] = { | |||
53 | * shrinker path and that leads to deadlock on the shrinker_rwsem. Hence we | 53 | * shrinker path and that leads to deadlock on the shrinker_rwsem. Hence we |
54 | * take a passive reference to the superblock to avoid this from occurring. | 54 | * take a passive reference to the superblock to avoid this from occurring. |
55 | */ | 55 | */ |
56 | static int prune_super(struct shrinker *shrink, struct shrink_control *sc) | 56 | static unsigned long super_cache_scan(struct shrinker *shrink, |
57 | struct shrink_control *sc) | ||
57 | { | 58 | { |
58 | struct super_block *sb; | 59 | struct super_block *sb; |
59 | int fs_objects = 0; | 60 | long fs_objects = 0; |
60 | int total_objects; | 61 | long total_objects; |
62 | long freed = 0; | ||
63 | long dentries; | ||
64 | long inodes; | ||
61 | 65 | ||
62 | sb = container_of(shrink, struct super_block, s_shrink); | 66 | sb = container_of(shrink, struct super_block, s_shrink); |
63 | 67 | ||
@@ -65,11 +69,11 @@ static int prune_super(struct shrinker *shrink, struct shrink_control *sc) | |||
65 | * Deadlock avoidance. We may hold various FS locks, and we don't want | 69 | * Deadlock avoidance. We may hold various FS locks, and we don't want |
66 | * to recurse into the FS that called us in clear_inode() and friends.. | 70 | * to recurse into the FS that called us in clear_inode() and friends.. |
67 | */ | 71 | */ |
68 | if (sc->nr_to_scan && !(sc->gfp_mask & __GFP_FS)) | 72 | if (!(sc->gfp_mask & __GFP_FS)) |
69 | return -1; | 73 | return SHRINK_STOP; |
70 | 74 | ||
71 | if (!grab_super_passive(sb)) | 75 | if (!grab_super_passive(sb)) |
72 | return -1; | 76 | return SHRINK_STOP; |
73 | 77 | ||
74 | if (sb->s_op->nr_cached_objects) | 78 | if (sb->s_op->nr_cached_objects) |
75 | fs_objects = sb->s_op->nr_cached_objects(sb); | 79 | fs_objects = sb->s_op->nr_cached_objects(sb); |
@@ -77,33 +81,46 @@ static int prune_super(struct shrinker *shrink, struct shrink_control *sc) | |||
77 | total_objects = sb->s_nr_dentry_unused + | 81 | total_objects = sb->s_nr_dentry_unused + |
78 | sb->s_nr_inodes_unused + fs_objects + 1; | 82 | sb->s_nr_inodes_unused + fs_objects + 1; |
79 | 83 | ||
80 | if (sc->nr_to_scan) { | 84 | /* proportion the scan between the caches */ |
81 | int dentries; | 85 | dentries = mult_frac(sc->nr_to_scan, sb->s_nr_dentry_unused, |
82 | int inodes; | 86 | total_objects); |
83 | 87 | inodes = mult_frac(sc->nr_to_scan, sb->s_nr_inodes_unused, | |
84 | /* proportion the scan between the caches */ | 88 | total_objects); |
85 | dentries = mult_frac(sc->nr_to_scan, sb->s_nr_dentry_unused, | ||
86 | total_objects); | ||
87 | inodes = mult_frac(sc->nr_to_scan, sb->s_nr_inodes_unused, | ||
88 | total_objects); | ||
89 | if (fs_objects) | ||
90 | fs_objects = mult_frac(sc->nr_to_scan, fs_objects, | ||
91 | total_objects); | ||
92 | /* | ||
93 | * prune the dcache first as the icache is pinned by it, then | ||
94 | * prune the icache, followed by the filesystem specific caches | ||
95 | */ | ||
96 | prune_dcache_sb(sb, dentries); | ||
97 | prune_icache_sb(sb, inodes); | ||
98 | 89 | ||
99 | if (fs_objects && sb->s_op->free_cached_objects) { | 90 | /* |
100 | sb->s_op->free_cached_objects(sb, fs_objects); | 91 | * prune the dcache first as the icache is pinned by it, then |
101 | fs_objects = sb->s_op->nr_cached_objects(sb); | 92 | * prune the icache, followed by the filesystem specific caches |
102 | } | 93 | */ |
103 | total_objects = sb->s_nr_dentry_unused + | 94 | freed = prune_dcache_sb(sb, dentries); |
104 | sb->s_nr_inodes_unused + fs_objects; | 95 | freed += prune_icache_sb(sb, inodes); |
96 | |||
97 | if (fs_objects) { | ||
98 | fs_objects = mult_frac(sc->nr_to_scan, fs_objects, | ||
99 | total_objects); | ||
100 | freed += sb->s_op->free_cached_objects(sb, fs_objects); | ||
105 | } | 101 | } |
106 | 102 | ||
103 | drop_super(sb); | ||
104 | return freed; | ||
105 | } | ||
106 | |||
107 | static unsigned long super_cache_count(struct shrinker *shrink, | ||
108 | struct shrink_control *sc) | ||
109 | { | ||
110 | struct super_block *sb; | ||
111 | long total_objects = 0; | ||
112 | |||
113 | sb = container_of(shrink, struct super_block, s_shrink); | ||
114 | |||
115 | if (!grab_super_passive(sb)) | ||
116 | return 0; | ||
117 | |||
118 | if (sb->s_op && sb->s_op->nr_cached_objects) | ||
119 | total_objects = sb->s_op->nr_cached_objects(sb); | ||
120 | |||
121 | total_objects += sb->s_nr_dentry_unused; | ||
122 | total_objects += sb->s_nr_inodes_unused; | ||
123 | |||
107 | total_objects = vfs_pressure_ratio(total_objects); | 124 | total_objects = vfs_pressure_ratio(total_objects); |
108 | drop_super(sb); | 125 | drop_super(sb); |
109 | return total_objects; | 126 | return total_objects; |
@@ -211,7 +228,8 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags) | |||
211 | s->cleancache_poolid = -1; | 228 | s->cleancache_poolid = -1; |
212 | 229 | ||
213 | s->s_shrink.seeks = DEFAULT_SEEKS; | 230 | s->s_shrink.seeks = DEFAULT_SEEKS; |
214 | s->s_shrink.shrink = prune_super; | 231 | s->s_shrink.scan_objects = super_cache_scan; |
232 | s->s_shrink.count_objects = super_cache_count; | ||
215 | s->s_shrink.batch = 1024; | 233 | s->s_shrink.batch = 1024; |
216 | } | 234 | } |
217 | out: | 235 | out: |
diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c index 16219b9c6790..73b62a24ceac 100644 --- a/fs/xfs/xfs_icache.c +++ b/fs/xfs/xfs_icache.c | |||
@@ -1167,7 +1167,7 @@ xfs_reclaim_inodes( | |||
1167 | * them to be cleaned, which we hope will not be very long due to the | 1167 | * them to be cleaned, which we hope will not be very long due to the |
1168 | * background walker having already kicked the IO off on those dirty inodes. | 1168 | * background walker having already kicked the IO off on those dirty inodes. |
1169 | */ | 1169 | */ |
1170 | void | 1170 | long |
1171 | xfs_reclaim_inodes_nr( | 1171 | xfs_reclaim_inodes_nr( |
1172 | struct xfs_mount *mp, | 1172 | struct xfs_mount *mp, |
1173 | int nr_to_scan) | 1173 | int nr_to_scan) |
@@ -1176,7 +1176,7 @@ xfs_reclaim_inodes_nr( | |||
1176 | xfs_reclaim_work_queue(mp); | 1176 | xfs_reclaim_work_queue(mp); |
1177 | xfs_ail_push_all(mp->m_ail); | 1177 | xfs_ail_push_all(mp->m_ail); |
1178 | 1178 | ||
1179 | xfs_reclaim_inodes_ag(mp, SYNC_TRYLOCK | SYNC_WAIT, &nr_to_scan); | 1179 | return xfs_reclaim_inodes_ag(mp, SYNC_TRYLOCK | SYNC_WAIT, &nr_to_scan); |
1180 | } | 1180 | } |
1181 | 1181 | ||
1182 | /* | 1182 | /* |
diff --git a/fs/xfs/xfs_icache.h b/fs/xfs/xfs_icache.h index 8a89f7d791bd..456f0144e1b6 100644 --- a/fs/xfs/xfs_icache.h +++ b/fs/xfs/xfs_icache.h | |||
@@ -46,7 +46,7 @@ void xfs_reclaim_worker(struct work_struct *work); | |||
46 | 46 | ||
47 | int xfs_reclaim_inodes(struct xfs_mount *mp, int mode); | 47 | int xfs_reclaim_inodes(struct xfs_mount *mp, int mode); |
48 | int xfs_reclaim_inodes_count(struct xfs_mount *mp); | 48 | int xfs_reclaim_inodes_count(struct xfs_mount *mp); |
49 | void xfs_reclaim_inodes_nr(struct xfs_mount *mp, int nr_to_scan); | 49 | long xfs_reclaim_inodes_nr(struct xfs_mount *mp, int nr_to_scan); |
50 | 50 | ||
51 | void xfs_inode_set_reclaim_tag(struct xfs_inode *ip); | 51 | void xfs_inode_set_reclaim_tag(struct xfs_inode *ip); |
52 | 52 | ||
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index 979a77d4b87d..71d7aaebb912 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c | |||
@@ -1535,19 +1535,19 @@ xfs_fs_mount( | |||
1535 | return mount_bdev(fs_type, flags, dev_name, data, xfs_fs_fill_super); | 1535 | return mount_bdev(fs_type, flags, dev_name, data, xfs_fs_fill_super); |
1536 | } | 1536 | } |
1537 | 1537 | ||
1538 | static int | 1538 | static long |
1539 | xfs_fs_nr_cached_objects( | 1539 | xfs_fs_nr_cached_objects( |
1540 | struct super_block *sb) | 1540 | struct super_block *sb) |
1541 | { | 1541 | { |
1542 | return xfs_reclaim_inodes_count(XFS_M(sb)); | 1542 | return xfs_reclaim_inodes_count(XFS_M(sb)); |
1543 | } | 1543 | } |
1544 | 1544 | ||
1545 | static void | 1545 | static long |
1546 | xfs_fs_free_cached_objects( | 1546 | xfs_fs_free_cached_objects( |
1547 | struct super_block *sb, | 1547 | struct super_block *sb, |
1548 | int nr_to_scan) | 1548 | long nr_to_scan) |
1549 | { | 1549 | { |
1550 | xfs_reclaim_inodes_nr(XFS_M(sb), nr_to_scan); | 1550 | return xfs_reclaim_inodes_nr(XFS_M(sb), nr_to_scan); |
1551 | } | 1551 | } |
1552 | 1552 | ||
1553 | static const struct super_operations xfs_super_operations = { | 1553 | static const struct super_operations xfs_super_operations = { |