All of lore.kernel.org
 help / color / mirror / Atom feed
From: Roman Anasal <roman.anasal@bdsu.de>
To: linux-btrfs@vger.kernel.org
Cc: Roman Anasal <roman.anasal@bdsu.de>
Subject: [PATCH v2 3/4] btrfs: send: fix invalid commands for inodes with changed rdev but same gen
Date: Mon, 25 Jan 2021 20:42:09 +0100	[thread overview]
Message-ID: <20210125194210.24071-4-roman.anasal@bdsu.de> (raw)
In-Reply-To: <20210125194210.24071-1-roman.anasal@bdsu.de>

This is analogous to the preceding patch ("btrfs: send: fix invalid
commands for inodes with changed type but same gen") but for changed
rdev:

When doing an incremental send, if a new inode has the same number as an
inode in the parent subvolume, was created with the same generation but
has differing rdev it will not be detected as changed and thus not
recreated. This will lead to incorrect results on the receiver where the
inode will keep the rdev of the inode in the parent subvolume or even
fail when also the ref is unchanged.

This case does not happen when doing incremental sends with snapshots
that are kept read-only by the user all the time, but it may happen if
- a snapshot was modified in the same transaction as its parent after it
  was created
- the subvol used as parent was created independently from the sent subvol

Example reproducers:

  # case 1: same ino at same path
  btrfs subvolume create subvol1
  btrfs subvolume create subvol2
  mknod subvol1/a c 1 3
  mknod subvol2/a c 1 5
  btrfs property set subvol1 ro true
  btrfs property set subvol2 ro true
  btrfs send -p subvol1 subvol2 | btrfs receive --dump

The produced tree state here is:
  |-- subvol1
  |   `-- a         (ino 257, c 1,3)
  |
  `-- subvol2
      `-- a         (ino 257, c 1,5)

Where subvol1/a and subvol2/a are character devices with differing minor
numbers but same inode number and same generation.

Example output of the receive command:
  At subvol subvol2
  snapshot        ./subvol2                       uuid=7513941c-4ef7-f847-b05e-4fdfe003af7b transid=9 parent_uuid=b66f015b-c226-2548-9e39-048c7fdbec99 parent_transid=9
  utimes          ./subvol2/                      atime=2021-01-25T17:14:36+0000 mtime=2021-01-25T17:14:36+0000 ctime=2021-01-25T17:14:36+0000
  link            ./subvol2/a                     dest=a
  unlink          ./subvol2/a
  utimes          ./subvol2/                      atime=2021-01-25T17:14:36+0000 mtime=2021-01-25T17:14:36+0000 ctime=2021-01-25T17:14:36+0000
  utimes          ./subvol2/a                     atime=2021-01-25T17:14:36+0000 mtime=2021-01-25T17:14:36+0000 ctime=2021-01-25T17:14:36+0000

=> the `link` command causes the receiver to fail with:
   ERROR: link a -> a failed: File exists

Second example:
  # case 2: same ino at different path
  btrfs subvolume create subvol1
  btrfs subvolume create subvol2
  mknod subvol1/a c 1 3
  mknod subvol2/b c 1 5
  btrfs property set subvol1 ro true
  btrfs property set subvol2 ro true
  btrfs send -p subvol1 subvol2 | btrfs receive --dump

The produced tree state here is:
  |-- subvol1
  |   `-- a         (ino 257, c 1,3)
  |
  `-- subvol2
      `-- b         (ino 257, c 1,5)

Where subvol1/a and subvol2/b are character devices with differing minor
numbers but same inode number and same generation.

Example output of the receive command:
  At subvol subvol2
  snapshot        ./subvol2                       uuid=1c175819-8b97-0046-a20e-5f95e37cbd40 transid=13 parent_uuid=bad4a908-21b4-6f40-9a08-6b0768346725 parent_transid=13
  utimes          ./subvol2/                      atime=2021-01-25T17:18:46+0000 mtime=2021-01-25T17:18:46+0000 ctime=2021-01-25T17:18:46+0000
  link            ./subvol2/b                     dest=a
  unlink          ./subvol2/a
  utimes          ./subvol2/                      atime=2021-01-25T17:18:46+0000 mtime=2021-01-25T17:18:46+0000 ctime=2021-01-25T17:18:46+0000
  utimes          ./subvol2/b                     atime=2021-01-25T17:18:46+0000 mtime=2021-01-25T17:18:46+0000 ctime=2021-01-25T17:18:46+0000

=> subvol1/a is renamed to subvol2/b instead of recreated to updated
   rdev which results in received subvol2/b having the wrong minor
   number:

  257 crw-r--r--. 1 root root 1, 3 Jan 25 17:18 subvol2/b

Signed-off-by: Roman Anasal <roman.anasal@bdsu.de>
---
v2:
  - add this patch to also handle changed rdev
---
 fs/btrfs/send.c | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index c8b1f441f..ef544525f 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -6263,6 +6263,7 @@ static int changed_inode(struct send_ctx *sctx,
 	struct btrfs_inode_item *right_ii = NULL;
 	u64 left_gen = 0;
 	u64 right_gen = 0;
+	u64 left_rdev, right_rdev;
 	u64 left_type, right_type;
 
 	sctx->cur_ino = key->objectid;
@@ -6285,6 +6286,8 @@ static int changed_inode(struct send_ctx *sctx,
 				struct btrfs_inode_item);
 		left_gen = btrfs_inode_generation(sctx->left_path->nodes[0],
 				left_ii);
+		left_rdev = btrfs_inode_rdev(sctx->left_path->nodes[0],
+				left_ii);
 	} else {
 		right_ii = btrfs_item_ptr(sctx->right_path->nodes[0],
 				sctx->right_path->slots[0],
@@ -6300,6 +6303,9 @@ static int changed_inode(struct send_ctx *sctx,
 		right_gen = btrfs_inode_generation(sctx->right_path->nodes[0],
 				right_ii);
 
+		right_rdev = btrfs_inode_rdev(sctx->right_path->nodes[0],
+				right_ii);
+
 		left_type = S_IFMT & btrfs_inode_mode(
 				sctx->left_path->nodes[0], left_ii);
 		right_type = S_IFMT & btrfs_inode_mode(
@@ -6310,7 +6316,8 @@ static int changed_inode(struct send_ctx *sctx,
 		 * the inode as deleted+reused because it would generate a
 		 * stream that tries to delete/mkdir the root dir.
 		 */
-		if ((left_gen != right_gen || left_type != right_type) &&
+		if ((left_gen != right_gen || left_type != right_type ||
+		    left_rdev != right_rdev) &&
 		    sctx->cur_ino != BTRFS_FIRST_FREE_OBJECTID)
 			sctx->cur_inode_recreated = 1;
 	}
@@ -6350,8 +6357,7 @@ static int changed_inode(struct send_ctx *sctx,
 				sctx->left_path->nodes[0], left_ii);
 		sctx->cur_inode_mode = btrfs_inode_mode(
 				sctx->left_path->nodes[0], left_ii);
-		sctx->cur_inode_rdev = btrfs_inode_rdev(
-				sctx->left_path->nodes[0], left_ii);
+		sctx->cur_inode_rdev = left_rdev;
 		if (sctx->cur_ino != BTRFS_FIRST_FREE_OBJECTID)
 			ret = send_create_inode_if_needed(sctx);
 	} else if (result == BTRFS_COMPARE_TREE_DELETED) {
@@ -6396,8 +6402,7 @@ static int changed_inode(struct send_ctx *sctx,
 					sctx->left_path->nodes[0], left_ii);
 			sctx->cur_inode_mode = btrfs_inode_mode(
 					sctx->left_path->nodes[0], left_ii);
-			sctx->cur_inode_rdev = btrfs_inode_rdev(
-					sctx->left_path->nodes[0], left_ii);
+			sctx->cur_inode_rdev = left_rdev;
 			ret = send_create_inode_if_needed(sctx);
 			if (ret < 0)
 				goto out;
-- 
2.26.2


  parent reply	other threads:[~2021-01-25 19:46 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-01-25 19:42 [PATCH v2 0/4] btrfs: send: correctly recreate changed inodes Roman Anasal
2021-01-25 19:42 ` [PATCH v2 1/4] btrfs: send: rename send_ctx.cur_inode_new_gen to cur_inode_recreated Roman Anasal
2021-01-25 19:42 ` [PATCH v2 2/4] btrfs: send: fix invalid commands for inodes with changed type but same gen Roman Anasal
2021-01-25 19:42 ` Roman Anasal [this message]
2021-01-25 20:51   ` [PATCH v2 3/4] btrfs: send: fix invalid commands for inodes with changed rdev " Filipe Manana
2021-01-26 19:19     ` Roman Anasal | BDSU
2021-01-27 10:53       ` Filipe Manana
2021-01-31 15:52     ` Roman Anasal | BDSU
2021-02-02 11:56       ` Filipe Manana
2021-02-03 16:20         ` Roman Anasal | BDSU
2021-01-25 19:42 ` [PATCH v2 4/4] btrfs: send: fix invalid commands for inodes in disconnected roots Roman Anasal

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210125194210.24071-4-roman.anasal@bdsu.de \
    --to=roman.anasal@bdsu.de \
    --cc=linux-btrfs@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.