#endif
#include "support/quotaio.h"
+#if __GNUC_PREREQ (4, 6)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-function"
+#endif
#include "ext2fs/fast_commit.h"
+#if __GNUC_PREREQ (4, 6)
+#pragma GCC diagnostic pop
+#endif
/*
* Exit codes used by fsck-type programs
#define E2F_OPT_UNSHARE_BLOCKS 0x40000
#define E2F_OPT_CLEAR_UNINIT 0x80000 /* Hack to clear the uninit bit */
#define E2F_OPT_CHECK_ENCODING 0x100000 /* Force verification of encoded filenames */
+#define E2F_OPT_MULTITHREAD 0x200000 /* Use multiple threads to speedup */
/*
* E2fsck flags
#define E2F_FLAG_TIME_INSANE 0x2000 /* Time is insane */
#define E2F_FLAG_PROBLEMS_FIXED 0x4000 /* At least one problem was fixed */
#define E2F_FLAG_ALLOC_OK 0x8000 /* Can we allocate blocks? */
+#define E2F_FLAG_DUP_BLOCK 0x20000 /* dup block found during pass1 */
#define E2F_RESET_FLAGS (E2F_FLAG_TIME_INSANE | E2F_FLAG_PROBLEMS_FIXED)
*/
typedef struct e2fsck_struct *e2fsck_t;
-#define MAX_EXTENT_DEPTH_COUNT 5
+#define MAX_EXTENT_DEPTH_COUNT 8
/*
* This strucutre is used to manage the list of extents in a file. Placing
struct extent_list fc_extent_list;
int fc_replay_num_tags;
int fc_replay_expected_off;
- int fc_current_pass;
+ enum passtype fc_current_pass;
int fc_cur_tag;
- int fc_crc;
+ unsigned int fc_crc;
__u16 fc_super_state;
};
+#ifdef HAVE_PTHREAD
+/*
+ * Fields that used for multi-thread
+ */
+struct e2fsck_thread {
+ /* Thread index */
+ int et_thread_index;
+ /* The start group number for this thread */
+ dgrp_t et_group_start;
+ /* The end (not included) group number for this thread*/
+ dgrp_t et_group_end;
+ /* The next group number to check */
+ dgrp_t et_group_next;
+ /* Scanned inode number */
+ ext2_ino_t et_inode_number;
+ char et_log_buf[2048];
+ int et_log_length;
+};
+#endif
+
struct e2fsck_struct {
+ /* Global context to get the cancel flag */
+ e2fsck_t global_ctx;
ext2_filsys fs;
const char *program_name;
char *filesystem_name;
ext2_ino_t free_inodes;
int mount_flags;
int openfs_flags;
+ io_manager io_manager;
blkid_cache blkid; /* blkid cache */
#ifdef HAVE_SETJMP_H
ext2_refcount_t refcount;
ext2_refcount_t refcount_extra;
+ ext2_refcount_t refcount_orig;
/*
* Quota blocks and inodes to be charged for each ea block.
/*
* For pass1_check_directory and pass1_get_blocks
*/
- ext2_ino_t stashed_ino;
- struct ext2_inode *stashed_inode;
+ ext2_ino_t stashed_ino;
+ struct ext2_inode *stashed_inode;
+
+ /* if @global_ctx is null, this field is unused */
+#ifdef HAVE_PTHREAD
+ struct e2fsck_thread thread_info;
+#endif
/*
* Location of the lost and found directory
__u32 fs_fragmented;
__u32 fs_fragmented_dir;
__u32 large_files;
+ __u32 large_dirs;
__u32 fs_ext_attr_inodes;
__u32 fs_ext_attr_blocks;
__u32 extent_depth_count[MAX_EXTENT_DEPTH_COUNT];
int ext_attr_ver;
profile_t profile;
int blocks_per_page;
+ ext2_u32_list casefolded_dirs;
/* Reserve blocks for root and l+f re-creation */
blk64_t root_repair_block, lnf_repair_block;
/* Fast commit replay state */
struct e2fsck_fc_replay_state fc_replay_state;
+#ifdef HAVE_PTHREAD
+ __u32 fs_num_threads;
+ int fs_need_locking;
+ /* serialize fix operation for multiple threads */
+ pthread_rwlock_t fs_fix_rwlock;
+ /* protect block_found_map, block_dup_map */
+ pthread_rwlock_t fs_block_map_rwlock;
+#endif
};
+#ifdef HAVE_PTHREAD
+#ifdef DEBUG_THREADS
+/*
+ * Enabling DEBUG_THREADS would cause the parallel
+ * fsck threads run sequentially.
+ */
+struct e2fsck_thread_debug {
+ pthread_mutex_t etd_mutex;
+ pthread_cond_t etd_cond;
+ int etd_finished_threads;
+};
+#endif
+
+struct e2fsck_thread_info {
+ /* ID returned by pthread_create() */
+ pthread_t eti_thread_id;
+ /* Application-defined thread index */
+ int eti_thread_index;
+ /* Thread has been started */
+ int eti_started;
+ /* Context used for this thread */
+ e2fsck_t eti_thread_ctx;
+#ifdef DEBUG_THREADS
+ struct e2fsck_thread_debug *eti_debug;
+#endif
+};
+
+#endif
+
/* Data structures to evaluate whether an extent tree needs rebuilding. */
struct extent_tree_level {
unsigned int num_extents;
extern void e2fsck_pass1(e2fsck_t ctx);
extern void e2fsck_pass1_dupblocks(e2fsck_t ctx, char *block_buf);
+extern void e2fsck_pass1_check_lock(e2fsck_t ctx);
+extern void e2fsck_pass1_check_unlock(e2fsck_t ctx);
extern void e2fsck_pass2(e2fsck_t ctx);
extern void e2fsck_pass3(e2fsck_t ctx);
extern void e2fsck_pass4(e2fsck_t ctx);
/* dirinfo.c */
extern void e2fsck_add_dir_info(e2fsck_t ctx, ext2_ino_t ino, ext2_ino_t parent);
+void e2fsck_merge_dir_info(e2fsck_t ctx, struct dir_info_db *src,
+ struct dir_info_db *dest);
extern void e2fsck_free_dir_info(e2fsck_t ctx);
extern int e2fsck_get_num_dirinfo(e2fsck_t ctx);
extern struct dir_info_iter *e2fsck_dir_info_iter_begin(e2fsck_t ctx);
ext2_ino_t *parent);
extern int e2fsck_dir_info_get_dotdot(e2fsck_t ctx, ext2_ino_t ino,
ext2_ino_t *dotdot);
+extern void e2fsck_merge_dx_dir(e2fsck_t global_ctx, e2fsck_t thread_ctx);
/* dx_dirinfo.c */
extern void e2fsck_add_dx_dir(e2fsck_t ctx, ext2_ino_t ino,
void check_resize_inode(e2fsck_t ctx);
/* util.c */
+#define E2FSCK_MAX_THREADS (65536)
extern void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned long size,
const char *description);
extern int ask(e2fsck_t ctx, const char * string, int def);
const char *profile_name,
ext2fs_block_bitmap *ret);
unsigned long long get_memory_size(void);
+extern void e2fsck_pass1_fix_lock(e2fsck_t ctx);
+extern void e2fsck_pass1_fix_unlock(e2fsck_t ctx);
+extern void e2fsck_pass1_block_map_w_lock(e2fsck_t ctx);
+extern void e2fsck_pass1_block_map_w_unlock(e2fsck_t ctx);
+extern void e2fsck_pass1_block_map_r_lock(e2fsck_t ctx);
+extern void e2fsck_pass1_block_map_r_unlock(e2fsck_t ctx);
/* unix.c */
extern void e2fsck_clear_progbar(e2fsck_t ctx);