diff --git a/configure b/configure index d8f6debc..6c503aaf 100755 --- a/configure +++ b/configure @@ -12404,7 +12404,7 @@ fi done fi -for ac_header in dirent.h errno.h execinfo.h getopt.h malloc.h mntent.h paths.h semaphore.h setjmp.h signal.h stdarg.h stdint.h stdlib.h termios.h termio.h unistd.h utime.h linux/falloc.h linux/fd.h linux/major.h linux/loop.h net/if_dl.h netinet/in.h sys/disklabel.h sys/disk.h sys/file.h sys/ioctl.h sys/mkdev.h sys/mman.h sys/mount.h sys/prctl.h sys/resource.h sys/select.h sys/socket.h sys/sockio.h sys/stat.h sys/syscall.h sys/sysmacros.h sys/time.h sys/types.h sys/un.h sys/wait.h +for ac_header in dirent.h errno.h execinfo.h getopt.h malloc.h mntent.h paths.h semaphore.h setjmp.h signal.h stdarg.h stdint.h stdlib.h termios.h termio.h unistd.h utime.h attr/xattr.h linux/falloc.h linux/fd.h linux/major.h linux/loop.h net/if_dl.h netinet/in.h sys/disklabel.h sys/disk.h sys/file.h sys/ioctl.h sys/mkdev.h sys/mman.h sys/mount.h sys/prctl.h sys/resource.h sys/select.h sys/socket.h sys/sockio.h sys/stat.h sys/syscall.h sys/sysmacros.h sys/time.h sys/types.h sys/un.h sys/wait.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" @@ -13071,7 +13071,7 @@ if test "$ac_res" != no; then : fi fi -for ac_func in __secure_getenv backtrace blkid_probe_get_topology blkid_probe_enable_partitions chflags fadvise64 fallocate fallocate64 fchown fdatasync fstat64 ftruncate64 futimes getcwd getdtablesize getmntinfo getpwuid_r getrlimit getrusage jrand48 llseek lseek64 mallinfo mbstowcs memalign mempcpy mmap msync nanosleep open64 pathconf posix_fadvise posix_fadvise64 posix_memalign prctl secure_getenv setmntent setresgid setresuid snprintf srandom stpcpy strcasecmp strdup strnlen strptime strtoull sync_file_range sysconf usleep utime valloc +for ac_func in __secure_getenv backtrace blkid_probe_get_topology blkid_probe_enable_partitions chflags fadvise64 fallocate fallocate64 fchown fdatasync fstat64 ftruncate64 futimes getcwd getdtablesize getmntinfo getpwuid_r getrlimit getrusage jrand48 llistxattr llseek lseek64 mallinfo mbstowcs memalign mempcpy mmap msync nanosleep open64 pathconf posix_fadvise posix_fadvise64 posix_memalign prctl secure_getenv setmntent setresgid setresuid snprintf srandom stpcpy strcasecmp strdup strnlen strptime strtoull sync_file_range sysconf usleep utime valloc do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" diff --git a/configure.in b/configure.in index 79c8dc26..67e54531 100644 --- a/configure.in +++ b/configure.in @@ -920,6 +920,7 @@ AC_CHECK_HEADERS(m4_flatten([ termio.h unistd.h utime.h + attr/xattr.h linux/falloc.h linux/fd.h linux/major.h @@ -1098,6 +1099,7 @@ AC_CHECK_FUNCS(m4_flatten([ getrlimit getrusage jrand48 + llistxattr llseek lseek64 mallinfo diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c index 5ab43a3e..641e8bc3 100644 --- a/debugfs/debugfs.c +++ b/debugfs/debugfs.c @@ -2094,7 +2094,6 @@ void do_symlink(int argc, char *argv[]) void do_dump_mmp(int argc EXT2FS_ATTR((unused)), char *argv[]) { #if CONFIG_MMP - struct ext2_super_block *sb; struct mmp_struct *mmp_s; time_t t; errcode_t retval = 0; @@ -2102,8 +2101,6 @@ void do_dump_mmp(int argc EXT2FS_ATTR((unused)), char *argv[]) if (check_fs_open(argv[0])) return; - sb = current_fs->super; - if (current_fs->mmp_buf == NULL) { retval = ext2fs_get_mem(current_fs->blocksize, ¤t_fs->mmp_buf); diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h index d6d0ba9f..8f162182 100644 --- a/e2fsck/e2fsck.h +++ b/e2fsck/e2fsck.h @@ -369,6 +369,9 @@ struct e2fsck_struct { profile_t profile; int blocks_per_page; + /* Reserve blocks for root and l+f re-creation */ + blk64_t root_repair_block, lnf_repair_block; + /* * For the use of callers of the e2fsck functions; not used by * e2fsck functions themselves. diff --git a/e2fsck/journal.c b/e2fsck/journal.c index a971df1d..206685af 100644 --- a/e2fsck/journal.c +++ b/e2fsck/journal.c @@ -443,8 +443,7 @@ static errcode_t e2fsck_get_journal(e2fsck_t ctx, journal_t **ret_journal) if (ext_journal) { blk64_t maxlen; - if (ctx->fs->blocksize == 1024) - start = 1; + start = ext2fs_journal_sb_start(ctx->fs->blocksize) - 1; bh = getblk(dev_journal, start, ctx->fs->blocksize); if (!bh) { retval = EXT2_ET_NO_MEMORY; @@ -455,7 +454,7 @@ static errcode_t e2fsck_get_journal(e2fsck_t ctx, journal_t **ret_journal) brelse(bh); goto errout; } - memcpy(&jsuper, start ? bh->b_data : bh->b_data + 1024, + memcpy(&jsuper, start ? bh->b_data : bh->b_data + SUPERBLOCK_OFFSET, sizeof(jsuper)); brelse(bh); #ifdef WORDS_BIGENDIAN diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c index 10ffe394..26fe60cb 100644 --- a/e2fsck/pass1.c +++ b/e2fsck/pass1.c @@ -277,8 +277,7 @@ static void check_size(e2fsck_t ctx, struct problem_context *pctx) if (!fix_problem(ctx, PR_1_SET_NONZSIZE, pctx)) return; - inode->i_size = 0; - inode->i_size_high = 0; + ext2fs_inode_size_set(ctx->fs, inode, 0); e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1"); } @@ -601,6 +600,42 @@ static errcode_t recheck_bad_inode_checksum(ext2_filsys fs, ext2_ino_t ino, return 0; } +static void reserve_block_for_root_repair(e2fsck_t ctx) +{ + blk64_t blk = 0; + errcode_t err; + ext2_filsys fs = ctx->fs; + + ctx->root_repair_block = 0; + if (ext2fs_test_inode_bitmap2(ctx->inode_used_map, EXT2_ROOT_INO)) + return; + + err = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk); + if (err) + return; + ext2fs_mark_block_bitmap2(ctx->block_found_map, blk); + ctx->root_repair_block = blk; +} + +static void reserve_block_for_lnf_repair(e2fsck_t ctx) +{ + blk64_t blk = 0; + errcode_t err; + ext2_filsys fs = ctx->fs; + static const char name[] = "lost+found"; + ext2_ino_t ino; + + ctx->lnf_repair_block = 0; + if (!ext2fs_lookup(fs, EXT2_ROOT_INO, name, sizeof(name)-1, 0, &ino)) + return; + + err = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk); + if (err) + return; + ext2fs_mark_block_bitmap2(ctx->block_found_map, blk); + ctx->lnf_repair_block = blk; +} + void e2fsck_pass1(e2fsck_t ctx) { int i; @@ -935,8 +970,10 @@ void e2fsck_pass1(e2fsck_t ctx) if (ino == EXT2_BAD_INO) { struct process_block_struct pb; - if ((inode->i_mode || inode->i_uid || inode->i_gid || - inode->i_links_count || inode->i_file_acl) && + if ((failed_csum || inode->i_mode || inode->i_uid || + inode->i_gid || inode->i_links_count || + (inode->i_flags & EXT4_INLINE_DATA_FL) || + inode->i_file_acl) && fix_problem(ctx, PR_1_INVALID_BAD_INODE, &pctx)) { memset(inode, 0, sizeof(struct ext2_inode)); e2fsck_write_inode(ctx, ino, inode, @@ -1280,6 +1317,9 @@ void e2fsck_pass1(e2fsck_t ctx) 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 @@ -1906,6 +1946,40 @@ void e2fsck_clear_inode(e2fsck_t ctx, ext2_ino_t ino, e2fsck_write_inode(ctx, ino, inode, source); } +/* + * Use the multiple-blocks reclamation code to fix alignment problems in + * a bigalloc filesystem. We want a logical cluster to map to *only* one + * physical cluster, and we want the block offsets within that cluster to + * line up. + */ +static int has_unaligned_cluster_map(e2fsck_t ctx, + blk64_t last_pblk, e2_blkcnt_t last_lblk, + blk64_t pblk, blk64_t lblk) +{ + blk64_t cluster_mask; + + if (!ctx->fs->cluster_ratio_bits) + return 0; + cluster_mask = EXT2FS_CLUSTER_MASK(ctx->fs); + + /* + * If the block in the logical cluster doesn't align with the block in + * the physical cluster... + */ + if ((lblk & cluster_mask) != (pblk & cluster_mask)) + return 1; + + /* + * If we cross a physical cluster boundary within a logical cluster... + */ + if (last_pblk && (lblk & cluster_mask) != 0 && + EXT2FS_B2C(ctx->fs, lblk) == EXT2FS_B2C(ctx->fs, last_lblk) && + EXT2FS_B2C(ctx->fs, pblk) != EXT2FS_B2C(ctx->fs, last_pblk)) + return 1; + + return 0; +} + static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx, struct process_block_struct *pb, blk64_t start_block, blk64_t end_block, @@ -1937,12 +2011,14 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx, last_lblk = extent.e_lblk + extent.e_len - 1; problem = 0; + pctx->blk = extent.e_pblk; + pctx->blk2 = extent.e_lblk; + pctx->num = extent.e_len; + pctx->blkcount = extent.e_lblk + extent.e_len; + /* Ask to clear a corrupt extent block */ if (try_repairs && pctx->errcode == EXT2_ET_EXTENT_CSUM_INVALID) { - pctx->blk = extent.e_pblk; - pctx->blk2 = extent.e_lblk; - pctx->num = extent.e_len; problem = PR_1_EXTENT_CSUM_INVALID; if (fix_problem(ctx, problem, pctx)) goto fix_problem_now; @@ -1970,19 +2046,6 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx, (1 << (21 - ctx->fs->super->s_log_block_size)))) problem = PR_1_TOOBIG_DIR; - /* Corrupt but passes checks? Ask to fix checksum. */ - if (try_repairs && failed_csum) { - pctx->blk = extent.e_pblk; - pctx->blk2 = extent.e_lblk; - pctx->num = extent.e_len; - problem = 0; - if (fix_problem(ctx, PR_1_EXTENT_ONLY_CSUM_INVALID, - pctx)) { - pb->inode_modified = 1; - ext2fs_extent_replace(ehandle, 0, &extent); - } - } - /* * Uninitialized blocks in a directory? Clear the flag and * we'll interpret the blocks later. @@ -1999,12 +2062,18 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx, failed_csum = 0; } + /* Failed csum but passes checks? Ask to fix checksum. */ + if (try_repairs && failed_csum && problem == 0 && + fix_problem(ctx, PR_1_EXTENT_ONLY_CSUM_INVALID, pctx)) { + pb->inode_modified = 1; + pctx->errcode = ext2fs_extent_replace(ehandle, + 0, &extent); + if (pctx->errcode) + return; + } + if (try_repairs && problem) { report_problem: - pctx->blk = extent.e_pblk; - pctx->blk2 = extent.e_lblk; - pctx->num = extent.e_len; - pctx->blkcount = extent.e_lblk + extent.e_len; if (fix_problem(ctx, problem, pctx)) { fix_problem_now: if (ctx->invalid_bitmaps) { @@ -2210,7 +2279,16 @@ alloc_later: mark_block_used(ctx, blk); pb->num_blocks++; } - + if (has_unaligned_cluster_map(ctx, pb->previous_block, + pb->last_block, blk, + blockcnt)) { + pctx->blk = blockcnt; + pctx->blk2 = blk; + fix_problem(ctx, PR_1_MISALIGNED_CLUSTER, pctx); + mark_block_used(ctx, blk); + mark_block_used(ctx, blk); + } + pb->last_block = blockcnt; pb->previous_block = blk; if (is_dir) { @@ -2505,9 +2583,9 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, pctx->num = (pb.last_block+1) * fs->blocksize; pctx->group = bad_size; if (fix_problem(ctx, PR_1_BAD_I_SIZE, pctx)) { - inode->i_size = pctx->num; - if (!LINUX_S_ISDIR(inode->i_mode)) - inode->i_size_high = pctx->num >> 32; + if (LINUX_S_ISDIR(inode->i_mode)) + pctx->num &= 0xFFFFFFFFULL; + ext2fs_inode_size_set(fs, inode, pctx->num); dirty_inode++; } pctx->num = 0; @@ -2776,6 +2854,13 @@ static int process_block(ext2_filsys fs, ((unsigned) blockcnt & EXT2FS_CLUSTER_MASK(ctx->fs)))) { mark_block_used(ctx, blk); p->num_blocks++; + } else if (has_unaligned_cluster_map(ctx, p->previous_block, + p->last_block, blk, blockcnt)) { + pctx->blk = blockcnt; + pctx->blk2 = blk; + fix_problem(ctx, PR_1_MISALIGNED_CLUSTER, pctx); + mark_block_used(ctx, blk); + mark_block_used(ctx, blk); } if (blockcnt >= 0) p->last_block = blockcnt; diff --git a/e2fsck/pass1b.c b/e2fsck/pass1b.c index 8d42d100..2d1b448b 100644 --- a/e2fsck/pass1b.c +++ b/e2fsck/pass1b.c @@ -261,7 +261,7 @@ struct process_block_struct { e2fsck_t ctx; ext2_ino_t ino; int dup_blocks; - blk64_t cur_cluster; + blk64_t cur_cluster, phys_cluster; blk64_t last_blk; struct ext2_inode *inode; struct problem_context *pctx; @@ -317,6 +317,7 @@ static void pass1b(e2fsck_t ctx, char *block_buf) pb.dup_blocks = 0; pb.inode = &inode; pb.cur_cluster = ~0; + pb.phys_cluster = ~0; pb.last_blk = 0; pb.pctx->blk = pb.pctx->blk2 = 0; @@ -360,7 +361,7 @@ static int process_pass1b_block(ext2_filsys fs EXT2FS_ATTR((unused)), { struct process_block_struct *p; e2fsck_t ctx; - blk64_t lc; + blk64_t lc, pc; problem_t op; if (HOLE_BLKADDR(*block_nr)) @@ -368,6 +369,7 @@ static int process_pass1b_block(ext2_filsys fs EXT2FS_ATTR((unused)), p = (struct process_block_struct *) priv_data; ctx = p->ctx; lc = EXT2FS_B2C(fs, blockcnt); + pc = EXT2FS_B2C(fs, *block_nr); if (!ext2fs_test_block_bitmap2(ctx->block_dup_map, *block_nr)) goto finish; @@ -389,11 +391,19 @@ static int process_pass1b_block(ext2_filsys fs EXT2FS_ATTR((unused)), p->dup_blocks++; ext2fs_mark_inode_bitmap2(inode_dup_map, p->ino); - if (blockcnt < 0 || lc != p->cur_cluster) + /* + * Qualifications for submitting a block for duplicate processing: + * It's an extent/indirect block (and has a negative logical offset); + * we've crossed a logical cluster boundary; or the physical cluster + * suddenly changed, which indicates that blocks in a logical cluster + * are mapped to multiple physical clusters. + */ + if (blockcnt < 0 || lc != p->cur_cluster || pc != p->phys_cluster) add_dupe(ctx, p->ino, EXT2FS_B2C(fs, *block_nr), p->inode); finish: p->cur_cluster = lc; + p->phys_cluster = pc; return 0; } @@ -563,7 +573,11 @@ static void pass1d(e2fsck_t ctx, char *block_buf) pctx.dir = t->dir; fix_problem(ctx, PR_1D_DUP_FILE_LIST, &pctx); } - if (file_ok) { + /* + * Even if the file shares blocks with itself, we still need to + * clone the blocks. + */ + if (file_ok && (meta_data ? shared_len+1 : shared_len) != 0) { fix_problem(ctx, PR_1D_DUP_BLOCKS_DEALT, &pctx); continue; } @@ -630,7 +644,8 @@ static int delete_file_block(ext2_filsys fs, _("internal error: can't find dup_blk for %llu\n"), *block_nr); } else { - ext2fs_block_alloc_stats2(fs, *block_nr, -1); + if ((*block_nr % EXT2FS_CLUSTER_RATIO(ctx->fs)) == 0) + ext2fs_block_alloc_stats2(fs, *block_nr, -1); pb->dup_blocks++; } pb->cur_cluster = lc; @@ -706,9 +721,10 @@ struct clone_struct { errcode_t errcode; blk64_t dup_cluster; blk64_t alloc_block; - ext2_ino_t dir; + ext2_ino_t dir, ino; char *buf; e2fsck_t ctx; + struct ext2_inode *inode; }; static int clone_file_block(ext2_filsys fs, @@ -756,13 +772,26 @@ static int clone_file_block(ext2_filsys fs, decrement_badcount(ctx, *block_nr, p); cs->dup_cluster = c; - + /* + * Let's try an implied cluster allocation. If we get the same + * cluster back, then we need to find a new block; otherwise, + * we're merely fixing the problem of one logical cluster being + * mapped to multiple physical clusters. + */ + new_block = 0; + retval = ext2fs_map_cluster_block(fs, cs->ino, cs->inode, + blockcnt, &new_block); + if (retval == 0 && new_block != 0 && + EXT2FS_B2C(ctx->fs, new_block) != + EXT2FS_B2C(ctx->fs, *block_nr)) + goto cluster_alloc_ok; retval = ext2fs_new_block2(fs, 0, ctx->block_found_map, &new_block); if (retval) { cs->errcode = retval; return BLOCK_ABORT; } +cluster_alloc_ok: cs->alloc_block = new_block; got_block: @@ -817,6 +846,8 @@ static errcode_t clone_file(e2fsck_t ctx, ext2_ino_t ino, cs.dup_cluster = ~0; cs.alloc_block = 0; cs.ctx = ctx; + cs.ino = ino; + cs.inode = &dp->inode; retval = ext2fs_get_mem(fs->blocksize, &cs.buf); if (retval) return retval; diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c index 0ef96373..69ebab6f 100644 --- a/e2fsck/pass2.c +++ b/e2fsck/pass2.c @@ -665,7 +665,8 @@ clear_and_exit: static void salvage_directory(ext2_filsys fs, struct ext2_dir_entry *dirent, struct ext2_dir_entry *prev, - unsigned int *offset) + unsigned int *offset, + unsigned int block_len) { char *cp = (char *) dirent; int left; @@ -673,7 +674,7 @@ static void salvage_directory(ext2_filsys fs, unsigned int name_len = ext2fs_dirent_name_len(dirent); (void) ext2fs_get_rec_len(fs, dirent, &rec_len); - left = fs->blocksize - *offset - rec_len; + left = block_len - *offset - rec_len; /* * Special case of directory entry of size 8: copy what's left @@ -703,7 +704,7 @@ static void salvage_directory(ext2_filsys fs, * previous directory entry absorb the invalid one. */ if (prev && rec_len && (rec_len % 4) == 0 && - (*offset + rec_len <= fs->blocksize)) { + (*offset + rec_len <= block_len)) { (void) ext2fs_get_rec_len(fs, prev, &prev_rec_len); prev_rec_len += rec_len; (void) ext2fs_set_rec_len(fs, prev_rec_len, prev); @@ -718,11 +719,11 @@ static void salvage_directory(ext2_filsys fs, */ if (prev) { (void) ext2fs_get_rec_len(fs, prev, &prev_rec_len); - prev_rec_len += fs->blocksize - *offset; + prev_rec_len += block_len - *offset; (void) ext2fs_set_rec_len(fs, prev_rec_len, prev); *offset = fs->blocksize; } else { - rec_len = fs->blocksize - *offset; + rec_len = block_len - *offset; (void) ext2fs_set_rec_len(fs, rec_len, dirent); ext2fs_dirent_set_name_len(dirent, 0); ext2fs_dirent_set_file_type(dirent, EXT2_FT_UNKNOWN); @@ -739,6 +740,38 @@ static int is_last_entry(ext2_filsys fs, int inline_data_size, return (offset < fs->blocksize - csum_size); } +#define NEXT_DIRENT(d) ((void *)((char *)(d) + (d)->rec_len)) +static errcode_t insert_dirent_tail(ext2_filsys fs, void *dirbuf) +{ + struct ext2_dir_entry *d; + void *top; + struct ext2_dir_entry_tail *t; + unsigned int rec_len; + + d = dirbuf; + top = EXT2_DIRENT_TAIL(dirbuf, fs->blocksize); + + while (d->rec_len && !(d->rec_len & 0x3) && NEXT_DIRENT(d) <= top) + d = NEXT_DIRENT(d); + + if (d != top) { + size_t min_size = EXT2_DIR_REC_LEN( + ext2fs_dirent_name_len(dirbuf)); + if (min_size > top - (void *)d) + return EXT2_ET_DIR_NO_SPACE_FOR_CSUM; + d->rec_len = top - (void *)d; + } + + t = (struct ext2_dir_entry_tail *)top; + if (t->det_reserved_zero1 || + t->det_rec_len != sizeof(struct ext2_dir_entry_tail) || + t->det_reserved_name_len != EXT2_DIR_NAME_LEN_CSUM) + ext2fs_initialize_dirent_tail(fs, t); + + return 0; +} +#undef NEXT_DIRENT + static int check_dir_block(ext2_filsys fs, struct ext2_db_entry2 *db, void *priv_data) @@ -960,8 +993,12 @@ skip_checksum: (rec_len < 12) || ((rec_len % 4) != 0) || ((ext2fs_dirent_name_len(dirent) + 8) > rec_len)) { - if (fix_problem(ctx, PR_2_DIR_CORRUPTED, &cd->pctx)) { - salvage_directory(fs, dirent, prev, &offset); + if (fix_problem(ctx, PR_2_DIR_CORRUPTED, + &cd->pctx)) { + salvage_directory(fs, dirent, prev, + &offset, + fs->blocksize - + de_csum_size); dir_modified++; continue; } else @@ -1275,8 +1312,12 @@ skip_checksum: if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super, EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) && is_leaf && - !ext2fs_dirent_has_tail(fs, (struct ext2_dir_entry *)buf)) + !inline_data_size && + !ext2fs_dirent_has_tail(fs, (struct ext2_dir_entry *)buf)) { + if (insert_dirent_tail(fs, buf) == 0) + goto write_and_fix; e2fsck_rehash_dir_later(ctx, ino); + } write_and_fix: if (e2fsck_dir_will_be_rehashed(ctx, ino)) @@ -1336,7 +1377,8 @@ static int deallocate_inode_block(ext2_filsys fs, if ((*block_nr < fs->super->s_first_data_block) || (*block_nr >= ext2fs_blocks_count(fs->super))) return 0; - ext2fs_block_alloc_stats2(fs, *block_nr, -1); + if ((*block_nr % EXT2FS_CLUSTER_RATIO(fs)) == 0) + ext2fs_block_alloc_stats2(fs, *block_nr, -1); p->num++; return 0; } @@ -1577,7 +1619,7 @@ static int allocate_dir_block(e2fsck_t ctx, struct problem_context *pctx) { ext2_filsys fs = ctx->fs; - blk64_t blk; + blk64_t blk = 0; char *block; struct ext2_inode inode; @@ -1593,11 +1635,17 @@ static int allocate_dir_block(e2fsck_t ctx, /* * First, find a free block */ - pctx->errcode = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk); - if (pctx->errcode) { - pctx->str = "ext2fs_new_block"; - fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx); - return 1; + e2fsck_read_inode(ctx, db->ino, &inode, "allocate_dir_block"); + pctx->errcode = ext2fs_map_cluster_block(fs, db->ino, &inode, + db->blockcnt, &blk); + if (pctx->errcode || blk == 0) { + pctx->errcode = ext2fs_new_block2(fs, 0, + ctx->block_found_map, &blk); + if (pctx->errcode) { + pctx->str = "ext2fs_new_block"; + fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx); + return 1; + } } ext2fs_mark_block_bitmap2(ctx->block_found_map, blk); ext2fs_mark_block_bitmap2(fs->block_map, blk); @@ -1629,10 +1677,16 @@ static int allocate_dir_block(e2fsck_t ctx, /* * Update the inode block count */ - e2fsck_read_inode(ctx, db->ino, &inode, "allocate_dir_block"); ext2fs_iblk_add_blocks(fs, &inode, 1); - if (inode.i_size < (db->blockcnt+1) * fs->blocksize) - inode.i_size = (db->blockcnt+1) * fs->blocksize; + if (EXT2_I_SIZE(&inode) < (db->blockcnt+1) * fs->blocksize) { + pctx->errcode = ext2fs_inode_size_set(fs, &inode, + (db->blockcnt+1) * fs->blocksize); + if (pctx->errcode) { + pctx->str = "ext2fs_inode_size_set"; + fix_problem(ctx, PR_2_ALLOC_DIRBOCK, pctx); + return 1; + } + } e2fsck_write_inode(ctx, db->ino, &inode, "allocate_dir_block"); /* diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c index 4fc390a8..31131ab5 100644 --- a/e2fsck/pass3.c +++ b/e2fsck/pass3.c @@ -134,6 +134,17 @@ abort_exit: inode_done_map = 0; } + if (ctx->lnf_repair_block) { + ext2fs_unmark_block_bitmap2(ctx->block_found_map, + ctx->lnf_repair_block); + ctx->lnf_repair_block = 0; + } + if (ctx->root_repair_block) { + ext2fs_unmark_block_bitmap2(ctx->block_found_map, + ctx->root_repair_block); + ctx->root_repair_block = 0; + } + print_resource_track(ctx, _("Pass 3"), &rtrack, ctx->fs->io); } @@ -176,6 +187,11 @@ static void check_root(e2fsck_t ctx) /* * First, find a free block */ + if (ctx->root_repair_block) { + blk = ctx->root_repair_block; + ctx->root_repair_block = 0; + goto skip_new_block; + } pctx.errcode = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk); if (pctx.errcode) { pctx.str = "ext2fs_new_block"; @@ -184,31 +200,10 @@ static void check_root(e2fsck_t ctx) return; } ext2fs_mark_block_bitmap2(ctx->block_found_map, blk); +skip_new_block: ext2fs_mark_block_bitmap2(fs->block_map, blk); ext2fs_mark_bb_dirty(fs); - /* - * Now let's create the actual data block for the inode - */ - pctx.errcode = ext2fs_new_dir_block(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, - &block); - if (pctx.errcode) { - pctx.str = "ext2fs_new_dir_block"; - fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); - ctx->flags |= E2F_FLAG_ABORT; - return; - } - - pctx.errcode = ext2fs_write_dir_block4(fs, blk, block, 0, - EXT2_ROOT_INO); - if (pctx.errcode) { - pctx.str = "ext2fs_write_dir_block4"; - fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); - ctx->flags |= E2F_FLAG_ABORT; - return; - } - ext2fs_free_mem(&block); - /* * Set up the inode structure */ @@ -231,6 +226,30 @@ static void check_root(e2fsck_t ctx) return; } + /* + * Now let's create the actual data block for the inode. + * Due to metadata_csum, we must write the dir blocks AFTER + * the inode has been written to disk! + */ + pctx.errcode = ext2fs_new_dir_block(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, + &block); + if (pctx.errcode) { + pctx.str = "ext2fs_new_dir_block"; + fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); + ctx->flags |= E2F_FLAG_ABORT; + return; + } + + pctx.errcode = ext2fs_write_dir_block4(fs, blk, block, 0, + EXT2_ROOT_INO); + ext2fs_free_mem(&block); + if (pctx.errcode) { + pctx.str = "ext2fs_write_dir_block4"; + fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); + ctx->flags |= E2F_FLAG_ABORT; + return; + } + /* * Miscellaneous bookkeeping... */ @@ -425,6 +444,11 @@ unlink: /* * First, find a free block */ + if (ctx->lnf_repair_block) { + blk = ctx->lnf_repair_block; + ctx->lnf_repair_block = 0; + goto skip_new_block; + } retval = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk); if (retval) { pctx.errcode = retval; @@ -432,6 +456,7 @@ unlink: return 0; } ext2fs_mark_block_bitmap2(ctx->block_found_map, blk); +skip_new_block: ext2fs_block_alloc_stats2(fs, blk, +1); /* @@ -448,24 +473,6 @@ unlink: ext2fs_mark_inode_bitmap2(ctx->inode_dir_map, ino); ext2fs_inode_alloc_stats2(fs, ino, +1, 1); - /* - * Now let's create the actual data block for the inode - */ - retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block); - if (retval) { - pctx.errcode = retval; - fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx); - return 0; - } - - retval = ext2fs_write_dir_block4(fs, blk, block, 0, ino); - ext2fs_free_mem(&block); - if (retval) { - pctx.errcode = retval; - fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx); - return 0; - } - /* * Set up the inode structure */ @@ -486,6 +493,27 @@ unlink: fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); return 0; } + + /* + * Now let's create the actual data block for the inode. + * Due to metadata_csum, the directory block MUST be written + * after the inode is written to disk! + */ + retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block); + if (retval) { + pctx.errcode = retval; + fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx); + return 0; + } + + retval = ext2fs_write_dir_block4(fs, blk, block, 0, ino); + ext2fs_free_mem(&block); + if (retval) { + pctx.errcode = retval; + fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx); + return 0; + } + /* * Finally, create the directory link */ @@ -823,8 +851,9 @@ errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir, return retval; sz = (es.last_block + 1) * fs->blocksize; - inode.i_size = sz; - inode.i_size_high = sz >> 32; + retval = ext2fs_inode_size_set(fs, &inode, sz); + if (retval) + return retval; ext2fs_iblk_add_blocks(fs, &inode, es.newblocks); quota_data_add(ctx->qctx, &inode, dir, es.newblocks * fs->blocksize); diff --git a/e2fsck/pass5.c b/e2fsck/pass5.c index eeb16c38..bf3f733d 100644 --- a/e2fsck/pass5.c +++ b/e2fsck/pass5.c @@ -327,7 +327,6 @@ static void check_block_bitmaps(e2fsck_t ctx) problem_t problem, save_problem; int fixit, had_problem; errcode_t retval; - int csum_flag; int old_desc_blocks = 0; int count = 0; int cmp_block = 0; @@ -374,7 +373,6 @@ static void check_block_bitmaps(e2fsck_t ctx) goto errout; } - csum_flag = ext2fs_has_group_desc_csum(fs); redo_counts: had_problem = 0; save_problem = 0; @@ -898,7 +896,7 @@ static void check_block_end(e2fsck_t ctx) clear_problem_context(&pctx); end = ext2fs_get_block_bitmap_start2(fs->block_map) + - ((blk64_t)EXT2_CLUSTERS_PER_GROUP(fs->super) * fs->group_desc_count) - 1; + EXT2_GROUPS_TO_CLUSTERS(fs->super, fs->group_desc_count) - 1; pctx.errcode = ext2fs_fudge_block_bitmap_end2(fs->block_map, end, &save_blocks_count); if (pctx.errcode) { diff --git a/e2fsck/problem.c b/e2fsck/problem.c index 60c02af7..2c9386f1 100644 --- a/e2fsck/problem.c +++ b/e2fsck/problem.c @@ -992,19 +992,17 @@ static struct e2fsck_problem problem_table[] = { "extent\n\t(logical @b %c, @n physical @b %b, len %N)\n"), PROMPT_FIX, 0 }, - /* Extended attribute block checksum for inode does not match. */ + /* Inode extended attribute block checksum does not match block. */ { PR_1_EA_BLOCK_CSUM_INVALID, - N_("Extended attribute @a @b %b checksum for @i %i does not " - "match. "), + N_("@i %i @a @b %b checksum does not match block. "), PROMPT_CLEAR, 0 }, /* - * Extended attribute block passes checks, but checksum for inode does - * not match. + * Inode extended attribute block passes checks, but checksum does not + * match block. */ { PR_1_EA_BLOCK_ONLY_CSUM_INVALID, - N_("Extended attribute @a @b %b passes checks, but checksum for " - "@i %i does not match. "), + N_("@i %i @a @b %b passes checks, but checksum does not match @b. "), PROMPT_FIX, 0 }, /* @@ -1048,6 +1046,11 @@ static struct e2fsck_problem problem_table[] = { N_("@d @i %i has @x marked uninitialized at @b %c. "), PROMPT_FIX, PR_PREEN_OK }, + /* Inode logical block (physical block ) is misaligned. */ + { PR_1_MISALIGNED_CLUSTER, + N_("@i %i logical @b %b (physical @b %c) violates cluster allocation rules.\nWill fix in pass 1B.\n"), + PROMPT_NONE, 0 }, + /* Pass 1b errors */ /* Pass 1B: Rescan for duplicate/bad blocks */ @@ -1477,27 +1480,27 @@ static struct e2fsck_problem problem_table[] = { /* htree root node fails checksum */ { PR_2_HTREE_ROOT_CSUM_INVALID, - N_("@p @h %d: root node fails checksum\n"), + N_("@p @h %d: root node fails checksum.\n"), PROMPT_CLEAR_HTREE, PR_PREEN_OK }, /* htree internal node fails checksum */ { PR_2_HTREE_NODE_CSUM_INVALID, - N_("@p @h %d: internal node fails checksum\n"), + N_("@p @h %d: internal node fails checksum.\n"), PROMPT_CLEAR_HTREE, PR_PREEN_OK }, /* leaf node fails checksum */ { PR_2_LEAF_NODE_CSUM_INVALID, - N_("@d @i %i, %B, offset %N: @d fails checksum\n"), + N_("@d @i %i, %B, offset %N: @d fails checksum.\n"), PROMPT_SALVAGE, PR_PREEN_OK }, /* leaf node has no checksum */ { PR_2_LEAF_NODE_MISSING_CSUM, - N_("@d @i %i, %B, offset %N: @d has no checksum\n"), + N_("@d @i %i, %B, offset %N: @d has no checksum.\n"), PROMPT_FIX, PR_PREEN_OK }, /* leaf node passes checks but fails checksum */ { PR_2_LEAF_NODE_ONLY_CSUM_INVALID, - N_("@d @i %i, %B, offset %N: @d passes checks but fails checksum\n"), + N_("@d @i %i, %B, offset %N: @d passes checks but fails checksum.\n"), PROMPT_FIX, PR_PREEN_OK }, /* Pass 3 errors */ @@ -1823,12 +1826,12 @@ static struct e2fsck_problem problem_table[] = { /* Group N inode bitmap does not match checksum */ { PR_5_INODE_BITMAP_CSUM_INVALID, - N_("@g %g @i bitmap does not match checksum\n"), + N_("@g %g @i @B does not match checksum.\n"), PROMPT_FIX, PR_LATCH_IBITMAP | PR_PREEN_OK }, /* Group N block bitmap does not match checksum */ { PR_5_BLOCK_BITMAP_CSUM_INVALID, - N_("@g %g @b bitmap does not match checksum\n"), + N_("@g %g @b @B does not match checksum.\n"), PROMPT_FIX, PR_LATCH_BBITMAP | PR_PREEN_OK }, /* Post-Pass 5 errors */ diff --git a/e2fsck/problem.h b/e2fsck/problem.h index 6cd3d50f..80ef4a22 100644 --- a/e2fsck/problem.h +++ b/e2fsck/problem.h @@ -609,6 +609,9 @@ struct problem_context { /* uninit directory block */ #define PR_1_UNINIT_DBLOCK 0x010073 +/* Inode logical block is misaligned */ +#define PR_1_MISALIGNED_CLUSTER 0x010074 + /* * Pass 1b errors */ diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c index 5913ae7f..2983e323 100644 --- a/e2fsck/rehash.c +++ b/e2fsck/rehash.c @@ -771,7 +771,10 @@ static errcode_t write_directory(e2fsck_t ctx, ext2_filsys fs, inode.i_flags &= ~EXT2_INDEX_FL; else inode.i_flags |= EXT2_INDEX_FL; - inode.i_size = outdir->num * fs->blocksize; + retval = ext2fs_inode_size_set(fs, &inode, + outdir->num * fs->blocksize); + if (retval) + return retval; ext2fs_iblk_sub_blocks(fs, &inode, wd.cleared); e2fsck_write_inode(ctx, ino, &inode, "rehash_dir"); diff --git a/e2fsck/super.c b/e2fsck/super.c index c8669f8c..00014e5b 100644 --- a/e2fsck/super.c +++ b/e2fsck/super.c @@ -421,7 +421,7 @@ void check_resize_inode(e2fsck_t ctx) for (j = 1; j < fs->group_desc_count; j++) { if (!ext2fs_bg_has_super(fs, j)) continue; - expect = pblk + (j * fs->super->s_blocks_per_group); + expect = pblk + EXT2_GROUPS_TO_BLOCKS(fs->super, j); if (ind_buf[ind_off] != expect) goto resize_inode_invalid; ind_off++; diff --git a/lib/config.h.in b/lib/config.h.in index 3ed71fa0..12a609a4 100644 --- a/lib/config.h.in +++ b/lib/config.h.in @@ -70,6 +70,9 @@ /* Define to 1 if you have the `asprintf' function. */ #undef HAVE_ASPRINTF +/* Define to 1 if you have the header file. */ +#undef HAVE_ATTR_XATTR_H + /* Define to 1 if you have the `backtrace' function. */ #undef HAVE_BACKTRACE @@ -244,6 +247,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_MAJOR_H +/* Define to 1 if you have the `llistxattr' function. */ +#undef HAVE_LLISTXATTR + /* Define to 1 if you have the `llseek' function. */ #undef HAVE_LLSEEK diff --git a/lib/ext2fs/alloc_stats.c b/lib/ext2fs/alloc_stats.c index 4feb24d6..3d3697c1 100644 --- a/lib/ext2fs/alloc_stats.c +++ b/lib/ext2fs/alloc_stats.c @@ -78,7 +78,7 @@ void ext2fs_block_alloc_stats2(ext2_filsys fs, blk64_t blk, int inuse) ext2fs_group_desc_csum_set(fs, group); ext2fs_free_blocks_count_add(fs->super, - -inuse * EXT2FS_CLUSTER_RATIO(fs)); + -inuse * (blk64_t) EXT2FS_CLUSTER_RATIO(fs)); ext2fs_mark_super_dirty(fs); ext2fs_mark_bb_dirty(fs); if (fs->block_alloc_stats) @@ -139,7 +139,7 @@ void ext2fs_block_alloc_stats_range(ext2_filsys fs, blk64_t blk, inuse*n/EXT2FS_CLUSTER_RATIO(fs)); ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT); ext2fs_group_desc_csum_set(fs, group); - ext2fs_free_blocks_count_add(fs->super, -inuse * n); + ext2fs_free_blocks_count_add(fs->super, -inuse * (blk64_t) n); blk += n; num -= n; } diff --git a/lib/ext2fs/bb_inode.c b/lib/ext2fs/bb_inode.c index 268eecf8..b0e114bb 100644 --- a/lib/ext2fs/bb_inode.c +++ b/lib/ext2fs/bb_inode.c @@ -128,7 +128,10 @@ errcode_t ext2fs_update_bb_inode(ext2_filsys fs, ext2_badblocks_list bb_list) if (!inode.i_ctime) inode.i_ctime = fs->now ? fs->now : time(0); ext2fs_iblk_set(fs, &inode, rec.bad_block_count); - inode.i_size = rec.bad_block_count * fs->blocksize; + retval = ext2fs_inode_size_set(fs, &inode, + rec.bad_block_count * fs->blocksize); + if (retval) + goto cleanup; retval = ext2fs_write_inode(fs, EXT2_BAD_INO, &inode); if (retval) diff --git a/lib/ext2fs/blkmap64_rb.c b/lib/ext2fs/blkmap64_rb.c index 8ab0e0d5..8d1778d6 100644 --- a/lib/ext2fs/blkmap64_rb.c +++ b/lib/ext2fs/blkmap64_rb.c @@ -83,7 +83,7 @@ static void print_tree(struct rb_root *root) static void check_tree(struct rb_root *root, const char *msg) { - struct rb_node *new_node, *node, *next; + struct rb_node *node; struct bmap_rb_extent *ext, *old = NULL; for (node = ext2fs_rb_first(root); node; @@ -297,21 +297,19 @@ static errcode_t rb_resize_bmap(ext2fs_generic_bitmap bmap, { struct ext2fs_rb_private *bp; - if (new_real_end >= bmap->real_end) { - bmap->end = new_end; - bmap->real_end = new_real_end; - return 0; - } - bp = (struct ext2fs_rb_private *) bmap->private; bp->rcursor = NULL; bp->wcursor = NULL; - /* truncate tree to new_real_end size */ - rb_truncate(new_real_end, &bp->root); + rb_truncate(((new_end < bmap->end) ? new_end : bmap->end) - bmap->start, + &bp->root); bmap->end = new_end; bmap->real_end = new_real_end; + + if (bmap->end < bmap->real_end) + rb_insert_extent(bmap->end + 1 - bmap->start, + bmap->real_end - bmap->end, bp); return 0; } diff --git a/lib/ext2fs/blknum.c b/lib/ext2fs/blknum.c index aced8972..93b64ced 100644 --- a/lib/ext2fs/blknum.c +++ b/lib/ext2fs/blknum.c @@ -29,7 +29,7 @@ dgrp_t ext2fs_group_of_blk2(ext2_filsys fs, blk64_t blk) blk64_t ext2fs_group_first_block2(ext2_filsys fs, dgrp_t group) { return fs->super->s_first_data_block + - ((blk64_t)group * fs->super->s_blocks_per_group); + EXT2_GROUPS_TO_BLOCKS(fs->super, group); } /* @@ -523,3 +523,31 @@ void ext2fs_file_acl_block_set(ext2_filsys fs, struct ext2_inode *inode, inode->osd2.linux2.l_i_file_acl_high = (__u64) blk >> 32; } +/* + * Set the size of the inode + */ +errcode_t ext2fs_inode_size_set(ext2_filsys fs, struct ext2_inode *inode, + ext2_off64_t size) +{ + /* Only regular files get to be larger than 4GB */ + if (!LINUX_S_ISREG(inode->i_mode) && (size >> 32)) + return EXT2_ET_FILE_TOO_BIG; + + /* If we're writing a large file, set the large_file flag */ + if (LINUX_S_ISREG(inode->i_mode) && + ext2fs_needs_large_file_feature(size) && + (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super, + EXT2_FEATURE_RO_COMPAT_LARGE_FILE) || + fs->super->s_rev_level == EXT2_GOOD_OLD_REV)) { + fs->super->s_feature_ro_compat |= + EXT2_FEATURE_RO_COMPAT_LARGE_FILE; + ext2fs_update_dynamic_rev(fs); + ext2fs_mark_super_dirty(fs); + } + + inode->i_size = size & 0xffffffff; + inode->i_size_high = (size >> 32); + + return 0; +} + diff --git a/lib/ext2fs/dosio.c b/lib/ext2fs/dosio.c index 0defff8a..d0cf2690 100644 --- a/lib/ext2fs/dosio.c +++ b/lib/ext2fs/dosio.c @@ -62,15 +62,16 @@ static errcode_t dos_write_blk(io_channel channel, unsigned long block, static errcode_t dos_flush(io_channel channel); static struct struct_io_manager struct_dos_manager = { - EXT2_ET_MAGIC_IO_MANAGER, - "DOS I/O Manager", - dos_open, - dos_close, - dos_set_blksize, - dos_read_blk, - dos_write_blk, - dos_flush + .magic = EXT2_ET_MAGIC_IO_MANAGER, + .name = "DOS I/O Manager", + .open = dos_open, + .close = dos_close, + .set_blksize = dos_set_blksize, + .read_blk = dos_read_blk, + .write_blk = dos_write_blk, + .flush = dos_flush }; + io_manager dos_io_manager = &struct_dos_manager; /* diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h index 21a8187b..f9a4bdb9 100644 --- a/lib/ext2fs/ext2_fs.h +++ b/lib/ext2fs/ext2_fs.h @@ -278,6 +278,11 @@ struct ext2_dx_tail { #define EXT2_DESC_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / EXT2_DESC_SIZE(s)) #endif +#define EXT2_GROUPS_TO_BLOCKS(s, g) ((blk64_t) EXT2_BLOCKS_PER_GROUP(s) * \ + (g)) +#define EXT2_GROUPS_TO_CLUSTERS(s, g) ((blk64_t) EXT2_CLUSTERS_PER_GROUP(s) * \ + (g)) + /* * Constants relative to the data blocks */ diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h index 74c872fc..7812956a 100644 --- a/lib/ext2fs/ext2fs.h +++ b/lib/ext2fs/ext2fs.h @@ -39,6 +39,8 @@ extern "C" { #define SUPERBLOCK_OFFSET 1024 #define SUPERBLOCK_SIZE 1024 +#define UUID_STR_SIZE 37 + /* * The last ext2fs revision level that this version of the library is * able to support. @@ -894,6 +896,8 @@ extern blk64_t ext2fs_file_acl_block(ext2_filsys fs, const struct ext2_inode *inode); extern void ext2fs_file_acl_block_set(ext2_filsys fs, struct ext2_inode *inode, blk64_t blk); +extern errcode_t ext2fs_inode_size_set(ext2_filsys fs, struct ext2_inode *inode, + ext2_off64_t size); /* block.c */ extern errcode_t ext2fs_block_iterate(ext2_filsys fs, @@ -1499,6 +1503,7 @@ extern errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t num_blocks, extern errcode_t ext2fs_add_journal_inode2(ext2_filsys fs, blk_t num_blocks, blk64_t goal, int flags); extern int ext2fs_default_journal_size(__u64 num_blocks); +extern int ext2fs_journal_sb_start(int blocksize); /* openfs.c */ extern errcode_t ext2fs_open(const char *name, int flags, int superblock, diff --git a/lib/ext2fs/fileio.c b/lib/ext2fs/fileio.c index 14eaed34..1d5032a5 100644 --- a/lib/ext2fs/fileio.c +++ b/lib/ext2fs/fileio.c @@ -568,20 +568,10 @@ errcode_t ext2fs_file_set_size2(ext2_file_t file, ext2_off64_t size) old_truncate = ((old_size + file->fs->blocksize - 1) >> EXT2_BLOCK_SIZE_BITS(file->fs->super)); - /* If we're writing a large file, set the large_file flag */ - if (LINUX_S_ISREG(file->inode.i_mode) && - ext2fs_needs_large_file_feature(EXT2_I_SIZE(&file->inode)) && - (!EXT2_HAS_RO_COMPAT_FEATURE(file->fs->super, - EXT2_FEATURE_RO_COMPAT_LARGE_FILE) || - file->fs->super->s_rev_level == EXT2_GOOD_OLD_REV)) { - file->fs->super->s_feature_ro_compat |= - EXT2_FEATURE_RO_COMPAT_LARGE_FILE; - ext2fs_update_dynamic_rev(file->fs); - ext2fs_mark_super_dirty(file->fs); - } + retval = ext2fs_inode_size_set(file->fs, &file->inode, size); + if (retval) + return retval; - file->inode.i_size = size & 0xffffffff; - file->inode.i_size_high = (size >> 32); if (file->ino) { retval = ext2fs_write_inode(file->fs, file->ino, &file->inode); if (retval) diff --git a/lib/ext2fs/imager.c b/lib/ext2fs/imager.c index 378a3c88..b643cc6f 100644 --- a/lib/ext2fs/imager.c +++ b/lib/ext2fs/imager.c @@ -286,8 +286,8 @@ errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags) ext2fs_generic_bitmap bmap; errcode_t retval; ssize_t actual; - __u32 itr, cnt, size; - int c, total_size; + size_t c; + __u64 itr, cnt, size, total_size; char buf[1024]; if (flags & IMAGER_FLAG_INODEMAP) { @@ -308,7 +308,7 @@ errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags) } bmap = fs->block_map; itr = fs->super->s_first_data_block; - cnt = EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count; + cnt = EXT2_GROUPS_TO_BLOCKS(fs->super, fs->group_desc_count); size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8; } total_size = size * fs->group_desc_count; @@ -342,9 +342,9 @@ errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags) if (c > (int) sizeof(buf)) c = sizeof(buf); actual = write(fd, buf, c); - if (actual == -1) + if (actual < 0) return errno; - if (actual != c) + if ((size_t) actual != c) return EXT2_ET_SHORT_WRITE; size -= c; } @@ -360,7 +360,7 @@ errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags) { ext2fs_generic_bitmap bmap; errcode_t retval; - __u32 itr, cnt; + __u64 itr, cnt; char buf[1024]; unsigned int size; ssize_t actual; @@ -383,7 +383,7 @@ errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags) } bmap = fs->block_map; itr = fs->super->s_first_data_block; - cnt = EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count; + cnt = EXT2_GROUPS_TO_BLOCKS(fs->super, fs->group_desc_count); size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8; } diff --git a/lib/ext2fs/inode_io.c b/lib/ext2fs/inode_io.c index 8e0944ef..f3d94c89 100644 --- a/lib/ext2fs/inode_io.c +++ b/lib/ext2fs/inode_io.c @@ -63,19 +63,17 @@ static errcode_t inode_write_blk64(io_channel channel, unsigned long long block, int count, const void *data); static struct struct_io_manager struct_inode_manager = { - EXT2_ET_MAGIC_IO_MANAGER, - "Inode I/O Manager", - inode_open, - inode_close, - inode_set_blksize, - inode_read_blk, - inode_write_blk, - inode_flush, - inode_write_byte, - NULL, - NULL, - inode_read_blk64, - inode_write_blk64 + .magic = EXT2_ET_MAGIC_IO_MANAGER, + .name = "Inode I/O Manager", + .open = inode_open, + .close = inode_close, + .set_blksize = inode_set_blksize, + .read_blk = inode_read_blk, + .write_blk = inode_write_blk, + .flush = inode_flush, + .write_byte = inode_write_byte, + .read_blk64 = inode_read_blk64, + .write_blk64 = inode_write_blk64 }; io_manager inode_io_manager = &struct_inode_manager; diff --git a/lib/ext2fs/kernel-jbd.h b/lib/ext2fs/kernel-jbd.h index 130c3a2b..a9cdc305 100644 --- a/lib/ext2fs/kernel-jbd.h +++ b/lib/ext2fs/kernel-jbd.h @@ -186,6 +186,9 @@ struct journal_revoke_tail { #define JFS_FLAG_LAST_TAG 8 /* last tag in this descriptor block */ +#define UUID_SIZE 16 +#define JFS_USERS_MAX 48 +#define JFS_USERS_SIZE (UUID_SIZE * JFS_USERS_MAX) /* * The journal superblock. All fields are in big-endian byte order. */ @@ -233,7 +236,8 @@ typedef struct journal_superblock_s __u32 s_checksum; /* crc32c(superblock) */ /* 0x0100 */ - __u8 s_users[16*48]; /* ids of all fs'es sharing the log */ + __u8 s_users[JFS_USERS_SIZE]; /* ids of all fs'es sharing the log */ + /* 0x0400 */ } journal_superblock_t; diff --git a/lib/ext2fs/mkjournal.c b/lib/ext2fs/mkjournal.c index 2331e9ed..96b6d360 100644 --- a/lib/ext2fs/mkjournal.c +++ b/lib/ext2fs/mkjournal.c @@ -49,7 +49,7 @@ errcode_t ext2fs_create_journal_superblock(ext2_filsys fs, errcode_t retval; journal_superblock_t *jsb; - if (num_blocks < 1024) + if (num_blocks < JFS_MIN_JOURNAL_BLOCKS) return EXT2_ET_JOURNAL_TOO_SMALL; if ((retval = ext2fs_get_mem(fs->blocksize, &jsb))) @@ -75,10 +75,7 @@ errcode_t ext2fs_create_journal_superblock(ext2_filsys fs, if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) { jsb->s_nr_users = 0; - if (fs->blocksize == 1024) - jsb->s_first = htonl(3); - else - jsb->s_first = htonl(2); + jsb->s_first = htonl(ext2fs_journal_sb_start(fs->blocksize) + 1); } *ret_jsb = (char *) jsb; @@ -383,15 +380,13 @@ static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino, goto errout; inode_size = (unsigned long long)fs->blocksize * num_blocks; - inode.i_size = inode_size & 0xFFFFFFFF; - inode.i_size_high = (inode_size >> 32) & 0xFFFFFFFF; - if (ext2fs_needs_large_file_feature(inode_size)) - fs->super->s_feature_ro_compat |= - EXT2_FEATURE_RO_COMPAT_LARGE_FILE; ext2fs_iblk_add_blocks(fs, &inode, es.newblocks); inode.i_mtime = inode.i_ctime = fs->now ? fs->now : time(0); inode.i_links_count = 1; inode.i_mode = LINUX_S_IFREG | 0600; + retval = ext2fs_inode_size_set(fs, &inode, inode_size); + if (retval) + goto errout; if ((retval = ext2fs_write_new_inode(fs, journal_ino, &inode))) goto errout; @@ -430,6 +425,13 @@ int ext2fs_default_journal_size(__u64 num_blocks) return 32768; } +int ext2fs_journal_sb_start(int blocksize) +{ + if (blocksize == EXT2_MIN_BLOCK_SIZE) + return 2; + return 1; +} + /* * This function adds a journal device to a filesystem */ @@ -437,7 +439,7 @@ errcode_t ext2fs_add_journal_device(ext2_filsys fs, ext2_filsys journal_dev) { struct stat st; errcode_t retval; - char buf[1024]; + char buf[SUPERBLOCK_SIZE]; journal_superblock_t *jsb; int start; __u32 i, nr_users; @@ -450,10 +452,9 @@ errcode_t ext2fs_add_journal_device(ext2_filsys fs, ext2_filsys journal_dev) return EXT2_ET_JOURNAL_NOT_BLOCK; /* Must be a block device */ /* Get the journal superblock */ - start = 1; - if (journal_dev->blocksize == 1024) - start++; - if ((retval = io_channel_read_blk64(journal_dev->io, start, -1024, + start = ext2fs_journal_sb_start(journal_dev->blocksize); + if ((retval = io_channel_read_blk64(journal_dev->io, start, + -SUPERBLOCK_SIZE, buf))) return retval; @@ -479,7 +480,8 @@ errcode_t ext2fs_add_journal_device(ext2_filsys fs, ext2_filsys journal_dev) } /* Writeback the journal superblock */ - if ((retval = io_channel_write_blk64(journal_dev->io, start, -1024, buf))) + if ((retval = io_channel_write_blk64(journal_dev->io, start, + -SUPERBLOCK_SIZE, buf))) return retval; fs->super->s_journal_inum = 0; @@ -632,7 +634,7 @@ main(int argc, char **argv) exit(1); } - retval = ext2fs_add_journal_inode(fs, 1024, 0); + retval = ext2fs_add_journal_inode(fs, JFS_MIN_JOURNAL_BLOCKS, 0); if (retval) { com_err(argv[0], retval, "while adding journal to %s", device_name); diff --git a/lib/ext2fs/nt_io.c b/lib/ext2fs/nt_io.c index 0f10543a..f0d16ae0 100644 --- a/lib/ext2fs/nt_io.c +++ b/lib/ext2fs/nt_io.c @@ -230,18 +230,16 @@ static errcode_t nt_write_blk(io_channel channel, unsigned long block, static errcode_t nt_flush(io_channel channel); static struct struct_io_manager struct_nt_manager = { - EXT2_ET_MAGIC_IO_MANAGER, - "NT I/O Manager", - nt_open, - nt_close, - nt_set_blksize, - nt_read_blk, - nt_write_blk, - nt_flush + .magic = EXT2_ET_MAGIC_IO_MANAGER, + .name = "NT I/O Manager", + .open = nt_open, + .close = nt_close, + .set_blksize = nt_set_blksize, + .read_blk = nt_read_blk, + .write_blk = nt_write_blk, + .flush = nt_flush }; - - // // function to get API // diff --git a/lib/ext2fs/res_gdt.c b/lib/ext2fs/res_gdt.c index e61c3303..46db61c5 100644 --- a/lib/ext2fs/res_gdt.c +++ b/lib/ext2fs/res_gdt.c @@ -133,12 +133,9 @@ errcode_t ext2fs_create_resize_inode(ext2_filsys fs) dindir_dirty = inode_dirty = 1; inode_size = apb*apb + apb + EXT2_NDIR_BLOCKS; inode_size *= fs->blocksize; - inode.i_size = inode_size & 0xFFFFFFFF; - inode.i_size_high = (inode_size >> 32) & 0xFFFFFFFF; - if(inode.i_size_high) { - sb->s_feature_ro_compat |= - EXT2_FEATURE_RO_COMPAT_LARGE_FILE; - } + retval = ext2fs_inode_size_set(fs, &inode, inode_size); + if (retval) + goto out_free; inode.i_ctime = fs->now ? fs->now : time(0); } diff --git a/lib/ext2fs/rw_bitmaps.c b/lib/ext2fs/rw_bitmaps.c index ad6cfc11..ae593d49 100644 --- a/lib/ext2fs/rw_bitmaps.c +++ b/lib/ext2fs/rw_bitmaps.c @@ -271,8 +271,8 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block) } blk = (fs->image_header->offset_blockmap / fs->blocksize); - blk_cnt = (blk64_t)EXT2_CLUSTERS_PER_GROUP(fs->super) * - fs->group_desc_count; + blk_cnt = EXT2_GROUPS_TO_CLUSTERS(fs->super, + fs->group_desc_count); while (block_nbytes > 0) { retval = io_channel_read_blk64(fs->image_io, blk++, 1, block_bitmap); diff --git a/lib/ext2fs/symlink.c b/lib/ext2fs/symlink.c index b2ef66c2..ba8ed8ef 100644 --- a/lib/ext2fs/symlink.c +++ b/lib/ext2fs/symlink.c @@ -79,7 +79,7 @@ errcode_t ext2fs_symlink(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t ino, inode.i_uid = inode.i_gid = 0; ext2fs_iblk_set(fs, &inode, fastlink ? 0 : 1); inode.i_links_count = 1; - inode.i_size = target_len; + ext2fs_inode_size_set(fs, &inode, target_len); /* The time fields are set by ext2fs_write_new_inode() */ if (fastlink) { diff --git a/lib/ext2fs/test_io.c b/lib/ext2fs/test_io.c index d16a3588..6f0d035c 100644 --- a/lib/ext2fs/test_io.c +++ b/lib/ext2fs/test_io.c @@ -487,20 +487,20 @@ static errcode_t test_discard(io_channel channel, unsigned long long block, } static struct struct_io_manager struct_test_manager = { - EXT2_ET_MAGIC_IO_MANAGER, - "Test I/O Manager", - test_open, - test_close, - test_set_blksize, - test_read_blk, - test_write_blk, - test_flush, - test_write_byte, - test_set_option, - test_get_stats, - test_read_blk64, - test_write_blk64, - test_discard, + .magic = EXT2_ET_MAGIC_IO_MANAGER, + .name = "Test I/O Manager", + .open = test_open, + .close = test_close, + .set_blksize = test_set_blksize, + .read_blk = test_read_blk, + .write_blk = test_write_blk, + .flush = test_flush, + .write_byte = test_write_byte, + .set_option = test_set_option, + .get_stats = test_get_stats, + .read_blk64 = test_read_blk64, + .write_blk64 = test_write_blk64, + .discard = test_discard, }; io_manager test_io_manager = &struct_test_manager; diff --git a/lib/ext2fs/undo_io.c b/lib/ext2fs/undo_io.c index 0e05c933..d6beb024 100644 --- a/lib/ext2fs/undo_io.c +++ b/lib/ext2fs/undo_io.c @@ -588,19 +588,19 @@ static errcode_t undo_get_stats(io_channel channel, io_stats *stats) } static struct struct_io_manager struct_undo_manager = { - EXT2_ET_MAGIC_IO_MANAGER, - "Undo I/O Manager", - undo_open, - undo_close, - undo_set_blksize, - undo_read_blk, - undo_write_blk, - undo_flush, - undo_write_byte, - undo_set_option, - undo_get_stats, - undo_read_blk64, - undo_write_blk64, + .magic = EXT2_ET_MAGIC_IO_MANAGER, + .name = "Undo I/O Manager", + .open = undo_open, + .close = undo_close, + .set_blksize = undo_set_blksize, + .read_blk = undo_read_blk, + .write_blk = undo_write_blk, + .flush = undo_flush, + .write_byte = undo_write_byte, + .set_option = undo_set_option, + .get_stats = undo_get_stats, + .read_blk64 = undo_read_blk64, + .write_blk64 = undo_write_blk64, }; io_manager undo_io_manager = &struct_undo_manager; diff --git a/lib/ext2fs/unix_io.c b/lib/ext2fs/unix_io.c index c3185b6a..e93684e8 100644 --- a/lib/ext2fs/unix_io.c +++ b/lib/ext2fs/unix_io.c @@ -923,20 +923,20 @@ unimplemented: } static struct struct_io_manager struct_unix_manager = { - EXT2_ET_MAGIC_IO_MANAGER, - "Unix I/O Manager", - unix_open, - unix_close, - unix_set_blksize, - unix_read_blk, - unix_write_blk, - unix_flush, - unix_write_byte, - unix_set_option, - unix_get_stats, - unix_read_blk64, - unix_write_blk64, - unix_discard, + .magic = EXT2_ET_MAGIC_IO_MANAGER, + .name = "Unix I/O Manager", + .open = unix_open, + .close = unix_close, + .set_blksize = unix_set_blksize, + .read_blk = unix_read_blk, + .write_blk = unix_write_blk, + .flush = unix_flush, + .write_byte = unix_write_byte, + .set_option = unix_set_option, + .get_stats = unix_get_stats, + .read_blk64 = unix_read_blk64, + .write_blk64 = unix_write_blk64, + .discard = unix_discard, }; io_manager unix_io_manager = &struct_unix_manager; diff --git a/lib/quota/mkquota.c b/lib/quota/mkquota.c index 58803d04..0ece0881 100644 --- a/lib/quota/mkquota.c +++ b/lib/quota/mkquota.c @@ -580,7 +580,6 @@ out: errcode_t quota_compare_and_update(quota_ctx_t qctx, int qtype, int *usage_inconsistent) { - ext2_filsys fs = qctx->fs; struct quota_handle qh; struct scan_dquots_data scan_data; struct dquot *dq; diff --git a/misc/create_inode.c b/misc/create_inode.c index c9c99b59..4d567199 100644 --- a/misc/create_inode.c +++ b/misc/create_inode.c @@ -12,6 +12,9 @@ #include #include #include /* for PATH_MAX */ +#ifdef HAVE_ATTR_XATTR_H +#include +#endif #include "create_inode.h" @@ -103,6 +106,94 @@ static errcode_t set_inode_extra(ext2_filsys fs, ext2_ino_t cwd, return retval; } +static errcode_t set_inode_xattr(ext2_filsys fs, ext2_ino_t ino, const char *filename) +{ +#ifdef HAVE_LLISTXATTR + errcode_t retval, close_retval; + struct ext2_inode inode; + struct ext2_xattr_handle *handle; + ssize_t size, value_size; + char *list; + int i; + + size = llistxattr(filename, NULL, 0); + if (size == -1) { + com_err(__func__, errno, "llistxattr failed on %s", filename); + return errno; + } else if (size == 0) { + return 0; + } + + retval = ext2fs_xattrs_open(fs, ino, &handle); + if (retval) { + if (retval == EXT2_ET_MISSING_EA_FEATURE) + return 0; + com_err(__func__, retval, "while opening inode %u", ino); + return retval; + } + + retval = ext2fs_get_mem(size, &list); + if (retval) { + com_err(__func__, retval, "whilst allocating memory"); + goto out; + } + + size = llistxattr(filename, list, size); + if (size == -1) { + com_err(__func__, errno, "llistxattr failed on %s", filename); + retval = errno; + goto out; + } + + for (i = 0; i < size; i += strlen(&list[i]) + 1) { + const char *name = &list[i]; + char *value; + + value_size = getxattr(filename, name, NULL, 0); + if (value_size == -1) { + com_err(__func__, errno, "getxattr failed on %s", + filename); + retval = errno; + break; + } + + retval = ext2fs_get_mem(value_size, &value); + if (retval) { + com_err(__func__, retval, "whilst allocating memory"); + break; + } + + value_size = getxattr(filename, name, value, value_size); + if (value_size == -1) { + ext2fs_free_mem(&value); + com_err(__func__, errno, "getxattr failed on %s", + filename); + retval = errno; + break; + } + + retval = ext2fs_xattr_set(handle, name, value, value_size); + ext2fs_free_mem(&value); + if (retval) { + com_err(__func__, retval, + "while writing xattr %u", ino); + break; + } + + } + out: + ext2fs_free_mem(&list); + close_retval = ext2fs_xattrs_close(&handle); + if (close_retval) { + com_err(__func__, retval, "while closing inode %u", ino); + retval = retval ? retval : close_retval; + } + return retval; +#else /* HAVE_LLISTXATTR */ + return 0; +#endif /* HAVE_LLISTXATTR */ +} + /* Make a special files (block and character devices), fifo's, and sockets */ errcode_t do_mknod_internal(ext2_filsys fs, ext2_ino_t cwd, const char *name, struct stat *st) @@ -418,7 +509,12 @@ errcode_t do_write_internal(ext2_filsys fs, ext2_ino_t cwd, const char *src, inode.i_atime = inode.i_ctime = inode.i_mtime = fs->now ? fs->now : time(0); inode.i_links_count = 1; - inode.i_size = statbuf.st_size; + retval = ext2fs_inode_size_set(fs, &inode, statbuf.st_size); + if (retval) { + com_err(dest, retval, 0); + close(fd); + return retval; + } if (EXT2_HAS_INCOMPAT_FEATURE(fs->super, EXT4_FEATURE_INCOMPAT_INLINE_DATA)) { inode.i_flags |= EXT4_INLINE_DATA_FL; @@ -615,6 +711,13 @@ static errcode_t __populate_fs(ext2_filsys fs, ext2_ino_t parent_ino, goto out; } + retval = set_inode_xattr(fs, ino, name); + if (retval) { + com_err(__func__, retval, + _("while setting xattrs for \"%s\""), name); + goto out; + } + /* Save the hardlink ino */ if (save_inode) { /* diff --git a/misc/filefrag.c b/misc/filefrag.c index 820821b5..2ce1b9b5 100644 --- a/misc/filefrag.c +++ b/misc/filefrag.c @@ -331,9 +331,10 @@ static int filefrag_fibmap(int fd, int blk_shift, int *num_extents, fm_ext.fe_physical = block * st->st_blksize; fm_ext.fe_length = 0; (*num_extents)++; - } else if (verbose && last_block && (block != last_block + 1)) { - printf("Discontinuity: Block %ld is at %lu (was %lu)\n", - i, block, last_block + 1); + } else if (last_block && (block != last_block + 1)) { + if (verbose) + printf("Discontinuity: Block %ld is at %lu (was " + "%lu)\n", i, block, last_block + 1); (*num_extents)++; } fm_ext.fe_length += st->st_blksize; @@ -350,6 +351,7 @@ static int filefrag_fibmap(int fd, int blk_shift, int *num_extents, static int frag_report(const char *filename) { static struct statfs fsinfo; + static unsigned int blksize; ext2fs_struct_stat st; int blk_shift; long fd; @@ -380,22 +382,22 @@ static int frag_report(const char *filename) #endif rc = -errno; perror("stat"); - close(fd); - return rc; + goto out_close; } if (last_device != st.st_dev) { if (fstatfs(fd, &fsinfo) < 0) { rc = -errno; perror("fstatfs"); - close(fd); - return rc; + goto out_close; } + if (ioctl(fd, FIGETBSZ, &blksize) < 0) + blksize = fsinfo.f_bsize; if (verbose) printf("Filesystem type is: %lx\n", (unsigned long)fsinfo.f_type); } - st.st_blksize = fsinfo.f_bsize; + st.st_blksize = blksize; if (ioctl(fd, EXT3_IOC_GETFLAGS, &flags) < 0) flags = 0; if (!(flags & EXT4_EXTENTS_FL) && @@ -404,13 +406,13 @@ static int frag_report(const char *filename) is_ext2++; if (is_ext2) { - long cylgroups = div_ceil(fsinfo.f_blocks, fsinfo.f_bsize * 8); + long cylgroups = div_ceil(fsinfo.f_blocks, blksize * 8); if (verbose && last_device != st.st_dev) printf("Filesystem cylinder groups approximately %ld\n", cylgroups); - data_blocks_per_cyl = fsinfo.f_bsize * 8 - + data_blocks_per_cyl = blksize * 8 - (fsinfo.f_files / 8 / cylgroups) - 3; } last_device = st.st_dev; @@ -419,11 +421,11 @@ static int frag_report(const char *filename) if (width > physical_width) physical_width = width; - numblocks = (st.st_size + fsinfo.f_bsize - 1) / fsinfo.f_bsize; + numblocks = (st.st_size + blksize - 1) / blksize; if (blocksize != 0) blk_shift = int_log2(blocksize); else - blk_shift = int_log2(fsinfo.f_bsize); + blk_shift = int_log2(blksize); width = int_log10(numblocks); if (width > logical_width) @@ -431,7 +433,7 @@ static int frag_report(const char *filename) if (verbose) printf("File size of %s is %llu (%llu block%s of %d bytes)\n", filename, (unsigned long long)st.st_size, - numblocks * fsinfo.f_bsize >> blk_shift, + numblocks * blksize >> blk_shift, numblocks == 1 ? "" : "s", 1 << blk_shift); if (!force_bmap) { @@ -439,7 +441,7 @@ static int frag_report(const char *filename) expected = 0; } - if (rc < 0) { + if (force_bmap || rc < 0) { expected = filefrag_fibmap(fd, blk_shift, &num_extents, &st, numblocks, is_ext2); if (expected < 0) { diff --git a/misc/mk_hugefiles.c b/misc/mk_hugefiles.c index 6bc25e62..c292ddc1 100644 --- a/misc/mk_hugefiles.c +++ b/misc/mk_hugefiles.c @@ -357,8 +357,9 @@ static errcode_t mk_hugefile(ext2_filsys fs, blk64_t num, if (retval) goto errout; size = (__u64) count * fs->blocksize; - inode.i_size = size & 0xffffffff; - inode.i_size_high = (size >> 32); + retval = ext2fs_inode_size_set(fs, &inode, size); + if (retval) + goto errout; retval = ext2fs_write_new_inode(fs, *ino, &inode); if (retval) @@ -468,7 +469,7 @@ errcode_t mk_hugefiles(ext2_filsys fs, const char *device_name) unsigned long i; ext2_ino_t dir; errcode_t retval; - blk64_t fs_blocks, part_offset; + blk64_t fs_blocks, part_offset = 0; unsigned long align; int d, dsize; char *t; diff --git a/misc/tune2fs.c b/misc/tune2fs.c index 967a80a8..5aaea5ea 100644 --- a/misc/tune2fs.c +++ b/misc/tune2fs.c @@ -180,6 +180,50 @@ static __u32 clear_ok_features[3] = { EXT4_FEATURE_RO_COMPAT_METADATA_CSUM }; +/** + * Try to get journal super block if any + */ +static int get_journal_sb(ext2_filsys jfs, char buf[SUPERBLOCK_SIZE]) +{ + int retval; + int start; + journal_superblock_t *jsb; + + if (!(jfs->super->s_feature_incompat & + EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) { + return EXT2_ET_UNSUPP_FEATURE; + } + + /* Get the journal superblock */ + if ((retval = io_channel_read_blk64(jfs->io, + ext2fs_journal_sb_start(jfs->blocksize), -SUPERBLOCK_SIZE, buf))) { + com_err(program_name, retval, "%s", + _("while reading journal superblock")); + return retval; + } + + jsb = (journal_superblock_t *) buf; + if ((jsb->s_header.h_magic != (unsigned)ntohl(JFS_MAGIC_NUMBER)) || + (jsb->s_header.h_blocktype != (unsigned)ntohl(JFS_SUPERBLOCK_V2))) { + fputs(_("Journal superblock not found!\n"), stderr); + return EXT2_ET_BAD_MAGIC; + } + + return 0; +} + +static void * +journal_user(char uuid[UUID_SIZE], char s_users[JFS_USERS_SIZE], int nr_users) +{ + int i; + for (i = 0; i < nr_users; i++) { + if (memcmp(uuid, &s_users[i * UUID_SIZE], UUID_SIZE) == 0) + return &s_users[i * UUID_SIZE]; + } + + return NULL; +} + /* * Remove an external journal from the filesystem */ @@ -187,12 +231,13 @@ static int remove_journal_device(ext2_filsys fs) { char *journal_path; ext2_filsys jfs; - char buf[1024]; + char buf[SUPERBLOCK_SIZE]; journal_superblock_t *jsb; int i, nr_users; errcode_t retval; int commit_remove_journal = 0; io_manager io_ptr; + int start; if (f_flag) commit_remove_journal = 1; /* force removal even if error */ @@ -222,34 +267,19 @@ static int remove_journal_device(ext2_filsys fs) _("while trying to open external journal")); goto no_valid_journal; } - if (!(jfs->super->s_feature_incompat & - EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) { - fprintf(stderr, _("%s is not a journal device.\n"), - journal_path); - goto no_valid_journal; - } - /* Get the journal superblock */ - if ((retval = io_channel_read_blk64(jfs->io, 1, -1024, buf))) { - com_err(program_name, retval, "%s", - _("while reading journal superblock")); + if ((retval = get_journal_sb(jfs, buf))) { + if (retval == EXT2_ET_UNSUPP_FEATURE) + fprintf(stderr, _("%s is not a journal device.\n"), + journal_path); goto no_valid_journal; } jsb = (journal_superblock_t *) buf; - if ((jsb->s_header.h_magic != (unsigned)ntohl(JFS_MAGIC_NUMBER)) || - (jsb->s_header.h_blocktype != (unsigned)ntohl(JFS_SUPERBLOCK_V2))) { - fputs(_("Journal superblock not found!\n"), stderr); - goto no_valid_journal; - } - /* Find the filesystem UUID */ nr_users = ntohl(jsb->s_nr_users); - for (i = 0; i < nr_users; i++) { - if (memcmp(fs->super->s_uuid, &jsb->s_users[i * 16], 16) == 0) - break; - } - if (i >= nr_users) { + + if (!journal_user(fs->super->s_uuid, jsb->s_users, nr_users)) { fputs(_("Filesystem's UUID not found on journal device.\n"), stderr); commit_remove_journal = 1; @@ -261,7 +291,8 @@ static int remove_journal_device(ext2_filsys fs) jsb->s_nr_users = htonl(nr_users); /* Write back the journal superblock */ - if ((retval = io_channel_write_blk64(jfs->io, 1, -1024, buf))) { + if ((retval = io_channel_write_blk64(jfs->io, start, + -SUPERBLOCK_SIZE, buf))) { com_err(program_name, retval, "while writing journal superblock."); goto no_valid_journal; @@ -1894,7 +1925,7 @@ static int ext2fs_is_block_in_group(ext2_filsys fs, dgrp_t group, blk64_t blk) { blk64_t start_blk, end_blk; start_blk = fs->super->s_first_data_block + - EXT2_BLOCKS_PER_GROUP(fs->super) * group; + EXT2_GROUPS_TO_BLOCKS(fs->super, group); /* * We cannot get new block beyond end_blk for for the last block group * so we can check with EXT2_BLOCKS_PER_GROUP even for last block group @@ -2404,6 +2435,68 @@ static int tune2fs_setup_tdb(const char *name, io_manager *io_ptr) return retval; } +int +fs_update_journal_user(struct ext2_super_block *sb, char old_uuid[UUID_SIZE]) +{ + int retval, nr_users, start; + journal_superblock_t *jsb; + ext2_filsys jfs; + char *j_uuid, *journal_path; + char uuid[UUID_STR_SIZE]; + char buf[SUPERBLOCK_SIZE]; + + if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) || + uuid_is_null(sb->s_journal_uuid)) + return 0; + + uuid_unparse(sb->s_journal_uuid, uuid); + journal_path = blkid_get_devname(NULL, "UUID", uuid); + if (!journal_path) + return 0; + + retval = ext2fs_open2(journal_path, io_options, + EXT2_FLAG_JOURNAL_DEV_OK | EXT2_FLAG_RW, + 0, 0, unix_io_manager, &jfs); + if (retval) { + com_err(program_name, retval, + _("while trying to open %s"), + journal_path); + return retval; + } + + if ((retval = get_journal_sb(jfs, buf))) { + if (retval == EXT2_ET_UNSUPP_FEATURE) + fprintf(stderr, _("%s is not a journal device.\n"), + journal_path); + return retval; + } + + jsb = (journal_superblock_t *) buf; + /* Find the filesystem UUID */ + nr_users = ntohl(jsb->s_nr_users); + + if (!(j_uuid = journal_user(old_uuid, jsb->s_users, nr_users))) { + fputs(_("Filesystem's UUID not found on journal device.\n"), + stderr); + return EXT2_ET_LOAD_EXT_JOURNAL; + } + + memcpy(j_uuid, sb->s_uuid, UUID_SIZE); + + start = ext2fs_journal_sb_start(jfs->blocksize); + /* Write back the journal superblock */ + if ((retval = io_channel_write_blk64(jfs->io, start, + -SUPERBLOCK_SIZE, buf))) { + com_err(program_name, retval, + "while writing journal superblock."); + return retval; + } + + ext2fs_close(jfs); + + return 0; +} + int main(int argc, char **argv) { errcode_t retval; @@ -2691,6 +2784,8 @@ retry_open: if (U_flag) { int set_csum = 0; dgrp_t i; + char buf[SUPERBLOCK_SIZE]; + char old_uuid[UUID_SIZE]; if (ext2fs_has_group_desc_csum(fs)) { /* @@ -2717,6 +2812,8 @@ retry_open: if (i >= fs->group_desc_count) set_csum = 1; } + + memcpy(old_uuid, sb->s_uuid, UUID_SIZE); if ((strcasecmp(new_UUID, "null") == 0) || (strcasecmp(new_UUID, "clear") == 0)) { uuid_clear(sb->s_uuid); @@ -2736,6 +2833,29 @@ retry_open: ext2fs_group_desc_csum_set(fs, i); fs->flags &= ~EXT2_FLAG_SUPER_ONLY; } + + /* If this is a journal dev, we need to copy UUID into jsb */ + if (!(rc = get_journal_sb(fs, buf))) { + journal_superblock_t *jsb; + + jsb = (journal_superblock_t *) buf; + fputs(_("Need to update journal superblock.\n"), stdout); + memcpy(jsb->s_uuid, sb->s_uuid, sizeof(sb->s_uuid)); + + /* Writeback the journal superblock */ + if ((rc = io_channel_write_blk64(fs->io, + ext2fs_journal_sb_start(fs->blocksize), + -SUPERBLOCK_SIZE, buf))) + goto closefs; + } else if (rc != EXT2_ET_UNSUPP_FEATURE) + goto closefs; + else { + rc = 0; /** Reset rc to avoid ext2fs_mmp_stop() */ + + if ((rc = fs_update_journal_user(sb, old_uuid))) + goto closefs; + } + ext2fs_mark_super_dirty(fs); if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super, EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) diff --git a/misc/uuidd.c b/misc/uuidd.c index 5a531380..02ca6be8 100644 --- a/misc/uuidd.c +++ b/misc/uuidd.c @@ -36,6 +36,7 @@ extern int optind; #include "uuid/uuid.h" #include "uuid/uuidd.h" #include "nls-enable.h" +#include "ext2fs/ext2fs.h" #ifdef __GNUC__ #define CODE_ATTR(x) __attribute__(x) @@ -236,7 +237,7 @@ static void server_loop(const char *socket_path, const char *pidfile_path, uuid_t uu; mode_t save_umask; char reply_buf[1024], *cp; - char op, str[37]; + char op, str[UUID_STR_SIZE]; int i, s, ns, len, num; int fd_pidfile, ret; diff --git a/resize/main.c b/resize/main.c index e4b44354..ef2a810b 100644 --- a/resize/main.c +++ b/resize/main.c @@ -318,6 +318,7 @@ int main (int argc, char ** argv) printf("%s", _("Couldn't find valid filesystem superblock.\n")); exit (1); } + fs->default_bitmap_type = EXT2FS_BMAP64_RBTREE; if (!(mount_flags & EXT2_MF_MOUNTED)) { if (!force && ((fs->super->s_lastcheck < fs->super->s_mtime) || diff --git a/resize/resize2fs.c b/resize/resize2fs.c index 546b1d85..ecde9ca7 100644 --- a/resize/resize2fs.c +++ b/resize/resize2fs.c @@ -435,8 +435,7 @@ retry: fs->inode_map); if (retval) goto errout; - real_end = (((blk64_t) EXT2_BLOCKS_PER_GROUP(fs->super) * - fs->group_desc_count)) - 1 + + real_end = EXT2_GROUPS_TO_BLOCKS(fs->super, fs->group_desc_count) - 1 + fs->super->s_first_data_block; retval = ext2fs_resize_block_bitmap2(new_size - 1, real_end, fs->block_map); @@ -2394,7 +2393,7 @@ blk64_t calculate_minimum_resize_size(ext2_filsys fs, int flags) fs->super->s_free_inodes_count; blks_needed = ext2fs_div_ceil(inode_count, fs->super->s_inodes_per_group) * - EXT2_BLOCKS_PER_GROUP(fs->super); + (blk64_t) EXT2_BLOCKS_PER_GROUP(fs->super); groups = ext2fs_div64_ceil(blks_needed, EXT2_BLOCKS_PER_GROUP(fs->super)); #ifdef RESIZE2FS_DEBUG @@ -2441,7 +2440,7 @@ blk64_t calculate_minimum_resize_size(ext2_filsys fs, int flags) * figure out how many data blocks we have given the number of groups * we need for our inodes */ - data_blocks = groups * EXT2_BLOCKS_PER_GROUP(fs->super); + data_blocks = EXT2_GROUPS_TO_BLOCKS(fs->super, groups); last_start = 0; for (grp = 0; grp < flex_groups; grp++) { overhead = calc_group_overhead(fs, grp, old_desc_blocks); @@ -2479,7 +2478,7 @@ blk64_t calculate_minimum_resize_size(ext2_filsys fs, int flags) extra_grps = ext2fs_div64_ceil(remainder, EXT2_BLOCKS_PER_GROUP(fs->super)); - data_blocks += extra_grps * EXT2_BLOCKS_PER_GROUP(fs->super); + data_blocks += EXT2_GROUPS_TO_BLOCKS(fs->super, extra_grps); /* ok we have to account for the last group */ overhead = calc_group_overhead(fs, groups-1, old_desc_blocks); @@ -2577,7 +2576,7 @@ blk64_t calculate_minimum_resize_size(ext2_filsys fs, int flags) * blocks needed to handle the group descriptor metadata+data * that we need */ - blks_needed = (groups-1) * EXT2_BLOCKS_PER_GROUP(fs->super); + blks_needed = EXT2_GROUPS_TO_BLOCKS(fs->super, groups - 1); blks_needed += overhead; /* diff --git a/tests/f_badcluster/expect b/tests/f_badcluster/expect new file mode 100644 index 00000000..eb3bcf0e --- /dev/null +++ b/tests/f_badcluster/expect @@ -0,0 +1,198 @@ +Pass 1: Checking inodes, blocks, and sizes +Inode 12 logical block 2 (physical block 1154) violates cluster allocation rules. +Will fix in pass 1B. +Inode 12, i_blocks is 32, should be 64. Fix? yes + +Inode 16 logical block 5 (physical block 1173) violates cluster allocation rules. +Will fix in pass 1B. +Inode 16, i_size is 3072, should be 6144. Fix? yes + +Inode 16, i_blocks is 32, should be 64. Fix? yes + +Inode 17 logical block 0 (physical block 1186) violates cluster allocation rules. +Will fix in pass 1B. +Inode 17 logical block 2 (physical block 1184) violates cluster allocation rules. +Will fix in pass 1B. +Inode 17, i_blocks is 32, should be 64. Fix? yes + +Inode 18 logical block 3 (physical block 1201) violates cluster allocation rules. +Will fix in pass 1B. +Inode 18, i_blocks is 32, should be 64. Fix? yes + + +Running additional passes to resolve blocks claimed by more than one inode... +Pass 1B: Rescanning for multiply-claimed blocks +Multiply-claimed block(s) in inode 12: 1154 +Multiply-claimed block(s) in inode 13: 1152--1154 +Multiply-claimed block(s) in inode 14: 1648--1650 +Multiply-claimed block(s) in inode 15: 1650 +Multiply-claimed block(s) in inode 16: 1173 +Multiply-claimed block(s) in inode 17: 1186 1185 1184 +Multiply-claimed block(s) in inode 18: 1201 +Pass 1C: Scanning directories for inodes with multiply-claimed blocks +Pass 1D: Reconciling multiply-claimed blocks +(There are 7 inodes containing multiply-claimed blocks.) + +File /a (inode #12, mod time Tue Jun 17 08:00:50 2014) + has 1 multiply-claimed block(s), shared with 1 file(s): + /b (inode #13, mod time Tue Jun 17 08:00:50 2014) +Clone multiply-claimed blocks? yes + +File /b (inode #13, mod time Tue Jun 17 08:00:50 2014) + has 1 multiply-claimed block(s), shared with 1 file(s): + /a (inode #12, mod time Tue Jun 17 08:00:50 2014) +Multiply-claimed blocks already reassigned or cloned. + +File /c (inode #14, mod time Tue Jun 17 08:00:50 2014) + has 1 multiply-claimed block(s), shared with 1 file(s): + /d (inode #15, mod time Tue Jun 17 08:00:50 2014) +Clone multiply-claimed blocks? yes + +File /d (inode #15, mod time Tue Jun 17 08:00:50 2014) + has 1 multiply-claimed block(s), shared with 1 file(s): + /c (inode #14, mod time Tue Jun 17 08:00:50 2014) +Multiply-claimed blocks already reassigned or cloned. + +File /e (inode #16, mod time Tue Jun 17 08:00:50 2014) + has 1 multiply-claimed block(s), shared with 0 file(s): +Clone multiply-claimed blocks? yes + +File /f (inode #17, mod time Tue Jun 17 08:00:50 2014) + has 1 multiply-claimed block(s), shared with 0 file(s): +Clone multiply-claimed blocks? yes + +File /g (inode #18, mod time Tue Jun 17 08:00:50 2014) + has 1 multiply-claimed block(s), shared with 0 file(s): +Clone multiply-claimed blocks? yes + +Pass 2: Checking directory structure +Pass 3: Checking directory connectivity +Pass 4: Checking reference counts +Pass 5: Checking group summary information +Free blocks count wrong for group #0 (50, counted=47). +Fix? yes + +Free blocks count wrong (800, counted=752). +Fix? yes + + +test_fs: ***** FILE SYSTEM WAS MODIFIED ***** +test_fs: 18/128 files (22.2% non-contiguous), 1296/2048 blocks +Pass 1: Checking inodes, blocks, and sizes +Inode 12, i_blocks is 64, should be 32. Fix? yes + +Inode 16, i_blocks is 64, should be 32. Fix? yes + +Inode 17, i_blocks is 64, should be 32. Fix? yes + +Inode 18, i_blocks is 64, should be 32. Fix? yes + +Pass 2: Checking directory structure +Pass 3: Checking directory connectivity +Pass 4: Checking reference counts +Pass 5: Checking group summary information +Block bitmap differences: -(1168--1200) +Fix? yes + +Free blocks count wrong for group #0 (47, counted=50). +Fix? yes + +Free blocks count wrong (752, counted=800). +Fix? yes + + +test_fs: ***** FILE SYSTEM WAS MODIFIED ***** +test_fs: 18/128 files (5.6% non-contiguous), 1248/2048 blocks +Pass 1: Checking inodes, blocks, and sizes +Pass 2: Checking directory structure +Pass 3: Checking directory connectivity +Pass 4: Checking reference counts +Pass 5: Checking group summary information +test_fs: 18/128 files (5.6% non-contiguous), 1248/2048 blocks +debugfs: stat /a +Inode: 12 Type: regular Mode: 0644 Flags: 0x80000 +Generation: 1117152157 Version: 0x00000001 +User: 0 Group: 0 Size: 3072 +File ACL: 0 Directory ACL: 0 +Links: 1 Blockcount: 32 +Fragment: Address: 0 Number: 0 Size: 0 +ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014 +atime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014 +mtime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014 +EXTENTS: +(0-1):1136-1137, (2):1138 +debugfs: stat /b +Inode: 13 Type: regular Mode: 0644 Flags: 0x80000 +Generation: 1117152158 Version: 0x00000001 +User: 0 Group: 0 Size: 3072 +File ACL: 0 Directory ACL: 0 +Links: 1 Blockcount: 32 +Fragment: Address: 0 Number: 0 Size: 0 +ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014 +atime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014 +mtime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014 +EXTENTS: +(0-2):1152-1154 +debugfs: stat /c +Inode: 14 Type: regular Mode: 0644 Flags: 0x80000 +Generation: 1117152159 Version: 0x00000001 +User: 0 Group: 0 Size: 3072 +File ACL: 0 Directory ACL: 0 +Links: 1 Blockcount: 32 +Fragment: Address: 0 Number: 0 Size: 0 +ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014 +atime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014 +mtime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014 +EXTENTS: +(0-1):1216-1217, (2):1218 +debugfs: stat /d +Inode: 15 Type: regular Mode: 0644 Flags: 0x0 +Generation: 1117152160 Version: 0x00000001 +User: 0 Group: 0 Size: 3072 +File ACL: 0 Directory ACL: 0 +Links: 1 Blockcount: 32 +Fragment: Address: 0 Number: 0 Size: 0 +ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014 +atime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014 +mtime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014 +BLOCKS: +(TIND):1650 +TOTAL: 1 + +debugfs: stat /e +Inode: 16 Type: regular Mode: 0644 Flags: 0x80000 +Generation: 1117152161 Version: 0x00000001 +User: 0 Group: 0 Size: 6144 +File ACL: 0 Directory ACL: 0 +Links: 1 Blockcount: 32 +Fragment: Address: 0 Number: 0 Size: 0 +ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014 +atime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014 +mtime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014 +EXTENTS: +(0-2):1664-1666, (5):1669 +debugfs: stat /f +Inode: 17 Type: regular Mode: 0644 Flags: 0x80000 +Generation: 1117152162 Version: 0x00000001 +User: 0 Group: 0 Size: 3072 +File ACL: 0 Directory ACL: 0 +Links: 1 Blockcount: 32 +Fragment: Address: 0 Number: 0 Size: 0 +ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014 +atime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014 +mtime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014 +EXTENTS: +(0):1232, (1):1233, (2):1234 +debugfs: stat /g +Inode: 18 Type: regular Mode: 0644 Flags: 0x80000 +Generation: 1117152163 Version: 0x00000001 +User: 0 Group: 0 Size: 3072 +File ACL: 0 Directory ACL: 0 +Links: 1 Blockcount: 32 +Fragment: Address: 0 Number: 0 Size: 0 +ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014 +atime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014 +mtime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014 +EXTENTS: +(0-2):1680-1682, (3):1683 +debugfs: \ No newline at end of file diff --git a/tests/f_badcluster/image.gz b/tests/f_badcluster/image.gz new file mode 100644 index 00000000..3f21e98e Binary files /dev/null and b/tests/f_badcluster/image.gz differ diff --git a/tests/f_badcluster/name b/tests/f_badcluster/name new file mode 100644 index 00000000..266f81c9 --- /dev/null +++ b/tests/f_badcluster/name @@ -0,0 +1,2 @@ +test alignment problems with bigalloc clusters + diff --git a/tests/f_badcluster/script b/tests/f_badcluster/script new file mode 100644 index 00000000..74498a44 --- /dev/null +++ b/tests/f_badcluster/script @@ -0,0 +1,24 @@ +if test -x $DEBUGFS_EXE; then + IMAGE=$test_dir/../f_badcluster/image.gz + OUT=$test_name.log + EXP=$test_dir/expect + gzip -d < $IMAGE > $TMPFILE + $FSCK -fy $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed > $OUT + $FSCK -fy $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT + $FSCK -fy $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT + for i in a b c d e f g; do echo "stat /$i"; done | $DEBUGFS_EXE $TMPFILE >> $OUT + + cmp -s $OUT $EXP + status=$? + + if [ "$status" = 0 ]; then + echo "$test_name: $test_description: ok" + touch $test_name.ok + else + echo "$test_name: $test_description: failed" + diff $DIFF_OPTS $EXP $OUT > $test_name.failed + rm -f $test_name.tmp + fi +else + echo "$test_name: skipped" +fi diff --git a/tests/f_big_sparse/expect.1 b/tests/f_big_sparse/expect.1 index 437ade74..eac82ed5 100644 --- a/tests/f_big_sparse/expect.1 +++ b/tests/f_big_sparse/expect.1 @@ -2,11 +2,6 @@ Pass 1: Checking inodes, blocks, and sizes Inode 12, i_size is 61440, should be 4398050758656. Fix? yes Pass 2: Checking directory structure -Filesystem contains large files, but lacks LARGE_FILE flag in superblock. -Fix? yes - -Filesystem has feature flag(s) set, but is a revision 0 filesystem. Fix? yes - Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information diff --git a/tests/f_corrupt_dirent_tail/expect.1 b/tests/f_corrupt_dirent_tail/expect.1 new file mode 100644 index 00000000..0813755c --- /dev/null +++ b/tests/f_corrupt_dirent_tail/expect.1 @@ -0,0 +1,16 @@ +Pass 1: Checking inodes, blocks, and sizes +Pass 2: Checking directory structure +Directory inode 2, block #0, offset 0: directory has no checksum. +Fix? yes + +Directory inode 2, block #0, offset 1012: directory corrupted +Salvage? yes + +Pass 3: Checking directory connectivity +Pass 3A: Optimizing directories +Pass 4: Checking reference counts +Pass 5: Checking group summary information + +test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** +test_filesys: 11/128 files (9.1% non-contiguous), 1090/2048 blocks +Exit status is 1 diff --git a/tests/f_corrupt_dirent_tail/expect.2 b/tests/f_corrupt_dirent_tail/expect.2 new file mode 100644 index 00000000..c42466d3 --- /dev/null +++ b/tests/f_corrupt_dirent_tail/expect.2 @@ -0,0 +1,7 @@ +Pass 1: Checking inodes, blocks, and sizes +Pass 2: Checking directory structure +Pass 3: Checking directory connectivity +Pass 4: Checking reference counts +Pass 5: Checking group summary information +test_filesys: 11/128 files (9.1% non-contiguous), 1090/2048 blocks +Exit status is 0 diff --git a/tests/f_corrupt_dirent_tail/image.gz b/tests/f_corrupt_dirent_tail/image.gz new file mode 100644 index 00000000..f2753080 Binary files /dev/null and b/tests/f_corrupt_dirent_tail/image.gz differ diff --git a/tests/f_corrupt_dirent_tail/name b/tests/f_corrupt_dirent_tail/name new file mode 100644 index 00000000..08259a31 --- /dev/null +++ b/tests/f_corrupt_dirent_tail/name @@ -0,0 +1 @@ +rebuild a directory with corrupt dirent tail diff --git a/tests/f_illitable/expect.1 b/tests/f_illitable/expect.1 index 552a2e79..0aa56872 100644 --- a/tests/f_illitable/expect.1 +++ b/tests/f_illitable/expect.1 @@ -12,7 +12,7 @@ Relocate? yes ../e2fsck/e2fsck: A block group is missing an inode table while reading bad blocks inode This doesn't bode well, but we'll try to go on... Pass 1: Checking inodes, blocks, and sizes -Relocating group 0's inode table to 5... +Relocating group 0's inode table to 7... Restarting e2fsck from the beginning... Pass 1: Checking inodes, blocks, and sizes Root inode is not a directory. Clear? yes diff --git a/tests/f_rebuild_csum_rootdir/expect.1 b/tests/f_rebuild_csum_rootdir/expect.1 new file mode 100644 index 00000000..4df58f91 --- /dev/null +++ b/tests/f_rebuild_csum_rootdir/expect.1 @@ -0,0 +1,311 @@ +Pass 1: Checking inodes, blocks, and sizes +Pass 2: Checking directory structure +Directory inode 2, block #0, offset 0: directory has no checksum. +Fix? yes + +Directory inode 2, block #0, offset 0: directory corrupted +Salvage? yes + +Missing '.' in directory inode 2. +Fix? yes + +Setting filetype for entry '.' in ??? (2) to 2. +Missing '..' in directory inode 2. +Fix? yes + +Setting filetype for entry '..' in ??? (2) to 2. +Pass 3: Checking directory connectivity +'..' in / (2) is (0), should be / (2). +Fix? yes + +Unconnected directory inode 11 (/???) +Connect to /lost+found? yes + +/lost+found not found. Create? yes + +Pass 3A: Optimizing directories +Pass 4: Checking reference counts +Inode 11 ref count is 3, should be 2. Fix? yes + +Unattached inode 12 +Connect to /lost+found? yes + +Inode 12 ref count is 2, should be 1. Fix? yes + +Unattached inode 13 +Connect to /lost+found? yes + +Inode 13 ref count is 2, should be 1. Fix? yes + +Unattached inode 14 +Connect to /lost+found? yes + +Inode 14 ref count is 2, should be 1. Fix? yes + +Unattached inode 15 +Connect to /lost+found? yes + +Inode 15 ref count is 2, should be 1. Fix? yes + +Unattached inode 16 +Connect to /lost+found? yes + +Inode 16 ref count is 2, should be 1. Fix? yes + +Unattached inode 17 +Connect to /lost+found? yes + +Inode 17 ref count is 2, should be 1. Fix? yes + +Unattached inode 18 +Connect to /lost+found? yes + +Inode 18 ref count is 2, should be 1. Fix? yes + +Unattached inode 19 +Connect to /lost+found? yes + +Inode 19 ref count is 2, should be 1. Fix? yes + +Unattached inode 20 +Connect to /lost+found? yes + +Inode 20 ref count is 2, should be 1. Fix? yes + +Unattached inode 21 +Connect to /lost+found? yes + +Inode 21 ref count is 2, should be 1. Fix? yes + +Unattached inode 22 +Connect to /lost+found? yes + +Inode 22 ref count is 2, should be 1. Fix? yes + +Unattached inode 23 +Connect to /lost+found? yes + +Inode 23 ref count is 2, should be 1. Fix? yes + +Unattached inode 24 +Connect to /lost+found? yes + +Inode 24 ref count is 2, should be 1. Fix? yes + +Unattached inode 25 +Connect to /lost+found? yes + +Inode 25 ref count is 2, should be 1. Fix? yes + +Unattached inode 26 +Connect to /lost+found? yes + +Inode 26 ref count is 2, should be 1. Fix? yes + +Unattached inode 27 +Connect to /lost+found? yes + +Inode 27 ref count is 2, should be 1. Fix? yes + +Unattached inode 28 +Connect to /lost+found? yes + +Inode 28 ref count is 2, should be 1. Fix? yes + +Unattached inode 29 +Connect to /lost+found? yes + +Inode 29 ref count is 2, should be 1. Fix? yes + +Unattached inode 30 +Connect to /lost+found? yes + +Inode 30 ref count is 2, should be 1. Fix? yes + +Unattached inode 31 +Connect to /lost+found? yes + +Inode 31 ref count is 2, should be 1. Fix? yes + +Unattached inode 32 +Connect to /lost+found? yes + +Inode 32 ref count is 2, should be 1. Fix? yes + +Unattached inode 33 +Connect to /lost+found? yes + +Inode 33 ref count is 2, should be 1. Fix? yes + +Unattached inode 34 +Connect to /lost+found? yes + +Inode 34 ref count is 2, should be 1. Fix? yes + +Unattached inode 35 +Connect to /lost+found? yes + +Inode 35 ref count is 2, should be 1. Fix? yes + +Unattached inode 36 +Connect to /lost+found? yes + +Inode 36 ref count is 2, should be 1. Fix? yes + +Unattached inode 37 +Connect to /lost+found? yes + +Inode 37 ref count is 2, should be 1. Fix? yes + +Unattached inode 38 +Connect to /lost+found? yes + +Inode 38 ref count is 2, should be 1. Fix? yes + +Unattached inode 39 +Connect to /lost+found? yes + +Inode 39 ref count is 2, should be 1. Fix? yes + +Unattached inode 40 +Connect to /lost+found? yes + +Inode 40 ref count is 2, should be 1. Fix? yes + +Unattached inode 41 +Connect to /lost+found? yes + +Inode 41 ref count is 2, should be 1. Fix? yes + +Unattached inode 42 +Connect to /lost+found? yes + +Inode 42 ref count is 2, should be 1. Fix? yes + +Unattached inode 43 +Connect to /lost+found? yes + +Inode 43 ref count is 2, should be 1. Fix? yes + +Unattached inode 44 +Connect to /lost+found? yes + +Inode 44 ref count is 2, should be 1. Fix? yes + +Unattached inode 45 +Connect to /lost+found? yes + +Inode 45 ref count is 2, should be 1. Fix? yes + +Unattached inode 46 +Connect to /lost+found? yes + +Inode 46 ref count is 2, should be 1. Fix? yes + +Unattached inode 47 +Connect to /lost+found? yes + +Inode 47 ref count is 2, should be 1. Fix? yes + +Unattached inode 48 +Connect to /lost+found? yes + +Inode 48 ref count is 2, should be 1. Fix? yes + +Unattached inode 49 +Connect to /lost+found? yes + +Inode 49 ref count is 2, should be 1. Fix? yes + +Unattached inode 50 +Connect to /lost+found? yes + +Inode 50 ref count is 2, should be 1. Fix? yes + +Unattached inode 51 +Connect to /lost+found? yes + +Inode 51 ref count is 2, should be 1. Fix? yes + +Unattached inode 52 +Connect to /lost+found? yes + +Inode 52 ref count is 2, should be 1. Fix? yes + +Unattached inode 53 +Connect to /lost+found? yes + +Inode 53 ref count is 2, should be 1. Fix? yes + +Unattached inode 54 +Connect to /lost+found? yes + +Inode 54 ref count is 2, should be 1. Fix? yes + +Unattached inode 55 +Connect to /lost+found? yes + +Inode 55 ref count is 2, should be 1. Fix? yes + +Unattached inode 56 +Connect to /lost+found? yes + +Inode 56 ref count is 2, should be 1. Fix? yes + +Unattached inode 57 +Connect to /lost+found? yes + +Inode 57 ref count is 2, should be 1. Fix? yes + +Unattached inode 58 +Connect to /lost+found? yes + +Inode 58 ref count is 2, should be 1. Fix? yes + +Unattached inode 59 +Connect to /lost+found? yes + +Inode 59 ref count is 2, should be 1. Fix? yes + +Unattached inode 60 +Connect to /lost+found? yes + +Inode 60 ref count is 2, should be 1. Fix? yes + +Unattached inode 61 +Connect to /lost+found? yes + +Inode 61 ref count is 2, should be 1. Fix? yes + +Unattached inode 62 +Connect to /lost+found? yes + +Inode 62 ref count is 2, should be 1. Fix? yes + +Unattached inode 63 +Connect to /lost+found? yes + +Inode 63 ref count is 2, should be 1. Fix? yes + +Unattached inode 64 +Connect to /lost+found? yes + +Inode 64 ref count is 2, should be 1. Fix? yes + +Unattached zero-length inode 65. Clear? yes + +Unattached inode 66 +Connect to /lost+found? yes + +Inode 66 ref count is 2, should be 1. Fix? yes + +Unattached inode 67 +Connect to /lost+found? yes + +Inode 67 ref count is 2, should be 1. Fix? yes + +Pass 5: Checking group summary information + +test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** +test_filesys: 67/512 files (1.5% non-contiguous), 1127/2048 blocks +Exit status is 1 diff --git a/tests/f_rebuild_csum_rootdir/expect.2 b/tests/f_rebuild_csum_rootdir/expect.2 new file mode 100644 index 00000000..033f1bf7 --- /dev/null +++ b/tests/f_rebuild_csum_rootdir/expect.2 @@ -0,0 +1,7 @@ +Pass 1: Checking inodes, blocks, and sizes +Pass 2: Checking directory structure +Pass 3: Checking directory connectivity +Pass 4: Checking reference counts +Pass 5: Checking group summary information +test_filesys: 67/512 files (1.5% non-contiguous), 1127/2048 blocks +Exit status is 0 diff --git a/tests/f_rebuild_csum_rootdir/image.gz b/tests/f_rebuild_csum_rootdir/image.gz new file mode 100644 index 00000000..a32fd443 Binary files /dev/null and b/tests/f_rebuild_csum_rootdir/image.gz differ diff --git a/tests/f_rebuild_csum_rootdir/name b/tests/f_rebuild_csum_rootdir/name new file mode 100644 index 00000000..b246f480 --- /dev/null +++ b/tests/f_rebuild_csum_rootdir/name @@ -0,0 +1 @@ +force fsck to rebuild a corrupted rootdir w/ metadata_csum diff --git a/tests/m_64bit_flexbg/expect.1 b/tests/m_64bit_flexbg/expect.1 new file mode 100644 index 00000000..36353183 --- /dev/null +++ b/tests/m_64bit_flexbg/expect.1 @@ -0,0 +1,55 @@ +Creating filesystem with 1024 1k blocks and 128 inodes + +Allocating group tables: done +Writing inode tables: done +Writing superblocks and filesystem accounting information: done + +Filesystem features: ext_attr resize_inode dir_index filetype extent 64bit flex_bg sparse_super +Pass 1: Checking inodes, blocks, and sizes +Pass 2: Checking directory structure +Pass 3: Checking directory connectivity +Pass 4: Checking reference counts +Pass 5: Checking group summary information +test_filesys: 11/128 files (0.0% non-contiguous), 42/1024 blocks +Exit status is 0 +Filesystem volume name: +Last mounted on: +Filesystem magic number: 0xEF53 +Filesystem revision #: 1 (dynamic) +Filesystem features: ext_attr resize_inode dir_index filetype extent 64bit flex_bg sparse_super +Default mount options: (none) +Filesystem state: clean +Errors behavior: Continue +Filesystem OS type: Linux +Inode count: 128 +Block count: 1024 +Reserved block count: 51 +Free blocks: 982 +Free inodes: 117 +First block: 1 +Block size: 1024 +Fragment size: 1024 +Group descriptor size: 64 +Reserved GDT blocks: 7 +Blocks per group: 8192 +Fragments per group: 8192 +Inodes per group: 128 +Inode blocks per group: 16 +Flex block group size: 16 +Mount count: 0 +Check interval: 15552000 (6 months) +Reserved blocks uid: 0 +Reserved blocks gid: 0 +First inode: 11 +Inode size: 128 +Default directory hash: half_md4 + + +Group 0: (Blocks 1-1023) + Primary superblock at 1, Group descriptors at 2-2 + Reserved GDT blocks at 3-9 + Block bitmap at 10 (+9), Inode bitmap at 26 (+25) + Inode table at 42-57 (+41) + 982 free blocks, 117 free inodes, 2 directories + Free blocks: 24-25, 28-41, 58-1023 + Free inodes: 12-128 diff --git a/tests/m_64bit_flexbg/script b/tests/m_64bit_flexbg/script new file mode 100644 index 00000000..98684e43 --- /dev/null +++ b/tests/m_64bit_flexbg/script @@ -0,0 +1,4 @@ +DESCRIPTION="mkfs with 64bit and flex_bg" +FS_SIZE=1M +MKE2FS_OPTS="-O 64bit,extents,flex_bg" +. $cmd_dir/run_mke2fs diff --git a/tests/scripts/resize_test b/tests/scripts/resize_test index a12e4b94..0633e0c9 100755 --- a/tests/scripts/resize_test +++ b/tests/scripts/resize_test @@ -64,8 +64,8 @@ then return 1 fi -echo $FSCK -fp $TMPFILE >> $LOG 2>&1 -if ! $FSCK -fp $TMPFILE >> $LOG 2>&1 +echo $FSCK -fy $TMPFILE >> $LOG 2>&1 +if ! $FSCK -fy $TMPFILE >> $LOG 2>&1 then dumpe2fs $TMPFILE >> $LOG return 1 @@ -94,8 +94,8 @@ then return 1 fi -echo $FSCK -fp $TMPFILE >> $LOG 2>&1 -if ! $FSCK -fp $TMPFILE >> $LOG 2>&1 +echo $FSCK -fy $TMPFILE >> $LOG 2>&1 +if ! $FSCK -fy $TMPFILE >> $LOG 2>&1 then dumpe2fs $TMPFILE >> $LOG return 1 @@ -119,8 +119,8 @@ then return 1 fi -echo $FSCK -fp $TMPFILE >> $LOG 2>&1 -if ! $FSCK -fp $TMPFILE >> $LOG 2>&1 +echo $FSCK -fy $TMPFILE >> $LOG 2>&1 +if ! $FSCK -fy $TMPFILE >> $LOG 2>&1 then dumpe2fs $TMPFILE >> $LOG return 1 @@ -144,8 +144,8 @@ then return 1 fi -echo $FSCK -fp $TMPFILE >> $LOG 2>&1 -if ! $FSCK -fp $TMPFILE >> $LOG 2>&1 +echo $FSCK -fy $TMPFILE >> $LOG 2>&1 +if ! $FSCK -fy $TMPFILE >> $LOG 2>&1 then dumpe2fs $TMPFILE >> $LOG return 1 diff --git a/util/gcc-wall-cleanup b/util/gcc-wall-cleanup index 6148e461..c6195268 100644 --- a/util/gcc-wall-cleanup +++ b/util/gcc-wall-cleanup @@ -16,7 +16,6 @@ /In file included from/d /In function `.*':/d /zero-length format string/d -/warning: missing initializer/d /warning: (near initialization for/d /^[ ]*from/d diff --git a/util/subst.c b/util/subst.c index 85020c95..5c9b142e 100644 --- a/util/subst.c +++ b/util/subst.c @@ -14,6 +14,9 @@ #include #include #include +#ifdef HAVE_SYS_TIME_H +#include +#endif #include #include #include