Dentries: Stab at movable dentries We should be able to move a dentry if we just fix up all reachable references? (Good luck....). So attempt that approach for the case that we only have a single reference (file). Track down the refs and update the pointers under dcache lock. Warning: This is highly experimental and avoids dealing with subsystems having references to the dentry. Signed-off-by: Christoph Lameter --- fs/dcache.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 7 deletions(-) Index: slub/fs/dcache.c =================================================================== --- slub.orig/fs/dcache.c 2007-05-15 21:47:28.000000000 -0700 +++ slub/fs/dcache.c 2007-05-15 21:49:40.000000000 -0700 @@ -2131,7 +2131,7 @@ static int get_dentry(struct kmem_cache */ if (dentry->d_inode) { dget_locked(dentry); - if (atomic_read(&dentry->d_count) > 2) + if (atomic_read(&dentry->d_count) > 3) result = -EINVAL; } else result = 1; @@ -2146,6 +2146,44 @@ static void put_dentry(struct kmem_cache dput(dentry); } +/* Relocate a dentry. dentry lock is held */ +static struct dentry *move_dentry(struct dentry *d) +{ + struct dentry *n = kmem_cache_alloc(dentry_cache, GFP_KERNEL); + + if (!n) + return d; + + memcpy(n, d, sizeof(struct dentry)); + list_del(&d->d_alias); + list_add(&n->d_alias, &n->d_inode->i_dentry); + + /* + * Hash list. What happens to lookups between + * drop and rehash? + */ + __d_drop(d); + _d_rehash(n); + + /* LRU */ + if (!list_empty(&d->d_lru)) { + list_del_init(&d->d_lru); + list_add(&n->d_lru, &dentry_unused); + } + + /* Subdirs Skip... we do not support dirs for now */ + + /* + * This leaves a long list of dangling pointers. + * fsnotify_d_instantiate? + * integrity_d_instantiate? + * security_d_instantiate? + */ + /* Need to do rcu here ??? */ + kmem_cache_free(dentry_cache, d); + return n; +} + /* * Slab has dropped all the locks. Get rid of the * refcount we obtained earlier and also rid of the @@ -2154,18 +2192,26 @@ static void put_dentry(struct kmem_cache static int kick_dentry(struct kmem_cache *s, void *private) { struct dentry *dentry = private; + int refcount; + int rc; spin_lock(&dcache_lock); spin_lock(&dentry->d_lock); - if (atomic_read(&dentry->d_count) > 1) { - /* - * References still exist. So we cannot - * do anything right now. - */ + refcount = atomic_read(&dentry->d_count); + if (refcount > 1) { + if (refcount > 2) + /* Too high refcount */ + rc = -EBUSY; + else { + /* File. May be able to move dentry */ + dentry = move_dentry(dentry); + rc = 0; + } + spin_unlock(&dentry->d_lock); spin_unlock(&dcache_lock); dput(dentry); - return -EBUSY; + return rc; } /* Remove from LRU */