mirror of https://gitee.com/openkylin/linux.git
Merge branch 'send_fixes_4.2' of git://git.kernel.org/pub/scm/linux/kernel/git/fdmanana/linux into for-linus-4.2
This commit is contained in:
commit
1ab818b137
104
fs/btrfs/send.c
104
fs/btrfs/send.c
|
@ -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);
|
ret = send_rename(sctx, valid_path,
|
||||||
if (ret < 0)
|
cur->full_path);
|
||||||
goto out;
|
if (!ret)
|
||||||
if (ret) {
|
ret = fs_path_copy(valid_path,
|
||||||
*pending_move = 1;
|
cur->full_path);
|
||||||
} else {
|
|
||||||
ret = send_rename(sctx, valid_path,
|
|
||||||
cur->full_path);
|
|
||||||
if (!ret)
|
|
||||||
ret = fs_path_copy(valid_path,
|
|
||||||
cur->full_path);
|
|
||||||
}
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in New Issue