static void au_ren_refresh(struct au_ren_args *a)
{
	aufs_bindex_t bend, bindex;
	struct dentry *d, *h_d;
	struct inode *i, *h_i;
	struct super_block *sb;

	d = a->dst_dentry;
	d_drop(d);
	if (a->h_dst)
		/* already dget-ed by au_ren_or_cpup() */
		au_set_h_dptr(d, a->btgt, a->h_dst);

	i = a->dst_inode;
	if (i) {
		if (!au_ftest_ren(a->flags, ISDIR))
			vfsub_drop_nlink(i);
		else {
			vfsub_dead_dir(i);
			au_cpup_attr_timesizes(i);
		}
		au_update_dbrange(d, /*do_put_zero*/1);
	} else {
		bend = a->btgt;
		for (bindex = au_dbstart(d); bindex < bend; bindex++)
			au_set_h_dptr(d, bindex, NULL);
		bend = au_dbend(d);
		for (bindex = a->btgt + 1; bindex <= bend; bindex++)
			au_set_h_dptr(d, bindex, NULL);
		au_update_dbrange(d, /*do_put_zero*/0);
	}

	d = a->src_dentry;
	au_set_dbwh(d, -1);
	bend = au_dbend(d);
	for (bindex = a->btgt + 1; bindex <= bend; bindex++) {
		h_d = au_h_dptr(d, bindex);
		if (h_d)
			au_set_h_dptr(d, bindex, NULL);
	}
	au_set_dbend(d, a->btgt);

	sb = d->d_sb;
	i = a->src_inode;
	if (au_opt_test(au_mntflags(sb), PLINK) && au_plink_test(i))
		return; /* success */

	bend = au_ibend(i);
	for (bindex = a->btgt + 1; bindex <= bend; bindex++) {
		h_i = au_h_iptr(i, bindex);
		if (h_i) {
			au_xino_write(sb, bindex, h_i->i_ino, /*ino*/0);
			/* ignore this error */
			au_set_h_iptr(i, bindex, NULL, 0);
		}
	}
	au_set_ibend(i, a->btgt);
}
Exemplo n.º 2
0
/*
 * when an error happened, remove the created whiteout and revert everything.
 */
static int do_revert(int err, struct inode *dir, aufs_bindex_t bindex,
		     aufs_bindex_t bwh, struct dentry *wh_dentry,
		     struct dentry *dentry, struct au_dtime *dt)
{
	int rerr;
	struct path h_path = {
		.dentry	= wh_dentry,
		.mnt	= au_sbr_mnt(dir->i_sb, bindex)
	};

	rerr = au_wh_unlink_dentry(au_h_iptr(dir, bindex), &h_path, dentry);
	if (!rerr) {
		au_set_dbwh(dentry, bwh);
		au_dtime_revert(dt);
		return 0;
	}

	AuIOErr("%.*s reverting whiteout failed(%d, %d)\n",
		AuDLNPair(dentry), err, rerr);
	return -EIO;
}

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

int aufs_unlink(struct inode *dir, struct dentry *dentry)
{
	int err;
	aufs_bindex_t bwh, bindex, bstart;
	struct au_dtime dt;
	struct au_pin pin;
	struct path h_path;
	struct inode *inode, *h_dir;
	struct dentry *parent, *wh_dentry;

	IMustLock(dir);

	err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN);
	if (unlikely(err))
		goto out;
	err = au_d_hashed_positive(dentry);
	if (unlikely(err))
		goto out_unlock;
	inode = dentry->d_inode;
	IMustLock(inode);
	err = -EISDIR;
	if (unlikely(S_ISDIR(inode->i_mode)))
		goto out_unlock; /* possible? */

	bstart = au_dbstart(dentry);
	bwh = au_dbwh(dentry);
	bindex = -1;
	parent = dentry->d_parent; /* dir inode is locked */
	di_write_lock_parent(parent);
	wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/0, &bindex, &dt, &pin);
	err = PTR_ERR(wh_dentry);
	if (IS_ERR(wh_dentry))
		goto out_parent;

	h_path.mnt = au_sbr_mnt(dentry->d_sb, bstart);
	h_path.dentry = au_h_dptr(dentry, bstart);
	dget(h_path.dentry);
	if (bindex == bstart) {
		h_dir = au_pinned_h_dir(&pin);
		err = vfsub_unlink(h_dir, &h_path, /*force*/0);
	} else {
		/* dir inode is locked */
		h_dir = wh_dentry->d_parent->d_inode;
		IMustLock(h_dir);
		err = 0;
	}

	if (!err) {
		vfsub_drop_nlink(inode);
		epilog(dir, dentry, bindex);

		/* update target timestamps */
		if (bindex == bstart) {
			vfsub_update_h_iattr(&h_path, /*did*/NULL); /*ignore*/
			inode->i_ctime = h_path.dentry->d_inode->i_ctime;
		} else
			/* todo: this timestamp may be reverted later */
			inode->i_ctime = h_dir->i_ctime;
		goto out_unpin; /* success */
	}

	/* revert */
	if (wh_dentry) {
		int rerr;

		rerr = do_revert(err, dir, bindex, bwh, wh_dentry, dentry, &dt);
		if (rerr)
			err = rerr;
	}

out_unpin:
	au_unpin(&pin);
	dput(wh_dentry);
	dput(h_path.dentry);
out_parent:
	di_write_unlock(parent);
out_unlock:
	aufs_read_unlock(dentry, AuLock_DW);
out:
	return err;
}
Exemplo n.º 3
0
/*
 * when an error happened, remove the created whiteout and revert everything.
 */
static int do_revert(int err, struct inode *dir, aufs_bindex_t bindex,
		     aufs_bindex_t bwh, struct dentry *wh_dentry,
		     struct dentry *dentry, struct au_dtime *dt)
{
	int rerr;
	struct path h_path = {
		.dentry	= wh_dentry,
		.mnt	= au_sbr_mnt(dir->i_sb, bindex)
	};

	rerr = au_wh_unlink_dentry(au_h_iptr(dir, bindex), &h_path, dentry);
	if (!rerr) {
		au_set_dbwh(dentry, bwh);
		au_dtime_revert(dt);
		return 0;
	}

	AuIOErr("%pd reverting whiteout failed(%d, %d)\n", dentry, err, rerr);
	return -EIO;
}

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

int aufs_unlink(struct inode *dir, struct dentry *dentry)
{
	int err;
	aufs_bindex_t bwh, bindex, bstart;
	struct inode *inode, *h_dir, *delegated;
	struct dentry *parent, *wh_dentry;
	/* to reuduce stack size */
	struct {
		struct au_dtime dt;
		struct au_pin pin;
		struct path h_path;
	} *a;

	IMustLock(dir);

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

	err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN);
	if (unlikely(err))
		goto out_free;
	err = au_d_hashed_positive(dentry);
	if (unlikely(err))
		goto out_unlock;
	inode = d_inode(dentry);
	IMustLock(inode);
	err = -EISDIR;
	if (unlikely(d_is_dir(dentry)))
		goto out_unlock; /* possible? */

	bstart = au_dbstart(dentry);
	bwh = au_dbwh(dentry);
	bindex = -1;
	parent = dentry->d_parent; /* dir inode is locked */
	di_write_lock_parent(parent);
	wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/0, &bindex, &a->dt,
					&a->pin);
	err = PTR_ERR(wh_dentry);
	if (IS_ERR(wh_dentry))
		goto out_parent;

	a->h_path.mnt = au_sbr_mnt(dentry->d_sb, bstart);
	a->h_path.dentry = au_h_dptr(dentry, bstart);
	dget(a->h_path.dentry);
	if (bindex == bstart) {
		h_dir = au_pinned_h_dir(&a->pin);
		delegated = NULL;
		err = vfsub_unlink(h_dir, &a->h_path, &delegated, /*force*/0);
		if (unlikely(err == -EWOULDBLOCK)) {
			pr_warn("cannot retry for NFSv4 delegation"
				" for an internal unlink\n");
			iput(delegated);
		}
	} else {
		/* dir inode is locked */
		h_dir = d_inode(wh_dentry->d_parent);
		IMustLock(h_dir);
		err = 0;
	}

	if (!err) {
		vfsub_drop_nlink(inode);
		epilog(dir, dentry, bindex);

		/* update target timestamps */
		if (bindex == bstart) {
			vfsub_update_h_iattr(&a->h_path, /*did*/NULL);
			/*ignore*/
			inode->i_ctime = d_inode(a->h_path.dentry)->i_ctime;
		} else
			/* todo: this timestamp may be reverted later */
			inode->i_ctime = h_dir->i_ctime;
		goto out_unpin; /* success */
	}

	/* revert */
	if (wh_dentry) {
		int rerr;

		rerr = do_revert(err, dir, bindex, bwh, wh_dentry, dentry,
				 &a->dt);
		if (rerr)
			err = rerr;
	}

out_unpin:
	au_unpin(&a->pin);
	dput(wh_dentry);
	dput(a->h_path.dentry);
out_parent:
	di_write_unlock(parent);
out_unlock:
	aufs_read_unlock(dentry, AuLock_DW);
out_free:
	kfree(a);
out:
	return err;
}