#include <stdio.h>
#include <string.h>
+#include <stddef.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#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_EXPAND_EISIZE 0x10000 /* Expand the inodes (i_extra_isize) */
+#define E2F_FLAG_DUP_BLOCK 0x20000 /* dup block found during pass1 */
#define E2F_RESET_FLAGS (E2F_FLAG_TIME_INSANE | E2F_FLAG_PROBLEMS_FIXED)
#define E2F_PASS_5 5
#define E2F_PASS_1B 6
+enum shared_opt {
+ E2F_SHARED_PRESERVE = 0,
+ E2F_SHARED_DELETE,
+ E2F_SHARED_LPF
+};
+
+enum clone_opt {
+ E2F_CLONE_DUP = 0,
+ E2F_CLONE_ZERO
+};
+
+#define EXT4_FITS_IN_INODE(ext4_inode, einode, field) \
+ ((offsetof(typeof(*ext4_inode), field) + \
+ sizeof(ext4_inode->field)) <= \
+ (EXT2_GOOD_OLD_INODE_SIZE + \
+ (einode)->i_extra_isize)) \
+
+#define EXT4_XTIME_FUTURE(ctx, sb, xtime, margin) \
+ (!((ctx)->flags & E2F_FLAG_TIME_INSANE) && \
+ (xtime) > (ctx)->now + (margin))
+#define EXT4_XTIME_ANCIENT(ctx, sb, xtime, margin) \
+ ((sb)->s_mkfs_time > (margin) && (xtime) < (sb)->s_mkfs_time - (margin))
+
+#define BADNESS_THRESHOLD 12
+#define BADNESS_MAX 0x7fff
+
/*
* Define the extended attribute refcount structure
*/
dgrp_t et_group_next;
/* Scanned inode number */
ext2_ino_t et_inode_number;
- char et_log_buf[2048];
int et_log_length;
+ char et_log_buf[2048];
};
#endif
struct e2fsck_struct {
/* Global context to get the cancel flag */
e2fsck_t global_ctx;
- ext2_filsys fs;
+ ext2_filsys fs; /* [fs_fix_rwlock] */
const char *program_name;
char *filesystem_name;
char *device_name;
char *log_fn;
FILE *problem_logf;
char *problem_log_fn;
- int flags; /* E2fsck internal flags */
+ /* E2fsck internal flags.
+ * shared by different threads for pass1 [fs_fix_rwlock] */
+ int flags;
int options;
unsigned blocksize; /* blocksize */
blk64_t use_superblock; /* sb requested by user */
int (*progress)(e2fsck_t ctx, int pass, unsigned long cur,
unsigned long max);
+ /* The following inode bitmaps are separately used in thread_ctx Pass1*/
ext2fs_inode_bitmap inode_used_map; /* Inodes which are in use */
- ext2fs_inode_bitmap inode_bad_map; /* Inodes which are bad somehow */
ext2fs_inode_bitmap inode_dir_map; /* Inodes which are directories */
ext2fs_inode_bitmap inode_bb_map; /* Inodes which are in bad blocks */
ext2fs_inode_bitmap inode_imagic_map; /* AFS inodes */
ext2fs_inode_bitmap inode_reg_map; /* Inodes which are regular files*/
ext2fs_inode_bitmap inode_casefold_map; /* Inodes which are casefolded */
+ /* Following 3 protected by [fs_block_map_rwlock] */
ext2fs_block_bitmap block_found_map; /* Blocks which are in use */
ext2fs_block_bitmap block_dup_map; /* Blks referenced more than once */
ext2fs_block_bitmap block_ea_map; /* Blocks which are used by EA's */
/*
- * Inode count arrays
+ * Inode count arrays.
+ * Separately used in thread_ctx, pass1
*/
ext2_icount_t inode_count;
ext2_icount_t inode_link_info;
+ ext2_icount_t inode_badness;
+ unsigned int inode_badness_threshold;
ext2_refcount_t refcount;
ext2_refcount_t refcount_extra;
/*
* Array of flags indicating whether an inode bitmap, block
- * bitmap, or inode table is invalid
+ * bitmap, or inode table is invalid.
+ * Separately used in thread_ctx, pass1
*/
int *invalid_inode_bitmap_flag;
int *invalid_block_bitmap_flag;
char *block_buf;
/*
- * For pass1_check_directory and pass1_get_blocks
+ * For pass1_check_directory and pass1_get_blocks.
+ * Separately used in thread_ctx in pass1
*/
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
*/
/*
* How we display the progress update (for unix)
+ * shared by different threads for pass1 [fs_fix_rwlock]
*/
int progress_fd;
int progress_pos;
int interactive; /* Are we connected directly to a tty? */
char start_meta[2], stop_meta[2];
- /* File counts */
+ /* File counts. Separately used in thread_ctx, pass1 */
__u32 fs_directory_count;
__u32 fs_regular_count;
__u32 fs_blockdev_count;
time_t now;
time_t time_fudge; /* For working around buggy init scripts */
int ext_attr_ver;
+ enum shared_opt shared;
+ enum clone_opt clone;
profile_t profile;
int blocks_per_page;
ext2_u32_list casefolded_dirs;
+ /* Expand large inodes to atleast these many bytes */
+ int want_extra_isize;
+ /* minimum i_extra_isize found in used inodes. Should not be lesser
+ * than s_min_extra_isize.
+ */
+ __u32 min_extra_isize;
+ int fs_unexpanded_inodes;
+ ext2fs_inode_bitmap expand_eisize_map;
+
/* 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
+ /* if @global_ctx is null, this field is unused */
+ struct e2fsck_thread thread_info;
+ __u32 pfs_num_threads;
+ __u32 mmp_update_thread;
+ int fs_need_locking;
/* serialize fix operation for multiple threads */
- pthread_mutex_t fs_fix_mutex;
+ pthread_rwlock_t fs_fix_rwlock;
/* protect block_found_map, block_dup_map */
- pthread_mutex_t fs_block_map_mutex;
+ pthread_rwlock_t fs_block_map_rwlock;
+ struct e2fsck_thread_info *infos;
#endif
};
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);
void destroy_encryption_policy_map(e2fsck_t ctx);
void destroy_encrypted_file_info(e2fsck_t ctx);
+int e2fsck_merge_encrypted_info(e2fsck_t ctx, struct encrypted_file_info *src,
+ struct encrypted_file_info *dest);
/* extents.c */
errcode_t e2fsck_rebuild_extents_later(e2fsck_t ctx, ext2_ino_t ino);
extern void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int use_shortcuts);
extern int e2fsck_pass1_check_device_inode(ext2_filsys fs,
struct ext2_inode *inode);
-extern int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino,
+extern int e2fsck_pass1_check_symlink(e2fsck_t ctx, ext2_ino_t ino,
struct ext2_inode *inode, char *buf);
extern void e2fsck_clear_inode(e2fsck_t ctx, ext2_ino_t ino,
struct ext2_inode *inode, int restart_flag,
const char *source);
+#define e2fsck_mark_inode_bad(ctx, pctx, code) \
+ e2fsck_mark_inode_bad_loc(ctx, pctx, code, 1, __func__, __LINE__)
+#define e2fsck_mark_inode_badder(ctx, pctx, code) \
+ e2fsck_mark_inode_bad_loc(ctx, pctx, code, 2, __func__, __LINE__)
+extern void e2fsck_mark_inode_bad_loc(e2fsck_t ctx,
+ struct problem_context *pctx, __u32 code,
+ int count, const char *func, const int line);
+extern int e2fsck_fix_bad_inode(e2fsck_t ctx, struct problem_context *pctx);
extern void e2fsck_intercept_block_allocations(e2fsck_t ctx);
/* pass2.c */
void check_resize_inode(e2fsck_t ctx);
/* util.c */
+#define E2FSCK_MAX_THREADS (65535)
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);
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_lock(e2fsck_t ctx);
-extern void e2fsck_pass1_block_map_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);