X-Git-Url: https://git.openpandora.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=fs%2Fdcache.c;h=d9ca1e5ceb92f02302fdeedb7bc1e2b6e5768f2e;hb=e589665eb97b297412fb16b4c1737a01a91db903;hp=678d39deb60770dffb5cbbbc0de1e84d6e139f36;hpb=efa7e8673c78cc6de2d6c367eb6f50449c57ed90;p=pandora-kernel.git diff --git a/fs/dcache.c b/fs/dcache.c index 678d39deb607..d9ca1e5ceb92 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -38,7 +38,7 @@ int sysctl_vfs_cache_pressure __read_mostly = 100; EXPORT_SYMBOL_GPL(sysctl_vfs_cache_pressure); __cacheline_aligned_in_smp DEFINE_SPINLOCK(dcache_lock); -static __cacheline_aligned_in_smp DEFINE_SEQLOCK(rename_lock); +__cacheline_aligned_in_smp DEFINE_SEQLOCK(rename_lock); EXPORT_SYMBOL(dcache_lock); @@ -381,20 +381,17 @@ restart: * Throw away a dentry - free the inode, dput the parent. This requires that * the LRU list has already been removed. * - * If prune_parents is true, try to prune ancestors as well. + * Try to prune ancestors as well. This is necessary to prevent + * quadratic behavior of shrink_dcache_parent(), but is also expected + * to be beneficial in reducing dentry cache fragmentation. * * Called with dcache_lock, drops it and then regains. * Called with dentry->d_lock held, drops it. */ -static void prune_one_dentry(struct dentry * dentry, int prune_parents) +static void prune_one_dentry(struct dentry * dentry) { __d_drop(dentry); dentry = d_kill(dentry); - if (!prune_parents) { - dput(dentry); - spin_lock(&dcache_lock); - return; - } /* * Prune ancestors. Locking is simpler than in dput(), @@ -422,7 +419,6 @@ static void prune_one_dentry(struct dentry * dentry, int prune_parents) * @count: number of entries to try and free * @sb: if given, ignore dentries for other superblocks * which are being unmounted. - * @prune_parents: if true, try to prune ancestors as well in one go * * Shrink the dcache. This is done when we need * more memory, or simply when we need to unmount @@ -433,7 +429,7 @@ static void prune_one_dentry(struct dentry * dentry, int prune_parents) * all the dentries are in use. */ -static void prune_dcache(int count, struct super_block *sb, int prune_parents) +static void prune_dcache(int count, struct super_block *sb) { spin_lock(&dcache_lock); for (; count ; count--) { @@ -493,7 +489,7 @@ static void prune_dcache(int count, struct super_block *sb, int prune_parents) * without taking the s_umount lock (I already hold it). */ if (sb && dentry->d_sb == sb) { - prune_one_dentry(dentry, prune_parents); + prune_one_dentry(dentry); continue; } /* @@ -508,7 +504,7 @@ static void prune_dcache(int count, struct super_block *sb, int prune_parents) s_umount = &dentry->d_sb->s_umount; if (down_read_trylock(s_umount)) { if (dentry->d_sb->s_root != NULL) { - prune_one_dentry(dentry, prune_parents); + prune_one_dentry(dentry); up_read(s_umount); continue; } @@ -557,18 +553,18 @@ void shrink_dcache_sb(struct super_block * sb) * superblock to the most recent end of the unused list. */ spin_lock(&dcache_lock); - list_for_each_safe(tmp, next, &dentry_unused) { + list_for_each_prev_safe(tmp, next, &dentry_unused) { dentry = list_entry(tmp, struct dentry, d_lru); if (dentry->d_sb != sb) continue; - list_move(tmp, &dentry_unused); + list_move_tail(tmp, &dentry_unused); } /* * Pass two ... free the dentries for this superblock. */ repeat: - list_for_each_safe(tmp, next, &dentry_unused) { + list_for_each_prev_safe(tmp, next, &dentry_unused) { dentry = list_entry(tmp, struct dentry, d_lru); if (dentry->d_sb != sb) continue; @@ -579,7 +575,7 @@ repeat: spin_unlock(&dentry->d_lock); continue; } - prune_one_dentry(dentry, 1); + prune_one_dentry(dentry); cond_resched_lock(&dcache_lock); goto repeat; } @@ -858,7 +854,7 @@ void shrink_dcache_parent(struct dentry * parent) int found; while ((found = select_parent(parent)) != 0) - prune_dcache(found, parent->d_sb, 1); + prune_dcache(found, parent->d_sb); } /* @@ -878,7 +874,7 @@ static int shrink_dcache_memory(int nr, gfp_t gfp_mask) if (nr) { if (!(gfp_mask & __GFP_FS)) return -1; - prune_dcache(nr, NULL, 1); + prune_dcache(nr, NULL); } return (dentry_stat.nr_unused / 100) * sysctl_vfs_cache_pressure; } @@ -903,7 +899,7 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) struct dentry *dentry; char *dname; - dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL); + dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL); if (!dentry) return NULL; @@ -1483,6 +1479,8 @@ static void switch_names(struct dentry *dentry, struct dentry *target) * dentry:internal, target:external. Steal target's * storage and make target internal. */ + memcpy(target->d_iname, dentry->d_name.name, + dentry->d_name.len + 1); dentry->d_name.name = target->d_name.name; target->d_name.name = target->d_iname; } @@ -1514,8 +1512,8 @@ static void switch_names(struct dentry *dentry, struct dentry *target) * This forceful removal will result in ugly /proc output if * somebody holds a file open that got deleted due to a rename. * We could be nicer about the deleted file, and let it show - * up under the name it got deleted rather than the name that - * deleted it. + * up under the name it had before it was deleted rather than + * under the original name of the file that was moved on top of it. */ /* @@ -1546,7 +1544,7 @@ static void d_move_locked(struct dentry * dentry, struct dentry * target) } /* Move the dentry to the target hash queue, if on different bucket */ - if (dentry->d_flags & DCACHE_UNHASHED) + if (d_unhashed(dentry)) goto already_unhashed; hlist_del_rcu(&dentry->d_hash); @@ -2108,7 +2106,7 @@ static void __init dcache_init_early(void) INIT_HLIST_HEAD(&dentry_hashtable[loop]); } -static void __init dcache_init(unsigned long mempages) +static void __init dcache_init(void) { int loop; @@ -2170,10 +2168,10 @@ void __init vfs_caches_init(unsigned long mempages) filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); - dcache_init(mempages); - inode_init(mempages); + dcache_init(); + inode_init(); files_init(mempages); - mnt_init(mempages); + mnt_init(); bdev_cache_init(); chrdev_init(); }