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)
* 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,
aufs_bindex_t bbot)
{
......@@ -576,7 +582,7 @@ static int au_test_dbusy(struct dentry *dentry, aufs_bindex_t btop,
* test if the branch is deletable or not.
*/
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;
aufs_bindex_t btop, bbot;
......@@ -626,6 +632,7 @@ static int test_dentry_busy(struct dentry *root, aufs_bindex_t bindex,
&& au_h_dptr(d, bindex)
&& au_test_dbusy(d, btop, bbot)) {
err = -EBUSY;
AuVerbose(verbose, "busy %pd\n", d);
AuDbgDentry(d);
}
di_read_unlock(d, AuLock_IR);
......@@ -639,7 +646,7 @@ out:
}
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;
unsigned long long max, ull;
......@@ -682,6 +689,7 @@ static int test_inode_busy(struct super_block *sb, aufs_bindex_t bindex,
&& au_h_iptr(i, bindex)
&& au_test_ibusy(i, btop, bbot)) {
err = -EBUSY;
AuVerbose(verbose, "busy i%lu\n", i->i_ino);
AuDbgInode(i);
}
ii_read_unlock(i);
......@@ -692,7 +700,8 @@ out:
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;
unsigned int sigen;
......@@ -701,9 +710,9 @@ static int test_children_busy(struct dentry *root, aufs_bindex_t bindex)
DiMustNoWaiters(root);
IiMustNoWaiters(d_inode(root));
di_write_unlock(root);
err = test_dentry_busy(root, bindex, sigen);
err = test_dentry_busy(root, bindex, sigen, verbose);
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() */
return err;
......@@ -941,7 +950,7 @@ int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount)
unsigned long long opened;
unsigned int mnt_flags;
aufs_bindex_t bindex, bbot, br_id;
unsigned char do_wh;
unsigned char do_wh, verbose;
struct au_branch *br;
struct au_wbr *wbr;
struct dentry *root;
......@@ -963,13 +972,19 @@ int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount)
err = -EBUSY;
mnt_flags = au_mntflags(sb);
verbose = !!au_opt_test(mnt_flags, VERBOSE);
bbot = au_sbbot(sb);
if (unlikely(!bbot))
if (unlikely(!bbot)) {
AuVerbose(verbose, "no more branches left\n");
goto out;
}
br = au_sbr(sb, bindex);
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;
}
br_id = br->br_id;
opened = au_lcnt_read(&br->br_nfiles, /*do_rev*/1);
......@@ -980,9 +995,11 @@ int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount)
goto out;
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;
}
}
wbr = br->br_wbr;
do_wh = wbr && (wbr->wbr_whbase || wbr->wbr_plink || wbr->wbr_orph);
......@@ -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 (do_wh)
goto out_wh;
......
......@@ -210,9 +210,7 @@ int cpup_iattr(struct dentry *dst, aufs_bindex_t bindex, struct dentry *h_src,
icex = br->br_perm & AuBrAttr_ICEX;
if (!err) {
mnt_flags = au_mntflags(dst->d_sb);
/* re-commit later */
/* verbose = !!au_opt_test(mnt_flags, VERBOSE); */
verbose = 0;
verbose = !!au_opt_test(mnt_flags, VERBOSE);
err = au_cpup_xattr(h_path.dentry, h_src, icex, verbose);
}
......
......@@ -16,7 +16,8 @@
enum {
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_rdblk_def, Opt_rdhash_def,
Opt_xino, Opt_noxino,
......@@ -27,6 +28,7 @@ enum {
Opt_udba,
Opt_dio, Opt_nodio,
Opt_wbr_copyup, Opt_wbr_create,
Opt_verbose, Opt_noverbose,
Opt_acl, Opt_noacl,
Opt_tail, Opt_ignore, Opt_ignore_silent, Opt_err
};
......@@ -44,6 +46,10 @@ static match_table_t options = {
{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_noxino, "noxino"},
{Opt_trunc_xino, "trunc_xino"},
......@@ -72,6 +78,13 @@ static match_table_t options = {
{Opt_dio, "dio"},
{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_rdblk, "rdblk=%d"},
{Opt_rdblk_def, "rdblk=def"},
......@@ -457,6 +470,7 @@ static void dump_opts(struct au_opts *opts)
/* reduce stack space */
union {
struct au_opt_add *add;
struct au_opt_del *del;
struct au_opt_xino *xino;
struct au_opt_xino_itrunc *xino_itrunc;
struct au_opt_wbr_create *create;
......@@ -472,6 +486,12 @@ static void dump_opts(struct au_opts *opts)
u.add->bindex, u.add->pathname, u.add->perm,
u.add->path.dentry);
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:
u.add = &opt->add;
AuDbg("append {b%d, %s, 0x%x, %p}\n",
......@@ -542,6 +562,12 @@ static void dump_opts(struct au_opts *opts)
case Opt_nodio:
AuLabel(nodio);
break;
case Opt_verbose:
AuLabel(verbose);
break;
case Opt_noverbose:
AuLabel(noverbose);
break;
case Opt_wbr_create:
u.create = &opt->wbr_create;
AuDbg("create %d, %s\n", u.create->wbr_create,
......@@ -595,6 +621,10 @@ void au_opts_free(struct au_opts *opts)
case Opt_prepend:
path_put(&opt->add.path);
break;
case Opt_del:
case Opt_idel:
path_put(&opt->del.h_path);
break;
case Opt_xino:
fput(opt->xino.file);
break;
......@@ -639,6 +669,45 @@ out:
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,
substring_t args[])
{
......@@ -774,7 +843,23 @@ int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts)
if (!err)
opt->type = token;
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:
err = au_opts_parse_xino(sb, &opt->xino, a->args);
if (!err)
......@@ -859,6 +944,8 @@ int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts)
case Opt_list_plink:
case Opt_dio:
case Opt_nodio:
case Opt_verbose:
case Opt_noverbose:
case Opt_rdblk_def:
case Opt_rdhash_def:
case Opt_acl:
......@@ -1013,6 +1100,13 @@ static int au_opt_simple(struct super_block *sb, struct au_opt *opt,
au_fset_opts(opts->flags, REFRESH_DYAOP);
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:
err = au_opt_wbr_create(sb, &opt->wbr_create);
break;
......@@ -1104,6 +1198,17 @@ static int au_opt_br(struct super_block *sb, struct au_opt *opt,
au_fset_opts(opts->flags, REFRESH);
}
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;
}
......
......@@ -26,6 +26,7 @@ struct file;
#define AuOpt_UDBA_REVAL (1 << 3)
#define AuOpt_UDBA_HNOTIFY (1 << 4)
#define AuOpt_PLINK (1 << 6) /* pseudo-link */
#define AuOpt_VERBOSE (1 << 13) /* print the cause of error */
#define AuOpt_DIO (1 << 14) /* direct io */
#ifndef CONFIG_AUFS_HNOTIFY
......@@ -125,6 +126,7 @@ struct au_opt {
struct au_opt_xino xino;
struct au_opt_xino_itrunc xino_itrunc;
struct au_opt_add add;
struct au_opt_del del;
int rdcache;
unsigned int rdblk;
unsigned int rdhash;
......
......@@ -273,6 +273,8 @@ static int aufs_show_options(struct seq_file *m, struct dentry *dentry)
AuUInt(RDBLK, rdblk, sbinfo->si_rdblk);
AuUInt(RDHASH, rdhash, sbinfo->si_rdhash);
AuBool(VERBOSE, verbose);
out:
/* be sure to print "br:" last */
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