if (i >= 4)
not_device++;
+ e2fsck_pass1_block_map_lock(ctx);
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))
+ blk)) {
+ e2fsck_pass1_block_map_unlock(ctx);
return; /* Invalid block, can't be dir */
+ }
+ e2fsck_pass1_block_map_unlock(ctx);
}
blk = inode->i_block[0];
}
errcode_t err;
ext2_filsys fs = ctx->fs;
- e2fsck_pass1_fix_lock(ctx);
ctx->root_repair_block = 0;
if (ext2fs_test_inode_bitmap2(ctx->inode_used_map, EXT2_ROOT_INO))
- goto out;
+ return;
err = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk);
if (err)
- goto out;
+ return;
ext2fs_mark_block_bitmap2(ctx->block_found_map, blk);
ctx->root_repair_block = blk;
-out:
- e2fsck_pass1_fix_unlock(ctx);
- return;
}
static void reserve_block_for_lnf_repair(e2fsck_t ctx)
static const char name[] = "lost+found";
ext2_ino_t ino;
- e2fsck_pass1_fix_lock(ctx);
ctx->lnf_repair_block = 0;
if (!ext2fs_lookup(fs, EXT2_ROOT_INO, name, sizeof(name)-1, 0, &ino))
- goto out;
+ return;
err = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk);
if (err)
- goto out;
+ return;
ext2fs_mark_block_bitmap2(ctx->block_found_map, blk);
ctx->lnf_repair_block = blk;
-out:
- e2fsck_pass1_fix_unlock(ctx);
return;
}
return 0;
}
+/*
+ * 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;
+
+ 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;
+ }
+
+ 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);
+
+ return 0;
+}
+
+static void e2fsck_pass1_post(e2fsck_t ctx)
+{
+ struct problem_context pctx;
+ ext2_filsys fs = ctx->fs;
+ char *block_buf;
+
+ reserve_block_for_root_repair(ctx);
+ reserve_block_for_lnf_repair(ctx);
+
+ if (ctx->invalid_bitmaps)
+ handle_fs_bad_blocks(ctx);
+
+ 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->options & E2F_OPT_PREEN) {
+ clear_problem_context(&pctx);
+ fix_problem(ctx, PR_1_DUP_BLOCKS_PREENSTOP, &pctx);
+ }
+ block_buf =
+ (char *)e2fsck_allocate_memory(ctx,
+ ctx->fs->blocksize * 3,
+ "block interate buffer");
+ e2fsck_pass1_dupblocks(ctx, block_buf);
+ ext2fs_free_mem(&block_buf);
+ }
+}
+
+
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 iterate 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);
failed_csum = 0;
}
+ e2fsck_pass1_block_map_lock(ctx);
pctx.errcode = ext2fs_copy_bitmap(ctx->block_found_map,
&pb.fs_meta_blocks);
+ e2fsck_pass1_block_map_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->ea_block_quota_inodes = 0;
}
- if (ctx->invalid_bitmaps) {
- e2fsck_pass1_fix_lock(ctx);
- handle_fs_bad_blocks(ctx);
- e2fsck_pass1_fix_unlock(ctx);
- }
/* We don't need the block_ea_map any more */
if (ctx->block_ea_map) {
/* 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);
- e2fsck_pass1_fix_lock(ctx);
- pctx.errcode = ext2fs_create_resize_inode(fs);
- e2fsck_pass1_fix_unlock(ctx);
- 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);
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_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);
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;
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_dup_map = block_dup_map;
global_ctx->dir_info = dir_info;
e2fsck_pass1_merge_dir_info(global_ctx, thread_ctx);
global_ctx->dx_dir_info = dx_dir_info;
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;
return 0;
}
e2fsck_pass1_free_bitmap(&thread_ctx->inode_imagic_map);
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);
e2fsck_free_dir_info(thread_ctx);
ext2fs_free_icount(thread_ctx->inode_count);
ext2fs_free_icount(thread_ctx->inode_link_info);
errcode_t retval;
pthread_mutex_init(&global_ctx->fs_fix_mutex, NULL);
+ pthread_mutex_init(&global_ctx->fs_block_map_mutex, NULL);
retval = e2fsck_pass1_threads_start(&infos, num_threads, global_ctx);
if (retval) {
com_err(global_ctx->program_name, retval,
void e2fsck_pass1(e2fsck_t ctx)
{
+ errcode_t retval;
+ int multiple = 0;
init_ext2_max_sizes();
+ retval = e2fsck_pass1_prepare(ctx);
+ if (retval)
+ return;
#ifdef HAVE_PTHREAD
if (multiple_threads_supported(ctx)) {
+ multiple = 1;
e2fsck_pass1_multithread(ctx);
- return;
+ } else {
+ fprintf(stderr, "Fall through single thread for pass1 "
+ "because tdb could not handle properly\n");
}
- fprintf(stderr, "Fall through single thread for pass1 "
- "because tdb could not handle properly\n");
#endif
- e2fsck_pass1_run(ctx);
+ if (!multiple)
+ e2fsck_pass1_run(ctx);
+ e2fsck_pass1_post(ctx);
}
#undef FINISH_INODE_LOOP
* WARNING: Assumes checks have already been done to make sure block
* is valid. This is true in both process_block and process_bad_block.
*/
-static _INLINE_ void mark_block_used(e2fsck_t ctx, blk64_t block)
+static _INLINE_ void mark_block_used_unlocked(e2fsck_t ctx, blk64_t block)
{
- struct problem_context pctx;
+ struct problem_context pctx;
+ e2fsck_t global_ctx;
+
+ global_ctx = ctx->global_ctx;
+ if (!global_ctx)
+ global_ctx = ctx;
clear_problem_context(&pctx);
!(ctx->options & E2F_OPT_UNSHARE_BLOCKS)) {
return;
}
- if (!ctx->block_dup_map) {
+ /**
+ * this should be safe because this operation has
+ * been serialized by mutex.
+ */
+ if (!global_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);
+ &global_ctx->block_dup_map);
if (pctx.errcode) {
pctx.num = 3;
fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR,
return;
}
}
- ext2fs_fast_mark_block_bitmap2(ctx->block_dup_map, block);
+ ext2fs_fast_mark_block_bitmap2(global_ctx->block_dup_map, block);
} else {
ext2fs_fast_mark_block_bitmap2(ctx->block_found_map, block);
}
}
+static _INLINE_ void mark_block_used(e2fsck_t ctx, blk64_t block)
+{
+ e2fsck_pass1_block_map_lock(ctx);
+ mark_block_used_unlocked(ctx, block);
+ e2fsck_pass1_block_map_unlock(ctx);
+
+}
+
/*
* When cluster size is greater than one block, it is caller's responsibility
* to make sure block parameter starts at a cluster boundary.
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))
+ e2fsck_pass1_block_map_lock(ctx);
+ if (ext2fs_test_block_bitmap_range2(ctx->block_found_map, 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))
- mark_block_used(ctx, block + i);
+ mark_block_used_unlocked(ctx, block + i);
}
+ e2fsck_pass1_block_map_unlock(ctx);
}
static errcode_t _INLINE_ e2fsck_write_ext_attr3(e2fsck_t ctx, blk64_t block,
}
if (blockcnt < 0) {
+ e2fsck_pass1_block_map_lock(ctx);
if (ext2fs_test_block_bitmap2(p->fs_meta_blocks, blk)) {
p->bbcheck = 1;
if (fix_problem(ctx, PR_1_BB_FS_BLOCK, pctx)) {
*block_nr = 0;
+ e2fsck_pass1_block_map_unlock(ctx);
return BLOCK_CHANGED;
}
} else if (ext2fs_test_block_bitmap2(ctx->block_found_map,
if (fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK,
pctx)) {
*block_nr = 0;
+ e2fsck_pass1_block_map_unlock(ctx);
return BLOCK_CHANGED;
}
- if (e2fsck_should_abort(ctx))
+ if (e2fsck_should_abort(ctx)) {
+ e2fsck_pass1_block_map_unlock(ctx);
return BLOCK_ABORT;
- } else
- mark_block_used(ctx, blk);
+ }
+ } else {
+ mark_block_used_unlocked(ctx, blk);
+ }
+ e2fsck_pass1_block_map_unlock(ctx);
return 0;
}
#if 0
* there's an overlap between the filesystem table blocks
* (bitmaps and inode table) and the bad block list.
*/
+ e2fsck_pass1_block_map_lock(ctx);
if (!ext2fs_test_block_bitmap2(ctx->block_found_map, blk)) {
ext2fs_mark_block_bitmap2(ctx->block_found_map, blk);
+ e2fsck_pass1_block_map_unlock(ctx);
return 0;
}
+ e2fsck_pass1_block_map_unlock(ctx);
/*
* Try to find the where the filesystem block was used...
*/
fix_problem(ctx, (old_block ? PR_1_RELOC_FROM_TO :
PR_1_RELOC_TO), &pctx);
pctx.blk2 = 0;
+ e2fsck_pass1_block_map_lock(ctx);
for (i = 0; i < num; i++) {
pctx.blk = i;
ext2fs_mark_block_bitmap2(ctx->block_found_map, (*new_block)+i);
if (pctx.errcode)
fix_problem(ctx, PR_1_RELOC_WRITE_ERR, &pctx);
}
+ e2fsck_pass1_block_map_unlock(ctx);
ext2fs_free_mem(&buf);
}