diff mbox series

[v2,2/2] btrfs-progs: expand corrupt_file_extent in btrfs-corrupt-block

Message ID d3e7d721bb98a6643ba243c21013ddfc929ccd12.1657919808.git.boris@bur.io (mailing list archive)
State New, archived
Headers show
Series btrfs-corrupt-block: btree data corruption | expand

Commit Message

Boris Burkov July 15, 2022, 9:22 p.m. UTC
To corrupt holes/prealloc/inline extents, we need to mess with
extent data items. This patch makes it possible to modify
disk_bytenr with a specific value (useful for hole corruptions)
and to modify the type field (useful for prealloc corruptions)

Signed-off-by: Boris Burkov <boris@bur.io>
---
 btrfs-corrupt-block.c | 22 +++++++++++++++++-----
 1 file changed, 17 insertions(+), 5 deletions(-)

Comments

Sweet Tea Dorminy July 18, 2022, 4:31 p.m. UTC | #1
On 2022-07-15 17:22, Boris Burkov wrote:
> To corrupt holes/prealloc/inline extents, we need to mess with
> extent data items. This patch makes it possible to modify
> disk_bytenr with a specific value (useful for hole corruptions)
> and to modify the type field (useful for prealloc corruptions)
> 
> Signed-off-by: Boris Burkov <boris@bur.io>
> ---
>  btrfs-corrupt-block.c | 22 +++++++++++++++++-----
>  1 file changed, 17 insertions(+), 5 deletions(-)
> 
> diff --git a/btrfs-corrupt-block.c b/btrfs-corrupt-block.c
> index 5c39459db..27844b184 100644
> --- a/btrfs-corrupt-block.c
> +++ b/btrfs-corrupt-block.c
> @@ -307,6 +307,7 @@ enum btrfs_inode_field {
> 
>  enum btrfs_file_extent_field {
>  	BTRFS_FILE_EXTENT_DISK_BYTENR,
> +	BTRFS_FILE_EXTENT_TYPE,
>  	BTRFS_FILE_EXTENT_BAD,
>  };
> 
> @@ -379,6 +380,8 @@ static enum btrfs_file_extent_field
> convert_file_extent_field(char *field)
>  {
>  	if (!strncmp(field, "disk_bytenr", FIELD_BUF_LEN))
>  		return BTRFS_FILE_EXTENT_DISK_BYTENR;
> +	if (!strncmp(field, "type", FIELD_BUF_LEN))
> +		return BTRFS_FILE_EXTENT_TYPE;
>  	return BTRFS_FILE_EXTENT_BAD;
>  }
> 
> @@ -752,14 +755,14 @@ out:
> 
>  static int corrupt_file_extent(struct btrfs_trans_handle *trans,
>  			       struct btrfs_root *root, u64 inode, u64 extent,
> -			       char *field)
> +			       char *field, u64 bogus)
>  {
>  	struct btrfs_file_extent_item *fi;
>  	struct btrfs_path *path;
>  	struct btrfs_key key;
>  	enum btrfs_file_extent_field corrupt_field;
> -	u64 bogus;
>  	u64 orig;
> +	u8 bogus_type = bogus;
>  	int ret = 0;
> 
>  	corrupt_field = convert_file_extent_field(field);
> @@ -791,9 +794,18 @@ static int corrupt_file_extent(struct
> btrfs_trans_handle *trans,
>  	switch (corrupt_field) {
>  	case BTRFS_FILE_EXTENT_DISK_BYTENR:
>  		orig = btrfs_file_extent_disk_bytenr(path->nodes[0], fi);
> -		bogus = generate_u64(orig);
> +		if (bogus == (u64)-1)
> +			bogus = generate_u64(orig);
Personally I like ternaries a little more but whatever.
>  		btrfs_set_file_extent_disk_bytenr(path->nodes[0], fi, bogus);
>  		break;
> +	case BTRFS_FILE_EXTENT_TYPE:
> +		if (bogus == (u64)-1) {
> +			fprintf(stderr, "Specify a new extent type value (-v)\n");
> +			ret = -EINVAL;
> +			goto out;
> +		}
Again calling out (u64)-1 as a defined name would be nice.

Reviewed-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
Nikolay Borisov July 22, 2022, 10:14 a.m. UTC | #2
On 16.07.22 г. 0:22 ч., Boris Burkov wrote:
> To corrupt holes/prealloc/inline extents, we need to mess with
> extent data items. This patch makes it possible to modify
> disk_bytenr with a specific value (useful for hole corruptions)
> and to modify the type field (useful for prealloc corruptions)
> 
> Signed-off-by: Boris Burkov <boris@bur.io>
> ---
>   btrfs-corrupt-block.c | 22 +++++++++++++++++-----
>   1 file changed, 17 insertions(+), 5 deletions(-)
> 
> diff --git a/btrfs-corrupt-block.c b/btrfs-corrupt-block.c
> index 5c39459db..27844b184 100644
> --- a/btrfs-corrupt-block.c
> +++ b/btrfs-corrupt-block.c
> @@ -307,6 +307,7 @@ enum btrfs_inode_field {
>   
>   enum btrfs_file_extent_field {
>   	BTRFS_FILE_EXTENT_DISK_BYTENR,
> +	BTRFS_FILE_EXTENT_TYPE,
>   	BTRFS_FILE_EXTENT_BAD,
>   };
>   
> @@ -379,6 +380,8 @@ static enum btrfs_file_extent_field convert_file_extent_field(char *field)
>   {
>   	if (!strncmp(field, "disk_bytenr", FIELD_BUF_LEN))
>   		return BTRFS_FILE_EXTENT_DISK_BYTENR;
> +	if (!strncmp(field, "type", FIELD_BUF_LEN))
> +		return BTRFS_FILE_EXTENT_TYPE;
>   	return BTRFS_FILE_EXTENT_BAD;
>   }
>   
> @@ -752,14 +755,14 @@ out:
>   
>   static int corrupt_file_extent(struct btrfs_trans_handle *trans,
>   			       struct btrfs_root *root, u64 inode, u64 extent,
> -			       char *field)
> +			       char *field, u64 bogus)
>   {
>   	struct btrfs_file_extent_item *fi;
>   	struct btrfs_path *path;
>   	struct btrfs_key key;
>   	enum btrfs_file_extent_field corrupt_field;
> -	u64 bogus;
>   	u64 orig;
> +	u8 bogus_type = bogus;

nit: Why do the truncation here, when you can simply pass bogus to 
btrfs_set_file_extent_type and the truncation would be done when the 
value is passed? Or simply cast it when passing bogus to 
btrfs_set_file_extent_type, it makes the code somewhat simpler since we 
now don't have this bogus_type which is really field-specific.
diff mbox series

Patch

diff --git a/btrfs-corrupt-block.c b/btrfs-corrupt-block.c
index 5c39459db..27844b184 100644
--- a/btrfs-corrupt-block.c
+++ b/btrfs-corrupt-block.c
@@ -307,6 +307,7 @@  enum btrfs_inode_field {
 
 enum btrfs_file_extent_field {
 	BTRFS_FILE_EXTENT_DISK_BYTENR,
+	BTRFS_FILE_EXTENT_TYPE,
 	BTRFS_FILE_EXTENT_BAD,
 };
 
@@ -379,6 +380,8 @@  static enum btrfs_file_extent_field convert_file_extent_field(char *field)
 {
 	if (!strncmp(field, "disk_bytenr", FIELD_BUF_LEN))
 		return BTRFS_FILE_EXTENT_DISK_BYTENR;
+	if (!strncmp(field, "type", FIELD_BUF_LEN))
+		return BTRFS_FILE_EXTENT_TYPE;
 	return BTRFS_FILE_EXTENT_BAD;
 }
 
@@ -752,14 +755,14 @@  out:
 
 static int corrupt_file_extent(struct btrfs_trans_handle *trans,
 			       struct btrfs_root *root, u64 inode, u64 extent,
-			       char *field)
+			       char *field, u64 bogus)
 {
 	struct btrfs_file_extent_item *fi;
 	struct btrfs_path *path;
 	struct btrfs_key key;
 	enum btrfs_file_extent_field corrupt_field;
-	u64 bogus;
 	u64 orig;
+	u8 bogus_type = bogus;
 	int ret = 0;
 
 	corrupt_field = convert_file_extent_field(field);
@@ -791,9 +794,18 @@  static int corrupt_file_extent(struct btrfs_trans_handle *trans,
 	switch (corrupt_field) {
 	case BTRFS_FILE_EXTENT_DISK_BYTENR:
 		orig = btrfs_file_extent_disk_bytenr(path->nodes[0], fi);
-		bogus = generate_u64(orig);
+		if (bogus == (u64)-1)
+			bogus = generate_u64(orig);
 		btrfs_set_file_extent_disk_bytenr(path->nodes[0], fi, bogus);
 		break;
+	case BTRFS_FILE_EXTENT_TYPE:
+		if (bogus == (u64)-1) {
+			fprintf(stderr, "Specify a new extent type value (-v)\n");
+			ret = -EINVAL;
+			goto out;
+		}
+		btrfs_set_file_extent_type(path->nodes[0], fi, bogus_type);
+		break;
 	default:
 		ret = -EINVAL;
 		break;
@@ -1480,9 +1492,9 @@  int main(int argc, char **argv)
 			printf("corrupting inode\n");
 			ret = corrupt_inode(trans, root, inode, field);
 		} else {
-			printf("corrupting file extent\n");
 			ret = corrupt_file_extent(trans, root, inode,
-						  file_extent, field);
+						  file_extent, field,
+						  bogus_value);
 		}
 		btrfs_commit_transaction(trans, root);
 		goto out_close;