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.29 2008/07/26 05:36:21 dillon Exp $
39 static int hammer_check_tail_signature(hammer_fifo_tail_t tail
,
40 hammer_off_t end_off
);
41 static int hammer_check_head_signature(hammer_fifo_head_t head
,
42 hammer_off_t beg_off
);
43 static void hammer_recover_copy_undo(hammer_off_t undo_offset
,
44 char *src
, char *dst
, int bytes
);
45 static hammer_fifo_any_t
hammer_recover_scan_fwd(hammer_mount_t hmp
,
46 hammer_volume_t root_volume
,
47 hammer_off_t
*scan_offsetp
,
48 int *errorp
, struct hammer_buffer
**bufferp
);
49 static hammer_fifo_any_t
hammer_recover_scan_rev(hammer_mount_t hmp
,
50 hammer_volume_t root_volume
,
51 hammer_off_t
*scan_offsetp
,
52 int *errorp
, struct hammer_buffer
**bufferp
);
54 static void hammer_recover_debug_dump(int w
, char *buf
, int bytes
);
56 static int hammer_recover_undo(hammer_mount_t hmp
, hammer_volume_t root_volume
,
57 hammer_fifo_undo_t undo
);
60 * Recover filesystem meta-data on mount. This procedure figures out the
61 * UNDO FIFO range and runs the UNDOs backwards. The FIFO pointers are not
62 * resynchronized by this procedure.
64 * This procedure is run near the beginning of the mount sequence, before
65 * any B-Tree or high-level accesses are enabled, and is responsible for
66 * restoring the meta-data to a consistent state. High level HAMMER data
67 * structures (such as the B-Tree) cannot be accessed here.
69 * NOTE: No information from the root volume has been cached in the
70 * hammer_mount structure yet, so we need to access the root volume's
76 hammer_recover_stage1(hammer_mount_t hmp
, hammer_volume_t root_volume
)
78 hammer_blockmap_t rootmap
;
79 hammer_buffer_t buffer
;
80 hammer_off_t scan_offset
;
81 hammer_off_t scan_offset_save
;
83 hammer_fifo_any_t head
;
84 hammer_off_t first_offset
;
85 hammer_off_t last_offset
;
90 * Examine the UNDO FIFO indices in the volume header.
92 rootmap
= &root_volume
->ondisk
->vol0_blockmap
[HAMMER_ZONE_UNDO_INDEX
];
93 first_offset
= rootmap
->first_offset
;
94 last_offset
= rootmap
->next_offset
;
98 if (first_offset
> rootmap
->alloc_offset
||
99 last_offset
> rootmap
->alloc_offset
) {
100 kprintf("HAMMER(%s) Illegal UNDO FIFO index range "
101 "%016jx, %016jx limit %016jx\n",
102 root_volume
->ondisk
->vol_name
,
103 (intmax_t)first_offset
,
104 (intmax_t)last_offset
,
105 (intmax_t)rootmap
->alloc_offset
);
111 * In HAMMER version 4+ filesystems the volume header does NOT
112 * contain definitive UNDO FIFO state. In particular, the
113 * rootmap->next_offset may not be indexed completely to the
114 * end of the active UNDO FIFO.
116 if (hmp
->version
>= HAMMER_VOL_VERSION_FOUR
) {
118 * To find the definitive range we must first scan backwards
119 * from first_offset to locate the first real record and
120 * extract the sequence number from it. This record is not
121 * part of the active undo space.
123 scan_offset
= first_offset
;
127 head
= hammer_recover_scan_rev(hmp
, root_volume
,
132 if (head
->head
.hdr_type
!= HAMMER_HEAD_TYPE_PAD
) {
133 seqno
= head
->head
.hdr_seq
;
138 kprintf("HAMMER(%s) meta-data recovery failure "
139 "during seqno backscan\n",
140 root_volume
->ondisk
->vol_name
);
145 * Scan forwards from first_offset and (seqno+1) looking
146 * for a sequence space discontinuity. This denotes the
147 * end of the active FIFO area.
149 * NOTE: For the case where the FIFO is empty the very first
150 * record we find will be discontinuous.
152 * NOTE: Do not include trailing PADs in the scan range,
153 * and remember the returned scan_offset after a
154 * fwd iteration points to the end of the returned
157 kprintf("HAMMER(%s) meta-data recovery check seqno=%08x\n",
158 root_volume
->ondisk
->vol_name
,
161 scan_offset
= first_offset
;
162 scan_offset_save
= scan_offset
;
165 head
= hammer_recover_scan_fwd(hmp
, root_volume
,
170 if (head
->head
.hdr_type
!= HAMMER_HEAD_TYPE_PAD
) {
171 if (seqno
!= head
->head
.hdr_seq
) {
172 scan_offset
= scan_offset_save
;
175 scan_offset_save
= scan_offset
;
181 * If the forward scan is grossly ahead of last_offset
182 * then something is wrong. last_offset is supposed
185 if (last_offset
>= scan_offset
) {
186 bytes
= last_offset
- scan_offset
;
188 bytes
= rootmap
->alloc_offset
- scan_offset
+
189 (last_offset
& HAMMER_OFF_LONG_MASK
);
192 (rootmap
->alloc_offset
& HAMMER_OFF_LONG_MASK
) *
194 kprintf("HAMMER(%s) meta-data forward scan is "
195 "grossly beyond the last_offset in "
196 "the volume header, this can't be "
198 root_volume
->ondisk
->vol_name
);
206 * Store the seqno. This will be the next seqno we lay down
207 * when generating new UNDOs.
209 hmp
->undo_seqno
= seqno
;
211 kprintf("HAMMER(%s) meta-data recovery failure "
212 "during seqno fwdscan\n",
213 root_volume
->ondisk
->vol_name
);
216 last_offset
= scan_offset
;
217 kprintf("HAMMER(%s) meta-data recovery range %016jx-%016jx "
218 "(invol %016jx) endseqno=%08x\n",
219 root_volume
->ondisk
->vol_name
,
220 (intmax_t)first_offset
,
221 (intmax_t)last_offset
,
222 (intmax_t)rootmap
->next_offset
,
227 * Calculate the size of the active portion of the FIFO. If the
228 * FIFO is empty the filesystem is clean and no further action is
231 if (last_offset
>= first_offset
) {
232 bytes
= last_offset
- first_offset
;
234 bytes
= rootmap
->alloc_offset
- first_offset
+
235 (last_offset
& HAMMER_OFF_LONG_MASK
);
242 kprintf("HAMMER(%s) Start meta-data recovery %016jx - %016jx "
243 "(%jd bytes of UNDO)%s\n",
244 root_volume
->ondisk
->vol_name
,
245 (intmax_t)first_offset
,
246 (intmax_t)last_offset
,
248 (hmp
->ronly
? " (RO)" : "(RW)"));
249 if (bytes
> (rootmap
->alloc_offset
& HAMMER_OFF_LONG_MASK
)) {
250 kprintf("Undo size is absurd, unable to mount\n");
256 * Scan the UNDOs backwards.
258 scan_offset
= last_offset
;
260 while ((int64_t)bytes
> 0) {
261 KKASSERT(scan_offset
!= first_offset
);
262 head
= hammer_recover_scan_rev(hmp
, root_volume
,
263 &scan_offset
, &error
, &buffer
);
266 error
= hammer_recover_undo(hmp
, root_volume
, &head
->undo
);
268 kprintf("HAMMER(%s) UNDO record at %016jx failed\n",
269 root_volume
->ondisk
->vol_name
,
270 (intmax_t)scan_offset
- head
->head
.hdr_size
);
273 bytes
-= head
->head
.hdr_size
;
276 * If too many dirty buffers have built up we have to flush'm
277 * out. As long as we do not flush out the volume header
278 * a crash here should not cause any problems.
280 * buffer must be released so the flush can assert that
281 * all buffers are idle.
283 if (hammer_flusher_meta_limit(hmp
)) {
285 hammer_rel_buffer(buffer
, 0);
288 if (hmp
->ronly
== 0) {
289 hammer_recover_flush_buffers(hmp
, root_volume
,
291 kprintf("HAMMER(%s) Continuing recovery\n",
292 root_volume
->ondisk
->vol_name
);
294 kprintf("HAMMER(%s) Recovery failure: Insufficient buffer cache to hold dirty buffers on read-only mount!\n",
295 root_volume
->ondisk
->vol_name
);
303 hammer_rel_buffer(buffer
, 0);
308 * After completely flushing all the recovered buffers the volume
309 * header will also be flushed.
311 if (root_volume
->io
.recovered
== 0) {
312 hammer_ref_volume(root_volume
);
313 root_volume
->io
.recovered
= 1;
317 * Finish up flushing (or discarding) recovered buffers. FIFO
318 * indices in the volume header are updated to the actual undo
319 * range but will not be collapsed until stage 2.
322 hammer_modify_volume(NULL
, root_volume
, NULL
, 0);
323 rootmap
= &root_volume
->ondisk
->vol0_blockmap
[HAMMER_ZONE_UNDO_INDEX
];
324 rootmap
->first_offset
= first_offset
;
325 rootmap
->next_offset
= last_offset
;
326 hammer_modify_volume_done(root_volume
);
328 hammer_recover_flush_buffers(hmp
, root_volume
, 1);
330 hammer_recover_flush_buffers(hmp
, root_volume
, -1);
332 kprintf("HAMMER(%s) End meta-data recovery\n",
333 root_volume
->ondisk
->vol_name
);
338 * Execute redo operations
340 * This procedure is run at the end of the mount sequence, after the hammer
341 * mount structure has been completely initialized but before the filesystem
342 * goes live. It can access standard cursors, the B-Tree, flush the
343 * filesystem, and so forth.
345 * This code may only be called for read-write mounts or when a mount
346 * switches from read-only to read-write.
348 * The stage1 code will have already calculated the correct FIFO range
349 * and stored it in the rootmap.
352 hammer_recover_stage2(hammer_mount_t hmp
, hammer_volume_t root_volume
)
354 hammer_blockmap_t rootmap
;
355 hammer_buffer_t buffer
;
356 hammer_off_t scan_offset
;
358 hammer_fifo_any_t head
;
359 hammer_off_t first_offset
;
360 hammer_off_t last_offset
;
364 * Stage 2 can only be run on a RW mount, or when the mount is
365 * switched from RO to RW. It must be run only once.
367 KKASSERT(hmp
->ronly
== 0);
369 if (hmp
->hflags
& HMNT_STAGE2
)
371 hmp
->hflags
|= HMNT_STAGE2
;
374 * Examine the UNDO FIFO. If it is empty the filesystem is clean
375 * and no action need be taken.
377 rootmap
= &root_volume
->ondisk
->vol0_blockmap
[HAMMER_ZONE_UNDO_INDEX
];
378 first_offset
= rootmap
->first_offset
;
379 last_offset
= rootmap
->next_offset
;
380 if (first_offset
== last_offset
)
383 if (last_offset
>= first_offset
) {
384 bytes
= last_offset
- first_offset
;
386 bytes
= rootmap
->alloc_offset
- first_offset
+
387 (last_offset
& HAMMER_OFF_LONG_MASK
);
389 kprintf("HAMMER(%s) Start redo recovery %016jx - %016jx "
390 "(%jd bytes of UNDO)%s\n",
391 root_volume
->ondisk
->vol_name
,
392 (intmax_t)first_offset
,
393 (intmax_t)last_offset
,
395 (hmp
->ronly
? " (RO)" : "(RW)"));
396 if (bytes
> (rootmap
->alloc_offset
& HAMMER_OFF_LONG_MASK
)) {
397 kprintf("Undo size is absurd, unable to mount\n");
402 * Scan the REDOs forwards.
404 scan_offset
= first_offset
;
408 KKASSERT(scan_offset
!= last_offset
);
410 head
= hammer_recover_scan_fwd(hmp
, root_volume
,
411 &scan_offset
, &error
, &buffer
);
416 error
= hammer_recover_redo(hmp
, root_volume
, &head
->redo
);
419 kprintf("HAMMER(%s) UNDO record at %016jx failed\n",
420 root_volume
->ondisk
->vol_name
,
421 (intmax_t)scan_offset
- head
->head
.hdr_size
);
424 bytes
-= head
->head
.hdr_size
;
427 hammer_rel_buffer(buffer
, 0);
432 * Finish up flushing (or discarding) recovered buffers by executing
433 * a normal flush cycle. Setting HMNT_UNDO_DIRTY bypasses degenerate
434 * case tests and forces the flush in order to update the FIFO indices.
436 * If a crash occurs during the flush the entire undo/redo will be
437 * re-run during recovery on the next mount.
440 if (rootmap
->first_offset
!= rootmap
->next_offset
)
441 hmp
->hflags
|= HMNT_UNDO_DIRTY
;
442 hammer_flusher_sync(hmp
);
444 kprintf("HAMMER(%s) End redo recovery\n",
445 root_volume
->ondisk
->vol_name
);
450 * Scan backwards from *scan_offsetp, return the FIFO record prior to the
451 * record at *scan_offsetp or NULL if an error occured.
453 * On return *scan_offsetp will be the offset of the returned record.
456 hammer_recover_scan_rev(hammer_mount_t hmp
, hammer_volume_t root_volume
,
457 hammer_off_t
*scan_offsetp
,
458 int *errorp
, struct hammer_buffer
**bufferp
)
460 hammer_off_t scan_offset
;
461 hammer_blockmap_t rootmap
;
462 hammer_fifo_any_t head
;
463 hammer_fifo_tail_t tail
;
465 rootmap
= &root_volume
->ondisk
->vol0_blockmap
[HAMMER_ZONE_UNDO_INDEX
];
466 scan_offset
= *scan_offsetp
;
468 if (hammer_debug_general
& 0x0080)
469 kprintf("rev scan_offset %016jx\n", (intmax_t)scan_offset
);
470 if (scan_offset
== HAMMER_ZONE_ENCODE(HAMMER_ZONE_UNDO_INDEX
, 0))
471 scan_offset
= rootmap
->alloc_offset
;
472 if (scan_offset
- sizeof(*tail
) <
473 HAMMER_ZONE_ENCODE(HAMMER_ZONE_UNDO_INDEX
, 0)) {
474 kprintf("HAMMER(%s) UNDO record at %016jx FIFO underflow\n",
475 root_volume
->ondisk
->vol_name
,
476 (intmax_t)scan_offset
);
480 tail
= hammer_bread(hmp
, scan_offset
- sizeof(*tail
),
483 kprintf("HAMMER(%s) Unable to read UNDO TAIL "
485 root_volume
->ondisk
->vol_name
,
486 (intmax_t)scan_offset
- sizeof(*tail
));
490 if (hammer_check_tail_signature(tail
, scan_offset
) != 0) {
491 kprintf("HAMMER(%s) Illegal UNDO TAIL signature "
493 root_volume
->ondisk
->vol_name
,
494 (intmax_t)scan_offset
- sizeof(*tail
));
498 head
= (void *)((char *)tail
+ sizeof(*tail
) - tail
->tail_size
);
499 *scan_offsetp
= scan_offset
- head
->head
.hdr_size
;
505 * Scan forwards from *scan_offsetp, return the FIFO record or NULL if
508 * On return *scan_offsetp will be the offset of the record following
509 * the returned record.
512 hammer_recover_scan_fwd(hammer_mount_t hmp
, hammer_volume_t root_volume
,
513 hammer_off_t
*scan_offsetp
,
514 int *errorp
, struct hammer_buffer
**bufferp
)
516 hammer_off_t scan_offset
;
517 hammer_blockmap_t rootmap
;
518 hammer_fifo_any_t head
;
520 rootmap
= &root_volume
->ondisk
->vol0_blockmap
[HAMMER_ZONE_UNDO_INDEX
];
521 scan_offset
= *scan_offsetp
;
523 if (hammer_debug_general
& 0x0080)
524 kprintf("fwd scan_offset %016jx\n", (intmax_t)scan_offset
);
525 if (scan_offset
== rootmap
->alloc_offset
)
526 scan_offset
= HAMMER_ZONE_ENCODE(HAMMER_ZONE_UNDO_INDEX
, 0);
528 head
= hammer_bread(hmp
, scan_offset
, errorp
, bufferp
);
530 kprintf("HAMMER(%s) Unable to read UNDO HEAD at %016jx\n",
531 root_volume
->ondisk
->vol_name
,
532 (intmax_t)scan_offset
);
536 if (hammer_check_head_signature(&head
->head
, scan_offset
) != 0) {
537 kprintf("HAMMER(%s) Illegal UNDO TAIL signature "
539 root_volume
->ondisk
->vol_name
,
540 (intmax_t)scan_offset
);
544 scan_offset
+= head
->head
.hdr_size
;
545 if (scan_offset
== rootmap
->alloc_offset
)
546 scan_offset
= HAMMER_ZONE_ENCODE(HAMMER_ZONE_UNDO_INDEX
, 0);
547 *scan_offsetp
= scan_offset
;
553 * Helper function for hammer_check_{head,tail}_signature(). Check stuff
554 * once the head and tail has been established.
556 * This function validates the entire FIFO record wrapper.
560 _hammer_check_signature(hammer_fifo_head_t head
, hammer_fifo_tail_t tail
,
561 hammer_off_t beg_off
)
563 hammer_off_t end_off
;
568 * Check signatures. The tail signature is allowed to be the
569 * head signature only for 8-byte PADs.
571 if (head
->hdr_signature
!= HAMMER_HEAD_SIGNATURE
) {
572 kprintf("HAMMER: FIFO record bad head signature "
578 if (head
->hdr_size
< HAMMER_HEAD_ALIGN
||
579 (head
->hdr_size
& HAMMER_HEAD_ALIGN_MASK
)) {
580 kprintf("HAMMER: FIFO record unaligned or bad size"
586 end_off
= beg_off
+ head
->hdr_size
;
588 if (head
->hdr_type
!= HAMMER_HEAD_TYPE_PAD
||
589 (size_t)(end_off
- beg_off
) != sizeof(*tail
)) {
590 if (head
->hdr_type
!= tail
->tail_type
) {
591 kprintf("HAMMER: FIFO record head/tail type mismatch "
592 "%04x %04x at %016jx\n",
593 head
->hdr_type
, tail
->tail_type
,
597 if (head
->hdr_size
!= tail
->tail_size
) {
598 kprintf("HAMMER: FIFO record head/tail size mismatch "
599 "%04x %04x at %016jx\n",
600 head
->hdr_size
, tail
->tail_size
,
604 if (tail
->tail_signature
!= HAMMER_TAIL_SIGNATURE
) {
605 kprintf("HAMMER: FIFO record bad tail signature "
607 tail
->tail_signature
,
614 * Non-PAD records must have a CRC and must be sized at
615 * least large enough to fit the head and tail.
617 if (head
->hdr_type
!= HAMMER_HEAD_TYPE_PAD
) {
618 crc
= crc32(head
, HAMMER_FIFO_HEAD_CRCOFF
) ^
619 crc32(head
+ 1, head
->hdr_size
- sizeof(*head
));
620 if (head
->hdr_crc
!= crc
) {
621 kprintf("HAMMER: FIFO record CRC failed %08x %08x "
627 if (head
->hdr_size
< sizeof(*head
) + sizeof(*tail
)) {
628 kprintf("HAMMER: FIFO record too small "
639 bytes
= head
->hdr_size
;
640 tail
= (void *)((char *)head
+ bytes
- sizeof(*tail
));
641 if (tail
->tail_size
!= head
->hdr_size
) {
642 kprintf("HAMMER: Bad tail size %04x vs %04x at %016jx\n",
643 tail
->tail_size
, head
->hdr_size
,
647 if (tail
->tail_type
!= head
->hdr_type
) {
648 kprintf("HAMMER: Bad tail type %04x vs %04x at %016jx\n",
649 tail
->tail_type
, head
->hdr_type
,
658 * Check that the FIFO record is in-bounds given the head and the
661 * Also checks that the head and tail structures agree with each other,
662 * but does not check beyond the signature, type, and size.
665 hammer_check_head_signature(hammer_fifo_head_t head
, hammer_off_t beg_off
)
667 hammer_fifo_tail_t tail
;
668 hammer_off_t end_off
;
671 * head overlaps buffer boundary. This could be a PAD so only
672 * check the minimum PAD size here.
674 if (((beg_off
+ sizeof(*tail
) - 1) ^ (beg_off
)) & ~HAMMER_BUFMASK64
)
678 * Calculate the ending offset and make sure the record does
679 * not cross a buffer boundary.
681 end_off
= beg_off
+ head
->hdr_size
;
682 if ((beg_off
^ (end_off
- 1)) & ~HAMMER_BUFMASK64
)
684 tail
= (void *)((char *)head
+ head
->hdr_size
- sizeof(*tail
));
685 return (_hammer_check_signature(head
, tail
, beg_off
));
689 * Check that the FIFO record is in-bounds given the tail and the
690 * hammer offset. The offset is pointing at the ending boundary of the
693 * Also checks that the head and tail structures agree with each other,
694 * but does not check beyond the signature, type, and size.
697 hammer_check_tail_signature(hammer_fifo_tail_t tail
, hammer_off_t end_off
)
699 hammer_fifo_head_t head
;
700 hammer_off_t beg_off
;
703 * tail overlaps buffer boundary
705 if (((end_off
- sizeof(*tail
)) ^ (end_off
- 1)) & ~HAMMER_BUFMASK64
)
709 * Calculate the begining offset and make sure the record does
710 * not cross a buffer boundary.
712 beg_off
= end_off
- tail
->tail_size
;
713 if ((beg_off
^ (end_off
- 1)) & ~HAMMER_BUFMASK64
)
715 head
= (void *)((char *)tail
+ sizeof(*tail
) - tail
->tail_size
);
716 return (_hammer_check_signature(head
, tail
, beg_off
));
720 hammer_recover_undo(hammer_mount_t hmp
, hammer_volume_t root_volume
,
721 hammer_fifo_undo_t undo
)
723 hammer_volume_t volume
;
724 hammer_buffer_t buffer
;
725 hammer_off_t buf_offset
;
733 * Only process UNDO records. Flag if we find other records to
734 * optimize stage2 recovery.
736 if (undo
->head
.hdr_type
!= HAMMER_HEAD_TYPE_UNDO
) {
737 if (undo
->head
.hdr_type
== HAMMER_HEAD_TYPE_REDO
)
738 hmp
->hflags
|= HMNT_HASREDO
;
743 * Validate the UNDO record.
745 bytes
= undo
->head
.hdr_size
- sizeof(*undo
) -
746 sizeof(struct hammer_fifo_tail
);
747 if (bytes
< 0 || undo
->undo_data_bytes
< 0 ||
748 undo
->undo_data_bytes
> bytes
) {
749 kprintf("HAMMER: Corrupt UNDO record, undo_data_bytes %d/%d\n",
750 undo
->undo_data_bytes
, bytes
);
754 bytes
= undo
->undo_data_bytes
;
757 * The undo offset may only be a zone-1 or zone-2 offset.
759 * Currently we only support a zone-1 offset representing the
762 zone
= HAMMER_ZONE_DECODE(undo
->undo_offset
);
763 offset
= undo
->undo_offset
& HAMMER_BUFMASK
;
765 if (offset
+ bytes
> HAMMER_BUFSIZE
) {
766 kprintf("HAMMER: Corrupt UNDO record, bad offset\n");
771 case HAMMER_ZONE_RAW_VOLUME_INDEX
:
772 vol_no
= HAMMER_VOL_DECODE(undo
->undo_offset
);
773 volume
= hammer_get_volume(hmp
, vol_no
, &error
);
774 if (volume
== NULL
) {
775 kprintf("HAMMER: UNDO record, "
776 "cannot access volume %d\n", vol_no
);
779 hammer_modify_volume(NULL
, volume
, NULL
, 0);
780 hammer_recover_copy_undo(undo
->undo_offset
,
782 (char *)volume
->ondisk
+ offset
,
784 hammer_modify_volume_done(volume
);
787 * Multiple modifications may be made to the same buffer.
788 * Also, the volume header cannot be written out until
789 * everything else has been flushed. This also
790 * covers the read-only case by preventing the kernel from
791 * flushing the buffer.
793 if (volume
->io
.recovered
== 0)
794 volume
->io
.recovered
= 1;
796 hammer_rel_volume(volume
, 0);
798 case HAMMER_ZONE_RAW_BUFFER_INDEX
:
799 buf_offset
= undo
->undo_offset
& ~HAMMER_BUFMASK64
;
800 buffer
= hammer_get_buffer(hmp
, buf_offset
, HAMMER_BUFSIZE
,
802 if (buffer
== NULL
) {
803 kprintf("HAMMER: UNDO record, "
804 "cannot access buffer %016jx\n",
805 (intmax_t)undo
->undo_offset
);
808 hammer_modify_buffer(NULL
, buffer
, NULL
, 0);
809 hammer_recover_copy_undo(undo
->undo_offset
,
811 (char *)buffer
->ondisk
+ offset
,
813 hammer_modify_buffer_done(buffer
);
816 * Multiple modifications may be made to the same buffer,
817 * improve performance by delaying the flush. This also
818 * covers the read-only case by preventing the kernel from
819 * flushing the buffer.
821 if (buffer
->io
.recovered
== 0)
822 buffer
->io
.recovered
= 1;
824 hammer_rel_buffer(buffer
, 0);
827 kprintf("HAMMER: Corrupt UNDO record\n");
834 hammer_recover_copy_undo(hammer_off_t undo_offset
,
835 char *src
, char *dst
, int bytes
)
837 if (hammer_debug_general
& 0x0080) {
838 kprintf("UNDO %016jx: %d\n",
839 (intmax_t)undo_offset
, bytes
);
842 kprintf("UNDO %016jx:", (intmax_t)undo_offset
);
843 hammer_recover_debug_dump(22, dst
, bytes
);
844 kprintf("%22s", "to:");
845 hammer_recover_debug_dump(22, src
, bytes
);
847 bcopy(src
, dst
, bytes
);
853 hammer_recover_debug_dump(int w
, char *buf
, int bytes
)
857 for (i
= 0; i
< bytes
; ++i
) {
858 if (i
&& (i
& 15) == 0)
859 kprintf("\n%*.*s", w
, w
, "");
860 kprintf(" %02x", (unsigned char)buf
[i
]);
868 * Flush recovered buffers from recovery operations. The call to this
869 * routine may be delayed if a read-only mount was made and then later
870 * upgraded to read-write. This routine is also called when unmounting
871 * a read-only mount to clean out recovered (dirty) buffers which we
872 * couldn't flush (because the mount is read-only).
874 * The volume header is always written last. The UNDO FIFO will be forced
875 * to zero-length by setting next_offset to first_offset. This leaves the
876 * (now stale) UNDO information used to recover the disk available for
879 * final is typically 0 or 1. The volume header is only written if final
880 * is 1. If final is -1 the recovered buffers are discarded instead of
881 * written and root_volume can also be passed as NULL in that case.
883 static int hammer_recover_flush_volume_callback(hammer_volume_t
, void *);
884 static int hammer_recover_flush_buffer_callback(hammer_buffer_t
, void *);
887 hammer_recover_flush_buffers(hammer_mount_t hmp
, hammer_volume_t root_volume
,
891 * Flush the buffers out asynchronously, wait for all the I/O to
892 * complete, then do it again to destroy the buffer cache buffer
893 * so it doesn't alias something later on.
895 RB_SCAN(hammer_buf_rb_tree
, &hmp
->rb_bufs_root
, NULL
,
896 hammer_recover_flush_buffer_callback
, &final
);
897 hammer_io_wait_all(hmp
, "hmrrcw", 1);
898 RB_SCAN(hammer_buf_rb_tree
, &hmp
->rb_bufs_root
, NULL
,
899 hammer_recover_flush_buffer_callback
, &final
);
902 * Flush all volume headers except the root volume. If final < 0
903 * we discard all volume headers including the root volume.
906 RB_SCAN(hammer_vol_rb_tree
, &hmp
->rb_vols_root
, NULL
,
907 hammer_recover_flush_volume_callback
, root_volume
);
909 RB_SCAN(hammer_vol_rb_tree
, &hmp
->rb_vols_root
, NULL
,
910 hammer_recover_flush_volume_callback
, NULL
);
914 * Finalize the root volume header.
916 if (root_volume
&& root_volume
->io
.recovered
&& final
> 0) {
917 hammer_io_wait_all(hmp
, "hmrflx", 1);
918 root_volume
->io
.recovered
= 0;
919 hammer_io_flush(&root_volume
->io
, 0);
920 hammer_rel_volume(root_volume
, 0);
921 hammer_io_wait_all(hmp
, "hmrfly", 1);
926 * Callback to flush volume headers. If discarding data will be NULL and
927 * all volume headers (including the root volume) will be discarded.
928 * Otherwise data is the root_volume and we flush all volume headers
929 * EXCEPT the root_volume.
931 * Clear any I/O error or modified condition when discarding buffers to
932 * clean up the reference count, otherwise the buffer may have extra refs
937 hammer_recover_flush_volume_callback(hammer_volume_t volume
, void *data
)
939 hammer_volume_t root_volume
= data
;
941 if (volume
->io
.recovered
&& volume
!= root_volume
) {
942 volume
->io
.recovered
= 0;
943 if (root_volume
!= NULL
) {
944 hammer_io_flush(&volume
->io
, 0);
946 hammer_io_clear_error(&volume
->io
);
947 hammer_io_clear_modify(&volume
->io
, 1);
949 hammer_rel_volume(volume
, 0);
955 * Flush or discard recovered I/O buffers.
957 * Clear any I/O error or modified condition when discarding buffers to
958 * clean up the reference count, otherwise the buffer may have extra refs
963 hammer_recover_flush_buffer_callback(hammer_buffer_t buffer
, void *data
)
965 int final
= *(int *)data
;
967 if (buffer
->io
.recovered
) {
968 buffer
->io
.recovered
= 0;
969 buffer
->io
.reclaim
= 1;
971 hammer_io_clear_error(&buffer
->io
);
972 hammer_io_clear_modify(&buffer
->io
, 1);
974 hammer_io_flush(&buffer
->io
, 0);
976 hammer_rel_buffer(buffer
, 0);
978 if (buffer
->io
.lock
.refs
== 0)
979 ++hammer_count_refedbufs
;
980 hammer_ref(&buffer
->io
.lock
);
982 hammer_io_clear_error(&buffer
->io
);
983 hammer_io_clear_modify(&buffer
->io
, 1);
985 KKASSERT(buffer
->io
.lock
.refs
== 1);
986 buffer
->io
.reclaim
= 1;
987 hammer_rel_buffer(buffer
, 1);