From ca2f88381ca96b76af4fff578c5c3fd29190474d Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Fri, 19 Jul 2013 09:59:51 +1000 Subject: super: fix calculation of shrinkable objects for small numbers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sysctl knob sysctl_vfs_cache_pressure is used to determine which percentage of the shrinkable objects in our cache we should actively try to shrink. It works great in situations in which we have many objects (at least more than 100), because the aproximation errors will be negligible. But if this is not the case, specially when total_objects < 100, we may end up concluding that we have no objects at all (total / 100 = 0, if total < 100). This is certainly not the biggest killer in the world, but may matter in very low kernel memory situations. Signed-off-by: Glauber Costa Reviewed-by: Carlos Maiolino Acked-by: KAMEZAWA Hiroyuki Acked-by: Mel Gorman Cc: Dave Chinner Cc: Al Viro Cc: "Theodore Ts'o" Cc: Adrian Hunter Cc: Al Viro Cc: Artem Bityutskiy Cc: Arve Hjønnevåg Cc: Carlos Maiolino Cc: Christoph Hellwig Cc: Chuck Lever Cc: Daniel Vetter Cc: David Rientjes Cc: Gleb Natapov Cc: Greg Thelen Cc: J. Bruce Fields Cc: Jan Kara Cc: Jerome Glisse Cc: John Stultz Cc: KAMEZAWA Hiroyuki Cc: Kent Overstreet Cc: Kirill A. Shutemov Cc: Marcelo Tosatti Cc: Mel Gorman Cc: Steven Whitehouse Cc: Thomas Hellstrom Cc: Trond Myklebust Signed-off-by: Andrew Morton --- fs/gfs2/glock.c | 2 +- fs/gfs2/quota.c | 2 +- fs/mbcache.c | 2 +- fs/nfs/dir.c | 2 +- fs/quota/dquot.c | 5 ++--- fs/super.c | 14 +++++++------- fs/xfs/xfs_qm.c | 2 +- include/linux/dcache.h | 4 ++++ 8 files changed, 18 insertions(+), 15 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 9435384562a2..3bd27480ac56 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -1463,7 +1463,7 @@ static int gfs2_shrink_glock_memory(struct shrinker *shrink, gfs2_scan_glock_lru(sc->nr_to_scan); } - return (atomic_read(&lru_count) / 100) * sysctl_vfs_cache_pressure; + return vfs_pressure_ratio(atomic_read(&lru_count)); } static struct shrinker glock_shrinker = { diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 3768c2f40e43..d550a5d6a05f 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -114,7 +114,7 @@ int gfs2_shrink_qd_memory(struct shrinker *shrink, struct shrink_control *sc) spin_unlock(&qd_lru_lock); out: - return (atomic_read(&qd_lru_count) * sysctl_vfs_cache_pressure) / 100; + return vfs_pressure_ratio(atomic_read(&qd_lru_count)); } static u64 qd2index(struct gfs2_quota_data *qd) diff --git a/fs/mbcache.c b/fs/mbcache.c index 8c32ef3ba88e..5eb04767cb29 100644 --- a/fs/mbcache.c +++ b/fs/mbcache.c @@ -189,7 +189,7 @@ mb_cache_shrink_fn(struct shrinker *shrink, struct shrink_control *sc) list_for_each_entry_safe(entry, tmp, &free_list, e_lru_list) { __mb_cache_entry_forget(entry, gfp_mask); } - return (count / 100) * sysctl_vfs_cache_pressure; + return vfs_pressure_ratio(count); } diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index e474ca2b2bfe..d6d6fd364b47 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -2005,7 +2005,7 @@ remove_lru_entry: } spin_unlock(&nfs_access_lru_lock); nfs_access_free_list(&head); - return (atomic_long_read(&nfs_access_nr_entries) / 100) * sysctl_vfs_cache_pressure; + return vfs_pressure_ratio(atomic_long_read(&nfs_access_nr_entries)); } static void __nfs_access_zap_cache(struct nfs_inode *nfsi, struct list_head *head) diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index fbad622841f9..1f9ef62047f3 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -719,9 +719,8 @@ static int shrink_dqcache_memory(struct shrinker *shrink, prune_dqcache(nr); spin_unlock(&dq_list_lock); } - return ((unsigned) - percpu_counter_read_positive(&dqstats.counter[DQST_FREE_DQUOTS]) - /100) * sysctl_vfs_cache_pressure; + return vfs_pressure_ratio( + percpu_counter_read_positive(&dqstats.counter[DQST_FREE_DQUOTS])); } static struct shrinker dqcache_shrinker = { diff --git a/fs/super.c b/fs/super.c index 7465d4364208..2a37fd618ac2 100644 --- a/fs/super.c +++ b/fs/super.c @@ -82,13 +82,13 @@ static int prune_super(struct shrinker *shrink, struct shrink_control *sc) int inodes; /* proportion the scan between the caches */ - dentries = (sc->nr_to_scan * sb->s_nr_dentry_unused) / - total_objects; - inodes = (sc->nr_to_scan * sb->s_nr_inodes_unused) / - total_objects; + dentries = mult_frac(sc->nr_to_scan, sb->s_nr_dentry_unused, + total_objects); + inodes = mult_frac(sc->nr_to_scan, sb->s_nr_inodes_unused, + total_objects); if (fs_objects) - fs_objects = (sc->nr_to_scan * fs_objects) / - total_objects; + fs_objects = mult_frac(sc->nr_to_scan, fs_objects, + total_objects); /* * prune the dcache first as the icache is pinned by it, then * prune the icache, followed by the filesystem specific caches @@ -104,7 +104,7 @@ static int prune_super(struct shrinker *shrink, struct shrink_control *sc) sb->s_nr_inodes_unused + fs_objects; } - total_objects = (total_objects / 100) * sysctl_vfs_cache_pressure; + total_objects = vfs_pressure_ratio(total_objects); drop_super(sb); return total_objects; } diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c index d320794d03ce..51209a3ea250 100644 --- a/fs/xfs/xfs_qm.c +++ b/fs/xfs/xfs_qm.c @@ -1688,7 +1688,7 @@ xfs_qm_shake( } out: - return (qi->qi_lru_count / 100) * sysctl_vfs_cache_pressure; + return vfs_pressure_ratio(qi->qi_lru_count); } /* diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 9def33ebb9f3..63992db3bd40 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -415,4 +415,8 @@ static inline bool d_mountpoint(struct dentry *dentry) extern int sysctl_vfs_cache_pressure; +static inline unsigned long vfs_pressure_ratio(unsigned long val) +{ + return mult_frac(val, sysctl_vfs_cache_pressure, 100); +} #endif /* __LINUX_DCACHE_H */ -- cgit v1.2.3