#include "transaction.h"
#include "list.h"
#include "utils.h"
+#include "help.h"
+
+#define BUFFER_SIZE SZ_64K
/* we write the mirror info to stdout unless they are dumping the data
* to stdout
}
logical = key.objectid;
if (key.type == BTRFS_METADATA_ITEM_KEY)
- len = fs_info->tree_root->leafsize;
+ len = fs_info->nodesize;
else
len = key.offset;
int i;
cur_len = len - cur_offset;
- ret = btrfs_map_block(&fs_info->mapping_tree, READ,
- logical + cur_offset, &cur_len,
- &multi, mirror_num, NULL);
+ ret = btrfs_map_block(fs_info, READ, logical + cur_offset,
+ &cur_len, &multi, mirror_num, NULL);
if (ret) {
fprintf(info_file,
"Error: fails to map mirror%d logical %llu: %s\n",
multi->stripes[0].physical,
device->name);
}
- kfree(multi);
+ free(multi);
multi = NULL;
cur_offset += cur_len;
}
int mirror_num;
int ret = 0;
- num_copies = btrfs_num_copies(&fs_info->mapping_tree, logical, len);
+ num_copies = btrfs_num_copies(fs_info, logical, len);
for (mirror_num = 1; mirror_num <= num_copies; mirror_num++) {
ret = __print_mapping_info(fs_info, logical, len, mirror_num);
if (ret < 0)
return ret;
}
-static struct extent_buffer * debug_read_block(struct btrfs_root *root,
- u64 bytenr, u32 blocksize, u64 copy)
+/* Same requisition as print_mapping_info function */
+static int write_extent_content(struct btrfs_fs_info *fs_info, int out_fd,
+ u64 logical, u64 length, int mirror)
{
- int ret;
- struct extent_buffer *eb;
- u64 length;
- struct btrfs_multi_bio *multi = NULL;
- struct btrfs_device *device;
- int num_copies;
- int mirror_num = 1;
-
- eb = btrfs_find_create_tree_block(root, bytenr, blocksize);
- if (!eb)
- return NULL;
+ char buffer[BUFFER_SIZE];
+ u64 cur_offset = 0;
+ u64 cur_len;
+ int ret = 0;
- length = blocksize;
- while (1) {
- ret = btrfs_map_block(&root->fs_info->mapping_tree, READ,
- eb->start, &length, &multi,
- mirror_num, NULL);
- if (ret) {
- fprintf(info_file,
- "Error: fails to map mirror%d logical %llu: %s\n",
- mirror_num, (unsigned long long)eb->start,
- strerror(-ret));
- free_extent_buffer(eb);
- return NULL;
+ while (cur_offset < length) {
+ cur_len = min_t(u64, length - cur_offset, BUFFER_SIZE);
+ ret = read_extent_data(fs_info, buffer,
+ logical + cur_offset, &cur_len, mirror);
+ if (ret < 0) {
+ fprintf(stderr,
+ "Failed to read extent at [%llu, %llu]: %s\n",
+ logical, logical + length, strerror(-ret));
+ return ret;
}
- device = multi->stripes[0].dev;
- eb->fd = device->fd;
- device->total_ios++;
- eb->dev_bytenr = multi->stripes[0].physical;
-
- fprintf(info_file, "mirror %d logical %Lu physical %Lu "
- "device %s\n", mirror_num, (unsigned long long)bytenr,
- (unsigned long long)eb->dev_bytenr, device->name);
- kfree(multi);
-
- if (!copy || mirror_num == copy) {
- ret = read_extent_from_disk(eb, 0, eb->len);
- if (ret) {
- fprintf(info_file,
- "Error: failed to read extent: mirror %d logical %llu: %s\n",
- mirror_num, (unsigned long long)eb->start,
- strerror(-ret));
- free_extent_buffer(eb);
- eb = NULL;
- break;
- }
+ ret = write(out_fd, buffer, cur_len);
+ if (ret < 0 || ret != cur_len) {
+ if (ret > 0)
+ ret = -EINTR;
+ fprintf(stderr, "output file write failed: %s\n",
+ strerror(-ret));
+ return ret;
}
-
- num_copies = btrfs_num_copies(&root->fs_info->mapping_tree,
- eb->start, eb->len);
- if (num_copies == 1)
- break;
-
- mirror_num++;
- if (mirror_num > num_copies)
- break;
+ cur_offset += cur_len;
}
- return eb;
+ return ret;
}
-static void print_usage(void) __attribute__((noreturn));
+__attribute__((noreturn))
static void print_usage(void)
{
- fprintf(stderr, "usage: btrfs-map-logical [options] device\n");
- fprintf(stderr, "\t-l Logical extent to map\n");
- fprintf(stderr, "\t-c Copy of the extent to read (usually 1 or 2)\n");
- fprintf(stderr, "\t-o Output file to hold the extent\n");
- fprintf(stderr, "\t-b Number of bytes to read\n");
+ printf("usage: btrfs-map-logical [options] device\n");
+ printf("\t-l Logical extent to map\n");
+ printf("\t-c Copy of the extent to read (usually 1 or 2)\n");
+ printf("\t-o Output file to hold the extent\n");
+ printf("\t-b Number of bytes to read\n");
exit(1);
}
-int main(int ac, char **av)
+int main(int argc, char **argv)
{
struct cache_tree root_cache;
struct btrfs_root *root;
- struct extent_buffer *eb;
char *dev;
char *output_file = NULL;
- u64 logical = 0;
- int ret = 0;
u64 copy = 0;
+ u64 logical = 0;
u64 bytes = 0;
- int out_fd = 0;
+ u64 cur_logical = 0;
+ u64 cur_len = 0;
+ int out_fd = -1;
+ int found = 0;
+ int ret = 0;
while(1) {
int c;
{ NULL, 0, NULL, 0}
};
- c = getopt_long(ac, av, "l:c:o:b:", long_options, NULL);
+ c = getopt_long(argc, argv, "l:c:o:b:", long_options, NULL);
if (c < 0)
break;
switch(c) {
print_usage();
}
}
- set_argv0(av);
- ac = ac - optind;
- if (check_argc_min(ac, 1))
+ set_argv0(argv);
+ if (check_argc_min(argc - optind, 1))
print_usage();
if (logical == 0)
print_usage();
- dev = av[optind];
+ dev = argv[optind];
radix_tree_init();
cache_tree_init(&root_cache);
root = open_ctree(dev, 0, 0);
if (!root) {
fprintf(stderr, "Open ctree failed\n");
+ free(output_file);
exit(1);
}
}
if (bytes == 0)
- bytes = root->sectorsize;
+ bytes = root->fs_info->nodesize;
+ cur_logical = logical;
+ cur_len = bytes;
+
+ /* First find the nearest extent */
+ ret = map_one_extent(root->fs_info, &cur_logical, &cur_len, 0);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to find extent at [%llu,%llu): %s\n",
+ cur_logical, cur_logical + cur_len, strerror(-ret));
+ goto out_close_fd;
+ }
+ /*
+ * Normally, search backward should be OK, but for special case like
+ * given logical is quite small where no extents are before it,
+ * we need to search forward.
+ */
+ if (ret > 0) {
+ ret = map_one_extent(root->fs_info, &cur_logical, &cur_len, 1);
+ if (ret < 0) {
+ fprintf(stderr,
+ "Failed to find extent at [%llu,%llu): %s\n",
+ cur_logical, cur_logical + cur_len,
+ strerror(-ret));
+ goto out_close_fd;
+ }
+ if (ret > 0) {
+ fprintf(stderr,
+ "Failed to find any extent at [%llu,%llu)\n",
+ cur_logical, cur_logical + cur_len);
+ goto out_close_fd;
+ }
+ }
- bytes = (bytes + root->sectorsize - 1) / root->sectorsize;
- bytes *= root->sectorsize;
+ while (cur_logical + cur_len >= logical && cur_logical < logical +
+ bytes) {
+ u64 real_logical;
+ u64 real_len;
- while (bytes > 0) {
- eb = debug_read_block(root, logical, root->sectorsize, copy);
- if (eb && output_file) {
- ret = write(out_fd, eb->data, eb->len);
- if (ret < 0 || ret != eb->len) {
- ret = 1;
- fprintf(stderr, "output file write failed\n");
+ found = 1;
+ ret = map_one_extent(root->fs_info, &cur_logical, &cur_len, 1);
+ if (ret < 0)
+ goto out_close_fd;
+ if (ret > 0)
+ break;
+ /* check again if there is overlap. */
+ if (cur_logical + cur_len < logical ||
+ cur_logical >= logical + bytes)
+ break;
+
+ real_logical = max(logical, cur_logical);
+ real_len = min(logical + bytes, cur_logical + cur_len) -
+ real_logical;
+
+ ret = print_mapping_info(root->fs_info, real_logical, real_len);
+ if (ret < 0)
+ goto out_close_fd;
+ if (output_file && out_fd != -1) {
+ ret = write_extent_content(root->fs_info, out_fd,
+ real_logical, real_len, copy);
+ if (ret < 0)
goto out_close_fd;
- }
}
- free_extent_buffer(eb);
- logical += root->sectorsize;
- bytes -= root->sectorsize;
+
+ cur_logical += cur_len;
}
+ if (!found) {
+ fprintf(stderr, "No extent found at range [%llu,%llu)\n",
+ logical, logical + bytes);
+ }
out_close_fd:
if (output_file && out_fd != 1)
close(out_fd);
close:
+ free(output_file);
close_ctree(root);
+ if (ret < 0)
+ ret = 1;
+ btrfs_close_all_devices();
return ret;
}