Tomas M: > The 'umount /squashfs' part sometimes causes the error message > "VFS: Busy inodes after unmount loop* ... etc", so I _think_ the loop :::
About this problem, please test this patch. > Hm it's hard :) My problem is that I usually can't reproduce it in a > normal Linux environment, I'm still finding these things in Slax, which > is a chrooted OS and makes things hard to debug. > > Nevertheless, you can download Slax from here > http://www.slax.org/dl/slax6broken.iso I will try after your uploading completes. > >> I tried the patch you sent me, but it does nothing, or I can't see any > >> output in dmesg after remount,del, I'm sorry. > > > > And EBUSY error returned? > > Then it means, > > - one or more files were opened on that branch. > > This is possible but i'm unable to say, I don't know. > I hope the feature to see this info through /sys > will be implemented soon :) Basically, /sys/fs/aufs/xxxx/opened_files will be equivalent to lsof. And then EBUSY is not depends upon only the opened files. You wrote that lsof reported /dev/initctl was opened. Are your sure that the device file is NOT inside aufs? If a process (init or something) invoked before you over-mount /dev, the process still refers the device file. Junjiro Okajima ---------------------------------------------------------------------- diff -x CVS -x RCS -x .pdiff -rup ../../aufs.anon/aufs/fs/aufs/opts.c ./fs/aufs/opts.c --- ../../aufs.anon/aufs/fs/aufs/opts.c 2007-06-18 10:51:10.000000000 +0900 +++ ./fs/aufs/opts.c 2007-06-19 15:24:33.679360152 +0900 @@ -764,7 +764,7 @@ static int au_do_opt_simple(struct super * minus: error */ static int au_do_opt_br(struct super_block *sb, struct opt *opt, int remount, - int *do_refresh) + int *do_refresh, int *deleted) { int err; @@ -790,7 +790,7 @@ static int au_do_opt_br(struct super_blo case Opt_idel: err = br_del(sb, &opt->del, remount); if (!err) - *do_refresh = err = 1; + *deleted = *do_refresh = err = 1; break; case Opt_mod: @@ -906,7 +906,7 @@ static int verify_opts(struct super_bloc int au_do_opts_mount(struct super_block *sb, struct opts *opts) { - int err, do_refresh; + int err, do_refresh, deleted; struct inode *dir; struct opt *opt; unsigned int flags, given; @@ -935,10 +935,11 @@ int au_do_opts_mount(struct super_block au_flag_clr(sb, AuFlag_XINO | AuFlag_DLGT); udba_set(sb, AuFlag_UDBA_REVAL); - do_refresh = 0; + deleted = do_refresh = 0; opt = opts->opt; while (err >= 0 && opt->type != Opt_tail) - err = au_do_opt_br(sb, opt++, /*remount*/0, &do_refresh); + err = au_do_opt_br(sb, opt++, /*remount*/0, &do_refresh, + &deleted); if (err > 0) err = 0; else if (unlikely(err < 0)) @@ -996,7 +997,7 @@ int au_do_opts_mount(struct super_block } int au_do_opts_remount(struct super_block *sb, struct opts *opts, - int *do_refresh, unsigned int *given) + int *do_refresh, unsigned int *given, int *deleted) { int err, rerr; struct inode *dir; @@ -1012,7 +1013,7 @@ int au_do_opts_remount(struct super_bloc //AuDebugOn(au_flag_test(sb, AuFlag_UDBA_INOTIFY)); err = 0; - *do_refresh = 0; + *deleted = *do_refresh = 0; *given = 0; dlgt = au_flag_test(sb, AuFlag_DLGT); opt_xino = NULL; @@ -1025,7 +1026,8 @@ int au_do_opts_remount(struct super_bloc au_flag_clr(sb, AuFlag_DLGT); if (!err) - err = au_do_opt_br(sb, opt, /*remount*/1, do_refresh); + err = au_do_opt_br(sb, opt, /*remount*/1, do_refresh, + deleted); if (!err) err = au_do_opt_xino(sb, opt, /*remount*/1, &opt_xino); diff -x CVS -x RCS -x .pdiff -rup ../../aufs.anon/aufs/fs/aufs/opts.h ./fs/aufs/opts.h --- ../../aufs.anon/aufs/fs/aufs/opts.h 2007-06-18 10:51:10.000000000 +0900 +++ ./fs/aufs/opts.h 2007-06-19 15:38:47.967488616 +0900 @@ -90,7 +90,7 @@ void au_free_opts(struct opts *opts); int au_parse_opts(struct super_block *sb, char *str, struct opts *opts); int au_do_opts_mount(struct super_block *sb, struct opts *opts); int au_do_opts_remount(struct super_block *sb, struct opts *opts, - int *do_refresh, unsigned int *given); + int *do_refresh, unsigned int *given, int *deleted); #endif /* __KERNEL__ */ #endif /* __AUFS_OPTS_H__ */ diff -x CVS -x RCS -x .pdiff -rup ../../aufs.anon/aufs/fs/aufs/super.c ./fs/aufs/super.c --- ../../aufs.anon/aufs/fs/aufs/super.c 2007-06-18 10:53:21.000000000 +0900 +++ ./fs/aufs/super.c 2007-06-19 15:40:42.172126872 +0900 @@ -432,6 +432,66 @@ static int refresh_dir(struct dentry *ro return err; } +static int test_nondir(struct dentry *dentry, void *arg) +{ + return !S_ISDIR(dentry->d_inode->i_mode); +} + +static int refresh_nondir(struct dentry *root, int sgen) +{ + int err, i, j, ndentry; + struct au_dcsub_pages dpages; + struct au_dpage *dpage; + struct dentry **dentries; + struct dentry *parent; + struct inode *inode; + + LKTRTrace("sgen %d\n", sgen); + SiMustWriteLock(root->d_sb); + AuDebugOn(au_digen(root) != sgen); + DiMustWriteLock(root); + + err = au_dpages_init(&dpages, GFP_KERNEL); + if (unlikely(err)) + goto out; + err = au_dcsub_pages(&dpages, root, test_nondir, NULL); + if (unlikely(err)) + goto out_dpages; + + for (i = 0; !err && i < dpages.ndpage; i++) { + dpage = dpages.dpages + i; + dentries = dpage->dentries; + ndentry = dpage->ndentry; + for (j = 0; !err && j < ndentry; j++) { + struct dentry *d; + d = dentries[j]; + if (d->d_inode && au_digen(d) != sgen) { + di_write_lock_child(d); + inode = d->d_inode; + parent = dget_parent(d); + AuDebugOn(S_ISDIR(inode->i_mode) + || au_digen(parent) != sgen); + di_read_lock_parent(parent, AUFS_I_RLOCK); + /* returns a number of positive dentries */ + err = au_refresh_hdentry(d, inode->i_mode & S_IFMT); + //err = -1; + if (err >= 0) + err = au_refresh_hinode(inode, d); + //err = -1; + di_read_unlock(parent, AUFS_I_RLOCK); + dput(parent); + di_write_unlock(d); + } + } + } + + out_dpages: + au_dpages_free(&dpages); + out: + TraceErr(err); + return err; +} + /* stop extra interpretation of errno in mount(8), and strange error messages */ static int cvt_err(int err) { @@ -450,7 +510,7 @@ static int cvt_err(int err) /* protected by s_umount */ static int aufs_remount_fs(struct super_block *sb, int *flags, char *data) { - int err, do_refresh; + int err, do_refresh, deleted; struct dentry *root; struct inode *inode; struct opts opts; @@ -498,9 +558,9 @@ static int aufs_remount_fs(struct super_ //DbgSleep(3); /* au_do_opts() may return an error */ - do_refresh = 0; + deleted = do_refresh = 0; given = 0; - err = au_do_opts_remount(sb, &opts, &do_refresh, &given); + err = au_do_opts_remount(sb, &opts, &do_refresh, &given, &deleted); //if (LktrCond) err = -1; au_free_opts(&opts); @@ -513,7 +573,14 @@ static int aufs_remount_fs(struct super_ au_reset_hinotify(inode, au_hi_flags(inode, /*isdir*/1)); sbinfo->si_failed_refresh_dirs = 0; rerr = refresh_dir(root, au_sigen(sb)); - if (unlikely(rerr)) { + if (!rerr) { + if (unlikely(deleted)) { + rerr = refresh_nondir(root, au_sigen(sb)); + if (unlikely(rerr)) + Warn("Refreshing non-directories failed," + " ignores (%d)\n", rerr); + } + } else { sbinfo->si_failed_refresh_dirs = 1; Warn("Refreshing directories failed, ignores (%d)\n", rerr); ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/