Beispiel #1
0
int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb)
{
	int err;
	struct au_wkinfo *wkinfo;

	atomic_inc(&au_sbi(sb)->si_nowait.nw_len);

	/*
	 * wkq_func() must free this wkinfo.
	 * it highly depends upon the implementation of workqueue.
	 */
	err = 0;
	wkinfo = kmalloc(sizeof(*wkinfo), GFP_NOFS);
	if (wkinfo) {
		wkinfo->sb = sb;
		wkinfo->flags = !AuWkq_WAIT;
		wkinfo->func = func;
		wkinfo->args = args;
		wkinfo->comp = NULL;
		kobject_get(&au_sbi(sb)->si_kobj);
		__module_get(THIS_MODULE);

		au_wkq_run(wkinfo);
	} else {
		err = -ENOMEM;
		atomic_dec(&au_sbi(sb)->si_nowait.nw_len);
	}

	return err;
}
Beispiel #2
0
int au_xigen_inc(struct inode *inode)
{
	int err;
	loff_t pos;
	ssize_t sz;
	__u32 igen;
	struct super_block *sb;
	struct au_sbinfo *sbinfo;

	LKTRTrace("i%lu\n", (unsigned long)inode->i_ino);

	err = 0;
	sb = inode->i_sb;
	if (unlikely(!au_opt_test_xino(au_mntflags(sb))))
		goto out;

	pos = inode->i_ino;
	pos *= sizeof(igen);
	igen = inode->i_generation + 1;
	sbinfo = au_sbi(sb);
	sz = xino_fwrite(sbinfo->si_xwrite, sbinfo->si_xigen, &igen,
			 sizeof(igen), &pos);
	if (sz == sizeof(igen))
		goto out; /* success */

	err = sz;
	if (unlikely(sz >= 0)) {
		err = -EIO;
		AuIOErr("xigen error (%zd)\n", sz);
	}

 out:
	AuTraceErr(err);
	return err;
}
Beispiel #3
0
static void sysrq_sb(struct super_block *sb)
{
	char *plevel;
	struct au_sbinfo *sbinfo;
	struct file *file;

	plevel = au_plevel;
	au_plevel = KERN_WARNING;
	au_debug(1);

	sbinfo = au_sbi(sb);
	pr_warning("si=%lx\n", sysaufs_si_id(sbinfo));
	pr_warning(AUFS_NAME ": superblock\n");
	au_dpri_sb(sb);
	pr_warning(AUFS_NAME ": root dentry\n");
	au_dpri_dentry(sb->s_root);
	pr_warning(AUFS_NAME ": root inode\n");
	au_dpri_inode(sb->s_root->d_inode);
#if 0
	struct inode *i;
	pr_warning(AUFS_NAME ": isolated inode\n");
	list_for_each_entry(i, &sb->s_inodes, i_sb_list)
		if (list_empty(&i->i_dentry))
			au_dpri_inode(i);
#endif
	pr_warning(AUFS_NAME ": files\n");
	list_for_each_entry(file, &sb->s_files, f_u.fu_list)
		if (!special_file(file->f_dentry->d_inode->i_mode))
			au_dpri_file(file);

	au_plevel = plevel;
	au_debug(0);
}
int au_do_open_nondir(struct file *file, int flags)
{
	int err;
	aufs_bindex_t bindex;
	struct file *h_file;
	struct dentry *dentry;
	struct au_finfo *finfo;

	FiMustWriteLock(file);

	err = 0;
	dentry = file->f_dentry;
	finfo = au_fi(file);
	memset(&finfo->fi_htop, 0, sizeof(finfo->fi_htop));
	atomic_set(&finfo->fi_mmapped, 0);
	bindex = au_dbstart(dentry);
	h_file = au_h_open(dentry, bindex, flags, file, /*force_wr*/0);
	if (IS_ERR(h_file))
		err = PTR_ERR(h_file);
	else {
		au_set_fbstart(file, bindex);
		au_set_h_fptr(file, bindex, h_file);
		au_update_figen(file);
		finfo->fi_file = file;
		au_sphl_add(&finfo->fi_hlist, &au_sbi(dentry->d_sb)->si_files);
		/* todo: necessary? */
		/* file->f_ra = h_file->f_ra; */
	}

	return err;
}
static int au_wbr_create_mfs(struct dentry *dentry, int isdir __maybe_unused)
{
	int err;
	struct super_block *sb;
	struct au_wbr_mfs *mfs;

	err = au_wbr_create_exp(dentry);
	if (err >= 0)
		goto out;

	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_br_rdonly(au_sbr(sb, mfs->mfs_bindex)))
		au_mfs(dentry);
	mutex_unlock(&mfs->mfs_lock);
	err = mfs->mfs_bindex;

	if (err >= 0)
		err = au_wbr_nonopq(dentry, err);

out:
	AuDbg("b%d\n", err);
	return err;
}
Beispiel #6
0
void au_fhsm_wrote(struct super_block *sb, aufs_bindex_t bindex, int force)
{
	int err;
	struct au_sbinfo *sbinfo;
	struct au_fhsm *fhsm;
	struct au_branch *br;
	struct au_br_fhsm *bf;

	AuDbg("b%d, force %d\n", bindex, force);
	SiMustAnyLock(sb);

	sbinfo = au_sbi(sb);
	fhsm = &sbinfo->si_fhsm;
	if (!au_ftest_si(sbinfo, FHSM)
	    || fhsm->fhsm_bottom == bindex)
		return;

	br = au_sbr(sb, bindex);
	bf = br->br_fhsm;
	AuDebugOn(!bf);
	mutex_lock(&bf->bf_lock);
	if (force
	    || au_fhsm_pid(fhsm)
	    || au_fhsm_test_jiffy(sbinfo, br))
		err = au_fhsm_stfs(sb, bindex, /*rstfs*/NULL, /*do_lock*/0,
				  /*do_notify*/1);
	mutex_unlock(&bf->bf_lock);
}
Beispiel #7
0
/*
 * decide the branch and the parent dir where we will create a new entry.
 * returns new bindex or an error.
 * copyup the parent dir if needed.
 */
int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry,
	      struct au_wr_dir_args *args)
{
	int err;
	aufs_bindex_t bcpup, bstart, src_bstart;
	const unsigned char add_entry = !!au_ftest_wrdir(args->flags,
							 ADD_ENTRY);
	struct super_block *sb;
	struct dentry *parent;
	struct au_sbinfo *sbinfo;

	sb = dentry->d_sb;
	sbinfo = au_sbi(sb);
	parent = dget_parent(dentry);
	bstart = au_dbstart(dentry);
	bcpup = bstart;
	if (args->force_btgt < 0) {
		if (src_dentry) {
			src_bstart = au_dbstart(src_dentry);
			if (src_bstart < bstart)
				bcpup = src_bstart;
		} else if (add_entry) {
			err = AuWbrCreate(sbinfo, dentry,
					  au_ftest_wrdir(args->flags, ISDIR));
			bcpup = err;
		}

		if (bcpup < 0 || au_test_ro(sb, bcpup, dentry->d_inode)) {
			if (add_entry)
				err = AuWbrCopyup(sbinfo, dentry);
			else {
				if (!IS_ROOT(dentry)) {
					di_read_lock_parent(parent, !AuLock_IR);
					err = AuWbrCopyup(sbinfo, dentry);
					di_read_unlock(parent, !AuLock_IR);
				} else
					err = AuWbrCopyup(sbinfo, dentry);
			}
			bcpup = err;
			if (unlikely(err < 0))
				goto out;
		}
	} else {
		bcpup = args->force_btgt;
		AuDebugOn(au_test_ro(sb, bcpup, dentry->d_inode));
	}
	AuDbg("bstart %d, bcpup %d\n", bstart, bcpup);
	err = bcpup;
	if (bcpup == bstart)
		goto out; /* success */
	else if (bstart < bcpup)
		au_update_dbrange(dentry, /*do_put_zero*/1);

	/* copyup the new parent into the branch we process */
	err = au_wr_dir_cpup(dentry, parent, add_entry, bcpup, bstart);

 out:
	dput(parent);
	return err;
}
static void au_br_do_del(struct super_block *sb, aufs_bindex_t bindex,
			 struct au_branch *br)
{
	aufs_bindex_t bend;
	struct au_sbinfo *sbinfo;
	struct dentry *root, *h_root;
	struct inode *inode, *h_inode;
	struct au_hinode *hinode;

	SiMustWriteLock(sb);

	root = sb->s_root;
	inode = root->d_inode;
	sbinfo = au_sbi(sb);
	bend = sbinfo->si_bend;

	h_root = au_h_dptr(root, bindex);
	hinode = au_hi(inode, bindex);
	h_inode = au_igrab(hinode->hi_inode);
	au_hiput(hinode);

	au_sbilist_lock();
	au_br_do_del_brp(sbinfo, bindex, bend);
	au_br_do_del_hdp(au_di(root), bindex, bend);
	au_br_do_del_hip(au_ii(inode), bindex, bend);
	au_sbilist_unlock();

	dput(h_root);
	iput(h_inode);
	au_br_do_free(br);
}
Beispiel #9
0
static char *au_build_path(struct dentry *h_parent, struct path *h_rootpath,
			   char *buf, int len, struct super_block *sb)
{
	char *p;
	int n;

	AuTraceEnter();

	p = d_path(h_rootpath->dentry, h_rootpath->mnt, buf, len);
	if (IS_ERR(p))
		goto out;
	n = strlen(p);

	p = d_path(h_parent, h_rootpath->mnt, buf, len);
	if (IS_ERR(p))
		goto out;
	LKTRTrace("%s\n", p);
	if (n != 1)
		p += n;
	LKTRTrace("%p, %s, %ld\n",
		  p, p, (long)(p - buf));

	p = d_path(sb->s_root, au_sbi(sb)->si_mnt, buf, len - strlen(p));
	if (IS_ERR(p))
		goto out;
	if (n != 1)
		p[strlen(p)] = '/';
	LKTRTrace("%s\n", p);

 out:
	AuTraceErrPtr(p);
	return p;
}
/* cf. aufs_rmdir() */
static int au_ren_del_whtmp(struct au_ren_args *a)
{
	int err;
	struct inode *dir;

	dir = a->dst_dir;
	SiMustAnyLock(dir->i_sb);
	if (!au_nhash_test_longer_wh(&a->whlist, a->btgt,
				     au_sbi(dir->i_sb)->si_dirwh)
	    || au_test_fs_remote(a->h_dst->d_sb)) {
		err = au_whtmp_rmdir(dir, a->btgt, a->h_dst, &a->whlist);
		if (unlikely(err))
			pr_warning("failed removing whtmp dir %.*s (%d), "
				   "ignored.\n", AuDLNPair(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;
}
Beispiel #11
0
static /* noinline_for_stack */
struct dentry *decode_by_dir_ino(struct super_block *sb, ino_t ino,
				 ino_t dir_ino, struct au_nfsd_si_lock *nsi_lock)
{
	struct dentry *dentry, *parent;
	struct path path;

	LKTRTrace("i%lu, diri%lu\n",
		  (unsigned long)ino, (unsigned long)dir_ino);

	parent = sb->s_root;
	if (dir_ino != AUFS_ROOT_INO) {
		parent = decode_by_ino(sb, dir_ino, 0);
		dentry = parent;
		if (!parent)
			goto out;
		if (IS_ERR(parent))
			goto out;
		AuDebugOn(au_test_anon(parent));
	} else
		dget(parent);

	path.dentry = parent;
	path.mnt = au_sbi(sb)->si_mnt;
	dentry = au_lkup_by_ino(&path, ino, nsi_lock);
	dput(parent);

 out:
	AuTraceErrPtr(dentry);
	return dentry;
}
Beispiel #12
0
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;
}
Beispiel #13
0
static void au_do_dir_ts(void *arg)
{
	struct au_dir_ts_arg *a = arg;
	struct au_dtime dt;
	struct path h_path;
	struct inode *dir, *h_dir;
	struct super_block *sb;
	struct au_branch *br;
	struct au_hinode *hdir;
	int err;
	aufs_bindex_t btop, bindex;

	sb = a->dentry->d_sb;
	if (d_really_is_negative(a->dentry))
		goto out;
	/* no dir->i_mutex lock */
	aufs_read_lock(a->dentry, AuLock_DW); /* noflush */

	dir = d_inode(a->dentry);
	btop = au_ibtop(dir);
	bindex = au_br_index(sb, a->brid);
	if (bindex < btop)
		goto out_unlock;

	br = au_sbr(sb, bindex);
	h_path.dentry = au_h_dptr(a->dentry, bindex);
	if (!h_path.dentry)
		goto out_unlock;
	h_path.mnt = au_br_mnt(br);
	au_dtime_store(&dt, a->dentry, &h_path);

	br = au_sbr(sb, btop);
	if (!au_br_writable(br->br_perm))
		goto out_unlock;
	h_path.dentry = au_h_dptr(a->dentry, btop);
	h_path.mnt = au_br_mnt(br);
	err = vfsub_mnt_want_write(h_path.mnt);
	if (err)
		goto out_unlock;
	hdir = au_hi(dir, btop);
	au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT);
	h_dir = au_h_iptr(dir, btop);
	if (h_dir->i_nlink
	    && timespec_compare(&h_dir->i_mtime, &dt.dt_mtime) < 0) {
		dt.dt_h_path = h_path;
		au_dtime_revert(&dt);
	}
	au_hn_inode_unlock(hdir);
	vfsub_mnt_drop_write(h_path.mnt);
	au_cpup_attr_timesizes(dir);

out_unlock:
	aufs_read_unlock(a->dentry, AuLock_DW);
out:
	dput(a->dentry);
	au_nwt_done(&au_sbi(sb)->si_nowait);
	kfree(arg);
}
Beispiel #14
0
/*
 * during a user process maintains the pseudo-links,
 * prohibit adding a new plink and branch manipulation.
 */
void au_plink_maint_block(struct super_block *sb)
{
	struct au_sbinfo *sbi = au_sbi(sb);

	SiMustAnyLock(sb);

	/* gave up wake_up_bit() */
	wait_event(sbi->si_plink_wq, !sbi->si_plink_maint);
}
Beispiel #15
0
/*
 * during a user process maintains the pseudo-links,
 * prohibit adding a new plink and branch manipulation.
 */
void au_plink_block_maintain(struct super_block *sb)
{
	struct au_sbinfo *sbi = au_sbi(sb);

	SiMustAnyLock(sb);

	/* gave up wake_up_bit() */
	wait_event(sbi->si_plink_wq, !au_ftest_si(sbi, MAINTAIN_PLINK));
}
Beispiel #16
0
void au_xigen_clr(struct super_block *sb)
{
	struct au_sbinfo *sbinfo;

	sbinfo = au_sbi(sb);
	if (sbinfo->si_xigen) {
		fput(sbinfo->si_xigen);
		sbinfo->si_xigen = NULL;
	}
}
Beispiel #17
0
int si_pid_test_slow(struct super_block *sb)
{
	void *p;

	rcu_read_lock();
	p = radix_tree_lookup(&au_sbi(sb)->au_si_pid.tree, current->pid);
	rcu_read_unlock();

	return (long)!!p;
}
Beispiel #18
0
static void sysrq_sb(struct super_block *sb)
{
	char *plevel;
	struct inode *i;
	struct au_sbinfo *sbinfo;
	struct file *file;

	plevel = au_plevel;
	au_plevel = KERN_WARNING;
	au_debug_on();

	sbinfo = au_sbi(sb);
	pr_warning("si=%lx\n", au_si_mask ^ (unsigned long)sbinfo);
	pr_warning(AUFS_NAME ": superblock\n");
	au_dpri_sb(sb);
	pr_warning(AUFS_NAME ": root dentry\n");
	au_dpri_dentry(sb->s_root);
	pr_warning(AUFS_NAME ": root inode\n");
	au_dpri_inode(sb->s_root->d_inode);
	pr_warning(AUFS_NAME ": isolated inode\n");
	list_for_each_entry(i, &sb->s_inodes, i_sb_list)
		if (list_empty(&i->i_dentry))
			au_dpri_inode(i);
	pr_warning(AUFS_NAME ": files\n");
	list_for_each_entry(file, &sb->s_files, f_u.fu_list)
		if (au_test_aufs_file(file))
			au_dpri_file(file);

#ifdef CONFIG_AUFS_DEBUG_LOCK
	{
		struct au_dbg_lock *p;
		struct list_head *head;

		pr_warning(AUFS_NAME ": locking si\n");
		head = &sbinfo->si_dbg_lock[AuDbgLock_SI_LOCKING].head;
		list_for_each_entry(p, head, list)
			pr_warning("pid: %d, 0x%x\n", p->pid, p->flags);
		pr_warning(AUFS_NAME ": locked si\n");
		head = &sbinfo->si_dbg_lock[AuDbgLock_SI_LOCKED].head;
		list_for_each_entry(p, head, list)
			pr_warning("pid: %d, 0x%x\n", p->pid, p->flags);
		pr_warning(AUFS_NAME ": locking di\n");
		head = &sbinfo->si_dbg_lock[AuDbgLock_DI_LOCKING].head;
		list_for_each_entry(p, head, list) {
			pr_warning("pid: %d, 0x%x, %d\n",
				   p->pid, p->flags, p->lsc);
			au_dpri_dentry(p->dentry);
		}
		pr_warning(AUFS_NAME ": locked di\n");
		head = &sbinfo->si_dbg_lock[AuDbgLock_DI_LOCKED].head;
		list_for_each_entry(p, head, list) {
			pr_warning("pid: %d, 0x%x, %d\n",
				   p->pid, p->flags, p->lsc);
			au_dpri_dentry(p->dentry);
		}
Beispiel #19
0
/* most free space */
static void au_mfs(struct dentry *dentry)
{
	struct super_block *sb;
	struct au_branch *br;
	struct au_wbr_mfs *mfs;
	aufs_bindex_t bindex, bend;
	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;
	bend = au_sbend(sb);
	for (bindex = 0; bindex <= bend; bindex++) {
		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.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);
	kfree(st);
}
Beispiel #20
0
static int aufs_commit_metadata(struct inode *inode)
{
	int err;
	aufs_bindex_t bindex;
	struct super_block *sb;
	struct inode *h_inode;
	int (*f)(struct inode *inode);

	sb = inode->i_sb;
	si_read_lock(sb, AuLock_FLUSH);
	ii_write_lock_child(inode);
	bindex = au_ibstart(inode);
	AuDebugOn(bindex < 0);
	h_inode = au_h_iptr(inode, bindex);

	f = h_inode->i_sb->s_export_op->commit_metadata;
	if (f)
		err = f(h_inode);
	else {
		struct writeback_control wbc = {
			.sync_mode	= WB_SYNC_ALL,
			.nr_to_write	= 0 /* metadata only */
		};

		err = sync_inode(h_inode, &wbc);
	}

	au_cpup_attr_timesizes(inode);
	ii_write_unlock(inode);
	si_read_unlock(sb);
	return err;
}

/* ---------------------------------------------------------------------- */

static struct export_operations aufs_export_op = {
	.fh_to_dentry		= aufs_fh_to_dentry,
	/* .fh_to_parent	= aufs_fh_to_parent, */
	.encode_fh		= aufs_encode_fh,
	.commit_metadata	= aufs_commit_metadata
};

void au_export_init(struct super_block *sb)
{
	struct au_sbinfo *sbinfo;
	__u32 u;

	sb->s_export_op = &aufs_export_op;
	sbinfo = au_sbi(sb);
	sbinfo->si_xigen = NULL;
	get_random_bytes(&u, sizeof(u));
	BUILD_BUG_ON(sizeof(u) != sizeof(int));
	atomic_set(&sbinfo->si_xigen_next, u);
}
Beispiel #21
0
int au_opts_remount(struct super_block *sb, struct au_opts *opts)
{
	int err, rerr;
	unsigned char no_dreval;
	struct inode *dir;
	struct au_opt_xino *opt_xino;
	struct au_opt *opt;
	struct au_sbinfo *sbinfo;

	SiMustWriteLock(sb);

	err = 0;
	dir = d_inode(sb->s_root);
	sbinfo = au_sbi(sb);
	opt_xino = NULL;
	opt = opts->opt;
	while (err >= 0 && opt->type != Opt_tail) {
		err = au_opt_simple(sb, opt, opts);
		if (!err)
			err = au_opt_br(sb, opt, opts);
		if (!err)
			err = au_opt_xino(sb, opt, &opt_xino, opts);
		opt++;
	}
	if (err > 0)
		err = 0;
	AuTraceErr(err);
	/* go on even err */

	no_dreval = !!au_ftest_si(sbinfo, NO_DREVAL);
	rerr = au_opts_verify(sb, opts->sb_flags, /*pending*/0);
	if (unlikely(rerr && !err))
		err = rerr;

	if (no_dreval != !!au_ftest_si(sbinfo, NO_DREVAL))
		au_fset_opts(opts->flags, REFRESH_IDOP);

	if (au_ftest_opts(opts->flags, TRUNC_XIB)) {
		rerr = au_xib_trunc(sb);
		if (unlikely(rerr && !err))
			err = rerr;
	}

	/* will be handled by the caller */
	if (!au_ftest_opts(opts->flags, REFRESH)
	    && (opts->given_udba
		|| au_opt_test(sbinfo->si_mntflags, XINO)
		|| au_ftest_opts(opts->flags, REFRESH_IDOP)
		    ))
		au_fset_opts(opts->flags, REFRESH);

	AuDbg("status 0x%x\n", opts->flags);
	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;
}
/* round robin */
static int au_wbr_create_init_rr(struct super_block *sb)
{
	int err;

	err = au_wbr_bu(sb, au_sbend(sb));
	atomic_set(&au_sbi(sb)->si_wbr_rr_next, -err); /* less important */
	/* smp_mb(); */

	AuDbg("b%d\n", err);
	return err;
}
Beispiel #24
0
unsigned int au_sigen_inc(struct super_block *sb)
{
	unsigned int gen;

	SiMustWriteLock(sb);

	gen = ++au_sbi(sb)->si_generation;
	au_update_digen(sb->s_root);
	au_update_iigen(sb->s_root->d_inode, /*half*/0);
	sb->s_root->d_inode->i_version++;
	return gen;
}
Beispiel #25
0
void au_fhsm_set_bottom(struct super_block *sb, aufs_bindex_t bindex)
{
	struct au_sbinfo *sbinfo;
	struct au_fhsm *fhsm;

	SiMustWriteLock(sb);

	sbinfo = au_sbi(sb);
	fhsm = &sbinfo->si_fhsm;
	AuDebugOn(!fhsm);
	fhsm->fhsm_bottom = bindex;
}
Beispiel #26
0
/*
 * decide if a new whiteout for @dentry is necessary or not.
 * when it is necessary, prepare the parent dir for the upper branch whose
 * branch index is @bcpup for creation. the actual creation of the whiteout will
 * be done by caller.
 * return value:
 * 0: wh is unnecessary
 * plus: wh is necessary
 * minus: error
 */
int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup)
{
	int need_wh, err;
	aufs_bindex_t bstart;
	struct super_block *sb;

	sb = dentry->d_sb;
	bstart = au_dbstart(dentry);
	if (*bcpup < 0) {
		*bcpup = bstart;
		if (au_test_ro(sb, bstart, dentry->d_inode)) {
			err = AuWbrCopyup(au_sbi(sb), dentry);
			*bcpup = err;
			if (unlikely(err < 0))
				goto out;
		}
	} else
		AuDebugOn(bstart < *bcpup
			  || au_test_ro(sb, *bcpup, dentry->d_inode));
	AuDbg("bcpup %d, bstart %d\n", *bcpup, bstart);

	if (*bcpup != bstart) {
		err = au_cpup_dirs(dentry, *bcpup);
		if (unlikely(err))
			goto out;
		need_wh = 1;
	} else {
		aufs_bindex_t old_bend, new_bend, bdiropq = -1;

		old_bend = au_dbend(dentry);
		if (isdir) {
			bdiropq = au_dbdiropq(dentry);
			au_set_dbdiropq(dentry, -1);
		}
		need_wh = au_lkup_dentry(dentry, bstart + 1, /*type*/0,
					 /*nd*/NULL);
		err = need_wh;
		if (isdir)
			au_set_dbdiropq(dentry, bdiropq);
		if (unlikely(err < 0))
			goto out;
		new_bend = au_dbend(dentry);
		if (!need_wh && old_bend != new_bend) {
			au_set_h_dptr(dentry, new_bend, NULL);
			au_set_dbend(dentry, old_bend);
		}
	}
	AuDbg("need_wh %d\n", need_wh);
	err = need_wh;

out:
	return err;
}
Beispiel #27
0
static aufs_bindex_t au_fhsm_bottom(struct super_block *sb)
{
	struct au_sbinfo *sbinfo;
	struct au_fhsm *fhsm;

	SiMustAnyLock(sb);

	sbinfo = au_sbi(sb);
	fhsm = &sbinfo->si_fhsm;
	AuDebugOn(!fhsm);
	return fhsm->fhsm_bottom;
}
Beispiel #28
0
void si_pid_clr_slow(struct super_block *sb)
{
	void *p;
	struct au_sbinfo *sbinfo;

	AuDebugOn(!si_pid_test_slow(sb));

	sbinfo = au_sbi(sb);
	spin_lock(&sbinfo->au_si_pid.tree_lock);
	p = radix_tree_delete(&sbinfo->au_si_pid.tree, current->pid);
	spin_unlock(&sbinfo->au_si_pid.tree_lock);
}
Beispiel #29
0
int au_xigen_new(struct inode *inode)
{
	int err;
	loff_t pos;
	ssize_t sz;
	struct super_block *sb;
	struct au_sbinfo *sbinfo;
	struct file *file;

	LKTRTrace("i%lu\n", inode->i_ino);

	err = 0;
	/* todo: dirty, at mount time */
	if (inode->i_ino == AUFS_ROOT_INO)
		goto out;
	sb = inode->i_sb;
	if (unlikely(!au_opt_test_xino(au_mntflags(sb))))
		goto out;

	err = -EFBIG;
	pos = inode->i_ino;
	if (unlikely(Au_LOFF_MAX / sizeof(inode->i_generation) - 1 < pos)) {
		AuIOErr1("too large i%lld\n", pos);
		goto out;
	}
	pos *= sizeof(inode->i_generation);

	err = 0;
	sbinfo = au_sbi(sb);
	file = sbinfo->si_xigen;
	BUG_ON(!file);

	if (i_size_read(file->f_dentry->d_inode)
	    < pos + sizeof(inode->i_generation)) {
		inode->i_generation = atomic_inc_return(&sbinfo->si_xigen_next);
		sz = xino_fwrite(sbinfo->si_xwrite, file, &inode->i_generation,
				 sizeof(inode->i_generation), &pos);
	} else
		sz = xino_fread(sbinfo->si_xread, file, &inode->i_generation,
				sizeof(inode->i_generation), &pos);
	if (sz == sizeof(inode->i_generation))
		goto out; /* success */

	err = sz;
	if (unlikely(sz >= 0)) {
		err = -EIO;
		AuIOErr("xigen error (%zd)\n", sz);
	}

 out:
	AuTraceErr(err);
	return err;
}
Beispiel #30
0
int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb)
{
	int err;

	SiMustAnyLock(sb);

	err = 0;
	if (au_opt_test(au_mntflags(sb), XINO)) {
		err = au_xino_path(seq, au_sbi(sb)->si_xib);
		seq_putc(seq, '\n');
	}
	return err;
}