diff mbox series

btrfs-progs: introduce inspect-internal map-logical command

Message ID ff62eb10cbf38e53ac26f458644257f82daba47c.1653031397.git.wqu@suse.com (mailing list archive)
State New, archived
Headers show
Series btrfs-progs: introduce inspect-internal map-logical command | expand

Commit Message

Qu Wenruo May 20, 2022, 7:23 a.m. UTC
This is a simpler version compared to btrfs-map-logical.

The differences are:

- No extent check
  Thus any bytenr which has chunk mapping can be mapped.

- No length specification
  Now it's fixed to sectorsize.
  Previously we use nodesize in btrfs-map-logical, which would only
  make the output more complex due as it may cross stripe boundary
  for data extent.

  Considering the main users of this functionality is data corruption,
  thus we really just want to resolve a single sector.

- No data write support nor mirror specification
  We always output all mirrors and call it a day.

- Ignore RAID56 parity manually

We still keep the old btrfs-map-logical, just in case there are some
usage of certain parameters.

Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 Documentation/btrfs-inspect-internal.rst |  7 +++
 cmds/inspect.c                           | 78 ++++++++++++++++++++++++
 2 files changed, 85 insertions(+)

Comments

Johannes Thumshirn May 20, 2022, 8:44 a.m. UTC | #1
On 20/05/2022 09:24, Qu Wenruo wrote:
[..]
>  
> +
Nit: stray newline

>  static const char * const cmd_inspect_logical_resolve_usage[] = {
>  	"btrfs inspect-internal logical-resolve [-Pvo] [-s bufsize] <logical> <path>",
>  	"Get file system paths for the given logical address",
> @@ -348,6 +350,81 @@ out:
>  }

Otherwise looks good,
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
David Sterba May 20, 2022, 6:12 p.m. UTC | #2
On Fri, May 20, 2022 at 03:23:26PM +0800, Qu Wenruo wrote:
> This is a simpler version compared to btrfs-map-logical.
> 
> The differences are:
> 
> - No extent check
>   Thus any bytenr which has chunk mapping can be mapped.
> 
> - No length specification
>   Now it's fixed to sectorsize.
>   Previously we use nodesize in btrfs-map-logical, which would only
>   make the output more complex due as it may cross stripe boundary
>   for data extent.
> 
>   Considering the main users of this functionality is data corruption,
>   thus we really just want to resolve a single sector.
> 
> - No data write support nor mirror specification
>   We always output all mirrors and call it a day.
> 
> - Ignore RAID56 parity manually
> 
> We still keep the old btrfs-map-logical, just in case there are some
> usage of certain parameters.
> 
> Signed-off-by: Qu Wenruo <wqu@suse.com>
> ---
>  Documentation/btrfs-inspect-internal.rst |  7 +++
>  cmds/inspect.c                           | 78 ++++++++++++++++++++++++
>  2 files changed, 85 insertions(+)
> 
> diff --git a/Documentation/btrfs-inspect-internal.rst b/Documentation/btrfs-inspect-internal.rst
> index 710a34fb0cb9..8a9264d3dc5b 100644
> --- a/Documentation/btrfs-inspect-internal.rst
> +++ b/Documentation/btrfs-inspect-internal.rst
> @@ -169,6 +169,13 @@ logical-resolve [-Pvo] [-s <bufsize>] <logical> <path>
>          -v
>                  (deprecated) alias for global *-v* option
>  
> +map-logical <logical> <device>
> +        map the sector at given *logical* address in the linear filesystem space into
> +        physical address.
> +
> +        .. note::
> +                For RAID56, this will only map the data stripe.
> +
>  min-dev-size [options] <path>
>          (needs root privileges)
>  
> diff --git a/cmds/inspect.c b/cmds/inspect.c
> index 1534f2040f4e..271adf8c6fd4 100644
> --- a/cmds/inspect.c
> +++ b/cmds/inspect.c
> @@ -29,6 +29,7 @@
>  #include "kernel-shared/ctree.h"
>  #include "common/send-utils.h"
>  #include "kernel-shared/disk-io.h"
> +#include "kernel-shared/volumes.h"
>  #include "cmds/commands.h"
>  #include "common/help.h"
>  #include "common/open-utils.h"
> @@ -125,6 +126,7 @@ static int cmd_inspect_inode_resolve(const struct cmd_struct *cmd,
>  }
>  static DEFINE_SIMPLE_COMMAND(inspect_inode_resolve, "inode-resolve");
>  
> +
>  static const char * const cmd_inspect_logical_resolve_usage[] = {
>  	"btrfs inspect-internal logical-resolve [-Pvo] [-s bufsize] <logical> <path>",
>  	"Get file system paths for the given logical address",
> @@ -348,6 +350,81 @@ out:
>  }
>  static DEFINE_SIMPLE_COMMAND(inspect_subvolid_resolve, "subvolid-resolve");
>  
> +static const char * const cmd_inspect_map_logical_usage[] = {
> +	"btrfs inspect-internal map-logical <logical> <device>",
> +	"Get the physical offset of a sector.",
> +	NULL
> +};
> +
> +static int print_mapping_info(struct btrfs_fs_info *fs_info, u64 logical)
> +{
> +	struct cache_extent *ce;
> +	struct map_lookup *map;
> +	int num_copies;
> +	int cur_mirror;
> +	int ret;
> +
> +	ce = search_cache_extent(&fs_info->mapping_tree.cache_tree, logical);
> +	if (!ce) {
> +		error("no chunk mapping found for logical %llu", logical);
> +		return -ENOENT;
> +	}
> +	map = container_of(ce, struct map_lookup, ce);
> +	/* For RAID56, we only return the data stripe. */
> +	if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK)
> +		num_copies = 1;
> +	else
> +		num_copies = btrfs_num_copies(fs_info, logical,
> +					      fs_info->sectorsize);
> +
> +	for (cur_mirror = 1; cur_mirror <= num_copies; cur_mirror++) {
> +		struct btrfs_multi_bio *multi = NULL;
> +		u64 len = fs_info->sectorsize;
> +
> +		ret = btrfs_map_block(fs_info, READ, logical, &len, &multi,
> +				      cur_mirror, NULL);
> +		if (ret < 0) {
> +			errno = -ret;
> +			error("failed to map logical %llu: %m", logical);
> +			return ret;
> +		}
> +		/* We're using READ, which should only return one mirror. */
> +		ASSERT(multi && multi->num_stripes == 1);
> +		printf("mirror %d logical %llu phyiscal %llu device %s\n",
> +			cur_mirror, logical, multi->stripes[0].physical,
> +			multi->stripes[0].dev->name);
> +		free(multi);
> +	}
> +	return 0;
> +}
> +
> +static int cmd_inspect_map_logical(const struct cmd_struct *cmd, int argc,
> +				   char **argv)
> +{
> +	struct open_ctree_flags ocf = {0};
> +	struct btrfs_fs_info *fs_info;
> +	u64 logical;
> +	int ret;
> +
> +	clean_args_no_options(cmd, argc, argv);
> +
> +	if (check_argc_exact(argc - optind, 2))
> +		return 1;
> +
> +	ocf.filename = argv[optind + 1];
> +	ocf.flags = OPEN_CTREE_CHUNK_ROOT_ONLY;
> +	logical = arg_strtou64(argv[optind]);
> +
> +	fs_info = open_ctree_fs_info(&ocf);

So this is for images, not for mounted filesystem. The inspect-internal
group has both but for the map-logical we could do both.

I'd expect the primary use to be for the mounted fs.  The question is
what for am I supposed to use map-logical for? See where a file is
located, ok, that I'd like to see on a mounted filesystem. Running that
on the block device while still mounted is unreliable.
Qu Wenruo May 21, 2022, 1:13 a.m. UTC | #3
On 2022/5/21 02:12, David Sterba wrote:
> On Fri, May 20, 2022 at 03:23:26PM +0800, Qu Wenruo wrote:
>> This is a simpler version compared to btrfs-map-logical.
>>
>> The differences are:
>>
>> - No extent check
>>    Thus any bytenr which has chunk mapping can be mapped.
>>
>> - No length specification
>>    Now it's fixed to sectorsize.
>>    Previously we use nodesize in btrfs-map-logical, which would only
>>    make the output more complex due as it may cross stripe boundary
>>    for data extent.
>>
>>    Considering the main users of this functionality is data corruption,
>>    thus we really just want to resolve a single sector.
>>
>> - No data write support nor mirror specification
>>    We always output all mirrors and call it a day.
>>
>> - Ignore RAID56 parity manually
>>
>> We still keep the old btrfs-map-logical, just in case there are some
>> usage of certain parameters.
>>
>> Signed-off-by: Qu Wenruo <wqu@suse.com>
>> ---
>>   Documentation/btrfs-inspect-internal.rst |  7 +++
>>   cmds/inspect.c                           | 78 ++++++++++++++++++++++++
>>   2 files changed, 85 insertions(+)
>>
>> diff --git a/Documentation/btrfs-inspect-internal.rst b/Documentation/btrfs-inspect-internal.rst
>> index 710a34fb0cb9..8a9264d3dc5b 100644
>> --- a/Documentation/btrfs-inspect-internal.rst
>> +++ b/Documentation/btrfs-inspect-internal.rst
>> @@ -169,6 +169,13 @@ logical-resolve [-Pvo] [-s <bufsize>] <logical> <path>
>>           -v
>>                   (deprecated) alias for global *-v* option
>>
>> +map-logical <logical> <device>
>> +        map the sector at given *logical* address in the linear filesystem space into
>> +        physical address.
>> +
>> +        .. note::
>> +                For RAID56, this will only map the data stripe.
>> +
>>   min-dev-size [options] <path>
>>           (needs root privileges)
>>
>> diff --git a/cmds/inspect.c b/cmds/inspect.c
>> index 1534f2040f4e..271adf8c6fd4 100644
>> --- a/cmds/inspect.c
>> +++ b/cmds/inspect.c
>> @@ -29,6 +29,7 @@
>>   #include "kernel-shared/ctree.h"
>>   #include "common/send-utils.h"
>>   #include "kernel-shared/disk-io.h"
>> +#include "kernel-shared/volumes.h"
>>   #include "cmds/commands.h"
>>   #include "common/help.h"
>>   #include "common/open-utils.h"
>> @@ -125,6 +126,7 @@ static int cmd_inspect_inode_resolve(const struct cmd_struct *cmd,
>>   }
>>   static DEFINE_SIMPLE_COMMAND(inspect_inode_resolve, "inode-resolve");
>>
>> +
>>   static const char * const cmd_inspect_logical_resolve_usage[] = {
>>   	"btrfs inspect-internal logical-resolve [-Pvo] [-s bufsize] <logical> <path>",
>>   	"Get file system paths for the given logical address",
>> @@ -348,6 +350,81 @@ out:
>>   }
>>   static DEFINE_SIMPLE_COMMAND(inspect_subvolid_resolve, "subvolid-resolve");
>>
>> +static const char * const cmd_inspect_map_logical_usage[] = {
>> +	"btrfs inspect-internal map-logical <logical> <device>",
>> +	"Get the physical offset of a sector.",
>> +	NULL
>> +};
>> +
>> +static int print_mapping_info(struct btrfs_fs_info *fs_info, u64 logical)
>> +{
>> +	struct cache_extent *ce;
>> +	struct map_lookup *map;
>> +	int num_copies;
>> +	int cur_mirror;
>> +	int ret;
>> +
>> +	ce = search_cache_extent(&fs_info->mapping_tree.cache_tree, logical);
>> +	if (!ce) {
>> +		error("no chunk mapping found for logical %llu", logical);
>> +		return -ENOENT;
>> +	}
>> +	map = container_of(ce, struct map_lookup, ce);
>> +	/* For RAID56, we only return the data stripe. */
>> +	if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK)
>> +		num_copies = 1;
>> +	else
>> +		num_copies = btrfs_num_copies(fs_info, logical,
>> +					      fs_info->sectorsize);
>> +
>> +	for (cur_mirror = 1; cur_mirror <= num_copies; cur_mirror++) {
>> +		struct btrfs_multi_bio *multi = NULL;
>> +		u64 len = fs_info->sectorsize;
>> +
>> +		ret = btrfs_map_block(fs_info, READ, logical, &len, &multi,
>> +				      cur_mirror, NULL);
>> +		if (ret < 0) {
>> +			errno = -ret;
>> +			error("failed to map logical %llu: %m", logical);
>> +			return ret;
>> +		}
>> +		/* We're using READ, which should only return one mirror. */
>> +		ASSERT(multi && multi->num_stripes == 1);
>> +		printf("mirror %d logical %llu phyiscal %llu device %s\n",
>> +			cur_mirror, logical, multi->stripes[0].physical,
>> +			multi->stripes[0].dev->name);
>> +		free(multi);
>> +	}
>> +	return 0;
>> +}
>> +
>> +static int cmd_inspect_map_logical(const struct cmd_struct *cmd, int argc,
>> +				   char **argv)
>> +{
>> +	struct open_ctree_flags ocf = {0};
>> +	struct btrfs_fs_info *fs_info;
>> +	u64 logical;
>> +	int ret;
>> +
>> +	clean_args_no_options(cmd, argc, argv);
>> +
>> +	if (check_argc_exact(argc - optind, 2))
>> +		return 1;
>> +
>> +	ocf.filename = argv[optind + 1];
>> +	ocf.flags = OPEN_CTREE_CHUNK_ROOT_ONLY;
>> +	logical = arg_strtou64(argv[optind]);
>> +
>> +	fs_info = open_ctree_fs_info(&ocf);
>
> So this is for images, not for mounted filesystem. The inspect-internal
> group has both but for the map-logical we could do both.

I'm afraid the map-logical tool will have the same requirement for
dump-tree, the preferred method is to run on unmounted device/image.

Running on mounted device is possible, but not recommended.

>
> I'd expect the primary use to be for the mounted fs.  The question is
> what for am I supposed to use map-logical for?

Mostly for fstests, to corrupt extents.

Thus we're completely capable to run it unmounted.

Thanks,
Qu

> See where a file is
> located, ok, that I'd like to see on a mounted filesystem. Running that
> on the block device while still mounted is unreliable.
diff mbox series

Patch

diff --git a/Documentation/btrfs-inspect-internal.rst b/Documentation/btrfs-inspect-internal.rst
index 710a34fb0cb9..8a9264d3dc5b 100644
--- a/Documentation/btrfs-inspect-internal.rst
+++ b/Documentation/btrfs-inspect-internal.rst
@@ -169,6 +169,13 @@  logical-resolve [-Pvo] [-s <bufsize>] <logical> <path>
         -v
                 (deprecated) alias for global *-v* option
 
+map-logical <logical> <device>
+        map the sector at given *logical* address in the linear filesystem space into
+        physical address.
+
+        .. note::
+                For RAID56, this will only map the data stripe.
+
 min-dev-size [options] <path>
         (needs root privileges)
 
diff --git a/cmds/inspect.c b/cmds/inspect.c
index 1534f2040f4e..271adf8c6fd4 100644
--- a/cmds/inspect.c
+++ b/cmds/inspect.c
@@ -29,6 +29,7 @@ 
 #include "kernel-shared/ctree.h"
 #include "common/send-utils.h"
 #include "kernel-shared/disk-io.h"
+#include "kernel-shared/volumes.h"
 #include "cmds/commands.h"
 #include "common/help.h"
 #include "common/open-utils.h"
@@ -125,6 +126,7 @@  static int cmd_inspect_inode_resolve(const struct cmd_struct *cmd,
 }
 static DEFINE_SIMPLE_COMMAND(inspect_inode_resolve, "inode-resolve");
 
+
 static const char * const cmd_inspect_logical_resolve_usage[] = {
 	"btrfs inspect-internal logical-resolve [-Pvo] [-s bufsize] <logical> <path>",
 	"Get file system paths for the given logical address",
@@ -348,6 +350,81 @@  out:
 }
 static DEFINE_SIMPLE_COMMAND(inspect_subvolid_resolve, "subvolid-resolve");
 
+static const char * const cmd_inspect_map_logical_usage[] = {
+	"btrfs inspect-internal map-logical <logical> <device>",
+	"Get the physical offset of a sector.",
+	NULL
+};
+
+static int print_mapping_info(struct btrfs_fs_info *fs_info, u64 logical)
+{
+	struct cache_extent *ce;
+	struct map_lookup *map;
+	int num_copies;
+	int cur_mirror;
+	int ret;
+
+	ce = search_cache_extent(&fs_info->mapping_tree.cache_tree, logical);
+	if (!ce) {
+		error("no chunk mapping found for logical %llu", logical);
+		return -ENOENT;
+	}
+	map = container_of(ce, struct map_lookup, ce);
+	/* For RAID56, we only return the data stripe. */
+	if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK)
+		num_copies = 1;
+	else
+		num_copies = btrfs_num_copies(fs_info, logical,
+					      fs_info->sectorsize);
+
+	for (cur_mirror = 1; cur_mirror <= num_copies; cur_mirror++) {
+		struct btrfs_multi_bio *multi = NULL;
+		u64 len = fs_info->sectorsize;
+
+		ret = btrfs_map_block(fs_info, READ, logical, &len, &multi,
+				      cur_mirror, NULL);
+		if (ret < 0) {
+			errno = -ret;
+			error("failed to map logical %llu: %m", logical);
+			return ret;
+		}
+		/* We're using READ, which should only return one mirror. */
+		ASSERT(multi && multi->num_stripes == 1);
+		printf("mirror %d logical %llu phyiscal %llu device %s\n",
+			cur_mirror, logical, multi->stripes[0].physical,
+			multi->stripes[0].dev->name);
+		free(multi);
+	}
+	return 0;
+}
+
+static int cmd_inspect_map_logical(const struct cmd_struct *cmd, int argc,
+				   char **argv)
+{
+	struct open_ctree_flags ocf = {0};
+	struct btrfs_fs_info *fs_info;
+	u64 logical;
+	int ret;
+
+	clean_args_no_options(cmd, argc, argv);
+
+	if (check_argc_exact(argc - optind, 2))
+		return 1;
+
+	ocf.filename = argv[optind + 1];
+	ocf.flags = OPEN_CTREE_CHUNK_ROOT_ONLY;
+	logical = arg_strtou64(argv[optind]);
+
+	fs_info = open_ctree_fs_info(&ocf);
+	if (!fs_info) {
+		error("failed to open btrfs on %s", ocf.filename);
+		return 1;
+	}
+	ret = print_mapping_info(fs_info, logical);
+	return !!ret;
+}
+static DEFINE_SIMPLE_COMMAND(inspect_map_logical, "map-logical");
+
 static const char* const cmd_inspect_rootid_usage[] = {
 	"btrfs inspect-internal rootid <path>",
 	"Get tree ID of the containing subvolume of path.",
@@ -690,6 +767,7 @@  static const struct cmd_group inspect_cmd_group = {
 		&cmd_struct_inspect_inode_resolve,
 		&cmd_struct_inspect_logical_resolve,
 		&cmd_struct_inspect_subvolid_resolve,
+		&cmd_struct_inspect_map_logical,
 		&cmd_struct_inspect_rootid,
 		&cmd_struct_inspect_min_dev_size,
 		&cmd_struct_inspect_dump_tree,