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();
		}
	}
}
static int test_inode_busy(struct super_block *sb, aufs_bindex_t bindex,
			   unsigned int sigen, const unsigned int verbose)
{
	int err;
	unsigned long long max, ull;
	struct inode *i, **array;
	aufs_bindex_t bstart, bend;

	array = au_iarray_alloc(sb, &max);
	err = PTR_ERR(array);
	if (IS_ERR(array))
		goto out;

	err = 0;
	AuDbg("b%d\n", bindex);
	for (ull = 0; !err && ull < max; ull++) {
		i = array[ull];
		if (i->i_ino == AUFS_ROOT_INO)
			continue;

		/* AuDbgInode(i); */
		if (au_iigen(i) == sigen)
			ii_read_lock_child(i);
		else {
			ii_write_lock_child(i);
			err = au_refresh_hinode_self(i);
			au_iigen_dec(i);
			if (!err)
				ii_downgrade_lock(i);
			else {
				ii_write_unlock(i);
				break;
			}
		}

		bstart = au_ibstart(i);
		bend = au_ibend(i);
		if (bstart <= bindex
		    && bindex <= bend
		    && au_h_iptr(i, bindex)
		    && au_test_ibusy(i, bstart, bend)) {
			err = -EBUSY;
			AuVerbose(verbose, "busy i%lu\n", i->i_ino);
			AuDbgInode(i);
		}
		ii_read_unlock(i);
	}
	au_iarray_free(array, max);

out:
	return err;
}
Beispiel #3
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;
}