2 * Copyright (C) 2013 FUJITSU LIMITED. 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.
19 #define _XOPEN_SOURCE 500
26 #include <uuid/uuid.h>
32 #include "kerncompat.h"
41 struct btrfs_recover_superblock
{
42 struct btrfs_fs_devices
*fs_devices
;
44 struct list_head good_supers
;
45 struct list_head bad_supers
;
50 struct super_block_record
{
51 struct list_head list
;
54 struct btrfs_super_block sb
;
60 void init_recover_superblock(struct btrfs_recover_superblock
*recover
)
62 INIT_LIST_HEAD(&recover
->good_supers
);
63 INIT_LIST_HEAD(&recover
->bad_supers
);
65 recover
->fs_devices
= NULL
;
66 recover
->max_generation
= 0;
70 void free_recover_superblock(struct btrfs_recover_superblock
*recover
)
72 struct btrfs_device
*device
;
73 struct super_block_record
*record
;
75 if (!recover
->fs_devices
)
78 while (!list_empty(&recover
->fs_devices
->devices
)) {
79 device
= list_entry(recover
->fs_devices
->devices
.next
,
80 struct btrfs_device
, dev_list
);
81 list_del_init(&device
->dev_list
);
85 free(recover
->fs_devices
);
87 while (!list_empty(&recover
->good_supers
)) {
88 record
= list_entry(recover
->good_supers
.next
,
89 struct super_block_record
, list
);
90 list_del_init(&record
->list
);
91 free(record
->device_name
);
95 while (!list_empty(&recover
->bad_supers
)) {
96 record
= list_entry(recover
->bad_supers
.next
,
97 struct super_block_record
, list
);
98 list_del_init(&record
->list
);
99 free(record
->device_name
);
104 static int check_super(u64 bytenr
, struct btrfs_super_block
*sb
)
106 int csum_size
= btrfs_super_csum_size(sb
);
107 char result
[csum_size
];
110 if (btrfs_super_bytenr(sb
) != bytenr
)
112 if (sb
->magic
!= cpu_to_le64(BTRFS_MAGIC
))
115 crc
= btrfs_csum_data(NULL
, (char *)sb
+ BTRFS_CSUM_SIZE
,
116 crc
, BTRFS_SUPER_INFO_SIZE
- BTRFS_CSUM_SIZE
);
117 btrfs_csum_final(crc
, result
);
119 return !memcmp(sb
, &result
, csum_size
);
122 static int add_superblock_record(struct btrfs_super_block
*sb
, char *fname
,
123 u64 bytenr
, struct list_head
*head
)
125 struct super_block_record
*record
;
127 record
= malloc(sizeof(struct super_block_record
));
131 record
->device_name
= strdup(fname
);
132 if (!record
->device_name
) {
136 memcpy(&record
->sb
, sb
, sizeof(*sb
));
137 record
->bytenr
= bytenr
;
138 list_add_tail(&record
->list
, head
);
144 read_dev_supers(char *filename
, struct btrfs_recover_superblock
*recover
)
147 u8 buf
[BTRFS_SUPER_INFO_SIZE
];
149 /* just ignore errno that were set in btrfs_scan_fs_devices() */
152 struct btrfs_super_block
*sb
= (struct btrfs_super_block
*)buf
;
154 fd
= open(filename
, O_RDONLY
, 0666);
158 for (i
= 0; i
< BTRFS_SUPER_MIRROR_MAX
; i
++) {
159 bytenr
= btrfs_sb_offset(i
);
160 ret
= pread64(fd
, buf
, sizeof(buf
), bytenr
);
161 if (ret
< sizeof(buf
)) {
165 ret
= check_super(bytenr
, sb
);
167 ret
= add_superblock_record(sb
, filename
, bytenr
,
168 &recover
->good_supers
);
171 max_gen
= btrfs_super_generation(sb
);
172 if (max_gen
> recover
->max_generation
)
173 recover
->max_generation
= max_gen
;
175 ret
= add_superblock_record(sb
, filename
, bytenr
,
176 &recover
->bad_supers
);
186 static int read_fs_supers(struct btrfs_recover_superblock
*recover
)
188 struct super_block_record
*record
;
189 struct super_block_record
*next_record
;
190 struct btrfs_device
*dev
;
194 list_for_each_entry(dev
, &recover
->fs_devices
->devices
,
196 ret
= read_dev_supers(dev
->name
, recover
);
200 list_for_each_entry_safe(record
, next_record
,
201 &recover
->good_supers
, list
) {
202 gen
= btrfs_super_generation(&record
->sb
);
203 if (gen
< recover
->max_generation
)
204 list_move_tail(&record
->list
, &recover
->bad_supers
);
210 static struct super_block_record
*recover_get_good_super(
211 struct btrfs_recover_superblock
*recover
)
213 struct super_block_record
*record
;
214 record
= list_entry(recover
->good_supers
.next
,
215 struct super_block_record
, list
);
219 static void print_all_devices(struct list_head
*devices
)
221 struct btrfs_device
*dev
;
223 printf("All Devices:\n");
224 list_for_each_entry(dev
, devices
, dev_list
) {
226 printf("Device: id = %llu, name = %s\n",
227 dev
->devid
, dev
->name
);
232 static void print_super_info(struct super_block_record
*record
)
234 printf("\t\tdevice name = %s\n", record
->device_name
);
235 printf("\t\tsuperblock bytenr = %llu\n", record
->bytenr
);
238 static void print_all_supers(struct btrfs_recover_superblock
*recover
)
240 struct super_block_record
*record
;
242 printf("\t[All good supers]:\n");
243 list_for_each_entry(record
, &recover
->good_supers
, list
) {
244 print_super_info(record
);
248 printf("\t[All bad supers]:\n");
249 list_for_each_entry(record
, &recover
->bad_supers
, list
) {
250 print_super_info(record
);
256 static void recover_err_str(int ret
)
260 printf("All supers are valid, no need to recover\n");
263 printf("Usage or syntax errors\n");
266 printf("Recovered bad superblocks successful\n");
269 printf("Failed to recover bad superblocks\n");
272 printf("Aborted to recover bad superblocks\n");
275 printf("Unknown recover result\n");
280 int btrfs_recover_superblocks(const char *dname
,
281 int verbose
, int yes
)
284 struct btrfs_recover_superblock recover
;
285 struct super_block_record
*record
;
286 struct btrfs_root
*root
= NULL
;
288 fd
= open(dname
, O_RDONLY
);
290 fprintf(stderr
, "open %s error\n", dname
);
293 init_recover_superblock(&recover
);
295 ret
= btrfs_scan_fs_devices(fd
, dname
, &recover
.fs_devices
, 0, 0);
303 print_all_devices(&recover
.fs_devices
->devices
);
305 ret
= read_fs_supers(&recover
);
311 printf("Before Recovering:\n");
312 print_all_supers(&recover
);
315 if (list_empty(&recover
.bad_supers
))
319 ret
= ask_user("Make sure this is a btrfs disk otherwise the tool will destroy other fs, Are you sure?");
325 record
= recover_get_good_super(&recover
);
326 root
= open_ctree(record
->device_name
, record
->bytenr
,
327 OPEN_CTREE_RECOVER_SUPER
| OPEN_CTREE_WRITES
);
332 /* reset super_bytenr in order that we will rewite all supers */
333 root
->fs_info
->super_bytenr
= BTRFS_SUPER_INFO_OFFSET
;
334 ret
= write_all_supers(root
);
342 recover_err_str(ret
);
343 free_recover_superblock(&recover
);