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_undo.c,v 1.6 2008/04/26 02:54:00 dillon Exp $
38 * HAMMER undo - undo buffer/FIFO management.
44 * Convert a zone-3 undo offset into a zone-2 buffer offset.
47 hammer_undo_lookup(hammer_mount_t hmp
, hammer_off_t zone3_off
, int *errorp
)
49 hammer_volume_t root_volume
;
50 hammer_blockmap_t undomap
;
51 struct hammer_blockmap_layer2
*layer2
;
52 hammer_off_t result_offset
;
55 KKASSERT((zone3_off
& HAMMER_OFF_ZONE_MASK
) == HAMMER_ZONE_UNDO
);
56 root_volume
= hammer_get_root_volume(hmp
, errorp
);
59 undomap
= &root_volume
->ondisk
->vol0_blockmap
[HAMMER_ZONE_UNDO_INDEX
];
60 KKASSERT(HAMMER_ZONE_DECODE(undomap
->alloc_offset
) == HAMMER_ZONE_UNDO_INDEX
);
61 KKASSERT (zone3_off
< undomap
->alloc_offset
);
63 i
= (zone3_off
& HAMMER_OFF_SHORT_MASK
) / HAMMER_LARGEBLOCK_SIZE
;
64 layer2
= &root_volume
->ondisk
->vol0_undo_array
[i
];
65 result_offset
= layer2
->u
.phys_offset
+
66 (zone3_off
& HAMMER_LARGEBLOCK_MASK64
);
68 hammer_rel_volume(root_volume
, 0);
69 return(result_offset
);
73 * Generate an UNDO record for the block of data at the specified zone1
77 hammer_generate_undo(hammer_transaction_t trans
, hammer_io_t io
,
78 hammer_off_t zone_off
, void *base
, int len
)
80 hammer_volume_t root_volume
;
81 hammer_volume_ondisk_t ondisk
;
82 hammer_blockmap_t undomap
;
83 hammer_buffer_t buffer
= NULL
;
84 struct hammer_blockmap_layer2
*layer2
;
85 hammer_fifo_undo_t undo
;
86 hammer_fifo_tail_t tail
;
87 hammer_off_t next_offset
;
88 hammer_off_t result_offset
;
93 root_volume
= trans
->rootvol
;
94 ondisk
= root_volume
->ondisk
;
95 undomap
= &ondisk
->vol0_blockmap
[HAMMER_ZONE_UNDO_INDEX
];
97 /* no undo recursion */
98 hammer_modify_volume(NULL
, root_volume
, NULL
, 0);
102 * Allocate space in the FIFO
104 bytes
= ((len
+ HAMMER_HEAD_ALIGN_MASK
) & ~HAMMER_HEAD_ALIGN_MASK
) +
105 sizeof(struct hammer_fifo_undo
) +
106 sizeof(struct hammer_fifo_tail
);
108 next_offset
= undomap
->next_offset
;
113 if (undomap
->next_offset
== undomap
->alloc_offset
) {
114 next_offset
= HAMMER_ZONE_ENCODE(HAMMER_ZONE_UNDO_INDEX
, 0);
115 undomap
->next_offset
= next_offset
;
116 kprintf("undo zone's next_offset wrapped\n");
119 i
= (next_offset
& HAMMER_OFF_SHORT_MASK
) / HAMMER_LARGEBLOCK_SIZE
;
120 layer2
= &root_volume
->ondisk
->vol0_undo_array
[i
];
121 result_offset
= layer2
->u
.phys_offset
+
122 (next_offset
& HAMMER_LARGEBLOCK_MASK64
);
124 undo
= hammer_bread(trans
->hmp
, result_offset
, &error
, &buffer
);
127 * We raced another thread, try again.
129 if (undomap
->next_offset
!= next_offset
)
132 hammer_modify_buffer(NULL
, buffer
, NULL
, 0);
135 * The FIFO entry would cross a buffer boundary, PAD to the end
136 * of the buffer and try again. Due to our data alignment, the
137 * worst case (smallest) PAD record is 8 bytes. PAD records only
138 * populate the first 8 bytes of hammer_fifo_head and the tail may
139 * be at the same offset as the head.
141 if ((result_offset
^ (result_offset
+ bytes
)) & ~HAMMER_BUFMASK64
) {
142 bytes
= HAMMER_BUFSIZE
- ((int)next_offset
& HAMMER_BUFMASK
);
143 tail
= (void *)((char *)undo
+ bytes
- sizeof(*tail
));
144 if ((void *)undo
!= (void *)tail
) {
145 tail
->tail_signature
= HAMMER_TAIL_SIGNATURE
;
146 tail
->tail_type
= HAMMER_HEAD_TYPE_PAD
;
147 tail
->tail_size
= bytes
;
149 undo
->head
.hdr_signature
= HAMMER_HEAD_SIGNATURE
;
150 undo
->head
.hdr_type
= HAMMER_HEAD_TYPE_PAD
;
151 undo
->head
.hdr_size
= bytes
;
152 undomap
->next_offset
+= bytes
;
153 hammer_modify_buffer_done(buffer
);
156 if (hammer_debug_general
& 0x0080)
157 kprintf("undo %016llx %d %d\n", result_offset
, bytes
, len
);
160 * We're good, create the entry.
162 undo
->head
.hdr_signature
= HAMMER_HEAD_SIGNATURE
;
163 undo
->head
.hdr_type
= HAMMER_HEAD_TYPE_UNDO
;
164 undo
->head
.hdr_size
= bytes
;
165 undo
->head
.reserved01
= 0;
166 undo
->head
.hdr_crc
= 0;
167 undo
->undo_offset
= zone_off
;
168 undo
->undo_data_bytes
= len
;
169 bcopy(base
, undo
+ 1, len
);
171 tail
= (void *)((char *)undo
+ bytes
- sizeof(*tail
));
172 tail
->tail_signature
= HAMMER_TAIL_SIGNATURE
;
173 tail
->tail_type
= HAMMER_HEAD_TYPE_UNDO
;
174 tail
->tail_size
= bytes
;
176 undo
->head
.hdr_crc
= crc32(undo
, bytes
);
177 hammer_modify_buffer_done(buffer
);
180 * Update the undo offset space in the IO XXX
183 undomap
->next_offset
+= bytes
;
184 hammer_modify_volume_done(root_volume
);
187 hammer_rel_buffer(buffer
, 0);