Hi, On Tue, 2011-08-23 at 18:56 +1000, Dave Chinner wrote: > From: Dave Chinner <dchinner@xxxxxxxxxx> > > Modify shrink_slab() to use the new .count_objects/.scan_objects API > and implement the callouts for all the existing shrinkers. > > Signed-off-by: Dave Chinner <dchinner@xxxxxxxxxx> GFS2 bits: Acked-by: Steven Whitehouse <swhiteho@xxxxxxxxxx> Looks good to me, Steve. > --- > Documentation/filesystems/vfs.txt | 11 +++-- > arch/x86/kvm/mmu.c | 16 ++++--- > drivers/gpu/drm/i915/i915_dma.c | 4 +- > drivers/gpu/drm/i915/i915_gem.c | 49 ++++++++++++++--------- > drivers/gpu/drm/ttm/ttm_page_alloc.c | 14 ++++-- > drivers/staging/zcache/zcache-main.c | 45 ++++++++++++--------- > fs/cifs/cifsacl.c | 57 +++++++++++++++++---------- > fs/dcache.c | 15 ++++--- > fs/gfs2/glock.c | 24 +++++++----- > fs/gfs2/main.c | 3 +- > fs/gfs2/quota.c | 19 +++++---- > fs/gfs2/quota.h | 4 +- > fs/inode.c | 7 ++- > fs/internal.h | 3 + > fs/mbcache.c | 37 +++++++++++------ > fs/nfs/dir.c | 17 ++++++-- > fs/nfs/internal.h | 6 ++- > fs/nfs/super.c | 3 +- > fs/quota/dquot.c | 39 +++++++++---------- > fs/super.c | 71 ++++++++++++++++++++-------------- > fs/ubifs/shrinker.c | 19 +++++---- > fs/ubifs/super.c | 3 +- > fs/ubifs/ubifs.h | 3 +- > fs/xfs/xfs_buf.c | 19 ++++++++- > fs/xfs/xfs_qm.c | 22 +++++++--- > fs/xfs/xfs_super.c | 8 ++-- > fs/xfs/xfs_sync.c | 17 +++++--- > fs/xfs/xfs_sync.h | 4 +- > include/linux/fs.h | 8 +--- > include/trace/events/vmscan.h | 12 +++--- > mm/vmscan.c | 46 +++++++++------------- > net/sunrpc/auth.c | 21 +++++++--- > 32 files changed, 369 insertions(+), 257 deletions(-) > > diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt > index 52d8fb8..4ca3c2d 100644 > --- a/Documentation/filesystems/vfs.txt > +++ b/Documentation/filesystems/vfs.txt > @@ -229,8 +229,8 @@ struct super_operations { > > ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t); > ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t); > - int (*nr_cached_objects)(struct super_block *); > - void (*free_cached_objects)(struct super_block *, int); > + long (*nr_cached_objects)(struct super_block *); > + long (*free_cached_objects)(struct super_block *, long); > }; > > All methods are called without any locks being held, unless otherwise > @@ -313,9 +313,10 @@ or bottom half). > implement ->nr_cached_objects for it to be called correctly. > > We can't do anything with any errors that the filesystem might > - encountered, hence the void return type. This will never be called if > - the VM is trying to reclaim under GFP_NOFS conditions, hence this > - method does not need to handle that situation itself. > + encountered, so the return value is the number of objects freed. This > + will never be called if the VM is trying to reclaim under GFP_NOFS > + conditions, hence this method does not need to handle that situation > + itself. > > Implementations must include conditional reschedule calls inside any > scanning loop that is done. This allows the VFS to determine > diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c > index 1c5b693..939e201 100644 > --- a/arch/x86/kvm/mmu.c > +++ b/arch/x86/kvm/mmu.c > @@ -3858,14 +3858,12 @@ static int kvm_mmu_remove_some_alloc_mmu_pages(struct kvm *kvm, > return kvm_mmu_prepare_zap_page(kvm, page, invalid_list); > } > > -static int mmu_shrink(struct shrinker *shrink, struct shrink_control *sc) > +static long mmu_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) > { > struct kvm *kvm; > struct kvm *kvm_freed = NULL; > int nr_to_scan = sc->nr_to_scan; > - > - if (nr_to_scan == 0) > - goto out; > + long freed_pages = 0; > > raw_spin_lock(&kvm_lock); > > @@ -3877,7 +3875,7 @@ static int mmu_shrink(struct shrinker *shrink, struct shrink_control *sc) > spin_lock(&kvm->mmu_lock); > if (!kvm_freed && nr_to_scan > 0 && > kvm->arch.n_used_mmu_pages > 0) { > - freed_pages = kvm_mmu_remove_some_alloc_mmu_pages(kvm, > + freed_pages += kvm_mmu_remove_some_alloc_mmu_pages(kvm, > &invalid_list); > kvm_freed = kvm; > } > @@ -3891,13 +3889,17 @@ static int mmu_shrink(struct shrinker *shrink, struct shrink_control *sc) > list_move_tail(&kvm_freed->vm_list, &vm_list); > > raw_spin_unlock(&kvm_lock); > + return freed_pages; > +} > > -out: > +static long mmu_shrink_count(struct shrinker *shrink, struct shrink_control *sc) > +{ > return percpu_counter_read_positive(&kvm_total_used_mmu_pages); > } > > static struct shrinker mmu_shrinker = { > - .shrink = mmu_shrink, > + .scan_objects = mmu_shrink_scan, > + .count_objects = mmu_shrink_count, > .seeks = DEFAULT_SEEKS * 10, > }; > > diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c > index 8a3942c..734ea5e 100644 > --- a/drivers/gpu/drm/i915/i915_dma.c > +++ b/drivers/gpu/drm/i915/i915_dma.c > @@ -2074,7 +2074,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) > return 0; > > out_gem_unload: > - if (dev_priv->mm.inactive_shrinker.shrink) > + if (dev_priv->mm.inactive_shrinker.scan_objects) > unregister_shrinker(&dev_priv->mm.inactive_shrinker); > > if (dev->pdev->msi_enabled) > @@ -2108,7 +2108,7 @@ int i915_driver_unload(struct drm_device *dev) > i915_mch_dev = NULL; > spin_unlock(&mchdev_lock); > > - if (dev_priv->mm.inactive_shrinker.shrink) > + if (dev_priv->mm.inactive_shrinker.scan_objects) > unregister_shrinker(&dev_priv->mm.inactive_shrinker); > > mutex_lock(&dev->struct_mutex); > diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c > index a546a71..0647a33 100644 > --- a/drivers/gpu/drm/i915/i915_gem.c > +++ b/drivers/gpu/drm/i915/i915_gem.c > @@ -56,7 +56,9 @@ static int i915_gem_phys_pwrite(struct drm_device *dev, > struct drm_file *file); > static void i915_gem_free_object_tail(struct drm_i915_gem_object *obj); > > -static int i915_gem_inactive_shrink(struct shrinker *shrinker, > +static long i915_gem_inactive_scan(struct shrinker *shrinker, > + struct shrink_control *sc); > +static long i915_gem_inactive_count(struct shrinker *shrinker, > struct shrink_control *sc); > > /* some bookkeeping */ > @@ -3999,7 +4001,8 @@ i915_gem_load(struct drm_device *dev) > > dev_priv->mm.interruptible = true; > > - dev_priv->mm.inactive_shrinker.shrink = i915_gem_inactive_shrink; > + dev_priv->mm.inactive_shrinker.scan_objects = i915_gem_inactive_scan; > + dev_priv->mm.inactive_shrinker.count_objects = i915_gem_inactive_count; > dev_priv->mm.inactive_shrinker.seeks = DEFAULT_SEEKS; > register_shrinker(&dev_priv->mm.inactive_shrinker); > } > @@ -4221,8 +4224,8 @@ i915_gpu_is_active(struct drm_device *dev) > return !lists_empty; > } > > -static int > -i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc) > +static long > +i915_gem_inactive_scan(struct shrinker *shrinker, struct shrink_control *sc) > { > struct drm_i915_private *dev_priv = > container_of(shrinker, > @@ -4231,22 +4234,10 @@ i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc) > struct drm_device *dev = dev_priv->dev; > struct drm_i915_gem_object *obj, *next; > int nr_to_scan = sc->nr_to_scan; > - int cnt; > > if (!mutex_trylock(&dev->struct_mutex)) > return 0; > > - /* "fast-path" to count number of available objects */ > - if (nr_to_scan == 0) { > - cnt = 0; > - list_for_each_entry(obj, > - &dev_priv->mm.inactive_list, > - mm_list) > - cnt++; > - mutex_unlock(&dev->struct_mutex); > - return cnt / 100 * sysctl_vfs_cache_pressure; > - } > - > rescan: > /* first scan for clean buffers */ > i915_gem_retire_requests(dev); > @@ -4262,15 +4253,12 @@ rescan: > } > > /* second pass, evict/count anything still on the inactive list */ > - cnt = 0; > list_for_each_entry_safe(obj, next, > &dev_priv->mm.inactive_list, > mm_list) { > if (nr_to_scan && > i915_gem_object_unbind(obj) == 0) > nr_to_scan--; > - else > - cnt++; > } > > if (nr_to_scan && i915_gpu_is_active(dev)) { > @@ -4284,5 +4272,26 @@ rescan: > goto rescan; > } > mutex_unlock(&dev->struct_mutex); > - return cnt / 100 * sysctl_vfs_cache_pressure; > + return sc->nr_to_scan - nr_to_scan; > +} > + > +static long > +i915_gem_inactive_count(struct shrinker *shrinker, struct shrink_control *sc) > +{ > + struct drm_i915_private *dev_priv = > + container_of(shrinker, > + struct drm_i915_private, > + mm.inactive_shrinker); > + struct drm_device *dev = dev_priv->dev; > + struct drm_i915_gem_object *obj; > + long count = 0; > + > + if (!mutex_trylock(&dev->struct_mutex)) > + return 0; > + > + list_for_each_entry(obj, &dev_priv->mm.inactive_list, mm_list) > + count++; > + > + mutex_unlock(&dev->struct_mutex); > + return count; > } > diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c b/drivers/gpu/drm/ttm/ttm_page_alloc.c > index 727e93d..3e71c68 100644 > --- a/drivers/gpu/drm/ttm/ttm_page_alloc.c > +++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c > @@ -395,14 +395,13 @@ static int ttm_pool_get_num_unused_pages(void) > /** > * Callback for mm to request pool to reduce number of page held. > */ > -static int ttm_pool_mm_shrink(struct shrinker *shrink, > - struct shrink_control *sc) > +static long ttm_pool_mm_scan(struct shrinker *shrink, struct shrink_control *sc) > { > static atomic_t start_pool = ATOMIC_INIT(0); > unsigned i; > unsigned pool_offset = atomic_add_return(1, &start_pool); > struct ttm_page_pool *pool; > - int shrink_pages = sc->nr_to_scan; > + long shrink_pages = sc->nr_to_scan; > > pool_offset = pool_offset % NUM_POOLS; > /* select start pool in round robin fashion */ > @@ -413,13 +412,18 @@ static int ttm_pool_mm_shrink(struct shrinker *shrink, > pool = &_manager->pools[(i + pool_offset)%NUM_POOLS]; > shrink_pages = ttm_page_pool_free(pool, nr_free); > } > - /* return estimated number of unused pages in pool */ > + return sc->nr_to_scan; > +} > + > +static long ttm_pool_mm_count(struct shrinker *shrink, struct shrink_control *sc) > +{ > return ttm_pool_get_num_unused_pages(); > } > > static void ttm_pool_mm_shrink_init(struct ttm_pool_manager *manager) > { > - manager->mm_shrink.shrink = &ttm_pool_mm_shrink; > + manager->mm_shrink.scan_objects = ttm_pool_mm_scan; > + manager->mm_shrink.count_objects = ttm_pool_mm_count; > manager->mm_shrink.seeks = 1; > register_shrinker(&manager->mm_shrink); > } > diff --git a/drivers/staging/zcache/zcache-main.c b/drivers/staging/zcache/zcache-main.c > index 855a5bb..3ccb723 100644 > --- a/drivers/staging/zcache/zcache-main.c > +++ b/drivers/staging/zcache/zcache-main.c > @@ -493,9 +493,10 @@ static void zbud_evict_zbpg(struct zbud_page *zbpg) > * page in use by another cpu, but also to avoid potential deadlock due to > * lock inversion. > */ > -static void zbud_evict_pages(int nr) > +static int zbud_evict_pages(int nr) > { > struct zbud_page *zbpg; > + int freed = 0; > int i; > > /* first try freeing any pages on unused list */ > @@ -511,7 +512,7 @@ retry_unused_list: > spin_unlock_bh(&zbpg_unused_list_spinlock); > zcache_free_page(zbpg); > zcache_evicted_raw_pages++; > - if (--nr <= 0) > + if (++freed >= nr) > goto out; > goto retry_unused_list; > } > @@ -535,7 +536,7 @@ retry_unbud_list_i: > /* want budlists unlocked when doing zbpg eviction */ > zbud_evict_zbpg(zbpg); > local_bh_enable(); > - if (--nr <= 0) > + if (++freed >= nr) > goto out; > goto retry_unbud_list_i; > } > @@ -559,13 +560,13 @@ retry_bud_list: > /* want budlists unlocked when doing zbpg eviction */ > zbud_evict_zbpg(zbpg); > local_bh_enable(); > - if (--nr <= 0) > + if (++freed >= nr) > goto out; > goto retry_bud_list; > } > spin_unlock_bh(&zbud_budlists_spinlock); > out: > - return; > + return freed; > } > > static void zbud_init(void) > @@ -1496,30 +1497,34 @@ static bool zcache_freeze; > /* > * zcache shrinker interface (only useful for ephemeral pages, so zbud only) > */ > -static int shrink_zcache_memory(struct shrinker *shrink, > - struct shrink_control *sc) > +static long shrink_zcache_scan(struct shrinker *shrink, > + struct shrink_control *sc) > { > int ret = -1; > int nr = sc->nr_to_scan; > gfp_t gfp_mask = sc->gfp_mask; > > - if (nr >= 0) { > - if (!(gfp_mask & __GFP_FS)) > - /* does this case really need to be skipped? */ > - goto out; > - if (spin_trylock(&zcache_direct_reclaim_lock)) { > - zbud_evict_pages(nr); > - spin_unlock(&zcache_direct_reclaim_lock); > - } else > - zcache_aborted_shrink++; > - } > - ret = (int)atomic_read(&zcache_zbud_curr_raw_pages); > -out: > + if (!(gfp_mask & __GFP_FS)) > + return -1; > + > + if (spin_trylock(&zcache_direct_reclaim_lock)) { > + ret = zbud_evict_pages(nr); > + spin_unlock(&zcache_direct_reclaim_lock); > + } else > + zcache_aborted_shrink++; > + > return ret; > } > > +static long shrink_zcache_count(struct shrinker *shrink, > + struct shrink_control *sc) > +{ > + return atomic_read(&zcache_zbud_curr_raw_pages); > +} > + > static struct shrinker zcache_shrinker = { > - .shrink = shrink_zcache_memory, > + .scan_objects = shrink_zcache_scan, > + .count_objects = shrink_zcache_count, > .seeks = DEFAULT_SEEKS, > }; > > diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c > index d0f59fa..508a684 100644 > --- a/fs/cifs/cifsacl.c > +++ b/fs/cifs/cifsacl.c > @@ -44,58 +44,73 @@ static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} }; > > const struct cred *root_cred; > > -static void > -shrink_idmap_tree(struct rb_root *root, int nr_to_scan, int *nr_rem, > - int *nr_del) > +static long > +shrink_idmap_tree(struct rb_root *root, int nr_to_scan) > { > struct rb_node *node; > struct rb_node *tmp; > struct cifs_sid_id *psidid; > + long count = 0; > > node = rb_first(root); > while (node) { > tmp = node; > node = rb_next(tmp); > psidid = rb_entry(tmp, struct cifs_sid_id, rbnode); > - if (nr_to_scan == 0 || *nr_del == nr_to_scan) > - ++(*nr_rem); > - else { > - if (time_after(jiffies, psidid->time + SID_MAP_EXPIRE) > - && psidid->refcount == 0) { > - rb_erase(tmp, root); > - ++(*nr_del); > - } else > - ++(*nr_rem); > + if (nr_to_scan == 0) { > + count++; > + continue: > + } > + if (time_after(jiffies, psidid->time + SID_MAP_EXPIRE) > + && psidid->refcount == 0) { > + rb_erase(tmp, root); > + if (++count >= nr_to_scan) > + break; > } > } > + return count; > } > > /* > * Run idmap cache shrinker. > */ > -static int > -cifs_idmap_shrinker(struct shrinker *shrink, struct shrink_control *sc) > +static long > +cifs_idmap_shrinker_scan(struct shrinker *shrink, struct shrink_control *sc) > { > - int nr_to_scan = sc->nr_to_scan; > - int nr_del = 0; > - int nr_rem = 0; > struct rb_root *root; > + long freed; > > root = &uidtree; > spin_lock(&siduidlock); > - shrink_idmap_tree(root, nr_to_scan, &nr_rem, &nr_del); > + freed = shrink_idmap_tree(root, sc->nr_to_scan); > spin_unlock(&siduidlock); > > root = &gidtree; > spin_lock(&sidgidlock); > - shrink_idmap_tree(root, nr_to_scan, &nr_rem, &nr_del); > + freed += shrink_idmap_tree(root, sc->nr_to_scan); > spin_unlock(&sidgidlock); > > - return nr_rem; > + return freed; > +} > + > +/* > + * This still abuses the nr_to_scan == 0 trick to get the common code just to > + * count objects. There neds to be an external count of the objects in the > + * caches to avoid this. > + */ > +static long > +cifs_idmap_shrinker_count(struct shrinker *shrink, struct shrink_control *sc) > +{ > + struct shrinker_control sc = { > + .nr_to_scan = 0, > + } > + > + return cifs_idmap_shrinker_scan(shrink, &sc); > } > > static struct shrinker cifs_shrinker = { > - .shrink = cifs_idmap_shrinker, > + .scan_objects = cifs_idmap_shrinker_scan, > + .count_objects = cifs_idmap_shrinker_count, > .seeks = DEFAULT_SEEKS, > }; > > diff --git a/fs/dcache.c b/fs/dcache.c > index 5123d71..d19e453 100644 > --- a/fs/dcache.c > +++ b/fs/dcache.c > @@ -759,11 +759,12 @@ static void shrink_dentry_list(struct list_head *list) > * > * If flags contains DCACHE_REFERENCED reference dentries will not be pruned. > */ > -static void __shrink_dcache_sb(struct super_block *sb, int count, int flags) > +static long __shrink_dcache_sb(struct super_block *sb, long count, int flags) > { > struct dentry *dentry; > LIST_HEAD(referenced); > LIST_HEAD(tmp); > + long freed = 0; > > relock: > spin_lock(&sb->s_dentry_lru_lock); > @@ -791,6 +792,7 @@ relock: > } else { > list_move_tail(&dentry->d_lru, &tmp); > spin_unlock(&dentry->d_lock); > + freed++; > if (!--count) > break; > } > @@ -801,6 +803,7 @@ relock: > spin_unlock(&sb->s_dentry_lru_lock); > > shrink_dentry_list(&tmp); > + return freed; > } > > /** > @@ -815,9 +818,9 @@ relock: > * This function may fail to free any resources if all the dentries are in > * use. > */ > -void prune_dcache_sb(struct super_block *sb, int nr_to_scan) > +long prune_dcache_sb(struct super_block *sb, long nr_to_scan) > { > - __shrink_dcache_sb(sb, nr_to_scan, DCACHE_REFERENCED); > + return __shrink_dcache_sb(sb, nr_to_scan, DCACHE_REFERENCED); > } > > /** > @@ -1070,12 +1073,12 @@ EXPORT_SYMBOL(have_submounts); > * drop the lock and return early due to latency > * constraints. > */ > -static int select_parent(struct dentry * parent) > +static long select_parent(struct dentry * parent) > { > struct dentry *this_parent; > struct list_head *next; > unsigned seq; > - int found = 0; > + long found = 0; > int locked = 0; > > seq = read_seqbegin(&rename_lock); > @@ -1163,7 +1166,7 @@ rename_retry: > void shrink_dcache_parent(struct dentry * parent) > { > struct super_block *sb = parent->d_sb; > - int found; > + long found; > > while ((found = select_parent(parent)) != 0) > __shrink_dcache_sb(sb, found, 0); > diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c > index 88e8a23..f9bc88d 100644 > --- a/fs/gfs2/glock.c > +++ b/fs/gfs2/glock.c > @@ -1370,24 +1370,21 @@ void gfs2_glock_complete(struct gfs2_glock *gl, int ret) > } > > > -static int gfs2_shrink_glock_memory(struct shrinker *shrink, > - struct shrink_control *sc) > +static long gfs2_shrink_glock_scan(struct shrinker *shrink, > + struct shrink_control *sc) > { > struct gfs2_glock *gl; > int may_demote; > int nr_skipped = 0; > - int nr = sc->nr_to_scan; > + int freed = 0; > gfp_t gfp_mask = sc->gfp_mask; > LIST_HEAD(skipped); > > - if (nr == 0) > - goto out; > - > if (!(gfp_mask & __GFP_FS)) > return -1; > > spin_lock(&lru_lock); > - while(nr && !list_empty(&lru_list)) { > + while (freed < sc->nr_to_scan && !list_empty(&lru_list)) { > gl = list_entry(lru_list.next, struct gfs2_glock, gl_lru); > list_del_init(&gl->gl_lru); > clear_bit(GLF_LRU, &gl->gl_flags); > @@ -1401,7 +1398,7 @@ static int gfs2_shrink_glock_memory(struct shrinker *shrink, > may_demote = demote_ok(gl); > if (may_demote) { > handle_callback(gl, LM_ST_UNLOCKED, 0); > - nr--; > + freed++; > } > clear_bit(GLF_LOCK, &gl->gl_flags); > smp_mb__after_clear_bit(); > @@ -1418,12 +1415,19 @@ static int gfs2_shrink_glock_memory(struct shrinker *shrink, > list_splice(&skipped, &lru_list); > atomic_add(nr_skipped, &lru_count); > spin_unlock(&lru_lock); > -out: > + > + return freed; > +} > + > +static long gfs2_shrink_glock_count(struct shrinker *shrink, > + struct shrink_control *sc) > +{ > return (atomic_read(&lru_count) / 100) * sysctl_vfs_cache_pressure; > } > > static struct shrinker glock_shrinker = { > - .shrink = gfs2_shrink_glock_memory, > + .scan_objects = gfs2_shrink_glock_scan, > + .count_objects = gfs2_shrink_glock_count, > .seeks = DEFAULT_SEEKS, > }; > > diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c > index 8ea7747..2c21986 100644 > --- a/fs/gfs2/main.c > +++ b/fs/gfs2/main.c > @@ -29,7 +29,8 @@ > #include "dir.h" > > static struct shrinker qd_shrinker = { > - .shrink = gfs2_shrink_qd_memory, > + .scan_objects = gfs2_shrink_qd_scan, > + .count_objects = gfs2_shrink_qd_count, > .seeks = DEFAULT_SEEKS, > }; > > diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c > index 42e8d23..5a5f76c 100644 > --- a/fs/gfs2/quota.c > +++ b/fs/gfs2/quota.c > @@ -78,20 +78,17 @@ static LIST_HEAD(qd_lru_list); > static atomic_t qd_lru_count = ATOMIC_INIT(0); > static DEFINE_SPINLOCK(qd_lru_lock); > > -int gfs2_shrink_qd_memory(struct shrinker *shrink, struct shrink_control *sc) > +long gfs2_shrink_qd_scan(struct shrinker *shrink, struct shrink_control *sc) > { > struct gfs2_quota_data *qd; > struct gfs2_sbd *sdp; > - int nr_to_scan = sc->nr_to_scan; > - > - if (nr_to_scan == 0) > - goto out; > + int freed = 0; > > if (!(sc->gfp_mask & __GFP_FS)) > return -1; > > spin_lock(&qd_lru_lock); > - while (nr_to_scan && !list_empty(&qd_lru_list)) { > + while (freed <= sc->nr_to_scan && !list_empty(&qd_lru_list)) { > qd = list_entry(qd_lru_list.next, > struct gfs2_quota_data, qd_reclaim); > sdp = qd->qd_gl->gl_sbd; > @@ -112,12 +109,16 @@ int gfs2_shrink_qd_memory(struct shrinker *shrink, struct shrink_control *sc) > spin_unlock(&qd_lru_lock); > kmem_cache_free(gfs2_quotad_cachep, qd); > spin_lock(&qd_lru_lock); > - nr_to_scan--; > + freed++; > } > spin_unlock(&qd_lru_lock); > > -out: > - return (atomic_read(&qd_lru_count) * sysctl_vfs_cache_pressure) / 100; > + return freed; > +} > + > +long gfs2_shrink_qd_count(struct shrinker *shrink, struct shrink_control *sc) > +{ > + return (atomic_read(&qd_lru_count) / 100) * sysctl_vfs_cache_pressure; > } > > static u64 qd2offset(struct gfs2_quota_data *qd) > diff --git a/fs/gfs2/quota.h b/fs/gfs2/quota.h > index 90bf1c3..c40fe6d 100644 > --- a/fs/gfs2/quota.h > +++ b/fs/gfs2/quota.h > @@ -52,7 +52,9 @@ static inline int gfs2_quota_lock_check(struct gfs2_inode *ip) > return ret; > } > > -extern int gfs2_shrink_qd_memory(struct shrinker *shrink, > +extern long gfs2_shrink_qd_scan(struct shrinker *shrink, > + struct shrink_control *sc); > +extern long gfs2_shrink_qd_count(struct shrinker *shrink, > struct shrink_control *sc); > extern const struct quotactl_ops gfs2_quotactl_ops; > > diff --git a/fs/inode.c b/fs/inode.c > index 848808f..fee5d9a 100644 > --- a/fs/inode.c > +++ b/fs/inode.c > @@ -613,10 +613,11 @@ static int can_unuse(struct inode *inode) > * LRU does not have strict ordering. Hence we don't want to reclaim inodes > * with this flag set because they are the inodes that are out of order. > */ > -void prune_icache_sb(struct super_block *sb, int nr_to_scan) > +long prune_icache_sb(struct super_block *sb, long nr_to_scan) > { > LIST_HEAD(freeable); > - int nr_scanned; > + long nr_scanned; > + long freed = 0; > unsigned long reap = 0; > > spin_lock(&sb->s_inode_lru_lock); > @@ -686,6 +687,7 @@ void prune_icache_sb(struct super_block *sb, int nr_to_scan) > list_move(&inode->i_lru, &freeable); > sb->s_nr_inodes_unused--; > this_cpu_dec(nr_unused); > + freed++; > } > if (current_is_kswapd()) > __count_vm_events(KSWAPD_INODESTEAL, reap); > @@ -694,6 +696,7 @@ void prune_icache_sb(struct super_block *sb, int nr_to_scan) > spin_unlock(&sb->s_inode_lru_lock); > > dispose_list(&freeable); > + return freed; > } > > static void __wait_on_freeing_inode(struct inode *inode); > diff --git a/fs/internal.h b/fs/internal.h > index fe327c2..2662ffa 100644 > --- a/fs/internal.h > +++ b/fs/internal.h > @@ -127,6 +127,8 @@ extern long do_handle_open(int mountdirfd, > * inode.c > */ > extern spinlock_t inode_sb_list_lock; > +extern long prune_icache_sb(struct super_block *sb, long nr_to_scan); > + > > /* > * fs-writeback.c > @@ -141,3 +143,4 @@ extern int invalidate_inodes(struct super_block *, bool); > * dcache.c > */ > extern struct dentry *__d_alloc(struct super_block *, const struct qstr *); > +extern long prune_dcache_sb(struct super_block *sb, long nr_to_scan); > diff --git a/fs/mbcache.c b/fs/mbcache.c > index 8c32ef3..aa3a19a 100644 > --- a/fs/mbcache.c > +++ b/fs/mbcache.c > @@ -90,11 +90,14 @@ static DEFINE_SPINLOCK(mb_cache_spinlock); > * What the mbcache registers as to get shrunk dynamically. > */ > > -static int mb_cache_shrink_fn(struct shrinker *shrink, > - struct shrink_control *sc); > +static long mb_cache_shrink_scan(struct shrinker *shrink, > + struct shrink_control *sc); > +static long mb_cache_shrink_count(struct shrinker *shrink, > + struct shrink_control *sc); > > static struct shrinker mb_cache_shrinker = { > - .shrink = mb_cache_shrink_fn, > + .scan_objects = mb_cache_shrink_scan, > + .count_objects = mb_cache_shrink_count, > .seeks = DEFAULT_SEEKS, > }; > > @@ -161,13 +164,12 @@ forget: > * > * Returns the number of objects which are present in the cache. > */ > -static int > -mb_cache_shrink_fn(struct shrinker *shrink, struct shrink_control *sc) > +static long > +mb_cache_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) > { > LIST_HEAD(free_list); > - struct mb_cache *cache; > struct mb_cache_entry *entry, *tmp; > - int count = 0; > + int freed = 0; > int nr_to_scan = sc->nr_to_scan; > gfp_t gfp_mask = sc->gfp_mask; > > @@ -180,18 +182,27 @@ mb_cache_shrink_fn(struct shrinker *shrink, struct shrink_control *sc) > list_move_tail(&ce->e_lru_list, &free_list); > __mb_cache_entry_unhash(ce); > } > - list_for_each_entry(cache, &mb_cache_list, c_cache_list) { > - mb_debug("cache %s (%d)", cache->c_name, > - atomic_read(&cache->c_entry_count)); > - count += atomic_read(&cache->c_entry_count); > - } > spin_unlock(&mb_cache_spinlock); > list_for_each_entry_safe(entry, tmp, &free_list, e_lru_list) { > __mb_cache_entry_forget(entry, gfp_mask); > + freed++; > } > - return (count / 100) * sysctl_vfs_cache_pressure; > + return freed; > } > > +static long > +mb_cache_shrink_count(struct shrinker *shrink, struct shrink_control *sc) > +{ > + struct mb_cache *cache; > + long count = 0; > + > + spin_lock(&mb_cache_spinlock); > + list_for_each_entry(cache, &mb_cache_list, c_cache_list) > + count += atomic_read(&cache->c_entry_count); > + > + spin_unlock(&mb_cache_spinlock); > + return (count / 100) * sysctl_vfs_cache_pressure; > +} > > /* > * mb_cache_create() create a new cache > diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c > index b238d95..a5aefb2 100644 > --- a/fs/nfs/dir.c > +++ b/fs/nfs/dir.c > @@ -2057,17 +2057,18 @@ static void nfs_access_free_list(struct list_head *head) > } > } > > -int nfs_access_cache_shrinker(struct shrinker *shrink, > - struct shrink_control *sc) > +long nfs_access_cache_scan(struct shrinker *shrink, > + struct shrink_control *sc) > { > LIST_HEAD(head); > struct nfs_inode *nfsi, *next; > struct nfs_access_entry *cache; > int nr_to_scan = sc->nr_to_scan; > + int freed = 0; > gfp_t gfp_mask = sc->gfp_mask; > > if ((gfp_mask & GFP_KERNEL) != GFP_KERNEL) > - return (nr_to_scan == 0) ? 0 : -1; > + return -1; > > spin_lock(&nfs_access_lru_lock); > list_for_each_entry_safe(nfsi, next, &nfs_access_lru_list, access_cache_inode_lru) { > @@ -2079,6 +2080,7 @@ int nfs_access_cache_shrinker(struct shrinker *shrink, > spin_lock(&inode->i_lock); > if (list_empty(&nfsi->access_cache_entry_lru)) > goto remove_lru_entry; > + freed++; > cache = list_entry(nfsi->access_cache_entry_lru.next, > struct nfs_access_entry, lru); > list_move(&cache->lru, &head); > @@ -2097,7 +2099,14 @@ 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 freed; > +} > + > +long nfs_access_cache_count(struct shrinker *shrink, > + struct shrink_control *sc) > +{ > + return (atomic_long_read(&nfs_access_nr_entries) / 100) * > + sysctl_vfs_cache_pressure; > } > > static void __nfs_access_zap_cache(struct nfs_inode *nfsi, struct list_head *head) > diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h > index ab12913..9c65e1f 100644 > --- a/fs/nfs/internal.h > +++ b/fs/nfs/internal.h > @@ -244,8 +244,10 @@ extern int nfs_init_client(struct nfs_client *clp, > int noresvport); > > /* dir.c */ > -extern int nfs_access_cache_shrinker(struct shrinker *shrink, > - struct shrink_control *sc); > +extern long nfs_access_cache_scan(struct shrinker *shrink, > + struct shrink_control *sc); > +extern long nfs_access_cache_count(struct shrinker *shrink, > + struct shrink_control *sc); > > /* inode.c */ > extern struct workqueue_struct *nfsiod_workqueue; > diff --git a/fs/nfs/super.c b/fs/nfs/super.c > index b961cea..e088c03 100644 > --- a/fs/nfs/super.c > +++ b/fs/nfs/super.c > @@ -380,7 +380,8 @@ static const struct super_operations nfs4_sops = { > #endif > > static struct shrinker acl_shrinker = { > - .shrink = nfs_access_cache_shrinker, > + .scan_objects = nfs_access_cache_scan, > + .count_objects = nfs_access_cache_count, > .seeks = DEFAULT_SEEKS, > }; > > diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c > index 5b572c8..c8724d2 100644 > --- a/fs/quota/dquot.c > +++ b/fs/quota/dquot.c > @@ -669,45 +669,42 @@ int dquot_quota_sync(struct super_block *sb, int type, int wait) > } > EXPORT_SYMBOL(dquot_quota_sync); > > -/* Free unused dquots from cache */ > -static void prune_dqcache(int count) > +/* > + * This is called from kswapd when we think we need some > + * more memory > + */ > +static long shrink_dqcache_scan(struct shrinker *shrink, > + struct shrink_control *sc) > { > struct list_head *head; > struct dquot *dquot; > + int freed = 0; > > + spin_lock(&dq_list_lock); > head = free_dquots.prev; > - while (head != &free_dquots && count) { > + while (head != &free_dquots && freed < sc->nr_to_scan) { > dquot = list_entry(head, struct dquot, dq_free); > remove_dquot_hash(dquot); > remove_free_dquot(dquot); > remove_inuse(dquot); > do_destroy_dquot(dquot); > - count--; > + freed++; > head = free_dquots.prev; > } > + spin_unlock(&dq_list_lock); > + > + return freed; > } > > -/* > - * This is called from kswapd when we think we need some > - * more memory > - */ > -static int shrink_dqcache_memory(struct shrinker *shrink, > +static long shrink_dqcache_count(struct shrinker *shrink, > struct shrink_control *sc) > { > - int nr = sc->nr_to_scan; > - > - if (nr) { > - spin_lock(&dq_list_lock); > - 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 (percpu_counter_read_positive(&dqstats.counter[DQST_FREE_DQUOTS]) > + / 100) * sysctl_vfs_cache_pressure; > } > - > static struct shrinker dqcache_shrinker = { > - .shrink = shrink_dqcache_memory, > + .scan_objects = shrink_dqcache_scan, > + .count_objects = shrink_dqcache_count, > .seeks = DEFAULT_SEEKS, > }; > > diff --git a/fs/super.c b/fs/super.c > index 6a72693..074abbe 100644 > --- a/fs/super.c > +++ b/fs/super.c > @@ -45,11 +45,14 @@ DEFINE_SPINLOCK(sb_lock); > * shrinker path and that leads to deadlock on the shrinker_rwsem. Hence we > * take a passive reference to the superblock to avoid this from occurring. > */ > -static int prune_super(struct shrinker *shrink, struct shrink_control *sc) > +static long super_cache_scan(struct shrinker *shrink, struct shrink_control *sc) > { > struct super_block *sb; > - int fs_objects = 0; > - int total_objects; > + long fs_objects = 0; > + long total_objects; > + long freed = 0; > + long dentries; > + long inodes; > > sb = container_of(shrink, struct super_block, s_shrink); > > @@ -57,7 +60,7 @@ static int prune_super(struct shrinker *shrink, struct shrink_control *sc) > * Deadlock avoidance. We may hold various FS locks, and we don't want > * to recurse into the FS that called us in clear_inode() and friends.. > */ > - if (sc->nr_to_scan && !(sc->gfp_mask & __GFP_FS)) > + if (!(sc->gfp_mask & __GFP_FS)) > return -1; > > if (!grab_super_passive(sb)) > @@ -69,33 +72,42 @@ static int prune_super(struct shrinker *shrink, struct shrink_control *sc) > total_objects = sb->s_nr_dentry_unused + > sb->s_nr_inodes_unused + fs_objects + 1; > > - if (sc->nr_to_scan) { > - int dentries; > - 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; > - if (fs_objects) > - fs_objects = (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 > - */ > - prune_dcache_sb(sb, dentries); > - prune_icache_sb(sb, 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; > > - if (fs_objects && sb->s_op->free_cached_objects) { > - sb->s_op->free_cached_objects(sb, fs_objects); > - fs_objects = sb->s_op->nr_cached_objects(sb); > - } > - total_objects = sb->s_nr_dentry_unused + > - sb->s_nr_inodes_unused + fs_objects; > + /* > + * prune the dcache first as the icache is pinned by it, then > + * prune the icache, followed by the filesystem specific caches > + */ > + freed = prune_dcache_sb(sb, dentries); > + freed += prune_icache_sb(sb, inodes); > + > + if (fs_objects) { > + fs_objects = (sc->nr_to_scan * fs_objects) / total_objects; > + freed += sb->s_op->free_cached_objects(sb, fs_objects); > } > > + drop_super(sb); > + return freed; > +} > + > +static long super_cache_count(struct shrinker *shrink, struct shrink_control *sc) > +{ > + struct super_block *sb; > + long total_objects = 0; > + > + sb = container_of(shrink, struct super_block, s_shrink); > + > + if (!grab_super_passive(sb)) > + return -1; > + > + if (sb->s_op && sb->s_op->nr_cached_objects) > + total_objects = sb->s_op->nr_cached_objects(sb); > + > + total_objects += sb->s_nr_dentry_unused; > + total_objects += sb->s_nr_inodes_unused; > + > total_objects = (total_objects / 100) * sysctl_vfs_cache_pressure; > drop_super(sb); > return total_objects; > @@ -182,7 +194,8 @@ static struct super_block *alloc_super(struct file_system_type *type) > s->cleancache_poolid = -1; > > s->s_shrink.seeks = DEFAULT_SEEKS; > - s->s_shrink.shrink = prune_super; > + s->s_shrink.scan_objects = super_cache_scan; > + s->s_shrink.count_objects = super_cache_count; > s->s_shrink.batch = 1024; > } > out: > diff --git a/fs/ubifs/shrinker.c b/fs/ubifs/shrinker.c > index 9e1d056..78ca7b7 100644 > --- a/fs/ubifs/shrinker.c > +++ b/fs/ubifs/shrinker.c > @@ -277,19 +277,12 @@ static int kick_a_thread(void) > return 0; > } > > -int ubifs_shrinker(struct shrinker *shrink, struct shrink_control *sc) > +long ubifs_shrinker_scan(struct shrinker *shrink, struct shrink_control *sc) > { > int nr = sc->nr_to_scan; > int freed, contention = 0; > long clean_zn_cnt = atomic_long_read(&ubifs_clean_zn_cnt); > > - if (nr == 0) > - /* > - * Due to the way UBIFS updates the clean znode counter it may > - * temporarily be negative. > - */ > - return clean_zn_cnt >= 0 ? clean_zn_cnt : 1; > - > if (!clean_zn_cnt) { > /* > * No clean znodes, nothing to reap. All we can do in this case > @@ -323,3 +316,13 @@ out: > dbg_tnc("%d znodes were freed, requested %d", freed, nr); > return freed; > } > + > +long ubifs_shrinker_count(struct shrinker *shrink, ubifs_shrinker_scan) > +{ > + long clean_zn_cnt = atomic_long_read(&ubifs_clean_zn_cnt); > + /* > + * Due to the way UBIFS updates the clean znode counter it may > + * temporarily be negative. > + */ > + return clean_zn_cnt >= 0 ? clean_zn_cnt : 1; > +} > diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c > index 91903f6..3d3f3e9 100644 > --- a/fs/ubifs/super.c > +++ b/fs/ubifs/super.c > @@ -49,7 +49,8 @@ struct kmem_cache *ubifs_inode_slab; > > /* UBIFS TNC shrinker description */ > static struct shrinker ubifs_shrinker_info = { > - .shrink = ubifs_shrinker, > + .scan_objects = ubifs_shrinker_scan, > + .count_objects = ubifs_shrinker_count, > .seeks = DEFAULT_SEEKS, > }; > > diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h > index 27f2255..2b8f48c 100644 > --- a/fs/ubifs/ubifs.h > +++ b/fs/ubifs/ubifs.h > @@ -1625,7 +1625,8 @@ int ubifs_tnc_start_commit(struct ubifs_info *c, struct ubifs_zbranch *zroot); > int ubifs_tnc_end_commit(struct ubifs_info *c); > > /* shrinker.c */ > -int ubifs_shrinker(struct shrinker *shrink, struct shrink_control *sc); > +long ubifs_shrinker_scan(struct shrinker *shrink, struct shrink_control *sc); > +long ubifs_shrinker_count(struct shrinker *shrink, struct shrink_control *sc); > > /* commit.c */ > int ubifs_bg_thread(void *info); > diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c > index 7a026cb..b2eea9e 100644 > --- a/fs/xfs/xfs_buf.c > +++ b/fs/xfs/xfs_buf.c > @@ -1456,8 +1456,8 @@ restart: > spin_unlock(&btp->bt_lru_lock); > } > > -int > -xfs_buftarg_shrink( > +static long > +xfs_buftarg_shrink_scan( > struct shrinker *shrink, > struct shrink_control *sc) > { > @@ -1465,6 +1465,7 @@ xfs_buftarg_shrink( > struct xfs_buftarg, bt_shrinker); > struct xfs_buf *bp; > int nr_to_scan = sc->nr_to_scan; > + int freed = 0; > LIST_HEAD(dispose); > > if (!nr_to_scan) > @@ -1493,6 +1494,7 @@ xfs_buftarg_shrink( > */ > list_move(&bp->b_lru, &dispose); > btp->bt_lru_nr--; > + freed++; > } > spin_unlock(&btp->bt_lru_lock); > > @@ -1502,6 +1504,16 @@ xfs_buftarg_shrink( > xfs_buf_rele(bp); > } > > + return freed; > +} > + > +static long > +xfs_buftarg_shrink_count( > + struct shrinker *shrink, > + struct shrink_control *sc) > +{ > + struct xfs_buftarg *btp = container_of(shrink, > + struct xfs_buftarg, bt_shrinker); > return btp->bt_lru_nr; > } > > @@ -1602,7 +1614,8 @@ xfs_alloc_buftarg( > goto error; > if (xfs_alloc_delwrite_queue(btp, fsname)) > goto error; > - btp->bt_shrinker.shrink = xfs_buftarg_shrink; > + btp->bt_shrinker.scan_objects = xfs_buftarg_shrink_scan; > + btp->bt_shrinker.count_objects = xfs_buftarg_shrink_count; > btp->bt_shrinker.seeks = DEFAULT_SEEKS; > register_shrinker(&btp->bt_shrinker); > return btp; > diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c > index 9a0aa76..19863a8 100644 > --- a/fs/xfs/xfs_qm.c > +++ b/fs/xfs/xfs_qm.c > @@ -60,10 +60,12 @@ STATIC void xfs_qm_list_destroy(xfs_dqlist_t *); > > STATIC int xfs_qm_init_quotainos(xfs_mount_t *); > STATIC int xfs_qm_init_quotainfo(xfs_mount_t *); > -STATIC int xfs_qm_shake(struct shrinker *, struct shrink_control *); > +STATIC long xfs_qm_shake_scan(struct shrinker *, struct shrink_control *); > +STATIC long xfs_qm_shake_count(struct shrinker *, struct shrink_control *); > > static struct shrinker xfs_qm_shaker = { > - .shrink = xfs_qm_shake, > + .scan_objects = xfs_qm_shake_scan, > + .count_objects = xfs_qm_shake_count, > .seeks = DEFAULT_SEEKS, > }; > > @@ -1963,9 +1965,8 @@ xfs_qm_shake_freelist( > /* > * The kmem_shake interface is invoked when memory is running low. > */ > -/* ARGSUSED */ > -STATIC int > -xfs_qm_shake( > +STATIC long > +xfs_qm_shake_scan( > struct shrinker *shrink, > struct shrink_control *sc) > { > @@ -1973,9 +1974,9 @@ xfs_qm_shake( > gfp_t gfp_mask = sc->gfp_mask; > > if (!kmem_shake_allow(gfp_mask)) > - return 0; > + return -1; > if (!xfs_Gqm) > - return 0; > + return -1; > > nfree = xfs_Gqm->qm_dqfrlist_cnt; /* free dquots */ > /* incore dquots in all f/s's */ > @@ -1992,6 +1993,13 @@ xfs_qm_shake( > return xfs_qm_shake_freelist(MAX(nfree, n)); > } > > +STATIC long > +xfs_qm_shake_count( > + struct shrinker *shrink, > + struct shrink_control *sc) > +{ > + return xfs_Gqm ? xfs_Gqm->qm_dqfrlist_cnt : -1; > +} > > /*------------------------------------------------------------------*/ > > diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c > index c94ec22..dff4b67 100644 > --- a/fs/xfs/xfs_super.c > +++ b/fs/xfs/xfs_super.c > @@ -1473,19 +1473,19 @@ xfs_fs_mount( > return mount_bdev(fs_type, flags, dev_name, data, xfs_fs_fill_super); > } > > -static int > +static long > xfs_fs_nr_cached_objects( > struct super_block *sb) > { > return xfs_reclaim_inodes_count(XFS_M(sb)); > } > > -static void > +static long > xfs_fs_free_cached_objects( > struct super_block *sb, > - int nr_to_scan) > + long nr_to_scan) > { > - xfs_reclaim_inodes_nr(XFS_M(sb), nr_to_scan); > + return xfs_reclaim_inodes_nr(XFS_M(sb), nr_to_scan); > } > > static const struct super_operations xfs_super_operations = { > diff --git a/fs/xfs/xfs_sync.c b/fs/xfs/xfs_sync.c > index 4604f90..5b60a3a 100644 > --- a/fs/xfs/xfs_sync.c > +++ b/fs/xfs/xfs_sync.c > @@ -896,7 +896,7 @@ int > xfs_reclaim_inodes_ag( > struct xfs_mount *mp, > int flags, > - int *nr_to_scan) > + long *nr_to_scan) > { > struct xfs_perag *pag; > int error = 0; > @@ -1017,7 +1017,7 @@ xfs_reclaim_inodes( > xfs_mount_t *mp, > int mode) > { > - int nr_to_scan = INT_MAX; > + long nr_to_scan = LONG_MAX; > > return xfs_reclaim_inodes_ag(mp, mode, &nr_to_scan); > } > @@ -1031,29 +1031,32 @@ xfs_reclaim_inodes( > * them to be cleaned, which we hope will not be very long due to the > * background walker having already kicked the IO off on those dirty inodes. > */ > -void > +long > xfs_reclaim_inodes_nr( > struct xfs_mount *mp, > - int nr_to_scan) > + long nr_to_scan) > { > + long nr = nr_to_scan; > + > /* kick background reclaimer and push the AIL */ > xfs_syncd_queue_reclaim(mp); > xfs_ail_push_all(mp->m_ail); > > - xfs_reclaim_inodes_ag(mp, SYNC_TRYLOCK | SYNC_WAIT, &nr_to_scan); > + xfs_reclaim_inodes_ag(mp, SYNC_TRYLOCK | SYNC_WAIT, &nr); > + return nr_to_scan - nr; > } > > /* > * Return the number of reclaimable inodes in the filesystem for > * the shrinker to determine how much to reclaim. > */ > -int > +long > xfs_reclaim_inodes_count( > struct xfs_mount *mp) > { > struct xfs_perag *pag; > xfs_agnumber_t ag = 0; > - int reclaimable = 0; > + long reclaimable = 0; > > while ((pag = xfs_perag_get_tag(mp, ag, XFS_ICI_RECLAIM_TAG))) { > ag = pag->pag_agno + 1; > diff --git a/fs/xfs/xfs_sync.h b/fs/xfs/xfs_sync.h > index 941202e..82e1b1c 100644 > --- a/fs/xfs/xfs_sync.h > +++ b/fs/xfs/xfs_sync.h > @@ -35,8 +35,8 @@ void xfs_quiesce_attr(struct xfs_mount *mp); > void xfs_flush_inodes(struct xfs_inode *ip); > > int xfs_reclaim_inodes(struct xfs_mount *mp, int mode); > -int xfs_reclaim_inodes_count(struct xfs_mount *mp); > -void xfs_reclaim_inodes_nr(struct xfs_mount *mp, int nr_to_scan); > +long xfs_reclaim_inodes_count(struct xfs_mount *mp); > +long xfs_reclaim_inodes_nr(struct xfs_mount *mp, long nr_to_scan); > > void xfs_inode_set_reclaim_tag(struct xfs_inode *ip); > void __xfs_inode_set_reclaim_tag(struct xfs_perag *pag, struct xfs_inode *ip); > diff --git a/include/linux/fs.h b/include/linux/fs.h > index 14be4d8..958c025 100644 > --- a/include/linux/fs.h > +++ b/include/linux/fs.h > @@ -1465,10 +1465,6 @@ struct super_block { > struct shrinker s_shrink; /* per-sb shrinker handle */ > }; > > -/* superblock cache pruning functions */ > -extern void prune_icache_sb(struct super_block *sb, int nr_to_scan); > -extern void prune_dcache_sb(struct super_block *sb, int nr_to_scan); > - > extern struct timespec current_fs_time(struct super_block *sb); > > /* > @@ -1662,8 +1658,8 @@ struct super_operations { > ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t); > #endif > int (*bdev_try_to_free_page)(struct super_block*, struct page*, gfp_t); > - int (*nr_cached_objects)(struct super_block *); > - void (*free_cached_objects)(struct super_block *, int); > + long (*nr_cached_objects)(struct super_block *); > + long (*free_cached_objects)(struct super_block *, long); > }; > > /* > diff --git a/include/trace/events/vmscan.h b/include/trace/events/vmscan.h > index 36851f7..80308ea 100644 > --- a/include/trace/events/vmscan.h > +++ b/include/trace/events/vmscan.h > @@ -190,7 +190,7 @@ TRACE_EVENT(mm_shrink_slab_start, > > TP_STRUCT__entry( > __field(struct shrinker *, shr) > - __field(void *, shrink) > + __field(void *, scan) > __field(long, nr_objects_to_shrink) > __field(gfp_t, gfp_flags) > __field(unsigned long, pgs_scanned) > @@ -202,7 +202,7 @@ TRACE_EVENT(mm_shrink_slab_start, > > TP_fast_assign( > __entry->shr = shr; > - __entry->shrink = shr->shrink; > + __entry->scan = shr->scan_objects; > __entry->nr_objects_to_shrink = nr_objects_to_shrink; > __entry->gfp_flags = sc->gfp_mask; > __entry->pgs_scanned = pgs_scanned; > @@ -213,7 +213,7 @@ TRACE_EVENT(mm_shrink_slab_start, > ), > > TP_printk("%pF %p: objects to shrink %ld gfp_flags %s pgs_scanned %ld lru_pgs %ld cache items %ld delta %lld total_scan %ld", > - __entry->shrink, > + __entry->scan, > __entry->shr, > __entry->nr_objects_to_shrink, > show_gfp_flags(__entry->gfp_flags), > @@ -232,7 +232,7 @@ TRACE_EVENT(mm_shrink_slab_end, > > TP_STRUCT__entry( > __field(struct shrinker *, shr) > - __field(void *, shrink) > + __field(void *, scan) > __field(long, unused_scan) > __field(long, new_scan) > __field(int, retval) > @@ -241,7 +241,7 @@ TRACE_EVENT(mm_shrink_slab_end, > > TP_fast_assign( > __entry->shr = shr; > - __entry->shrink = shr->shrink; > + __entry->scan = shr->scan_objects; > __entry->unused_scan = unused_scan_cnt; > __entry->new_scan = new_scan_cnt; > __entry->retval = shrinker_retval; > @@ -249,7 +249,7 @@ TRACE_EVENT(mm_shrink_slab_end, > ), > > TP_printk("%pF %p: unused scan count %ld new scan count %ld total_scan %ld last shrinker return val %d", > - __entry->shrink, > + __entry->scan, > __entry->shr, > __entry->unused_scan, > __entry->new_scan, > diff --git a/mm/vmscan.c b/mm/vmscan.c > index 7ef6912..e32ce2d 100644 > --- a/mm/vmscan.c > +++ b/mm/vmscan.c > @@ -202,14 +202,6 @@ void unregister_shrinker(struct shrinker *shrinker) > } > EXPORT_SYMBOL(unregister_shrinker); > > -static inline int do_shrinker_shrink(struct shrinker *shrinker, > - struct shrink_control *sc, > - unsigned long nr_to_scan) > -{ > - sc->nr_to_scan = nr_to_scan; > - return (*shrinker->shrink)(shrinker, sc); > -} > - > #define SHRINK_BATCH 128 > /* > * Call the shrink functions to age shrinkable caches > @@ -230,27 +222,26 @@ static inline int do_shrinker_shrink(struct shrinker *shrinker, > * > * Returns the number of slab objects which we shrunk. > */ > -unsigned long shrink_slab(struct shrink_control *shrink, > +unsigned long shrink_slab(struct shrink_control *sc, > unsigned long nr_pages_scanned, > unsigned long lru_pages) > { > struct shrinker *shrinker; > - unsigned long ret = 0; > + unsigned long freed = 0; > > if (nr_pages_scanned == 0) > nr_pages_scanned = SWAP_CLUSTER_MAX; > > if (!down_read_trylock(&shrinker_rwsem)) { > /* Assume we'll be able to shrink next time */ > - ret = 1; > + freed = 1; > goto out; > } > > list_for_each_entry(shrinker, &shrinker_list, list) { > - unsigned long long delta; > - unsigned long total_scan; > - unsigned long max_pass; > - int shrink_ret = 0; > + long long delta; > + long total_scan; > + long max_pass; > long nr; > long new_nr; > long batch_size = shrinker->batch ? shrinker->batch > @@ -266,7 +257,9 @@ unsigned long shrink_slab(struct shrink_control *shrink, > } while (cmpxchg(&shrinker->nr, nr, 0) != nr); > > total_scan = nr; > - max_pass = do_shrinker_shrink(shrinker, shrink, 0); > + max_pass = shrinker->count_objects(shrinker, sc); > + WARN_ON_ONCE(max_pass < 0); > + > delta = (4 * nr_pages_scanned) / shrinker->seeks; > delta *= max_pass; > do_div(delta, lru_pages + 1); > @@ -274,7 +267,7 @@ unsigned long shrink_slab(struct shrink_control *shrink, > if (total_scan < 0) { > printk(KERN_ERR "shrink_slab: %pF negative objects to " > "delete nr=%ld\n", > - shrinker->shrink, total_scan); > + shrinker->scan_objects, total_scan); > total_scan = max_pass; > } > > @@ -301,20 +294,19 @@ unsigned long shrink_slab(struct shrink_control *shrink, > if (total_scan > max_pass * 2) > total_scan = max_pass * 2; > > - trace_mm_shrink_slab_start(shrinker, shrink, nr, > + trace_mm_shrink_slab_start(shrinker, sc, nr, > nr_pages_scanned, lru_pages, > max_pass, delta, total_scan); > > while (total_scan >= batch_size) { > - int nr_before; > + long ret; > + > + sc->nr_to_scan = batch_size; > + ret = shrinker->scan_objects(shrinker, sc); > > - nr_before = do_shrinker_shrink(shrinker, shrink, 0); > - shrink_ret = do_shrinker_shrink(shrinker, shrink, > - batch_size); > - if (shrink_ret == -1) > + if (ret == -1) > break; > - if (shrink_ret < nr_before) > - ret += nr_before - shrink_ret; > + freed += ret; > count_vm_events(SLABS_SCANNED, batch_size); > total_scan -= batch_size; > > @@ -333,12 +325,12 @@ unsigned long shrink_slab(struct shrink_control *shrink, > break; > } while (cmpxchg(&shrinker->nr, nr, new_nr) != nr); > > - trace_mm_shrink_slab_end(shrinker, shrink_ret, nr, new_nr); > + trace_mm_shrink_slab_end(shrinker, freed, nr, new_nr); > } > up_read(&shrinker_rwsem); > out: > cond_resched(); > - return ret; > + return freed; > } > > static void set_reclaim_mode(int priority, struct scan_control *sc, > diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c > index 727e506..f5955c3 100644 > --- a/net/sunrpc/auth.c > +++ b/net/sunrpc/auth.c > @@ -292,6 +292,7 @@ rpcauth_prune_expired(struct list_head *free, int nr_to_scan) > spinlock_t *cache_lock; > struct rpc_cred *cred, *next; > unsigned long expired = jiffies - RPC_AUTH_EXPIRY_MORATORIUM; > + int freed = 0; > > list_for_each_entry_safe(cred, next, &cred_unused, cr_lru) { > > @@ -303,10 +304,10 @@ rpcauth_prune_expired(struct list_head *free, int nr_to_scan) > */ > if (time_in_range(cred->cr_expire, expired, jiffies) && > test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0) > - return 0; > + break; > > - list_del_init(&cred->cr_lru); > number_cred_unused--; > + list_del_init(&cred->cr_lru); > if (atomic_read(&cred->cr_count) != 0) > continue; > > @@ -316,17 +317,18 @@ rpcauth_prune_expired(struct list_head *free, int nr_to_scan) > get_rpccred(cred); > list_add_tail(&cred->cr_lru, free); > rpcauth_unhash_cred_locked(cred); > + freed++; > } > spin_unlock(cache_lock); > } > - return (number_cred_unused / 100) * sysctl_vfs_cache_pressure; > + return freed; > } > > /* > * Run memory cache shrinker. > */ > -static int > -rpcauth_cache_shrinker(struct shrinker *shrink, struct shrink_control *sc) > +static long > +rpcauth_cache_scan(struct shrinker *shrink, struct shrink_control *sc) > { > LIST_HEAD(free); > int res; > @@ -344,6 +346,12 @@ rpcauth_cache_shrinker(struct shrinker *shrink, struct shrink_control *sc) > return res; > } > > +static long > +rpcauth_cache_count(struct shrinker *shrink, struct shrink_control *sc) > +{ > + return (number_cred_unused / 100) * sysctl_vfs_cache_pressure; > +} > + > /* > * Look up a process' credentials in the authentication cache > */ > @@ -658,7 +666,8 @@ rpcauth_uptodatecred(struct rpc_task *task) > } > > static struct shrinker rpc_cred_shrinker = { > - .shrink = rpcauth_cache_shrinker, > + .scan_objects = rpcauth_cache_scan, > + .count_objects = rpcauth_cache_count, > .seeks = DEFAULT_SEEKS, > }; > -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@xxxxxxxxx. For more info on Linux MM, see: http://www.linux-mm.org/ . Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/ Don't email: <a href=mailto:"dont@xxxxxxxxx"> email@xxxxxxxxx </a>