[v1.2,2/3] btrfs: tree-checker: Add simple keyed refs check
diff mbox series

Message ID 20190809012424.11420-3-wqu@suse.com
State New
Headers show
Series
  • btrfs: tree-checker: Add extent items check
Related show

Commit Message

Qu Wenruo Aug. 9, 2019, 1:24 a.m. UTC
For TREE_BLOCK_REF, SHARED_DATA_REF and SHARED_BLOCK_REF we need to
check:
              | TREE_BLOCK_REF | SHARED_BLOCK_REF | SHARED_BLOCK_REF
--------------+----------------+-----------------+------------------
key->objectid |    Alignment   |     Alignment    |    Alignment
key->offset   |    Any value   |     Alignment    |    Alignment
item_size     |        0       |        0         |   sizeof(le32) (*)

*: sizeof(struct btrfs_shared_data_ref)

So introduce a check to check all these 3 key types together.

Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 fs/btrfs/tree-checker.c | 40 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 39 insertions(+), 1 deletion(-)

Comments

Alex Shashkov Aug. 9, 2019, 4:25 a.m. UTC | #1
I'm trying to understand how deletion works on BTRFS. Let's say
directory containing files and other directories gets deleted. What is
essentially happening during this action, what strucutres get updated,
what artifacts remain after the deletion, is it possible to find them
and recover deleted objects, if yes, then how? Thanks in advance!
David Sterba Aug. 22, 2019, 3:02 p.m. UTC | #2
On Fri, Aug 09, 2019 at 09:24:23AM +0800, Qu Wenruo wrote:
> For TREE_BLOCK_REF, SHARED_DATA_REF and SHARED_BLOCK_REF we need to
> check:
>               | TREE_BLOCK_REF | SHARED_BLOCK_REF | SHARED_BLOCK_REF
> --------------+----------------+-----------------+------------------
> key->objectid |    Alignment   |     Alignment    |    Alignment
> key->offset   |    Any value   |     Alignment    |    Alignment
> item_size     |        0       |        0         |   sizeof(le32) (*)
> 
> *: sizeof(struct btrfs_shared_data_ref)
> 
> So introduce a check to check all these 3 key types together.
> 
> Signed-off-by: Qu Wenruo <wqu@suse.com>

Reviewed-by: David Sterba <dsterba@suse.com>
Nikolay Borisov Aug. 22, 2019, 4:18 p.m. UTC | #3
On 9.08.19 г. 7:25 ч., Alex Shashkov wrote:
> I'm trying to understand how deletion works on BTRFS. Let's say
> directory containing files and other directories gets deleted. What is
> essentially happening during this action, what strucutres get updated,
> what artifacts remain after the deletion, is it possible to find them
> and recover deleted objects, if yes, then how? Thanks in advance!

You want to look into btrfs_unlink_inode to see how unlinking works in
bttrfs.

>

Patch
diff mbox series

diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
index 836f5d8a8ebe..39d10b553c5f 100644
--- a/fs/btrfs/tree-checker.c
+++ b/fs/btrfs/tree-checker.c
@@ -912,7 +912,9 @@  static void extent_err(const struct extent_buffer *eb, int slot,
 
 	btrfs_item_key_to_cpu(eb, &key, slot);
 	bytenr = key.objectid;
-	if (key.type == BTRFS_METADATA_ITEM_KEY)
+	if (key.type == BTRFS_METADATA_ITEM_KEY ||
+	    key.type == BTRFS_TREE_BLOCK_REF_KEY ||
+	    key.type == BTRFS_SHARED_BLOCK_REF_KEY)
 		len = eb->fs_info->nodesize;
 	else
 		len = key.offset;
@@ -1145,6 +1147,37 @@  static int check_extent_item(struct extent_buffer *leaf,
 	return -EUCLEAN;
 }
 
+static int check_simple_keyed_refs(struct extent_buffer *leaf,
+				   struct btrfs_key *key, int slot)
+{
+	u32 expect_item_size = 0;
+
+	if (key->type == BTRFS_SHARED_DATA_REF_KEY)
+		expect_item_size = sizeof(struct btrfs_shared_data_ref);
+
+	if (btrfs_item_size_nr(leaf, slot) != expect_item_size) {
+		generic_err(leaf, slot,
+	"invalid item size, have %u expect %u for key type %u",
+			    btrfs_item_size_nr(leaf, slot),
+			    expect_item_size, key->type);
+		return -EUCLEAN;
+	}
+	if (!IS_ALIGNED(key->objectid, leaf->fs_info->sectorsize)) {
+		generic_err(leaf, slot,
+"invalid key objectid for shared block ref, have %llu expect aligned to %u",
+			    key->objectid, leaf->fs_info->sectorsize);
+		return -EUCLEAN;
+	}
+	if (key->type != BTRFS_TREE_BLOCK_REF_KEY &&
+	    !IS_ALIGNED(key->offset, leaf->fs_info->sectorsize)) {
+		extent_err(leaf, slot,
+		"invalid tree parent bytenr, have %llu expect aligned to %u",
+			   key->offset, leaf->fs_info->sectorsize);
+		return -EUCLEAN;
+	}
+	return 0;
+}
+
 /*
  * Common point to switch the item-specific validation.
  */
@@ -1187,6 +1220,11 @@  static int check_leaf_item(struct extent_buffer *leaf,
 	case BTRFS_METADATA_ITEM_KEY:
 		ret = check_extent_item(leaf, key, slot);
 		break;
+	case BTRFS_TREE_BLOCK_REF_KEY:
+	case BTRFS_SHARED_DATA_REF_KEY:
+	case BTRFS_SHARED_BLOCK_REF_KEY:
+		ret = check_simple_keyed_refs(leaf, key, slot);
+		break;
 	}
 	return ret;
 }