2 * Copyright (c) 2008 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * $DragonFly: src/sys/vfs/hammer/hammer_recover.c,v 1.10 2008/04/26 02:54:00 dillon Exp $
39 static int hammer_check_tail_signature(hammer_fifo_tail_t tail
,
40 hammer_off_t end_off
);
41 static void hammer_recover_copy_undo(hammer_off_t undo_offset
,
42 char *src
, char *dst
, int bytes
);
43 static void hammer_recover_debug_dump(int w
, char *buf
, int bytes
);
44 static int hammer_recover_undo(hammer_mount_t hmp
, hammer_fifo_undo_t undo
,
48 * Recover a filesystem on mount
51 hammer_recover(hammer_mount_t hmp
, hammer_volume_t root_volume
)
53 hammer_blockmap_t rootmap
;
54 hammer_buffer_t buffer
;
55 hammer_off_t scan_offset
;
57 hammer_fifo_tail_t tail
;
58 hammer_fifo_undo_t undo
;
62 * Examine the UNDO FIFO. If it is empty the filesystem is clean
63 * and no action need be taken.
65 rootmap
= &root_volume
->ondisk
->vol0_blockmap
[HAMMER_ZONE_UNDO_INDEX
];
66 if (rootmap
->first_offset
== rootmap
->next_offset
)
69 if (rootmap
->next_offset
< rootmap
->first_offset
)
70 bytes
= rootmap
->alloc_offset
- rootmap
->first_offset
+
72 bytes
= (rootmap
->next_offset
- rootmap
->first_offset
);
73 kprintf("HAMMER(%s) Start Recovery (%lld bytes of UNDO)\n",
74 root_volume
->ondisk
->vol_name
, bytes
);
77 * Scan the UNDOs backwards.
79 scan_offset
= rootmap
->next_offset
;
81 if (scan_offset
> rootmap
->alloc_offset
) {
82 kprintf("HAMMER(%s) UNDO record at %016llx FIFO overflow\n",
83 root_volume
->ondisk
->vol_name
,
89 while ((int64_t)bytes
> 0) {
90 kprintf("scan_offset %016llx\n", scan_offset
);
91 if (scan_offset
- sizeof(*tail
) <
92 HAMMER_ZONE_ENCODE(HAMMER_ZONE_UNDO_INDEX
, 0)) {
93 kprintf("HAMMER(%s) UNDO record at %016llx FIFO "
95 root_volume
->ondisk
->vol_name
,
100 if (scan_offset
== HAMMER_ZONE_ENCODE(HAMMER_ZONE_UNDO_INDEX
, 0)) {
101 scan_offset
= rootmap
->alloc_offset
;
104 tail
= hammer_bread(hmp
, scan_offset
- sizeof(*tail
),
107 kprintf("HAMMER(%s) Unable to read UNDO TAIL "
109 root_volume
->ondisk
->vol_name
,
110 scan_offset
- sizeof(*tail
));
114 if (hammer_check_tail_signature(tail
, scan_offset
) != 0) {
115 kprintf("HAMMER(%s) Illegal UNDO TAIL signature "
117 root_volume
->ondisk
->vol_name
,
118 scan_offset
- sizeof(*tail
));
122 undo
= (void *)((char *)tail
+ sizeof(*tail
) - tail
->tail_size
);
124 error
= hammer_recover_undo(hmp
, undo
,
126 (int)((char *)undo
- (char *)buffer
->ondisk
));
128 kprintf("HAMMER(%s) UNDO record at %016llx failed\n",
129 root_volume
->ondisk
->vol_name
,
130 scan_offset
- tail
->tail_size
);
133 scan_offset
-= tail
->tail_size
;
134 bytes
-= tail
->tail_size
;
138 hammer_rel_buffer(buffer
, 0);
143 hammer_check_tail_signature(hammer_fifo_tail_t tail
, hammer_off_t end_off
)
147 max_bytes
= ((end_off
- sizeof(*tail
)) & HAMMER_BUFMASK
);
148 max_bytes
+= sizeof(*tail
);
151 * tail overlaps buffer boundary
153 if (((end_off
- sizeof(*tail
)) ^ (end_off
- 1)) & ~HAMMER_BUFMASK64
) {
158 * signature check, the tail signature is allowed to be the head
159 * signature only for 8-byte PADs.
161 switch(tail
->tail_signature
) {
162 case HAMMER_TAIL_SIGNATURE
:
164 case HAMMER_HEAD_SIGNATURE
:
165 if (tail
->tail_type
!= HAMMER_HEAD_TYPE_PAD
||
166 tail
->tail_size
!= sizeof(*tail
)) {
173 * The undo structure must not overlap a buffer boundary.
175 if (tail
->tail_size
< 0 || tail
->tail_size
> max_bytes
) {
182 hammer_recover_undo(hammer_mount_t hmp
, hammer_fifo_undo_t undo
, int bytes
)
184 hammer_fifo_tail_t tail
;
185 hammer_volume_t volume
;
186 hammer_buffer_t buffer
;
194 * Basic sanity checks
196 if (bytes
< HAMMER_HEAD_ALIGN
) {
197 kprintf("HAMMER: Undo alignment error (%d)\n", bytes
);
200 if (undo
->head
.hdr_signature
!= HAMMER_HEAD_SIGNATURE
) {
201 kprintf("HAMMER: Bad head signature %04x\n",
202 undo
->head
.hdr_signature
);
205 if (undo
->head
.hdr_size
< HAMMER_HEAD_ALIGN
||
206 undo
->head
.hdr_size
> bytes
) {
207 kprintf("HAMMER: Bad size %d\n", bytes
);
212 * Skip PAD records. Note that PAD records also do not require
215 if (undo
->head
.hdr_type
== HAMMER_HEAD_TYPE_PAD
)
221 bytes
= undo
->head
.hdr_size
;
222 tail
= (void *)((char *)undo
+ bytes
- sizeof(*tail
));
223 if (tail
->tail_size
!= undo
->head
.hdr_size
) {
224 kprintf("HAMMER: Bad tail size %d\n", tail
->tail_size
);
227 if (tail
->tail_type
!= undo
->head
.hdr_type
) {
228 kprintf("HAMMER: Bad tail type %d\n", tail
->tail_type
);
233 * Only process UNDO records
235 if (undo
->head
.hdr_type
!= HAMMER_HEAD_TYPE_UNDO
)
239 * Validate the UNDO record.
241 max_bytes
= undo
->head
.hdr_size
- sizeof(*undo
) - sizeof(*tail
);
242 if (undo
->undo_data_bytes
< 0 || undo
->undo_data_bytes
> max_bytes
) {
243 kprintf("HAMMER: Corrupt UNDO record, undo_data_bytes %d/%d\n",
244 undo
->undo_data_bytes
, max_bytes
);
249 * The undo offset may only be a zone-1 or zone-2 offset.
251 * Currently we only support a zone-1 offset representing the
254 zone
= HAMMER_ZONE_DECODE(undo
->undo_offset
);
255 offset
= undo
->undo_offset
& HAMMER_BUFMASK
;
257 if (offset
+ undo
->undo_data_bytes
> HAMMER_BUFSIZE
) {
258 kprintf("HAMMER: Corrupt UNDO record, bad offset\n");
263 case HAMMER_ZONE_RAW_VOLUME_INDEX
:
264 vol_no
= HAMMER_VOL_DECODE(undo
->undo_offset
);
265 volume
= hammer_get_volume(hmp
, vol_no
, &error
);
266 if (volume
== NULL
) {
267 kprintf("HAMMER: UNDO record, "
268 "cannot access volume %d\n", vol_no
);
271 hammer_modify_volume(NULL
, volume
, NULL
, 0);
272 hammer_recover_copy_undo(undo
->undo_offset
,
274 (char *)volume
->ondisk
+ offset
,
275 undo
->undo_data_bytes
);
276 hammer_modify_volume_done(volume
);
277 hammer_io_flush(&volume
->io
);
278 hammer_rel_volume(volume
, 0);
280 case HAMMER_ZONE_RAW_BUFFER_INDEX
:
281 buffer
= hammer_get_buffer(hmp
, undo
->undo_offset
, 0, &error
);
282 if (buffer
== NULL
) {
283 kprintf("HAMMER: UNDO record, "
284 "cannot access buffer %016llx\n",
288 hammer_modify_buffer(NULL
, buffer
, NULL
, 0);
289 hammer_recover_copy_undo(undo
->undo_offset
,
291 (char *)buffer
->ondisk
+ offset
,
292 undo
->undo_data_bytes
);
293 hammer_modify_buffer_done(buffer
);
294 hammer_io_flush(&buffer
->io
);
295 hammer_rel_buffer(buffer
, 0);
298 kprintf("HAMMER: Corrupt UNDO record\n");
305 hammer_recover_copy_undo(hammer_off_t undo_offset
,
306 char *src
, char *dst
, int bytes
)
308 kprintf("UNDO %016llx:", undo_offset
);
309 hammer_recover_debug_dump(22, dst
, bytes
);
310 kprintf("%22s", "to:");
311 hammer_recover_debug_dump(22, src
, bytes
);
312 bcopy(src
, dst
, bytes
);
316 hammer_recover_debug_dump(int w
, char *buf
, int bytes
)
320 for (i
= 0; i
< bytes
; ++i
) {
321 if (i
&& (i
& 15) == 0)
322 kprintf("\n%*.*s", w
, w
, "");
323 kprintf(" %02x", (unsigned char)buf
[i
]);