Ejemplo n.º 1
0
/*
 * Try to revert everything we have done in __rename_all and __rename_all_unlink
 */
static int __rename_all_revert(struct inode *old_dir, struct dentry *old_dentry,
			       struct inode *new_dir, struct dentry *new_dentry,
			       fd_set * success_mask, struct rename_info *info)
{
	int bindex;

	int err;
	int eio = 0;

	print_entry_location();

	for (bindex = info->old_bstart; bindex <= info->old_bend; bindex++) {
		if (!FD_ISSET(bindex, success_mask))
			continue;

		err = unionfs_refresh_hidden_dentry(new_dentry, bindex);
		if (err) {
			printk(KERN_WARNING "Revert failed in rename: "
			       "the new refresh failed.\n");
			eio = -EIO;
		}

		err = unionfs_refresh_hidden_dentry(old_dentry, bindex);
		if (err) {
			printk(KERN_WARNING "Revert failed in rename: "
			       "the old refresh failed.\n");
			eio = -EIO;
			continue;
		}

		if (!dtohd_index(new_dentry, bindex)
		    || !dtohd_index(new_dentry, bindex)->d_inode) {
			printk(KERN_WARNING "Revert failed in rename: "
			       "the object disappeared from under us!\n");
			eio = -EIO;
			continue;
		}

		if (dtohd_index(old_dentry, bindex)
		    && dtohd_index(old_dentry, bindex)->d_inode) {
			printk(KERN_WARNING "Revert failed in rename: "
			       "the object was created underneath us!\n");
			eio = -EIO;
			continue;
		}

		err =
		    do_rename(new_dir, new_dentry, old_dir, old_dentry, bindex,
			      NULL);
		/* If we can't fix it, then we cop-out with -EIO. */
		if (err) {
			printk(KERN_WARNING "Revert failed in rename!\n");
			eio = -EIO;
		}

		err = unionfs_refresh_hidden_dentry(new_dentry, bindex);
		if (err)
			eio = -EIO;
		err = unionfs_refresh_hidden_dentry(old_dentry, bindex);
		if (err)
			eio = -EIO;
	}

	print_exit_status(eio);
	return eio;
}
Ejemplo n.º 2
0
static int unionfs_rmdir_all(struct inode *dir, struct dentry *dentry,
			     struct unionfs_dir_state *namelist)
{
	struct dentry *hidden_dentry;
	struct dentry *hidden_dir_dentry;
	int bstart, bend, bindex;
	int err = 0;
	int global_err = 0;

	print_entry_location();
	fist_print_dentry("IN unionfs_rmdir_all: ", dentry);

	bstart = dbstart(dentry);
	bend = dbend(dentry);

	for (bindex = bend; bindex >= bstart; bindex--) {
		hidden_dentry = dtohd_index(dentry, bindex);
		if (!hidden_dentry)
			continue;

		hidden_dir_dentry = lock_parent(hidden_dentry);
		if (S_ISDIR(hidden_dentry->d_inode->i_mode)) {
			delete_whiteouts(dentry, bindex, namelist);
			if (!(err = is_robranch_super(dentry->d_sb, bindex))) {
				err =
				    vfs_rmdir(hidden_dir_dentry->d_inode,
					      hidden_dentry);
			}
		} else {
			err = -EISDIR;
		}

		fist_copy_attr_times(dir, hidden_dir_dentry->d_inode);
		unlock_dir(hidden_dir_dentry);
		if (err) {
			int local_err =
			    unionfs_refresh_hidden_dentry(dentry, bindex);
			if (local_err) {
				err = local_err;
				goto out;
			}

			if (!IS_COPYUP_ERR(err) && err != -ENOTEMPTY
			    && err != -EISDIR)
				goto out;

			global_err = err;
		}
	}

	/* check if encountered error in the above loop */
	if (global_err) {
		/* If we failed in the leftmost branch, then err will be set and we should
		 * move one over to create the whiteout.  Otherwise, we should try in the
		 * leftmost branch.
		 */
		if (err) {
			if (dbstart(dentry) == 0) {
				goto out;
			}
			err = create_whiteout(dentry, dbstart(dentry) - 1);
		} else {
			err = create_whiteout(dentry, dbstart(dentry));
		}
	} else {
		err = create_whiteout(dentry, dbstart(dentry));
	}

      out:
	/* propagate number of hard-links */
	dentry->d_inode->i_nlink = get_nlinks(dentry->d_inode);

	fist_print_dentry("OUT unionfs_rmdir_all: ", dentry);
	print_exit_status(err);
	return err;
}
Ejemplo n.º 3
0
static int unionfs_rename_whiteout(struct inode *old_dir,
				   struct dentry *old_dentry,
				   struct inode *new_dir,
				   struct dentry *new_dentry)
{
	int err = 0;
	int bindex, bwh_old;
	int old_bstart, old_bend;
	int new_bstart, new_bend;
	int do_copyup = -1;
	struct dentry *parent_dentry;
	int local_err = 0;
	int eio = 0;
	int revert = 0;
	struct dentry *wh_old = NULL;

	print_entry_location();

	old_bstart = dbstart(old_dentry);
	bwh_old = old_bstart;
	old_bend = dbend(old_dentry);
	parent_dentry = old_dentry->d_parent;

	new_bstart = dbstart(new_dentry);
	new_bend = dbend(new_dentry);

	/* Rename source to destination. */
	err = do_rename(old_dir, old_dentry, new_dir, new_dentry, old_bstart,
			&wh_old);
	if (err) {
		if (!IS_COPYUP_ERR(err)) {
			goto out;
		}
		do_copyup = old_bstart - 1;
	} else {
		revert = 1;
	}

	/* Unlink all instances of destination that exist to the left of
	 * bstart of source. On error, revert back, goto out.
	 */
	for (bindex = old_bstart - 1; bindex >= new_bstart; bindex--) {
		struct dentry *unlink_dentry;
		struct dentry *unlink_dir_dentry;

		unlink_dentry = dtohd_index(new_dentry, bindex);
		if (!unlink_dentry) {
			continue;
		}

		unlink_dir_dentry = lock_parent(unlink_dentry);
		if (!(err = is_robranch_super(old_dir->i_sb, bindex))) {
			err =
			    vfs_unlink(unlink_dir_dentry->d_inode,
				       unlink_dentry);
		}

		fist_copy_attr_times(new_dentry->d_parent->d_inode,
				     unlink_dir_dentry->d_inode);
		/* propagate number of hard-links */
		new_dentry->d_parent->d_inode->i_nlink =
		    get_nlinks(new_dentry->d_parent->d_inode);

		unlock_dir(unlink_dir_dentry);
		if (!err) {
			if (bindex != new_bstart) {
				DPUT(unlink_dentry);
				set_dtohd_index(new_dentry, bindex, NULL);
			}
		} else if (IS_COPYUP_ERR(err)) {
			do_copyup = bindex - 1;
		} else if (revert) {
			DPUT(wh_old);
			goto revert;
		}
	}

	if (do_copyup != -1) {
		for (bindex = do_copyup; bindex >= 0; bindex--) {
			/* copyup the file into some left directory, so that you can rename it */
			err =
			    copyup_dentry(old_dentry->d_parent->d_inode,
					  old_dentry, old_bstart, bindex, NULL,
					  old_dentry->d_inode->i_size);
			if (!err) {
				DPUT(wh_old);
				bwh_old = bindex;
				err =
				    do_rename(old_dir, old_dentry, new_dir,
					      new_dentry, bindex, &wh_old);
				break;
			}
		}
	}

	/* Create whiteout for source, only if:
	 * (1) There is more than one underlying instance of source.
	 * (2) We did a copy_up
	 */
	if ((old_bstart != old_bend) || (do_copyup != -1)) {
		struct dentry *hidden_parent;
		BUG_ON(!wh_old || IS_ERR(wh_old) || wh_old->d_inode
		       || bwh_old < 0);
		hidden_parent = lock_parent(wh_old);
		local_err = vfs_create(hidden_parent->d_inode, wh_old, S_IRUGO,
				       NULL);
		unlock_dir(hidden_parent);
		if (!local_err)
			set_dbopaque(old_dentry, bwh_old);
		else {
			/* We can't fix anything now, so we cop-out and use -EIO. */
			printk
			    ("<0>We can't create a whiteout for the source in rename!\n");
			err = -EIO;
		}
	}

      out:
	DPUT(wh_old);
	print_exit_status(err);
	return err;

      revert:
	/* Do revert here. */
	local_err = unionfs_refresh_hidden_dentry(new_dentry, old_bstart);
	if (local_err) {
		printk(KERN_WARNING
		       "Revert failed in rename: the new refresh failed.\n");
		eio = -EIO;
	}

	local_err = unionfs_refresh_hidden_dentry(old_dentry, old_bstart);
	if (local_err) {
		printk(KERN_WARNING
		       "Revert failed in rename: the old refresh failed.\n");
		eio = -EIO;
		goto revert_out;
	}

	if (!dtohd_index(new_dentry, bindex)
	    || !dtohd_index(new_dentry, bindex)->d_inode) {
		printk(KERN_WARNING
		       "Revert failed in rename: the object disappeared from under us!\n");
		eio = -EIO;
		goto revert_out;
	}

	if (dtohd_index(old_dentry, bindex)
	    && dtohd_index(old_dentry, bindex)->d_inode) {
		printk(KERN_WARNING
		       "Revert failed in rename: the object was created underneath us!\n");
		eio = -EIO;
		goto revert_out;
	}

	local_err =
	    do_rename(new_dir, new_dentry, old_dir, old_dentry, old_bstart,
		      NULL);

	/* If we can't fix it, then we cop-out with -EIO. */
	if (local_err) {
		printk(KERN_WARNING "Revert failed in rename!\n");
		eio = -EIO;
	}

	local_err = unionfs_refresh_hidden_dentry(new_dentry, bindex);
	if (local_err)
		eio = -EIO;
	local_err = unionfs_refresh_hidden_dentry(old_dentry, bindex);
	if (local_err)
		eio = -EIO;

      revert_out:
	if (eio)
		err = eio;
	print_exit_status(err);
	return err;
}