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

aufs: writable branch select policy 2/2, variations



Several policies to select one among multiple writable branches.
See also the document in previous commit.
Signed-off-by: default avatarJ. R. Okajima <hooanon05g@gmail.com>
parent 60b24eed
...@@ -50,6 +50,9 @@ struct au_wbr { ...@@ -50,6 +50,9 @@ struct au_wbr {
#define wbr_whbase wbr_wh[AuBrWh_BASE] /* whiteout base */ #define wbr_whbase wbr_wh[AuBrWh_BASE] /* whiteout base */
#define wbr_plink wbr_wh[AuBrWh_PLINK] /* pseudo-link dir */ #define wbr_plink wbr_wh[AuBrWh_PLINK] /* pseudo-link dir */
#define wbr_orph wbr_wh[AuBrWh_ORPH] /* dir for orphans */ #define wbr_orph wbr_wh[AuBrWh_ORPH] /* dir for orphans */
/* mfs mode */
unsigned long long wbr_bytes;
}; };
/* sysfs entries */ /* sysfs entries */
......
...@@ -255,19 +255,98 @@ void au_optstr_br_perm(au_br_perm_str_t *str, int perm) ...@@ -255,19 +255,98 @@ void au_optstr_br_perm(au_br_perm_str_t *str, int perm)
static match_table_t au_wbr_create_policy = { static match_table_t au_wbr_create_policy = {
{AuWbrCreate_TDP, "tdp"}, {AuWbrCreate_TDP, "tdp"},
{AuWbrCreate_TDP, "top-down-parent"}, {AuWbrCreate_TDP, "top-down-parent"},
{AuWbrCreate_RR, "rr"},
{AuWbrCreate_RR, "round-robin"},
{AuWbrCreate_MFS, "mfs"},
{AuWbrCreate_MFS, "most-free-space"},
{AuWbrCreate_MFSV, "mfs:%d"},
{AuWbrCreate_MFSV, "most-free-space:%d"},
/* top-down regardless the parent, and then mfs */
{AuWbrCreate_TDMFS, "tdmfs:%d"},
{AuWbrCreate_TDMFSV, "tdmfs:%d:%d"},
{AuWbrCreate_MFSRR, "mfsrr:%d"},
{AuWbrCreate_MFSRRV, "mfsrr:%d:%d"},
{AuWbrCreate_PMFS, "pmfs"},
{AuWbrCreate_PMFSV, "pmfs:%d"},
{AuWbrCreate_PMFSRR, "pmfsrr:%d"},
{AuWbrCreate_PMFSRRV, "pmfsrr:%d:%d"},
/* add more later */
{-1, NULL} {-1, NULL}
}; };
static int au_wbr_mfs_wmark(substring_t *arg, char *str,
struct au_opt_wbr_create *create)
{
int err;
unsigned long long ull;
err = 0;
if (!match_u64(arg, &ull))
create->mfsrr_watermark = ull;
else {
pr_err("bad integer in %s\n", str);
err = -EINVAL;
}
return err;
}
static int au_wbr_mfs_sec(substring_t *arg, char *str,
struct au_opt_wbr_create *create)
{
int n, err;
err = 0;
if (!match_int(arg, &n) && 0 <= n && n <= AUFS_MFS_MAX_SEC)
create->mfs_second = n;
else {
pr_err("bad integer in %s\n", str);
err = -EINVAL;
}
return err;
}
static int noinline_for_stack static int noinline_for_stack
au_wbr_create_val(char *str, struct au_opt_wbr_create *create) au_wbr_create_val(char *str, struct au_opt_wbr_create *create)
{ {
int err; int err, e;
substring_t args[MAX_OPT_ARGS]; substring_t args[MAX_OPT_ARGS];
err = match_token(str, au_wbr_create_policy, args); err = match_token(str, au_wbr_create_policy, args);
create->wbr_create = err; create->wbr_create = err;
switch (err) {
case AuWbrCreate_MFSRRV:
case AuWbrCreate_TDMFSV:
case AuWbrCreate_PMFSRRV:
e = au_wbr_mfs_wmark(&args[0], str, create);
if (!e)
e = au_wbr_mfs_sec(&args[1], str, create);
if (unlikely(e))
err = e;
break;
case AuWbrCreate_MFSRR:
case AuWbrCreate_TDMFS:
case AuWbrCreate_PMFSRR:
e = au_wbr_mfs_wmark(&args[0], str, create);
if (unlikely(e)) {
err = e;
break;
}
/*FALLTHROUGH*/
case AuWbrCreate_MFS:
case AuWbrCreate_PMFS:
create->mfs_second = AUFS_MFS_DEF_SEC;
break;
case AuWbrCreate_MFSV:
case AuWbrCreate_PMFSV:
e = au_wbr_mfs_sec(&args[0], str, create);
if (unlikely(e))
err = e;
break;
}
return err; return err;
} }
...@@ -280,6 +359,10 @@ const char *au_optstr_wbr_create(int wbr_create) ...@@ -280,6 +359,10 @@ const char *au_optstr_wbr_create(int wbr_create)
static match_table_t au_wbr_copyup_policy = { static match_table_t au_wbr_copyup_policy = {
{AuWbrCopyup_TDP, "tdp"}, {AuWbrCopyup_TDP, "tdp"},
{AuWbrCopyup_TDP, "top-down-parent"}, {AuWbrCopyup_TDP, "top-down-parent"},
{AuWbrCopyup_BUP, "bup"},
{AuWbrCopyup_BUP, "bottom-up-parent"},
{AuWbrCopyup_BU, "bu"},
{AuWbrCopyup_BU, "bottom-up"},
{-1, NULL} {-1, NULL}
}; };
...@@ -357,6 +440,24 @@ static void dump_opts(struct au_opts *opts) ...@@ -357,6 +440,24 @@ static void dump_opts(struct au_opts *opts)
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,
au_optstr_wbr_create(u.create->wbr_create)); au_optstr_wbr_create(u.create->wbr_create));
switch (u.create->wbr_create) {
case AuWbrCreate_MFSV:
case AuWbrCreate_PMFSV:
AuDbg("%d sec\n", u.create->mfs_second);
break;
case AuWbrCreate_MFSRR:
case AuWbrCreate_TDMFS:
AuDbg("%llu watermark\n",
u.create->mfsrr_watermark);
break;
case AuWbrCreate_MFSRRV:
case AuWbrCreate_TDMFSV:
case AuWbrCreate_PMFSRRV:
AuDbg("%llu watermark, %d sec\n",
u.create->mfsrr_watermark,
u.create->mfs_second);
break;
}
break; break;
case Opt_wbr_copyup: case Opt_wbr_copyup:
AuDbg("copyup %d, %s\n", opt->wbr_copyup, AuDbg("copyup %d, %s\n", opt->wbr_copyup,
...@@ -665,6 +766,23 @@ static int au_opt_wbr_create(struct super_block *sb, ...@@ -665,6 +766,23 @@ static int au_opt_wbr_create(struct super_block *sb,
sbinfo->si_wbr_create = create->wbr_create; sbinfo->si_wbr_create = create->wbr_create;
sbinfo->si_wbr_create_ops = au_wbr_create_ops + create->wbr_create; sbinfo->si_wbr_create_ops = au_wbr_create_ops + create->wbr_create;
switch (create->wbr_create) {
case AuWbrCreate_MFSRRV:
case AuWbrCreate_MFSRR:
case AuWbrCreate_TDMFS:
case AuWbrCreate_TDMFSV:
case AuWbrCreate_PMFSRR:
case AuWbrCreate_PMFSRRV:
sbinfo->si_wbr_mfs.mfsrr_watermark = create->mfsrr_watermark;
/*FALLTHROUGH*/
case AuWbrCreate_MFS:
case AuWbrCreate_MFSV:
case AuWbrCreate_PMFS:
case AuWbrCreate_PMFSV:
sbinfo->si_wbr_mfs.mfs_expire
= msecs_to_jiffies(create->mfs_second * MSEC_PER_SEC);
break;
}
if (sbinfo->si_wbr_create_ops->init) if (sbinfo->si_wbr_create_ops->init)
sbinfo->si_wbr_create_ops->init(sb); /* ignore */ sbinfo->si_wbr_create_ops->init(sb); /* ignore */
......
...@@ -49,14 +49,25 @@ static inline unsigned int au_opts_plink(unsigned int mntflags) ...@@ -49,14 +49,25 @@ static inline unsigned int au_opts_plink(unsigned int mntflags)
/* policies to select one among multiple writable branches */ /* policies to select one among multiple writable branches */
enum { enum {
AuWbrCreate_TDP, /* top down parent */ AuWbrCreate_TDP, /* top down parent */
/* add more later */ AuWbrCreate_RR, /* round robin */
AuWbrCreate_MFS, /* most free space */
AuWbrCreate_MFSV, /* mfs with seconds */
AuWbrCreate_MFSRR, /* mfs then rr */
AuWbrCreate_MFSRRV, /* mfs then rr with seconds */
AuWbrCreate_TDMFS, /* top down regardless parent and mfs */
AuWbrCreate_TDMFSV, /* top down regardless parent and mfs */
AuWbrCreate_PMFS, /* parent and mfs */
AuWbrCreate_PMFSV, /* parent and mfs with seconds */
AuWbrCreate_PMFSRR, /* parent, mfs and round-robin */
AuWbrCreate_PMFSRRV, /* plus seconds */
AuWbrCreate_Def = AuWbrCreate_TDP AuWbrCreate_Def = AuWbrCreate_TDP
}; };
enum { enum {
AuWbrCopyup_TDP, /* top down parent */ AuWbrCopyup_TDP, /* top down parent */
/* add more later */ AuWbrCopyup_BUP, /* bottom up parent */
AuWbrCopyup_BU, /* bottom up */
AuWbrCopyup_Def = AuWbrCopyup_TDP AuWbrCopyup_Def = AuWbrCopyup_TDP
}; };
...@@ -81,7 +92,8 @@ struct au_opt_xino_itrunc { ...@@ -81,7 +92,8 @@ struct au_opt_xino_itrunc {
struct au_opt_wbr_create { struct au_opt_wbr_create {
int wbr_create; int wbr_create;
/* add more later */ int mfs_second;
unsigned long long mfsrr_watermark;
}; };
struct au_opt { struct au_opt {
......
...@@ -103,21 +103,61 @@ static int au_show_brs(struct seq_file *seq, struct super_block *sb) ...@@ -103,21 +103,61 @@ static int au_show_brs(struct seq_file *seq, struct super_block *sb)
return err; return err;
} }
static void au_gen_fmt(char *fmt, int len __maybe_unused, const char *pat,
const char *append)
{
char *p;
p = fmt;
while (*pat != ':')
*p++ = *pat++;
*p++ = *pat++;
strcpy(p, append);
AuDebugOn(strlen(fmt) >= len);
}
/* re-commit later */ __maybe_unused /* re-commit later */ __maybe_unused
static void au_show_wbr_create(struct seq_file *m, int v, static void au_show_wbr_create(struct seq_file *m, int v,
struct au_sbinfo *sbinfo) struct au_sbinfo *sbinfo)
{ {
const char *pat; const char *pat;
char fmt[32];
struct au_wbr_mfs *mfs;
AuRwMustAnyLock(&sbinfo->si_rwsem); AuRwMustAnyLock(&sbinfo->si_rwsem);
seq_puts(m, ",create="); seq_puts(m, ",create=");
pat = au_optstr_wbr_create(v); pat = au_optstr_wbr_create(v);
mfs = &sbinfo->si_wbr_mfs;
switch (v) { switch (v) {
case AuWbrCreate_TDP: case AuWbrCreate_TDP:
case AuWbrCreate_RR:
case AuWbrCreate_MFS:
case AuWbrCreate_PMFS:
seq_puts(m, pat); seq_puts(m, pat);
break; break;
case AuWbrCreate_MFSRR:
case AuWbrCreate_TDMFS:
case AuWbrCreate_PMFSRR:
au_gen_fmt(fmt, sizeof(fmt), pat, "%llu");
seq_printf(m, fmt, mfs->mfsrr_watermark);
break;
case AuWbrCreate_MFSV:
case AuWbrCreate_PMFSV:
au_gen_fmt(fmt, sizeof(fmt), pat, "%lu");
seq_printf(m, fmt,
jiffies_to_msecs(mfs->mfs_expire)
/ MSEC_PER_SEC);
break;
case AuWbrCreate_MFSRRV:
case AuWbrCreate_TDMFSV:
case AuWbrCreate_PMFSRRV:
au_gen_fmt(fmt, sizeof(fmt), pat, "%llu:%lu");
seq_printf(m, fmt, mfs->mfsrr_watermark,
jiffies_to_msecs(mfs->mfs_expire) / MSEC_PER_SEC);
break; break;
default:
BUG();
} }
} }
......
...@@ -36,6 +36,16 @@ struct au_wbr_create_operations { ...@@ -36,6 +36,16 @@ struct au_wbr_create_operations {
int (*fin)(struct super_block *sb); int (*fin)(struct super_block *sb);
}; };
struct au_wbr_mfs {
struct mutex mfs_lock; /* protect this structure */
unsigned long mfs_jiffy;
unsigned long mfs_expire;
aufs_bindex_t mfs_bindex;
unsigned long long mfsrr_bytes;
unsigned long long mfsrr_watermark;
};
#define AuPlink_NHASH 100 #define AuPlink_NHASH 100
static inline int au_plink_hash(ino_t ino) static inline int au_plink_hash(ino_t ino)
{ {
...@@ -69,6 +79,12 @@ struct au_sbinfo { ...@@ -69,6 +79,12 @@ struct au_sbinfo {
struct au_wbr_copyup_operations *si_wbr_copyup_ops; struct au_wbr_copyup_operations *si_wbr_copyup_ops;
struct au_wbr_create_operations *si_wbr_create_ops; struct au_wbr_create_operations *si_wbr_create_ops;
/* round robin */
atomic_t si_wbr_rr_next;
/* most free space */
struct au_wbr_mfs si_wbr_mfs;
/* mount flags */ /* mount flags */
/* include/asm-ia64/siginfo.h defines a macro named si_flags */ /* include/asm-ia64/siginfo.h defines a macro named si_flags */
unsigned int si_mntflags; unsigned int si_mntflags;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
* policies for selecting one among multiple writable branches * policies for selecting one among multiple writable branches
*/ */
#include <linux/statfs.h>
#include "aufs.h" #include "aufs.h"
/* subset of cpup_attr() */ /* subset of cpup_attr() */
...@@ -288,6 +289,394 @@ out: ...@@ -288,6 +289,394 @@ out:
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
/* an exception for the policy other than tdp */
static int au_wbr_create_exp(struct dentry *dentry)
{
int err;
aufs_bindex_t bwh, bdiropq;
struct dentry *parent;
err = -1;
bwh = au_dbwh(dentry);
parent = dget_parent(dentry);
bdiropq = au_dbdiropq(parent);
if (bwh >= 0) {
if (bdiropq >= 0)
err = min(bdiropq, bwh);
else
err = bwh;
AuDbg("%d\n", err);
} else if (bdiropq >= 0) {
err = bdiropq;
AuDbg("%d\n", err);
}
dput(parent);
if (err >= 0)
err = au_wbr_nonopq(dentry, err);
if (err >= 0 && au_br_rdonly(au_sbr(dentry->d_sb, err)))
err = -1;
AuDbg("%d\n", err);
return err;
}
/* ---------------------------------------------------------------------- */
/* round robin */
static int au_wbr_create_init_rr(struct super_block *sb)
{
int err;
err = au_wbr_bu(sb, au_sbbot(sb));
atomic_set(&au_sbi(sb)->si_wbr_rr_next, -err); /* less important */
/* smp_mb(); */
AuDbg("b%d\n", err);
return err;
}
static int au_wbr_create_rr(struct dentry *dentry, unsigned int flags)
{
int err, nbr;
unsigned int u;
aufs_bindex_t bindex, bbot;
struct super_block *sb;
atomic_t *next;
err = au_wbr_create_exp(dentry);
if (err >= 0)
goto out;
sb = dentry->d_sb;
next = &au_sbi(sb)->si_wbr_rr_next;
bbot = au_sbbot(sb);
nbr = bbot + 1;
for (bindex = 0; bindex <= bbot; bindex++) {
if (!au_ftest_wbr(flags, DIR)) {
err = atomic_dec_return(next) + 1;
/* modulo for 0 is meaningless */
if (unlikely(!err))
err = atomic_dec_return(next) + 1;
} else
err = atomic_read(next);
AuDbg("%d\n", err);
u = err;
err = u % nbr;
AuDbg("%d\n", err);
if (!au_br_rdonly(au_sbr(sb, err)))
break;
err = -EROFS;
}
if (err >= 0)
err = au_wbr_nonopq(dentry, err);
out:
AuDbg("%d\n", err);
return err;
}
/* ---------------------------------------------------------------------- */
/* most free space */
static void au_mfs(struct dentry *dentry, struct dentry *parent)
{
struct super_block *sb;
struct au_branch *br;
struct au_wbr_mfs *mfs;
struct dentry *h_parent;
aufs_bindex_t bindex, bbot;
int err;
unsigned long long b, bavail;
struct path h_path;
/* reduce the stack usage */
struct kstatfs *st;
st = kmalloc(sizeof(*st), GFP_NOFS);
if (unlikely(!st)) {
AuWarn1("failed updating mfs(%d), ignored\n", -ENOMEM);
return;
}
bavail = 0;
sb = dentry->d_sb;
mfs = &au_sbi(sb)->si_wbr_mfs;
MtxMustLock(&mfs->mfs_lock);
mfs->mfs_bindex = -EROFS;
mfs->mfsrr_bytes = 0;
if (!parent) {
bindex = 0;
bbot = au_sbbot(sb);
} else {
bindex = au_dbtop(parent);
bbot = au_dbtaildir(parent);
}
for (; bindex <= bbot; bindex++) {
if (parent) {
h_parent = au_h_dptr(parent, bindex);
if (!h_parent || d_is_negative(h_parent))
continue;
}
br = au_sbr(sb, bindex);
if (au_br_rdonly(br))
continue;
/* sb->s_root for NFS is unreliable */
h_path.mnt = au_br_mnt(br);
h_path.dentry = h_path.mnt->mnt_root;
err = vfs_statfs(&h_path, st);
if (unlikely(err)) {
AuWarn1("failed statfs, b%d, %d\n", bindex, err);
continue;
}
/* when the available size is equal, select the lower one */
BUILD_BUG_ON(sizeof(b) < sizeof(st->f_bavail)
|| sizeof(b) < sizeof(st->f_bsize));
b = st->f_bavail * st->f_bsize;
br->br_wbr->wbr_bytes = b;
if (b >= bavail) {
bavail = b;
mfs->mfs_bindex = bindex;
mfs->mfs_jiffy = jiffies;
}
}
mfs->mfsrr_bytes = bavail;
AuDbg("b%d\n", mfs->mfs_bindex);
au_kfree_rcu(st);
}
static int au_wbr_create_mfs(struct dentry *dentry, unsigned int flags)
{
int err;
struct dentry *parent;
struct super_block *sb;
struct au_wbr_mfs *mfs;
err = au_wbr_create_exp(dentry);
if (err >= 0)
goto out;
sb = dentry->d_sb;
parent = NULL;
if (au_ftest_wbr(flags, PARENT))
parent = dget_parent(dentry);
mfs = &au_sbi(sb)->si_wbr_mfs;
mutex_lock(&mfs->mfs_lock);
if (time_after(jiffies, mfs->mfs_jiffy + mfs->mfs_expire)
|| mfs->mfs_bindex < 0
|| au_br_rdonly(au_sbr(sb, mfs->mfs_bindex)))
au_mfs(dentry, parent);
mutex_unlock(&mfs->mfs_lock);
err = mfs->mfs_bindex;
dput(parent);
if (err >= 0)
err = au_wbr_nonopq(dentry, err);
out:
AuDbg("b%d\n", err);
return err;
}
static int au_wbr_create_init_mfs(struct super_block *sb)
{
struct au_wbr_mfs *mfs;
mfs = &au_sbi(sb)->si_wbr_mfs;
mutex_init(&mfs->mfs_lock);
mfs->mfs_jiffy = 0;
mfs->mfs_bindex = -EROFS;
return 0;
}
static int au_wbr_create_fin_mfs(struct super_block *sb __maybe_unused)
{
mutex_destroy(&au_sbi(sb)->si_wbr_mfs.mfs_lock);
return 0;
}
/* ---------------------------------------------------------------------- */
/* top down regardless parent, and then mfs */
static int au_wbr_create_tdmfs(struct dentry *dentry,
unsigned int flags __maybe_unused)
{
int err;
aufs_bindex_t bwh, btail, bindex, bfound, bmfs;
unsigned long long watermark;
struct super_block *sb;
struct au_wbr_mfs *mfs;
struct au_branch *br;
struct dentry *parent;
sb = dentry->d_sb;
mfs = &au_sbi(sb)->si_wbr_mfs;
mutex_lock(&mfs->mfs_lock);
if (time_after(jiffies, mfs->mfs_jiffy + mfs->mfs_expire)
|| mfs->mfs_bindex < 0)
au_mfs(dentry, /*parent*/NULL);
watermark = mfs->mfsrr_watermark;
bmfs = mfs->mfs_bindex;
mutex_unlock(&mfs->mfs_lock);
/* another style of au_wbr_create_exp() */
bwh = au_dbwh(dentry);
parent = dget_parent(dentry);
btail = au_dbtaildir(parent);
if (bwh >= 0 && bwh < btail)
btail = bwh;
err = au_wbr_nonopq(dentry, btail);
if (unlikely(err < 0))
goto out;
btail = err;
bfound = -1;
for (bindex = 0; bindex <= btail; bindex++) {
br = au_sbr(sb, bindex);
if (au_br_rdonly(br))
continue;
if (br->br_wbr->wbr_bytes > watermark) {
bfound = bindex;
break;
}
}
err = bfound;
if (err < 0)
err = bmfs;
out:
dput(parent);
AuDbg("b%d\n", err);
return err;
}
/* ---------------------------------------------------------------------- */
/* most free space and then round robin */
static int au_wbr_create_mfsrr(struct dentry *dentry, unsigned int flags)
{
int err;
struct au_wbr_mfs *mfs;
err = au_wbr_create_mfs(dentry, flags);
if (err >= 0) {
mfs = &au_sbi(dentry->d_sb)->si_wbr_mfs;
mutex_lock(&mfs->mfs_lock);
if (mfs->mfsrr_bytes < mfs->mfsrr_watermark)
err = au_wbr_create_rr(dentry, flags);
mutex_unlock(&mfs->mfs_lock);
}
AuDbg("b%d\n", err);
return err;
}
static int au_wbr_create_init_mfsrr(struct super_block *sb)
{
int err;
au_wbr_create_init_mfs(sb); /* ignore */
err = au_wbr_create_init_rr(sb);
return err;
}
/* ---------------------------------------------------------------------- */
/* top down parent and most free space */
static int au_wbr_create_pmfs(struct dentry *dentry, unsigned int flags)
{
int err, e2;
unsigned long long b;
aufs_bindex_t bindex, btop, bbot;
struct super_block *sb;
struct dentry *parent, *h_parent;
struct au_branch *br;
err = au_wbr_create_tdp(dentry, flags);
if (unlikely(err < 0))
goto out;
parent = dget_parent(dentry);
btop = au_dbtop(parent);
bbot = au_dbtaildir(parent);
if (btop == bbot)
goto out_parent; /* success */
e2 = au_wbr_create_mfs(dentry, flags);
if (e2 < 0)
goto out_parent; /* success */
/* when the available size is equal, select upper one */
sb = dentry->d_sb;
br = au_sbr(sb, err);
b = br->br_wbr->wbr_bytes;
AuDbg("b%d, %llu\n", err, b);
for (bindex = btop; bindex <= bbot; bindex++) {
h_parent = au_h_dptr(parent, bindex);
if (!h_parent || d_is_negative(h_parent))
continue;
br = au_sbr(sb, bindex);
if (!au_br_rdonly(br) && br->br_wbr->wbr_bytes > b) {
b = br->br_wbr->wbr_bytes;
err = bindex;
AuDbg("b%d, %llu\n", err, b);
}
}
if (err >= 0)
err = au_wbr_nonopq(dentry, err);
out_parent:
dput(parent);
out:
AuDbg("b%d\n", err);
return err;
}
/* ---------------------------------------------------------------------- */
/*
* - top down parent
* - most free space with parent
* - most free space round-robin regardless parent
*/
static int au_wbr_create_pmfsrr(struct dentry *dentry, unsigned int flags)
{
int err;
unsigned long long watermark;
struct super_block *sb;
struct au_branch *br;
struct au_wbr_mfs *mfs;
err = au_wbr_create_pmfs(dentry, flags | AuWbr_PARENT);
if (unlikely(err < 0))
goto out;
sb = dentry->d_sb;
br = au_sbr(sb, err);
mfs = &au_sbi(sb)->si_wbr_mfs;
mutex_lock(&mfs->mfs_lock);
watermark = mfs->mfsrr_watermark;
mutex_unlock(&mfs->mfs_lock);
if (br->br_wbr->wbr_bytes < watermark)
/* regardless the parent dir */
err = au_wbr_create_mfsrr(dentry, flags);
out:
AuDbg("b%d\n", err);
return err;
}
/* ---------------------------------------------------------------------- */
/* policies for copyup */ /* policies for copyup */
/* top down parent */ /* top down parent */
...@@ -296,16 +685,132 @@ static int au_wbr_copyup_tdp(struct dentry *dentry) ...@@ -296,16 +685,132 @@ static int au_wbr_copyup_tdp(struct dentry *dentry)
return au_wbr_create_tdp(dentry, /*flags, anything is ok*/0); return au_wbr_create_tdp(dentry, /*flags, anything is ok*/0);
} }
/* bottom up parent */
static int au_wbr_copyup_bup(struct dentry *dentry)
{
int err;
aufs_bindex_t bindex, btop;
struct dentry *parent, *h_parent;
struct super_block *sb;
err = -EROFS;
sb = dentry->d_sb;
parent = dget_parent(dentry);
btop = au_dbtop(parent);
for (bindex = au_dbtop(dentry); bindex >= btop; bindex--) {
h_parent = au_h_dptr(parent, bindex);
if (!h_parent || d_is_negative(h_parent))
continue;
if (!au_br_rdonly(au_sbr(sb, bindex))) {
err = bindex;
break;
}
}
dput(parent);
/* bottom up here */
if (unlikely(err < 0))
err = au_wbr_bu(sb, btop - 1);
AuDbg("b%d\n", err);
return err;
}
/* bottom up */
int au_wbr_do_copyup_bu(struct dentry *dentry, aufs_bindex_t btop)
{
int err;
err = au_wbr_bu(dentry->d_sb, btop);
AuDbg("b%d\n", err);
if (err > btop)
err = au_wbr_nonopq(dentry, err);
AuDbg("b%d\n", err);
return err;
}
static int au_wbr_copyup_bu(struct dentry *dentry)
{
int err;
aufs_bindex_t btop;
btop = au_dbtop(dentry);
err = au_wbr_do_copyup_bu(dentry, btop);
return err;
}
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
struct au_wbr_copyup_operations au_wbr_copyup_ops[] = { struct au_wbr_copyup_operations au_wbr_copyup_ops[] = {
[AuWbrCopyup_TDP] = { [AuWbrCopyup_TDP] = {
.copyup = au_wbr_copyup_tdp .copyup = au_wbr_copyup_tdp
},
[AuWbrCopyup_BUP] = {
.copyup = au_wbr_copyup_bup
},
[AuWbrCopyup_BU] = {
.copyup = au_wbr_copyup_bu
} }
}; };
struct au_wbr_create_operations au_wbr_create_ops[] = { struct au_wbr_create_operations au_wbr_create_ops[] = {
[AuWbrCreate_TDP] = { [AuWbrCreate_TDP] = {
.create = au_wbr_create_tdp .create = au_wbr_create_tdp
},
[AuWbrCreate_RR] = {
.create = au_wbr_create_rr,
.init = au_wbr_create_init_rr
},
[AuWbrCreate_MFS] = {
.create = au_wbr_create_mfs,
.init = au_wbr_create_init_mfs,
.fin = au_wbr_create_fin_mfs
},
[AuWbrCreate_MFSV] = {
.create = au_wbr_create_mfs,
.init = au_wbr_create_init_mfs,
.fin = au_wbr_create_fin_mfs
},
[AuWbrCreate_MFSRR] = {
.create = au_wbr_create_mfsrr,
.init = au_wbr_create_init_mfsrr,
.fin = au_wbr_create_fin_mfs
},
[AuWbrCreate_MFSRRV] = {
.create = au_wbr_create_mfsrr,
.init = au_wbr_create_init_mfsrr,
.fin = au_wbr_create_fin_mfs
},
[AuWbrCreate_TDMFS] = {
.create = au_wbr_create_tdmfs,
.init = au_wbr_create_init_mfs,
.fin = au_wbr_create_fin_mfs
},
[AuWbrCreate_TDMFSV] = {
.create = au_wbr_create_tdmfs,
.init = au_wbr_create_init_mfs,
.fin = au_wbr_create_fin_mfs
},
[AuWbrCreate_PMFS] = {
.create = au_wbr_create_pmfs,
.init = au_wbr_create_init_mfs,
.fin = au_wbr_create_fin_mfs
},
[AuWbrCreate_PMFSV] = {
.create = au_wbr_create_pmfs,
.init = au_wbr_create_init_mfs,
.fin = au_wbr_create_fin_mfs
},
[AuWbrCreate_PMFSRR] = {
.create = au_wbr_create_pmfsrr,
.init = au_wbr_create_init_mfsrr,
.fin = au_wbr_create_fin_mfs
},
[AuWbrCreate_PMFSRRV] = {
.create = au_wbr_create_pmfsrr,
.init = au_wbr_create_init_mfsrr,
.fin = au_wbr_create_fin_mfs
} }
}; };
...@@ -74,6 +74,8 @@ typedef int16_t aufs_bindex_t; ...@@ -74,6 +74,8 @@ typedef int16_t aufs_bindex_t;
#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_WKQ_NAME AUFS_NAME "d" #define AUFS_WKQ_NAME AUFS_NAME "d"
#define AUFS_MFS_DEF_SEC 30 /* seconds */
#define AUFS_MFS_MAX_SEC 3600 /* seconds */
#define AUFS_PLINK_WARN 50 /* number of plinks in a single bucket */ #define AUFS_PLINK_WARN 50 /* number of plinks in a single bucket */
/* pseudo-link maintenace under /proc */ /* pseudo-link maintenace under /proc */
......
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