Re: Linux hostile to poverty

Andi Kleen (ak@muc.de)
18 Jul 1998 14:16:22 +0200


Bill Metzenthen <melbpc@melbpc.org.au> writes:

> [For those new to the effect, somewhere in the 2.1.xx kernel series
> my low memory machine (8Mbyte) began to get sluggish after being
> used for some time due to lots of swapping. This is reliably triggered
> by doing a 'find' on a directory which has lots of files (a few tens
> of thousands) in sub-directories, etc. My test consists of compiling
> one of the kernel files before and after doing such a find (fresh after
> re-booting.]

Could you try if this patch helps against your rusting effect? (should
apply to 2.1.10x). Also please post /proc/slabinfo and Shft-Roll on the
console output on such a rusted machine.

Index: linux/fs/dcache.c
===================================================================
RCS file: /vger/u4/cvs/linux/fs/dcache.c,v
retrieving revision 1.57
diff -u -r1.57 dcache.c
--- dcache.c 1998/05/07 20:50:05 1.57
+++ dcache.c 1998/07/12 17:27:32
@@ -17,6 +17,7 @@
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/init.h>

#include <asm/uaccess.h>
@@ -29,6 +30,8 @@
extern int inodes_stat[];
#define nr_inodes (inodes_stat[0])

+kmem_cache_t *dentry_cache;
+
/*
* This is the single most critical data structure when it comes
* to the dcache: the hashtable for lookups. Somebody should try
@@ -56,8 +59,9 @@
{
if (dentry->d_op && dentry->d_op->d_release)
dentry->d_op->d_release(dentry);
- kfree(dentry->d_name.name);
- kfree(dentry);
+ if (dname_external(dentry))
+ kfree(dentry->d_name.name);
+ kmem_cache_free(dentry_cache, dentry);
}

/*
@@ -461,15 +465,18 @@
free_inode_memory(8);
}

- dentry = kmalloc(sizeof(struct dentry), GFP_KERNEL);
+ dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL);
if (!dentry)
return NULL;

- str = kmalloc(NAME_ALLOC_LEN(name->len), GFP_KERNEL);
- if (!str) {
- kfree(dentry);
- return NULL;
- }
+ if (name->len > DNAME_INLINE_LEN-1) {
+ str = kmalloc(NAME_ALLOC_LEN(name->len), GFP_KERNEL);
+ if (!str) {
+ kmem_cache_free(dentry_cache, dentry);
+ return NULL;
+ }
+ } else
+ str = dentry->d_iname;

memcpy(str, name->name, name->len);
str[name->len] = 0;
@@ -654,6 +661,15 @@
__typeof__ (x) __tmp = x; \
x = y; y = __tmp; } while (0)

+void memswap(char *a, char *b, int len)
+{
+ while (len-- > 0) {
+ do_switch(*a, *b);
+ a++;
+ b++;
+ }
+}
+
/*
* We cannibalize "target" when moving dentry on top of it,
* because it's going to be thrown away anyway. We could be more
@@ -686,8 +702,17 @@
list_del(&target->d_child);

/* Switch the parents and the names.. */
- do_switch(dentry->d_parent, target->d_parent);
+
+ /* Could do a longword copy when it is sufficiently aligned,
+ * but I'm not sure if it is worth the optimization. */
+ memswap(dentry->d_iname, target->d_iname, DNAME_INLINE_LEN);
do_switch(dentry->d_name.name, target->d_name.name);
+ if (target->d_name.name == dentry->d_iname)
+ target->d_name.name = target->d_iname;
+ if (dentry->d_name.name == target->d_iname)
+ dentry->d_name.name = dentry->d_iname;
+
+ do_switch(dentry->d_parent, target->d_parent);
do_switch(dentry->d_name.len, target->d_name.len);
do_switch(dentry->d_name.hash, target->d_name.hash);
list_add(&target->d_child, &target->d_parent->d_subdirs);
@@ -847,6 +872,22 @@
{
int i;
struct list_head *d = dentry_hashtable;
+
+ /*
+ * A constructor could be added for stable state like the lists,
+ * but it is probably not worth it because of the cache nature
+ * of the dcache.
+ * If fragmentation is too bad then the SLAB_HWCACHE_ALIGN
+ * flag could be removed here, to hint to the allocator that
+ * it should not try to get multiple page regions.
+ */
+ dentry_cache = kmem_cache_create("dentry_cache",
+ sizeof(struct dentry),
+ 0,
+ SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (!dentry_cache)
+ panic("Cannot create dentry cache");

i = D_HASHSIZE;
do {
Index: linux/include/linux/dcache.h
===================================================================
RCS file: /vger/u4/cvs/linux/include/linux/dcache.h,v
retrieving revision 1.17
diff -u -r1.17 dcache.h
--- dcache.h 1998/05/07 20:48:49 1.17
+++ dcache.h 1998/07/12 17:27:33
@@ -50,6 +50,8 @@
return end_name_hash(hash);
}

+#define DNAME_INLINE_LEN 16
+
struct dentry {
int d_count;
unsigned int d_flags;
@@ -68,6 +70,7 @@
struct super_block * d_sb; /* The root of the dentry tree */
unsigned long d_reftime; /* last time referenced */
void * d_fsdata; /* fs-specific data */
+ unsigned char d_iname[DNAME_INLINE_LEN]; /* small names */
};

struct dentry_operations {
@@ -112,6 +115,11 @@
{
list_del(&dentry->d_hash);
INIT_LIST_HEAD(&dentry->d_hash);
+}
+
+static __inline__ int dname_external(struct dentry *d)
+{
+ return d->d_name.name != d->d_iname;
}

/*

-Andi

-
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.altern.org/andrebalsa/doc/lkml-faq.html