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;
e2fsck_t ctx;
ext2_ino_t ino;
int dup_blocks;
+ blk64_t cur_cluster;
struct ext2_inode *inode;
struct problem_context *pctx;
};
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;
pb.ino = ino;
pb.dup_blocks = 0;
pb.inode = &inode;
+ pb.cur_cluster = ~0;
- if (ext2fs_inode_has_valid_blocks(&inode) ||
+ if (ext2fs_inode_has_valid_blocks2(fs, &inode) ||
(ino == EXT2_BAD_INO))
pctx.errcode = ext2fs_block_iterate3(fs, ino,
BLOCK_FLAG_READ_ONLY, block_buf,
process_pass1b_block, &pb);
/* If the feature is not set, attrs will be cleared later anyway */
if ((fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) &&
- ext2fs_file_acl_block(&inode)) {
- blk64_t blk = ext2fs_file_acl_block(&inode);
+ ext2fs_file_acl_block(fs, &inode)) {
+ blk64_t blk = ext2fs_file_acl_block(fs, &inode);
process_pass1b_block(fs, &blk,
BLOCK_COUNT_EXTATTR, 0, 0, &pb);
- ext2fs_file_acl_block_set(&inode, blk);
+ ext2fs_file_acl_block_set(fs, &inode, blk);
}
if (pb.dup_blocks) {
end_problem_latch(ctx, PR_LATCH_DBLOCK);
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) {
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;
}
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)
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;
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"),
ext2fs_block_alloc_stats2(fs, *block_nr, -1);
pb->dup_blocks++;
}
+ pb->cur_cluster = lc;
return 0;
}
{
ext2_filsys fs = ctx->fs;
struct process_block_struct pb;
- struct ext2_inode inode;
struct problem_context pctx;
unsigned int count;
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_blocks(&inode))
- pctx.errcode = ext2fs_block_iterate3(fs, ino, BLOCK_FLAG_READ_ONLY,
- block_buf, delete_file_block, &pb);
+ if (ext2fs_inode_has_valid_blocks2(fs, &dp->inode))
+ pctx.errcode = ext2fs_block_iterate3(fs, ino,
+ BLOCK_FLAG_READ_ONLY,
+ block_buf,
+ delete_file_block, &pb);
if (pctx.errcode)
fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx);
if (ctx->inode_bad_map)
ext2fs_unmark_inode_bitmap2(ctx->inode_bad_map, ino);
- ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
- quota_data_sub(ctx->qctx, &inode, ino, pb.dup_blocks * fs->blocksize);
- quota_data_inodes(ctx->qctx, &inode, ino, -1);
+ ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(dp->inode.i_mode));
+ quota_data_sub(ctx->qctx, &dp->inode, ino,
+ pb.dup_blocks * fs->blocksize);
+ quota_data_inodes(ctx->qctx, &dp->inode, ino, -1);
/* Inode may have changed by block_iterate, so reread it */
- e2fsck_read_inode(ctx, ino, &inode, "delete_file");
- e2fsck_clear_inode(ctx, ino, &inode, 0, "delete_file");
- if (ext2fs_file_acl_block(&inode) &&
+ e2fsck_read_inode(ctx, ino, &dp->inode, "delete_file");
+ e2fsck_clear_inode(ctx, ino, &dp->inode, 0, "delete_file");
+ if (ext2fs_file_acl_block(fs, &dp->inode) &&
(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
count = 1;
- pctx.errcode = ext2fs_adjust_ea_refcount2(fs,
- ext2fs_file_acl_block(&inode),
- block_buf, -1, &count);
+ pctx.errcode = ext2fs_adjust_ea_refcount3(fs,
+ ext2fs_file_acl_block(fs, &dp->inode),
+ block_buf, -1, &count, ino);
if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) {
pctx.errcode = 0;
count = 1;
}
if (pctx.errcode) {
- pctx.blk = ext2fs_file_acl_block(&inode);
+ pctx.blk = ext2fs_file_acl_block(fs, &dp->inode);
fix_problem(ctx, PR_1B_ADJ_EA_REFCOUNT, &pctx);
}
/*
*/
if ((count == 0) ||
ext2fs_test_block_bitmap2(ctx->block_dup_map,
- ext2fs_file_acl_block(&inode))) {
- blk64_t blk = ext2fs_file_acl_block(&inode);
+ ext2fs_file_acl_block(fs, &dp->inode))) {
+ blk64_t blk = ext2fs_file_acl_block(fs, &dp->inode);
delete_file_block(fs, &blk,
BLOCK_COUNT_EXTATTR, 0, 0, &pb);
- ext2fs_file_acl_block_set(&inode, blk);
- quota_data_sub(ctx->qctx, &inode, ino, fs->blocksize);
+ ext2fs_file_acl_block_set(fs, &dp->inode, blk);
+ quota_data_sub(ctx->qctx, &dp->inode, ino, fs->blocksize);
}
}
}
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) {
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 ((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,
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);
pctx.ino = ino;
pctx.str = "clone_file";
- if (ext2fs_inode_has_valid_blocks(&dp->inode))
+ if (ext2fs_inode_has_valid_blocks2(fs, &dp->inode))
pctx.errcode = ext2fs_block_iterate3(fs, ino, 0, block_buf,
clone_file_block, &cs);
ext2fs_mark_bb_dirty(fs);
}
/* The inode may have changed on disk, so we have to re-read it */
e2fsck_read_inode(ctx, ino, &dp->inode, "clone file EA");
- blk = ext2fs_file_acl_block(&dp->inode);
+ blk = ext2fs_file_acl_block(fs, &dp->inode);
new_blk = blk;
if (blk && (clone_file_block(fs, &new_blk,
BLOCK_COUNT_EXTATTR, 0, 0, &cs) ==
BLOCK_CHANGED)) {
- ext2fs_file_acl_block_set(&dp->inode, new_blk);
+ ext2fs_file_acl_block_set(fs, &dp->inode, new_blk);
e2fsck_write_inode(ctx, ino, &dp->inode, "clone file EA");
/*
* If we cloned the EA block, find all other inodes
goto errout;
}
di = (struct dup_inode *) dnode_get(n);
- if (ext2fs_file_acl_block(&di->inode) == blk) {
- ext2fs_file_acl_block_set(&di->inode,
- ext2fs_file_acl_block(&dp->inode));
+ if (ext2fs_file_acl_block(fs, &di->inode) == blk) {
+ ext2fs_file_acl_block_set(fs, &di->inode,
+ ext2fs_file_acl_block(fs, &dp->inode));
e2fsck_write_inode(ctx, ino_el->inode,
&di->inode, "clone file EA");
decrement_badcount(ctx, blk, dc);