e2fsck_write_inode(ctx, ino, inode, source);
}
+/*
+ * Use the multiple-blocks reclamation code to fix alignment problems in
+ * a bigalloc filesystem. We want a logical cluster to map to *only* one
+ * physical cluster, and we want the block offsets within that cluster to
+ * line up.
+ */
+static int has_unaligned_cluster_map(e2fsck_t ctx,
+ blk64_t last_pblk, e2_blkcnt_t last_lblk,
+ blk64_t pblk, blk64_t lblk)
+{
+ blk64_t cluster_mask;
+
+ if (!ctx->fs->cluster_ratio_bits)
+ return 0;
+ cluster_mask = EXT2FS_CLUSTER_MASK(ctx->fs);
+
+ /*
+ * If the block in the logical cluster doesn't align with the block in
+ * the physical cluster...
+ */
+ if ((lblk & cluster_mask) != (pblk & cluster_mask))
+ return 1;
+
+ /*
+ * If we cross a physical cluster boundary within a logical cluster...
+ */
+ if (last_pblk && (lblk & cluster_mask) != 0 &&
+ EXT2FS_B2C(ctx->fs, lblk) == EXT2FS_B2C(ctx->fs, last_lblk) &&
+ EXT2FS_B2C(ctx->fs, pblk) != EXT2FS_B2C(ctx->fs, last_pblk))
+ return 1;
+
+ return 0;
+}
+
static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
struct process_block_struct *pb,
blk64_t start_block, blk64_t end_block,
mark_block_used(ctx, blk);
pb->num_blocks++;
}
-
+ if (has_unaligned_cluster_map(ctx, pb->previous_block,
+ pb->last_block, blk,
+ blockcnt)) {
+ pctx->blk = blockcnt;
+ pctx->blk2 = blk;
+ fix_problem(ctx, PR_1_MISALIGNED_CLUSTER, pctx);
+ mark_block_used(ctx, blk);
+ mark_block_used(ctx, blk);
+ }
+ pb->last_block = blockcnt;
pb->previous_block = blk;
if (is_dir) {
((unsigned) blockcnt & EXT2FS_CLUSTER_MASK(ctx->fs)))) {
mark_block_used(ctx, blk);
p->num_blocks++;
+ } else if (has_unaligned_cluster_map(ctx, p->previous_block,
+ p->last_block, blk, blockcnt)) {
+ pctx->blk = blockcnt;
+ pctx->blk2 = blk;
+ fix_problem(ctx, PR_1_MISALIGNED_CLUSTER, pctx);
+ mark_block_used(ctx, blk);
+ mark_block_used(ctx, blk);
}
if (blockcnt >= 0)
p->last_block = blockcnt;
e2fsck_t ctx;
ext2_ino_t ino;
int dup_blocks;
- blk64_t cur_cluster;
+ blk64_t cur_cluster, phys_cluster;
struct ext2_inode *inode;
struct problem_context *pctx;
};
pb.dup_blocks = 0;
pb.inode = &inode;
pb.cur_cluster = ~0;
+ pb.phys_cluster = ~0;
if (ext2fs_inode_has_valid_blocks2(fs, &inode) ||
(ino == EXT2_BAD_INO))
{
struct process_block_struct *p;
e2fsck_t ctx;
- blk64_t lc;
+ blk64_t lc, pc;
if (HOLE_BLKADDR(*block_nr))
return 0;
p = (struct process_block_struct *) priv_data;
ctx = p->ctx;
lc = EXT2FS_B2C(fs, blockcnt);
+ pc = EXT2FS_B2C(fs, *block_nr);
if (!ext2fs_test_block_bitmap2(ctx->block_dup_map, *block_nr))
goto finish;
p->dup_blocks++;
ext2fs_mark_inode_bitmap2(inode_dup_map, p->ino);
- if (lc != p->cur_cluster)
+ /*
+ * Qualifications for submitting a block for duplicate processing:
+ * It's an extent/indirect block (and has a negative logical offset);
+ * we've crossed a logical cluster boundary; or the physical cluster
+ * suddenly changed, which indicates that blocks in a logical cluster
+ * are mapped to multiple physical clusters.
+ */
+ if (blockcnt < 0 || lc != p->cur_cluster || pc != p->phys_cluster)
add_dupe(ctx, p->ino, EXT2FS_B2C(fs, *block_nr), p->inode);
finish:
p->cur_cluster = lc;
+ p->phys_cluster = pc;
return 0;
}
pctx.dir = t->dir;
fix_problem(ctx, PR_1D_DUP_FILE_LIST, &pctx);
}
- if (file_ok) {
+ /*
+ * Even if the file shares blocks with itself, we still need to
+ * clone the blocks.
+ */
+ if (file_ok && (meta_data ? shared_len+1 : shared_len) != 0) {
fix_problem(ctx, PR_1D_DUP_BLOCKS_DEALT, &pctx);
continue;
}
errcode_t errcode;
blk64_t dup_cluster;
blk64_t alloc_block;
- ext2_ino_t dir;
+ ext2_ino_t dir, ino;
char *buf;
e2fsck_t ctx;
+ struct ext2_inode *inode;
};
static int clone_file_block(ext2_filsys fs,
decrement_badcount(ctx, *block_nr, p);
cs->dup_cluster = c;
-
+ /*
+ * Let's try an implied cluster allocation. If we get the same
+ * cluster back, then we need to find a new block; otherwise,
+ * we're merely fixing the problem of one logical cluster being
+ * mapped to multiple physical clusters.
+ */
+ new_block = 0;
+ retval = ext2fs_map_cluster_block(fs, cs->ino, cs->inode,
+ blockcnt, &new_block);
+ if (retval == 0 && new_block != 0 &&
+ EXT2FS_B2C(ctx->fs, new_block) !=
+ EXT2FS_B2C(ctx->fs, *block_nr))
+ goto cluster_alloc_ok;
retval = ext2fs_new_block2(fs, 0, ctx->block_found_map,
&new_block);
if (retval) {
cs->errcode = retval;
return BLOCK_ABORT;
}
+cluster_alloc_ok:
cs->alloc_block = new_block;
got_block:
cs.dup_cluster = ~0;
cs.alloc_block = 0;
cs.ctx = ctx;
+ cs.ino = ino;
+ cs.inode = &dp->inode;
retval = ext2fs_get_mem(fs->blocksize, &cs.buf);
if (retval)
return retval;
N_("@d @i %i has @x marked uninitialized at @b %c. "),
PROMPT_FIX, PR_PREEN_OK },
+ /* Inode logical block (physical block ) is misaligned. */
+ { PR_1_MISALIGNED_CLUSTER,
+ N_("@i %i logical @b %b (physical @b %c) violates cluster allocation rules.\nWill fix in pass 1B.\n"),
+ PROMPT_NONE, 0 },
+
/* Pass 1b errors */
/* Pass 1B: Rescan for duplicate/bad blocks */
/* uninit directory block */
#define PR_1_UNINIT_DBLOCK 0x010073
+/* Inode logical block is misaligned */
+#define PR_1_MISALIGNED_CLUSTER 0x010074
+
/*
* Pass 1b errors
*/