Ejemplo n.º 1
0
void __au_dbg_verify_dinode(struct dentry *dentry, const char *func, int line)
{
	struct inode *h_inode, *inode = dentry->d_inode;
	struct dentry *h_dentry;
	aufs_bindex_t bindex, bend, bi;

	if (!inode /* || au_di(dentry)->di_lsc == AuLsc_DI_TMP */)
		return;

	bend = au_dbend(dentry);
	bi = au_ibend(inode);
	if (bi < bend)
		bend = bi;
	bindex = au_dbstart(dentry);
	bi = au_ibstart(inode);
	if (bi > bindex)
		bindex = bi;

	for (; bindex <= bend; bindex++) {
		h_dentry = au_h_dptr(dentry, bindex);
		if (!h_dentry)
			continue;
		h_inode = au_h_iptr(inode, bindex);
		if (unlikely(h_inode != h_dentry->d_inode)) {
			au_debug_on();
			AuDbg("b%d, %s:%d\n", bindex, func, line);
			AuDbgDentry(dentry);
			AuDbgInode(inode);
			au_debug_off();
			BUG();
		}
	}
}
Ejemplo n.º 2
0
static void au_hide(struct dentry *dentry)
{
	int err;

	AuDbgDentry(dentry);
	if (d_is_dir(dentry)) {
		/* shrink_dcache_parent(dentry); */
		err = au_hide_children(dentry);
		if (unlikely(err))
			AuIOErr("%pd, failed hiding children, ignored %d\n",
				dentry, err);
	}
	au_do_hide(dentry);
}
Ejemplo n.º 3
0
static void au_hide(struct dentry *dentry)
{
	int err;
	struct inode *inode;

	AuDbgDentry(dentry);
	inode = dentry->d_inode;
	if (inode && S_ISDIR(inode->i_mode)) {
		/* shrink_dcache_parent(dentry); */
		err = au_hide_children(dentry);
		if (unlikely(err))
			AuIOErr("%.*s, failed hiding children, ignored %d\n",
				AuDLNPair(dentry), err);
	}
	au_do_hide(dentry);
}
Ejemplo n.º 4
0
/*
 * extended version of au_h_dptr().
 * returns a hashed and positive (or linkable) h_dentry in bindex, NULL, or
 * error.
 */
struct dentry *au_h_d_alias(struct dentry *dentry, aufs_bindex_t bindex)
{
	struct dentry *h_dentry;
	struct inode *inode, *h_inode;

	inode = dentry->d_inode;
	AuDebugOn(!inode);

	h_dentry = NULL;
	if (au_dbstart(dentry) <= bindex
	    && bindex <= au_dbend(dentry))
		h_dentry = au_h_dptr(dentry, bindex);
	if (h_dentry && !au_d_linkable(h_dentry)) {
		dget(h_dentry);
		goto out; /* success */
	}

	AuDebugOn(bindex < au_ibstart(inode));
	AuDebugOn(au_ibend(inode) < bindex);
	h_inode = au_h_iptr(inode, bindex);
	h_dentry = d_find_alias(h_inode);
	if (h_dentry) {
		if (!IS_ERR(h_dentry)) {
			if (!au_d_linkable(h_dentry))
				goto out; /* success */
			dput(h_dentry);
		} else
			goto out;
	}

	if (au_opt_test(au_mntflags(dentry->d_sb), PLINK)) {
		h_dentry = au_plink_lkup(inode, bindex);
		AuDebugOn(!h_dentry);
		if (!IS_ERR(h_dentry)) {
			if (!au_d_hashed_positive(h_dentry))
				goto out; /* success */
			dput(h_dentry);
			h_dentry = NULL;
		}
	}

out:
	AuDbgDentry(h_dentry);
	return h_dentry;
}
Ejemplo n.º 5
0
int au_mvdown(struct dentry *dentry, struct aufs_mvdown __user *uarg)
{
	int err, e;
	unsigned char dmsg;
	struct au_mvd_args *args;

	err = -EPERM;
	if (unlikely(!capable(CAP_SYS_ADMIN)))
		goto out;

	err = -ENOMEM;
	args = kmalloc(sizeof(*args), GFP_NOFS);
	if (unlikely(!args))
		goto out;

	err = copy_from_user(&args->mvdown, uarg, sizeof(args->mvdown));
	if (!err)
		err = !access_ok(VERIFY_WRITE, uarg, sizeof(*uarg));
	if (unlikely(err)) {
		err = -EFAULT;
		AuTraceErr(err);
		goto out_free;
	}
	AuDbg("flags 0x%x\n", args->mvdown.flags);
	args->mvdown.flags &= ~(AUFS_MVDOWN_ROLOWER_R | AUFS_MVDOWN_ROUPPER_R);
	args->mvdown.au_errno = 0;
	args->dentry = dentry;
	args->inode = dentry->d_inode;
	args->sb = dentry->d_sb;

	err = -ENOENT;
	dmsg = !!(args->mvdown.flags & AUFS_MVDOWN_DMSG);
	args->parent = dget_parent(dentry);
	args->dir = args->parent->d_inode;
	mutex_lock_nested(&args->dir->i_mutex, I_MUTEX_PARENT);
	dput(args->parent);
	if (unlikely(args->parent != dentry->d_parent)) {
		AU_MVD_PR(dmsg, "parent dir is moved\n");
		goto out_dir;
	}

	mutex_lock_nested(&args->inode->i_mutex, I_MUTEX_CHILD);
	err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH);
	if (unlikely(err))
		goto out_inode;

	di_write_lock_parent(args->parent);
	err = au_mvd_args(dmsg, args);
	if (unlikely(err))
		goto out_parent;

	AuDbgDentry(dentry);
	AuDbgInode(args->inode);
	err = au_do_mvdown(dmsg, args);
	if (unlikely(err))
		goto out_parent;
	AuDbgDentry(dentry);
	AuDbgInode(args->inode);

	au_cpup_attr_timesizes(args->dir);
	au_cpup_attr_timesizes(args->inode);
	au_cpup_igen(args->inode, au_h_iptr(args->inode, args->mvd_bdst));
	/* au_digen_dec(dentry); */

out_parent:
	di_write_unlock(args->parent);
	aufs_read_unlock(dentry, AuLock_DW);
out_inode:
	mutex_unlock(&args->inode->i_mutex);
out_dir:
	mutex_unlock(&args->dir->i_mutex);
out_free:
	e = copy_to_user(uarg, &args->mvdown, sizeof(args->mvdown));
	if (unlikely(e))
		err = -EFAULT;
	kfree(args);
out:
	AuTraceErr(err);
	return err;
}
Ejemplo n.º 6
0
int au_refresh_dentry(struct dentry *dentry, struct dentry *parent)
{
	int err, ebrange;
	unsigned int sigen;
	struct au_dinfo *dinfo, *tmp;
	struct super_block *sb;
	struct inode *inode;

	DiMustWriteLock(dentry);
	AuDebugOn(IS_ROOT(dentry));
	AuDebugOn(!parent->d_inode);

	sb = dentry->d_sb;
	inode = dentry->d_inode;
	sigen = au_sigen(sb);
	err = au_digen_test(parent, sigen);
	if (unlikely(err))
		goto out;

	dinfo = au_di(dentry);
	err = au_di_realloc(dinfo, au_sbend(sb) + 1);
	if (unlikely(err))
		goto out;
	ebrange = au_dbrange_test(dentry);
	if (!ebrange)
		ebrange = au_do_refresh_hdentry(dentry, parent);

	if (d_unhashed(dentry) || ebrange) {
		AuDebugOn(au_dbstart(dentry) < 0 && au_dbend(dentry) >= 0);
		if (inode)
			err = au_refresh_hinode_self(inode);
		au_dbg_verify_dinode(dentry);
		if (!err)
			goto out_dgen; /* success */
		goto out;
	}

	/* temporary dinfo */
	AuDbgDentry(dentry);
	err = -ENOMEM;
	tmp = au_di_alloc(sb, AuLsc_DI_TMP);
	if (unlikely(!tmp))
		goto out;
	au_di_swap(tmp, dinfo);
	/* returns the number of positive dentries */
	/*
	 * if current working dir is removed, it returns an error.
	 * but the dentry is legal.
	 */
	err = au_lkup_dentry(dentry, /*bstart*/0, /*type*/0, /*nd*/NULL);
	AuDbgDentry(dentry);
	au_di_swap(tmp, dinfo);
	if (err == -ENOENT)
		err = 0;
	if (err >= 0) {
		/* compare/refresh by dinfo */
		AuDbgDentry(dentry);
		err = au_refresh_by_dinfo(dentry, dinfo, tmp);
		au_dbg_verify_dinode(dentry);
		AuTraceErr(err);
	}
	au_rw_write_unlock(&tmp->di_rwsem);
	au_di_free(tmp);
	if (unlikely(err))
		goto out;

out_dgen:
	au_update_digen(dentry);
out:
	if (unlikely(err && !(dentry->d_flags & DCACHE_NFSFS_RENAMED))) {
		AuIOErr("failed refreshing %.*s, %d\n",
			AuDLNPair(dentry), err);
		AuDbgDentry(dentry);
	}
	AuTraceErr(err);
	return err;
}
/*
 * test if the branch is deletable or not.
 */
static int test_dentry_busy(struct dentry *root, aufs_bindex_t bindex,
			    unsigned int sigen, const unsigned int verbose)
{
	int err, i, j, ndentry;
	aufs_bindex_t bstart, bend;
	struct au_dcsub_pages dpages;
	struct au_dpage *dpage;
	struct dentry *d;

	err = au_dpages_init(&dpages, GFP_NOFS);
	if (unlikely(err))
		goto out;
	err = au_dcsub_pages(&dpages, root, NULL, NULL);
	if (unlikely(err))
		goto out_dpages;

	for (i = 0; !err && i < dpages.ndpage; i++) {
		dpage = dpages.dpages + i;
		ndentry = dpage->ndentry;
		for (j = 0; !err && j < ndentry; j++) {
			d = dpage->dentries[j];
			AuDebugOn(!atomic_read(&d->d_count));
			if (!au_digen_test(d, sigen)) {
				di_read_lock_child(d, AuLock_IR);
				if (unlikely(au_dbrange_test(d))) {
					di_read_unlock(d, AuLock_IR);
					continue;
				}
			} else {
				di_write_lock_child(d);
				if (unlikely(au_dbrange_test(d))) {
					di_write_unlock(d);
					continue;
				}
				err = au_reval_dpath(d, sigen);
				if (!err)
					di_downgrade_lock(d, AuLock_IR);
				else {
					di_write_unlock(d);
					break;
				}
			}

			/* AuDbgDentry(d); */
			bstart = au_dbstart(d);
			bend = au_dbend(d);
			if (bstart <= bindex
			    && bindex <= bend
			    && au_h_dptr(d, bindex)
			    && au_test_dbusy(d, bstart, bend)) {
				err = -EBUSY;
				AuVerbose(verbose, "busy %.*s\n", AuDLNPair(d));
				AuDbgDentry(d);
			}
			di_read_unlock(d, AuLock_IR);
		}
	}

out_dpages:
	au_dpages_free(&dpages);
out:
	return err;
}