static int au_ren_lock(struct au_ren_args *a)
{
	int err;
	unsigned int udba;

	err = 0;
	a->src_h_parent = au_h_dptr(a->src_parent, a->btgt);
	a->src_hdir = au_hi(a->src_dir, a->btgt);
	a->dst_h_parent = au_h_dptr(a->dst_parent, a->btgt);
	a->dst_hdir = au_hi(a->dst_dir, a->btgt);
	a->h_trap = vfsub_lock_rename(a->src_h_parent, a->src_hdir,
				      a->dst_h_parent, a->dst_hdir);
	udba = au_opt_udba(a->src_dentry->d_sb);
	if (unlikely(a->src_hdir->hi_inode != a->src_h_parent->d_inode
		     || a->dst_hdir->hi_inode != a->dst_h_parent->d_inode))
		err = au_busy_or_stale();
	if (!err && au_dbstart(a->src_dentry) == a->btgt)
		err = au_h_verify(a->src_h_dentry, udba,
				  a->src_h_parent->d_inode, a->src_h_parent,
				  a->br);
	if (!err && au_dbstart(a->dst_dentry) == a->btgt)
		err = au_h_verify(a->dst_h_dentry, udba,
				  a->dst_h_parent->d_inode, a->dst_h_parent,
				  a->br);
	if (!err) {
		err = mnt_want_write(a->br->br_mnt);
		if (unlikely(err))
			goto out_unlock;
		au_fset_ren(a->flags, MNT_WRITE);
		goto out; /* success */
	}

	err = au_busy_or_stale();

out_unlock:
	au_ren_unlock(a);
out:
	return err;
}
Example #2
0
int au_do_pin(struct au_pin *p)
{
	int err;
	struct super_block *sb;
	struct dentry *h_dentry, *h_parent;
	struct au_branch *br;
	struct inode *h_dir;

	err = 0;
	sb = p->dentry->d_sb;
	br = au_sbr(sb, p->bindex);
	if (IS_ROOT(p->dentry)) {
		if (au_ftest_pin(p->flags, MNT_WRITE)) {
			p->h_mnt = br->br_mnt;
			err = mnt_want_write(p->h_mnt);
			if (unlikely(err)) {
				au_fclr_pin(p->flags, MNT_WRITE);
				goto out_err;
			}
		}
		goto out;
	}

	h_dentry = NULL;
	if (p->bindex <= au_dbend(p->dentry))
		h_dentry = au_h_dptr(p->dentry, p->bindex);

	p->parent = dget_parent(p->dentry);
	if (!au_ftest_pin(p->flags, DI_LOCKED))
		di_read_lock(p->parent, AuLock_IR, p->lsc_di);

	h_dir = NULL;
	h_parent = au_h_dptr(p->parent, p->bindex);
	p->hdir = au_hi(p->parent->d_inode, p->bindex);
	if (p->hdir)
		h_dir = p->hdir->hi_inode;

	/*
	 * udba case, or
	 * if DI_LOCKED is not set, then p->parent may be different
	 * and h_parent can be NULL.
	 */
	if (unlikely(!p->hdir || !h_dir || !h_parent)) {
		err = -EBUSY;
		if (!au_ftest_pin(p->flags, DI_LOCKED))
			di_read_unlock(p->parent, AuLock_IR);
		dput(p->parent);
		p->parent = NULL;
		goto out_err;
	}

	au_igrab(h_dir);
	au_hn_imtx_lock_nested(p->hdir, p->lsc_hi);

	if (unlikely(p->hdir->hi_inode != h_parent->d_inode)) {
		err = -EBUSY;
		goto out_unpin;
	}
	if (h_dentry) {
		err = au_h_verify(h_dentry, p->udba, h_dir, h_parent, br);
		if (unlikely(err)) {
			au_fclr_pin(p->flags, MNT_WRITE);
			goto out_unpin;
		}
	}

	if (au_ftest_pin(p->flags, MNT_WRITE)) {
		p->h_mnt = br->br_mnt;
		err = mnt_want_write(p->h_mnt);
		if (unlikely(err)) {
			au_fclr_pin(p->flags, MNT_WRITE);
			goto out_unpin;
		}
	}
	goto out; /* success */

out_unpin:
	au_unpin(p);
out_err:
	pr_err("err %d\n", err);
	err = au_busy_or_stale();
out:
	return err;
}