summaryrefslogtreecommitdiffstats
path: root/fs/btrfs/send.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/send.c')
-rw-r--r--fs/btrfs/send.c124
1 files changed, 106 insertions, 18 deletions
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index c10e4c70f02d..20d3300bd268 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -3521,7 +3521,40 @@ out:
3521} 3521}
3522 3522
3523/* 3523/*
3524 * Check if ino ino1 is an ancestor of inode ino2 in the given root. 3524 * Check if inode ino2, or any of its ancestors, is inode ino1.
3525 * Return 1 if true, 0 if false and < 0 on error.
3526 */
3527static int check_ino_in_path(struct btrfs_root *root,
3528 const u64 ino1,
3529 const u64 ino1_gen,
3530 const u64 ino2,
3531 const u64 ino2_gen,
3532 struct fs_path *fs_path)
3533{
3534 u64 ino = ino2;
3535
3536 if (ino1 == ino2)
3537 return ino1_gen == ino2_gen;
3538
3539 while (ino > BTRFS_FIRST_FREE_OBJECTID) {
3540 u64 parent;
3541 u64 parent_gen;
3542 int ret;
3543
3544 fs_path_reset(fs_path);
3545 ret = get_first_ref(root, ino, &parent, &parent_gen, fs_path);
3546 if (ret < 0)
3547 return ret;
3548 if (parent == ino1)
3549 return parent_gen == ino1_gen;
3550 ino = parent;
3551 }
3552 return 0;
3553}
3554
3555/*
3556 * Check if ino ino1 is an ancestor of inode ino2 in the given root for any
3557 * possible path (in case ino2 is not a directory and has multiple hard links).
3525 * Return 1 if true, 0 if false and < 0 on error. 3558 * Return 1 if true, 0 if false and < 0 on error.
3526 */ 3559 */
3527static int is_ancestor(struct btrfs_root *root, 3560static int is_ancestor(struct btrfs_root *root,
@@ -3530,36 +3563,91 @@ static int is_ancestor(struct btrfs_root *root,
3530 const u64 ino2, 3563 const u64 ino2,
3531 struct fs_path *fs_path) 3564 struct fs_path *fs_path)
3532{ 3565{
3533 u64 ino = ino2; 3566 bool free_fs_path = false;
3534 bool free_path = false;
3535 int ret = 0; 3567 int ret = 0;
3568 struct btrfs_path *path = NULL;
3569 struct btrfs_key key;
3536 3570
3537 if (!fs_path) { 3571 if (!fs_path) {
3538 fs_path = fs_path_alloc(); 3572 fs_path = fs_path_alloc();
3539 if (!fs_path) 3573 if (!fs_path)
3540 return -ENOMEM; 3574 return -ENOMEM;
3541 free_path = true; 3575 free_fs_path = true;
3542 } 3576 }
3543 3577
3544 while (ino > BTRFS_FIRST_FREE_OBJECTID) { 3578 path = alloc_path_for_send();
3545 u64 parent; 3579 if (!path) {
3546 u64 parent_gen; 3580 ret = -ENOMEM;
3581 goto out;
3582 }
3547 3583
3548 fs_path_reset(fs_path); 3584 key.objectid = ino2;
3549 ret = get_first_ref(root, ino, &parent, &parent_gen, fs_path); 3585 key.type = BTRFS_INODE_REF_KEY;
3550 if (ret < 0) { 3586 key.offset = 0;
3551 if (ret == -ENOENT && ino == ino2) 3587
3552 ret = 0; 3588 ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
3553 goto out; 3589 if (ret < 0)
3590 goto out;
3591
3592 while (true) {
3593 struct extent_buffer *leaf = path->nodes[0];
3594 int slot = path->slots[0];
3595 u32 cur_offset = 0;
3596 u32 item_size;
3597
3598 if (slot >= btrfs_header_nritems(leaf)) {
3599 ret = btrfs_next_leaf(root, path);
3600 if (ret < 0)
3601 goto out;
3602 if (ret > 0)
3603 break;
3604 continue;
3554 } 3605 }
3555 if (parent == ino1) { 3606
3556 ret = parent_gen == ino1_gen ? 1 : 0; 3607 btrfs_item_key_to_cpu(leaf, &key, slot);
3557 goto out; 3608 if (key.objectid != ino2)
3609 break;
3610 if (key.type != BTRFS_INODE_REF_KEY &&
3611 key.type != BTRFS_INODE_EXTREF_KEY)
3612 break;
3613
3614 item_size = btrfs_item_size_nr(leaf, slot);
3615 while (cur_offset < item_size) {
3616 u64 parent;
3617 u64 parent_gen;
3618
3619 if (key.type == BTRFS_INODE_EXTREF_KEY) {
3620 unsigned long ptr;
3621 struct btrfs_inode_extref *extref;
3622
3623 ptr = btrfs_item_ptr_offset(leaf, slot);
3624 extref = (struct btrfs_inode_extref *)
3625 (ptr + cur_offset);
3626 parent = btrfs_inode_extref_parent(leaf,
3627 extref);
3628 cur_offset += sizeof(*extref);
3629 cur_offset += btrfs_inode_extref_name_len(leaf,
3630 extref);
3631 } else {
3632 parent = key.offset;
3633 cur_offset = item_size;
3634 }
3635
3636 ret = get_inode_info(root, parent, NULL, &parent_gen,
3637 NULL, NULL, NULL, NULL);
3638 if (ret < 0)
3639 goto out;
3640 ret = check_ino_in_path(root, ino1, ino1_gen,
3641 parent, parent_gen, fs_path);
3642 if (ret)
3643 goto out;
3558 } 3644 }
3559 ino = parent; 3645 path->slots[0]++;
3560 } 3646 }
3647 ret = 0;
3561 out: 3648 out:
3562 if (free_path) 3649 btrfs_free_path(path);
3650 if (free_fs_path)
3563 fs_path_free(fs_path); 3651 fs_path_free(fs_path);
3564 return ret; 3652 return ret;
3565} 3653}