aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2006-10-11 04:22:19 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-11 14:14:25 -0400
commitc636ebdb186bf37f98d3839f69293597723edb36 (patch)
treedb1d54d355cd8030bf5d1645ce6bac8842f32690 /fs
parent6ce315234aefcbc599dea390c15672156ebf9e7b (diff)
[PATCH] VFS: Destroy the dentries contributed by a superblock on unmounting
The attached patch destroys all the dentries attached to a superblock in one go by: (1) Destroying the tree rooted at s_root. (2) Destroying every entry in the anon list, one at a time. (3) Each entry in the anon list has its subtree consumed from the leaves inwards. This reduces the amount of work generic_shutdown_super() does, and avoids iterating through the dentry_unused list. Note that locking is almost entirely absent in the shrink_dcache_for_umount*() functions added by this patch. This is because: (1) at the point the filesystem calls generic_shutdown_super(), it is not permitted to further touch the superblock's set of dentries, and nor may it remove aliases from inodes; (2) the dcache memory shrinker now skips dentries that are being unmounted; and (3) the superblock no longer has any external references through which the VFS can reach it. Given these points, the only locking we need to do is when we remove dentries from the unused list and the name hashes, which we do a directory's worth at a time. We also don't need to guard against reference counts going to zero unexpectedly and removing bits of the tree we're working on as nothing else can call dput(). A cut down version of dentry_iput() has been folded into shrink_dcache_for_umount_subtree() function. Apart from not needing to unlock things, it also doesn't need to check for inotify watches. In this version of the patch, the complaint about a dentry still being in use has been expanded from a single BUG_ON() and now gives much more information. Signed-off-by: David Howells <dhowells@redhat.com> Acked-by: NeilBrown <neilb@suse.de> Acked-by: Ian Kent <raven@themaw.net> Cc: Trond Myklebust <trond.myklebust@fys.uio.no> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/dcache.c130
-rw-r--r--fs/super.c12
2 files changed, 136 insertions, 6 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index 2355bddad8de..2bac4ba1d1d3 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -549,6 +549,136 @@ repeat:
549} 549}
550 550
551/* 551/*
552 * destroy a single subtree of dentries for unmount
553 * - see the comments on shrink_dcache_for_umount() for a description of the
554 * locking
555 */
556static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
557{
558 struct dentry *parent;
559
560 BUG_ON(!IS_ROOT(dentry));
561
562 /* detach this root from the system */
563 spin_lock(&dcache_lock);
564 if (!list_empty(&dentry->d_lru)) {
565 dentry_stat.nr_unused--;
566 list_del_init(&dentry->d_lru);
567 }
568 __d_drop(dentry);
569 spin_unlock(&dcache_lock);
570
571 for (;;) {
572 /* descend to the first leaf in the current subtree */
573 while (!list_empty(&dentry->d_subdirs)) {
574 struct dentry *loop;
575
576 /* this is a branch with children - detach all of them
577 * from the system in one go */
578 spin_lock(&dcache_lock);
579 list_for_each_entry(loop, &dentry->d_subdirs,
580 d_u.d_child) {
581 if (!list_empty(&loop->d_lru)) {
582 dentry_stat.nr_unused--;
583 list_del_init(&loop->d_lru);
584 }
585
586 __d_drop(loop);
587 cond_resched_lock(&dcache_lock);
588 }
589 spin_unlock(&dcache_lock);
590
591 /* move to the first child */
592 dentry = list_entry(dentry->d_subdirs.next,
593 struct dentry, d_u.d_child);
594 }
595
596 /* consume the dentries from this leaf up through its parents
597 * until we find one with children or run out altogether */
598 do {
599 struct inode *inode;
600
601 if (atomic_read(&dentry->d_count) != 0) {
602 printk(KERN_ERR
603 "BUG: Dentry %p{i=%lx,n=%s}"
604 " still in use (%d)"
605 " [unmount of %s %s]\n",
606 dentry,
607 dentry->d_inode ?
608 dentry->d_inode->i_ino : 0UL,
609 dentry->d_name.name,
610 atomic_read(&dentry->d_count),
611 dentry->d_sb->s_type->name,
612 dentry->d_sb->s_id);
613 BUG();
614 }
615
616 parent = dentry->d_parent;
617 if (parent == dentry)
618 parent = NULL;
619 else
620 atomic_dec(&parent->d_count);
621
622 list_del(&dentry->d_u.d_child);
623 dentry_stat.nr_dentry--; /* For d_free, below */
624
625 inode = dentry->d_inode;
626 if (inode) {
627 dentry->d_inode = NULL;
628 list_del_init(&dentry->d_alias);
629 if (dentry->d_op && dentry->d_op->d_iput)
630 dentry->d_op->d_iput(dentry, inode);
631 else
632 iput(inode);
633 }
634
635 d_free(dentry);
636
637 /* finished when we fall off the top of the tree,
638 * otherwise we ascend to the parent and move to the
639 * next sibling if there is one */
640 if (!parent)
641 return;
642
643 dentry = parent;
644
645 } while (list_empty(&dentry->d_subdirs));
646
647 dentry = list_entry(dentry->d_subdirs.next,
648 struct dentry, d_u.d_child);
649 }
650}
651
652/*
653 * destroy the dentries attached to a superblock on unmounting
654 * - we don't need to use dentry->d_lock, and only need dcache_lock when
655 * removing the dentry from the system lists and hashes because:
656 * - the superblock is detached from all mountings and open files, so the
657 * dentry trees will not be rearranged by the VFS
658 * - s_umount is write-locked, so the memory pressure shrinker will ignore
659 * any dentries belonging to this superblock that it comes across
660 * - the filesystem itself is no longer permitted to rearrange the dentries
661 * in this superblock
662 */
663void shrink_dcache_for_umount(struct super_block *sb)
664{
665 struct dentry *dentry;
666
667 if (down_read_trylock(&sb->s_umount))
668 BUG();
669
670 dentry = sb->s_root;
671 sb->s_root = NULL;
672 atomic_dec(&dentry->d_count);
673 shrink_dcache_for_umount_subtree(dentry);
674
675 while (!hlist_empty(&sb->s_anon)) {
676 dentry = hlist_entry(sb->s_anon.first, struct dentry, d_hash);
677 shrink_dcache_for_umount_subtree(dentry);
678 }
679}
680
681/*
552 * Search for at least 1 mount point in the dentry's subdirs. 682 * Search for at least 1 mount point in the dentry's subdirs.
553 * We descend to the next level whenever the d_subdirs 683 * We descend to the next level whenever the d_subdirs
554 * list is non-empty and continue searching. 684 * list is non-empty and continue searching.
diff --git a/fs/super.c b/fs/super.c
index aec99ddbe53f..47e554c12e76 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -260,17 +260,17 @@ int fsync_super(struct super_block *sb)
260 * that need destruction out of superblock, call generic_shutdown_super() 260 * that need destruction out of superblock, call generic_shutdown_super()
261 * and release aforementioned objects. Note: dentries and inodes _are_ 261 * and release aforementioned objects. Note: dentries and inodes _are_
262 * taken care of and do not need specific handling. 262 * taken care of and do not need specific handling.
263 *
264 * Upon calling this function, the filesystem may no longer alter or
265 * rearrange the set of dentries belonging to this super_block, nor may it
266 * change the attachments of dentries to inodes.
263 */ 267 */
264void generic_shutdown_super(struct super_block *sb) 268void generic_shutdown_super(struct super_block *sb)
265{ 269{
266 struct dentry *root = sb->s_root;
267 struct super_operations *sop = sb->s_op; 270 struct super_operations *sop = sb->s_op;
268 271
269 if (root) { 272 if (sb->s_root) {
270 sb->s_root = NULL; 273 shrink_dcache_for_umount(sb);
271 shrink_dcache_parent(root);
272 shrink_dcache_sb(sb);
273 dput(root);
274 fsync_super(sb); 274 fsync_super(sb);
275 lock_super(sb); 275 lock_super(sb);
276 sb->s_flags &= ~MS_ACTIVE; 276 sb->s_flags &= ~MS_ACTIVE;