In message <[EMAIL PROTECTED]>, "Luiz Fernando N. Capitulino" writes:
[...]
>  Yeah, maybe.. But we have to fix that OOPS too.
> 
>  I've captured the backtrace, but I'm not sure what the shutdown
> script is doing when the OOPS happens.
> 
>  I'm still investigating. Should I open a ticket for that one too?
> 
>  The first and last lines of the backtrace are mixed with the output of
> the Mandriva's shutdown script because I was running it with 'bash -x'
> when I got the OOPS.
> 
> """
> BUG: Dentry dc1ad6b8{i=6b5e2,n=} still in use (1) [unmount of nfs 0:15]
> me/ { print $1 }------------[ cut here ]------------

Luiz/Dave,

I was able to reproduce the bug in question: just umount -f an nfs partition
or umount -l any partition that's used as a lower branch, then try to umount
unionfs's mount; you get the exact oops above.  Turns out that grabbing a
vfsmount ref isn't enough: it prevents a casual umount on a lower branch
from succeeding, returning an EBUSY.  But we also needed to grab an s_active
reference on all lower superblocks, to prevent a forced/detached unmount
from destroying the lower super too early.  With the patch below, the lower
super will be detached from the namespace, but it won't be destroyed until
unionfs is mounted: unionfs_put_super will decrement the (possibly last)
reference on the lower super, which'd then be properly destroyed.

Try this patch.  I quickly tried it w/ branch management, umount -l, and my
basic regression suite.  It seems to work, but I'd like to hear from both of
you first before considering this bug fixed.

Thanks,
Erez.


Unionfs: grab lower super_block references

This prevents the lower super_block from being destroyed too early, when a
lower file system is being unmounted with MNT_FORCE or MNT_DETACH.

Signed-off-by: Erez Zadok <[EMAIL PROTECTED]>

diff --git a/fs/unionfs/main.c b/fs/unionfs/main.c
index 23c18f7..ba3471d 100644
--- a/fs/unionfs/main.c
+++ b/fs/unionfs/main.c
@@ -636,6 +636,7 @@ static int unionfs_read_super(struct super_block *sb, void 
*raw_data,
        sbend(sb) = bend = lower_root_info->bend;
        for (bindex = bstart; bindex <= bend; bindex++) {
                struct dentry *d = lower_root_info->lower_paths[bindex].dentry;
+               atomic_inc(&d->d_sb->s_active);
                unionfs_set_lower_super_idx(sb, bindex, d->d_sb);
        }
 
@@ -711,6 +712,8 @@ out_dput:
                        dput(d);
                        /* initializing: can't use unionfs_mntput here */
                        mntput(m);
+                       /* drop refs we took earlier */
+                       atomic_dec(&d->d_sb->s_active);
                }
                kfree(lower_root_info->lower_paths);
                kfree(lower_root_info);
diff --git a/fs/unionfs/super.c b/fs/unionfs/super.c
index 986c980..175840f 100644
--- a/fs/unionfs/super.c
+++ b/fs/unionfs/super.c
@@ -116,6 +116,14 @@ static void unionfs_put_super(struct super_block *sb)
                }
        BUG_ON(leaks != 0);
 
+       /* decrement lower super references */
+       for (bindex = bstart; bindex <= bend; bindex++) {
+               struct super_block *s;
+               s = unionfs_lower_super_idx(sb, bindex);
+               unionfs_set_lower_super_idx(sb, bindex, NULL);
+               atomic_dec(&s->s_active);
+       }
+
        kfree(spd->data);
        kfree(spd);
        sb->s_fs_info = NULL;
@@ -729,6 +737,12 @@ out_no_change:
         */
        purge_sb_data(sb);
 
+       /* grab new lower super references; release old ones */
+       for (i = 0; i < new_branches; i++)
+               atomic_inc(&new_data[i].sb->s_active);
+       for (i = 0; i < new_branches; i++)
+               atomic_dec(&UNIONFS_SB(sb)->data[i].sb->s_active);
+
        /* copy new vectors into their correct place */
        tmp_data = UNIONFS_SB(sb)->data;
        UNIONFS_SB(sb)->data = new_data;
diff --git a/fs/unionfs/union.h b/fs/unionfs/union.h
index 14577bc..ff764d9 100644
--- a/fs/unionfs/union.h
+++ b/fs/unionfs/union.h
@@ -134,7 +134,7 @@ struct unionfs_dentry_info {
 
 /* These are the pointers to our various objects. */
 struct unionfs_data {
-       struct super_block *sb;
+       struct super_block *sb; /* lower super_block */
        atomic_t open_files;    /* number of open files on branch */
        int branchperms;
        int branch_id;          /* unique branch ID at re/mount time */
_______________________________________________
unionfs mailing list: http://unionfs.filesystems.org/
unionfs@mail.fsl.cs.sunysb.edu
http://www.fsl.cs.sunysb.edu/mailman/listinfo/unionfs

Reply via email to