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 add_superblock_record(struct btrfs_super_block
*sb
, char *fname
,
92 u64 bytenr
, struct list_head
*head
)
94 struct super_block_record
*record
;
96 record
= malloc(sizeof(struct super_block_record
));
100 record
->device_name
= strdup(fname
);
101 if (!record
->device_name
) {
105 memcpy(&record
->sb
, sb
, sizeof(*sb
));
106 record
->bytenr
= bytenr
;
107 list_add_tail(&record
->list
, head
);
113 read_dev_supers(char *filename
, struct btrfs_recover_superblock
*recover
)
116 u8 buf
[BTRFS_SUPER_INFO_SIZE
];
118 struct btrfs_super_block
*sb
= (struct btrfs_super_block
*)buf
;
120 /* just ignore errno that were set in btrfs_scan_fs_devices() */
123 fd
= open(filename
, O_RDONLY
);
127 for (i
= 0; i
< BTRFS_SUPER_MIRROR_MAX
; i
++) {
128 bytenr
= btrfs_sb_offset(i
);
130 ret
= btrfs_read_dev_super(fd
, sb
, bytenr
, SBREAD_DEFAULT
);
132 ret
= add_superblock_record(sb
, filename
, bytenr
,
133 &recover
->good_supers
);
136 max_gen
= btrfs_super_generation(sb
);
137 if (max_gen
> recover
->max_generation
)
138 recover
->max_generation
= max_gen
;
139 } else if (ret
== -EIO
){
141 * Skip superblock which doesn't exist, only adds
142 * really corrupted superblock
144 ret
= add_superblock_record(sb
, filename
, bytenr
,
145 &recover
->bad_supers
);
156 static int read_fs_supers(struct btrfs_recover_superblock
*recover
)
158 struct super_block_record
*record
;
159 struct super_block_record
*next_record
;
160 struct btrfs_device
*dev
;
164 list_for_each_entry(dev
, &recover
->fs_devices
->devices
,
166 ret
= read_dev_supers(dev
->name
, recover
);
170 list_for_each_entry_safe(record
, next_record
,
171 &recover
->good_supers
, list
) {
172 gen
= btrfs_super_generation(&record
->sb
);
173 if (gen
< recover
->max_generation
)
174 list_move_tail(&record
->list
, &recover
->bad_supers
);
180 static struct super_block_record
*recover_get_good_super(
181 struct btrfs_recover_superblock
*recover
)
183 struct super_block_record
*record
;
184 record
= list_entry(recover
->good_supers
.next
,
185 struct super_block_record
, list
);
189 static void print_all_devices(struct list_head
*devices
)
191 struct btrfs_device
*dev
;
193 printf("All Devices:\n");
194 list_for_each_entry(dev
, devices
, dev_list
) {
196 printf("Device: id = %llu, name = %s\n",
197 dev
->devid
, dev
->name
);
202 static void print_super_info(struct super_block_record
*record
)
204 printf("\t\tdevice name = %s\n", record
->device_name
);
205 printf("\t\tsuperblock bytenr = %llu\n", record
->bytenr
);
208 static void print_all_supers(struct btrfs_recover_superblock
*recover
)
210 struct super_block_record
*record
;
212 printf("\t[All good supers]:\n");
213 list_for_each_entry(record
, &recover
->good_supers
, list
) {
214 print_super_info(record
);
218 printf("\t[All bad supers]:\n");
219 list_for_each_entry(record
, &recover
->bad_supers
, list
) {
220 print_super_info(record
);
226 static void recover_err_str(int ret
)
230 printf("All supers are valid, no need to recover\n");
233 printf("Usage or syntax errors\n");
236 printf("Recovered bad superblocks successful\n");
239 printf("Failed to recover bad superblocks\n");
242 printf("Aborted to recover bad superblocks\n");
245 printf("Unknown recover result\n");
250 int btrfs_recover_superblocks(const char *dname
,
251 int verbose
, int yes
)
254 struct btrfs_recover_superblock recover
;
255 struct super_block_record
*record
;
256 struct btrfs_root
*root
= NULL
;
258 fd
= open(dname
, O_RDONLY
);
260 fprintf(stderr
, "open %s error\n", dname
);
263 init_recover_superblock(&recover
);
265 ret
= btrfs_scan_fs_devices(fd
, dname
, &recover
.fs_devices
, 0,
274 print_all_devices(&recover
.fs_devices
->devices
);
276 ret
= read_fs_supers(&recover
);
282 printf("Before Recovering:\n");
283 print_all_supers(&recover
);
286 if (list_empty(&recover
.bad_supers
))
290 ret
= ask_user("Make sure this is a btrfs disk otherwise the tool will destroy other fs, Are you sure?");
296 record
= recover_get_good_super(&recover
);
297 root
= open_ctree(record
->device_name
, record
->bytenr
,
298 OPEN_CTREE_RECOVER_SUPER
| OPEN_CTREE_WRITES
);
303 /* reset super_bytenr in order that we will rewrite all supers */
304 root
->fs_info
->super_bytenr
= BTRFS_SUPER_INFO_OFFSET
;
305 ret
= write_all_supers(root
->fs_info
);
313 recover_err_str(ret
);
314 free_recover_superblock(&recover
);
315 /* check if we have freed fs_devices in close_ctree() */
317 btrfs_close_devices(recover
.fs_devices
);