1 /* 2 * Copyright (c) 2008 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 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 16 * distribution. 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. 20 * 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 32 * SUCH DAMAGE. 33 * 34 * $DragonFly: src/sys/vfs/hammer/hammer_undo.c,v 1.4 2008/04/22 19:00:15 dillon Exp $ 35 */ 36 37 /* 38 * HAMMER undo - undo buffer/FIFO management. 39 */ 40 41 #include "hammer.h" 42 43 /* 44 * Convert a zone-3 undo offset into a zone-2 buffer offset. 45 */ 46 hammer_off_t 47 hammer_undo_lookup(hammer_mount_t hmp, hammer_off_t zone3_off, int *errorp) 48 { 49 hammer_volume_t root_volume; 50 hammer_blockmap_t undomap; 51 struct hammer_blockmap_layer2 *layer2; 52 hammer_off_t result_offset; 53 int i; 54 55 KKASSERT((zone3_off & HAMMER_OFF_ZONE_MASK) == HAMMER_ZONE_UNDO); 56 root_volume = hammer_get_root_volume(hmp, errorp); 57 if (*errorp) 58 return(0); 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); 62 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); 67 68 hammer_rel_volume(root_volume, 0); 69 return(result_offset); 70 } 71 72 /* 73 * Generate an UNDO record for the block of data at the specified zone1 74 * offset. 75 */ 76 int 77 hammer_generate_undo(hammer_transaction_t trans, hammer_io_t io, 78 hammer_off_t zone1_off, void *base, int len) 79 { 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; 89 int i; 90 int error; 91 int bytes; 92 93 bytes = ((len + 7) & ~7) + sizeof(struct hammer_fifo_undo) + 94 sizeof(struct hammer_fifo_tail); 95 96 root_volume = trans->rootvol; 97 ondisk = root_volume->ondisk; 98 undomap = &ondisk->vol0_blockmap[HAMMER_ZONE_UNDO_INDEX]; 99 100 /* no undo recursion */ 101 hammer_modify_volume(NULL, root_volume, NULL, 0); 102 103 /* 104 * Allocate space in the FIFO 105 */ 106 again: 107 next_offset = undomap->next_offset; 108 109 /* 110 * Wrap next_offset 111 */ 112 if (undomap->next_offset == undomap->alloc_offset) { 113 next_offset = HAMMER_ZONE_ENCODE(HAMMER_ZONE_UNDO_INDEX, 0); 114 undomap->next_offset = next_offset; 115 kprintf("undo zone's next_offset wrapped\n"); 116 } 117 118 i = (next_offset & HAMMER_OFF_SHORT_MASK) / HAMMER_LARGEBLOCK_SIZE; 119 layer2 = &root_volume->ondisk->vol0_undo_array[i]; 120 result_offset = layer2->u.phys_offset + 121 (next_offset & HAMMER_LARGEBLOCK_MASK64); 122 123 undo = hammer_bread(trans->hmp, result_offset, &error, &buffer); 124 125 /* 126 * We raced another thread, try again. 127 */ 128 if (undomap->next_offset != next_offset) 129 goto again; 130 131 hammer_modify_buffer(NULL, buffer, NULL, 0); 132 133 /* 134 * The FIFO entry would cross a buffer boundary, PAD to the end 135 * of the buffer and try again. Due to our data alignment, the 136 * worst case (smallest) PAD record is 8 bytes. PAD records only 137 * populate the first 8 bytes of hammer_fifo_head and the tail may 138 * be at the same offset as the head. 139 */ 140 if ((result_offset ^ (result_offset + bytes)) & ~HAMMER_BUFMASK64) { 141 bytes = HAMMER_BUFSIZE - ((int)next_offset & HAMMER_BUFMASK); 142 tail = (void *)((char *)undo + bytes - sizeof(*tail)); 143 if ((void *)undo != (void *)tail) { 144 tail->tail_signature = HAMMER_TAIL_SIGNATURE; 145 tail->tail_type = HAMMER_HEAD_TYPE_PAD; 146 tail->tail_size = bytes; 147 } 148 undo->head.hdr_signature = HAMMER_HEAD_SIGNATURE; 149 undo->head.hdr_type = HAMMER_HEAD_TYPE_PAD; 150 undo->head.hdr_size = bytes; 151 undomap->next_offset += bytes; 152 goto again; 153 } 154 if (hammer_debug_general & 0x0080) 155 kprintf("undo %016llx %d %d\n", result_offset, bytes, len); 156 157 /* 158 * We're good, create the entry. 159 */ 160 undo->head.hdr_signature = HAMMER_HEAD_SIGNATURE; 161 undo->head.hdr_type = HAMMER_HEAD_TYPE_PAD; 162 undo->head.hdr_size = bytes; 163 undo->head.reserved01 = 0; 164 undo->head.hdr_crc = 0; 165 undo->undo_offset = zone1_off; 166 undo->undo_data_bytes = len; 167 bcopy(base, undo + 1, len); 168 undo->head.hdr_crc = crc32(undo, bytes); 169 170 /* 171 * Update the undo offset space in the IO XXX 172 */ 173 174 175 undomap->next_offset += bytes; 176 177 if (buffer) 178 hammer_rel_buffer(buffer, 0); 179 return(error); 180 } 181 182