/*
- * Copyright (C) 2005-2012 Junjiro R. Okajima
+ * Copyright (C) 2005-2013 Junjiro R. Okajima
*
* This program, aufs is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
ia.ia_uid = h_isrc->i_uid;
ia.ia_gid = h_isrc->i_gid;
sbits = !!(ia.ia_mode & (S_ISUID | S_ISGID));
- au_cpup_attr_flags(h_path->dentry->d_inode, h_isrc);
+ au_cpup_attr_flags(h_path->dentry->d_inode, h_isrc->i_flags);
err = vfsub_sio_notify_change(h_path, &ia);
/* is this nfs only? */
#define au_fclr_cpdown(flags, name) \
do { (flags) &= ~AuCpdown_##name; } while (0)
-struct au_cpdown_dir_args {
- struct dentry *parent;
- unsigned int flags;
-};
-
static int au_cpdown_dir_opq(struct dentry *dentry, aufs_bindex_t bdst,
- struct au_cpdown_dir_args *a)
+ unsigned int *flags)
{
int err;
struct dentry *opq_dentry;
if (IS_ERR(opq_dentry))
goto out;
dput(opq_dentry);
- au_fset_cpdown(a->flags, DIROPQ);
+ au_fset_cpdown(*flags, DIROPQ);
out:
return err;
err = 0;
if (h_path.dentry->d_inode) {
- h_path.mnt = br->br_mnt;
+ h_path.mnt = au_br_mnt(br);
err = au_wh_unlink_dentry(au_h_iptr(dir, bdst), &h_path,
dentry);
}
}
static int au_cpdown_dir(struct dentry *dentry, aufs_bindex_t bdst,
+ struct au_pin *pin,
struct dentry *h_parent, void *arg)
{
int err, rerr;
struct path h_path;
struct dentry *parent;
struct inode *h_dir, *h_inode, *inode, *dir;
- struct au_cpdown_dir_args *args = arg;
+ unsigned int *flags = arg;
bstart = au_dbstart(dentry);
/* dentry is di-locked */
AuDebugOn(h_dir != au_h_iptr(dir, bdst));
IMustLock(h_dir);
- err = au_lkup_neg(dentry, bdst);
+ err = au_lkup_neg(dentry, bdst, /*wh*/0);
if (unlikely(err < 0))
goto out;
h_path.dentry = au_h_dptr(dentry, bdst);
S_IRWXU | S_IRUGO | S_IXUGO);
if (unlikely(err))
goto out_put;
- au_fset_cpdown(args->flags, MADE_DIR);
+ au_fset_cpdown(*flags, MADE_DIR);
bopq = au_dbdiropq(dentry);
- au_fclr_cpdown(args->flags, WHED);
- au_fclr_cpdown(args->flags, DIROPQ);
+ au_fclr_cpdown(*flags, WHED);
+ au_fclr_cpdown(*flags, DIROPQ);
if (au_dbwh(dentry) == bdst)
- au_fset_cpdown(args->flags, WHED);
- if (!au_ftest_cpdown(args->flags, PARENT_OPQ) && bopq <= bdst)
- au_fset_cpdown(args->flags, PARENT_OPQ);
+ au_fset_cpdown(*flags, WHED);
+ if (!au_ftest_cpdown(*flags, PARENT_OPQ) && bopq <= bdst)
+ au_fset_cpdown(*flags, PARENT_OPQ);
h_inode = h_path.dentry->d_inode;
mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
- if (au_ftest_cpdown(args->flags, WHED)) {
- err = au_cpdown_dir_opq(dentry, bdst, args);
+ if (au_ftest_cpdown(*flags, WHED)) {
+ err = au_cpdown_dir_opq(dentry, bdst, flags);
if (unlikely(err)) {
mutex_unlock(&h_inode->i_mutex);
goto out_dir;
if (unlikely(err))
goto out_opq;
- if (au_ftest_cpdown(args->flags, WHED)) {
+ if (au_ftest_cpdown(*flags, WHED)) {
err = au_cpdown_dir_wh(dentry, h_parent, dir, bdst);
if (unlikely(err))
goto out_opq;
/* revert */
out_opq:
- if (au_ftest_cpdown(args->flags, DIROPQ)) {
+ if (au_ftest_cpdown(*flags, DIROPQ)) {
mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
rerr = au_diropq_remove(dentry, bdst);
mutex_unlock(&h_inode->i_mutex);
}
}
out_dir:
- if (au_ftest_cpdown(args->flags, MADE_DIR)) {
+ if (au_ftest_cpdown(*flags, MADE_DIR)) {
rerr = vfsub_sio_rmdir(au_h_iptr(dir, bdst), &h_path);
if (unlikely(rerr)) {
AuIOErr("failed removing %.*s b%d (%d)\n",
int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst)
{
int err;
- struct au_cpdown_dir_args args = {
- .parent = dget_parent(dentry),
- .flags = 0
- };
+ unsigned int flags;
- err = au_cp_dirs(dentry, bdst, au_cpdown_dir, &args);
- dput(args.parent);
+ flags = 0;
+ err = au_cp_dirs(dentry, bdst, au_cpdown_dir, &flags);
return err;
}
}
/* top down parent */
-static int au_wbr_create_tdp(struct dentry *dentry, int isdir __maybe_unused)
+static int au_wbr_create_tdp(struct dentry *dentry,
+ unsigned int flags __maybe_unused)
{
int err;
aufs_bindex_t bstart, bindex;
return err;
}
-static int au_wbr_create_rr(struct dentry *dentry, int isdir)
+static int au_wbr_create_rr(struct dentry *dentry, unsigned int flags)
{
int err, nbr;
unsigned int u;
bend = au_sbend(sb);
nbr = bend + 1;
for (bindex = 0; bindex <= bend; bindex++) {
- if (!isdir) {
+ if (!au_ftest_wbr(flags, DIR)) {
err = atomic_dec_return(next) + 1;
/* modulo for 0 is meaningless */
if (unlikely(!err))
/* ---------------------------------------------------------------------- */
/* most free space */
-static void au_mfs(struct dentry *dentry)
+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, bend;
int err;
unsigned long long b, bavail;
MtxMustLock(&mfs->mfs_lock);
mfs->mfs_bindex = -EROFS;
mfs->mfsrr_bytes = 0;
- bend = au_sbend(sb);
- for (bindex = 0; bindex <= bend; bindex++) {
+ if (!parent) {
+ bindex = 0;
+ bend = au_sbend(sb);
+ } else {
+ bindex = au_dbstart(parent);
+ bend = au_dbtaildir(parent);
+ }
+
+ for (; bindex <= bend; bindex++) {
+ if (parent) {
+ h_parent = au_h_dptr(parent, bindex);
+ if (!h_parent || !h_parent->d_inode)
+ continue;
+ }
br = au_sbr(sb, bindex);
if (au_br_rdonly(br))
continue;
/* sb->s_root for NFS is unreliable */
- h_path.mnt = br->br_mnt;
+ h_path.mnt = au_br_mnt(br);
h_path.dentry = h_path.mnt->mnt_root;
err = vfs_statfs(&h_path, st);
if (unlikely(err)) {
kfree(st);
}
-static int au_wbr_create_mfs(struct dentry *dentry, int isdir __maybe_unused)
+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;
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);
+ au_mfs(dentry, parent);
mutex_unlock(&mfs->mfs_lock);
err = mfs->mfs_bindex;
+ dput(parent);
if (err >= 0)
err = au_wbr_nonopq(dentry, err);
/* ---------------------------------------------------------------------- */
/* most free space and then round robin */
-static int au_wbr_create_mfsrr(struct dentry *dentry, int isdir)
+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, isdir);
+ 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, isdir);
+ err = au_wbr_create_rr(dentry, flags);
mutex_unlock(&mfs->mfs_lock);
}
/* ---------------------------------------------------------------------- */
/* top down parent and most free space */
-static int au_wbr_create_pmfs(struct dentry *dentry, int isdir)
+static int au_wbr_create_pmfs(struct dentry *dentry, unsigned int flags)
{
int err, e2;
unsigned long long b;
struct dentry *parent, *h_parent;
struct au_branch *br;
- err = au_wbr_create_tdp(dentry, isdir);
+ err = au_wbr_create_tdp(dentry, flags);
if (unlikely(err < 0))
goto out;
parent = dget_parent(dentry);
if (bstart == bend)
goto out_parent; /* success */
- e2 = au_wbr_create_mfs(dentry, isdir);
+ e2 = au_wbr_create_mfs(dentry, flags);
if (e2 < 0)
goto out_parent; /* success */
/* ---------------------------------------------------------------------- */
+/*
+ * - 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 */
/* top down parent */
static int au_wbr_copyup_tdp(struct dentry *dentry)
{
- return au_wbr_create_tdp(dentry, /*isdir, anything is ok*/0);
+ return au_wbr_create_tdp(dentry, /*flags, anything is ok*/0);
}
/* bottom up parent */
.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
}
};