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 super_block_record
*record
;
74 if (!recover
->fs_devices
)
77 while (!list_empty(&recover
->good_supers
)) {
78 record
= list_entry(recover
->good_supers
.next
,
79 struct super_block_record
, list
);
80 list_del_init(&record
->list
);
81 free(record
->device_name
);
85 while (!list_empty(&recover
->bad_supers
)) {
86 record
= list_entry(recover
->bad_supers
.next
,
87 struct super_block_record
, list
);
88 list_del_init(&record
->list
);
89 free(record
->device_name
);
94 static int check_super(u64 bytenr
, struct btrfs_super_block
*sb
)
96 int csum_size
= btrfs_super_csum_size(sb
);
97 char result
[csum_size
];
100 if (btrfs_super_bytenr(sb
) != bytenr
)
102 if (sb
->magic
!= cpu_to_le64(BTRFS_MAGIC
))
105 crc
= btrfs_csum_data(NULL
, (char *)sb
+ BTRFS_CSUM_SIZE
,
106 crc
, BTRFS_SUPER_INFO_SIZE
- BTRFS_CSUM_SIZE
);
107 btrfs_csum_final(crc
, result
);
109 return !memcmp(sb
, &result
, csum_size
);
112 static int add_superblock_record(struct btrfs_super_block
*sb
, char *fname
,
113 u64 bytenr
, struct list_head
*head
)
115 struct super_block_record
*record
;
117 record
= malloc(sizeof(struct super_block_record
));
121 record
->device_name
= strdup(fname
);
122 if (!record
->device_name
) {
126 memcpy(&record
->sb
, sb
, sizeof(*sb
));
127 record
->bytenr
= bytenr
;
128 list_add_tail(&record
->list
, head
);
134 read_dev_supers(char *filename
, struct btrfs_recover_superblock
*recover
)
137 u8 buf
[BTRFS_SUPER_INFO_SIZE
];
139 /* just ignore errno that were set in btrfs_scan_fs_devices() */
142 struct btrfs_super_block
*sb
= (struct btrfs_super_block
*)buf
;
144 fd
= open(filename
, O_RDONLY
, 0666);
148 for (i
= 0; i
< BTRFS_SUPER_MIRROR_MAX
; i
++) {
149 bytenr
= btrfs_sb_offset(i
);
150 ret
= pread64(fd
, buf
, sizeof(buf
), bytenr
);
151 if (ret
< sizeof(buf
)) {
155 ret
= check_super(bytenr
, sb
);
157 ret
= add_superblock_record(sb
, filename
, bytenr
,
158 &recover
->good_supers
);
161 max_gen
= btrfs_super_generation(sb
);
162 if (max_gen
> recover
->max_generation
)
163 recover
->max_generation
= max_gen
;
165 ret
= add_superblock_record(sb
, filename
, bytenr
,
166 &recover
->bad_supers
);
176 static int read_fs_supers(struct btrfs_recover_superblock
*recover
)
178 struct super_block_record
*record
;
179 struct super_block_record
*next_record
;
180 struct btrfs_device
*dev
;
184 list_for_each_entry(dev
, &recover
->fs_devices
->devices
,
186 ret
= read_dev_supers(dev
->name
, recover
);
190 list_for_each_entry_safe(record
, next_record
,
191 &recover
->good_supers
, list
) {
192 gen
= btrfs_super_generation(&record
->sb
);
193 if (gen
< recover
->max_generation
)
194 list_move_tail(&record
->list
, &recover
->bad_supers
);
200 static struct super_block_record
*recover_get_good_super(
201 struct btrfs_recover_superblock
*recover
)
203 struct super_block_record
*record
;
204 record
= list_entry(recover
->good_supers
.next
,
205 struct super_block_record
, list
);
209 static void print_all_devices(struct list_head
*devices
)
211 struct btrfs_device
*dev
;
213 printf("All Devices:\n");
214 list_for_each_entry(dev
, devices
, dev_list
) {
216 printf("Device: id = %llu, name = %s\n",
217 dev
->devid
, dev
->name
);
222 static void print_super_info(struct super_block_record
*record
)
224 printf("\t\tdevice name = %s\n", record
->device_name
);
225 printf("\t\tsuperblock bytenr = %llu\n", record
->bytenr
);
228 static void print_all_supers(struct btrfs_recover_superblock
*recover
)
230 struct super_block_record
*record
;
232 printf("\t[All good supers]:\n");
233 list_for_each_entry(record
, &recover
->good_supers
, list
) {
234 print_super_info(record
);
238 printf("\t[All bad supers]:\n");
239 list_for_each_entry(record
, &recover
->bad_supers
, list
) {
240 print_super_info(record
);
246 static void recover_err_str(int ret
)
250 printf("All supers are valid, no need to recover\n");
253 printf("Usage or syntax errors\n");
256 printf("Recovered bad superblocks successful\n");
259 printf("Failed to recover bad superblocks\n");
262 printf("Aborted to recover bad superblocks\n");
265 printf("Unknown recover result\n");
270 int btrfs_recover_superblocks(const char *dname
,
271 int verbose
, int yes
)
274 struct btrfs_recover_superblock recover
;
275 struct super_block_record
*record
;
276 struct btrfs_root
*root
= NULL
;
278 fd
= open(dname
, O_RDONLY
);
280 fprintf(stderr
, "open %s error\n", dname
);
283 init_recover_superblock(&recover
);
285 ret
= btrfs_scan_fs_devices(fd
, dname
, &recover
.fs_devices
, 0, 1);
293 print_all_devices(&recover
.fs_devices
->devices
);
295 ret
= read_fs_supers(&recover
);
301 printf("Before Recovering:\n");
302 print_all_supers(&recover
);
305 if (list_empty(&recover
.bad_supers
))
309 ret
= ask_user("Make sure this is a btrfs disk otherwise the tool will destroy other fs, Are you sure?");
315 record
= recover_get_good_super(&recover
);
316 root
= open_ctree(record
->device_name
, record
->bytenr
,
317 OPEN_CTREE_RECOVER_SUPER
| OPEN_CTREE_WRITES
);
322 /* reset super_bytenr in order that we will rewite all supers */
323 root
->fs_info
->super_bytenr
= BTRFS_SUPER_INFO_OFFSET
;
324 ret
= write_all_supers(root
);
332 recover_err_str(ret
);
333 free_recover_superblock(&recover
);
334 /* check if we have freed fs_deivces in close_ctree() */
336 btrfs_close_devices(recover
.fs_devices
);