2 * Copyright (C) 2009 Oracle. All rights reserved.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License v2 as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public
14 * License along with this program; if not, write to the
15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 * Boston, MA 021110-1307, USA.
24 #include "kerncompat.h"
28 #include "print-tree.h"
29 #include "transaction.h"
34 #define BUFFER_SIZE SZ_64K
36 /* we write the mirror info to stdout unless they are dumping the data
39 static FILE *info_file
;
41 static int map_one_extent(struct btrfs_fs_info
*fs_info
,
42 u64
*logical_ret
, u64
*len_ret
, int search_forward
)
44 struct btrfs_path
*path
;
51 logical
= *logical_ret
;
53 path
= btrfs_alloc_path();
57 key
.objectid
= logical
;
61 ret
= btrfs_search_slot(NULL
, fs_info
->extent_root
, &key
, path
,
69 btrfs_item_key_to_cpu(path
->nodes
[0], &key
, path
->slots
[0]);
70 if ((search_forward
&& key
.objectid
< logical
) ||
71 (!search_forward
&& key
.objectid
> logical
) ||
72 (key
.type
!= BTRFS_EXTENT_ITEM_KEY
&&
73 key
.type
!= BTRFS_METADATA_ITEM_KEY
)) {
75 ret
= btrfs_previous_extent_item(fs_info
->extent_root
,
78 ret
= btrfs_next_extent_item(fs_info
->extent_root
,
84 logical
= key
.objectid
;
85 if (key
.type
== BTRFS_METADATA_ITEM_KEY
)
86 len
= fs_info
->nodesize
;
91 btrfs_free_path(path
);
93 *logical_ret
= logical
;
100 static int __print_mapping_info(struct btrfs_fs_info
*fs_info
, u64 logical
,
101 u64 len
, int mirror_num
)
103 struct btrfs_multi_bio
*multi
= NULL
;
108 while (cur_offset
< len
) {
109 struct btrfs_device
*device
;
112 cur_len
= len
- cur_offset
;
113 ret
= btrfs_map_block(fs_info
, READ
, logical
+ cur_offset
,
114 &cur_len
, &multi
, mirror_num
, NULL
);
117 "Error: fails to map mirror%d logical %llu: %s\n",
118 mirror_num
, logical
, strerror(-ret
));
121 for (i
= 0; i
< multi
->num_stripes
; i
++) {
122 device
= multi
->stripes
[i
].dev
;
124 "mirror %d logical %Lu physical %Lu device %s\n",
125 mirror_num
, logical
+ cur_offset
,
126 multi
->stripes
[0].physical
,
131 cur_offset
+= cur_len
;
137 * Logical and len is the exact value of a extent.
138 * And offset is the offset inside the extent. It's only used for case
139 * where user only want to print part of the extent.
141 * Caller *MUST* ensure the range [logical,logical+len) are in one extent.
142 * Or we can encounter the following case, causing a -ENOENT error:
143 * |<-----given parameter------>|
144 * |<------ Extent A ----->|
146 static int print_mapping_info(struct btrfs_fs_info
*fs_info
, u64 logical
,
153 num_copies
= btrfs_num_copies(fs_info
, logical
, len
);
154 for (mirror_num
= 1; mirror_num
<= num_copies
; mirror_num
++) {
155 ret
= __print_mapping_info(fs_info
, logical
, len
, mirror_num
);
162 /* Same requisition as print_mapping_info function */
163 static int write_extent_content(struct btrfs_fs_info
*fs_info
, int out_fd
,
164 u64 logical
, u64 length
, int mirror
)
166 char buffer
[BUFFER_SIZE
];
171 while (cur_offset
< length
) {
172 cur_len
= min_t(u64
, length
- cur_offset
, BUFFER_SIZE
);
173 ret
= read_extent_data(fs_info
, buffer
,
174 logical
+ cur_offset
, &cur_len
, mirror
);
177 "Failed to read extent at [%llu, %llu]: %s\n",
178 logical
, logical
+ length
, strerror(-ret
));
181 ret
= write(out_fd
, buffer
, cur_len
);
182 if (ret
< 0 || ret
!= cur_len
) {
185 fprintf(stderr
, "output file write failed: %s\n",
189 cur_offset
+= cur_len
;
194 __attribute__((noreturn
))
195 static void print_usage(void)
197 printf("usage: btrfs-map-logical [options] device\n");
198 printf("\t-l Logical extent to map\n");
199 printf("\t-c Copy of the extent to read (usually 1 or 2)\n");
200 printf("\t-o Output file to hold the extent\n");
201 printf("\t-b Number of bytes to read\n");
205 int main(int argc
, char **argv
)
207 struct cache_tree root_cache
;
208 struct btrfs_root
*root
;
210 char *output_file
= NULL
;
222 static const struct option long_options
[] = {
223 /* { "byte-count", 1, NULL, 'b' }, */
224 { "logical", required_argument
, NULL
, 'l' },
225 { "copy", required_argument
, NULL
, 'c' },
226 { "output", required_argument
, NULL
, 'o' },
227 { "bytes", required_argument
, NULL
, 'b' },
231 c
= getopt_long(argc
, argv
, "l:c:o:b:", long_options
, NULL
);
236 logical
= arg_strtou64(optarg
);
239 copy
= arg_strtou64(optarg
);
242 bytes
= arg_strtou64(optarg
);
245 output_file
= strdup(optarg
);
252 if (check_argc_min(argc
- optind
, 1))
260 cache_tree_init(&root_cache
);
262 root
= open_ctree(dev
, 0, 0);
264 fprintf(stderr
, "Open ctree failed\n");
271 if (strcmp(output_file
, "-") == 0) {
275 out_fd
= open(output_file
, O_RDWR
| O_CREAT
, 0600);
278 ret
= ftruncate(out_fd
, 0);
289 bytes
= root
->fs_info
->nodesize
;
290 cur_logical
= logical
;
293 /* First find the nearest extent */
294 ret
= map_one_extent(root
->fs_info
, &cur_logical
, &cur_len
, 0);
296 fprintf(stderr
, "Failed to find extent at [%llu,%llu): %s\n",
297 cur_logical
, cur_logical
+ cur_len
, strerror(-ret
));
301 * Normally, search backward should be OK, but for special case like
302 * given logical is quite small where no extents are before it,
303 * we need to search forward.
306 ret
= map_one_extent(root
->fs_info
, &cur_logical
, &cur_len
, 1);
309 "Failed to find extent at [%llu,%llu): %s\n",
310 cur_logical
, cur_logical
+ cur_len
,
316 "Failed to find any extent at [%llu,%llu)\n",
317 cur_logical
, cur_logical
+ cur_len
);
322 while (cur_logical
+ cur_len
>= logical
&& cur_logical
< logical
+
328 ret
= map_one_extent(root
->fs_info
, &cur_logical
, &cur_len
, 1);
333 /* check again if there is overlap. */
334 if (cur_logical
+ cur_len
< logical
||
335 cur_logical
>= logical
+ bytes
)
338 real_logical
= max(logical
, cur_logical
);
339 real_len
= min(logical
+ bytes
, cur_logical
+ cur_len
) -
342 ret
= print_mapping_info(root
->fs_info
, real_logical
, real_len
);
345 if (output_file
&& out_fd
!= -1) {
346 ret
= write_extent_content(root
->fs_info
, out_fd
,
347 real_logical
, real_len
, copy
);
352 cur_logical
+= cur_len
;
356 fprintf(stderr
, "No extent found at range [%llu,%llu)\n",
357 logical
, logical
+ bytes
);
360 if (output_file
&& out_fd
!= 1)
367 btrfs_close_all_devices();