Date:2006-10-11 10:22:19 (15 years 11 months ago)
Author:David Howells
Commit:c636ebdb186bf37f98d3839f69293597723edb36
Message:[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>
Files: fs/dcache.c (1 diff)
fs/super.c (1 diff)
include/linux/dcache.h (1 diff)

Change Details

fs/dcache.c
549549}
550550
551551/*
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/*
552682 * Search for at least 1 mount point in the dentry's subdirs.
553683 * We descend to the next level whenever the d_subdirs
554684 * list is non-empty and continue searching.
fs/super.c
260260 * that need destruction out of superblock, call generic_shutdown_super()
261261 * and release aforementioned objects. Note: dentries and inodes _are_
262262 * 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.
263267 */
264268void generic_shutdown_super(struct super_block *sb)
265269{
266    struct dentry *root = sb->s_root;
267270    struct super_operations *sop = sb->s_op;
268271
269    if (root) {
270        sb->s_root = NULL;
271        shrink_dcache_parent(root);
272        shrink_dcache_sb(sb);
273        dput(root);
272    if (sb->s_root) {
273        shrink_dcache_for_umount(sb);
274274        fsync_super(sb);
275275        lock_super(sb);
276276        sb->s_flags &= ~MS_ACTIVE;
include/linux/dcache.h
230230extern struct dentry * d_splice_alias(struct inode *, struct dentry *);
231231extern void shrink_dcache_sb(struct super_block *);
232232extern void shrink_dcache_parent(struct dentry *);
233extern void shrink_dcache_for_umount(struct super_block *);
233234extern int d_invalidate(struct dentry *);
234235
235236/* only used at mount-time */

Archive Download the corresponding diff file



interactive