OK, rename was a bit trickier than I thought first, but this patch
should work.
Alan, could you test if it helps with your fragmentation problems?
Linus, could you please add it to the next kernel if you like it?
Other testers are welcome too of course.
Thanks,
-Andi
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;
}
/*
-
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