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