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.
23 #include <uuid/uuid.h>
29 #include "kerncompat.h"
38 struct btrfs_recover_superblock
{
39 struct btrfs_fs_devices
*fs_devices
;
41 struct list_head good_supers
;
42 struct list_head bad_supers
;
47 struct super_block_record
{
48 struct list_head list
;
51 struct btrfs_super_block sb
;
57 void init_recover_superblock(struct btrfs_recover_superblock
*recover
)
59 INIT_LIST_HEAD(&recover
->good_supers
);
60 INIT_LIST_HEAD(&recover
->bad_supers
);
62 recover
->fs_devices
= NULL
;
63 recover
->max_generation
= 0;
67 void free_recover_superblock(struct btrfs_recover_superblock
*recover
)
69 struct super_block_record
*record
;
71 if (!recover
->fs_devices
)
74 while (!list_empty(&recover
->good_supers
)) {
75 record
= list_entry(recover
->good_supers
.next
,
76 struct super_block_record
, list
);
77 list_del_init(&record
->list
);
78 free(record
->device_name
);
82 while (!list_empty(&recover
->bad_supers
)) {
83 record
= list_entry(recover
->bad_supers
.next
,
84 struct super_block_record
, list
);
85 list_del_init(&record
->list
);
86 free(record
->device_name
);
91 static int check_super(u64 bytenr
, struct btrfs_super_block
*sb
)
93 int csum_size
= btrfs_super_csum_size(sb
);
94 char result
[csum_size
];
97 if (btrfs_super_bytenr(sb
) != bytenr
)
99 if (sb
->magic
!= cpu_to_le64(BTRFS_MAGIC
))
102 crc
= btrfs_csum_data(NULL
, (char *)sb
+ BTRFS_CSUM_SIZE
,
103 crc
, BTRFS_SUPER_INFO_SIZE
- BTRFS_CSUM_SIZE
);
104 btrfs_csum_final(crc
, result
);
106 return !memcmp(sb
, &result
, csum_size
);
109 static int add_superblock_record(struct btrfs_super_block
*sb
, char *fname
,
110 u64 bytenr
, struct list_head
*head
)
112 struct super_block_record
*record
;
114 record
= malloc(sizeof(struct super_block_record
));
118 record
->device_name
= strdup(fname
);
119 if (!record
->device_name
) {
123 memcpy(&record
->sb
, sb
, sizeof(*sb
));
124 record
->bytenr
= bytenr
;
125 list_add_tail(&record
->list
, head
);
131 read_dev_supers(char *filename
, struct btrfs_recover_superblock
*recover
)
134 u8 buf
[BTRFS_SUPER_INFO_SIZE
];
136 /* just ignore errno that were set in btrfs_scan_fs_devices() */
139 struct btrfs_super_block
*sb
= (struct btrfs_super_block
*)buf
;
141 fd
= open(filename
, O_RDONLY
, 0666);
145 for (i
= 0; i
< BTRFS_SUPER_MIRROR_MAX
; i
++) {
146 bytenr
= btrfs_sb_offset(i
);
147 ret
= pread64(fd
, buf
, sizeof(buf
), bytenr
);
148 if (ret
< sizeof(buf
)) {
152 ret
= check_super(bytenr
, sb
);
154 ret
= add_superblock_record(sb
, filename
, bytenr
,
155 &recover
->good_supers
);
158 max_gen
= btrfs_super_generation(sb
);
159 if (max_gen
> recover
->max_generation
)
160 recover
->max_generation
= max_gen
;
162 ret
= add_superblock_record(sb
, filename
, bytenr
,
163 &recover
->bad_supers
);
173 static int read_fs_supers(struct btrfs_recover_superblock
*recover
)
175 struct super_block_record
*record
;
176 struct super_block_record
*next_record
;
177 struct btrfs_device
*dev
;
181 list_for_each_entry(dev
, &recover
->fs_devices
->devices
,
183 ret
= read_dev_supers(dev
->name
, recover
);
187 list_for_each_entry_safe(record
, next_record
,
188 &recover
->good_supers
, list
) {
189 gen
= btrfs_super_generation(&record
->sb
);
190 if (gen
< recover
->max_generation
)
191 list_move_tail(&record
->list
, &recover
->bad_supers
);
197 static struct super_block_record
*recover_get_good_super(
198 struct btrfs_recover_superblock
*recover
)
200 struct super_block_record
*record
;
201 record
= list_entry(recover
->good_supers
.next
,
202 struct super_block_record
, list
);
206 static void print_all_devices(struct list_head
*devices
)
208 struct btrfs_device
*dev
;
210 printf("All Devices:\n");
211 list_for_each_entry(dev
, devices
, dev_list
) {
213 printf("Device: id = %llu, name = %s\n",
214 dev
->devid
, dev
->name
);
219 static void print_super_info(struct super_block_record
*record
)
221 printf("\t\tdevice name = %s\n", record
->device_name
);
222 printf("\t\tsuperblock bytenr = %llu\n", record
->bytenr
);
225 static void print_all_supers(struct btrfs_recover_superblock
*recover
)
227 struct super_block_record
*record
;
229 printf("\t[All good supers]:\n");
230 list_for_each_entry(record
, &recover
->good_supers
, list
) {
231 print_super_info(record
);
235 printf("\t[All bad supers]:\n");
236 list_for_each_entry(record
, &recover
->bad_supers
, list
) {
237 print_super_info(record
);
243 static void recover_err_str(int ret
)
247 printf("All supers are valid, no need to recover\n");
250 printf("Usage or syntax errors\n");
253 printf("Recovered bad superblocks successful\n");
256 printf("Failed to recover bad superblocks\n");
259 printf("Aborted to recover bad superblocks\n");
262 printf("Unknown recover result\n");
267 int btrfs_recover_superblocks(const char *dname
,
268 int verbose
, int yes
)
271 struct btrfs_recover_superblock recover
;
272 struct super_block_record
*record
;
273 struct btrfs_root
*root
= NULL
;
275 fd
= open(dname
, O_RDONLY
);
277 fprintf(stderr
, "open %s error\n", dname
);
280 init_recover_superblock(&recover
);
282 ret
= btrfs_scan_fs_devices(fd
, dname
, &recover
.fs_devices
, 0, 1, 0);
290 print_all_devices(&recover
.fs_devices
->devices
);
292 ret
= read_fs_supers(&recover
);
298 printf("Before Recovering:\n");
299 print_all_supers(&recover
);
302 if (list_empty(&recover
.bad_supers
))
306 ret
= ask_user("Make sure this is a btrfs disk otherwise the tool will destroy other fs, Are you sure?");
312 record
= recover_get_good_super(&recover
);
313 root
= open_ctree(record
->device_name
, record
->bytenr
,
314 OPEN_CTREE_RECOVER_SUPER
| OPEN_CTREE_WRITES
);
319 /* reset super_bytenr in order that we will rewrite all supers */
320 root
->fs_info
->super_bytenr
= BTRFS_SUPER_INFO_OFFSET
;
321 ret
= write_all_supers(root
);
329 recover_err_str(ret
);
330 free_recover_superblock(&recover
);
331 /* check if we have freed fs_devices in close_ctree() */
333 btrfs_close_devices(recover
.fs_devices
);