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

aufs: dirwh option



This is a feature to optimize for rmdir and rename dir.
When the number of whiteouts under the target dir is very many, it may
take a long time to remove them all. To prevent this, 'dirwh=%d' option
specifies the watermark to decide when to remove them.

For details, see aufs manual in aufs-util.git.
Signed-off-by: default avatarJ. R. Okajima <hooanon05g@gmail.com>
parent b3b9c456
...@@ -82,6 +82,8 @@ int au_test_empty(struct dentry *dentry, struct au_nhash *whlist); ...@@ -82,6 +82,8 @@ int au_test_empty(struct dentry *dentry, struct au_nhash *whlist);
unsigned int au_rdhash_est(loff_t sz); unsigned int au_rdhash_est(loff_t sz);
int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp); int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp);
void au_nhash_wh_free(struct au_nhash *whlist); void au_nhash_wh_free(struct au_nhash *whlist);
int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt,
int limit);
int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen); int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen);
int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino, int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino,
unsigned int d_type, aufs_bindex_t bindex); unsigned int d_type, aufs_bindex_t bindex);
......
...@@ -206,7 +206,7 @@ out: ...@@ -206,7 +206,7 @@ out:
static int renwh_and_rmdir(struct dentry *dentry, aufs_bindex_t bindex, static int renwh_and_rmdir(struct dentry *dentry, aufs_bindex_t bindex,
struct au_nhash *whlist, struct inode *dir) struct au_nhash *whlist, struct inode *dir)
{ {
int err; int rmdir_later, err, dirwh;
struct dentry *h_dentry; struct dentry *h_dentry;
struct super_block *sb; struct super_block *sb;
struct inode *inode; struct inode *inode;
...@@ -222,6 +222,16 @@ static int renwh_and_rmdir(struct dentry *dentry, aufs_bindex_t bindex, ...@@ -222,6 +222,16 @@ static int renwh_and_rmdir(struct dentry *dentry, aufs_bindex_t bindex,
inode = d_inode(dentry); inode = d_inode(dentry);
au_hn_free(au_hi(inode, bindex)); au_hn_free(au_hi(inode, bindex));
if (!au_test_fs_remote(h_dentry->d_sb)) {
dirwh = au_sbi(sb)->si_dirwh;
rmdir_later = (dirwh <= 1);
if (!rmdir_later)
rmdir_later = au_nhash_test_longer_wh(whlist, bindex,
dirwh);
if (rmdir_later)
return rmdir_later;
}
err = au_whtmp_rmdir(dir, bindex, h_dentry, whlist); err = au_whtmp_rmdir(dir, bindex, h_dentry, whlist);
if (unlikely(err)) { if (unlikely(err)) {
AuIOErr("rmdir %pd, b%d failed, %d. ignored\n", AuIOErr("rmdir %pd, b%d failed, %d. ignored\n",
......
...@@ -238,16 +238,26 @@ static int au_ren_or_cpup(struct au_ren_args *a) ...@@ -238,16 +238,26 @@ static int au_ren_or_cpup(struct au_ren_args *a)
/* cf. aufs_rmdir() */ /* cf. aufs_rmdir() */
static int au_ren_del_whtmp(struct au_ren_args *a) static int au_ren_del_whtmp(struct au_ren_args *a)
{ {
int err;
struct inode *dir; struct inode *dir;
dir = a->dst_dir; dir = a->dst_dir;
SiMustAnyLock(dir->i_sb); SiMustAnyLock(dir->i_sb);
au_nhash_wh_free(&a->thargs->whlist); if (!au_nhash_test_longer_wh(&a->whlist, a->btgt,
a->thargs->whlist = a->whlist; au_sbi(dir->i_sb)->si_dirwh)
a->whlist.nh_num = 0; || au_test_fs_remote(a->h_dst->d_sb)) {
au_whtmp_kick_rmdir(dir, a->btgt, a->h_dst, a->thargs); err = au_whtmp_rmdir(dir, a->btgt, a->h_dst, &a->whlist);
dput(a->h_dst); if (unlikely(err))
a->thargs = NULL; pr_warn("failed removing whtmp dir %pd (%d), "
"ignored.\n", a->h_dst, err);
} else {
au_nhash_wh_free(&a->thargs->whlist);
a->thargs->whlist = a->whlist;
a->whlist.nh_num = 0;
au_whtmp_kick_rmdir(dir, a->btgt, a->h_dst, a->thargs);
dput(a->h_dst);
a->thargs = NULL;
}
return 0; return 0;
} }
......
...@@ -18,7 +18,7 @@ enum { ...@@ -18,7 +18,7 @@ enum {
Opt_br, Opt_br,
Opt_add, Opt_del, Opt_mod, Opt_append, Opt_prepend, Opt_add, Opt_del, Opt_mod, Opt_append, Opt_prepend,
Opt_idel, Opt_imod, Opt_idel, Opt_imod,
Opt_rdcache, Opt_rdblk, Opt_rdhash, Opt_dirwh, 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,
Opt_trunc_xino, Opt_trunc_xino_v, Opt_notrunc_xino, Opt_trunc_xino, Opt_trunc_xino_v, Opt_notrunc_xino,
...@@ -54,6 +54,8 @@ static match_table_t options = { ...@@ -54,6 +54,8 @@ static match_table_t options = {
{Opt_mod, "mod:%s"}, {Opt_mod, "mod:%s"},
/* {Opt_imod, "imod:%d:%s"}, */ /* {Opt_imod, "imod:%d:%s"}, */
{Opt_dirwh, "dirwh=%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"},
...@@ -518,6 +520,9 @@ static void dump_opts(struct au_opts *opts) ...@@ -518,6 +520,9 @@ 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_dirwh:
AuDbg("dirwh %d\n", opt->dirwh);
break;
case Opt_rdcache: case Opt_rdcache:
AuDbg("rdcache %d\n", opt->rdcache); AuDbg("rdcache %d\n", opt->rdcache);
break; break;
...@@ -990,6 +995,13 @@ int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts) ...@@ -990,6 +995,13 @@ int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts)
opt->type = token; opt->type = token;
break; break;
case Opt_dirwh:
if (unlikely(match_int(&a->args[0], &opt->dirwh)))
break;
err = 0;
opt->type = token;
break;
case Opt_rdcache: case Opt_rdcache:
if (unlikely(match_int(&a->args[0], &n))) { if (unlikely(match_int(&a->args[0], &n))) {
pr_err("bad integer in %s\n", opt_str); pr_err("bad integer in %s\n", opt_str);
...@@ -1216,6 +1228,10 @@ static int au_opt_simple(struct super_block *sb, struct au_opt *opt, ...@@ -1216,6 +1228,10 @@ static int au_opt_simple(struct super_block *sb, struct au_opt *opt,
sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + opt->wbr_copyup; sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + opt->wbr_copyup;
break; break;
case Opt_dirwh:
sbinfo->si_dirwh = opt->dirwh;
break;
case Opt_rdcache: case Opt_rdcache:
sbinfo->si_rdcache sbinfo->si_rdcache
= msecs_to_jiffies(opt->rdcache * MSEC_PER_SEC); = msecs_to_jiffies(opt->rdcache * MSEC_PER_SEC);
......
...@@ -138,6 +138,7 @@ struct au_opt { ...@@ -138,6 +138,7 @@ struct au_opt {
struct au_opt_add add; struct au_opt_add add;
struct au_opt_del del; struct au_opt_del del;
struct au_opt_mod mod; struct au_opt_mod mod;
int dirwh;
int rdcache; int rdcache;
unsigned int rdblk; unsigned int rdblk;
unsigned int rdhash; unsigned int rdhash;
......
...@@ -88,6 +88,7 @@ int au_si_alloc(struct super_block *sb) ...@@ -88,6 +88,7 @@ int au_si_alloc(struct super_block *sb)
sbinfo->si_rdcache = msecs_to_jiffies(AUFS_RDCACHE_DEF * MSEC_PER_SEC); sbinfo->si_rdcache = msecs_to_jiffies(AUFS_RDCACHE_DEF * MSEC_PER_SEC);
sbinfo->si_rdblk = AUFS_RDBLK_DEF; sbinfo->si_rdblk = AUFS_RDBLK_DEF;
sbinfo->si_rdhash = AUFS_RDHASH_DEF; sbinfo->si_rdhash = AUFS_RDHASH_DEF;
sbinfo->si_dirwh = AUFS_DIRWH_DEF;
for (i = 0; i < AuPlink_NHASH; i++) for (i = 0; i < AuPlink_NHASH; i++)
INIT_HLIST_BL_HEAD(sbinfo->si_plink + i); INIT_HLIST_BL_HEAD(sbinfo->si_plink + i);
......
...@@ -268,6 +268,8 @@ static int aufs_show_options(struct seq_file *m, struct dentry *dentry) ...@@ -268,6 +268,8 @@ static int aufs_show_options(struct seq_file *m, struct dentry *dentry)
if (v != AuWbrCopyup_Def) if (v != AuWbrCopyup_Def)
seq_printf(m, ",cpup=%s", au_optstr_wbr_copyup(v)); seq_printf(m, ",cpup=%s", au_optstr_wbr_copyup(v));
AuUInt(DIRWH, dirwh, sbinfo->si_dirwh);
v = jiffies_to_msecs(sbinfo->si_rdcache) / MSEC_PER_SEC; v = jiffies_to_msecs(sbinfo->si_rdcache) / MSEC_PER_SEC;
AuUInt(RDCACHE, rdcache, v); AuUInt(RDCACHE, rdcache, v);
......
...@@ -130,6 +130,14 @@ struct au_sbinfo { ...@@ -130,6 +130,14 @@ struct au_sbinfo {
unsigned int si_rdblk; /* deblk size */ unsigned int si_rdblk; /* deblk size */
unsigned int si_rdhash; /* hash size */ unsigned int si_rdhash; /* hash size */
/*
* If the number of whiteouts are larger than si_dirwh, leave all of
* them after au_whtmp_ren to reduce the cost of rmdir(2).
* future fsck.aufs or kernel thread will remove them later.
* Otherwise, remove all whiteouts and the dir in rmdir(2).
*/
unsigned int si_dirwh;
/* pseudo_link list */ /* pseudo_link list */
struct hlist_bl_head si_plink[AuPlink_NHASH]; struct hlist_bl_head si_plink[AuPlink_NHASH];
wait_queue_head_t si_plink_wq; wait_queue_head_t si_plink_wq;
......
...@@ -141,6 +141,24 @@ static void au_nhash_de_free(struct au_nhash *delist) ...@@ -141,6 +141,24 @@ static void au_nhash_de_free(struct au_nhash *delist)
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt,
int limit)
{
int num;
unsigned int u, n;
struct hlist_head *head;
struct au_vdir_wh *pos;
num = 0;
n = whlist->nh_num;
head = whlist->nh_head;
for (u = 0; u < n; u++, head++)
hlist_for_each_entry(pos, head, wh_hash)
if (pos->wh_bindex == btgt && ++num > limit)
return 1;
return 0;
}
static struct hlist_head *au_name_hash(struct au_nhash *nhash, static struct hlist_head *au_name_hash(struct au_nhash *nhash,
unsigned char *name, unsigned char *name,
unsigned int len) unsigned int len)
......
...@@ -73,6 +73,7 @@ typedef int16_t aufs_bindex_t; ...@@ -73,6 +73,7 @@ typedef int16_t aufs_bindex_t;
#define AUFS_XINO_DEFPATH "/tmp/" AUFS_XINO_FNAME #define AUFS_XINO_DEFPATH "/tmp/" AUFS_XINO_FNAME
#define AUFS_XINO_DEF_SEC 30 /* seconds */ #define AUFS_XINO_DEF_SEC 30 /* seconds */
#define AUFS_XINO_DEF_TRUNC 45 /* percentage */ #define AUFS_XINO_DEF_TRUNC 45 /* percentage */
#define AUFS_DIRWH_DEF 3
#define AUFS_RDCACHE_DEF 10 /* seconds */ #define AUFS_RDCACHE_DEF 10 /* seconds */
#define AUFS_RDCACHE_MAX 3600 /* seconds */ #define AUFS_RDCACHE_MAX 3600 /* seconds */
#define AUFS_RDBLK_DEF 512 /* bytes */ #define AUFS_RDBLK_DEF 512 /* bytes */
......
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