Re: Strange interrupt behaviour

Andi Kleen (ak@muc.de)
Sun, 12 Jul 1998 20:40:23 +0200


On Sun, Jul 12, 1998 at 07:09:20PM +0200, Andi Kleen wrote:
> On Sun, Jul 12, 1998 at 06:23:30PM +0200, Linus Torvalds wrote:
> > I certainly agree that we might have a 16-byte "default allocation" inside
> > the dentry, and have the name pointer point to that when it is enough.
> > That would work - waste some memory when there are names longer than 16
> > bytes, but those are rare, and it would save memory for the default case
> > by having just one allocation.
> >
> > Andi, do you want to look into this?
>
> My kernel already runs with this :), so expect a patch soon.
>
> I have just to verify that it does the right thing in the rename case.

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