1 1.1 uch /* $NetBSD: datablock.c,v 1.1 2011/06/27 11:52:58 uch Exp $ */ 2 1.1 uch 3 1.1 uch /*- 4 1.1 uch * Copyright (c) 2011 The NetBSD Foundation, Inc. 5 1.1 uch * All rights reserved. 6 1.1 uch * 7 1.1 uch * This code is derived from software contributed to The NetBSD Foundation 8 1.1 uch * by UCHIYAMA Yasushi. 9 1.1 uch * 10 1.1 uch * Redistribution and use in source and binary forms, with or without 11 1.1 uch * modification, are permitted provided that the following conditions 12 1.1 uch * are met: 13 1.1 uch * 1. Redistributions of source code must retain the above copyright 14 1.1 uch * notice, this list of conditions and the following disclaimer. 15 1.1 uch * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 uch * notice, this list of conditions and the following disclaimer in the 17 1.1 uch * documentation and/or other materials provided with the distribution. 18 1.1 uch * 19 1.1 uch * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 uch * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 uch * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 uch * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 uch * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 uch * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 uch * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 uch * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 uch * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 uch * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 uch * POSSIBILITY OF SUCH DAMAGE. 30 1.1 uch */ 31 1.1 uch 32 1.1 uch #include <sys/cdefs.h> 33 1.1 uch #ifndef lint 34 1.1 uch __RCSID("$NetBSD: datablock.c,v 1.1 2011/06/27 11:52:58 uch Exp $"); 35 1.1 uch #endif /* not lint */ 36 1.1 uch 37 1.1 uch #include <stdio.h> 38 1.1 uch #include <stdbool.h> 39 1.1 uch 40 1.1 uch #include "v7fs.h" 41 1.1 uch #include "v7fs_endian.h" 42 1.1 uch #include "v7fs_superblock.h" 43 1.1 uch #include "v7fs_inode.h" 44 1.1 uch #include "v7fs_impl.h" 45 1.1 uch #include "v7fs_datablock.h" 46 1.1 uch #include "v7fs_file.h" 47 1.1 uch #include "fsck_v7fs.h" 48 1.1 uch 49 1.1 uch static void datablock_dup_remove(struct v7fs_self *, v7fs_ino_t, v7fs_ino_t, 50 1.1 uch v7fs_daddr_t); 51 1.1 uch 52 1.1 uch struct loop_context { 53 1.1 uch v7fs_ino_t i; 54 1.1 uch v7fs_ino_t j; 55 1.1 uch v7fs_daddr_t blk; 56 1.1 uch }; 57 1.1 uch 58 1.1 uch /* 59 1.1 uch * datablock vs freeblock 60 1.1 uch */ 61 1.1 uch static int 62 1.1 uch freeblock_subr(struct v7fs_self *fs, void *ctx, v7fs_daddr_t freeblk) 63 1.1 uch { 64 1.1 uch struct loop_context *arg = (struct loop_context *)ctx; 65 1.1 uch 66 1.1 uch progress(0); 67 1.1 uch if (arg->blk == freeblk) { 68 1.1 uch pwarn("*** ino%d(%s) data block %d found at freeblock", 69 1.1 uch arg->i, filename(fs, arg->i), freeblk); 70 1.1 uch if (reply("CORRECT?")) { 71 1.1 uch freeblock_dup_remove(fs, freeblk); 72 1.1 uch return V7FS_ITERATOR_ERROR; /* Rescan needed. */ 73 1.1 uch } 74 1.1 uch } 75 1.1 uch 76 1.1 uch return 0; 77 1.1 uch } 78 1.1 uch 79 1.1 uch static int 80 1.1 uch datablock_subr(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk, 81 1.1 uch size_t sz __unused) 82 1.1 uch { 83 1.1 uch struct loop_context *arg = (struct loop_context *)ctx; 84 1.1 uch int ret; 85 1.1 uch 86 1.1 uch arg->blk = blk; 87 1.1 uch if ((ret = v7fs_freeblock_foreach(fs, freeblock_subr, ctx)) == 88 1.1 uch V7FS_ITERATOR_ERROR) 89 1.1 uch return ret; 90 1.1 uch 91 1.1 uch return 0; 92 1.1 uch } 93 1.1 uch 94 1.1 uch static int 95 1.1 uch inode_subr(struct v7fs_self *fs, void *ctx, struct v7fs_inode *p, 96 1.1 uch v7fs_ino_t ino) 97 1.1 uch { 98 1.1 uch struct loop_context *arg = (struct loop_context *)ctx; 99 1.1 uch int ret; 100 1.1 uch 101 1.1 uch arg->i = ino; 102 1.1 uch 103 1.1 uch if ((ret = v7fs_datablock_foreach(fs, p, datablock_subr, ctx)) == 104 1.1 uch V7FS_ITERATOR_ERROR) 105 1.1 uch return ret; 106 1.1 uch 107 1.1 uch return 0; 108 1.1 uch } 109 1.1 uch 110 1.1 uch int 111 1.1 uch datablock_vs_freeblock_check(struct v7fs_self *fs) 112 1.1 uch { 113 1.1 uch struct v7fs_superblock *sb = &fs->superblock; 114 1.1 uch int nfree = sb->total_freeblock; 115 1.1 uch int ndata = sb->volume_size - sb->datablock_start_sector - nfree; 116 1.1 uch int ret; 117 1.1 uch 118 1.1 uch progress(&(struct progress_arg){ .label = "data-free", .tick = (ndata / 119 1.1 uch PROGRESS_BAR_GRANULE) * nfree }); 120 1.1 uch 121 1.1 uch if ((ret = v7fs_ilist_foreach(fs, inode_subr, &(struct loop_context) 122 1.1 uch { .i = 0, .blk = 0 })) == V7FS_ITERATOR_ERROR) 123 1.1 uch return FSCK_EXIT_UNRESOLVED; 124 1.1 uch 125 1.1 uch return 0; 126 1.1 uch } 127 1.1 uch 128 1.1 uch 129 1.1 uch /* 130 1.1 uch * datablock vs datablock 131 1.1 uch */ 132 1.1 uch static int 133 1.1 uch datablock_i_j(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk, size_t sz 134 1.1 uch __unused) 135 1.1 uch { 136 1.1 uch struct loop_context *arg = (struct loop_context *)ctx; 137 1.1 uch 138 1.1 uch progress(0); 139 1.1 uch if (blk == arg->blk) { 140 1.1 uch pwarn("*** duplicated block found." 141 1.1 uch "#%d(%s) and #%d(%s) refer block %d", 142 1.1 uch arg->i, filename(fs, arg->i), 143 1.1 uch arg->j, filename(fs, arg->j), blk); 144 1.1 uch if (reply("CORRECT?")) { 145 1.1 uch datablock_dup_remove(fs, arg->i, arg->j, blk); 146 1.1 uch return V7FS_ITERATOR_ERROR; /* Rescan needed. */ 147 1.1 uch } 148 1.1 uch } 149 1.1 uch 150 1.1 uch return 0; 151 1.1 uch } 152 1.1 uch 153 1.1 uch static int 154 1.1 uch loopover_j(struct v7fs_self *fs, void *ctx, struct v7fs_inode *p, 155 1.1 uch v7fs_ino_t ino) 156 1.1 uch { 157 1.1 uch struct loop_context *arg = (struct loop_context *)ctx; 158 1.1 uch int ret; 159 1.1 uch 160 1.1 uch arg->j = ino; 161 1.1 uch 162 1.1 uch if (arg->j >= arg->i) 163 1.1 uch return V7FS_ITERATOR_BREAK; 164 1.1 uch 165 1.1 uch if ((ret = v7fs_datablock_foreach(fs, p, datablock_i_j, ctx)) == 166 1.1 uch V7FS_ITERATOR_ERROR) 167 1.1 uch return V7FS_ITERATOR_ERROR; 168 1.1 uch 169 1.1 uch return 0; 170 1.1 uch } 171 1.1 uch 172 1.1 uch static int 173 1.1 uch datablock_i(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk, 174 1.1 uch size_t sz __unused) 175 1.1 uch { 176 1.1 uch struct loop_context *arg = (struct loop_context *)ctx; 177 1.1 uch int ret; 178 1.1 uch 179 1.1 uch arg->blk = blk; 180 1.1 uch 181 1.1 uch if ((ret = v7fs_ilist_foreach(fs, loopover_j, ctx)) == 182 1.1 uch V7FS_ITERATOR_ERROR) 183 1.1 uch return V7FS_ITERATOR_ERROR; 184 1.1 uch 185 1.1 uch return 0; 186 1.1 uch } 187 1.1 uch 188 1.1 uch static int 189 1.1 uch loopover_i(struct v7fs_self *fs, void *ctx, struct v7fs_inode *inode, 190 1.1 uch v7fs_ino_t ino) 191 1.1 uch { 192 1.1 uch struct loop_context *arg = (struct loop_context *)ctx; 193 1.1 uch int ret; 194 1.1 uch 195 1.1 uch arg->i = ino; 196 1.1 uch 197 1.1 uch if ((ret = v7fs_datablock_foreach(fs, inode, datablock_i, ctx)) == 198 1.1 uch V7FS_ITERATOR_ERROR) 199 1.1 uch return V7FS_ITERATOR_ERROR; 200 1.1 uch 201 1.1 uch return 0; 202 1.1 uch } 203 1.1 uch 204 1.1 uch 205 1.1 uch int 206 1.1 uch datablock_vs_datablock_check(struct v7fs_self *fs) 207 1.1 uch { 208 1.1 uch const struct v7fs_superblock *sb = &fs->superblock; 209 1.1 uch int n = sb->volume_size - sb->total_freeblock; 210 1.1 uch int ret; 211 1.1 uch 212 1.1 uch progress(&(struct progress_arg){ .label = "data-data", .tick = (n / 2) 213 1.1 uch * ((n - 1) / PROGRESS_BAR_GRANULE) }); 214 1.1 uch 215 1.1 uch if ((ret = v7fs_ilist_foreach(fs, loopover_i, &(struct loop_context){ 216 1.1 uch .i = 0, .j = 0 })) == V7FS_ITERATOR_ERROR) 217 1.1 uch return FSCK_EXIT_UNRESOLVED; 218 1.1 uch 219 1.1 uch return 0; 220 1.1 uch } 221 1.1 uch 222 1.1 uch /* 223 1.1 uch * Remove duplicated block. 224 1.1 uch */ 225 1.1 uch static void 226 1.1 uch copy_block(struct v7fs_self *fs, v7fs_daddr_t dst, v7fs_daddr_t src) 227 1.1 uch { 228 1.1 uch void *buf; 229 1.1 uch 230 1.1 uch if (!(buf = scratch_read(fs, src))) 231 1.1 uch return; 232 1.1 uch fs->io.write(fs->io.cookie, buf, dst); 233 1.1 uch scratch_free(fs, buf); 234 1.1 uch 235 1.1 uch pwarn("copy block %d->%d\n", src, dst); 236 1.1 uch } 237 1.1 uch 238 1.1 uch static void 239 1.1 uch replace_block_direct(struct v7fs_self *fs, struct v7fs_inode *p, int dupidx, 240 1.1 uch v7fs_daddr_t newblk) 241 1.1 uch { 242 1.1 uch v7fs_daddr_t oldblk; 243 1.1 uch 244 1.1 uch oldblk = p->addr[dupidx]; 245 1.1 uch p->addr[dupidx] = newblk; 246 1.1 uch v7fs_inode_writeback(fs, p); /* endian conversion done by here. */ 247 1.1 uch 248 1.1 uch copy_block(fs, newblk, oldblk); 249 1.1 uch } 250 1.1 uch 251 1.1 uch static void 252 1.1 uch prepare_list(struct v7fs_self *fs, v7fs_daddr_t listblk, v7fs_daddr_t *p) 253 1.1 uch { 254 1.1 uch size_t i; 255 1.1 uch 256 1.1 uch fs->io.read(fs->io.cookie, (void *)p, listblk); 257 1.1 uch for (i = 0; i < V7FS_DADDR_PER_BLOCK; i++) 258 1.1 uch p[i] = V7FS_VAL32(fs, p[i]); 259 1.1 uch } 260 1.1 uch 261 1.1 uch static void 262 1.1 uch replace_block_indexed(struct v7fs_self *fs, v7fs_daddr_t listblk, int dupidx, 263 1.1 uch v7fs_daddr_t newblk) 264 1.1 uch { 265 1.1 uch void *buf; 266 1.1 uch v7fs_daddr_t *list; 267 1.1 uch v7fs_daddr_t oldblk; 268 1.1 uch 269 1.1 uch if (!(buf = scratch_read(fs, listblk))) 270 1.1 uch return; 271 1.1 uch list = (v7fs_daddr_t *)buf; 272 1.1 uch oldblk = V7FS_VAL32(fs, list[dupidx]); 273 1.1 uch list[dupidx] = V7FS_VAL32(fs, newblk); 274 1.1 uch fs->io.write(fs->io.cookie, buf, listblk); 275 1.1 uch scratch_free(fs, buf); 276 1.1 uch 277 1.1 uch copy_block(fs, newblk, oldblk); 278 1.1 uch pwarn("dup block replaced by %d\n", newblk); 279 1.1 uch } 280 1.1 uch 281 1.1 uch static bool 282 1.1 uch dupfind_loop1(struct v7fs_self *fs, v7fs_daddr_t listblk, v7fs_daddr_t dupblk, 283 1.1 uch v7fs_daddr_t newblk) 284 1.1 uch { 285 1.1 uch v7fs_daddr_t list[V7FS_DADDR_PER_BLOCK]; 286 1.1 uch size_t i; 287 1.1 uch 288 1.1 uch prepare_list(fs, listblk, list); 289 1.1 uch for (i = 0; i < V7FS_DADDR_PER_BLOCK; i++) { 290 1.1 uch if (list[i] == dupblk) { 291 1.1 uch replace_block_indexed(fs, listblk, i, newblk); 292 1.1 uch return true; 293 1.1 uch } 294 1.1 uch } 295 1.1 uch 296 1.1 uch return false; 297 1.1 uch } 298 1.1 uch 299 1.1 uch static bool 300 1.1 uch dupfind_loop2(struct v7fs_self *fs, v7fs_daddr_t listblk, v7fs_daddr_t dupblk, 301 1.1 uch v7fs_daddr_t newblk) 302 1.1 uch { 303 1.1 uch v7fs_daddr_t list[V7FS_DADDR_PER_BLOCK]; 304 1.1 uch v7fs_daddr_t blk; 305 1.1 uch size_t i; 306 1.1 uch 307 1.1 uch prepare_list(fs, listblk, list); 308 1.1 uch for (i = 0; i < V7FS_DADDR_PER_BLOCK; i++) { 309 1.1 uch if ((blk = list[i]) == dupblk) { 310 1.1 uch replace_block_indexed(fs, listblk, i, newblk); 311 1.1 uch return true; 312 1.1 uch } 313 1.1 uch if (dupfind_loop1(fs, blk, dupblk, newblk)) 314 1.1 uch return true; 315 1.1 uch } 316 1.1 uch 317 1.1 uch return false; 318 1.1 uch } 319 1.1 uch 320 1.1 uch static void 321 1.1 uch do_replace(struct v7fs_self *fs, struct v7fs_inode *p, v7fs_daddr_t dupblk, 322 1.1 uch v7fs_daddr_t newblk) 323 1.1 uch { 324 1.1 uch size_t i; 325 1.1 uch v7fs_daddr_t blk, blk2; 326 1.1 uch v7fs_daddr_t list[V7FS_DADDR_PER_BLOCK]; 327 1.1 uch 328 1.1 uch /* Direct */ 329 1.1 uch for (i = 0; i < V7FS_NADDR_DIRECT; i++) { 330 1.1 uch if (p->addr[i] == dupblk) { 331 1.1 uch replace_block_direct(fs, p, i, newblk); 332 1.1 uch return; 333 1.1 uch } 334 1.1 uch } 335 1.1 uch 336 1.1 uch /* Index 1 */ 337 1.1 uch if ((blk = p->addr[V7FS_NADDR_INDEX1]) == dupblk) { 338 1.1 uch replace_block_direct(fs, p, V7FS_NADDR_INDEX1, newblk); 339 1.1 uch return; 340 1.1 uch } 341 1.1 uch if (dupfind_loop1(fs, blk, dupblk, newblk)) 342 1.1 uch return; 343 1.1 uch 344 1.1 uch /* Index 2 */ 345 1.1 uch if ((blk = p->addr[V7FS_NADDR_INDEX2]) == dupblk) { 346 1.1 uch replace_block_direct(fs, p, V7FS_NADDR_INDEX2, newblk); 347 1.1 uch return; 348 1.1 uch } 349 1.1 uch if (dupfind_loop2(fs, blk, dupblk, newblk)) 350 1.1 uch return; 351 1.1 uch 352 1.1 uch /* Index 3 */ 353 1.1 uch if ((blk = p->addr[V7FS_NADDR_INDEX3]) == dupblk) { 354 1.1 uch replace_block_direct(fs, p, V7FS_NADDR_INDEX3, newblk); 355 1.1 uch return; 356 1.1 uch } 357 1.1 uch prepare_list(fs, blk, list); 358 1.1 uch for (i = 0; i < V7FS_DADDR_PER_BLOCK; i++) { 359 1.1 uch if ((blk2 = list[i]) == dupblk) { 360 1.1 uch replace_block_indexed(fs, blk, i, newblk); 361 1.1 uch return; 362 1.1 uch } 363 1.1 uch if (dupfind_loop2(fs, blk2, dupblk, newblk)) 364 1.1 uch return; 365 1.1 uch } 366 1.1 uch } 367 1.1 uch 368 1.1 uch static void 369 1.1 uch datablock_dup_remove(struct v7fs_self *fs, v7fs_ino_t i, v7fs_ino_t j, 370 1.1 uch v7fs_daddr_t dupblk) 371 1.1 uch { 372 1.1 uch struct v7fs_inode inode; 373 1.1 uch v7fs_ino_t victim; 374 1.1 uch v7fs_daddr_t newblk; 375 1.1 uch int error; 376 1.1 uch 377 1.1 uch pwarn("Is victim %s (%s is preserved)", filename(fs, i), 378 1.1 uch filename(fs, j)); 379 1.1 uch if (reply("?")) { 380 1.1 uch victim = i; 381 1.1 uch } else { 382 1.1 uch pwarn("Is victim %s (%s is preserved)", 383 1.1 uch filename(fs, j), filename(fs, i)); 384 1.1 uch if (reply("?")) { 385 1.1 uch victim = j; 386 1.1 uch } else { 387 1.1 uch pwarn("Don't correct.\n"); 388 1.1 uch return; 389 1.1 uch } 390 1.1 uch } 391 1.1 uch 392 1.1 uch if ((error = v7fs_inode_load(fs, &inode, victim))) 393 1.1 uch return; 394 1.1 uch 395 1.1 uch /* replace block. */ 396 1.1 uch if ((error = v7fs_datablock_allocate(fs, &newblk))) { 397 1.1 uch pwarn("Can't allocate substitute block."); 398 1.1 uch return; 399 1.1 uch } 400 1.1 uch 401 1.1 uch do_replace(fs, &inode, dupblk, newblk); 402 1.1 uch } 403 1.1 uch 404