Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1ab818b1 authored by Chris Mason's avatar Chris Mason
Browse files

Merge branch 'send_fixes_4.2' of...

Merge branch 'send_fixes_4.2' of git://git.kernel.org/pub/scm/linux/kernel/git/fdmanana/linux into for-linus-4.2
parents 6ca07097 8b191a68
Loading
Loading
Loading
Loading
+83 −21
Original line number Original line Diff line number Diff line
@@ -243,6 +243,7 @@ struct waiting_dir_move {
	 * after this directory is moved, we can try to rmdir the ino rmdir_ino.
	 * after this directory is moved, we can try to rmdir the ino rmdir_ino.
	 */
	 */
	u64 rmdir_ino;
	u64 rmdir_ino;
	bool orphanized;
};
};


struct orphan_dir_info {
struct orphan_dir_info {
@@ -1916,8 +1917,13 @@ static int did_overwrite_ref(struct send_ctx *sctx,
		goto out;
		goto out;
	}
	}


	/* we know that it is or will be overwritten. check this now */
	/*
	if (ow_inode < sctx->send_progress)
	 * We know that it is or will be overwritten. Check this now.
	 * The current inode being processed might have been the one that caused
	 * inode 'ino' to be orphanized, therefore ow_inode can actually be the
	 * same as sctx->send_progress.
	 */
	if (ow_inode <= sctx->send_progress)
		ret = 1;
		ret = 1;
	else
	else
		ret = 0;
		ret = 0;
@@ -2239,6 +2245,8 @@ static int get_cur_path(struct send_ctx *sctx, u64 ino, u64 gen,
	fs_path_reset(dest);
	fs_path_reset(dest);


	while (!stop && ino != BTRFS_FIRST_FREE_OBJECTID) {
	while (!stop && ino != BTRFS_FIRST_FREE_OBJECTID) {
		struct waiting_dir_move *wdm;

		fs_path_reset(name);
		fs_path_reset(name);


		if (is_waiting_for_rm(sctx, ino)) {
		if (is_waiting_for_rm(sctx, ino)) {
@@ -2249,7 +2257,11 @@ static int get_cur_path(struct send_ctx *sctx, u64 ino, u64 gen,
			break;
			break;
		}
		}


		if (is_waiting_for_move(sctx, ino)) {
		wdm = get_waiting_dir_move(sctx, ino);
		if (wdm && wdm->orphanized) {
			ret = gen_unique_name(sctx, ino, gen, name);
			stop = 1;
		} else if (wdm) {
			ret = get_first_ref(sctx->parent_root, ino,
			ret = get_first_ref(sctx->parent_root, ino,
					    &parent_inode, &parent_gen, name);
					    &parent_inode, &parent_gen, name);
		} else {
		} else {
@@ -2939,7 +2951,7 @@ static int is_waiting_for_move(struct send_ctx *sctx, u64 ino)
	return entry != NULL;
	return entry != NULL;
}
}


static int add_waiting_dir_move(struct send_ctx *sctx, u64 ino)
static int add_waiting_dir_move(struct send_ctx *sctx, u64 ino, bool orphanized)
{
{
	struct rb_node **p = &sctx->waiting_dir_moves.rb_node;
	struct rb_node **p = &sctx->waiting_dir_moves.rb_node;
	struct rb_node *parent = NULL;
	struct rb_node *parent = NULL;
@@ -2950,6 +2962,7 @@ static int add_waiting_dir_move(struct send_ctx *sctx, u64 ino)
		return -ENOMEM;
		return -ENOMEM;
	dm->ino = ino;
	dm->ino = ino;
	dm->rmdir_ino = 0;
	dm->rmdir_ino = 0;
	dm->orphanized = orphanized;


	while (*p) {
	while (*p) {
		parent = *p;
		parent = *p;
@@ -3046,7 +3059,7 @@ static int add_pending_dir_move(struct send_ctx *sctx,
			goto out;
			goto out;
	}
	}


	ret = add_waiting_dir_move(sctx, pm->ino);
	ret = add_waiting_dir_move(sctx, pm->ino, is_orphan);
	if (ret)
	if (ret)
		goto out;
		goto out;


@@ -3369,8 +3382,40 @@ static int wait_for_dest_dir_move(struct send_ctx *sctx,
	return ret;
	return ret;
}
}


/*
 * Check if ino ino1 is an ancestor of inode ino2 in the given root.
 * Return 1 if true, 0 if false and < 0 on error.
 */
static int is_ancestor(struct btrfs_root *root,
		       const u64 ino1,
		       const u64 ino1_gen,
		       const u64 ino2,
		       struct fs_path *fs_path)
{
	u64 ino = ino2;

	while (ino > BTRFS_FIRST_FREE_OBJECTID) {
		int ret;
		u64 parent;
		u64 parent_gen;

		fs_path_reset(fs_path);
		ret = get_first_ref(root, ino, &parent, &parent_gen, fs_path);
		if (ret < 0) {
			if (ret == -ENOENT && ino == ino2)
				ret = 0;
			return ret;
		}
		if (parent == ino1)
			return parent_gen == ino1_gen ? 1 : 0;
		ino = parent;
	}
	return 0;
}

static int wait_for_parent_move(struct send_ctx *sctx,
static int wait_for_parent_move(struct send_ctx *sctx,
				struct recorded_ref *parent_ref)
				struct recorded_ref *parent_ref,
				const bool is_orphan)
{
{
	int ret = 0;
	int ret = 0;
	u64 ino = parent_ref->dir;
	u64 ino = parent_ref->dir;
@@ -3390,11 +3435,24 @@ static int wait_for_parent_move(struct send_ctx *sctx,
	 * Our current directory inode may not yet be renamed/moved because some
	 * Our current directory inode may not yet be renamed/moved because some
	 * ancestor (immediate or not) has to be renamed/moved first. So find if
	 * ancestor (immediate or not) has to be renamed/moved first. So find if
	 * such ancestor exists and make sure our own rename/move happens after
	 * such ancestor exists and make sure our own rename/move happens after
	 * that ancestor is processed.
	 * that ancestor is processed to avoid path build infinite loops (done
	 * at get_cur_path()).
	 */
	 */
	while (ino > BTRFS_FIRST_FREE_OBJECTID) {
	while (ino > BTRFS_FIRST_FREE_OBJECTID) {
		if (is_waiting_for_move(sctx, ino)) {
		if (is_waiting_for_move(sctx, ino)) {
			ret = 1;
			/*
			 * If the current inode is an ancestor of ino in the
			 * parent root, we need to delay the rename of the
			 * current inode, otherwise don't delayed the rename
			 * because we can end up with a circular dependency
			 * of renames, resulting in some directories never
			 * getting the respective rename operations issued in
			 * the send stream or getting into infinite path build
			 * loops.
			 */
			ret = is_ancestor(sctx->parent_root,
					  sctx->cur_ino, sctx->cur_inode_gen,
					  ino, path_before);
			break;
			break;
		}
		}


@@ -3436,7 +3494,7 @@ static int wait_for_parent_move(struct send_ctx *sctx,
					   ino,
					   ino,
					   &sctx->new_refs,
					   &sctx->new_refs,
					   &sctx->deleted_refs,
					   &sctx->deleted_refs,
					   false);
					   is_orphan);
		if (!ret)
		if (!ret)
			ret = 1;
			ret = 1;
	}
	}
@@ -3605,6 +3663,17 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
			}
			}
		}
		}


		if (S_ISDIR(sctx->cur_inode_mode) && sctx->parent_root &&
		    can_rename) {
			ret = wait_for_parent_move(sctx, cur, is_orphan);
			if (ret < 0)
				goto out;
			if (ret == 1) {
				can_rename = false;
				*pending_move = 1;
			}
		}

		/*
		/*
		 * link/move the ref to the new place. If we have an orphan
		 * link/move the ref to the new place. If we have an orphan
		 * inode, move it and update valid_path. If not, link or move
		 * inode, move it and update valid_path. If not, link or move
@@ -3625,18 +3694,11 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
				 * dirs, we always have one new and one deleted
				 * dirs, we always have one new and one deleted
				 * ref. The deleted ref is ignored later.
				 * ref. The deleted ref is ignored later.
				 */
				 */
				ret = wait_for_parent_move(sctx, cur);
				if (ret < 0)
					goto out;
				if (ret) {
					*pending_move = 1;
				} else {
				ret = send_rename(sctx, valid_path,
				ret = send_rename(sctx, valid_path,
						  cur->full_path);
						  cur->full_path);
				if (!ret)
				if (!ret)
					ret = fs_path_copy(valid_path,
					ret = fs_path_copy(valid_path,
							   cur->full_path);
							   cur->full_path);
				}
				if (ret < 0)
				if (ret < 0)
					goto out;
					goto out;
			} else {
			} else {