--- fs/dcache.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 68 insertions(+), 7 deletions(-) Index: slub/fs/dcache.c =================================================================== --- slub.orig/fs/dcache.c 2007-06-04 21:27:29.000000000 -0700 +++ slub/fs/dcache.c 2007-06-04 21:27:33.000000000 -0700 @@ -2114,14 +2114,67 @@ static void __init dcache_init_early(voi * to a different memory locations * * Called with dcache_lock held. - * - * return 1 for success and 0 for failure. - * - * If we fail then we should not drop the reference count. */ -static int move_or_reclaim_dentry(struct dentry *d) +static struct dentry *move_or_reclaim_dentry(struct dentry *old, + struct dentry *new) { - return 0; + count = atomic_read(&old->d_count); + if (count == 1) { + /* + * Unused entry. Simply throw it away. + * dget_locked() already took it off the LRU. + * The d_count is one but that does not bother any + * of the free functions. + */ + prune_one_dentry(old, 1); + d_free(new); + return NULL; + } + + BUG_ON(!old->d_inode); + /* Make lookups cycle if they find nothing */ + write_seqlock(&rename_lock); + spin_lock(&old->d_lock); + __d_drop(old); + new->d_time = old->d_time; + new->d_op = old->d_op; + new->d_sb = old->s_sb; +#ifdef CONFIG_PROFILING + new->d_cookie = old->d_cookie; +#endif + new->d_mounted = old->d_mounted; + memcpy(new->name, old->name, sizeof(struct qstr)); + /* + * The old dentry is now invisible and d_lookup may be cycling in a loop + */ + new->d_inode = old->d_inode; + atomic_inc(new->d_count); + list_add(new, inode->i_dentry); + list_del(old->d_inode); + + /* Deal with parents */ + if (parent) { + list_add(&new->d_u.d_child, &parent->d_subdirs); + list_del(&old->d_u.d_child); + } + + /* Deal with children */ + + /* Move contents */ + /* Make name visible again */ + _d_rehash(new); + seq_sequnlock(&rename_lock); + if (qstr_equal(d->name, new->name) && atomic_read(&d->d_count) == 0) { + free(d); + return new; + } + + /* Failed there are links remaining or the file was renamed */ + /* Reestablish links */ + d_free(new); + + + return old; } /* @@ -2161,18 +2214,24 @@ static void kick_dentries(struct kmem_ca struct dentry *dentry; int abort = 0; int i; + struct new_dentries *new[nr]; + + for (i = 0; i < nr; i++) + if (v[i]) + new[i] = d_alloc(NULL, &anonstring); spin_lock(&dcache_lock); for (i = 0; i < nr; i++) { dentry = v[i]; + if (!dentry) continue; if (abort) goto abort_next; - if (move_or_reclaim_dentry(dentry)) + if (move_or_reclaim_dentry(dentry, new[i]) != dentry) /* Successfully moved object */ continue; @@ -2184,6 +2243,8 @@ static void kick_dentries(struct kmem_ca abort = 1; spin_unlock(&dcache_lock); abort_next: + if (new[i]) + d_free(new[i]); dput(dentry); }