+ FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum);
+
+ if (e2fsck_should_abort(ctx)) {
+ e2fsck_pass1_check_unlock(ctx);
+ goto endit;
+ }
+
+ if (process_inode_count >= ctx->process_inode_size) {
+ process_inodes(ctx, block_buf, inodes_to_process,
+ &process_inode_count);
+
+ if (e2fsck_should_abort(ctx)) {
+ e2fsck_pass1_check_unlock(ctx);
+ goto endit;
+ }
+ }
+ e2fsck_pass1_check_unlock(ctx);
+ }
+ process_inodes(ctx, block_buf, inodes_to_process,
+ &process_inode_count);
+ ext2fs_close_inode_scan(scan);
+ scan = NULL;
+
+ if (ctx->ea_block_quota_blocks) {
+ ea_refcount_free(ctx->ea_block_quota_blocks);
+ ctx->ea_block_quota_blocks = 0;
+ }
+
+ if (ctx->ea_block_quota_inodes) {
+ ea_refcount_free(ctx->ea_block_quota_inodes);
+ ctx->ea_block_quota_inodes = 0;
+ }
+
+ /* We don't need the encryption policy => ID map any more */
+ destroy_encryption_policy_map(ctx);
+
+ if (ctx->flags & E2F_FLAG_RESTART) {
+ /*
+ * Only the master copy of the superblock and block
+ * group descriptors are going to be written during a
+ * restart, so set the superblock to be used to be the
+ * master superblock.
+ */
+ ctx->use_superblock = 0;
+ goto endit;
+ }
+
+ if (ctx->large_dirs && !ext2fs_has_feature_largedir(fs->super)) {
+ if (fix_problem(ctx, PR_2_FEATURE_LARGE_DIRS, &pctx)) {
+ ext2fs_set_feature_largedir(fs->super);
+ fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
+ ext2fs_mark_super_dirty(fs);
+ }
+ if (fs->super->s_rev_level == EXT2_GOOD_OLD_REV &&
+ fix_problem(ctx, PR_1_FS_REV_LEVEL, &pctx)) {
+ ext2fs_update_dynamic_rev(fs);
+ ext2fs_mark_super_dirty(fs);
+ }
+ }
+
+ ctx->flags |= E2F_FLAG_ALLOC_OK;
+ ext2fs_free_mem(&inodes_to_process);
+endit:
+ e2fsck_use_inode_shortcuts(ctx, 0);
+ ext2fs_free_mem(&inodes_to_process);
+ inodes_to_process = 0;
+
+ if (scan)
+ ext2fs_close_inode_scan(scan);
+ if (block_buf)
+ ext2fs_free_mem(&block_buf);
+ if (inode)
+ ext2fs_free_mem(&inode);
+
+ /*
+ * The l+f inode may have been cleared, so zap it now and
+ * later passes will recalculate it if necessary
+ */
+ ctx->lost_and_found = 0;
+
+ if ((ctx->flags & E2F_FLAG_SIGNAL_MASK) == 0)
+ print_resource_track(ctx, _("Pass 1"), &rtrack, ctx->fs->io);
+ else
+ ctx->invalid_bitmaps++;
+#ifdef HAVE_PTHREAD
+ /* reset update_thread after this thread exit */
+ e2fsck_pass1_block_map_w_lock(ctx);
+ if (check_mmp)
+ global_ctx->mmp_update_thread = 0;
+ e2fsck_pass1_block_map_w_unlock(ctx);
+#endif
+}
+
+#ifdef HAVE_PTHREAD
+static errcode_t e2fsck_pass1_copy_bitmap(ext2_filsys fs, ext2fs_generic_bitmap *src,
+ ext2fs_generic_bitmap *dest)
+{
+ errcode_t ret;
+
+ ret = ext2fs_copy_bitmap(*src, dest);
+ if (ret)
+ return ret;
+
+ (*dest)->fs = fs;
+
+ return 0;
+}
+
+static void e2fsck_pass1_free_bitmap(ext2fs_generic_bitmap *bitmap)
+{
+ if (*bitmap) {
+ ext2fs_free_generic_bmap(*bitmap);
+ *bitmap = NULL;
+ }
+
+}
+
+static errcode_t e2fsck_pass1_merge_bitmap(ext2_filsys fs, ext2fs_generic_bitmap *src,
+ ext2fs_generic_bitmap *dest)
+{
+ errcode_t ret = 0;
+
+ if (*src) {
+ if (*dest == NULL) {
+ *dest = *src;
+ *src = NULL;
+ } else {
+ ret = ext2fs_merge_bitmap(*src, *dest, NULL, NULL);
+ if (ret)
+ return ret;
+ }
+ (*dest)->fs = fs;
+ }
+
+ return 0;
+}
+
+static errcode_t e2fsck_pass1_copy_fs(ext2_filsys dest, e2fsck_t src_context,
+ ext2_filsys src)
+{
+ errcode_t retval;
+
+ memcpy(dest, src, sizeof(struct struct_ext2_filsys));
+ dest->inode_map = NULL;
+ dest->block_map = NULL;
+ dest->badblocks = NULL;
+ if (dest->dblist)
+ dest->dblist->fs = dest;
+ if (src->block_map) {
+ retval = e2fsck_pass1_copy_bitmap(dest, &src->block_map,
+ &dest->block_map);
+ if (retval)
+ return retval;
+ }
+ if (src->inode_map) {
+ retval = e2fsck_pass1_copy_bitmap(dest, &src->inode_map,
+ &dest->inode_map);
+ if (retval)
+ return retval;
+ }
+
+ if (src->badblocks) {
+ retval = ext2fs_badblocks_copy(src->badblocks,
+ &dest->badblocks);
+ if (retval)
+ return retval;
+ }
+
+ /* disable it for now */
+ src_context->openfs_flags &= ~EXT2_FLAG_EXCLUSIVE;
+ retval = ext2fs_open_channel(dest, src_context->io_options,
+ src_context->io_manager,
+ src_context->openfs_flags,
+ src->io->block_size);
+ if (retval)
+ return retval;
+
+ /* Block size might not be default */
+ io_channel_set_blksize(dest->io, src->io->block_size);
+ ehandler_init(dest->io);
+
+ assert(dest->io->magic == src->io->magic);
+ assert(dest->io->manager == src->io->manager);
+ assert(strcmp(dest->io->name, src->io->name) == 0);
+ assert(dest->io->block_size == src->io->block_size);
+ assert(dest->io->read_error == src->io->read_error);
+ assert(dest->io->write_error == src->io->write_error);
+ assert(dest->io->refcount == src->io->refcount);
+ assert(dest->io->flags == src->io->flags);
+ assert(dest->io->app_data == dest);
+ assert(src->io->app_data == src);
+ assert(dest->io->align == src->io->align);
+
+ /* The data should be written to disk immediately */
+ dest->io->flags |= CHANNEL_FLAGS_WRITETHROUGH;
+ /* icache will be rebuilt if needed, so do not copy from @src */
+ src->icache = NULL;
+ return 0;
+}
+
+static int e2fsck_pass1_merge_fs(ext2_filsys dest, ext2_filsys src)
+{
+ struct ext2_inode_cache *icache = dest->icache;
+ errcode_t retval = 0;
+ io_channel dest_io;
+ io_channel dest_image_io;
+ ext2fs_inode_bitmap inode_map;
+ ext2fs_block_bitmap block_map;
+ ext2_badblocks_list badblocks;
+ ext2_dblist dblist;
+ int flags;
+ e2fsck_t dest_ctx = dest->priv_data;
+
+ dest_io = dest->io;
+ dest_image_io = dest->image_io;
+ inode_map = dest->inode_map;
+ 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->image_io = dest_image_io;
+ dest->icache = icache;
+ dest->inode_map = inode_map;
+ dest->block_map = block_map;
+ dest->badblocks = badblocks;
+ dest->dblist = dblist;
+ dest->priv_data = dest_ctx;
+ 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);
+ src->icache = NULL;
+ }
+
+ retval = e2fsck_pass1_merge_bitmap(dest, &src->inode_map,
+ &dest->inode_map);
+ if (retval)
+ goto out;
+
+ retval = e2fsck_pass1_merge_bitmap(dest, &src->block_map,
+ &dest->block_map);
+ if (retval)
+ goto out;
+
+ if (src->dblist) {
+ if (dest->dblist) {
+ retval = ext2fs_merge_dblist(src->dblist,
+ dest->dblist);
+ if (retval)
+ goto out;
+ } else {
+ dest->dblist = src->dblist;
+ dest->dblist->fs = dest;
+ src->dblist = NULL;
+ }
+ }
+
+ if (src->badblocks) {
+ if (dest->badblocks == NULL)
+ retval = ext2fs_badblocks_copy(src->badblocks,
+ &dest->badblocks);
+ else
+ retval = ext2fs_badblocks_merge(src->badblocks,
+ dest->badblocks);
+ }
+out:
+ io_channel_close(src->io);
+ if (src->inode_map)
+ ext2fs_free_generic_bmap(src->inode_map);
+ if (src->block_map)
+ ext2fs_free_generic_bmap(src->block_map);
+ if (src->badblocks)
+ ext2fs_badblocks_list_free(src->badblocks);
+ if (src->dblist)
+ ext2fs_free_dblist(src->dblist);
+
+ 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 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,
+ dgrp_t average_group)
+{
+ errcode_t retval;
+ e2fsck_t thread_context;
+ ext2_filsys thread_fs;
+ ext2_filsys global_fs = global_ctx->fs;
+ struct e2fsck_thread *tinfo;
+
+ assert(global_ctx->inode_used_map == NULL);
+ assert(global_ctx->inode_dir_map == NULL);
+ assert(global_ctx->inode_bb_map == NULL);
+ assert(global_ctx->inode_imagic_map == NULL);
+ 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_metadata_map != NULL);
+ assert(global_ctx->block_dup_map != NULL);
+ assert(global_ctx->block_ea_map == NULL);
+ assert(global_ctx->fs->dblist == NULL);
+
+ retval = ext2fs_get_mem(sizeof(struct e2fsck_struct), &thread_context);
+ if (retval) {
+ com_err(global_ctx->program_name, retval, "while allocating memory");
+ return retval;
+ }
+ memcpy(thread_context, global_ctx, sizeof(struct e2fsck_struct));
+ thread_context->block_dup_map = NULL;
+ thread_context->casefolded_dirs = 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");
+ goto out_context;
+ }
+
+ io_channel_flush_cleanup(global_fs->io);
+ retval = e2fsck_pass1_copy_fs(thread_fs, global_ctx, global_fs);
+ if (retval) {
+ com_err(global_ctx->program_name, retval, "while copying fs");
+ goto out_fs;
+ }
+ thread_fs->priv_data = thread_context;
+
+ thread_context->thread_info.et_thread_index = thread_index;
+ set_up_logging(thread_context);
+
+ tinfo = &thread_context->thread_info;
+ tinfo->et_group_start = average_group * thread_index;
+ if (thread_index == global_fs->fs_num_threads - 1)
+ tinfo->et_group_end = thread_fs->group_desc_count;
+ else
+ tinfo->et_group_end = average_group * (thread_index + 1);
+ tinfo->et_group_next = tinfo->et_group_start;
+ tinfo->et_inode_number = 0;
+ tinfo->et_log_buf[0] = '\0';
+ tinfo->et_log_length = 0;
+ if (thread_context->options & E2F_OPT_MULTITHREAD)
+ 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;
+}
+
+static void e2fsck_pass1_merge_dir_info(e2fsck_t global_ctx, e2fsck_t thread_ctx)
+{
+ if (thread_ctx->dir_info == NULL)
+ return;
+
+ if (global_ctx->dir_info == NULL) {
+ global_ctx->dir_info = thread_ctx->dir_info;
+ thread_ctx->dir_info = NULL;
+ return;
+ }
+
+ e2fsck_merge_dir_info(global_ctx, thread_ctx->dir_info,
+ 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)
+{
+ if (*src_icount) {
+ if (*dest_icount == NULL) {
+ *dest_icount = *src_icount;
+ *src_icount = NULL;
+ } else {
+ errcode_t ret;
+
+ ret = ext2fs_icount_merge(*src_icount,
+ *dest_icount);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static errcode_t e2fsck_pass1_merge_icounts(e2fsck_t global_ctx, e2fsck_t thread_ctx)
+{
+ errcode_t ret;
+
+ ret = e2fsck_pass1_merge_icount(&global_ctx->inode_count,
+ &thread_ctx->inode_count);
+ if (ret)
+ return ret;
+ ret = e2fsck_pass1_merge_icount(&global_ctx->inode_link_info,
+ &thread_ctx->inode_link_info);
+
+ 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 thread_count, global_count;
+ ea_key_t ino;
+ 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 ((ino = ea_refcount_intr_next(thread_ctx->ea_inode_refs,
+ &thread_count)) == 0)
+ break;
+ ea_refcount_fetch(global_ctx->ea_inode_refs,
+ ino, &global_count);
+ retval = ea_refcount_store(global_ctx->ea_inode_refs,
+ ino, thread_count + global_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 errcode_t e2fsck_pass1_merge_casefolded_dirs(e2fsck_t global_ctx,
+ e2fsck_t thread_ctx)
+{
+ errcode_t retval = 0;
+
+ if (!thread_ctx->casefolded_dirs)
+ return 0;
+
+ if (!global_ctx->casefolded_dirs)
+ retval = ext2fs_badblocks_copy(thread_ctx->casefolded_dirs,
+ &global_ctx->casefolded_dirs);
+ else
+ retval = ext2fs_badblocks_merge(thread_ctx->casefolded_dirs,
+ global_ctx->casefolded_dirs);
+
+ return retval;
+}
+
+static errcode_t e2fsck_pass1_merge_context(e2fsck_t global_ctx,
+ e2fsck_t thread_ctx)
+{
+ ext2_filsys global_fs = global_ctx->fs;
+ errcode_t retval;
+ int i;
+
+ global_ctx->fs_directory_count += thread_ctx->fs_directory_count;
+ global_ctx->fs_regular_count += thread_ctx->fs_regular_count;
+ global_ctx->fs_blockdev_count += thread_ctx->fs_blockdev_count;
+ global_ctx->fs_chardev_count += thread_ctx->fs_chardev_count;
+ global_ctx->fs_links_count += thread_ctx->fs_links_count;
+ global_ctx->fs_symlinks_count += thread_ctx->fs_symlinks_count;
+ global_ctx->fs_fast_symlinks_count += thread_ctx->fs_fast_symlinks_count;
+ global_ctx->fs_fifo_count += thread_ctx->fs_fifo_count;
+ global_ctx->fs_total_count += thread_ctx->fs_total_count;
+ global_ctx->fs_badblocks_count += thread_ctx->fs_badblocks_count;
+ global_ctx->fs_sockets_count += thread_ctx->fs_sockets_count;
+ global_ctx->fs_ind_count += thread_ctx->fs_ind_count;
+ global_ctx->fs_dind_count += thread_ctx->fs_dind_count;
+ global_ctx->fs_tind_count += thread_ctx->fs_tind_count;
+ global_ctx->fs_fragmented += thread_ctx->fs_fragmented;
+ global_ctx->fs_fragmented_dir += thread_ctx->fs_fragmented_dir;
+ global_ctx->large_files += thread_ctx->large_files;
+ /* threads might enable E2F_OPT_YES */
+ global_ctx->options |= thread_ctx->options;
+ global_ctx->flags |= thread_ctx->flags;
+ /*
+ * The l+f inode may have been cleared, so zap it now and
+ * later passes will recalculate it if necessary
+ */
+ global_ctx->lost_and_found = 0;
+ /* merge extent depth count */
+ for (i = 0; i < MAX_EXTENT_DEPTH_COUNT; i++)
+ global_ctx->extent_depth_count[i] +=
+ thread_ctx->extent_depth_count[i];