1 /* 2 * Copyright (c) 2007-2016 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 35 #include "hammer.h" 36 37 static int hammer_test_offset(const char *msg, hammer_off_t offset); 38 static void hammer_strip_bigblock(int zone, hammer_off_t offset); 39 static void hammer_ask_yn(void); 40 41 void 42 hammer_cmd_strip(void) 43 { 44 volume_info_t volume; 45 hammer_blockmap_t rootmap; 46 hammer_blockmap_layer1_t layer1; 47 hammer_blockmap_layer2_t layer2; 48 buffer_info_t buffer1 = NULL; 49 buffer_info_t buffer2 = NULL; 50 hammer_off_t layer1_offset; 51 hammer_off_t layer2_offset; 52 hammer_off_t phys_offset; 53 hammer_off_t block_offset; 54 hammer_off_t offset; 55 int i, zone = HAMMER_ZONE_FREEMAP_INDEX; 56 57 hammer_ask_yn(); 58 59 volume = get_root_volume(); 60 if (volume == NULL) { 61 printf("No root volume found\n"); 62 goto strip_header; 63 } 64 65 rootmap = &volume->ondisk->vol0_blockmap[zone]; 66 if (!hammer_test_offset("layer1 physical", rootmap->phys_offset)) 67 goto strip_header; 68 69 for (phys_offset = HAMMER_ZONE_ENCODE(zone, 0); 70 phys_offset < HAMMER_ZONE_ENCODE(zone, HAMMER_OFF_LONG_MASK); 71 phys_offset += HAMMER_BLOCKMAP_LAYER2) { 72 /* 73 * Dive layer 1. 74 */ 75 layer1_offset = rootmap->phys_offset + 76 HAMMER_BLOCKMAP_LAYER1_OFFSET(phys_offset); 77 if (!hammer_test_offset("layer1", layer1_offset)) 78 break; 79 layer1 = get_buffer_data(layer1_offset, &buffer1, 0); 80 81 if (layer1->phys_offset == HAMMER_BLOCKMAP_UNAVAIL) 82 continue; 83 84 for (block_offset = 0; 85 block_offset < HAMMER_BLOCKMAP_LAYER2; 86 block_offset += HAMMER_BIGBLOCK_SIZE) { 87 offset = phys_offset + block_offset; 88 /* 89 * Dive layer 2, each entry represents a big-block. 90 */ 91 layer2_offset = layer1->phys_offset + 92 HAMMER_BLOCKMAP_LAYER2_OFFSET(block_offset); 93 if (!hammer_test_offset("layer2", layer2_offset)) 94 break; 95 layer2 = get_buffer_data(layer2_offset, &buffer2, 0); 96 97 if (layer2->zone == HAMMER_ZONE_BTREE_INDEX || 98 layer2->zone == HAMMER_ZONE_META_INDEX) { 99 hammer_strip_bigblock(layer2->zone, offset); 100 layer2->zone = HAMMER_ZONE_UNAVAIL_INDEX; 101 layer2->append_off = HAMMER_BIGBLOCK_SIZE; 102 layer2->bytes_free = 0; 103 hammer_crc_set_layer2(HammerVersion, layer2); 104 buffer2->cache.modified = 1; 105 } else if (layer2->zone == HAMMER_ZONE_UNAVAIL_INDEX) { 106 break; 107 } 108 } 109 } 110 rel_buffer(buffer1); 111 rel_buffer(buffer2); 112 113 strip_header: 114 for (i = 0; i < HAMMER_MAX_VOLUMES; i++) { 115 volume = get_volume(i); 116 if (volume) { 117 bzero(volume->ondisk, sizeof(*volume->ondisk)); 118 memcpy(&volume->ondisk->vol_signature, "STRIPPED", 8); 119 printf("Stripped volume header %s\n", volume->name); 120 } 121 } 122 123 flush_all_volumes(); 124 } 125 126 static 127 int 128 hammer_test_offset(const char *msg, hammer_off_t offset) 129 { 130 if (get_volume(HAMMER_VOL_DECODE(offset)) == NULL) { 131 printf("Invalid volume# %d\n", HAMMER_VOL_DECODE(offset)); 132 return(0); 133 } 134 if (!hammer_is_zone_raw_buffer(offset)) { 135 printf("Invalid %s offset 0x%jx\n", msg, offset); 136 return(0); 137 } 138 139 return(1); 140 } 141 142 static 143 void 144 hammer_strip_bigblock(int zone, hammer_off_t offset) 145 { 146 buffer_info_t buffer = NULL; 147 int i; 148 149 assert(hammer_is_index_record(zone)); 150 assert((offset & HAMMER_BIGBLOCK_MASK64) == 0); 151 assert((offset & HAMMER_BUFMASK) == 0); 152 offset = hammer_xlate_to_zoneX(zone, offset); 153 154 /* 155 * This format is taken from hammer blockmap. 156 */ 157 printf("Stripped big-block "); 158 if (VerboseOpt) { 159 printf("%016jx zone=%-2d vol=%-3d L1#=%-6d L2#=%-6d L1=%-7lu L2=%-7lu\n", 160 offset, 161 zone, 162 HAMMER_VOL_DECODE(offset), 163 HAMMER_BLOCKMAP_LAYER1_INDEX(offset), 164 HAMMER_BLOCKMAP_LAYER2_INDEX(offset), 165 HAMMER_BLOCKMAP_LAYER1_OFFSET(offset), 166 HAMMER_BLOCKMAP_LAYER2_OFFSET(offset)); 167 } else { 168 printf("%016jx\n", offset); 169 } 170 171 for (i = 0; i < HAMMER_BIGBLOCK_SIZE; i += HAMMER_BUFSIZE) { 172 get_buffer_data(offset + i, &buffer, 1); 173 assert(buffer); 174 } 175 } 176 177 static 178 void 179 hammer_ask_yn(void) 180 { 181 volume_info_t volume; 182 #define _HAMMER "HAMMER filesystem" 183 char type[64]; 184 char label[64 + 4]; 185 int i; 186 187 volume = get_root_volume(); 188 189 if (volume && volume->ondisk->vol_signature == HAMMER_FSBUF_VOLUME) 190 strcpy(type, _HAMMER); 191 else 192 strcpy(type, "devices"); 193 194 if (volume && volume->ondisk->vol_label[0]) { 195 snprintf(label, sizeof(label), " (%s)", 196 volume->ondisk->vol_label); 197 } else { 198 strcpy(label, ""); 199 } 200 201 /* 202 * This format is taken from hammer pfs-destroy. 203 */ 204 printf("You have requested that %s%s be stripped", type, label); 205 if (strcmp(type, _HAMMER)) 206 printf(", but %s may not be %s volumes\n", type, _HAMMER); 207 else 208 printf("\n"); 209 210 printf("Do you really want to do this? [y/n] "); 211 fflush(stdout); 212 if (getyn() == 0) { 213 errx(1, "No action taken"); 214 /* not reached */ 215 } 216 217 if (strcmp(type, _HAMMER)) { 218 printf("Are you absolutely sure you want to do this? [y/n] "); 219 fflush(stdout); 220 if (getyn() == 0) { 221 errx(1, "No action taken"); 222 /* not reached */ 223 } 224 } 225 226 printf("Stripping %s%s", type, label); 227 228 if (DebugOpt) { 229 printf("\n"); 230 } else { 231 printf(" in"); 232 for (i = 5; i; --i) { 233 printf(" %d", i); 234 fflush(stdout); 235 sleep(1); 236 } 237 printf(".. starting destruction pass\n"); 238 } 239 } 240