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

aufs: branch attributes, copy/move-up on open



When these attributes are specified and aufs tries opening a file on that
branch, aufs copies/moves it up.
Signed-off-by: default avatarJ. R. Okajima <hooanon05g@gmail.com>
parent ca3bca20
......@@ -94,6 +94,111 @@ out:
return h_file;
}
static int au_cmoo(struct dentry *dentry)
{
int err, cmoo;
unsigned int udba;
struct path h_path;
struct au_pin pin;
struct au_cp_generic cpg = {
.dentry = dentry,
.bdst = -1,
.bsrc = -1,
.len = -1,
.pin = &pin,
.flags = AuCpup_DTIME
};
struct inode *delegated;
struct super_block *sb;
struct au_sbinfo *sbinfo;
struct au_branch *br;
struct dentry *parent;
struct au_hinode *hdir;
DiMustWriteLock(dentry);
IiMustWriteLock(d_inode(dentry));
err = 0;
if (IS_ROOT(dentry))
goto out;
cpg.bsrc = au_dbtop(dentry);
if (!cpg.bsrc)
goto out;
sb = dentry->d_sb;
sbinfo = au_sbi(sb);
br = au_sbr(sb, cpg.bsrc);
cmoo = au_br_cmoo(br->br_perm);
if (!cmoo)
goto out;
if (!d_is_reg(dentry))
cmoo &= AuBrAttr_COO_ALL;
if (!cmoo)
goto out;
parent = dget_parent(dentry);
di_write_lock_parent(parent);
err = au_wbr_do_copyup_bu(dentry, cpg.bsrc - 1);
cpg.bdst = err;
if (unlikely(err < 0)) {
err = 0; /* there is no upper writable branch */
goto out_dgrade;
}
AuDbg("bsrc %d, bdst %d\n", cpg.bsrc, cpg.bdst);
/* do not respect the coo attrib for the target branch */
err = au_cpup_dirs(dentry, cpg.bdst);
if (unlikely(err))
goto out_dgrade;
di_downgrade_lock(parent, AuLock_IR);
udba = au_opt_udba(sb);
err = au_pin(&pin, dentry, cpg.bdst, udba,
AuPin_DI_LOCKED | AuPin_MNT_WRITE);
if (unlikely(err))
goto out_parent;
err = au_sio_cpup_simple(&cpg);
au_unpin(&pin);
if (unlikely(err))
goto out_parent;
if (!(cmoo & AuBrWAttr_MOO))
goto out_parent; /* success */
err = au_pin(&pin, dentry, cpg.bsrc, udba,
AuPin_DI_LOCKED | AuPin_MNT_WRITE);
if (unlikely(err))
goto out_parent;
h_path.mnt = au_br_mnt(br);
h_path.dentry = au_h_dptr(dentry, cpg.bsrc);
hdir = au_hi(d_inode(parent), cpg.bsrc);
delegated = NULL;
err = vfsub_unlink(hdir->hi_inode, &h_path, &delegated, /*force*/1);
au_unpin(&pin);
/* todo: keep h_dentry or not? */
if (unlikely(err == -EWOULDBLOCK)) {
pr_warn("cannot retry for NFSv4 delegation"
" for an internal unlink\n");
iput(delegated);
}
if (unlikely(err)) {
pr_err("unlink %pd after coo failed (%d), ignored\n",
dentry, err);
err = 0;
}
goto out_parent; /* success */
out_dgrade:
di_downgrade_lock(parent, AuLock_IR);
out_parent:
di_read_unlock(parent, AuLock_IR);
dput(parent);
out:
AuTraceErr(err);
return err;
}
int au_do_open(struct file *file, struct au_do_open_args *args)
{
int err, aopen = args->aopen;
......@@ -112,14 +217,18 @@ int au_do_open(struct file *file, struct au_do_open_args *args)
dentry = file->f_path.dentry;
AuDebugOn(IS_ERR_OR_NULL(dentry));
di_read_lock_child(dentry, AuLock_IR);
if (!aopen)
err = args->open(file, vfsub_file_flags(file), NULL);
else {
lockdep_off();
di_write_lock_child(dentry);
err = au_cmoo(dentry);
di_downgrade_lock(dentry, AuLock_IR);
if (!err) {
if (!aopen)
err = args->open(file, vfsub_file_flags(file), NULL);
else {
lockdep_off();
err = args->open(file, vfsub_file_flags(file),
args->h_file);
lockdep_on();
lockdep_on();
}
}
di_read_unlock(dentry, AuLock_IR);
......
......@@ -202,6 +202,9 @@ static match_table_t brperm = {
};
static match_table_t brattr = {
/* general */
{AuBrAttr_COO_REG, AUFS_BRATTR_COO_REG},
{AuBrAttr_COO_ALL, AUFS_BRATTR_COO_ALL},
#ifdef CONFIG_AUFS_XATTR
{AuBrAttr_ICEX, AUFS_BRATTR_ICEX},
{AuBrAttr_ICEX_SEC, AUFS_BRATTR_ICEX_SEC},
......@@ -215,9 +218,9 @@ static match_table_t brattr = {
{AuBrRAttr_WH, AUFS_BRRATTR_WH},
/* rw branch */
{AuBrWAttr_MOO, AUFS_BRWATTR_MOO},
{AuBrWAttr_NoLinkWH, AUFS_BRWATTR_NLWH},
/* add more later */
{0, NULL}
};
......@@ -232,9 +235,11 @@ static int br_attr_val(char *str, match_table_t table, substring_t args[])
if (p)
*p = 0;
v = match_token(str, table, args);
if (v)
if (v) {
if (v & AuBrAttr_CMOO_Mask)
attr &= ~AuBrAttr_CMOO_Mask;
attr |= v;
else {
} else {
if (p)
*p = '+';
pr_warn("ignored branch attribute %s\n", str);
......
......@@ -111,6 +111,8 @@ typedef int16_t aufs_bindex_t;
#define AUFS_BRPERM_RW "rw"
#define AUFS_BRPERM_RO "ro"
#define AUFS_BRPERM_RR "rr"
#define AUFS_BRATTR_COO_REG "coo_reg"
#define AUFS_BRATTR_COO_ALL "coo_all"
#define AUFS_BRATTR_ICEX "icex"
#define AUFS_BRATTR_ICEX_SEC "icexsec"
#define AUFS_BRATTR_ICEX_SYS "icexsys"
......@@ -119,12 +121,17 @@ typedef int16_t aufs_bindex_t;
#define AUFS_BRATTR_ICEX_OTH "icexoth"
#define AUFS_BRRATTR_WH "wh"
#define AUFS_BRWATTR_NLWH "nolwh"
#define AUFS_BRWATTR_MOO "moo"
#define AuBrPerm_RW 1 /* writable, hardlinkable wh */
#define AuBrPerm_RO (1 << 1) /* readonly */
#define AuBrPerm_RR (1 << 2) /* natively readonly */
#define AuBrPerm_Mask (AuBrPerm_RW | AuBrPerm_RO | AuBrPerm_RR)
#define AuBrAttr_COO_REG (1 << 3) /* copy-up on open */
#define AuBrAttr_COO_ALL (1 << 4)
#define AuBrAttr_COO_Mask (AuBrAttr_COO_REG | AuBrAttr_COO_ALL)
/* ignore error in copying XATTR */
#define AuBrAttr_ICEX_SEC (1 << 7)
#define AuBrAttr_ICEX_SYS (1 << 8)
......@@ -141,7 +148,10 @@ typedef int16_t aufs_bindex_t;
#define AuBrRAttr_Mask AuBrRAttr_WH
#define AuBrWAttr_NoLinkWH (1 << 13) /* un-hardlinkable whiteouts */
#define AuBrWAttr_Mask AuBrWAttr_NoLinkWH
#define AuBrWAttr_MOO (1 << 14) /* move-up on open */
#define AuBrWAttr_Mask (AuBrWAttr_NoLinkWH | AuBrWAttr_MOO)
#define AuBrAttr_CMOO_Mask (AuBrAttr_COO_Mask | AuBrWAttr_MOO)
/* #warning test userspace */
#ifdef __KERNEL__
......@@ -189,6 +199,11 @@ static inline int au_br_wh_linkable(int brperm)
return !(brperm & AuBrWAttr_NoLinkWH);
}
static inline int au_br_cmoo(int brperm)
{
return brperm & AuBrAttr_CMOO_Mask;
}
/* ---------------------------------------------------------------------- */
/* ioctl */
......
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