patch-2.1.116 linux/fs/dcache.c

Next file: linux/fs/exec.c
Previous file: linux/fs/binfmt_elf.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.115/linux/fs/dcache.c linux/fs/dcache.c
@@ -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); 
 }
 
 /*
@@ -398,7 +402,7 @@
 		this_parent = this_parent->d_parent;
 		goto resume;
 	}
-	return (count == 1); /* one remaining use count? */
+	return (count > 1); /* remaining users? */
 }
 
 /*
@@ -498,15 +502,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;
@@ -692,6 +699,32 @@
 	x = y; y = __tmp; } while (0)
 
 /*
+ * When switching names, the actual string doesn't strictly have to
+ * be preserved in the target - because we're dropping the target
+ * anyway. As such, we can just do a simple memcpy() to copy over
+ * the new name before we switch.
+ *
+ * Note that we have to be a lot more careful about getting the hash
+ * switched - we have to switch the hash value properly even if it
+ * then no longer matches the actual (corrupted) string of the target.
+ * The has value has to match the hash queue that the dentry is on..
+ */
+static inline void switch_names(struct dentry * dentry, struct dentry * target)
+{
+	const unsigned char *old_name, *new_name;
+
+	memcpy(dentry->d_iname, target->d_iname, DNAME_INLINE_LEN); 
+	old_name = target->d_name.name;
+	new_name = dentry->d_name.name;
+	if (old_name == target->d_iname)
+		old_name = dentry->d_iname;
+	if (new_name == dentry->d_iname)
+		new_name = target->d_iname;
+	target->d_name.name = new_name;
+	dentry->d_name.name = old_name;
+}
+
+/*
  * We cannibalize "target" when moving dentry on top of it,
  * because it's going to be thrown away anyway. We could be more
  * polite about it, though.
@@ -723,10 +756,12 @@
 	list_del(&target->d_child);
 
 	/* Switch the parents and the names.. */
+	switch_names(dentry, target);
 	do_switch(dentry->d_parent, target->d_parent);
-	do_switch(dentry->d_name.name, target->d_name.name);
 	do_switch(dentry->d_name.len, target->d_name.len);
 	do_switch(dentry->d_name.hash, target->d_name.hash);
+
+	/* And add them back to the (new) parent lists */
 	list_add(&target->d_child, &target->d_parent->d_subdirs);
 	list_add(&dentry->d_child, &dentry->d_parent->d_subdirs);
 }
@@ -884,6 +919,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 {

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov