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.18 2008/05/18 01:48:50 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
);
44 static void hammer_recover_debug_dump(int w
, char *buf
, int bytes
);
46 static int hammer_recover_undo(hammer_mount_t hmp
, hammer_fifo_undo_t undo
,
50 * Recover a filesystem on mount
52 * NOTE: No information from the root volume has been cached in the
53 * hammer_mount structure yet, so we need to access the root volume's
57 hammer_recover(hammer_mount_t hmp
, hammer_volume_t root_volume
)
59 hammer_blockmap_t rootmap
;
60 hammer_buffer_t buffer
;
61 hammer_off_t scan_offset
;
63 hammer_fifo_tail_t tail
;
64 hammer_fifo_undo_t undo
;
68 * Examine the UNDO FIFO. If it is empty the filesystem is clean
69 * and no action need be taken.
71 * NOTE: hmp->blockmap has not been initialized yet so use the
72 * root volume's ondisk buffer directly.
74 rootmap
= &root_volume
->ondisk
->vol0_blockmap
[HAMMER_ZONE_UNDO_INDEX
];
75 hmp
->flusher_undo_start
= rootmap
->next_offset
;
77 if (rootmap
->first_offset
== rootmap
->next_offset
)
80 if (rootmap
->next_offset
>= rootmap
->first_offset
) {
81 bytes
= rootmap
->next_offset
- rootmap
->first_offset
;
83 bytes
= rootmap
->alloc_offset
- rootmap
->first_offset
+
84 (rootmap
->next_offset
& HAMMER_OFF_LONG_MASK
);
86 kprintf("HAMMER(%s) Start Recovery %016llx - %016llx "
87 "(%lld bytes of UNDO)\n",
88 root_volume
->ondisk
->vol_name
,
89 rootmap
->first_offset
, rootmap
->next_offset
,
91 if (bytes
> (rootmap
->alloc_offset
& HAMMER_OFF_LONG_MASK
)) {
92 kprintf("Undo size is absurd, unable to mount\n");
97 * Scan the UNDOs backwards.
99 scan_offset
= rootmap
->next_offset
;
101 if (scan_offset
> rootmap
->alloc_offset
) {
102 kprintf("HAMMER(%s) UNDO record at %016llx FIFO overflow\n",
103 root_volume
->ondisk
->vol_name
,
109 while ((int64_t)bytes
> 0) {
110 if (hammer_debug_general
& 0x0080)
111 kprintf("scan_offset %016llx\n", scan_offset
);
112 if (scan_offset
== HAMMER_ZONE_ENCODE(HAMMER_ZONE_UNDO_INDEX
, 0)) {
113 scan_offset
= rootmap
->alloc_offset
;
116 if (scan_offset
- sizeof(*tail
) <
117 HAMMER_ZONE_ENCODE(HAMMER_ZONE_UNDO_INDEX
, 0)) {
118 kprintf("HAMMER(%s) UNDO record at %016llx FIFO "
120 root_volume
->ondisk
->vol_name
,
125 tail
= hammer_bread(hmp
, scan_offset
- sizeof(*tail
),
128 kprintf("HAMMER(%s) Unable to read UNDO TAIL "
130 root_volume
->ondisk
->vol_name
,
131 scan_offset
- sizeof(*tail
));
135 if (hammer_check_tail_signature(tail
, scan_offset
) != 0) {
136 kprintf("HAMMER(%s) Illegal UNDO TAIL signature "
138 root_volume
->ondisk
->vol_name
,
139 scan_offset
- sizeof(*tail
));
143 undo
= (void *)((char *)tail
+ sizeof(*tail
) - tail
->tail_size
);
145 error
= hammer_recover_undo(hmp
, undo
,
147 (int)((char *)undo
- (char *)buffer
->ondisk
));
149 kprintf("HAMMER(%s) UNDO record at %016llx failed\n",
150 root_volume
->ondisk
->vol_name
,
151 scan_offset
- tail
->tail_size
);
154 scan_offset
-= tail
->tail_size
;
155 bytes
-= tail
->tail_size
;
159 * Reload flusher_undo_start to kick off the UNDO sequencing.
161 hmp
->flusher_undo_start
= rootmap
->next_offset
;
163 hammer_rel_buffer(buffer
, 0);
168 hammer_check_tail_signature(hammer_fifo_tail_t tail
, hammer_off_t end_off
)
172 max_bytes
= ((end_off
- sizeof(*tail
)) & HAMMER_BUFMASK
);
173 max_bytes
+= sizeof(*tail
);
176 * tail overlaps buffer boundary
178 if (((end_off
- sizeof(*tail
)) ^ (end_off
- 1)) & ~HAMMER_BUFMASK64
) {
183 * signature check, the tail signature is allowed to be the head
184 * signature only for 8-byte PADs.
186 switch(tail
->tail_signature
) {
187 case HAMMER_TAIL_SIGNATURE
:
189 case HAMMER_HEAD_SIGNATURE
:
190 if (tail
->tail_type
!= HAMMER_HEAD_TYPE_PAD
||
191 tail
->tail_size
!= sizeof(*tail
)) {
198 * The undo structure must not overlap a buffer boundary.
200 if (tail
->tail_size
< 0 || tail
->tail_size
> max_bytes
) {
207 hammer_recover_undo(hammer_mount_t hmp
, hammer_fifo_undo_t undo
, int bytes
)
209 hammer_fifo_tail_t tail
;
210 hammer_volume_t volume
;
211 hammer_buffer_t buffer
;
212 hammer_off_t buf_offset
;
221 * Basic sanity checks
223 if (bytes
< HAMMER_HEAD_ALIGN
) {
224 kprintf("HAMMER: Undo alignment error (%d)\n", bytes
);
227 if (undo
->head
.hdr_signature
!= HAMMER_HEAD_SIGNATURE
) {
228 kprintf("HAMMER: Bad head signature %04x\n",
229 undo
->head
.hdr_signature
);
232 if (undo
->head
.hdr_size
< HAMMER_HEAD_ALIGN
||
233 undo
->head
.hdr_size
> bytes
) {
234 kprintf("HAMMER: Bad size %d\n", bytes
);
239 * Skip PAD records. Note that PAD records also do not require
240 * a tail and may have a truncated structure.
242 if (undo
->head
.hdr_type
== HAMMER_HEAD_TYPE_PAD
)
248 crc
= crc32(undo
, HAMMER_FIFO_HEAD_CRCOFF
) ^
249 crc32(&undo
->head
+ 1, undo
->head
.hdr_size
- sizeof(undo
->head
));
250 if (undo
->head
.hdr_crc
!= crc
) {
251 kprintf("HAMMER: Undo record CRC failed %08x %08x\n",
252 undo
->head
.hdr_crc
, crc
);
260 bytes
= undo
->head
.hdr_size
;
261 tail
= (void *)((char *)undo
+ bytes
- sizeof(*tail
));
262 if (tail
->tail_size
!= undo
->head
.hdr_size
) {
263 kprintf("HAMMER: Bad tail size %d\n", tail
->tail_size
);
266 if (tail
->tail_type
!= undo
->head
.hdr_type
) {
267 kprintf("HAMMER: Bad tail type %d\n", tail
->tail_type
);
272 * Only process UNDO records
274 if (undo
->head
.hdr_type
!= HAMMER_HEAD_TYPE_UNDO
)
278 * Validate the UNDO record.
280 max_bytes
= undo
->head
.hdr_size
- sizeof(*undo
) - sizeof(*tail
);
281 if (undo
->undo_data_bytes
< 0 || undo
->undo_data_bytes
> max_bytes
) {
282 kprintf("HAMMER: Corrupt UNDO record, undo_data_bytes %d/%d\n",
283 undo
->undo_data_bytes
, max_bytes
);
288 * The undo offset may only be a zone-1 or zone-2 offset.
290 * Currently we only support a zone-1 offset representing the
293 zone
= HAMMER_ZONE_DECODE(undo
->undo_offset
);
294 offset
= undo
->undo_offset
& HAMMER_BUFMASK
;
296 if (offset
+ undo
->undo_data_bytes
> HAMMER_BUFSIZE
) {
297 kprintf("HAMMER: Corrupt UNDO record, bad offset\n");
302 case HAMMER_ZONE_RAW_VOLUME_INDEX
:
303 vol_no
= HAMMER_VOL_DECODE(undo
->undo_offset
);
304 volume
= hammer_get_volume(hmp
, vol_no
, &error
);
305 if (volume
== NULL
) {
306 kprintf("HAMMER: UNDO record, "
307 "cannot access volume %d\n", vol_no
);
310 hammer_modify_volume(NULL
, volume
, NULL
, 0);
311 hammer_recover_copy_undo(undo
->undo_offset
,
313 (char *)volume
->ondisk
+ offset
,
314 undo
->undo_data_bytes
);
315 hammer_modify_volume_done(volume
);
316 hammer_io_flush(&volume
->io
);
317 hammer_rel_volume(volume
, 0);
319 case HAMMER_ZONE_RAW_BUFFER_INDEX
:
320 buf_offset
= undo
->undo_offset
& ~HAMMER_BUFMASK64
;
321 buffer
= hammer_get_buffer(hmp
, buf_offset
, 0, &error
);
322 if (buffer
== NULL
) {
323 kprintf("HAMMER: UNDO record, "
324 "cannot access buffer %016llx\n",
328 hammer_modify_buffer(NULL
, buffer
, NULL
, 0);
329 hammer_recover_copy_undo(undo
->undo_offset
,
331 (char *)buffer
->ondisk
+ offset
,
332 undo
->undo_data_bytes
);
333 hammer_modify_buffer_done(buffer
);
334 hammer_io_flush(&buffer
->io
);
335 hammer_rel_buffer(buffer
, 0);
338 kprintf("HAMMER: Corrupt UNDO record\n");
345 hammer_recover_copy_undo(hammer_off_t undo_offset
,
346 char *src
, char *dst
, int bytes
)
349 if (hammer_debug_general
& 0x0080)
350 kprintf("NDO %016llx: %d\n", undo_offset
, bytes
);
352 kprintf("UNDO %016llx:", undo_offset
);
353 hammer_recover_debug_dump(22, dst
, bytes
);
354 kprintf("%22s", "to:");
355 hammer_recover_debug_dump(22, src
, bytes
);
357 bcopy(src
, dst
, bytes
);
363 hammer_recover_debug_dump(int w
, char *buf
, int bytes
)
367 for (i
= 0; i
< bytes
; ++i
) {
368 if (i
&& (i
& 15) == 0)
369 kprintf("\n%*.*s", w
, w
, "");
370 kprintf(" %02x", (unsigned char)buf
[i
]);