Home | History | Annotate | Line # | Download | only in fsck_v7fs
      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