pctx->num = entry->e_value_inum;
if (fix_problem(ctx, PR_1_ATTR_SET_EA_INODE_FL, pctx)) {
inode.i_flags |= EXT4_EA_INODE_FL;
+ e2fsck_pass1_fix_lock(ctx);
ext2fs_write_inode(ctx->fs, entry->e_value_inum,
&inode);
+ e2fsck_pass1_fix_unlock(ctx);
} else {
return PR_1_ATTR_NO_EA_INODE_FL;
}
}
+static _INLINE_ int is_blocks_used(e2fsck_t ctx, blk64_t block,
+ unsigned int num)
+{
+ int retval;
+
+ /* used to avoid duplicate output from below */
+ retval = ext2fs_test_block_bitmap_range2_valid(ctx->block_found_map,
+ block, num);
+ if (!retval)
+ return 0;
+
+ retval = ext2fs_test_block_bitmap_range2(ctx->block_found_map, block, num);
+ if (retval) {
+ e2fsck_pass1_block_map_r_lock(ctx);
+ if (ctx->global_ctx)
+ retval = ext2fs_test_block_bitmap_range2(
+ ctx->global_ctx->block_found_map, block, num);
+ e2fsck_pass1_block_map_r_unlock(ctx);
+ if (retval)
+ return 0;
+ }
+
+ return 1;
+}
+
/*
* Check to see if the inode might really be a directory, despite i_mode
*
LINUX_S_ISLNK(inode->i_mode) || inode->i_block[0] == 0)
return;
- /*
+ /*
* Check the block numbers in the i_block array for validity:
* zero blocks are skipped (but the first one cannot be zero -
* see above), other blocks are checked against the first and
* max data blocks (from the the superblock) and against the
* block bitmap. Any invalid block found means this cannot be
* a directory.
- *
+ *
* If there are non-zero blocks past the fourth entry, then
* this cannot be a device file: we remember that for the next
* check.
if (blk < ctx->fs->super->s_first_data_block ||
blk >= ext2fs_blocks_count(ctx->fs->super) ||
- ext2fs_fast_test_block_bitmap2(ctx->block_found_map,
- blk))
+ is_blocks_used(ctx, blk, 1))
return; /* Invalid block, can't be dir */
}
blk = inode->i_block[0];
if (!fix_problem(ctx, PR_1_INODE_ONLY_CSUM_INVALID, pctx))
return 0;
+
+ e2fsck_pass1_fix_lock(ctx);
retval = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
sizeof(inode));
+ e2fsck_pass1_fix_unlock(ctx);
return retval;
}
return;
ext2fs_mark_block_bitmap2(ctx->block_found_map, blk);
ctx->lnf_repair_block = blk;
+ return;
}
static errcode_t get_inline_data_ea_size(ext2_filsys fs, ext2_ino_t ino,
return 0;
}
+static void init_ext2_max_sizes()
+{
+ int i;
+ __u64 max_sizes;
+
+ /*
+ * Init ext2_max_sizes which will be immutable and shared between
+ * threads
+ */
+#define EXT2_BPP(bits) (1ULL << ((bits) - 2))
+
+ for (i = EXT2_MIN_BLOCK_LOG_SIZE; i <= EXT2_MAX_BLOCK_LOG_SIZE; i++) {
+ max_sizes = EXT2_NDIR_BLOCKS + EXT2_BPP(i);
+ max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i);
+ max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i) * EXT2_BPP(i);
+ max_sizes = (max_sizes * (1UL << i));
+ ext2_max_sizes[i - EXT2_MIN_BLOCK_LOG_SIZE] = max_sizes;
+ }
+#undef EXT2_BPP
+}
+
+#ifdef HAVE_PTHREAD
+/* TODO: tdb needs to be handled properly for multiple threads*/
+static int multiple_threads_supported(e2fsck_t ctx)
+{
+#ifdef CONFIG_TDB
+ unsigned int threshold;
+ ext2_ino_t num_dirs;
+ errcode_t retval;
+ char *tdb_dir;
+ int enable;
+
+ profile_get_string(ctx->profile, "scratch_files", "directory", 0, 0,
+ &tdb_dir);
+ profile_get_uint(ctx->profile, "scratch_files",
+ "numdirs_threshold", 0, 0, &threshold);
+ profile_get_boolean(ctx->profile, "scratch_files",
+ "icount", 0, 1, &enable);
+
+ retval = ext2fs_get_num_dirs(ctx->fs, &num_dirs);
+ if (retval)
+ num_dirs = 1024; /* Guess */
+
+ /* tdb is unsupported now */
+ if (enable && tdb_dir && !access(tdb_dir, W_OK) &&
+ (!threshold || num_dirs > threshold))
+ return 0;
+#endif
+ return 1;
+}
+
+/**
+ * Even though we could specify number of threads,
+ * but it might be more than the whole filesystem
+ * block groups, correct it here.
+ */
+static void e2fsck_pass1_set_thread_num(e2fsck_t ctx)
+{
+ unsigned flexbg_size = 1;
+ ext2_filsys fs = ctx->fs;
+ int num_threads = ctx->fs_num_threads;
+ int max_threads;
+
+ if (num_threads < 1) {
+ num_threads = 1;
+ goto out;
+ }
+
+ if (!multiple_threads_supported(ctx)) {
+ num_threads = 1;
+ fprintf(stderr, "Fall through single thread for pass1 "
+ "because tdb could not handle properly\n");
+ goto out;
+ }
+
+ if (ext2fs_has_feature_flex_bg(fs->super))
+ flexbg_size = 1 << fs->super->s_log_groups_per_flex;
+ max_threads = fs->group_desc_count / flexbg_size;
+ if (max_threads == 0)
+ max_threads = 1;
+
+ if (num_threads > max_threads) {
+ fprintf(stderr, "Use max possible thread num: %d instead\n",
+ max_threads);
+ num_threads = max_threads;
+ }
+out:
+ ctx->fs_num_threads = num_threads;
+}
+#endif
+
+/*
+ * We need call mark_table_blocks() before multiple
+ * thread start, since all known system blocks should be
+ * marked and checked later.
+ */
+static errcode_t e2fsck_pass1_prepare(e2fsck_t ctx)
+{
+ struct problem_context pctx;
+ ext2_filsys fs = ctx->fs;
+
+ init_ext2_max_sizes();
+#ifdef HAVE_PTHREAD
+ e2fsck_pass1_set_thread_num(ctx);
+#endif
+
+ clear_problem_context(&pctx);
+ if (!(ctx->options & E2F_OPT_PREEN))
+ fix_problem(ctx, PR_1_PASS_HEADER, &pctx);
+
+ pctx.errcode = e2fsck_allocate_subcluster_bitmap(ctx->fs,
+ _("in-use block map"), EXT2FS_BMAP64_RBTREE,
+ "block_found_map", &ctx->block_found_map);
+ if (pctx.errcode) {
+ pctx.num = 1;
+ fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return pctx.errcode;
+ }
+ pctx.errcode = e2fsck_allocate_block_bitmap(ctx->fs,
+ _("metadata block map"), EXT2FS_BMAP64_RBTREE,
+ "block_metadata_map", &ctx->block_metadata_map);
+ if (pctx.errcode) {
+ pctx.num = 1;
+ fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return pctx.errcode;
+ }
+
+ mark_table_blocks(ctx);
+ pctx.errcode = ext2fs_convert_subcluster_bitmap(ctx->fs,
+ &ctx->block_found_map);
+ if (pctx.errcode) {
+ fix_problem(ctx, PR_1_CONVERT_SUBCLUSTER, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return pctx.errcode;
+ }
+
+ pctx.errcode = e2fsck_allocate_block_bitmap(ctx->fs,
+ _("multiply claimed block map"),
+ EXT2FS_BMAP64_RBTREE, "block_dup_map",
+ &ctx->block_dup_map);
+ if (pctx.errcode) {
+ pctx.num = 3;
+ fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR,
+ &pctx);
+ /* Should never get here */
+ ctx->flags |= E2F_FLAG_ABORT;
+ return pctx.errcode;
+ }
+
+ if (ext2fs_has_feature_mmp(fs->super) &&
+ fs->super->s_mmp_block > fs->super->s_first_data_block &&
+ fs->super->s_mmp_block < ext2fs_blocks_count(fs->super))
+ ext2fs_mark_block_bitmap2(ctx->block_found_map,
+ fs->super->s_mmp_block);
+#ifdef HAVE_PTHREAD
+ pthread_mutex_init(&ctx->fs_fix_mutex, NULL);
+ pthread_rwlock_init(&ctx->fs_block_map_rwlock, NULL);
+#endif
+
+ return 0;
+}
+
+static void e2fsck_pass1_post(e2fsck_t ctx)
+{
+ struct problem_context pctx;
+ ext2_filsys fs = ctx->fs;
+
+ char *block_buf =
+ (char *)e2fsck_allocate_memory(ctx, ctx->fs->blocksize * 3,
+ "block interate buffer");
+ reserve_block_for_root_repair(ctx);
+ reserve_block_for_lnf_repair(ctx);
+
+ /*
+ * If any extended attribute blocks' reference counts need to
+ * be adjusted, either up (ctx->refcount_extra), or down
+ * (ctx->refcount), then fix them.
+ */
+ if (ctx->refcount) {
+ adjust_extattr_refcount(ctx, ctx->refcount, block_buf, -1);
+ ea_refcount_free(ctx->refcount);
+ ctx->refcount = 0;
+ }
+ if (ctx->refcount_extra) {
+ adjust_extattr_refcount(ctx, ctx->refcount_extra,
+ block_buf, +1);
+ ea_refcount_free(ctx->refcount_extra);
+ ctx->refcount_extra = 0;
+ }
+
+ if (ctx->invalid_bitmaps)
+ handle_fs_bad_blocks(ctx);
+
+ /* We don't need the block_ea_map any more */
+ if (ctx->block_ea_map) {
+ ext2fs_free_block_bitmap(ctx->block_ea_map);
+ ctx->block_ea_map = 0;
+ }
+
+ if (ctx->flags & E2F_FLAG_RESIZE_INODE) {
+ struct ext2_inode *inode;
+ int inode_size = EXT2_INODE_SIZE(fs->super);
+ inode = e2fsck_allocate_memory(ctx, inode_size,
+ "scratch inode");
+
+ clear_problem_context(&pctx);
+ pctx.errcode = ext2fs_create_resize_inode(fs);
+ if (pctx.errcode) {
+ if (!fix_problem(ctx, PR_1_RESIZE_INODE_CREATE,
+ &pctx)) {
+ ctx->flags |= E2F_FLAG_ABORT;
+ ext2fs_free_mem(&inode);
+ ext2fs_free_mem(&block_buf);
+ return;
+ }
+ pctx.errcode = 0;
+ }
+ if (!pctx.errcode) {
+ e2fsck_read_inode(ctx, EXT2_RESIZE_INO, inode,
+ "recreate inode");
+ inode->i_mtime = ctx->now;
+ e2fsck_write_inode(ctx, EXT2_RESIZE_INO, inode,
+ "recreate inode");
+ }
+ ctx->flags &= ~E2F_FLAG_RESIZE_INODE;
+ ext2fs_free_mem(&inode);
+ }
+
+ if (ctx->flags & E2F_FLAG_RESTART) {
+ ext2fs_free_mem(&block_buf);
+ return;
+ }
+
+ if (ctx->block_dup_map) {
+ if (!(ctx->flags & E2F_FLAG_DUP_BLOCK)) {
+ ext2fs_free_mem(&block_buf);
+ return;
+ }
+ if (ctx->options & E2F_OPT_PREEN) {
+ clear_problem_context(&pctx);
+ fix_problem(ctx, PR_1_DUP_BLOCKS_PREENSTOP, &pctx);
+ }
+ e2fsck_pass1_dupblocks(ctx, block_buf);
+ ext2fs_free_mem(&block_buf);
+ ctx->flags &= ~E2F_FLAG_DUP_BLOCK;
+ }
+}
+
+
void e2fsck_pass1_run(e2fsck_t ctx)
{
int i;
ctx->readahead_kb = e2fsck_guess_readahead(ctx->fs);
pass1_readahead(ctx, &ra_group, &ino_threshold);
- if (!(ctx->options & E2F_OPT_PREEN))
- fix_problem(ctx, PR_1_PASS_HEADER, &pctx);
-
if (ext2fs_has_feature_dir_index(fs->super) &&
!(ctx->options & E2F_OPT_NO)) {
if (ext2fs_u32_list_create(&ctx->dirs_to_hash, 50))
ctx->flags |= E2F_FLAG_ABORT;
return;
}
- pctx.errcode = e2fsck_allocate_subcluster_bitmap(fs,
- _("in-use block map"), EXT2FS_BMAP64_RBTREE,
- "block_found_map", &ctx->block_found_map);
- if (pctx.errcode) {
- pctx.num = 1;
- fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx);
- ctx->flags |= E2F_FLAG_ABORT;
- return;
- }
- pctx.errcode = e2fsck_allocate_block_bitmap(fs,
- _("metadata block map"), EXT2FS_BMAP64_RBTREE,
- "block_metadata_map", &ctx->block_metadata_map);
- if (pctx.errcode) {
- pctx.num = 1;
- fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx);
- ctx->flags |= E2F_FLAG_ABORT;
- return;
- }
if (casefold_fs) {
pctx.errcode =
e2fsck_allocate_inode_bitmap(fs,
}
}
- mark_table_blocks(ctx);
- pctx.errcode = ext2fs_convert_subcluster_bitmap(fs,
- &ctx->block_found_map);
- if (pctx.errcode) {
- fix_problem(ctx, PR_1_CONVERT_SUBCLUSTER, &pctx);
- ctx->flags |= E2F_FLAG_ABORT;
- goto endit;
- }
block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 3,
"block interate buffer");
if (EXT2_INODE_SIZE(fs->super) == EXT2_GOOD_OLD_INODE_SIZE)
fs->super->s_mkfs_time < fs->super->s_inodes_count))
low_dtime_check = 0;
- if (ext2fs_has_feature_mmp(fs->super) &&
- fs->super->s_mmp_block > fs->super->s_first_data_block &&
- fs->super->s_mmp_block < ext2fs_blocks_count(fs->super))
- ext2fs_mark_block_bitmap2(ctx->block_found_map,
- fs->super->s_mmp_block);
-
/* Set up ctx->lost_and_found if possible */
(void) e2fsck_get_lost_and_found(ctx, 0);
pctx.errcode = get_inline_data_ea_size(fs, ino, &size);
if (!pctx.errcode &&
fix_problem(ctx, PR_1_INLINE_DATA_FEATURE, &pctx)) {
+ e2fsck_pass1_fix_lock(ctx);
ext2fs_set_feature_inline_data(sb);
ext2fs_mark_super_dirty(fs);
+ e2fsck_pass1_fix_unlock(ctx);
inlinedata_fs = 1;
} else if (fix_problem(ctx, PR_1_INLINE_DATA_SET, &pctx)) {
e2fsck_clear_inode(ctx, ino, inode, 0, "pass1");
if ((ext2fs_extent_header_verify(inode->i_block,
sizeof(inode->i_block)) == 0) &&
fix_problem(ctx, PR_1_EXTENT_FEATURE, &pctx)) {
+ e2fsck_pass1_fix_lock(ctx);
ext2fs_set_feature_extents(sb);
ext2fs_mark_super_dirty(fs);
extent_fs = 1;
+ e2fsck_pass1_fix_unlock(ctx);
} else if (fix_problem(ctx, PR_1_EXTENTS_SET, &pctx)) {
clear_inode:
e2fsck_clear_inode(ctx, ino, inode, 0, "pass1");
failed_csum = 0;
}
- pctx.errcode = ext2fs_copy_bitmap(ctx->block_found_map,
- &pb.fs_meta_blocks);
+ e2fsck_pass1_block_map_r_lock(ctx);
+ pctx.errcode = ext2fs_copy_bitmap(ctx->global_ctx ?
+ ctx->global_ctx->block_found_map :
+ ctx->block_found_map, &pb.fs_meta_blocks);
+ e2fsck_pass1_block_map_r_unlock(ctx);
if (pctx.errcode) {
pctx.num = 4;
fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx);
ext2fs_close_inode_scan(scan);
scan = NULL;
- reserve_block_for_root_repair(ctx);
- reserve_block_for_lnf_repair(ctx);
-
- /*
- * If any extended attribute blocks' reference counts need to
- * be adjusted, either up (ctx->refcount_extra), or down
- * (ctx->refcount), then fix them.
- */
- if (ctx->refcount) {
- adjust_extattr_refcount(ctx, ctx->refcount, block_buf, -1);
- ea_refcount_free(ctx->refcount);
- ctx->refcount = 0;
- }
- if (ctx->refcount_extra) {
- adjust_extattr_refcount(ctx, ctx->refcount_extra,
- block_buf, +1);
- ea_refcount_free(ctx->refcount_extra);
- ctx->refcount_extra = 0;
- }
-
if (ctx->ea_block_quota_blocks) {
ea_refcount_free(ctx->ea_block_quota_blocks);
ctx->ea_block_quota_blocks = 0;
ctx->ea_block_quota_inodes = 0;
}
- if (ctx->invalid_bitmaps)
- handle_fs_bad_blocks(ctx);
-
- /* We don't need the block_ea_map any more */
- if (ctx->block_ea_map) {
- ext2fs_free_block_bitmap(ctx->block_ea_map);
- ctx->block_ea_map = 0;
- }
-
/* We don't need the encryption policy => ID map any more */
destroy_encryption_policy_map(ctx);
- if (ctx->flags & E2F_FLAG_RESIZE_INODE) {
- clear_problem_context(&pctx);
- pctx.errcode = ext2fs_create_resize_inode(fs);
- if (pctx.errcode) {
- if (!fix_problem(ctx, PR_1_RESIZE_INODE_CREATE,
- &pctx)) {
- ctx->flags |= E2F_FLAG_ABORT;
- goto endit;
- }
- pctx.errcode = 0;
- }
- if (!pctx.errcode) {
- e2fsck_read_inode(ctx, EXT2_RESIZE_INO, inode,
- "recreate inode");
- inode->i_mtime = ctx->now;
- e2fsck_write_inode(ctx, EXT2_RESIZE_INO, inode,
- "recreate inode");
- }
- ctx->flags &= ~E2F_FLAG_RESIZE_INODE;
- }
-
if (ctx->flags & E2F_FLAG_RESTART) {
/*
* Only the master copy of the superblock and block
}
}
- if (ctx->block_dup_map) {
- if (ctx->options & E2F_OPT_PREEN) {
- clear_problem_context(&pctx);
- fix_problem(ctx, PR_1_DUP_BLOCKS_PREENSTOP, &pctx);
- }
- e2fsck_pass1_dupblocks(ctx, block_buf);
- }
ctx->flags |= E2F_FLAG_ALLOC_OK;
endit:
e2fsck_use_inode_shortcuts(ctx, 0);
ctx->invalid_bitmaps++;
}
-static void init_ext2_max_sizes()
-{
- int i;
- __u64 max_sizes;
-
- /*
- * Init ext2_max_sizes which will be immutable and shared between
- * threads
- */
-#define EXT2_BPP(bits) (1ULL << ((bits) - 2))
-
- for (i = EXT2_MIN_BLOCK_LOG_SIZE; i <= EXT2_MAX_BLOCK_LOG_SIZE; i++) {
- max_sizes = EXT2_NDIR_BLOCKS + EXT2_BPP(i);
- max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i);
- max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i) * EXT2_BPP(i);
- max_sizes = (max_sizes * (1UL << i));
- ext2_max_sizes[i - EXT2_MIN_BLOCK_LOG_SIZE] = max_sizes;
- }
-#undef EXT2_BPP
-}
-
#ifdef HAVE_PTHREAD
static errcode_t e2fsck_pass1_copy_bitmap(ext2_filsys fs, ext2fs_generic_bitmap *src,
ext2fs_generic_bitmap *dest)
ext2fs_block_bitmap block_map;
ext2_badblocks_list badblocks;
ext2_dblist dblist;
+ int flags;
dest_io = dest->io;
dest_image_io = dest->image_io;
block_map = dest->block_map;
badblocks = dest->badblocks;
dblist = dest->dblist;
+ flags = dest->flags;
memcpy(dest, src, sizeof(struct struct_ext2_filsys));
dest->io = dest_io;
dest->dblist = dblist;
if (dest->dblist)
dest->dblist->fs = dest;
+ dest->flags = src->flags | flags;
+ if (!(src->flags & EXT2_FLAG_VALID) || !(flags & EXT2_FLAG_VALID))
+ ext2fs_unmark_valid(dest);
if (src->icache) {
ext2fs_free_inode_cache(src->icache);
return retval;
}
+static void e2fsck_pass1_copy_invalid_bitmaps(e2fsck_t global_ctx,
+ e2fsck_t thread_ctx)
+{
+ dgrp_t i, j;
+ dgrp_t grp_start = thread_ctx->thread_info.et_group_start;
+ dgrp_t grp_end = thread_ctx->thread_info.et_group_end;
+ dgrp_t total = grp_end - grp_start;
+
+ thread_ctx->invalid_inode_bitmap_flag =
+ e2fsck_allocate_memory(global_ctx, sizeof(int) * total,
+ "invalid_inode_bitmap");
+ thread_ctx->invalid_block_bitmap_flag =
+ e2fsck_allocate_memory(global_ctx, sizeof(int) * total,
+ "invalid_block_bitmap");
+ thread_ctx->invalid_inode_table_flag =
+ e2fsck_allocate_memory(global_ctx, sizeof(int) * total,
+ "invalid_inode_table");
+
+ memcpy(thread_ctx->invalid_block_bitmap_flag,
+ &global_ctx->invalid_block_bitmap_flag[grp_start],
+ total * sizeof(int));
+ memcpy(thread_ctx->invalid_inode_bitmap_flag,
+ &global_ctx->invalid_inode_bitmap_flag[grp_start],
+ total * sizeof(int));
+ memcpy(thread_ctx->invalid_inode_table_flag,
+ &global_ctx->invalid_inode_table_flag[grp_start],
+ total * sizeof(int));
+
+ thread_ctx->invalid_bitmaps = 0;
+ for (i = grp_start, j = 0; i < grp_end; i++, j++) {
+ if (thread_ctx->invalid_block_bitmap_flag[j])
+ thread_ctx->invalid_bitmaps++;
+ if (thread_ctx->invalid_inode_bitmap_flag[j])
+ thread_ctx->invalid_bitmaps++;
+ if (thread_ctx->invalid_inode_table_flag[j])
+ thread_ctx->invalid_bitmaps++;
+ }
+}
+
+static void e2fsck_pass1_merge_invalid_bitmaps(e2fsck_t global_ctx,
+ e2fsck_t thread_ctx)
+{
+ dgrp_t i, j;
+ dgrp_t grp_start = thread_ctx->thread_info.et_group_start;
+ dgrp_t grp_end = thread_ctx->thread_info.et_group_end;
+ dgrp_t total = grp_end - grp_start;
+
+ memcpy(&global_ctx->invalid_block_bitmap_flag[grp_start],
+ thread_ctx->invalid_block_bitmap_flag, total * sizeof(int));
+ memcpy(&global_ctx->invalid_inode_bitmap_flag[grp_start],
+ thread_ctx->invalid_inode_bitmap_flag, total * sizeof(int));
+ memcpy(&global_ctx->invalid_inode_table_flag[grp_start],
+ thread_ctx->invalid_inode_table_flag, total * sizeof(int));
+ global_ctx->invalid_bitmaps += thread_ctx->invalid_bitmaps;
+}
+
static errcode_t e2fsck_pass1_thread_prepare(e2fsck_t global_ctx, e2fsck_t *thread_ctx,
int thread_index, int num_threads)
{
assert(global_ctx->inode_reg_map == NULL);
assert(global_ctx->inodes_to_rebuild == NULL);
- assert(global_ctx->block_found_map == NULL);
- assert(global_ctx->block_dup_map == NULL);
+ assert(global_ctx->block_found_map != NULL);
+ assert(global_ctx->block_metadata_map != NULL);
+ assert(global_ctx->block_dup_map != NULL);
assert(global_ctx->block_ea_map == NULL);
- assert(global_ctx->block_metadata_map == NULL);
assert(global_ctx->fs->dblist == NULL);
retval = ext2fs_get_mem(sizeof(struct e2fsck_struct), &thread_context);
return retval;
}
memcpy(thread_context, global_ctx, sizeof(struct e2fsck_struct));
- thread_context->global_ctx = global_ctx;
+ thread_context->block_dup_map = NULL;
+
+ retval = e2fsck_allocate_block_bitmap(global_ctx->fs,
+ _("in-use block map"), EXT2FS_BMAP64_RBTREE,
+ "block_found_map", &thread_context->block_found_map);
+ if (retval)
+ goto out_context;
+ thread_context->global_ctx = global_ctx;
retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &thread_fs);
if (retval) {
com_err(global_ctx->program_name, retval, "while allocating memory");
log_out(thread_context, _("Scan group range [%d, %d)\n"),
tinfo->et_group_start, tinfo->et_group_end);
thread_context->fs = thread_fs;
+ retval = quota_init_context(&thread_context->qctx, thread_fs, 0);
+ if (retval) {
+ com_err(global_ctx->program_name, retval,
+ "while init quota context");
+ goto out_fs;
+ }
*thread_ctx = thread_context;
+ e2fsck_pass1_copy_invalid_bitmaps(global_ctx, thread_context);
return 0;
out_fs:
ext2fs_free_mem(&thread_fs);
out_context:
+ if (thread_context->block_found_map)
+ ext2fs_free_mem(&thread_context->block_found_map);
ext2fs_free_mem(&thread_context);
return retval;
}
global_ctx->dir_info);
}
+static void e2fsck_pass1_merge_dx_dir(e2fsck_t global_ctx, e2fsck_t thread_ctx)
+{
+ if (thread_ctx->dx_dir_info == NULL)
+ return;
+
+ if (global_ctx->dx_dir_info == NULL) {
+ global_ctx->dx_dir_info = thread_ctx->dx_dir_info;
+ global_ctx->dx_dir_info_size = thread_ctx->dx_dir_info_size;
+ global_ctx->dx_dir_info_count = thread_ctx->dx_dir_info_count;
+ thread_ctx->dx_dir_info = NULL;
+ return;
+ }
+
+ e2fsck_merge_dx_dir(global_ctx, thread_ctx);
+}
+
static inline errcode_t
e2fsck_pass1_merge_icount(ext2_icount_t *dest_icount,
ext2_icount_t *src_icount)
return ret;
}
+static errcode_t e2fsck_pass1_merge_dirs_to_hash(e2fsck_t global_ctx,
+ e2fsck_t thread_ctx)
+{
+ errcode_t retval = 0;
+
+ if (!thread_ctx->dirs_to_hash)
+ return 0;
+
+ if (!global_ctx->dirs_to_hash)
+ retval = ext2fs_badblocks_copy(thread_ctx->dirs_to_hash,
+ &global_ctx->dirs_to_hash);
+ else
+ retval = ext2fs_badblocks_merge(thread_ctx->dirs_to_hash,
+ global_ctx->dirs_to_hash);
+
+ return retval;
+}
+
+static errcode_t e2fsck_pass1_merge_ea_inode_refs(e2fsck_t global_ctx,
+ e2fsck_t thread_ctx)
+{
+ ea_value_t count;
+ blk64_t blk;
+ errcode_t retval;
+
+ if (!thread_ctx->ea_inode_refs)
+ return 0;
+
+ if (!global_ctx->ea_inode_refs) {
+ global_ctx->ea_inode_refs = thread_ctx->ea_inode_refs;
+ thread_ctx->ea_inode_refs = NULL;
+ return 0;
+ }
+
+ ea_refcount_intr_begin(thread_ctx->ea_inode_refs);
+ while (1) {
+ if ((blk = ea_refcount_intr_next(thread_ctx->ea_inode_refs,
+ &count)) == 0)
+ break;
+ if (!global_ctx->block_ea_map ||
+ !ext2fs_fast_test_block_bitmap2(global_ctx->block_ea_map,
+ blk)) {
+ retval = ea_refcount_store(global_ctx->ea_inode_refs,
+ blk, count);
+ if (retval)
+ return retval;
+ }
+ }
+
+ return retval;
+}
+
+static ea_value_t ea_refcount_usage(e2fsck_t ctx, blk64_t blk,
+ ea_value_t *orig)
+{
+ ea_value_t count_cur;
+ ea_value_t count_extra = 0;
+ ea_value_t count_orig;
+
+ ea_refcount_fetch(ctx->refcount_orig, blk, &count_orig);
+ ea_refcount_fetch(ctx->refcount, blk, &count_cur);
+ /* most of time this is not needed */
+ if (ctx->refcount_extra && count_cur == 0)
+ ea_refcount_fetch(ctx->refcount_extra, blk, &count_extra);
+
+ if (!count_orig)
+ count_orig = *orig;
+ else if (orig)
+ *orig = count_orig;
+
+ return count_orig + count_extra - count_cur;
+}
+
+static errcode_t e2fsck_pass1_merge_ea_refcount(e2fsck_t global_ctx,
+ e2fsck_t thread_ctx)
+{
+ ea_value_t count;
+ blk64_t blk;
+ errcode_t retval = 0;
+
+ if (!thread_ctx->refcount)
+ return 0;
+
+ if (!global_ctx->refcount) {
+ global_ctx->refcount = thread_ctx->refcount;
+ thread_ctx->refcount = NULL;
+ global_ctx->refcount_extra = thread_ctx->refcount;
+ thread_ctx->refcount_extra = NULL;
+ return 0;
+ }
+
+ ea_refcount_intr_begin(thread_ctx->refcount);
+ while (1) {
+ if ((blk = ea_refcount_intr_next(thread_ctx->refcount,
+ &count)) == 0)
+ break;
+ /**
+ * this EA has never seen before, so just store its
+ * refcount and refcount_extra into global_ctx if needed.
+ */
+ if (!global_ctx->block_ea_map ||
+ !ext2fs_fast_test_block_bitmap2(global_ctx->block_ea_map,
+ blk)) {
+ ea_value_t extra;
+
+ retval = ea_refcount_store(global_ctx->refcount,
+ blk, count);
+ if (retval)
+ return retval;
+
+ if (count > 0 || !thread_ctx->refcount_extra)
+ continue;
+ ea_refcount_fetch(thread_ctx->refcount_extra, blk,
+ &extra);
+ if (extra == 0)
+ continue;
+
+ if (!global_ctx->refcount_extra) {
+ retval = ea_refcount_create(0,
+ &global_ctx->refcount_extra);
+ if (retval)
+ return retval;
+ }
+ retval = ea_refcount_store(global_ctx->refcount_extra,
+ blk, extra);
+ if (retval)
+ return retval;
+ } else {
+ ea_value_t orig;
+ ea_value_t thread_usage;
+ ea_value_t global_usage;
+ ea_value_t new;
+
+ thread_usage = ea_refcount_usage(thread_ctx,
+ blk, &orig);
+ global_usage = ea_refcount_usage(global_ctx,
+ blk, &orig);
+ if (thread_usage + global_usage <= orig) {
+ new = orig - thread_usage - global_usage;
+ retval = ea_refcount_store(global_ctx->refcount,
+ blk, new);
+ if (retval)
+ return retval;
+ continue;
+ }
+ /* update it is as zero */
+ retval = ea_refcount_store(global_ctx->refcount,
+ blk, 0);
+ if (retval)
+ return retval;
+ /* Ooops, this EA was referenced more than it stated */
+ if (!global_ctx->refcount_extra) {
+ retval = ea_refcount_create(0,
+ &global_ctx->refcount_extra);
+ if (retval)
+ return retval;
+ }
+ new = global_usage + thread_usage - orig;
+ retval = ea_refcount_store(global_ctx->refcount_extra,
+ blk, new);
+ if (retval)
+ return retval;
+ }
+ }
+
+ return retval;
+}
+
static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctx)
{
errcode_t retval;
FILE *global_problem_logf = global_ctx->problem_logf;
ext2fs_inode_bitmap inode_bad_map = global_ctx->inode_bad_map;
struct dir_info_db *dir_info = global_ctx->dir_info;
+ struct dx_dir_info *dx_dir_info = global_ctx->dx_dir_info;
ext2fs_inode_bitmap inode_used_map = global_ctx->inode_used_map;
ext2fs_inode_bitmap inode_dir_map = global_ctx->inode_dir_map;
ext2fs_inode_bitmap inode_bb_map = global_ctx->inode_bb_map;
ext2fs_inode_bitmap inode_imagic_map = global_ctx->inode_imagic_map;
ext2fs_inode_bitmap inode_reg_map = global_ctx->inode_reg_map;
- ext2fs_block_bitmap block_found_map = global_ctx->block_found_map;
- ext2fs_block_bitmap block_dup_map = global_ctx->block_dup_map;
- ext2fs_block_bitmap block_ea_map = global_ctx->block_ea_map;
- ext2fs_block_bitmap block_metadata_map = global_ctx->block_metadata_map;
ext2fs_block_bitmap inodes_to_rebuild = global_ctx->inodes_to_rebuild;
ext2_icount_t inode_count = global_ctx->inode_count;
ext2_icount_t inode_link_info = global_ctx->inode_link_info;
+ __u32 fs_directory_count = global_ctx->fs_directory_count;
+ __u32 fs_regular_count = global_ctx->fs_regular_count;
+ __u32 fs_blockdev_count = global_ctx->fs_blockdev_count;
+ __u32 fs_chardev_count = global_ctx->fs_chardev_count;
+ __u32 fs_links_count = global_ctx->fs_links_count;
+ __u32 fs_symlinks_count = global_ctx->fs_symlinks_count;
+ __u32 fs_fast_symlinks_count = global_ctx->fs_fast_symlinks_count;
+ __u32 fs_fifo_count = global_ctx->fs_fifo_count;
+ __u32 fs_total_count = global_ctx->fs_total_count;
+ __u32 fs_badblocks_count = global_ctx->fs_badblocks_count;
+ __u32 fs_sockets_count = global_ctx->fs_sockets_count;
+ __u32 fs_ind_count = global_ctx->fs_ind_count;
+ __u32 fs_dind_count = global_ctx->fs_dind_count;
+ __u32 fs_tind_count = global_ctx->fs_tind_count;
+ __u32 fs_fragmented = global_ctx->fs_fragmented;
+ __u32 fs_fragmented_dir = global_ctx->fs_fragmented_dir;
+ __u32 large_files = global_ctx->large_files;
+ ext2_ino_t dx_dir_info_size = global_ctx->dx_dir_info_size;
+ ext2_ino_t dx_dir_info_count = global_ctx->dx_dir_info_count;
+ ext2_u32_list dirs_to_hash = global_ctx->dirs_to_hash;
+ quota_ctx_t qctx = global_ctx->qctx;
+ int *invalid_block_bitmap_flag = global_ctx->invalid_block_bitmap_flag;
+ int *invalid_inode_bitmap_flag = global_ctx->invalid_inode_bitmap_flag;
+ int *invalid_inode_table_flag = global_ctx->invalid_inode_table_flag;
+ int invalid_bitmaps = global_ctx->invalid_bitmaps;
+ ext2_refcount_t refcount = global_ctx->refcount;
+ ext2_refcount_t refcount_extra = global_ctx->refcount_extra;
+ ext2_refcount_t refcount_orig = global_ctx->refcount_orig;
+ ext2_refcount_t ea_block_quota_blocks = global_ctx->ea_block_quota_blocks;
+ ext2_refcount_t ea_block_quota_inodes = global_ctx->ea_block_quota_inodes;
+ ext2fs_block_bitmap block_ea_map = global_ctx->block_ea_map;
+ ext2_refcount_t ea_inode_refs = global_ctx->ea_inode_refs;
+ ext2fs_block_bitmap block_found_map = global_ctx->block_found_map;
+ ext2fs_block_bitmap block_dup_map = global_ctx->block_dup_map;
#ifdef HAVE_SETJMP_H
jmp_buf old_jmp;
global_ctx->inode_imagic_map = inode_imagic_map;
global_ctx->inodes_to_rebuild = inodes_to_rebuild;
global_ctx->inode_reg_map = inode_reg_map;
- global_ctx->block_found_map = block_found_map;
global_ctx->block_dup_map = block_dup_map;
- global_ctx->block_ea_map = block_ea_map;
- global_ctx->block_metadata_map = block_metadata_map;
+ global_ctx->block_found_map = block_found_map;
global_ctx->dir_info = dir_info;
e2fsck_pass1_merge_dir_info(global_ctx, thread_ctx);
+ global_ctx->dx_dir_info = dx_dir_info;
+ global_ctx->dx_dir_info_count = dx_dir_info_count;
+ global_ctx->dx_dir_info_size = dx_dir_info_size;
+ e2fsck_pass1_merge_dx_dir(global_ctx, thread_ctx);
global_ctx->inode_count = inode_count;
global_ctx->inode_link_info = inode_link_info;
-
- /* Keep the global singal flags*/
- global_ctx->flags |= (flags & E2F_FLAG_SIGNAL_MASK) |
- (global_ctx->flags & E2F_FLAG_SIGNAL_MASK);
+ global_ctx->refcount = refcount;
+ global_ctx->refcount_extra = refcount_extra;
+ global_ctx->refcount_orig = refcount_orig;
+ global_ctx->ea_block_quota_blocks = ea_block_quota_blocks;
+ global_ctx->ea_block_quota_inodes = ea_block_quota_inodes;
+ global_ctx->block_ea_map = block_ea_map;
+ global_ctx->ea_inode_refs = ea_inode_refs;
+ global_ctx->fs_directory_count += fs_directory_count;
+ global_ctx->fs_regular_count += fs_regular_count;
+ global_ctx->fs_blockdev_count += fs_blockdev_count;
+ global_ctx->fs_chardev_count += fs_chardev_count;
+ global_ctx->fs_links_count += fs_links_count;
+ global_ctx->fs_symlinks_count += fs_symlinks_count;
+ global_ctx->fs_fast_symlinks_count += fs_fast_symlinks_count;
+ global_ctx->fs_fifo_count += fs_fifo_count;
+ global_ctx->fs_total_count += fs_total_count;
+ global_ctx->fs_badblocks_count += fs_badblocks_count;
+ global_ctx->fs_sockets_count += fs_sockets_count;
+ global_ctx->fs_ind_count += fs_ind_count;
+ global_ctx->fs_dind_count += fs_dind_count;
+ global_ctx->fs_tind_count += fs_tind_count;
+ global_ctx->fs_fragmented += fs_fragmented;
+ global_ctx->fs_fragmented_dir += fs_fragmented_dir;
+ global_ctx->large_files += large_files;
+
+ global_ctx->flags |= flags;
retval = e2fsck_pass1_merge_fs(global_fs, thread_fs);
if (retval) {
return retval;
}
+ global_ctx->dirs_to_hash = dirs_to_hash;
+ retval = e2fsck_pass1_merge_dirs_to_hash(global_ctx, thread_ctx);
+ if (retval) {
+ com_err(global_ctx->program_name, 0,
+ _("while merging dirs to hash\n"));
+ return retval;
+ }
+
+ e2fsck_pass1_merge_ea_inode_refs(global_ctx, thread_ctx);
+ e2fsck_pass1_merge_ea_refcount(global_ctx, thread_ctx);
+ global_ctx->qctx = qctx;
+ retval = quota_merge_and_update_usage(global_ctx->qctx,
+ thread_ctx->qctx);
+ if (retval)
+ return retval;
+ global_ctx->invalid_block_bitmap_flag = invalid_block_bitmap_flag;
+ global_ctx->invalid_inode_bitmap_flag = invalid_inode_bitmap_flag;
+ global_ctx->invalid_inode_table_flag = invalid_inode_table_flag;
+ global_ctx->invalid_bitmaps = invalid_bitmaps;
+ e2fsck_pass1_merge_invalid_bitmaps(global_ctx, thread_ctx);
+
retval = e2fsck_pass1_merge_bitmap(global_fs,
&thread_ctx->inode_used_map,
&global_ctx->inode_used_map);
if (retval)
return retval;
retval = e2fsck_pass1_merge_bitmap(global_fs,
- &thread_ctx->block_found_map,
- &global_ctx->block_found_map);
- if (retval)
- return retval;
- retval = e2fsck_pass1_merge_bitmap(global_fs,
- &thread_ctx->block_dup_map,
- &global_ctx->block_dup_map);
- if (retval)
- return retval;
- retval = e2fsck_pass1_merge_bitmap(global_fs,
&thread_ctx->block_ea_map,
&global_ctx->block_ea_map);
if (retval)
return retval;
- retval = e2fsck_pass1_merge_bitmap(global_fs,
- &thread_ctx->block_metadata_map,
- &global_ctx->block_metadata_map);
- if (retval)
- return retval;
+
+ if (ext2fs_has_feature_shared_blocks(global_fs->super) &&
+ !(global_ctx->options & E2F_OPT_UNSHARE_BLOCKS))
+ return 0;
+ /*
+ * This need be done after merging block_ea_map
+ * because ea block might be shared, we need exclude
+ * them from dup blocks.
+ */
+ e2fsck_pass1_block_map_w_lock(thread_ctx);
+ retval = ext2fs_merge_bitmap(thread_ctx->block_found_map,
+ global_ctx->block_found_map,
+ global_ctx->block_dup_map,
+ global_ctx->block_ea_map);
+ e2fsck_pass1_block_map_w_unlock(thread_ctx);
+ if (retval == EEXIST)
+ global_ctx->flags |= E2F_FLAG_DUP_BLOCK;
return 0;
}
e2fsck_pass1_free_bitmap(&thread_ctx->inode_reg_map);
e2fsck_pass1_free_bitmap(&thread_ctx->inodes_to_rebuild);
e2fsck_pass1_free_bitmap(&thread_ctx->block_found_map);
- e2fsck_pass1_free_bitmap(&thread_ctx->block_dup_map);
e2fsck_pass1_free_bitmap(&thread_ctx->block_ea_map);
- e2fsck_pass1_free_bitmap(&thread_ctx->block_metadata_map);
+ if (thread_ctx->refcount)
+ ea_refcount_free(thread_ctx->refcount);
+ if (thread_ctx->refcount_extra)
+ ea_refcount_free(thread_ctx->refcount_extra);
+ if (thread_ctx->ea_inode_refs)
+ ea_refcount_free(thread_ctx->ea_inode_refs);
+ if (thread_ctx->refcount_orig)
+ ea_refcount_free(thread_ctx->refcount_orig);
e2fsck_free_dir_info(thread_ctx);
ext2fs_free_icount(thread_ctx->inode_count);
ext2fs_free_icount(thread_ctx->inode_link_info);
+ if (thread_ctx->dirs_to_hash)
+ ext2fs_badblocks_list_free(thread_ctx->dirs_to_hash);
+ quota_release_context(&thread_ctx->qctx);
+ ext2fs_free_mem(&thread_ctx->invalid_block_bitmap_flag);
+ ext2fs_free_mem(&thread_ctx->invalid_inode_bitmap_flag);
+ ext2fs_free_mem(&thread_ctx->invalid_inode_table_flag);
ext2fs_free_mem(&thread_ctx);
return retval;
int i;
struct e2fsck_thread_info *pinfo;
+ /* merge invalid bitmaps will recalculate it */
+ global_ctx->invalid_bitmaps = 0;
for (i = 0; i < num_threads; i++) {
pinfo = &infos[i];
static void e2fsck_pass1_multithread(e2fsck_t global_ctx)
{
- struct e2fsck_thread_info *infos = NULL;
- int num_threads = 1;
- errcode_t retval;
+ struct e2fsck_thread_info *infos = NULL;
+ int num_threads = global_ctx->fs_num_threads;
+ errcode_t retval;
retval = e2fsck_pass1_threads_start(&infos, num_threads, global_ctx);
if (retval) {
}
#endif
-/* TODO: tdb needs to be handled properly for multiple threads*/
-static int multiple_threads_supported(e2fsck_t ctx)
-{
-#ifdef CONFIG_TDB
- unsigned int threshold;
- ext2_ino_t num_dirs;
- errcode_t retval;
- char *tdb_dir;
- int enable;
-
- profile_get_string(ctx->profile, "scratch_files", "directory", 0, 0,
- &tdb_dir);
- profile_get_uint(ctx->profile, "scratch_files",
- "numdirs_threshold", 0, 0, &threshold);
- profile_get_boolean(ctx->profile, "scratch_files",
- "icount", 0, 1, &enable);
-
- retval = ext2fs_get_num_dirs(ctx->fs, &num_dirs);
- if (retval)
- num_dirs = 1024; /* Guess */
-
- /* tdb is unsupported now */
- if (enable && tdb_dir && !access(tdb_dir, W_OK) &&
- (!threshold || num_dirs > threshold))
- return 0;
- #endif
- return 1;
-}
-
void e2fsck_pass1(e2fsck_t ctx)
{
+ errcode_t retval;
+ int need_single = 1;
- init_ext2_max_sizes();
+ retval = e2fsck_pass1_prepare(ctx);
+ if (retval)
+ return;
#ifdef HAVE_PTHREAD
- if (multiple_threads_supported(ctx)) {
+ if (ctx->fs_num_threads > 1 ||
+ ctx->options & E2F_OPT_MULTITHREAD) {
+ need_single = 0;
e2fsck_pass1_multithread(ctx);
- return;
}
- fprintf(stderr, "Fall through single thread for pass1 "
- "because tdb could not handle properly\n");
#endif
- e2fsck_pass1_run(ctx);
+ if (need_single)
+ e2fsck_pass1_run(ctx);
+ e2fsck_pass1_post(ctx);
}
#undef FINISH_INODE_LOOP
*/
static _INLINE_ void mark_block_used(e2fsck_t ctx, blk64_t block)
{
- struct problem_context pctx;
+ struct problem_context pctx;
+ e2fsck_t global_ctx = ctx->global_ctx ? ctx->global_ctx : ctx;
clear_problem_context(&pctx);
- if (ext2fs_fast_test_block_bitmap2(ctx->block_found_map, block)) {
+ if (is_blocks_used(ctx, block, 1)) {
if (ext2fs_has_feature_shared_blocks(ctx->fs->super) &&
!(ctx->options & E2F_OPT_UNSHARE_BLOCKS)) {
return;
}
- if (!ctx->block_dup_map) {
- pctx.errcode = e2fsck_allocate_block_bitmap(ctx->fs,
- _("multiply claimed block map"),
- EXT2FS_BMAP64_RBTREE, "block_dup_map",
- &ctx->block_dup_map);
- if (pctx.errcode) {
- pctx.num = 3;
- fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR,
- &pctx);
- /* Should never get here */
- ctx->flags |= E2F_FLAG_ABORT;
- return;
- }
- }
- ext2fs_fast_mark_block_bitmap2(ctx->block_dup_map, block);
+ ctx->flags |= E2F_FLAG_DUP_BLOCK;
+ e2fsck_pass1_block_map_w_lock(ctx);
+ ext2fs_fast_mark_block_bitmap2(global_ctx->block_dup_map, block);
+ e2fsck_pass1_block_map_w_unlock(ctx);
} else {
ext2fs_fast_mark_block_bitmap2(ctx->block_found_map, block);
}
static _INLINE_ void mark_blocks_used(e2fsck_t ctx, blk64_t block,
unsigned int num)
{
- if (ext2fs_test_block_bitmap_range2(ctx->block_found_map, block, num))
+ if (!is_blocks_used(ctx, block, num)) {
ext2fs_mark_block_bitmap_range2(ctx->block_found_map, block, num);
- else {
+ } else {
unsigned int i;
for (i = 0; i < num; i += EXT2FS_CLUSTER_RATIO(ctx->fs))
}
}
+static errcode_t _INLINE_ e2fsck_write_ext_attr3(e2fsck_t ctx, blk64_t block,
+ void *inbuf, ext2_ino_t inum)
+{
+ errcode_t retval;
+ ext2_filsys fs = ctx->fs;
+
+ e2fsck_pass1_fix_lock(ctx);
+ retval = ext2fs_write_ext_attr3(fs, block, inbuf, inum);
+ e2fsck_pass1_fix_unlock(ctx);
+
+ return retval;
+}
/*
* Adjust the extended attribute block's reference counts at the end
* of pass 1, either by subtracting out references for EA blocks that
pctx.num = should_be;
if (fix_problem(ctx, PR_1_EXTATTR_REFCOUNT, &pctx)) {
header->h_refcount = should_be;
- pctx.errcode = ext2fs_write_ext_attr3(fs, blk,
+ pctx.errcode = e2fsck_write_ext_attr3(ctx, blk,
block_buf,
pctx.ino);
if (pctx.errcode) {
/* Create the EA refcount structure if necessary */
if (!ctx->refcount) {
+ pctx->errcode = ea_refcount_create(0,
+ &ctx->refcount_orig);
+ if (pctx->errcode) {
+ pctx->num = 1;
+ fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return 0;
+ }
+
pctx->errcode = ea_refcount_create(0, &ctx->refcount);
if (pctx->errcode) {
pctx->num = 1;
*/
if (failed_csum &&
fix_problem(ctx, PR_1_EA_BLOCK_ONLY_CSUM_INVALID, pctx)) {
- pctx->errcode = ext2fs_write_ext_attr3(fs, blk, block_buf,
+ pctx->errcode = e2fsck_write_ext_attr3(ctx, blk, block_buf,
pctx->ino);
if (pctx->errcode)
return 0;
inc_ea_inode_refs(ctx, pctx, first, end);
ea_refcount_store(ctx->refcount, blk, header->h_refcount - 1);
- mark_block_used(ctx, blk);
+ ea_refcount_store(ctx->refcount_orig, blk, header->h_refcount);
+ /**
+ * It might be racy that this block has been merged in the
+ * global found map.
+ */
+ if (!is_blocks_used(ctx, blk, 1))
+ ext2fs_fast_mark_block_bitmap2(ctx->block_found_map, blk);
ext2fs_fast_mark_block_bitmap2(ctx->block_ea_map, blk);
return 1;
if (try_repairs && is_dir && problem == 0 &&
(extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT) &&
fix_problem(ctx, PR_1_UNINIT_DBLOCK, pctx)) {
+ e2fsck_pass1_fix_lock(ctx);
extent.e_flags &= ~EXT2_EXTENT_FLAGS_UNINIT;
pb->inode_modified = 1;
pctx->errcode = ext2fs_extent_replace(ehandle, 0,
&extent);
+ e2fsck_pass1_fix_unlock(ctx);
if (pctx->errcode)
return;
failed_csum = 0;
}
continue;
}
+ e2fsck_pass1_fix_lock(ctx);
e2fsck_read_bitmaps(ctx);
pb->inode_modified = 1;
pctx->errcode =
ext2fs_extent_delete(ehandle, 0);
+ e2fsck_pass1_fix_unlock(ctx);
if (pctx->errcode) {
pctx->str = "ext2fs_extent_delete";
return;
}
+ e2fsck_pass1_fix_lock(ctx);
pctx->errcode = ext2fs_extent_fix_parents(ehandle);
+ e2fsck_pass1_fix_unlock(ctx);
if (pctx->errcode &&
pctx->errcode != EXT2_ET_NO_CURRENT_NODE) {
pctx->str = "ext2fs_extent_fix_parents";
pctx->num = e_info.curr_level - 1;
problem = PR_1_EXTENT_INDEX_START_INVALID;
if (fix_problem(ctx, problem, pctx)) {
+ e2fsck_pass1_fix_lock(ctx);
pb->inode_modified = 1;
pctx->errcode =
ext2fs_extent_fix_parents(ehandle);
+ e2fsck_pass1_fix_unlock(ctx);
if (pctx->errcode) {
pctx->str = "ext2fs_extent_fix_parents";
return;
pctx->blk = extent.e_lblk;
pctx->blk2 = new_lblk;
if (fix_problem(ctx, PR_1_COLLAPSE_DBLOCK, pctx)) {
+ e2fsck_pass1_fix_lock(ctx);
extent.e_lblk = new_lblk;
pb->inode_modified = 1;
pctx->errcode = ext2fs_extent_replace(ehandle,
0, &extent);
+ e2fsck_pass1_fix_unlock(ctx);
if (pctx->errcode) {
pctx->errcode = 0;
goto alloc_later;
}
+ e2fsck_pass1_fix_lock(ctx);
pctx->errcode = ext2fs_extent_fix_parents(ehandle);
+ e2fsck_pass1_fix_unlock(ctx);
if (pctx->errcode)
goto failed_add_dir_block;
pctx->errcode = ext2fs_extent_goto(ehandle,
/* Failed csum but passes checks? Ask to fix checksum. */
if (failed_csum &&
fix_problem(ctx, PR_1_EXTENT_ONLY_CSUM_INVALID, pctx)) {
+ e2fsck_pass1_fix_lock(ctx);
pb->inode_modified = 1;
pctx->errcode = ext2fs_extent_replace(ehandle, 0, &extent);
+ e2fsck_pass1_fix_unlock(ctx);
if (pctx->errcode)
return;
}
*block_nr = 0;
return BLOCK_CHANGED;
}
- } else if (ext2fs_test_block_bitmap2(ctx->block_found_map,
- blk)) {
+ } else if (is_blocks_used(ctx, blk, 1)) {
p->bbcheck = 1;
if (fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK,
pctx)) {
}
if (e2fsck_should_abort(ctx))
return BLOCK_ABORT;
- } else
+ } else {
mark_block_used(ctx, blk);
+ }
return 0;
}
#if 0
* there's an overlap between the filesystem table blocks
* (bitmaps and inode table) and the bad block list.
*/
- if (!ext2fs_test_block_bitmap2(ctx->block_found_map, blk)) {
+ if (!is_blocks_used(ctx, blk, 1)) {
ext2fs_mark_block_bitmap2(ctx->block_found_map, blk);
return 0;
}