[PATCH] fix nr_pages reported by shrink_caches

From: Ed Tomlinson (tomlins@cam.org)
Date: Fri Nov 02 2001 - 20:00:14 EST


Hi,

The shrink_caches call in vmscan can return a bogus nr_pages due to
the shrink_dcache_memory and friends not returning the number of
pages they free. This patch corrects this.

I add a kmem_cache_empty funtion and modify kmem_cache_shrink to
return the number of pages shrunk. I audited the kernel tree to
see if any code depended on kmem_cache_shrink returning zero and
replaced these calls with !kmem_cache_empty.

Comments?

Ed Tomlinson

---------------------------
--- linux/fs/inode.c.orig Fri Nov 2 18:40:42 2001
+++ linux/fs/inode.c Fri Nov 2 18:42:27 2001
@@ -724,8 +724,7 @@
         count = inodes_stat.nr_unused / priority;
 
         prune_icache(count);
- kmem_cache_shrink(inode_cachep);
- return 0;
+ return kmem_cache_shrink(inode_cachep);
 }
 
 /*
--- linux/fs/dcache.c.orig Fri Nov 2 18:40:27 2001
+++ linux/fs/dcache.c Fri Nov 2 18:41:52 2001
@@ -568,8 +568,7 @@
         count = dentry_stat.nr_unused / priority;
 
         prune_dcache(count);
- kmem_cache_shrink(dentry_cache);
- return 0;
+ return kmem_cache_shrink(dentry_cache);
 }
 
 #define NAME_ALLOC_LEN(len) ((len+16) & ~15)
--- linux/fs/dquot.c.orig Fri Nov 2 18:41:12 2001
+++ linux/fs/dquot.c Fri Nov 2 18:43:11 2001
@@ -429,8 +429,7 @@
 int shrink_dqcache_memory(int priority, unsigned int gfp_mask)
 {
         prune_dqcache(nr_free_dquots / (priority + 1));
- kmem_cache_shrink(dquot_cachep);
- return 0;
+ return kmem_cache_shrink(dquot_cachep);
 }
 
 /* NOTE: If you change this function please check whether dqput_blocks() works right... */
--- linux/include/linux/slab.h.orig Fri Nov 2 18:45:25 2001
+++ linux/include/linux/slab.h Fri Nov 2 18:46:08 2001
@@ -54,6 +54,7 @@
                                        void (*)(void *, kmem_cache_t *, unsigned long));
 extern int kmem_cache_destroy(kmem_cache_t *);
 extern int kmem_cache_shrink(kmem_cache_t *);
+extern int kmem_cache_empty(kmem_cache_t *);
 extern void *kmem_cache_alloc(kmem_cache_t *, int);
 extern void kmem_cache_free(kmem_cache_t *, void *);
 
--- linux/mm/slab.c.orig Fri Nov 2 18:48:11 2001
+++ linux/mm/slab.c Fri Nov 2 19:16:14 2001
@@ -912,7 +912,7 @@
 static int __kmem_cache_shrink(kmem_cache_t *cachep)
 {
         slab_t *slabp;
- int ret;
+ int ret = 0;
 
         drain_cpu_caches(cachep);
 
@@ -936,8 +936,19 @@
                 spin_unlock_irq(&cachep->spinlock);
                 kmem_slab_destroy(cachep, slabp);
                 spin_lock_irq(&cachep->spinlock);
+ ret += 1;
         }
- ret = !list_empty(&cachep->slabs_full) || !list_empty(&cachep->slabs_partial);
+ spin_unlock_irq(&cachep->spinlock);
+ return ret<<(cachep->gfporder);
+}
+
+int kmem_cache_empty(kmem_cache_t *cachep)
+{
+ slab_t *slabp;
+ int ret;
+
+ spin_lock_irq(&cachep->spinlock);
+ ret = list_empty(&cachep->slabs_full) && list_empty(&cachep->slabs_partial);
         spin_unlock_irq(&cachep->spinlock);
         return ret;
 }
@@ -947,7 +958,7 @@
  * @cachep: The cache to shrink.
  *
  * Releases as many slabs as possible for a cache.
- * To help debugging, a zero exit status indicates all slabs were released.
+ * To aid the vm the number of pages released is returned.
  */
 int kmem_cache_shrink(kmem_cache_t *cachep)
 {
@@ -986,7 +997,8 @@
         list_del(&cachep->next);
         up(&cache_chain_sem);
 
- if (__kmem_cache_shrink(cachep)) {
+ __kmem_cache_shrink(cachep);
+ if (!kmem_cache_empty(cachep)) {
                 printk(KERN_ERR "kmem_cache_destroy: Can't free all objects %p\n",
                        cachep);
                 down(&cache_chain_sem);
--- linux/mm/vmscan.c.orig Fri Nov 2 18:58:25 2001
+++ linux/mm/vmscan.c Fri Nov 2 19:00:04 2001
@@ -564,11 +564,13 @@
         if (nr_pages <= 0)
                 return 0;
 
- shrink_dcache_memory(priority, gfp_mask);
- shrink_icache_memory(priority, gfp_mask);
+ nr_pages -= shrink_dcache_memory(priority, gfp_mask);
+ nr_pages -= shrink_icache_memory(priority, gfp_mask);
 #ifdef CONFIG_QUOTA
- shrink_dqcache_memory(DEF_PRIORITY, gfp_mask);
+ nr_pages -= shrink_dqcache_memory(DEF_PRIORITY, gfp_mask);
 #endif
+ if (nr_pages <= 0)
+ return 0;
 
         return nr_pages;
 }
--- linux/drivers/s390/ccwcache.c.orig Fri Nov 2 19:02:54 2001
+++ linux/drivers/s390/ccwcache.c Fri Nov 2 19:03:57 2001
@@ -291,7 +291,8 @@
         /* Shrink the caches, if available */
         for ( cachind = 0; cachind < CCW_NUMBER_CACHES; cachind ++ ) {
                 if ( ccw_cache[cachind] ) {
- if ( kmem_cache_shrink(ccw_cache[cachind]) == 0 ) {
+ kmem_cache_shrink(ccw_cache[cachind]);
+ if ( kmem_cache_empty(ccw_cache[cachind]) ) {
                                 ccw_cache[cachind] = NULL;
                         }
                         kmem_cache_destroy(ccw_cache[cachind]);
---------------------
-
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/



This archive was generated by hypermail 2b29 : Wed Nov 07 2001 - 21:00:20 EST