Linux-kernel mailing list archive 2000-06,: [patch] Re: 2.3.42 buffer problem/leak ?

# [patch] Re: 2.3.42 buffer problem/leak ?

Andrea Arcangeli (andrea@suse.de)
Wed, 9 Feb 2000 16:21:12 +0100 (CET)

- Messages sorted by: [ date ][ thread ][ subject ][ author ]
- Next message: John Levon: "Re: dead comments"
- Previous message: Andrea Arcangeli: "Re: [q] what is TASK_SWAPPING for?"

Harald could you give a try to 2.3.42aa3?

ftp://ftp.*.kernel.org/pub/linux/kernel/people/andrea/kerenls/v2.3/2.3.42aa3.gz

The interesting bit is here:

ftp://ftp.*.kernel.org/pub/linux/kernel/people/andrea/kernels/v2.3/2.3.42aa3/icache-dcache-preshrink-1.gz

I attach the interesting patch to the email too. It's against 2.3.42.

diff -urN 2.3.42/fs/dcache.c 2.3.42-idcache/fs/dcache.c
--- 2.3.42/fs/dcache.c Sun Jan 30 15:43:39 2000
+++ 2.3.42-idcache/fs/dcache.c Tue Feb 8 12:26:43 2000
@@ -57,6 +57,15 @@
int dummy[2];
} dentry_stat = {0, 0, 45, 0,};
+struct {
+ /* Enlarging too much is not a good idea since a too large cache
+ may generate too much collisions in the hash potentially
+ slowing down the system. */
+ int limit_percent;
+} dcache_ctl = { 2, };
+int dcache_ctl_min[] = { 0, };
+int dcache_ctl_max[] = { 100, };
+
static inline void d_free(struct dentry *dentry)
{
if (dentry->d_op && dentry->d_op->d_release)
@@ -428,6 +437,20 @@
return 0;
}
+static inline void preshrink_dcache_memory(void)
+{
+ unsigned long size, limit;
+
+ size = (dentry_stat.nr_unused * sizeof(struct dentry)) >> PAGE_SHIFT;
+ limit = num_physpages * dcache_ctl.limit_percent / 100;
+ if (size > limit)
+ {
+ lock_kernel();
+ prune_dcache(dentry_stat.nr_unused >> 2);
+ unlock_kernel();
+ }
+}
+
#define NAME_ALLOC_LEN(len) ((len+16) & ~15)
struct dentry * d_alloc(struct dentry * parent, const struct qstr *name)
@@ -435,6 +458,7 @@
char * str;
struct dentry *dentry;
+ preshrink_dcache_memory();
dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL);
if (!dentry)
return NULL;
diff -urN 2.3.42/fs/inode.c 2.3.42-idcache/fs/inode.c
--- 2.3.42/fs/inode.c Sun Jan 30 15:43:39 2000
+++ 2.3.42-idcache/fs/inode.c Tue Feb 8 12:26:43 2000
@@ -70,10 +70,19 @@
int dummy[5];
} inodes_stat = {0, 0,};
+struct {
+ /* Enlarging too much is not a good idea since a too large cache
+ may generate too much collisions in the hash potentially
+ slowing down the system. */
+ int limit_percent;
+} icache_ctl = { 2, };
+int icache_ctl_min[] = { 0, };
+int icache_ctl_max[] = { 100, };
+
static kmem_cache_t * inode_cachep;
#define alloc_inode() \
- ((struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL))
+ (preshrink_icache_memory(), (struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL))
#define destroy_inode(inode) kmem_cache_free(inode_cachep, (inode))
/*
@@ -411,6 +420,16 @@
kmem_cache_shrink(inode_cachep);
return 0;
+}
+
+static inline void preshrink_icache_memory(void)
+{
+ unsigned long size, limit;
+
+ size = (inodes_stat.nr_unused * sizeof(struct inode)) >> PAGE_SHIFT;
+ limit = num_physpages * icache_ctl.limit_percent / 100;
+ if (size > limit)
+ prune_icache(inodes_stat.nr_unused >> 2);
}
static inline void __iget(struct inode * inode)
diff -urN 2.3.42/include/linux/sysctl.h 2.3.42-idcache/include/linux/sysctl.h
--- 2.3.42/include/linux/sysctl.h Sun Jan 30 15:43:39 2000
+++ 2.3.42-idcache/include/linux/sysctl.h Tue Feb 8 12:26:43 2000
@@ -500,7 +500,9 @@
FS_NRSUPER=9, /* int:current number of allocated super_blocks */
FS_MAXSUPER=10, /* int:maximum number of super_blocks that can be allocated */
FS_OVERFLOWUID=11, /* int: overflow UID */
- FS_OVERFLOWGID=12 /* int: overflow GID */
+ FS_OVERFLOWGID=12, /* int: overflow GID */
+ FS_DCACHE_CTL=13, /* dentry cache controls */
+ FS_ICACHE_CTL=14, /* inode cache controls */
};
/* CTL_DEBUG names: */
diff -urN 2.3.42/kernel/sysctl.c 2.3.42-idcache/kernel/sysctl.c
--- 2.3.42/kernel/sysctl.c Sun Jan 30 15:43:40 2000
+++ 2.3.42-idcache/kernel/sysctl.c Tue Feb 8 12:26:43 2000
@@ -47,6 +47,9 @@
static int maxolduid = 65535;
static int minolduid = 0;
+extern int dcache_ctl[], dcache_ctl_min[], dcache_ctl_max[];
+extern int icache_ctl[], icache_ctl_min[], icache_ctl_max[];
+
#ifdef CONFIG_KMOD
extern char modprobe_path[];
#endif
@@ -306,6 +309,12 @@
{FS_OVERFLOWGID, "overflowgid", &fs_overflowgid, sizeof(int), 0644, NULL,
&proc_dointvec_minmax, &sysctl_intvec, NULL,
&minolduid, &maxolduid},
+ {FS_DCACHE_CTL, "dcache_ctl", &dcache_ctl, 1*sizeof(int), 0644, NULL,
+ &proc_dointvec_minmax, &sysctl_intvec, NULL,
+ &dcache_ctl_min, &dcache_ctl_max},
+ {FS_ICACHE_CTL, "icache_ctl", &icache_ctl, 1*sizeof(int), 0644, NULL,
+ &proc_dointvec_minmax, &sysctl_intvec, NULL,
+ &icache_ctl_min, &icache_ctl_max},
{0}
};

It basically avoids the caching part of the icache and dcache to grow more
than 2% of the memory in the machine. You can tune via sysctl the
percentage. The percentage should choosed in function of the hashtable
size to avoid an insane number of collisions in the hash that could lead
the dcache to be potentially slower than rereading the inode and direntry
from the buffer cache. Actually the hashtable is not yet dynamic but of
course my thoughts will apply to the future.

Andrea

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/

- Next message: John Levon: "Re: dead comments"
- Previous message: Andrea Arcangeli: "Re: [q] what is TASK_SWAPPING for?"