btrfs-progs/btrfs-map-logical.c

369 lines
8.6 KiB
C
Raw Permalink Normal View History

/*
* Copyright (C) 2009 Oracle. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License v2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 021110-1307, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <getopt.h>
#include "kerncompat.h"
#include "ctree.h"
#include "volumes.h"
#include "disk-io.h"
#include "print-tree.h"
#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
* */
static FILE *info_file;
static int map_one_extent(struct btrfs_fs_info *fs_info,
u64 *logical_ret, u64 *len_ret, int search_foward)
{
struct btrfs_path *path;
struct btrfs_key key;
u64 logical;
u64 len = 0;
int ret = 0;
BUG_ON(!logical_ret);
logical = *logical_ret;
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
key.objectid = logical;
key.type = 0;
key.offset = 0;
ret = btrfs_search_slot(NULL, fs_info->extent_root, &key, path,
0, 0);
if (ret < 0)
goto out;
BUG_ON(ret == 0);
ret = 0;
again:
btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
if ((search_foward && key.objectid < logical) ||
(!search_foward && key.objectid > logical) ||
(key.type != BTRFS_EXTENT_ITEM_KEY &&
key.type != BTRFS_METADATA_ITEM_KEY)) {
if (!search_foward)
ret = btrfs_previous_extent_item(fs_info->extent_root,
path, 0);
else
ret = btrfs_next_item(fs_info->extent_root, path);
if (ret)
goto out;
goto again;
}
logical = key.objectid;
if (key.type == BTRFS_METADATA_ITEM_KEY)
len = fs_info->nodesize;
else
len = key.offset;
out:
btrfs_free_path(path);
if (!ret) {
*logical_ret = logical;
if (len_ret)
*len_ret = len;
}
return ret;
}
static int __print_mapping_info(struct btrfs_fs_info *fs_info, u64 logical,
u64 len, int mirror_num)
{
struct btrfs_multi_bio *multi = NULL;
u64 cur_offset = 0;
u64 cur_len;
int ret = 0;
while (cur_offset < len) {
struct btrfs_device *device;
int i;
cur_len = len - cur_offset;
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",
mirror_num, logical, strerror(-ret));
return ret;
}
for (i = 0; i < multi->num_stripes; i++) {
device = multi->stripes[i].dev;
fprintf(info_file,
"mirror %d logical %Lu physical %Lu device %s\n",
mirror_num, logical + cur_offset,
multi->stripes[0].physical,
device->name);
}
free(multi);
multi = NULL;
cur_offset += cur_len;
}
return ret;
}
/*
* Logical and len is the exact value of a extent.
* And offset is the offset inside the extent. It's only used for case
* where user only want to print part of the extent.
*
* Caller *MUST* ensure the range [logical,logical+len) are in one extent.
* Or we can encounter the following case, causing a -ENOENT error:
* |<-----given parameter------>|
* |<------ Extent A ----->|
*/
static int print_mapping_info(struct btrfs_fs_info *fs_info, u64 logical,
u64 len)
{
int num_copies;
int mirror_num;
int ret = 0;
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;
}
return ret;
}
/* 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)
{
char buffer[BUFFER_SIZE];
u64 cur_offset = 0;
u64 cur_len;
int ret = 0;
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;
}
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;
}
cur_offset += cur_len;
}
return ret;
}
static void print_usage(void) __attribute__((noreturn));
static void print_usage(void)
{
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 argc, char **argv)
{
struct cache_tree root_cache;
struct btrfs_root *root;
char *dev;
char *output_file = NULL;
u64 copy = 0;
btrfs-progs: map-logical: Rework map-logical logics [BUG] The original map-logical has the following problems: 1) Assert if we pass any tree root bytenr. The problem is easy to trigger, here the number 29622272 is the bytenr of tree root: # btrfs-map-logical -l 29622272 /dev/sda6 mirror 1 logical 29622272 physical 38010880 device /dev/sda6 mirror 2 logical 29622272 physical 1111752704 device /dev/sda6 extent_io.c:582: free_extent_buffer: Assertion `eb->refs < 0` failed. btrfs-map-logical[0x41c464] btrfs-map-logical(free_extent_buffer+0xc0)[0x41cf10] btrfs-map-logical(btrfs_release_all_roots+0x59)[0x40e649] btrfs-map-logical(close_ctree+0x1aa)[0x40f51a] btrfs-map-logical(main+0x387)[0x4077c7] /usr/lib/libc.so.6(__libc_start_main+0xf0)[0x7f80a5562790] btrfs-map-logical(_start+0x29)[0x4078f9] The problem is that, btrfs-map-logical always use sectorsize as default block size to call alloc_extent_buffer. And when it failes to find the block with the same size, it will free the extent buffer in a incorrect method(Free and create a new one with refs == 1). 2) Will return map result for non-exist extent. # btrfs-map-logical -l 1 -b 123456 /dev/sda6 mirror 1 logical 1 physical 1 device /dev/sda6 mirror 1 logical 4097 physical 4097 device /dev/sda6 mirror 1 logical 8193 physical 8193 device /dev/sda6 ... Normally, before bytenr 12582912, there should be no extent as that's the mkfs time temp metadata/system chunk. But map-logical will still map them out. Not to mention the 1 offset among all results. [FIX] This patch will rework the whole map logical by the following methods: 1) Always do things inside a extent Even under the following case, map logical will only return covered range in existing extents. |<------ range given ------->| |<-Extent A->| |<-Extent B->| |<---Extent C->| Result: |<-->| |<---------->| |<-->| So with this patch, we will search extent tree to ensure all operation are inside a extent before we do some stupid things. 2) No direct call on alloc_extent_buffer function. That low-level function shouldn't be called at such high level. It's only designed for low-level tree operation. So in this patch we will only use safe high level functions avoid such problem. [RESULT] With this patch, no assert will be triggered and better handle on non-exist extents. # btrfs-map-logical -l 29622272 /dev/sda6 mirror 1 logical 29622272 physical 38010880 device /dev/sda6 mirror 2 logical 29622272 physical 1111752704 device /dev/sda6 # btrfs-map-logical -l 1 -b 123456 /dev/sda6 No extent found at range [1,123457) Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com> Signed-off-by: David Sterba <dsterba@suse.cz>
2015-06-17 07:49:04 +00:00
u64 logical = 0;
u64 bytes = 0;
btrfs-progs: map-logical: Rework map-logical logics [BUG] The original map-logical has the following problems: 1) Assert if we pass any tree root bytenr. The problem is easy to trigger, here the number 29622272 is the bytenr of tree root: # btrfs-map-logical -l 29622272 /dev/sda6 mirror 1 logical 29622272 physical 38010880 device /dev/sda6 mirror 2 logical 29622272 physical 1111752704 device /dev/sda6 extent_io.c:582: free_extent_buffer: Assertion `eb->refs < 0` failed. btrfs-map-logical[0x41c464] btrfs-map-logical(free_extent_buffer+0xc0)[0x41cf10] btrfs-map-logical(btrfs_release_all_roots+0x59)[0x40e649] btrfs-map-logical(close_ctree+0x1aa)[0x40f51a] btrfs-map-logical(main+0x387)[0x4077c7] /usr/lib/libc.so.6(__libc_start_main+0xf0)[0x7f80a5562790] btrfs-map-logical(_start+0x29)[0x4078f9] The problem is that, btrfs-map-logical always use sectorsize as default block size to call alloc_extent_buffer. And when it failes to find the block with the same size, it will free the extent buffer in a incorrect method(Free and create a new one with refs == 1). 2) Will return map result for non-exist extent. # btrfs-map-logical -l 1 -b 123456 /dev/sda6 mirror 1 logical 1 physical 1 device /dev/sda6 mirror 1 logical 4097 physical 4097 device /dev/sda6 mirror 1 logical 8193 physical 8193 device /dev/sda6 ... Normally, before bytenr 12582912, there should be no extent as that's the mkfs time temp metadata/system chunk. But map-logical will still map them out. Not to mention the 1 offset among all results. [FIX] This patch will rework the whole map logical by the following methods: 1) Always do things inside a extent Even under the following case, map logical will only return covered range in existing extents. |<------ range given ------->| |<-Extent A->| |<-Extent B->| |<---Extent C->| Result: |<-->| |<---------->| |<-->| So with this patch, we will search extent tree to ensure all operation are inside a extent before we do some stupid things. 2) No direct call on alloc_extent_buffer function. That low-level function shouldn't be called at such high level. It's only designed for low-level tree operation. So in this patch we will only use safe high level functions avoid such problem. [RESULT] With this patch, no assert will be triggered and better handle on non-exist extents. # btrfs-map-logical -l 29622272 /dev/sda6 mirror 1 logical 29622272 physical 38010880 device /dev/sda6 mirror 2 logical 29622272 physical 1111752704 device /dev/sda6 # btrfs-map-logical -l 1 -b 123456 /dev/sda6 No extent found at range [1,123457) Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com> Signed-off-by: David Sterba <dsterba@suse.cz>
2015-06-17 07:49:04 +00:00
u64 cur_logical = 0;
u64 cur_len = 0;
int out_fd = -1;
int found = 0;
int ret = 0;
while(1) {
int c;
static const struct option long_options[] = {
/* { "byte-count", 1, NULL, 'b' }, */
{ "logical", required_argument, NULL, 'l' },
{ "copy", required_argument, NULL, 'c' },
{ "output", required_argument, NULL, 'o' },
{ "bytes", required_argument, NULL, 'b' },
{ NULL, 0, NULL, 0}
};
c = getopt_long(argc, argv, "l:c:o:b:", long_options, NULL);
if (c < 0)
break;
switch(c) {
case 'l':
logical = arg_strtou64(optarg);
break;
case 'c':
copy = arg_strtou64(optarg);
break;
case 'b':
bytes = arg_strtou64(optarg);
break;
case 'o':
output_file = strdup(optarg);
break;
default:
print_usage();
}
}
set_argv0(argv);
if (check_argc_min(argc - optind, 1))
print_usage();
if (logical == 0)
print_usage();
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);
}
info_file = stdout;
if (output_file) {
if (strcmp(output_file, "-") == 0) {
out_fd = 1;
info_file = stderr;
} else {
out_fd = open(output_file, O_RDWR | O_CREAT, 0600);
if (out_fd < 0)
goto close;
ret = ftruncate(out_fd, 0);
if (ret) {
ret = 1;
close(out_fd);
goto close;
}
info_file = stdout;
}
}
if (bytes == 0)
bytes = root->fs_info->nodesize;
btrfs-progs: map-logical: Rework map-logical logics [BUG] The original map-logical has the following problems: 1) Assert if we pass any tree root bytenr. The problem is easy to trigger, here the number 29622272 is the bytenr of tree root: # btrfs-map-logical -l 29622272 /dev/sda6 mirror 1 logical 29622272 physical 38010880 device /dev/sda6 mirror 2 logical 29622272 physical 1111752704 device /dev/sda6 extent_io.c:582: free_extent_buffer: Assertion `eb->refs < 0` failed. btrfs-map-logical[0x41c464] btrfs-map-logical(free_extent_buffer+0xc0)[0x41cf10] btrfs-map-logical(btrfs_release_all_roots+0x59)[0x40e649] btrfs-map-logical(close_ctree+0x1aa)[0x40f51a] btrfs-map-logical(main+0x387)[0x4077c7] /usr/lib/libc.so.6(__libc_start_main+0xf0)[0x7f80a5562790] btrfs-map-logical(_start+0x29)[0x4078f9] The problem is that, btrfs-map-logical always use sectorsize as default block size to call alloc_extent_buffer. And when it failes to find the block with the same size, it will free the extent buffer in a incorrect method(Free and create a new one with refs == 1). 2) Will return map result for non-exist extent. # btrfs-map-logical -l 1 -b 123456 /dev/sda6 mirror 1 logical 1 physical 1 device /dev/sda6 mirror 1 logical 4097 physical 4097 device /dev/sda6 mirror 1 logical 8193 physical 8193 device /dev/sda6 ... Normally, before bytenr 12582912, there should be no extent as that's the mkfs time temp metadata/system chunk. But map-logical will still map them out. Not to mention the 1 offset among all results. [FIX] This patch will rework the whole map logical by the following methods: 1) Always do things inside a extent Even under the following case, map logical will only return covered range in existing extents. |<------ range given ------->| |<-Extent A->| |<-Extent B->| |<---Extent C->| Result: |<-->| |<---------->| |<-->| So with this patch, we will search extent tree to ensure all operation are inside a extent before we do some stupid things. 2) No direct call on alloc_extent_buffer function. That low-level function shouldn't be called at such high level. It's only designed for low-level tree operation. So in this patch we will only use safe high level functions avoid such problem. [RESULT] With this patch, no assert will be triggered and better handle on non-exist extents. # btrfs-map-logical -l 29622272 /dev/sda6 mirror 1 logical 29622272 physical 38010880 device /dev/sda6 mirror 2 logical 29622272 physical 1111752704 device /dev/sda6 # btrfs-map-logical -l 1 -b 123456 /dev/sda6 No extent found at range [1,123457) Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com> Signed-off-by: David Sterba <dsterba@suse.cz>
2015-06-17 07:49:04 +00:00
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;
}
}
btrfs-progs: map-logical: Rework map-logical logics [BUG] The original map-logical has the following problems: 1) Assert if we pass any tree root bytenr. The problem is easy to trigger, here the number 29622272 is the bytenr of tree root: # btrfs-map-logical -l 29622272 /dev/sda6 mirror 1 logical 29622272 physical 38010880 device /dev/sda6 mirror 2 logical 29622272 physical 1111752704 device /dev/sda6 extent_io.c:582: free_extent_buffer: Assertion `eb->refs < 0` failed. btrfs-map-logical[0x41c464] btrfs-map-logical(free_extent_buffer+0xc0)[0x41cf10] btrfs-map-logical(btrfs_release_all_roots+0x59)[0x40e649] btrfs-map-logical(close_ctree+0x1aa)[0x40f51a] btrfs-map-logical(main+0x387)[0x4077c7] /usr/lib/libc.so.6(__libc_start_main+0xf0)[0x7f80a5562790] btrfs-map-logical(_start+0x29)[0x4078f9] The problem is that, btrfs-map-logical always use sectorsize as default block size to call alloc_extent_buffer. And when it failes to find the block with the same size, it will free the extent buffer in a incorrect method(Free and create a new one with refs == 1). 2) Will return map result for non-exist extent. # btrfs-map-logical -l 1 -b 123456 /dev/sda6 mirror 1 logical 1 physical 1 device /dev/sda6 mirror 1 logical 4097 physical 4097 device /dev/sda6 mirror 1 logical 8193 physical 8193 device /dev/sda6 ... Normally, before bytenr 12582912, there should be no extent as that's the mkfs time temp metadata/system chunk. But map-logical will still map them out. Not to mention the 1 offset among all results. [FIX] This patch will rework the whole map logical by the following methods: 1) Always do things inside a extent Even under the following case, map logical will only return covered range in existing extents. |<------ range given ------->| |<-Extent A->| |<-Extent B->| |<---Extent C->| Result: |<-->| |<---------->| |<-->| So with this patch, we will search extent tree to ensure all operation are inside a extent before we do some stupid things. 2) No direct call on alloc_extent_buffer function. That low-level function shouldn't be called at such high level. It's only designed for low-level tree operation. So in this patch we will only use safe high level functions avoid such problem. [RESULT] With this patch, no assert will be triggered and better handle on non-exist extents. # btrfs-map-logical -l 29622272 /dev/sda6 mirror 1 logical 29622272 physical 38010880 device /dev/sda6 mirror 2 logical 29622272 physical 1111752704 device /dev/sda6 # btrfs-map-logical -l 1 -b 123456 /dev/sda6 No extent found at range [1,123457) Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com> Signed-off-by: David Sterba <dsterba@suse.cz>
2015-06-17 07:49:04 +00:00
while (cur_logical + cur_len >= logical && cur_logical < logical +
bytes) {
u64 real_logical;
u64 real_len;
btrfs-progs: map-logical: Rework map-logical logics [BUG] The original map-logical has the following problems: 1) Assert if we pass any tree root bytenr. The problem is easy to trigger, here the number 29622272 is the bytenr of tree root: # btrfs-map-logical -l 29622272 /dev/sda6 mirror 1 logical 29622272 physical 38010880 device /dev/sda6 mirror 2 logical 29622272 physical 1111752704 device /dev/sda6 extent_io.c:582: free_extent_buffer: Assertion `eb->refs < 0` failed. btrfs-map-logical[0x41c464] btrfs-map-logical(free_extent_buffer+0xc0)[0x41cf10] btrfs-map-logical(btrfs_release_all_roots+0x59)[0x40e649] btrfs-map-logical(close_ctree+0x1aa)[0x40f51a] btrfs-map-logical(main+0x387)[0x4077c7] /usr/lib/libc.so.6(__libc_start_main+0xf0)[0x7f80a5562790] btrfs-map-logical(_start+0x29)[0x4078f9] The problem is that, btrfs-map-logical always use sectorsize as default block size to call alloc_extent_buffer. And when it failes to find the block with the same size, it will free the extent buffer in a incorrect method(Free and create a new one with refs == 1). 2) Will return map result for non-exist extent. # btrfs-map-logical -l 1 -b 123456 /dev/sda6 mirror 1 logical 1 physical 1 device /dev/sda6 mirror 1 logical 4097 physical 4097 device /dev/sda6 mirror 1 logical 8193 physical 8193 device /dev/sda6 ... Normally, before bytenr 12582912, there should be no extent as that's the mkfs time temp metadata/system chunk. But map-logical will still map them out. Not to mention the 1 offset among all results. [FIX] This patch will rework the whole map logical by the following methods: 1) Always do things inside a extent Even under the following case, map logical will only return covered range in existing extents. |<------ range given ------->| |<-Extent A->| |<-Extent B->| |<---Extent C->| Result: |<-->| |<---------->| |<-->| So with this patch, we will search extent tree to ensure all operation are inside a extent before we do some stupid things. 2) No direct call on alloc_extent_buffer function. That low-level function shouldn't be called at such high level. It's only designed for low-level tree operation. So in this patch we will only use safe high level functions avoid such problem. [RESULT] With this patch, no assert will be triggered and better handle on non-exist extents. # btrfs-map-logical -l 29622272 /dev/sda6 mirror 1 logical 29622272 physical 38010880 device /dev/sda6 mirror 2 logical 29622272 physical 1111752704 device /dev/sda6 # btrfs-map-logical -l 1 -b 123456 /dev/sda6 No extent found at range [1,123457) Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com> Signed-off-by: David Sterba <dsterba@suse.cz>
2015-06-17 07:49:04 +00:00
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;
btrfs-progs: map-logical: Rework map-logical logics [BUG] The original map-logical has the following problems: 1) Assert if we pass any tree root bytenr. The problem is easy to trigger, here the number 29622272 is the bytenr of tree root: # btrfs-map-logical -l 29622272 /dev/sda6 mirror 1 logical 29622272 physical 38010880 device /dev/sda6 mirror 2 logical 29622272 physical 1111752704 device /dev/sda6 extent_io.c:582: free_extent_buffer: Assertion `eb->refs < 0` failed. btrfs-map-logical[0x41c464] btrfs-map-logical(free_extent_buffer+0xc0)[0x41cf10] btrfs-map-logical(btrfs_release_all_roots+0x59)[0x40e649] btrfs-map-logical(close_ctree+0x1aa)[0x40f51a] btrfs-map-logical(main+0x387)[0x4077c7] /usr/lib/libc.so.6(__libc_start_main+0xf0)[0x7f80a5562790] btrfs-map-logical(_start+0x29)[0x4078f9] The problem is that, btrfs-map-logical always use sectorsize as default block size to call alloc_extent_buffer. And when it failes to find the block with the same size, it will free the extent buffer in a incorrect method(Free and create a new one with refs == 1). 2) Will return map result for non-exist extent. # btrfs-map-logical -l 1 -b 123456 /dev/sda6 mirror 1 logical 1 physical 1 device /dev/sda6 mirror 1 logical 4097 physical 4097 device /dev/sda6 mirror 1 logical 8193 physical 8193 device /dev/sda6 ... Normally, before bytenr 12582912, there should be no extent as that's the mkfs time temp metadata/system chunk. But map-logical will still map them out. Not to mention the 1 offset among all results. [FIX] This patch will rework the whole map logical by the following methods: 1) Always do things inside a extent Even under the following case, map logical will only return covered range in existing extents. |<------ range given ------->| |<-Extent A->| |<-Extent B->| |<---Extent C->| Result: |<-->| |<---------->| |<-->| So with this patch, we will search extent tree to ensure all operation are inside a extent before we do some stupid things. 2) No direct call on alloc_extent_buffer function. That low-level function shouldn't be called at such high level. It's only designed for low-level tree operation. So in this patch we will only use safe high level functions avoid such problem. [RESULT] With this patch, no assert will be triggered and better handle on non-exist extents. # btrfs-map-logical -l 29622272 /dev/sda6 mirror 1 logical 29622272 physical 38010880 device /dev/sda6 mirror 2 logical 29622272 physical 1111752704 device /dev/sda6 # btrfs-map-logical -l 1 -b 123456 /dev/sda6 No extent found at range [1,123457) Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com> Signed-off-by: David Sterba <dsterba@suse.cz>
2015-06-17 07:49:04 +00:00
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;
}
btrfs-progs: map-logical: Rework map-logical logics [BUG] The original map-logical has the following problems: 1) Assert if we pass any tree root bytenr. The problem is easy to trigger, here the number 29622272 is the bytenr of tree root: # btrfs-map-logical -l 29622272 /dev/sda6 mirror 1 logical 29622272 physical 38010880 device /dev/sda6 mirror 2 logical 29622272 physical 1111752704 device /dev/sda6 extent_io.c:582: free_extent_buffer: Assertion `eb->refs < 0` failed. btrfs-map-logical[0x41c464] btrfs-map-logical(free_extent_buffer+0xc0)[0x41cf10] btrfs-map-logical(btrfs_release_all_roots+0x59)[0x40e649] btrfs-map-logical(close_ctree+0x1aa)[0x40f51a] btrfs-map-logical(main+0x387)[0x4077c7] /usr/lib/libc.so.6(__libc_start_main+0xf0)[0x7f80a5562790] btrfs-map-logical(_start+0x29)[0x4078f9] The problem is that, btrfs-map-logical always use sectorsize as default block size to call alloc_extent_buffer. And when it failes to find the block with the same size, it will free the extent buffer in a incorrect method(Free and create a new one with refs == 1). 2) Will return map result for non-exist extent. # btrfs-map-logical -l 1 -b 123456 /dev/sda6 mirror 1 logical 1 physical 1 device /dev/sda6 mirror 1 logical 4097 physical 4097 device /dev/sda6 mirror 1 logical 8193 physical 8193 device /dev/sda6 ... Normally, before bytenr 12582912, there should be no extent as that's the mkfs time temp metadata/system chunk. But map-logical will still map them out. Not to mention the 1 offset among all results. [FIX] This patch will rework the whole map logical by the following methods: 1) Always do things inside a extent Even under the following case, map logical will only return covered range in existing extents. |<------ range given ------->| |<-Extent A->| |<-Extent B->| |<---Extent C->| Result: |<-->| |<---------->| |<-->| So with this patch, we will search extent tree to ensure all operation are inside a extent before we do some stupid things. 2) No direct call on alloc_extent_buffer function. That low-level function shouldn't be called at such high level. It's only designed for low-level tree operation. So in this patch we will only use safe high level functions avoid such problem. [RESULT] With this patch, no assert will be triggered and better handle on non-exist extents. # btrfs-map-logical -l 29622272 /dev/sda6 mirror 1 logical 29622272 physical 38010880 device /dev/sda6 mirror 2 logical 29622272 physical 1111752704 device /dev/sda6 # btrfs-map-logical -l 1 -b 123456 /dev/sda6 No extent found at range [1,123457) Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com> Signed-off-by: David Sterba <dsterba@suse.cz>
2015-06-17 07:49:04 +00:00
cur_logical += cur_len;
}
btrfs-progs: map-logical: Rework map-logical logics [BUG] The original map-logical has the following problems: 1) Assert if we pass any tree root bytenr. The problem is easy to trigger, here the number 29622272 is the bytenr of tree root: # btrfs-map-logical -l 29622272 /dev/sda6 mirror 1 logical 29622272 physical 38010880 device /dev/sda6 mirror 2 logical 29622272 physical 1111752704 device /dev/sda6 extent_io.c:582: free_extent_buffer: Assertion `eb->refs < 0` failed. btrfs-map-logical[0x41c464] btrfs-map-logical(free_extent_buffer+0xc0)[0x41cf10] btrfs-map-logical(btrfs_release_all_roots+0x59)[0x40e649] btrfs-map-logical(close_ctree+0x1aa)[0x40f51a] btrfs-map-logical(main+0x387)[0x4077c7] /usr/lib/libc.so.6(__libc_start_main+0xf0)[0x7f80a5562790] btrfs-map-logical(_start+0x29)[0x4078f9] The problem is that, btrfs-map-logical always use sectorsize as default block size to call alloc_extent_buffer. And when it failes to find the block with the same size, it will free the extent buffer in a incorrect method(Free and create a new one with refs == 1). 2) Will return map result for non-exist extent. # btrfs-map-logical -l 1 -b 123456 /dev/sda6 mirror 1 logical 1 physical 1 device /dev/sda6 mirror 1 logical 4097 physical 4097 device /dev/sda6 mirror 1 logical 8193 physical 8193 device /dev/sda6 ... Normally, before bytenr 12582912, there should be no extent as that's the mkfs time temp metadata/system chunk. But map-logical will still map them out. Not to mention the 1 offset among all results. [FIX] This patch will rework the whole map logical by the following methods: 1) Always do things inside a extent Even under the following case, map logical will only return covered range in existing extents. |<------ range given ------->| |<-Extent A->| |<-Extent B->| |<---Extent C->| Result: |<-->| |<---------->| |<-->| So with this patch, we will search extent tree to ensure all operation are inside a extent before we do some stupid things. 2) No direct call on alloc_extent_buffer function. That low-level function shouldn't be called at such high level. It's only designed for low-level tree operation. So in this patch we will only use safe high level functions avoid such problem. [RESULT] With this patch, no assert will be triggered and better handle on non-exist extents. # btrfs-map-logical -l 29622272 /dev/sda6 mirror 1 logical 29622272 physical 38010880 device /dev/sda6 mirror 2 logical 29622272 physical 1111752704 device /dev/sda6 # btrfs-map-logical -l 1 -b 123456 /dev/sda6 No extent found at range [1,123457) Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com> Signed-off-by: David Sterba <dsterba@suse.cz>
2015-06-17 07:49:04 +00:00
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);
btrfs-progs: map-logical: Rework map-logical logics [BUG] The original map-logical has the following problems: 1) Assert if we pass any tree root bytenr. The problem is easy to trigger, here the number 29622272 is the bytenr of tree root: # btrfs-map-logical -l 29622272 /dev/sda6 mirror 1 logical 29622272 physical 38010880 device /dev/sda6 mirror 2 logical 29622272 physical 1111752704 device /dev/sda6 extent_io.c:582: free_extent_buffer: Assertion `eb->refs < 0` failed. btrfs-map-logical[0x41c464] btrfs-map-logical(free_extent_buffer+0xc0)[0x41cf10] btrfs-map-logical(btrfs_release_all_roots+0x59)[0x40e649] btrfs-map-logical(close_ctree+0x1aa)[0x40f51a] btrfs-map-logical(main+0x387)[0x4077c7] /usr/lib/libc.so.6(__libc_start_main+0xf0)[0x7f80a5562790] btrfs-map-logical(_start+0x29)[0x4078f9] The problem is that, btrfs-map-logical always use sectorsize as default block size to call alloc_extent_buffer. And when it failes to find the block with the same size, it will free the extent buffer in a incorrect method(Free and create a new one with refs == 1). 2) Will return map result for non-exist extent. # btrfs-map-logical -l 1 -b 123456 /dev/sda6 mirror 1 logical 1 physical 1 device /dev/sda6 mirror 1 logical 4097 physical 4097 device /dev/sda6 mirror 1 logical 8193 physical 8193 device /dev/sda6 ... Normally, before bytenr 12582912, there should be no extent as that's the mkfs time temp metadata/system chunk. But map-logical will still map them out. Not to mention the 1 offset among all results. [FIX] This patch will rework the whole map logical by the following methods: 1) Always do things inside a extent Even under the following case, map logical will only return covered range in existing extents. |<------ range given ------->| |<-Extent A->| |<-Extent B->| |<---Extent C->| Result: |<-->| |<---------->| |<-->| So with this patch, we will search extent tree to ensure all operation are inside a extent before we do some stupid things. 2) No direct call on alloc_extent_buffer function. That low-level function shouldn't be called at such high level. It's only designed for low-level tree operation. So in this patch we will only use safe high level functions avoid such problem. [RESULT] With this patch, no assert will be triggered and better handle on non-exist extents. # btrfs-map-logical -l 29622272 /dev/sda6 mirror 1 logical 29622272 physical 38010880 device /dev/sda6 mirror 2 logical 29622272 physical 1111752704 device /dev/sda6 # btrfs-map-logical -l 1 -b 123456 /dev/sda6 No extent found at range [1,123457) Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com> Signed-off-by: David Sterba <dsterba@suse.cz>
2015-06-17 07:49:04 +00:00
if (ret < 0)
ret = 1;
btrfs_close_all_devices();
return ret;
}