Commit dea1d77c authored by J. R. Okajima's avatar J. R. Okajima
Browse files

aufs: branch management, delete 3/3, mount option



Implement the user interface.
Since users often wonder "Why I cannot delete this branch?", 'verbose'
option was introduced.

You may think aufs should not hold several strings for the variation of
the option, and the mount helper (/sbin/mount.aufs) can convert all
variations to a single fixed string, and in kernel space aufs should
contain this only one string.
I agree, but in our real world, many users don't install
/sbin/mount.aufs. To be convenient, aufs contains these variations.
Signed-off-by: default avatarJ. R. Okajima <hooanon05g@gmail.com>
parent b79632ef
...@@ -560,6 +560,12 @@ static void au_farray_free(struct file **a, unsigned long long max) ...@@ -560,6 +560,12 @@ static void au_farray_free(struct file **a, unsigned long long max)
* delete a branch * delete a branch
*/ */
/* to show the line number, do not make it inlined function */
#define AuVerbose(do_info, fmt, ...) do { \
if (do_info) \
pr_info(fmt, ##__VA_ARGS__); \
} while (0)
static int au_test_ibusy(struct inode *inode, aufs_bindex_t btop, static int au_test_ibusy(struct inode *inode, aufs_bindex_t btop,
aufs_bindex_t bbot) aufs_bindex_t bbot)
{ {
...@@ -576,7 +582,7 @@ static int au_test_dbusy(struct dentry *dentry, aufs_bindex_t btop, ...@@ -576,7 +582,7 @@ static int au_test_dbusy(struct dentry *dentry, aufs_bindex_t btop,
* test if the branch is deletable or not. * test if the branch is deletable or not.
*/ */
static int test_dentry_busy(struct dentry *root, aufs_bindex_t bindex, static int test_dentry_busy(struct dentry *root, aufs_bindex_t bindex,
unsigned int sigen) unsigned int sigen, const unsigned int verbose)
{ {
int err, i, j, ndentry; int err, i, j, ndentry;
aufs_bindex_t btop, bbot; aufs_bindex_t btop, bbot;
...@@ -626,6 +632,7 @@ static int test_dentry_busy(struct dentry *root, aufs_bindex_t bindex, ...@@ -626,6 +632,7 @@ static int test_dentry_busy(struct dentry *root, aufs_bindex_t bindex,
&& au_h_dptr(d, bindex) && au_h_dptr(d, bindex)
&& au_test_dbusy(d, btop, bbot)) { && au_test_dbusy(d, btop, bbot)) {
err = -EBUSY; err = -EBUSY;
AuVerbose(verbose, "busy %pd\n", d);
AuDbgDentry(d); AuDbgDentry(d);
} }
di_read_unlock(d, AuLock_IR); di_read_unlock(d, AuLock_IR);
...@@ -639,7 +646,7 @@ out: ...@@ -639,7 +646,7 @@ out:
} }
static int test_inode_busy(struct super_block *sb, aufs_bindex_t bindex, static int test_inode_busy(struct super_block *sb, aufs_bindex_t bindex,
unsigned int sigen) unsigned int sigen, const unsigned int verbose)
{ {
int err; int err;
unsigned long long max, ull; unsigned long long max, ull;
...@@ -682,6 +689,7 @@ static int test_inode_busy(struct super_block *sb, aufs_bindex_t bindex, ...@@ -682,6 +689,7 @@ static int test_inode_busy(struct super_block *sb, aufs_bindex_t bindex,
&& au_h_iptr(i, bindex) && au_h_iptr(i, bindex)
&& au_test_ibusy(i, btop, bbot)) { && au_test_ibusy(i, btop, bbot)) {
err = -EBUSY; err = -EBUSY;
AuVerbose(verbose, "busy i%lu\n", i->i_ino);
AuDbgInode(i); AuDbgInode(i);
} }
ii_read_unlock(i); ii_read_unlock(i);
...@@ -692,7 +700,8 @@ out: ...@@ -692,7 +700,8 @@ out:
return err; return err;
} }
static int test_children_busy(struct dentry *root, aufs_bindex_t bindex) static int test_children_busy(struct dentry *root, aufs_bindex_t bindex,
const unsigned int verbose)
{ {
int err; int err;
unsigned int sigen; unsigned int sigen;
...@@ -701,9 +710,9 @@ static int test_children_busy(struct dentry *root, aufs_bindex_t bindex) ...@@ -701,9 +710,9 @@ static int test_children_busy(struct dentry *root, aufs_bindex_t bindex)
DiMustNoWaiters(root); DiMustNoWaiters(root);
IiMustNoWaiters(d_inode(root)); IiMustNoWaiters(d_inode(root));
di_write_unlock(root); di_write_unlock(root);
err = test_dentry_busy(root, bindex, sigen); err = test_dentry_busy(root, bindex, sigen, verbose);
if (!err) if (!err)
err = test_inode_busy(root->d_sb, bindex, sigen); err = test_inode_busy(root->d_sb, bindex, sigen, verbose);
di_write_lock_child(root); /* aufs_write_lock() calls ..._child() */ di_write_lock_child(root); /* aufs_write_lock() calls ..._child() */
return err; return err;
...@@ -941,7 +950,7 @@ int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount) ...@@ -941,7 +950,7 @@ int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount)
unsigned long long opened; unsigned long long opened;
unsigned int mnt_flags; unsigned int mnt_flags;
aufs_bindex_t bindex, bbot, br_id; aufs_bindex_t bindex, bbot, br_id;
unsigned char do_wh; unsigned char do_wh, verbose;
struct au_branch *br; struct au_branch *br;
struct au_wbr *wbr; struct au_wbr *wbr;
struct dentry *root; struct dentry *root;
...@@ -963,13 +972,19 @@ int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount) ...@@ -963,13 +972,19 @@ int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount)
err = -EBUSY; err = -EBUSY;
mnt_flags = au_mntflags(sb); mnt_flags = au_mntflags(sb);
verbose = !!au_opt_test(mnt_flags, VERBOSE);
bbot = au_sbbot(sb); bbot = au_sbbot(sb);
if (unlikely(!bbot)) if (unlikely(!bbot)) {
AuVerbose(verbose, "no more branches left\n");
goto out; goto out;
}
br = au_sbr(sb, bindex); br = au_sbr(sb, bindex);
AuDebugOn(!path_equal(&br->br_path, &del->h_path)); AuDebugOn(!path_equal(&br->br_path, &del->h_path));
if (unlikely(au_lcnt_read(&br->br_count, /*do_rev*/1))) if (unlikely(au_lcnt_read(&br->br_count, /*do_rev*/1))) {
AuVerbose(verbose, "br %pd2 is busy now\n", del->h_path.dentry);
goto out; goto out;
}
br_id = br->br_id; br_id = br->br_id;
opened = au_lcnt_read(&br->br_nfiles, /*do_rev*/1); opened = au_lcnt_read(&br->br_nfiles, /*do_rev*/1);
...@@ -980,8 +995,10 @@ int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount) ...@@ -980,8 +995,10 @@ int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount)
goto out; goto out;
err = test_file_busy(sb, br_id, to_free, opened); err = test_file_busy(sb, br_id, to_free, opened);
if (unlikely(err)) if (unlikely(err)) {
AuVerbose(verbose, "%llu file(s) opened\n", opened);
goto out; goto out;
}
} }
wbr = br->br_wbr; wbr = br->br_wbr;
...@@ -995,7 +1012,7 @@ int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount) ...@@ -995,7 +1012,7 @@ int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount)
} }
} }
err = test_children_busy(root, bindex); err = test_children_busy(root, bindex, verbose);
if (unlikely(err)) { if (unlikely(err)) {
if (do_wh) if (do_wh)
goto out_wh; goto out_wh;
......
...@@ -210,9 +210,7 @@ int cpup_iattr(struct dentry *dst, aufs_bindex_t bindex, struct dentry *h_src, ...@@ -210,9 +210,7 @@ int cpup_iattr(struct dentry *dst, aufs_bindex_t bindex, struct dentry *h_src,
icex = br->br_perm & AuBrAttr_ICEX; icex = br->br_perm & AuBrAttr_ICEX;
if (!err) { if (!err) {
mnt_flags = au_mntflags(dst->d_sb); mnt_flags = au_mntflags(dst->d_sb);
/* re-commit later */ verbose = !!au_opt_test(mnt_flags, VERBOSE);
/* verbose = !!au_opt_test(mnt_flags, VERBOSE); */
verbose = 0;
err = au_cpup_xattr(h_path.dentry, h_src, icex, verbose); err = au_cpup_xattr(h_path.dentry, h_src, icex, verbose);
} }
......
...@@ -16,7 +16,8 @@ ...@@ -16,7 +16,8 @@
enum { enum {
Opt_br, Opt_br,
Opt_add, Opt_append, Opt_prepend, Opt_add, Opt_del, Opt_append, Opt_prepend,
Opt_idel,
Opt_rdcache, Opt_rdblk, Opt_rdhash, Opt_rdcache, Opt_rdblk, Opt_rdhash,
Opt_rdblk_def, Opt_rdhash_def, Opt_rdblk_def, Opt_rdhash_def,
Opt_xino, Opt_noxino, Opt_xino, Opt_noxino,
...@@ -27,6 +28,7 @@ enum { ...@@ -27,6 +28,7 @@ enum {
Opt_udba, Opt_udba,
Opt_dio, Opt_nodio, Opt_dio, Opt_nodio,
Opt_wbr_copyup, Opt_wbr_create, Opt_wbr_copyup, Opt_wbr_create,
Opt_verbose, Opt_noverbose,
Opt_acl, Opt_noacl, Opt_acl, Opt_noacl,
Opt_tail, Opt_ignore, Opt_ignore_silent, Opt_err Opt_tail, Opt_ignore, Opt_ignore_silent, Opt_err
}; };
...@@ -44,6 +46,10 @@ static match_table_t options = { ...@@ -44,6 +46,10 @@ static match_table_t options = {
{Opt_prepend, "prepend=%s"}, {Opt_prepend, "prepend=%s"},
{Opt_prepend, "prepend:%s"}, {Opt_prepend, "prepend:%s"},
{Opt_del, "del=%s"},
{Opt_del, "del:%s"},
/* {Opt_idel, "idel:%d"}, */
{Opt_xino, "xino=%s"}, {Opt_xino, "xino=%s"},
{Opt_noxino, "noxino"}, {Opt_noxino, "noxino"},
{Opt_trunc_xino, "trunc_xino"}, {Opt_trunc_xino, "trunc_xino"},
...@@ -72,6 +78,13 @@ static match_table_t options = { ...@@ -72,6 +78,13 @@ static match_table_t options = {
{Opt_dio, "dio"}, {Opt_dio, "dio"},
{Opt_nodio, "nodio"}, {Opt_nodio, "nodio"},
{Opt_verbose, "verbose"},
{Opt_verbose, "v"},
{Opt_noverbose, "noverbose"},
{Opt_noverbose, "quiet"},
{Opt_noverbose, "q"},
{Opt_noverbose, "silent"},
{Opt_rdcache, "rdcache=%d"}, {Opt_rdcache, "rdcache=%d"},
{Opt_rdblk, "rdblk=%d"}, {Opt_rdblk, "rdblk=%d"},
{Opt_rdblk_def, "rdblk=def"}, {Opt_rdblk_def, "rdblk=def"},
...@@ -457,6 +470,7 @@ static void dump_opts(struct au_opts *opts) ...@@ -457,6 +470,7 @@ static void dump_opts(struct au_opts *opts)
/* reduce stack space */ /* reduce stack space */
union { union {
struct au_opt_add *add; struct au_opt_add *add;
struct au_opt_del *del;
struct au_opt_xino *xino; struct au_opt_xino *xino;
struct au_opt_xino_itrunc *xino_itrunc; struct au_opt_xino_itrunc *xino_itrunc;
struct au_opt_wbr_create *create; struct au_opt_wbr_create *create;
...@@ -472,6 +486,12 @@ static void dump_opts(struct au_opts *opts) ...@@ -472,6 +486,12 @@ static void dump_opts(struct au_opts *opts)
u.add->bindex, u.add->pathname, u.add->perm, u.add->bindex, u.add->pathname, u.add->perm,
u.add->path.dentry); u.add->path.dentry);
break; break;
case Opt_del:
case Opt_idel:
u.del = &opt->del;
AuDbg("del {%s, %p}\n",
u.del->pathname, u.del->h_path.dentry);
break;
case Opt_append: case Opt_append:
u.add = &opt->add; u.add = &opt->add;
AuDbg("append {b%d, %s, 0x%x, %p}\n", AuDbg("append {b%d, %s, 0x%x, %p}\n",
...@@ -542,6 +562,12 @@ static void dump_opts(struct au_opts *opts) ...@@ -542,6 +562,12 @@ static void dump_opts(struct au_opts *opts)
case Opt_nodio: case Opt_nodio:
AuLabel(nodio); AuLabel(nodio);
break; break;
case Opt_verbose:
AuLabel(verbose);
break;
case Opt_noverbose:
AuLabel(noverbose);
break;
case Opt_wbr_create: case Opt_wbr_create:
u.create = &opt->wbr_create; u.create = &opt->wbr_create;
AuDbg("create %d, %s\n", u.create->wbr_create, AuDbg("create %d, %s\n", u.create->wbr_create,
...@@ -595,6 +621,10 @@ void au_opts_free(struct au_opts *opts) ...@@ -595,6 +621,10 @@ void au_opts_free(struct au_opts *opts)
case Opt_prepend: case Opt_prepend:
path_put(&opt->add.path); path_put(&opt->add.path);
break; break;
case Opt_del:
case Opt_idel:
path_put(&opt->del.h_path);
break;
case Opt_xino: case Opt_xino:
fput(opt->xino.file); fput(opt->xino.file);
break; break;
...@@ -639,6 +669,45 @@ out: ...@@ -639,6 +669,45 @@ out:
return err; return err;
} }
static int au_opts_parse_del(struct au_opt_del *del, substring_t args[])
{
int err;
del->pathname = args[0].from;
AuDbg("del path %s\n", del->pathname);
err = vfsub_kern_path(del->pathname, lkup_dirflags, &del->h_path);
if (unlikely(err))
pr_err("lookup failed %s (%d)\n", del->pathname, err);
return err;
}
#if 0 /* reserved for future use */
static int au_opts_parse_idel(struct super_block *sb, aufs_bindex_t bindex,
struct au_opt_del *del, substring_t args[])
{
int err;
struct dentry *root;
err = -EINVAL;
root = sb->s_root;
aufs_read_lock(root, AuLock_FLUSH);
if (bindex < 0 || au_sbbot(sb) < bindex) {
pr_err("out of bounds, %d\n", bindex);
goto out;
}
err = 0;
del->h_path.dentry = dget(au_h_dptr(root, bindex));
del->h_path.mnt = mntget(au_sbr_mnt(sb, bindex));
out:
aufs_read_unlock(root, !AuLock_IR);
return err;
}
#endif
static int au_opts_parse_xino(struct super_block *sb, struct au_opt_xino *xino, static int au_opts_parse_xino(struct super_block *sb, struct au_opt_xino *xino,
substring_t args[]) substring_t args[])
{ {
...@@ -774,7 +843,23 @@ int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts) ...@@ -774,7 +843,23 @@ int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts)
if (!err) if (!err)
opt->type = token; opt->type = token;
break; break;
case Opt_del:
err = au_opts_parse_del(&opt->del, a->args);
if (!err)
opt->type = token;
break;
#if 0 /* reserved for future use */
case Opt_idel:
del->pathname = "(indexed)";
if (unlikely(match_int(&args[0], &n))) {
pr_err("bad integer in %s\n", opt_str);
break;
}
err = au_opts_parse_idel(sb, n, &opt->del, a->args);
if (!err)
opt->type = token;
break;
#endif
case Opt_xino: case Opt_xino:
err = au_opts_parse_xino(sb, &opt->xino, a->args); err = au_opts_parse_xino(sb, &opt->xino, a->args);
if (!err) if (!err)
...@@ -859,6 +944,8 @@ int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts) ...@@ -859,6 +944,8 @@ int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts)
case Opt_list_plink: case Opt_list_plink:
case Opt_dio: case Opt_dio:
case Opt_nodio: case Opt_nodio:
case Opt_verbose:
case Opt_noverbose:
case Opt_rdblk_def: case Opt_rdblk_def:
case Opt_rdhash_def: case Opt_rdhash_def:
case Opt_acl: case Opt_acl:
...@@ -1013,6 +1100,13 @@ static int au_opt_simple(struct super_block *sb, struct au_opt *opt, ...@@ -1013,6 +1100,13 @@ static int au_opt_simple(struct super_block *sb, struct au_opt *opt,
au_fset_opts(opts->flags, REFRESH_DYAOP); au_fset_opts(opts->flags, REFRESH_DYAOP);
break; break;
case Opt_verbose:
au_opt_set(sbinfo->si_mntflags, VERBOSE);
break;
case Opt_noverbose:
au_opt_clr(sbinfo->si_mntflags, VERBOSE);
break;
case Opt_wbr_create: case Opt_wbr_create:
err = au_opt_wbr_create(sb, &opt->wbr_create); err = au_opt_wbr_create(sb, &opt->wbr_create);
break; break;
...@@ -1104,6 +1198,17 @@ static int au_opt_br(struct super_block *sb, struct au_opt *opt, ...@@ -1104,6 +1198,17 @@ static int au_opt_br(struct super_block *sb, struct au_opt *opt,
au_fset_opts(opts->flags, REFRESH); au_fset_opts(opts->flags, REFRESH);
} }
break; break;
case Opt_del:
case Opt_idel:
err = au_br_del(sb, &opt->del,
au_ftest_opts(opts->flags, REMOUNT));
if (!err) {
err = 1;
au_fset_opts(opts->flags, TRUNC_XIB);
au_fset_opts(opts->flags, REFRESH);
}
break;
} }
return err; return err;
} }
......
...@@ -26,6 +26,7 @@ struct file; ...@@ -26,6 +26,7 @@ struct file;
#define AuOpt_UDBA_REVAL (1 << 3) #define AuOpt_UDBA_REVAL (1 << 3)
#define AuOpt_UDBA_HNOTIFY (1 << 4) #define AuOpt_UDBA_HNOTIFY (1 << 4)
#define AuOpt_PLINK (1 << 6) /* pseudo-link */ #define AuOpt_PLINK (1 << 6) /* pseudo-link */
#define AuOpt_VERBOSE (1 << 13) /* print the cause of error */
#define AuOpt_DIO (1 << 14) /* direct io */ #define AuOpt_DIO (1 << 14) /* direct io */
#ifndef CONFIG_AUFS_HNOTIFY #ifndef CONFIG_AUFS_HNOTIFY
...@@ -125,6 +126,7 @@ struct au_opt { ...@@ -125,6 +126,7 @@ struct au_opt {
struct au_opt_xino xino; struct au_opt_xino xino;
struct au_opt_xino_itrunc xino_itrunc; struct au_opt_xino_itrunc xino_itrunc;
struct au_opt_add add; struct au_opt_add add;
struct au_opt_del del;
int rdcache; int rdcache;
unsigned int rdblk; unsigned int rdblk;
unsigned int rdhash; unsigned int rdhash;
......
...@@ -273,6 +273,8 @@ static int aufs_show_options(struct seq_file *m, struct dentry *dentry) ...@@ -273,6 +273,8 @@ static int aufs_show_options(struct seq_file *m, struct dentry *dentry)
AuUInt(RDBLK, rdblk, sbinfo->si_rdblk); AuUInt(RDBLK, rdblk, sbinfo->si_rdblk);
AuUInt(RDHASH, rdhash, sbinfo->si_rdhash); AuUInt(RDHASH, rdhash, sbinfo->si_rdhash);
AuBool(VERBOSE, verbose);
out: out:
/* be sure to print "br:" last */ /* be sure to print "br:" last */
if (!sysaufs_brs) { if (!sysaufs_brs) {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment