Whamcloud - gitweb
tests: add tests for uninitialized bitmaps
[tools/e2fsprogs.git] / e2fsck / pass1b.c
index d5585dd..49dc0dd 100644 (file)
@@ -218,8 +218,10 @@ void e2fsck_pass1_dupblocks(e2fsck_t ctx, char *block_buf)
 
        clear_problem_context(&pctx);
 
-       pctx.errcode = ext2fs_allocate_inode_bitmap(fs,
-                     _("multiply claimed inode map"), &inode_dup_map);
+       pctx.errcode = e2fsck_allocate_inode_bitmap(fs,
+                       _("multiply claimed inode map"),
+                       EXT2FS_BMAP64_RBTREE, "inode_dup_map",
+                       &inode_dup_map);
        if (pctx.errcode) {
                fix_problem(ctx, PR_1B_ALLOCATE_IBITMAP_ERROR, &pctx);
                ctx->flags |= E2F_FLAG_ABORT;
@@ -259,6 +261,7 @@ struct process_block_struct {
        e2fsck_t        ctx;
        ext2_ino_t      ino;
        int             dup_blocks;
+       blk64_t         cur_cluster;
        struct ext2_inode *inode;
        struct problem_context *pctx;
 };
@@ -266,7 +269,7 @@ struct process_block_struct {
 static void pass1b(e2fsck_t ctx, char *block_buf)
 {
        ext2_filsys fs = ctx->fs;
-       ext2_ino_t ino;
+       ext2_ino_t ino = 0;
        struct ext2_inode inode;
        ext2_inode_scan scan;
        struct process_block_struct pb;
@@ -310,6 +313,7 @@ static void pass1b(e2fsck_t ctx, char *block_buf)
                pb.ino = ino;
                pb.dup_blocks = 0;
                pb.inode = &inode;
+               pb.cur_cluster = ~0;
 
                if (ext2fs_inode_has_valid_blocks2(fs, &inode) ||
                    (ino == EXT2_BAD_INO))
@@ -339,21 +343,23 @@ static void pass1b(e2fsck_t ctx, char *block_buf)
 
 static int process_pass1b_block(ext2_filsys fs EXT2FS_ATTR((unused)),
                                blk64_t *block_nr,
-                               e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
+                               e2_blkcnt_t blockcnt,
                                blk64_t ref_blk EXT2FS_ATTR((unused)),
                                int ref_offset EXT2FS_ATTR((unused)),
                                void *priv_data)
 {
        struct process_block_struct *p;
        e2fsck_t ctx;
+       blk64_t lc;
 
        if (HOLE_BLKADDR(*block_nr))
                return 0;
        p = (struct process_block_struct *) priv_data;
        ctx = p->ctx;
+       lc = EXT2FS_B2C(fs, blockcnt);
 
        if (!ext2fs_test_block_bitmap2(ctx->block_dup_map, *block_nr))
-               return 0;
+               goto finish;
 
        /* OK, this is a duplicate block */
        if (p->ino != EXT2_BAD_INO) {
@@ -363,8 +369,11 @@ static int process_pass1b_block(ext2_filsys fs EXT2FS_ATTR((unused)),
        p->dup_blocks++;
        ext2fs_mark_inode_bitmap2(inode_dup_map, p->ino);
 
-       add_dupe(ctx, p->ino, EXT2FS_B2C(fs, *block_nr), p->inode);
+       if (lc != p->cur_cluster)
+               add_dupe(ctx, p->ino, EXT2FS_B2C(fs, *block_nr), p->inode);
 
+finish:
+       p->cur_cluster = lc;
        return 0;
 }
 
@@ -483,6 +492,9 @@ static void pass1d(e2fsck_t ctx, char *block_buf)
                        q = (struct dup_cluster *) dnode_get(m);
                        if (q->num_bad > 1)
                                file_ok = 0;
+                       if (q->num_bad == 1 && (ctx->clone == E2F_CLONE_ZERO ||
+                           ctx->shared != E2F_SHARED_PRESERVE))
+                               file_ok = 0;
                        if (check_if_fs_cluster(ctx, s->cluster)) {
                                file_ok = 0;
                                meta_data = 1;
@@ -538,13 +550,26 @@ static void pass1d(e2fsck_t ctx, char *block_buf)
                        fix_problem(ctx, PR_1D_DUP_BLOCKS_DEALT, &pctx);
                        continue;
                }
-               if (fix_problem(ctx, PR_1D_CLONE_QUESTION, &pctx)) {
+               if (ctx->shared != E2F_SHARED_DELETE &&
+                   fix_problem(ctx, PR_1D_CLONE_QUESTION, &pctx)) {
                        pctx.errcode = clone_file(ctx, ino, p, block_buf);
-                       if (pctx.errcode)
+                       if (pctx.errcode) {
                                fix_problem(ctx, PR_1D_CLONE_ERROR, &pctx);
-                       else
-                               continue;
+                               goto delete;
+                       }
+                       if (ctx->shared == E2F_SHARED_LPF &&
+                           fix_problem(ctx, PR_1D_DISCONNECT_QUESTION, &pctx)){
+                               pctx.errcode = ext2fs_unlink(fs, p->dir,
+                                                            NULL, ino, 0);
+                               if (pctx.errcode) {
+                                       fix_problem(ctx, PR_1D_DISCONNECT_ERROR,
+                                                   &pctx);
+                                       goto delete;
+                               }
+                       }
+                       continue;
                }
+delete:
                if (fix_problem(ctx, PR_1D_DELETE_QUESTION, &pctx))
                        delete_file(ctx, ino, p, block_buf);
                else
@@ -562,7 +587,8 @@ static void decrement_badcount(e2fsck_t ctx, blk64_t block,
 {
        p->num_bad--;
        if (p->num_bad <= 0 ||
-           (p->num_bad == 1 && !check_if_fs_block(ctx, block))) {
+           (p->num_bad == 1 && !check_if_fs_block(ctx, block) &&
+           ctx->clone == E2F_CLONE_DUP)) {
                if (check_if_fs_cluster(ctx, EXT2FS_B2C(ctx->fs, block)))
                        return;
                ext2fs_unmark_block_bitmap2(ctx->block_dup_map, block);
@@ -571,7 +597,7 @@ static void decrement_badcount(e2fsck_t ctx, blk64_t block,
 
 static int delete_file_block(ext2_filsys fs,
                             blk64_t    *block_nr,
-                            e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
+                            e2_blkcnt_t blockcnt,
                             blk64_t ref_block EXT2FS_ATTR((unused)),
                             int ref_offset EXT2FS_ATTR((unused)),
                             void *priv_data)
@@ -580,7 +606,7 @@ static int delete_file_block(ext2_filsys fs,
        struct dup_cluster *p;
        dnode_t *n;
        e2fsck_t ctx;
-       blk64_t c;
+       blk64_t c, lc;
 
        pb = (struct process_block_struct *) priv_data;
        ctx = pb->ctx;
@@ -589,11 +615,13 @@ static int delete_file_block(ext2_filsys fs,
                return 0;
 
        c = EXT2FS_B2C(fs, *block_nr);
+       lc = EXT2FS_B2C(fs, blockcnt);
        if (ext2fs_test_block_bitmap2(ctx->block_dup_map, *block_nr)) {
                n = dict_lookup(&clstr_dict, INT_TO_VOIDPTR(c));
                if (n) {
                        p = (struct dup_cluster *) dnode_get(n);
-                       decrement_badcount(ctx, *block_nr, p);
+                       if (lc != pb->cur_cluster)
+                               decrement_badcount(ctx, *block_nr, p);
                } else
                        com_err("delete_file_block", 0,
                            _("internal error: can't find dup_blk for %llu\n"),
@@ -603,6 +631,7 @@ static int delete_file_block(ext2_filsys fs,
                ext2fs_block_alloc_stats2(fs, *block_nr, -1);
                pb->dup_blocks++;
        }
+       pb->cur_cluster = lc;
 
        return 0;
 }
@@ -621,6 +650,7 @@ static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
        pb.dup_blocks = 0;
        pb.ctx = ctx;
        pctx.str = "delete_file";
+       pb.cur_cluster = ~0;
 
        e2fsck_read_inode(ctx, ino, &inode, "delete_file");
        if (ext2fs_inode_has_valid_blocks2(fs, &inode))
@@ -703,8 +733,12 @@ static int clone_file_block(ext2_filsys fs,
        if (check_if_fs_cluster(ctx, EXT2FS_B2C(fs, *block_nr)))
                is_meta = 1;
 
-       if (((blockcnt > 0) && c == cs->dup_cluster) ||
-           ext2fs_test_block_bitmap2(ctx->block_dup_map, *block_nr)) {
+       if (c == cs->dup_cluster && cs->alloc_block) {
+               new_block = cs->alloc_block;
+               goto got_block;
+       }
+
+       if (ext2fs_test_block_bitmap2(ctx->block_dup_map, *block_nr)) {
                n = dict_lookup(&clstr_dict,
                                INT_TO_VOIDPTR(EXT2FS_B2C(fs, *block_nr)));
                if (!n) {
@@ -715,31 +749,15 @@ static int clone_file_block(ext2_filsys fs,
                }
 
                p = (struct dup_cluster *) dnode_get(n);
-               if (!is_meta)
+               if (!is_meta) {
                        decrement_badcount(ctx, *block_nr, p);
-
-               if (p->num_bad == 0 && !is_meta) {
-                       /*
-                        * Normally num_bad never gets to zero; but in
-                        * the case of bigalloc file systems, we don't
-                        * how many blocks might be in use by a
-                        * particular inode.  So we may end up
-                        * relocating the cluster even though this
-                        * inode is the last user of the cluster.  In
-                        * that case, since we've already moved some
-                        * of the blocks of that cluster, we'll
-                        * complete the relocation and free the
-                        * original cluster here.
-                        */
-                       ext2fs_unmark_block_bitmap2(ctx->block_found_map,
-                                                   *block_nr);
-                       ext2fs_block_alloc_stats2(fs, *block_nr, -1);
+                       if (ctx->clone == E2F_CLONE_ZERO && p->num_bad == 0) {
+                               ext2fs_unmark_block_bitmap2(ctx->block_found_map,
+                                                           *block_nr);
+                               ext2fs_block_alloc_stats(fs, *block_nr, -1);
+                       }
                }
 
-               if ((blockcnt > 0) && c == cs->dup_cluster) {
-                       new_block = cs->alloc_block;
-                       goto got_block;
-               }
                cs->dup_cluster = c;
 
                retval = ext2fs_new_block2(fs, 0, ctx->block_found_map,
@@ -765,10 +783,15 @@ static int clone_file_block(ext2_filsys fs,
                printf("Cloning block #%lld from %llu to %llu\n",
                       blockcnt, *block_nr, new_block);
 #endif
-               retval = io_channel_read_blk64(fs->io, *block_nr, 1, cs->buf);
-               if (retval) {
-                       cs->errcode = retval;
-                       return BLOCK_ABORT;
+               if (ctx->clone == E2F_CLONE_ZERO) {
+                       memset(cs->buf, 0, fs->blocksize);
+               } else {
+                       retval = io_channel_read_blk64(fs->io, *block_nr, 1,
+                                                      cs->buf);
+                       if (retval) {
+                               cs->errcode = retval;
+                               return BLOCK_ABORT;
+                       }
                }
                retval = io_channel_write_blk64(fs->io, new_block, 1, cs->buf);
                if (retval) {
@@ -799,7 +822,7 @@ static int clone_file(e2fsck_t ctx, ext2_ino_t ino,
        clear_problem_context(&pctx);
        cs.errcode = 0;
        cs.dir = 0;
-       cs.dup_cluster = 0;
+       cs.dup_cluster = ~0;
        cs.alloc_block = 0;
        cs.ctx = ctx;
        retval = ext2fs_get_mem(fs->blocksize, &cs.buf);