* - A bitmap of which inodes have bad fields. (inode_bad_map)
* - A bitmap of which inodes are in bad blocks. (inode_bb_map)
* - A bitmap of which inodes are imagic inodes. (inode_imagic_map)
+ * - A bitmap of which inodes are casefolded. (inode_casefold_map)
* - A bitmap of which blocks are in use. (block_found_map)
* - A bitmap of which blocks are in use by two inodes (block_dup_map)
* - The data blocks of the directory inodes. (dir_map)
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
+#include <assert.h>
+#ifdef HAVE_PTHREAD
+#include <pthread.h>
+#endif
#include "e2fsck.h"
#include <ext2fs/ext2_ext_attr.h>
+/* todo remove this finally */
+#include <ext2fs/ext2fsP.h>
#include <e2p/e2p.h>
#include "problem.h"
static void alloc_bb_map(e2fsck_t ctx);
static void alloc_imagic_map(e2fsck_t ctx);
static void mark_inode_bad(e2fsck_t ctx, ino_t ino);
+static void add_casefolded_dir(e2fsck_t ctx, ino_t ino);
static void handle_fs_bad_blocks(e2fsck_t ctx);
-static void process_inodes(e2fsck_t ctx, char *block_buf);
static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b);
static errcode_t scan_callback(ext2_filsys fs, ext2_inode_scan scan,
dgrp_t group, void * priv_data);
};
struct scan_callback_struct {
- e2fsck_t ctx;
- char *block_buf;
+ e2fsck_t ctx;
+ char *block_buf;
+ struct process_inode_block *inodes_to_process;
+ int *process_inode_count;
};
-/*
- * For the inodes to process list.
- */
-static struct process_inode_block *inodes_to_process;
-static int process_inode_count;
+static void process_inodes(e2fsck_t ctx, char *block_buf,
+ struct process_inode_block *inodes_to_process,
+ int *process_inode_count);
static __u64 ext2_max_sizes[EXT2_MAX_BLOCK_LOG_SIZE -
EXT2_MIN_BLOCK_LOG_SIZE + 1];
static void inc_ea_inode_refs(e2fsck_t ctx, struct problem_context *pctx,
struct ext2_ext_attr_entry *first, void *end)
{
- struct ext2_ext_attr_entry *entry;
+ struct ext2_ext_attr_entry *entry = first;
+ struct ext2_ext_attr_entry *np = EXT2_EXT_ATTR_NEXT(entry);
- for (entry = first;
- (void *)entry < end && !EXT2_EXT_IS_LAST_ENTRY(entry);
- entry = EXT2_EXT_ATTR_NEXT(entry)) {
+ while ((void *) entry < end && (void *) np < end &&
+ !EXT2_EXT_IS_LAST_ENTRY(entry)) {
if (!entry->e_value_inum)
- continue;
+ goto next;
if (!ctx->ea_inode_refs) {
pctx->errcode = ea_refcount_create(0,
&ctx->ea_inode_refs);
}
ea_refcount_increment(ctx->ea_inode_refs, entry->e_value_inum,
0);
+ next:
+ entry = np;
+ np = EXT2_EXT_ATTR_NEXT(entry);
}
}
return 0;
}
-void e2fsck_pass1(e2fsck_t ctx)
+static int e2fsck_should_abort(e2fsck_t ctx)
+{
+ e2fsck_t global_ctx;
+
+ if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+ return 1;
+
+ if (ctx->global_ctx) {
+ global_ctx = ctx->global_ctx;
+ if (global_ctx->flags & E2F_FLAG_SIGNAL_MASK)
+ return 1;
+ }
+ return 0;
+}
+
+void e2fsck_pass1_run(e2fsck_t ctx)
{
int i;
- __u64 max_sizes;
ext2_filsys fs = ctx->fs;
ext2_ino_t ino = 0;
struct ext2_inode *inode = NULL;
ext2_ino_t ino_threshold = 0;
dgrp_t ra_group = 0;
struct ea_quota ea_ibody_quota;
+ struct process_inode_block *inodes_to_process;
+ int process_inode_count;
init_resource_track(&rtrack, ctx->fs->io);
clear_problem_context(&pctx);
mtrace_print("Pass 1");
#endif
-#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
-
imagic_fs = ext2fs_has_feature_imagic_inodes(sb);
extent_fs = ext2fs_has_feature_extents(sb);
inlinedata_fs = ext2fs_has_feature_inline_data(sb);
}
pctx.errcode = e2fsck_allocate_inode_bitmap(fs,
_("directory inode map"),
+ ctx->global_ctx ? EXT2FS_BMAP64_RBTREE :
EXT2FS_BMAP64_AUTODIR,
"inode_dir_map", &ctx->inode_dir_map);
if (pctx.errcode) {
ctx->flags |= E2F_FLAG_ABORT;
return;
}
+ if (casefold_fs) {
+ pctx.errcode =
+ e2fsck_allocate_inode_bitmap(fs,
+ _("inode casefold map"),
+ EXT2FS_BMAP64_RBTREE,
+ "inode_casefold_map",
+ &ctx->inode_casefold_map);
+ if (pctx.errcode) {
+ pctx.num = 1;
+ fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return;
+ }
+ }
pctx.errcode = e2fsck_setup_icount(ctx, "inode_link_info", 0, NULL,
&ctx->inode_link_info);
if (pctx.errcode) {
ctx->stashed_inode = inode;
scan_struct.ctx = ctx;
scan_struct.block_buf = block_buf;
+ scan_struct.inodes_to_process = inodes_to_process;
+ scan_struct.process_inode_count = &process_inode_count;
ext2fs_set_inode_callback(scan, scan_callback, &scan_struct);
if (ctx->progress && ((ctx->progress)(ctx, 1, 0,
ctx->fs->group_desc_count)))
/* Set up ctx->lost_and_found if possible */
(void) e2fsck_get_lost_and_found(ctx, 0);
+#ifdef HAVE_PTHREAD
+ if (ctx->global_ctx) {
+ if (ctx->options & E2F_OPT_DEBUG &&
+ ctx->options & E2F_OPT_MULTITHREAD)
+ fprintf(stderr, "thread %d jumping to group %d\n",
+ ctx->thread_info.et_thread_index,
+ ctx->thread_info.et_group_start);
+ pctx.errcode = ext2fs_inode_scan_goto_blockgroup(scan,
+ ctx->thread_info.et_group_start);
+ if (pctx.errcode) {
+ fix_problem(ctx, PR_1_PASS_HEADER, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ goto endit;
+ }
+ }
+#endif
+
while (1) {
if (ino % (fs->super->s_inodes_per_group * 4) == 1) {
if (e2fsck_mmp_update(fs))
if (ino > ino_threshold)
pass1_readahead(ctx, &ra_group, &ino_threshold);
ehandler_operation(old_op);
- if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+ if (e2fsck_should_abort(ctx))
goto endit;
if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) {
/*
fix_problem(ctx, PR_1_ISCAN_ERROR,
&pctx);
ctx->flags |= E2F_FLAG_ABORT;
- goto endit;
- }
- err = ext2fs_inode_scan_goto_blockgroup(scan,
- 0);
- if (err) {
- fix_problem(ctx, PR_1_ISCAN_ERROR,
- &pctx);
- ctx->flags |= E2F_FLAG_ABORT;
- goto endit;
- }
- continue;
+ } else
+ ctx->flags |= E2F_FLAG_RESTART;
+ goto endit;
}
if (!ctx->inode_bb_map)
alloc_bb_map(ctx);
ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino);
continue;
}
+ if (pctx.errcode == EXT2_ET_SCAN_FINISHED)
+ break;
if (pctx.errcode &&
pctx.errcode != EXT2_ET_INODE_CSUM_INVALID &&
pctx.errcode != EXT2_ET_INODE_IS_GARBAGE) {
}
if (!ino)
break;
+#ifdef HAVE_PTHREAD
+ if (ctx->global_ctx)
+ ctx->thread_info.et_inode_number++;
+#endif
pctx.ino = ino;
pctx.inode = inode;
ctx->stashed_ino = ino;
add_encrypted_file(ctx, &pctx) < 0)
goto clear_inode;
+ if (casefold_fs && inode->i_flags & EXT4_CASEFOLD_FL)
+ ext2fs_mark_inode_bitmap2(ctx->inode_casefold_map, ino);
+
if (LINUX_S_ISDIR(inode->i_mode)) {
ext2fs_mark_inode_bitmap2(ctx->inode_dir_map, ino);
e2fsck_add_dir_info(ctx, ino, 0);
ctx->fs_directory_count++;
+ if (inode->i_flags & EXT4_CASEFOLD_FL)
+ add_casefolded_dir(ctx, ino);
} else if (LINUX_S_ISREG (inode->i_mode)) {
ext2fs_mark_inode_bitmap2(ctx->inode_reg_map, ino);
ctx->fs_regular_count++;
goto endit;
if (process_inode_count >= ctx->process_inode_size) {
- process_inodes(ctx, block_buf);
+ process_inodes(ctx, block_buf, inodes_to_process,
+ &process_inode_count);
- if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+ if (e2fsck_should_abort(ctx))
goto endit;
}
}
- process_inodes(ctx, block_buf);
+ process_inodes(ctx, block_buf, inodes_to_process,
+ &process_inode_count);
ext2fs_close_inode_scan(scan);
scan = NULL;
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);
+ }
+ }
+
if (ctx->block_dup_map) {
if (ctx->options & E2F_OPT_PREEN) {
clear_problem_context(&pctx);
else
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)
+{
+ 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;
+
+ 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;
+
+ 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;
+ if (dest->dblist)
+ dest->dblist->fs = 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 errcode_t e2fsck_pass1_thread_prepare(e2fsck_t global_ctx, e2fsck_t *thread_ctx,
+ int thread_index, int num_threads)
+{
+ errcode_t retval;
+ e2fsck_t thread_context;
+ ext2_filsys thread_fs;
+ ext2_filsys global_fs = global_ctx->fs;
+ struct e2fsck_thread *tinfo;
+ dgrp_t average_group;
+
+ 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_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);
+ 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->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);
+
+ /*
+ * Distribute work to multiple threads:
+ * Each thread work on fs->group_desc_count / nthread groups.
+ */
+ tinfo = &thread_context->thread_info;
+ average_group = thread_fs->group_desc_count / num_threads;
+ if (average_group == 0)
+ average_group = 1;
+ tinfo->et_group_start = average_group * thread_index;
+ if (thread_index == 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;
+ *thread_ctx = thread_context;
+ return 0;
+out_fs:
+ ext2fs_free_mem(&thread_fs);
+out_context:
+ 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 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 int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctx)
+{
+ errcode_t retval;
+ int flags = global_ctx->flags;
+ ext2_filsys thread_fs = thread_ctx->fs;
+ ext2_filsys global_fs = global_ctx->fs;
+ FILE *global_logf = global_ctx->logf;
+ 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;
+ 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;
+
+#ifdef HAVE_SETJMP_H
+ jmp_buf old_jmp;
+
+ memcpy(old_jmp, global_ctx->abort_loc, sizeof(jmp_buf));
+#endif
+ memcpy(global_ctx, thread_ctx, sizeof(struct e2fsck_struct));
+#ifdef HAVE_SETJMP_H
+ memcpy(global_ctx->abort_loc, old_jmp, sizeof(jmp_buf));
+#endif
+
+ global_ctx->inode_used_map = inode_used_map;
+ global_ctx->inode_bad_map = inode_bad_map;
+ global_ctx->inode_dir_map = inode_dir_map;
+ global_ctx->inode_bb_map = inode_bb_map;
+ 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->dir_info = dir_info;
+ e2fsck_pass1_merge_dir_info(global_ctx, thread_ctx);
+ global_ctx->inode_count = inode_count;
+ global_ctx->inode_link_info = inode_link_info;
+ 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;
+
+ /* Keep the global singal flags*/
+ global_ctx->flags |= (flags & E2F_FLAG_SIGNAL_MASK) |
+ (global_ctx->flags & E2F_FLAG_SIGNAL_MASK);
+
+ retval = e2fsck_pass1_merge_fs(global_fs, thread_fs);
+ if (retval) {
+ com_err(global_ctx->program_name, 0, _("while merging fs\n"));
+ return retval;
+ }
+ global_fs->priv_data = global_ctx;
+ global_ctx->fs = global_fs;
+ global_ctx->logf = global_logf;
+ global_ctx->problem_logf = global_problem_logf;
+ global_ctx->global_ctx = NULL;
+ retval = e2fsck_pass1_merge_icounts(global_ctx, thread_ctx);
+ if (retval) {
+ com_err(global_ctx->program_name, 0,
+ _("while merging icounts\n"));
+ return retval;
+ }
+
+ 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->inode_bad_map,
+ &global_ctx->inode_bad_map);
+ if (retval)
+ return retval;
+ retval = e2fsck_pass1_merge_bitmap(global_fs,
+ &thread_ctx->inode_dir_map,
+ &global_ctx->inode_dir_map);
+ if (retval)
+ return retval;
+ retval = e2fsck_pass1_merge_bitmap(global_fs,
+ &thread_ctx->inode_bb_map,
+ &global_ctx->inode_bb_map);
+ if (retval)
+ return retval;
+ retval = e2fsck_pass1_merge_bitmap(global_fs,
+ &thread_ctx->inode_imagic_map,
+ &global_ctx->inode_imagic_map);
+ if (retval)
+ return retval;
+ retval = e2fsck_pass1_merge_bitmap(global_fs,
+ &thread_ctx->inode_reg_map,
+ &global_ctx->inode_reg_map);
+ if (retval)
+ return retval;
+ retval = e2fsck_pass1_merge_bitmap(global_fs,
+ &thread_ctx->inodes_to_rebuild,
+ &global_ctx->inodes_to_rebuild);
+ 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;
+}
+
+static int e2fsck_pass1_thread_join(e2fsck_t global_ctx, e2fsck_t thread_ctx)
+{
+ errcode_t retval;
+
+ retval = e2fsck_pass1_thread_join_one(global_ctx, thread_ctx);
+ ext2fs_free_mem(&thread_ctx->fs);
+ if (thread_ctx->logf)
+ fclose(thread_ctx->logf);
+ if (thread_ctx->problem_logf) {
+ fputs("</problem_log>\n", thread_ctx->problem_logf);
+ fclose(thread_ctx->problem_logf);
+ }
+ e2fsck_pass1_free_bitmap(&thread_ctx->inode_used_map);
+ e2fsck_pass1_free_bitmap(&thread_ctx->inode_bad_map);
+ e2fsck_pass1_free_bitmap(&thread_ctx->inode_dir_map);
+ e2fsck_pass1_free_bitmap(&thread_ctx->inode_bb_map);
+ 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);
+ ext2fs_free_mem(&thread_ctx);
+
+ return retval;
+}
+
+static int e2fsck_pass1_threads_join(struct e2fsck_thread_info *infos,
+ int num_threads, e2fsck_t global_ctx)
+{
+ errcode_t rc;
+ errcode_t ret = 0;
+ int i;
+ struct e2fsck_thread_info *pinfo;
+
+ for (i = 0; i < num_threads; i++) {
+ pinfo = &infos[i];
+
+ if (!pinfo->eti_started)
+ continue;
+
+ rc = pthread_join(pinfo->eti_thread_id, NULL);
+ if (rc) {
+ com_err(global_ctx->program_name, rc,
+ _("while joining thread\n"));
+ if (ret == 0)
+ ret = rc;
+ }
+ rc = e2fsck_pass1_thread_join(global_ctx, infos[i].eti_thread_ctx);
+ if (rc) {
+ com_err(global_ctx->program_name, rc,
+ _("while joining pass1 thread\n"));
+ if (ret == 0)
+ ret = rc;
+ }
+ }
+ free(infos);
+
+ return ret;
+}
+
+static void *e2fsck_pass1_thread(void *arg)
+{
+ struct e2fsck_thread_info *info = arg;
+ e2fsck_t thread_ctx = info->eti_thread_ctx;
+#ifdef DEBUG_THREADS
+ struct e2fsck_thread_debug *thread_debug = info->eti_debug;
+#endif
+
+#ifdef DEBUG_THREADS
+ pthread_mutex_lock(&thread_debug->etd_mutex);
+ while (info->eti_thread_index > thread_debug->etd_finished_threads) {
+ pthread_cond_wait(&thread_debug->etd_cond,
+ &thread_debug->etd_mutex);
+ }
+ pthread_mutex_unlock(&thread_debug->etd_mutex);
+#endif
+
+#ifdef HAVE_SETJMP_H
+ /*
+ * When fatal_error() happens, jump to here. The thread
+ * context's flags will be saved, but its abort_loc will
+ * be overwritten by original jump buffer for the later
+ * tests.
+ */
+ if (setjmp(thread_ctx->abort_loc)) {
+ thread_ctx->flags &= ~E2F_FLAG_SETJMP_OK;
+ goto out;
+ }
+ thread_ctx->flags |= E2F_FLAG_SETJMP_OK;
+#endif
+
+ e2fsck_pass1_run(thread_ctx);
+
+out:
+ if (thread_ctx->options & E2F_OPT_MULTITHREAD)
+ log_out(thread_ctx,
+ _("Scanned group range [%lu, %lu), inodes %lu\n"),
+ thread_ctx->thread_info.et_group_start,
+ thread_ctx->thread_info.et_group_end,
+ thread_ctx->thread_info.et_inode_number);
+
+#ifdef DEBUG_THREADS
+ pthread_mutex_lock(&thread_debug->etd_mutex);
+ thread_debug->etd_finished_threads++;
+ pthread_cond_broadcast(&thread_debug->etd_cond);
+ pthread_mutex_unlock(&thread_debug->etd_mutex);
+#endif
+
+ return NULL;
+}
+
+static int e2fsck_pass1_threads_start(struct e2fsck_thread_info **pinfo,
+ int num_threads, e2fsck_t global_ctx)
+{
+ struct e2fsck_thread_info *infos;
+ pthread_attr_t attr;
+ errcode_t retval;
+ errcode_t ret;
+ struct e2fsck_thread_info *tmp_pinfo;
+ int i;
+ e2fsck_t thread_ctx;
+#ifdef DEBUG_THREADS
+ struct e2fsck_thread_debug thread_debug =
+ {PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, 0};
+
+ thread_debug.etd_finished_threads = 0;
+#endif
+
+ retval = pthread_attr_init(&attr);
+ if (retval) {
+ com_err(global_ctx->program_name, retval,
+ _("while setting pthread attribute\n"));
+ return retval;
+ }
+
+ infos = calloc(num_threads, sizeof(struct e2fsck_thread_info));
+ if (infos == NULL) {
+ retval = -ENOMEM;
+ com_err(global_ctx->program_name, retval,
+ _("while allocating memory for threads\n"));
+ pthread_attr_destroy(&attr);
+ return retval;
+ }
+
+ for (i = 0; i < num_threads; i++) {
+ tmp_pinfo = &infos[i];
+ tmp_pinfo->eti_thread_index = i;
+#ifdef DEBUG_THREADS
+ tmp_pinfo->eti_debug = &thread_debug;
+#endif
+ retval = e2fsck_pass1_thread_prepare(global_ctx, &thread_ctx,
+ i, num_threads);
+ if (retval) {
+ com_err(global_ctx->program_name, retval,
+ _("while preparing pass1 thread\n"));
+ break;
+ }
+ tmp_pinfo->eti_thread_ctx = thread_ctx;
+
+ retval = pthread_create(&tmp_pinfo->eti_thread_id, &attr,
+ &e2fsck_pass1_thread, tmp_pinfo);
+ if (retval) {
+ com_err(global_ctx->program_name, retval,
+ _("while creating thread\n"));
+ e2fsck_pass1_thread_join(global_ctx, thread_ctx);
+ break;
+ }
+
+ tmp_pinfo->eti_started = 1;
+ }
+
+ /* destroy the thread attribute object, since it is no longer needed */
+ ret = pthread_attr_destroy(&attr);
+ if (ret) {
+ com_err(global_ctx->program_name, ret,
+ _("while destroying thread attribute\n"));
+ if (retval == 0)
+ retval = ret;
+ }
+
+ if (retval) {
+ e2fsck_pass1_threads_join(infos, num_threads, global_ctx);
+ return retval;
+ }
+ *pinfo = infos;
+ return 0;
+}
+
+static void e2fsck_pass1_multithread(e2fsck_t global_ctx)
+{
+ struct e2fsck_thread_info *infos = NULL;
+ int num_threads = 1;
+ errcode_t retval;
+
+ retval = e2fsck_pass1_threads_start(&infos, num_threads, global_ctx);
+ if (retval) {
+ com_err(global_ctx->program_name, retval,
+ _("while starting pass1 threads\n"));
+ goto out_abort;
+ }
+
+ retval = e2fsck_pass1_threads_join(infos, num_threads, global_ctx);
+ if (retval) {
+ com_err(global_ctx->program_name, retval,
+ _("while joining pass1 threads\n"));
+ goto out_abort;
+ }
+ return;
+out_abort:
+ global_ctx->flags |= E2F_FLAG_ABORT;
+ return;
+}
+#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)
+{
+
+ init_ext2_max_sizes();
+#ifdef HAVE_PTHREAD
+ if (multiple_threads_supported(ctx)) {
+ 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);
+}
+
#undef FINISH_INODE_LOOP
/*
{
struct scan_callback_struct *scan_struct;
e2fsck_t ctx;
+ struct e2fsck_thread *tinfo;
scan_struct = (struct scan_callback_struct *) priv_data;
ctx = scan_struct->ctx;
- process_inodes((e2fsck_t) fs->priv_data, scan_struct->block_buf);
+ process_inodes((e2fsck_t) fs->priv_data, scan_struct->block_buf,
+ scan_struct->inodes_to_process,
+ scan_struct->process_inode_count);
if (ctx->progress)
if ((ctx->progress)(ctx, 1, group+1,
ctx->fs->group_desc_count))
return EXT2_ET_CANCEL_REQUESTED;
+#ifdef HAVE_PTHREAD
+ if (ctx->global_ctx) {
+ tinfo = &ctx->thread_info;
+ tinfo->et_group_next++;
+ if (ctx->options & E2F_OPT_DEBUG &&
+ ctx->options & E2F_OPT_MULTITHREAD)
+ log_out(ctx, _("group %d finished\n"),
+ tinfo->et_group_next);
+ if (tinfo->et_group_next >= tinfo->et_group_end)
+ return EXT2_ET_SCAN_FINISHED;
+ }
+#endif
+
return 0;
}
/*
* Process the inodes in the "inodes to process" list.
*/
-static void process_inodes(e2fsck_t ctx, char *block_buf)
+static void process_inodes(e2fsck_t ctx, char *block_buf,
+ struct process_inode_block *inodes_to_process,
+ int *process_inode_count)
{
int i;
struct ext2_inode *old_stashed_inode;
#if 0
printf("begin process_inodes: ");
#endif
- if (process_inode_count == 0)
+ if (*process_inode_count == 0)
return;
old_operation = ehandler_operation(0);
old_stashed_inode = ctx->stashed_inode;
old_stashed_ino = ctx->stashed_ino;
- qsort(inodes_to_process, process_inode_count,
+ qsort(inodes_to_process, *process_inode_count,
sizeof(struct process_inode_block), process_inode_cmp);
clear_problem_context(&pctx);
- for (i=0; i < process_inode_count; i++) {
+ for (i=0; i < *process_inode_count; i++) {
pctx.inode = ctx->stashed_inode =
(struct ext2_inode *) &inodes_to_process[i].inode;
pctx.ino = ctx->stashed_ino = inodes_to_process[i].ino;
ehandler_operation(buf);
check_blocks(ctx, &pctx, block_buf,
&inodes_to_process[i].ea_ibody_quota);
- if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+ if (e2fsck_should_abort(ctx))
break;
}
ctx->stashed_inode = old_stashed_inode;
ctx->stashed_ino = old_stashed_ino;
- process_inode_count = 0;
+ *process_inode_count = 0;
#if 0
printf("end process inodes\n");
#endif
ext2fs_mark_inode_bitmap2(ctx->inode_bad_map, ino);
}
+static void add_casefolded_dir(e2fsck_t ctx, ino_t ino)
+{
+ struct problem_context pctx;
+
+ if (!ctx->casefolded_dirs) {
+ pctx.errcode = ext2fs_u32_list_create(&ctx->casefolded_dirs, 0);
+ if (pctx.errcode)
+ goto error;
+ }
+ pctx.errcode = ext2fs_u32_list_add(ctx->casefolded_dirs, ino);
+ if (pctx.errcode == 0)
+ return;
+error:
+ fix_problem(ctx, PR_1_ALLOCATE_CASEFOLDED_DIRLIST, &pctx);
+ /* Should never get here */
+ ctx->flags |= E2F_FLAG_ABORT;
+}
+
/*
* This procedure will allocate the inode "bb" (badblock) map table
*/
break;
}
if (entry->e_value_inum == 0) {
- if (entry->e_value_offs + entry->e_value_size >
- fs->blocksize) {
+ if (entry->e_value_size > EXT2_XATTR_SIZE_MAX ||
+ (entry->e_value_offs + entry->e_value_size >
+ fs->blocksize)) {
if (fix_problem(ctx, PR_1_EA_BAD_VALUE, pctx))
goto clear_extattr;
break;
if ((root->hash_version != EXT2_HASH_LEGACY) &&
(root->hash_version != EXT2_HASH_HALF_MD4) &&
(root->hash_version != EXT2_HASH_TEA) &&
+ (root->hash_version != EXT2_HASH_SIPHASH) &&
fix_problem(ctx, PR_1_HTREE_HASHV, pctx))
return 1;
+ if (ext4_hash_in_dirent(inode)) {
+ if (root->hash_version != EXT2_HASH_SIPHASH &&
+ fix_problem(ctx, PR_1_HTREE_NEEDS_SIPHASH, pctx))
+ return 1;
+ } else {
+ if (root->hash_version == EXT2_HASH_SIPHASH &&
+ fix_problem(ctx, PR_1_HTREE_CANNOT_SIPHASH, pctx))
+ return 1;
+ }
+
if ((root->unused_flags & EXT2_HASH_FLAG_INCOMPAT) &&
fix_problem(ctx, PR_1_HTREE_INCOMPAT, pctx))
return 1;
pctx->num = root->indirect_levels;
- if ((root->indirect_levels > ext2_dir_htree_level(fs)) &&
+ /* if htree level is clearly too high, consider it to be broken */
+ if (root->indirect_levels > EXT4_HTREE_LEVEL &&
fix_problem(ctx, PR_1_HTREE_DEPTH, pctx))
return 1;
+ /* if level is only maybe too high, LARGE_DIR feature could be unset */
+ if (root->indirect_levels > ext2_dir_htree_level(fs) &&
+ !ext2fs_has_feature_largedir(fs->super)) {
+ int blockbits = EXT2_BLOCK_SIZE_BITS(fs->super) + 10;
+ unsigned idx_pb = 1 << (blockbits - 3);
+
+ /* compare inode size/blocks vs. max-sized 2-level htree */
+ if (EXT2_I_SIZE(pctx->inode) <
+ (idx_pb - 1) * (idx_pb - 2) << blockbits &&
+ pctx->inode->i_blocks <
+ (idx_pb - 1) * (idx_pb - 2) << (blockbits - 9) &&
+ fix_problem(ctx, PR_1_HTREE_DEPTH, pctx))
+ return 1;
+ }
+
+ if (root->indirect_levels > EXT4_HTREE_LEVEL_COMPAT ||
+ ext2fs_needs_large_file_feature(EXT2_I_SIZE(inode)))
+ ctx->large_dirs++;
+
return 0;
}
if (pctx->errcode)
return;
if (!(ctx->options & E2F_OPT_FIXES_ONLY) &&
- !pb->eti.force_rebuild) {
+ !pb->eti.force_rebuild &&
+ info.curr_level < MAX_EXTENT_DEPTH_COUNT) {
struct extent_tree_level *etl;
etl = pb->eti.ext_info + info.curr_level;
(extent.e_pblk + extent.e_len) >
ext2fs_blocks_count(ctx->fs->super))
problem = PR_1_EXTENT_ENDS_BEYOND;
- else if (is_leaf && is_dir &&
+ else if (is_leaf && is_dir && !pctx->inode->i_size_high &&
+ !ext2fs_has_feature_largedir(ctx->fs->super) &&
((extent.e_lblk + extent.e_len) >
(1U << (21 - ctx->fs->super->s_log_block_size))))
problem = PR_1_TOOBIG_DIR;
if (is_leaf && problem == 0 && extent.e_len > 0) {
#if 0
printf("extent_region(ino=%u, expect=%llu, "
- "lblk=%llu, len=%u)\n",
- pb->ino, pb->next_lblock,
- extent.e_lblk, extent.e_len);
+ "lblk=%llu, len=%u)\n", pb->ino,
+ (unsigned long long) pb->next_lblock,
+ (unsigned long long) extent.e_lblk,
+ extent.e_len);
#endif
if (extent.e_lblk < pb->next_lblock)
problem = PR_1_EXTENT_COLLISION;
if (extent.e_lblk != lblk) {
struct ext2_extent_info e_info;
- ext2fs_extent_get_info(ehandle, &e_info);
+ pctx->errcode = ext2fs_extent_get_info(ehandle,
+ &e_info);
+ if (pctx->errcode) {
+ pctx->str = "ext2fs_extent_get_info";
+ return;
+ }
pctx->blk = lblk;
pctx->blk2 = extent.e_lblk;
pctx->num = e_info.curr_level - 1;
inlinedata_fs = ext2fs_has_feature_inline_data(ctx->fs->super);
if (check_ext_attr(ctx, pctx, block_buf, &ea_block_quota)) {
- if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+ if (e2fsck_should_abort(ctx))
goto out;
pb.num_blocks += EXT2FS_B2C(ctx->fs, ea_block_quota.blocks);
}
}
end_problem_latch(ctx, PR_LATCH_BLOCK);
end_problem_latch(ctx, PR_LATCH_TOOBIG);
- if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+ if (e2fsck_should_abort(ctx))
goto out;
if (pctx->errcode)
fix_problem(ctx, PR_1_BLOCK_ITERATE, pctx);
pb.num_blocks *= EXT2FS_CLUSTER_RATIO(fs);
#if 0
printf("inode %u, i_size = %u, last_block = %llu, i_blocks=%llu, num_blocks = %llu\n",
- ino, inode->i_size, pb.last_block, ext2fs_inode_i_blocks(fs, inode),
- pb.num_blocks);
+ ino, inode->i_size, (unsigned long long) pb.last_block,
+ (unsigned long long) ext2fs_inode_i_blocks(fs, inode),
+ (unsigned long long) pb.num_blocks);
#endif
+ size = EXT2_I_SIZE(inode);
if (pb.is_dir) {
- unsigned nblock = inode->i_size >> EXT2_BLOCK_SIZE_BITS(fs->super);
+ unsigned nblock = size >> EXT2_BLOCK_SIZE_BITS(fs->super);
if (inode->i_flags & EXT4_INLINE_DATA_FL) {
int flags;
size_t sz = 0;
EXT2_FLAG_IGNORE_CSUM_ERRORS) |
(ctx->fs->flags &
~EXT2_FLAG_IGNORE_CSUM_ERRORS);
- if (err || sz != inode->i_size) {
+ if (err || sz != size) {
bad_size = 7;
pctx->num = sz;
}
- } else if (inode->i_size & (fs->blocksize - 1))
+ } else if (size & (fs->blocksize - 1))
bad_size = 5;
else if (nblock > (pb.last_block + 1))
bad_size = 1;
bad_size = 2;
}
} else {
- size = EXT2_I_SIZE(inode);
if ((pb.last_init_lblock >= 0) &&
/* Do not allow initialized allocated blocks past i_size*/
(size < (__u64)pb.last_init_lblock * fs->blocksize) &&
pctx->num = (pb.last_block + 1) * fs->blocksize;
pctx->group = bad_size;
if (fix_problem(ctx, PR_1_BAD_I_SIZE, pctx)) {
- if (LINUX_S_ISDIR(inode->i_mode))
- pctx->num &= 0xFFFFFFFFULL;
ext2fs_inode_size_set(fs, inode, pctx->num);
if (EXT2_I_SIZE(inode) == 0 &&
(inode->i_flags & EXT4_INLINE_DATA_FL)) {
(unsigned long) pctx->ino, type,
(unsigned long) p->previous_block+1,
(unsigned long) blk,
- blockcnt);
+ (long long) blockcnt);
}
p->fragmented = 1;
}
}
if (p->is_dir && !ext2fs_has_feature_largedir(fs->super) &&
+ !pctx->inode->i_size_high &&
blockcnt > (1 << (21 - fs->super->s_log_block_size)))
problem = PR_1_TOOBIG_DIR;
if (p->is_dir && p->num_blocks + 1 >= p->max_blocks)
*block_nr = 0;
return BLOCK_CHANGED;
}
- if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+ if (e2fsck_should_abort(ctx))
return BLOCK_ABORT;
} else
mark_block_used(ctx, blk);
*block_nr = 0;
return BLOCK_CHANGED;
}
- if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+ if (e2fsck_should_abort(ctx))
return BLOCK_ABORT;
return 0;
}
*/
is_flexbg = ext2fs_has_feature_flex_bg(fs->super);
if (is_flexbg) {
- flexbg_size = 1 << fs->super->s_log_groups_per_flex;
+ flexbg_size = 1U << fs->super->s_log_groups_per_flex;
flexbg = group / flexbg_size;
first_block = ext2fs_group_first_block2(fs,
flexbg_size * flexbg);