Compare commits

...

19 Commits

Author SHA1 Message Date
Vitaliy Filippov 6e4fa6e281 Fix ea remapping 2016-09-29 01:51:04 +03:00
Vitaliy Filippov b331d80fba Fix itable_unused adjustment - fixes shrink FS + shrink inode tables and some other cases 2016-09-27 23:53:58 +03:00
Vitaliy Filippov f99c7a2e12 One way to fix non-contiguous inode table allocations... 2016-09-26 00:02:00 +03:00
Vitaliy Filippov b9b963d427 Fix the rest of block bitmap differences 2016-09-26 00:02:00 +03:00
Vitaliy Filippov f58c260dc4 Remap blocks before moving inode tables (fixes big flex_bg extend),
check blocks to move even when shrinking inode tables (fixes big flex_bg shrink),
mark inode tables during allocation (fixes bigalloc shrink)
2016-09-25 23:48:01 +03:00
Vitaliy Filippov 152890aa45 Split inode_scan_and_fix into two parts.
- Basic extend and shrink works
- Extend on bigalloc fs works
- Shrink on bigalloc fs gives errors
- Extend on big flex_bg gives errors
2016-09-25 23:48:01 +03:00
Vitaliy Filippov 63039f4bac Implement inode table resizing (not done yet, should split inode_scan_and_fix()) 2016-09-25 23:47:54 +03:00
Vitaliy Filippov 7e0136332c Add patch_io manager support to resize2fs and e2fsck 2016-09-25 23:47:26 +03:00
Vitaliy Filippov b3782b2e5b Add e2patch utility 2016-09-16 11:54:35 +03:00
Vitaliy Filippov 460c0af190 Add patch_io manager 2016-09-16 11:38:14 +03:00
Vitaliy Filippov 2051d63a83 misc: Return error if file is too big for FIBMAP 2016-09-16 11:02:45 +03:00
Theodore Ts'o e703ba4b42 Fix reversed FORCE_NATIVE_MAKE test in acinclude.m4
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
2016-09-11 23:12:07 -04:00
Theodore Ts'o d6cad379eb libext2fs: fix unaligned, multiblock writes in the unix_io handler
The read-modify-write code for the unaligned fallback code wasn't
working for multi-block writes.  This was unmasked by FreeBSD 11-rc2,
since its malloc() is returning unaligned memory regions for large
memory regions.

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
2016-09-11 00:25:48 -04:00
Theodore Ts'o 4e52870eeb Update release notes, etc., for 1.43.3 release
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
2016-09-04 21:31:21 -04:00
Theodore Ts'o 047d5d774f e2fsck: enforce that the extra isize fields in the superblock are sane
Invalid extra isize fields can cause crashes in e2fsprogs and possibly
in the kernel for some architectures due to unaligned accesses.

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
2016-09-04 17:41:20 -04:00
Theodore Ts'o a7b27f11a1 e2fsck: enforce that extra_isize must be a multiple of four
We need to prevent unaligned accesses, so treat any extra_isize which
is not a multiple of four as an bug.

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
2016-09-04 16:34:49 -04:00
Theodore Ts'o 8d7a63921f Avoid crashing on unaligned pointers from corrupted file systems
On platforms that don't permit unaligned pointer dereferences,
corrupted file systems will as used by the regression test suite can
cause e2fsck and debugfs to crash.  Avoid those crashes caused by
corrupted file systems.  With this commit the full set of regression
test suites will pass on the sparc64 platform.

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
2016-09-04 15:06:32 -04:00
Theodore Ts'o f3bc1561c8 Fix FreeBSD pmake support
Fix a typo in the @ifNotGNUmake@ case of MCONFIG.in.

Also allow the FORCE_NATIVE_MAKE to force the use of the non-GNU make
optimized Makefile.  The resulting makefile will work with GNU Make
4.2.1, although "make V=1" won't be honored.

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
2016-09-04 00:16:35 -04:00
Theodore Ts'o 254195627f e2fsck: fix timestamps logic for 32-bit systems
Commit 35a4e1b1c5 introduced a regression which caused e2fsck on
32-bit systems to think all timestamps were legacy pre-1970
timestamps.  Fix the bug.

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
2016-09-03 23:33:11 -04:00
81 changed files with 19267 additions and 10971 deletions

2
.gitignore vendored
View File

@ -161,6 +161,8 @@ misc/e2initrd_helper
misc/e2label.8
misc/e2undo
misc/e2undo.8
misc/e2patch
misc/e2patch.8
misc/e4defrag
misc/e4defrag.8
misc/ext4.5

View File

@ -68,8 +68,8 @@ pkgconfigdir = $(libdir)/pkgconfig
@ifGNUmake@ endif
@ifGNUmake@ endif
@ifNotGNUmake@ CHECK_CMD=@true
@ifNotGNUmake@ CPPHECK_CMD=@true
@ifNotGNUmake@ CHECK_CMD=true
@ifNotGNUmake@ CPPCHECK_CMD=true
CC = @CC@
BUILD_CC = @BUILD_CC@

2
README
View File

@ -1,4 +1,4 @@
This is the new version (1.43.2) of the second extended file
This is the new version (1.43.3) of the second extended file
system management programs.
From time to time, I release new versions of e2fsprogs, to fix

View File

@ -1,3 +1,31 @@
E2fsprogs 1.43.3 (September 4, 2016)
====================================
Fix e2fsck's handling of timestamps on 32-bit systems.
E2fsck will now check, and if necessary repair the extra isize fields
in the inode and superblock.
Fix crashes on architectures such as sparc64 that are sensitive to
unaligned pointer derferences in the journal recovery code when
journal checksums are enabled.
Programming notes
-----------------
Support reproducible builds by not capturing the build directory into
the mk_cmds and compile_et scripts. Also fix debian build rules to
ensure build reproducibility.
Fix debian build rules to ensure build reproducibility and to avoid
hiding the linker flags for e2fsck.static so the build hardening log
scanner can properly audit the build.
Fix compatibility with FreeBSD's pmake and teach the configure script
to force the creation of pmake-compatible Makefiles if the
FORCE_NATIVE_MAKE environment variable is set to a non-empty value.
E2fsprogs 1.43.2 (September 1, 2016)
====================================

View File

@ -108,7 +108,12 @@ AC_DEFUN(
[CHECK_GNU_MAKE], [ AC_CACHE_CHECK( for GNU make,_cv_gnu_make_command,
_cv_gnu_make_command='' ;
dnl Search all the common names for GNU make
for a in "$MAKE" make gmake gnumake ; do
if test -n "$FORCE_NATIVE_MAKE" ; then
MAKES="make"
else
MAKES="make gmake gnumake"
fi
for a in "$MAKE" $MAKES ; do
if test -z "$a" ; then continue ; fi ;
if ( sh -c "$a --version" 2> /dev/null | grep GNU 2>&1 > /dev/null ) ; then
_cv_gnu_make_command=$a ;

7
configure vendored
View File

@ -11515,7 +11515,12 @@ if ${_cv_gnu_make_command+:} false; then :
$as_echo_n "(cached) " >&6
else
_cv_gnu_make_command='' ;
for a in "$MAKE" make gmake gnumake ; do
if test -n "$FORCE_NATIVE_MAKE" ; then
MAKES="make"
else
MAKES="make gmake gnumake"
fi
for a in "$MAKE" $MAKES ; do
if test -z "$a" ; then continue ; fi ;
if ( sh -c "$a --version" 2> /dev/null | grep GNU 2>&1 > /dev/null ) ; then
_cv_gnu_make_command=$a ;

10
debian/changelog vendored
View File

@ -1,3 +1,13 @@
e2fsprogs (1.43.3-1) unstable; urgency=medium
* Fix e2fsck's handling of timestamps on 32-bit system (Closes: #836559)
* E2fsck will sanity check and repair the extra isize fields in inodes
and the superblock.
* Fix sparc64 crashes when dereferencing unaligned integers in journal
blocks when metdata checksums are enabled.
-- Theodore Y. Ts'o <tytso@mit.edu> Sun, 04 Sep 2016 20:41:21 -0400
e2fsprogs (1.43.2-2) unstable; urgency=medium
* Fix build reproducibility problems

View File

@ -1,7 +1,7 @@
\input texinfo @c -*-texinfo-*-
@c %**start of header
@setfilename libext2fs.info
@settitle The EXT2FS Library (version 1.43.2)
@settitle The EXT2FS Library (version 1.43.3)
@synindex tp fn
@comment %**end of header
@ -60,7 +60,7 @@ by the author.
@title The EXT2FS Library
@subtitle The EXT2FS Library
@subtitle Version 1.43.2
@subtitle Version 1.43.3
@subtitle September 2016
@author by Theodore Ts'o
@ -101,7 +101,7 @@ by the Foundation.
@top The EXT2FS Library
This manual documents the EXT2FS Library, version 1.43.2.
This manual documents the EXT2FS Library, version 1.43.3.
@menu
* Introduction to the EXT2FS Library::

View File

@ -345,6 +345,12 @@ or
.B \-p
options.
.TP
.BI \-T " patch_file"
Do not apply changes to the real filesystem; write updates into a sparse file
named 'patch_file' to safely apply them later with e2patch(8) utility.
You'll also be able to create a backup before applying patch and safely
restore it in case of power outage or system crash.
.TP
.BI \-z " undo_file"
Before overwriting a file system block, write the old contents of the block to
an undo file. This undo file can be used with e2undo(8) to restore the old

View File

@ -391,6 +391,9 @@ struct e2fsck_struct {
*/
ext2fs_inode_bitmap inodes_to_rebuild;
/* Patch file */
char *patch_file;
/* Undo file */
char *undo_file;
};

View File

@ -488,10 +488,14 @@ static void check_inode_extra_space(e2fsck_t ctx, struct problem_context *pctx)
* implementations should never allow i_extra_isize to be 0
*/
if (inode->i_extra_isize &&
(inode->i_extra_isize < min || inode->i_extra_isize > max)) {
(inode->i_extra_isize < min || inode->i_extra_isize > max ||
inode->i_extra_isize & 3)) {
if (!fix_problem(ctx, PR_1_EXTRA_ISIZE, pctx))
return;
inode->i_extra_isize = min;
if (inode->i_extra_isize < min || inode->i_extra_isize > max)
inode->i_extra_isize = sb->s_want_extra_isize;
else
inode->i_extra_isize = (inode->i_extra_isize + 3) & ~3;
e2fsck_write_inode_full(ctx, pctx->ino, pctx->inode,
EXT2_INODE_SIZE(sb), "pass1");
return;
@ -512,9 +516,9 @@ static void check_inode_extra_space(e2fsck_t ctx, struct problem_context *pctx)
* If the inode's extended atime (ctime, crtime, mtime) is stored in
* the old, invalid format, repair it.
*/
if ((sizeof(time_t) <= 4) ||
(((sizeof(time_t) > 4) &&
ctx->now < EXT4_EXTRA_NEGATIVE_DATE_CUTOFF)) &&
if (((sizeof(time_t) <= 4) ||
(((sizeof(time_t) > 4) &&
ctx->now < EXT4_EXTRA_NEGATIVE_DATE_CUTOFF))) &&
(CHECK_INODE_EXTRA_NEGATIVE_EPOCH(inode, atime) ||
CHECK_INODE_EXTRA_NEGATIVE_EPOCH(inode, ctime) ||
CHECK_INODE_EXTRA_NEGATIVE_EPOCH(inode, crtime) ||

View File

@ -477,6 +477,16 @@ static struct e2fsck_problem problem_table[] = {
N_("Error initializing quota context in support library: %m\n"),
PROMPT_NULL, PR_FATAL },
/* Bad s_min_extra_isize in superblock */
{ PR_0_BAD_MIN_EXTRA_ISIZE,
N_("Bad required extra isize in @S (%N). "),
PROMPT_FIX, 0 },
/* Bad s_min_extra_isize in superblock */
{ PR_0_BAD_WANT_EXTRA_ISIZE,
N_("Bad desired extra isize in @S (%N). "),
PROMPT_FIX, 0 },
/* Pass 1 errors */
/* Pass 1: Checking inodes, blocks, and sizes */

View File

@ -274,6 +274,12 @@ struct problem_context {
/* Error initializing quota context */
#define PR_0_QUOTA_INIT_CTX 0x00004C
/* Bad s_min_extra_isize in superblock */
#define PR_0_BAD_MIN_EXTRA_ISIZE 0x00004D
/* Bad s_want_extra_isize in superblock */
#define PR_0_BAD_WANT_EXTRA_ISIZE 0x00004E
/*
* Pass 1 errors

View File

@ -338,12 +338,24 @@ int journal_skip_recovery(journal_t *journal)
return err;
}
static inline __u32 get_be32(__be32 *p)
{
unsigned char *cp = (unsigned char *) p;
__u32 ret;
ret = *cp++;
ret = (ret << 8) + *cp++;
ret = (ret << 8) + *cp++;
ret = (ret << 8) + *cp++;
return ret;
}
static inline unsigned long long read_tag_block(journal_t *journal,
journal_block_tag_t *tag)
{
unsigned long long block = ext2fs_be32_to_cpu(tag->t_blocknr);
unsigned long long block = get_be32(&tag->t_blocknr);
if (jfs_has_feature_64bit(journal))
block |= (u64)ext2fs_be32_to_cpu(tag->t_blocknr_high) << 32;
block |= (u64)get_be32(&tag->t_blocknr_high) << 32;
return block;
}

View File

@ -578,7 +578,35 @@ void check_super_block(e2fsck_t ctx)
ext2fs_mark_super_dirty(fs);
}
}
if (EXT2_INODE_SIZE(sb) > EXT2_GOOD_OLD_INODE_SIZE) {
unsigned min =
sizeof(((struct ext2_inode_large *) 0)->i_extra_isize) +
sizeof(((struct ext2_inode_large *) 0)->i_checksum_hi);
unsigned max = EXT2_INODE_SIZE(sb) - EXT2_GOOD_OLD_INODE_SIZE;
pctx.num = sb->s_min_extra_isize;
if (sb->s_min_extra_isize &&
(sb->s_min_extra_isize < min ||
sb->s_min_extra_isize > max ||
sb->s_min_extra_isize & 3) &&
fix_problem(ctx, PR_0_BAD_MIN_EXTRA_ISIZE, &pctx)) {
sb->s_min_extra_isize =
(sizeof(struct ext2_inode_large) -
EXT2_GOOD_OLD_INODE_SIZE);
ext2fs_mark_super_dirty(fs);
}
pctx.num = sb->s_want_extra_isize;
if (sb->s_want_extra_isize &&
(sb->s_want_extra_isize < min ||
sb->s_want_extra_isize > max ||
sb->s_want_extra_isize & 3) &&
fix_problem(ctx, PR_0_BAD_WANT_EXTRA_ISIZE, &pctx)) {
sb->s_want_extra_isize =
(sizeof(struct ext2_inode_large) -
EXT2_GOOD_OLD_INODE_SIZE);
ext2fs_mark_super_dirty(fs);
}
}
/* Are metadata_csum and uninit_bg both set? */
if (ext2fs_has_feature_metadata_csum(fs->super) &&
ext2fs_has_feature_gdt_csum(fs->super) &&

View File

@ -76,7 +76,7 @@ static void usage(e2fsck_t ctx)
fprintf(stderr,
_("Usage: %s [-panyrcdfktvDFV] [-b superblock] [-B blocksize]\n"
"\t\t[-l|-L bad_blocks_file] [-C fd] [-j external_journal]\n"
"\t\t[-E extended-options] [-z undo_file] device\n"),
"\t\t[-E extended-options] [-T patch_file] [-z undo_file] device\n"),
ctx->program_name);
fprintf(stderr, "%s", _("\nEmergency help:\n"
@ -92,6 +92,7 @@ static void usage(e2fsck_t ctx)
" -j external_journal Set location of the external journal\n"
" -l bad_blocks_file Add to badblocks list\n"
" -L bad_blocks_file Set badblocks list\n"
" -T patch_file Create a patch file instead of applying changes to real FS\n"
" -z undo_file Create an undo file\n"
));
@ -804,7 +805,7 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
phys_mem_kb = get_memory_size() / 1024;
ctx->readahead_kb = ~0ULL;
while ((c = getopt(argc, argv, "panyrcC:B:dE:fvtFVM:b:I:j:P:l:L:N:SsDkz:")) != EOF)
while ((c = getopt(argc, argv, "panyrcC:B:dE:fvtFVM:b:I:j:P:l:L:N:SsDkT:z:")) != EOF)
switch (c) {
case 'C':
ctx->progress = e2fsck_update_progress;
@ -936,6 +937,9 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
case 'k':
keep_bad_blocks++;
break;
case 'T':
ctx->patch_file = optarg;
break;
case 'z':
ctx->undo_file = optarg;
break;
@ -1233,6 +1237,19 @@ check_error:
return retval;
}
static int e2fsck_setup_patch(e2fsck_t ctx, io_manager *io_ptr)
{
set_patch_io_backing_manager(*io_ptr);
set_patch_io_patch_file(ctx->patch_file);
*io_ptr = patch_io_manager;
printf(_("To make backup before applying changes run:\n"
" e2patch backup %s %s %s.backup\n"
"Then, to apply the operation to the real filesystem run:\n"
" e2patch apply %s %s\n"),
ctx->device_name, ctx->patch_file, ctx->patch_file, ctx->device_name, ctx->patch_file);
return 0;
}
static int e2fsck_setup_tdb(e2fsck_t ctx, io_manager *io_ptr)
{
errcode_t retval = ENOMEM;
@ -1430,7 +1447,11 @@ restart:
flags &= ~EXT2_FLAG_EXCLUSIVE;
}
if (ctx->undo_file) {
if (ctx->patch_file) {
retval = e2fsck_setup_patch(ctx, &io_ptr);
if (retval)
exit(FSCK_ERROR);
} else if (ctx->undo_file) {
retval = e2fsck_setup_tdb(ctx, &io_ptr);
if (retval)
exit(FSCK_ERROR);

View File

@ -1,16 +1,16 @@
Begin3
Title: EXT2 Filesystem utilities
Version: 1.43.2
Entered-date: 2016-09-01
Version: 1.43.3
Entered-date: 2016-09-04
Description: The filesystem utilities for the EXT2, EXT3, and EXT4
filesystems, including e2fsck, mke2fs, dumpe2fs, and others.
Keywords: utilities, filesystem, Ext2fs, ext3, ext4
Author: tytso@mit.edu (Theodore Tso)
Maintained-by: tytso@mit.edu (Theodore Tso)
Primary-site: ftp.kernel.org /pub/linux/kernel/people/tytso/e2fsprogs
7224kB e2fsprogs-1.43.2.tar.gz
644kB e2fsprogs-libs-1.43.2.tar.gz
1kB e2fsprogs-1.43.2.lsm
7224kB e2fsprogs-1.43.3.tar.gz
644kB e2fsprogs-libs-1.43.3.tar.gz
1kB e2fsprogs-1.43.3.lsm
Alternate-site: download.sourceforge.net /pub/sourceforge/e2fsprogs
Platforms: linux 1.2.x/1.3.x/2.0.x/2.1.x/2.2.x/2.3.x/2.4.x/2.5.x/2.6.x/3.x/4.x
Copying-policy: GPL-2/LGPL-2

View File

@ -117,6 +117,7 @@ exit 0
%{_root_sbindir}/e2image
%{_root_sbindir}/e2label
%{_root_sbindir}/e2undo
%{_root_sbindir}/e2patch
%{_root_sbindir}/findfs
%{_root_sbindir}/fsck
%{_root_sbindir}/fsck.ext2
@ -168,6 +169,7 @@ exit 0
%{_mandir}/man8/e2image.8*
%{_mandir}/man8/e2label.8*
%{_mandir}/man8/e2undo.8*
%{_mandir}/man8/e2patch.8*
%{_mandir}/man8/fsck.8*
%{_mandir}/man8/logsave.8*
%{_mandir}/man8/mke2fs.8*

View File

@ -75,6 +75,8 @@ libext2fs_src_files := \
swapfs.c \
symlink.c \
undo_io.c \
patch.c \
patch_io.c \
unix_io.c \
unlink.c \
valid_blk.c \

View File

@ -124,6 +124,8 @@ OBJS= $(DEBUGFS_LIB_OBJS) $(RESIZE_LIB_OBJS) $(E2IMAGE_LIB_OBJS) \
symlink.o \
$(TDB_OBJ) \
undo_io.o \
patch.o \
patch_io.o \
unix_io.o \
unlink.o \
valid_blk.o \
@ -211,6 +213,8 @@ SRCS= ext2_err.c \
$(srcdir)/tst_getsize.c \
$(srcdir)/tst_iscan.c \
$(srcdir)/undo_io.c \
$(srcdir)/patch.c \
$(srcdir)/patch_io.c \
$(srcdir)/unix_io.c \
$(srcdir)/unlink.c \
$(srcdir)/valid_blk.c \
@ -1099,6 +1103,18 @@ undo_io.o: $(srcdir)/undo_io.c $(top_builddir)/lib/config.h \
$(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
$(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
$(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h $(srcdir)/ext2fsP.h
patch.o: $(srcdir)/patch.c $(top_builddir)/lib/config.h \
$(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.h \
$(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
$(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
$(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
$(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h $(srcdir)/ext2fsP.h
patch_io.o: $(srcdir)/patch_io.c $(top_builddir)/lib/config.h \
$(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.h \
$(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
$(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
$(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
$(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h $(srcdir)/ext2fsP.h
unix_io.o: $(srcdir)/unix_io.c $(top_builddir)/lib/config.h \
$(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.h \
$(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \

View File

@ -185,8 +185,9 @@ struct ext2_group_desc *ext2fs_group_desc(ext2_filsys fs,
struct opaque_ext2_group_desc *gdp,
dgrp_t group)
{
return (struct ext2_group_desc *)((char *)gdp +
group * EXT2_DESC_SIZE(fs->super));
int desc_size = EXT2_DESC_SIZE(fs->super) & ~7;
return (struct ext2_group_desc *)((char *)gdp + group * desc_size);
}
/* Do the same but as an ext4 group desc for internal use here */

View File

@ -539,4 +539,7 @@ ec EXT2_ET_BAD_CRC,
ec EXT2_ET_CORRUPT_JOURNAL_SB,
"The journal superblock is corrupt"
ec EXT2_ET_INODE_CORRUPTED,
"Inode is corrupted"
end

View File

@ -145,6 +145,11 @@ extern io_manager undo_io_manager;
extern errcode_t set_undo_io_backing_manager(io_manager manager);
extern errcode_t set_undo_io_backup_file(char *file_name);
/* patch_io.c */
extern io_manager patch_io_manager;
extern errcode_t set_patch_io_backing_manager(io_manager manager);
extern errcode_t set_patch_io_patch_file(char *file_name);
/* test_io.c */
extern io_manager test_io_manager, test_io_backing_manager;
extern void (*test_io_cb_read_blk)

View File

@ -554,6 +554,10 @@ errcode_t ext2fs_xattrs_write(struct ext2_xattr_handle *handle)
memset(p + EXT2_GOOD_OLD_INODE_SIZE, 0, extra);
inode->i_extra_isize = extra;
}
if (inode->i_extra_isize & 3) {
err = EXT2_ET_INODE_CORRUPTED;
goto out;
}
/*
* Force the inlinedata attr to the front and the empty entries
@ -806,6 +810,10 @@ errcode_t ext2fs_xattrs_read(struct ext2_xattr_handle *handle)
inode->i_extra_isize +
sizeof(__u32))
goto read_ea_block;
if (inode->i_extra_isize & 3) {
err = EXT2_ET_INODE_CORRUPTED;
goto out;
}
/* Look for EA in the inode */
memcpy(&ea_inode_magic, ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +

228
lib/ext2fs/patch.c Normal file
View File

@ -0,0 +1,228 @@
/**
* patch.c --- Common "patch" file functions
*
* Copyright (c) Vitaliy Filippov <vitalif@mail.ru> 2014
* License: GNU GPLv2 or later
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define _LARGEFILE_SOURCE
#define _LARGEFILE64_SOURCE
#include <unistd.h>
#include <fcntl.h>
#include "patch.h"
errcode_t ext2fs_patch_retry_read(int fd, ssize_t size, void *buf)
{
ssize_t r, done = 0;
while (done < size)
{
r = read(fd, buf+done, size-done);
if (!r || (r < 0 && errno != EAGAIN))
break;
done += r;
}
if (done < size)
return errno;
return 0;
}
errcode_t ext2fs_patch_retry_write(int fd, ssize_t size, const void *buf)
{
ssize_t r, done = 0;
while (done < size)
{
r = write(fd, buf+done, size-done);
if (r <= 0 && errno != EAGAIN)
break;
done += r;
}
if (done < size)
return errno;
return 0;
}
errcode_t ext2fs_patch_retry_read_at(int fd, unsigned long long offset, ssize_t size, void *buf)
{
if ((unsigned long long)ext2fs_llseek(fd, offset, SEEK_SET) != offset)
return errno ? errno : EXT2_ET_LLSEEK_FAILED;
return ext2fs_patch_retry_read(fd, size, buf);
}
errcode_t ext2fs_patch_retry_write_at(int fd, unsigned long long offset, ssize_t size, const void *buf)
{
if ((unsigned long long)ext2fs_llseek(fd, offset, SEEK_SET) != offset)
return errno ? errno : EXT2_ET_LLSEEK_FAILED;
return ext2fs_patch_retry_write(fd, size, buf);
}
errcode_t ext2fs_patch_read_bmap(struct ext2fs_patch_file *data)
{
errcode_t retval = 0;
int bufsize = 65536;
blk64_t i, r;
void *buf = malloc(bufsize);
if (!buf)
return ENOMEM;
ext2fs_llseek(data->patch_fd, data->block_size, SEEK_SET);
for (i = 0; i < data->size/8; )
{
r = bufsize;
if (data->size/8 - i < r)
r = data->size/8 - i;
retval = ext2fs_patch_retry_read(data->patch_fd, r, buf);
if (retval)
goto out;
ext2fs_set_generic_bmap_range(data->bmap, i*8, r*8, buf);
i += r;
}
out:
free(buf);
return retval;
}
errcode_t ext2fs_patch_write_bmap(struct ext2fs_patch_file *data)
{
errcode_t retval = 0;
int bufsize = 65536;
blk64_t i, r;
struct patchbd_super s;
void *buf = malloc(bufsize);
if (!buf)
return ENOMEM;
ext2fs_llseek(data->patch_fd, data->block_size, SEEK_SET);
for (i = 0; i < data->size/8; )
{
r = bufsize;
if (data->size/8 - i < r)
r = data->size/8 - i;
ext2fs_get_generic_bmap_range(data->bmap, i*8, r*8, buf);
retval = ext2fs_patch_retry_write(data->patch_fd, r, buf);
if (retval)
goto out;
i += r;
}
ext2fs_llseek(data->patch_fd, 0, SEEK_SET);
s.magic = PATCHBD_MAGIC;
s.patch_block = data->block_size;
s.patch_size = data->size;
write(data->patch_fd, &s, sizeof(struct patchbd_super));
out:
free(buf);
return 0;
}
errcode_t ext2fs_patch_open(struct ext2fs_patch_file *data, char *patch_file, int flags)
{
errcode_t retval = 0;
ext2_loff_t size;
struct patchbd_super s;
data->block_size = 0;
data->size = 0;
data->offset = 0;
data->bmap = NULL;
data->patch_file = strdup(patch_file);
data->patch_fd = open(data->patch_file, flags|O_RDWR, 0666);
if (data->patch_fd < 0)
return errno;
size = ext2fs_llseek(data->patch_fd, 0, SEEK_END);
if (size < 0)
return errno;
if (size > 0)
{
size = ext2fs_llseek(data->patch_fd, 0, SEEK_SET);
read(data->patch_fd, &s, sizeof(struct patchbd_super));
if (s.magic != PATCHBD_MAGIC)
return 0;
data->block_size = s.patch_block;
// if (data->block_size != 4096)
// return EINVAL;
data->size = s.patch_size;
retval = ext2fs_patch_init_bmap(data, NULL);
if (retval)
return retval;
retval = ext2fs_patch_read_bmap(data);
}
return 0;
}
errcode_t ext2fs_patch_close(struct ext2fs_patch_file *data)
{
if (data)
{
if (data->bmap)
{
if (data->patch_fd >= 0)
ext2fs_patch_write_bmap(data);
ext2fs_free_generic_bmap(data->bmap);
data->bmap = NULL;
}
if (data->patch_fd >= 0)
{
close(data->patch_fd);
data->patch_fd = -1;
}
if (data->patch_file)
{
free(data->patch_file);
data->patch_file = NULL;
}
}
return 0;
}
errcode_t ext2fs_patch_init_bmap(struct ext2fs_patch_file *data, io_channel channel)
{
errcode_t retval = 0;
if (!data->bmap)
{
if (channel)
{
// channel is optional parameter, if passed, means 'take size from channel'
data->block_size = channel->block_size;
// if (data->block_size != 4096)
// return EINVAL;
retval = ext2fs_get_device_size2(channel->name, data->block_size, &data->size);
if (retval)
return retval;
}
else if (!data->block_size || !data->size)
return EINVAL;
retval = ext2fs_make_generic_bitmap(EXT2_ET_MAGIC_BLOCK_BITMAP, NULL,
0, data->size, data->size, "overwritten blocks", 0, &data->bmap);
data->offset = data->block_size + ((((data->size+7)>>3)+(data->block_size-1))&~(data->block_size-1));
}
return retval;
}
errcode_t ext2fs_patch_write_blk64(struct ext2fs_patch_file *data, unsigned long long block, int count, const void *buf)
{
ssize_t size;
if (!data->bmap)
return EINVAL;
if (count < 0)
{
if ((unsigned)-count > data->block_size)
return EINVAL;
size = -count;
count = 1;
}
else
size = count*data->block_size;
ext2fs_mark_block_bitmap_range2(data->bmap, block, count);
return ext2fs_patch_retry_write_at(data->patch_fd, data->offset + block*data->block_size, size, buf);
}

64
lib/ext2fs/patch.h Normal file
View File

@ -0,0 +1,64 @@
/**
* patch.h --- Common "patch" file functions
*
* Patch file format:
* 1) sparse data blocks - same size as the patched filesystem, but only changed blocks are written
* 2) updated block bitmap - fs_size/block_size/8 bytes
* 3) 4 byte FS block size
* 4) 8 byte FS size in blocks
*
* Copyright (c) Vitaliy Filippov <vitalif@mail.ru> 2014
* License: GNU GPLv2 or later
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef E2_PATCH_H
#define E2_PATCH_H
#include "ext2_fs.h"
#include "ext2fs.h"
#define PATCHBD_MAGIC 0x44623950 // P9bD
struct ext2fs_patch_file
{
char *patch_file;
int patch_fd;
__u32 block_size;
blk64_t size;
ext2_loff_t offset;
ext2fs_generic_bitmap bmap;
};
struct patchbd_super
{
__u32 magic;
__u32 patch_block;
__u64 patch_size;
};
errcode_t ext2fs_patch_retry_read(int fd, ssize_t size, void *buf);
errcode_t ext2fs_patch_retry_write(int fd, ssize_t size, const void *buf);
errcode_t ext2fs_patch_retry_read_at(int fd, unsigned long long offset, ssize_t size, void *buf);
errcode_t ext2fs_patch_retry_write_at(int fd, unsigned long long offset, ssize_t size, const void *buf);
errcode_t ext2fs_patch_read_bmap(struct ext2fs_patch_file *data);
errcode_t ext2fs_patch_write_bmap(struct ext2fs_patch_file *data);
errcode_t ext2fs_patch_open(struct ext2fs_patch_file *data, char *patch_file, int flags);
errcode_t ext2fs_patch_close(struct ext2fs_patch_file *data);
errcode_t ext2fs_patch_init_bmap(struct ext2fs_patch_file *data, io_channel channel);
errcode_t ext2fs_patch_write_blk64(struct ext2fs_patch_file *data, unsigned long long block, int count, const void *buf);
#endif

375
lib/ext2fs/patch_io.c Normal file
View File

@ -0,0 +1,375 @@
/*
* patch_io.c --- This is the "patch" io manager that writes the new data into
* a separate sparse file to apply it later.
*
* Copyright (c) Vitaliy Filippov <vitalif@mail.ru> 2014
* License: GNU GPLv2 or later
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define _LARGEFILE_SOURCE
#define _LARGEFILE64_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include "ext2_fs.h"
#include "ext2fs.h"
#include "patch.h"
#ifdef __GNUC__
#define ATTR(x) __attribute__(x)
#else
#define ATTR(x)
#endif
#define EXT2_CHECK_MAGIC(struct, code) if ((struct)->magic != (code)) return (code)
struct patch_private_data
{
int magic;
struct ext2fs_patch_file patch;
/* The backing io channel */
io_channel real;
/* to support offset in unix I/O manager */
ext2_loff_t offset;
};
static errcode_t patch_open(const char *name, int flags, io_channel *channel);
static errcode_t patch_close(io_channel channel);
static errcode_t patch_set_blksize(io_channel channel, int blksize);
static errcode_t patch_read_blk64(io_channel channel, unsigned long long block, int count, void *data);
static errcode_t patch_write_blk64(io_channel channel, unsigned long long block, int count, const void *data);
static errcode_t patch_read_blk(io_channel channel, unsigned long block, int count, void *data);
static errcode_t patch_write_blk(io_channel channel, unsigned long block, int count, const void *data);
static errcode_t patch_flush(io_channel channel);
static errcode_t patch_write_byte(io_channel channel, unsigned long offset, int size, const void *data);
static errcode_t patch_set_option(io_channel channel, const char *option, const char *arg);
static errcode_t patch_get_stats(io_channel channel, io_stats *stats);
static struct struct_io_manager struct_patch_manager = {
EXT2_ET_MAGIC_IO_MANAGER,
"Patch I/O Manager",
patch_open,
patch_close,
patch_set_blksize,
patch_read_blk,
patch_write_blk,
patch_flush,
patch_write_byte,
patch_set_option,
patch_get_stats,
patch_read_blk64,
patch_write_blk64,
};
io_manager patch_io_manager = &struct_patch_manager;
static char *patch_file;
static io_manager patch_io_backing_manager;
errcode_t set_patch_io_backing_manager(io_manager manager)
{
patch_io_backing_manager = manager;
return 0;
}
errcode_t set_patch_io_patch_file(char *file)
{
patch_file = file;
return 0;
}
static errcode_t patch_open(const char *name, int flags, io_channel *channel)
{
io_channel io = NULL;
struct patch_private_data *data = NULL;
errcode_t retval;
if (name == 0)
return EXT2_ET_BAD_DEVICE_NAME;
retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
if (retval)
goto cleanup;
memset(io, 0, sizeof(struct struct_io_channel));
io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
retval = ext2fs_get_mem(sizeof(struct patch_private_data), &data);
if (retval)
goto cleanup;
io->manager = patch_io_manager;
retval = ext2fs_get_mem(strlen(name)+1, &io->name);
if (retval)
goto cleanup;
strcpy(io->name, name);
io->private_data = data;
io->block_size = 1024;
io->read_error = 0;
io->write_error = 0;
io->refcount = 1;
memset(data, 0, sizeof(struct patch_private_data));
data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL;
if (patch_io_backing_manager)
{
retval = patch_io_backing_manager->open(name, flags & ~IO_FLAG_RW, &data->real);
if (retval)
goto cleanup;
}
if (patch_file)
{
retval = ext2fs_patch_open(&data->patch, patch_file, O_CREAT);
if (retval)
goto cleanup;
if (data->patch.block_size)
{
retval = io_channel_set_blksize(data->real, data->patch.block_size);
if (retval)
goto cleanup;
}
}
*channel = io;
return 0;
cleanup:
if (data)
{
ext2fs_patch_close(&data->patch);
if (data->real)
io_channel_close(data->real);
ext2fs_free_mem(&data);
}
if (io)
{
if (io->name)
ext2fs_free_mem(&io->name);
ext2fs_free_mem(&io);
}
return retval;
}
static errcode_t patch_close(io_channel channel)
{
struct patch_private_data *data;
errcode_t retval = 0;
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
data = (struct patch_private_data *) channel->private_data;
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
if (--channel->refcount > 0)
return 0;
ext2fs_patch_close(&data->patch);
if (data->real)
retval = io_channel_close(data->real);
ext2fs_free_mem(&channel->private_data);
if (channel->name)
ext2fs_free_mem(&channel->name);
ext2fs_free_mem(&channel);
return retval;
}
static errcode_t patch_set_blksize(io_channel channel, int blksize)
{
struct patch_private_data *data;
errcode_t retval = 0;
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
data = (struct patch_private_data *) channel->private_data;
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
channel->block_size = (unsigned)blksize;
if (data->patch.block_size && data->patch.block_size != (unsigned)blksize)
return EINVAL;
if (data->real)
retval = io_channel_set_blksize(data->real, blksize);
return retval;
}
static errcode_t patch_read_blk64(io_channel channel, unsigned long long block, int count, void *buf)
{
errcode_t retval = 0;
struct patch_private_data *data;
int b, n;
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
data = (struct patch_private_data *) channel->private_data;
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
if (count < 0)
{
if (-count <= channel->block_size)
{
if (data->patch.bmap && ext2fs_test_generic_bitmap(data->patch.bmap, block))
retval = ext2fs_patch_retry_read_at(data->patch.patch_fd, data->patch.offset + block*channel->block_size, -count, buf);
else
retval = io_channel_read_blk64(data->real, block, count, buf);
return retval;
}
else
return EINVAL;
}
for (b = 0; b < count; )
{
for (n = 0; (b+n < count) && data->patch.bmap && ext2fs_test_generic_bitmap(data->patch.bmap, block+b+n); n++) {}
if (n > 0)
{
retval = ext2fs_patch_retry_read_at(data->patch.patch_fd, data->patch.offset + (block+b)*channel->block_size, n*channel->block_size, buf+b*channel->block_size);
if (retval)
break;
b += n;
}
for (n = 0; (b+n < count) && (!data->patch.bmap || !ext2fs_test_generic_bitmap(data->patch.bmap, block+b+n)); n++) {}
if (n > 0)
{
retval = io_channel_read_blk64(data->real, block+b, n, buf+b*channel->block_size);
if (retval)
break;
b += n;
}
}
return retval;
}
static errcode_t patch_read_blk(io_channel channel, unsigned long block, int count, void *buf)
{
return patch_read_blk64(channel, block, count, buf);
}
static errcode_t patch_write_blk64(io_channel channel, unsigned long long block, int count, const void *buf)
{
struct patch_private_data *data;
errcode_t retval = 0;
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
data = (struct patch_private_data *) channel->private_data;
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
retval = ext2fs_patch_init_bmap(&data->patch, channel);
if (retval)
return retval;
// libext2fs changes block size to 1024 in order to write the superblock, so we must support it...
if ((__u32)channel->block_size < data->patch.block_size)
{
void *buf2 = NULL;
unsigned long long block_real = block / (data->patch.block_size / channel->block_size);
int count_real = ( (block % (data->patch.block_size / channel->block_size))
+ (count > 0 ? count*channel->block_size : -count)
+ data->patch.block_size - 1 ) / data->patch.block_size;
retval = ext2fs_get_mem(count_real * data->patch.block_size, &buf2);
if (retval)
goto out;
retval = patch_read_blk64(channel, block_real, count_real, buf2);
if (retval)
goto out;
memcpy(buf2 + (block % (data->patch.block_size / channel->block_size)) * channel->block_size,
buf, (count > 0 ? count*channel->block_size : -count));
retval = ext2fs_patch_write_blk64(&data->patch, block_real, count_real, buf2);
out:
if (buf2)
ext2fs_free_mem(&buf2);
return retval;
}
else if ((__u32)channel->block_size > data->patch.block_size)
{
return EXT2_ET_UNIMPLEMENTED;
}
return ext2fs_patch_write_blk64(&data->patch, block, count, buf);
}
static errcode_t patch_write_blk(io_channel channel, unsigned long block, int count, const void *buf)
{
return patch_write_blk64(channel, block, count, buf);
}
static errcode_t patch_write_byte(io_channel channel, unsigned long offset, int size, const void *buf)
{
return EXT2_ET_UNIMPLEMENTED;
}
/*
* Flush data buffers to disk.
*/
static errcode_t patch_flush(io_channel channel)
{
errcode_t retval = 0;
struct patch_private_data *data;
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
data = (struct patch_private_data *) channel->private_data;
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
if (data->real)
retval = io_channel_flush(data->real);
if (data->patch.patch_fd)
fsync(data->patch.patch_fd);
return retval;
}
static errcode_t patch_set_option(io_channel channel, const char *option, const char *arg)
{
errcode_t retval = 0;
struct patch_private_data *data;
unsigned long tmp;
char *end;
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
data = (struct patch_private_data *) channel->private_data;
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
/*
* Need to support offset option to work with
* Unix I/O manager
*/
if (data->real && data->real->manager->set_option)
retval = data->real->manager->set_option(data->real, option, arg);
if (!retval && !strcmp(option, "offset"))
{
if (!arg)
return EXT2_ET_INVALID_ARGUMENT;
tmp = strtoul(arg, &end, 0);
if (*end)
return EXT2_ET_INVALID_ARGUMENT;
data->offset = tmp;
}
return retval;
}
static errcode_t patch_get_stats(io_channel channel, io_stats *stats)
{
errcode_t retval = 0;
struct patch_private_data *data;
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
data = (struct patch_private_data *) channel->private_data;
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
if (data->real)
retval = (data->real->manager->get_stats)(data->real, stats);
return retval;
}

View File

@ -307,6 +307,8 @@ void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
/* this is error case: i_extra_size is too large */
return;
}
if (extra_isize & 3)
return; /* Illegal inode extra_isize */
inode_size = EXT2_GOOD_OLD_INODE_SIZE + extra_isize;
if (inode_includes(inode_size, i_checksum_hi))

View File

@ -300,6 +300,7 @@ static errcode_t raw_write_blk(io_channel channel,
goto short_write;
size -= actual;
buf += actual;
location += actual;
}
return 0;

View File

@ -33,12 +33,12 @@ INSTALL = @INSTALL@
@FUSE_CMT@FUSE_PROG= fuse2fs
SPROGS= mke2fs badblocks tune2fs dumpe2fs $(BLKID_PROG) logsave \
$(E2IMAGE_PROG) @FSCK_PROG@ e2undo
$(E2IMAGE_PROG) @FSCK_PROG@ e2undo e2patch
USPROGS= mklost+found filefrag e2freefrag $(UUIDD_PROG) \
$(E4DEFRAG_PROG) $(E4CRYPT_PROG) $(FUSE_PROG)
SMANPAGES= tune2fs.8 mklost+found.8 mke2fs.8 dumpe2fs.8 badblocks.8 \
e2label.8 $(FINDFS_MAN) $(BLKID_MAN) $(E2IMAGE_MAN) \
logsave.8 filefrag.8 e2freefrag.8 e2undo.8 \
logsave.8 filefrag.8 e2freefrag.8 e2undo.8 e2patch.8 \
$(UUIDD_MAN) $(E4DEFRAG_MAN) $(E4CRYPT_MAN) @FSCK_MAN@
FMANPAGES= mke2fs.conf.5 ext4.5
@ -63,6 +63,7 @@ FSCK_OBJS= fsck.o base_device.o ismounted.o
BLKID_OBJS= blkid.o
FILEFRAG_OBJS= filefrag.o
E2UNDO_OBJS= e2undo.o
E2PATCH_OBJS= e2patch.o
E4DEFRAG_OBJS= e4defrag.o
E4CRYPT_OBJS= e4crypt.o
E2FREEFRAG_OBJS= e2freefrag.o
@ -88,6 +89,7 @@ PROFILED_BLKID_OBJS= profiled/blkid.o
PROFILED_FILEFRAG_OBJS= profiled/filefrag.o
PROFILED_E2FREEFRAG_OBJS= profiled/e2freefrag.o
PROFILED_E2UNDO_OBJS= profiled/e2undo.o
PROFILED_E2PATCH_OBJS= profiled/e2patch.o
PROFILED_E4DEFRAG_OBJS= profiled/e4defrag.o
PROFILED_E4CRYPT_OBJS= profiled/e4crypt.o
PROFILED_FUSE2FS_OJBS= profiled/fuse2fs.o profiled/journal.o \
@ -98,7 +100,7 @@ SRCS= $(srcdir)/tune2fs.c $(srcdir)/mklost+found.c $(srcdir)/mke2fs.c $(srcdir)/
$(srcdir)/badblocks.c $(srcdir)/fsck.c $(srcdir)/util.c \
$(srcdir)/uuidgen.c $(srcdir)/blkid.c $(srcdir)/logsave.c \
$(srcdir)/filefrag.c $(srcdir)/base_device.c \
$(srcdir)/ismounted.c $(srcdir)/e2undo.c \
$(srcdir)/ismounted.c $(srcdir)/e2undo.c $(srcdir)/e2patch.c \
$(srcdir)/e2freefrag.c $(srcdir)/create_inode.c \
$(srcdir)/fuse2fs.c \
$(srcdir)/../debugfs/journal.c $(srcdir)/../e2fsck/revoke.c \
@ -133,7 +135,7 @@ all:: profiled $(SPROGS) $(UPROGS) $(USPROGS) $(SMANPAGES) $(UMANPAGES) \
$(FMANPAGES) $(LPROGS) $(E4DEFRAG_PROG) $(E4CRYPT_PROGS) e2fuzz
@PROFILE_CMT@all:: tune2fs.profiled blkid.profiled e2image.profiled \
e2undo.profiled mke2fs.profiled dumpe2fs.profiled fsck.profiled \
e2undo.profiled e2patch.profiled mke2fs.profiled dumpe2fs.profiled fsck.profiled \
logsave.profiled filefrag.profiled uuidgen.profiled $(UUIDD_PROFILED) \
e2image.profiled e4defrag.profiled e4crypt.profiled \
e2freefrag.profiled
@ -226,6 +228,16 @@ e2undo.profiled: $(E2UNDO_OBJS) $(PROFILED_DEPLIBS)
$(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o e2undo.profiled \
$(PROFILED_E2UNDO_OBJS) $(PROFILED_LIBS) $(LIBINTL) $(SYSLIBS)
e2patch: $(E2PATCH_OBJS) $(DEPLIBS)
$(E) " LD $@"
$(Q) $(CC) $(ALL_LDFLAGS) -o e2patch $(E2PATCH_OBJS) $(LIBS) \
$(LIBINTL) $(SYSLIBS)
e2patch.profiled: $(E2PATCH_OBJS) $(PROFILED_DEPLIBS)
$(E) " LD $@"
$(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o e2patch.profiled \
$(PROFILED_E2PATCH_OBJS) $(PROFILED_LIBS) $(LIBINTL) $(SYSLIBS)
e4defrag: $(E4DEFRAG_OBJS) $(DEPLIBS)
$(E) " LD $@"
$(Q) $(CC) $(ALL_LDFLAGS) -o e4defrag $(E4DEFRAG_OBJS) $(LIBS) \
@ -439,6 +451,10 @@ e2undo.8: $(DEP_SUBSTITUTE) $(srcdir)/e2undo.8.in
$(E) " SUBST $@"
$(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/e2undo.8.in e2undo.8
e2patch.8: $(DEP_SUBSTITUTE) $(srcdir)/e2patch.8.in
$(E) " SUBST $@"
$(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/e2patch.8.in e2patch.8
findfs.8: $(DEP_SUBSTITUTE) $(srcdir)/findfs.8.in
$(E) " SUBST $@"
$(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/findfs.8.in findfs.8
@ -669,7 +685,7 @@ clean::
e2initrd_helper partinfo prof_err.[ch] default_profile.c \
uuidd e2image tune2fs.static tst_ismounted fsck.profiled \
blkid.profiled tune2fs.profiled e2image.profiled \
e2undo.profiled mke2fs.profiled dumpe2fs.profiled \
e2undo.profiled e2patch.profiled mke2fs.profiled dumpe2fs.profiled \
logsave.profiled filefrag.profiled uuidgen.profiled \
uuidd.profiled e2image.profiled e2fuzz mke2fs.conf \
profiled/*.o \#* *.s *.o *.a *~ core gmon.out
@ -792,6 +808,12 @@ e2undo.o: $(srcdir)/e2undo.c $(top_builddir)/lib/config.h \
$(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
$(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
$(top_srcdir)/lib/support/nls-enable.h
e2patch.o: $(srcdir)/e2patch.c $(top_builddir)/lib/config.h \
$(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
$(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
$(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
$(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
$(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h
e2freefrag.o: $(srcdir)/e2freefrag.c $(top_builddir)/lib/config.h \
$(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
$(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2fs.h \

31
misc/e2patch.8.in Normal file
View File

@ -0,0 +1,31 @@
.TH E2PATCH 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
.SH NAME
e2patch \- patch tool for safely applying libext2fs patch files to block devices
.SH SYNOPSIS
.B e2patch backup \fI<device>\fR \fI<patch_file>\fR \fI<backup_file>\fR
.br
.B e2patch apply \fI<device>\fR \fI<patch_file>\fR
.SH DESCRIPTION
.B e2patch
applies and restores "patches" produced by e2fsprogs with patch file option
(\fBresize2fs -T <patch_file>\fR) to block devices.
.PP
"Patch files" are sparse files containing overwritten device blocks and
a block bitmap.
.PP
"Patch files" are faster, safer and simpler to use than "undo files"
(\fBe2undo\fR and \fBresize2fs -z <undo_file>\fR), even though their original
design goal is similar.
.SH COMMANDS
.TP
.B e2patch backup \fI<device>\fR \fI<patch_file>\fR \fI<backup_file>\fR
Creates a backup in <backup_file> for restoring after bad patch <patch_file>.
Backup can then also be applied with \fBe2patch apply\fR
.TP
.B e2patch apply \fI<device>\fR \fI<patch_file>\fR
Apply <patch_file> to <device>.
.SH AUTHOR
Written by Vitaliy Filippov <vitalif@mail.ru>
.SH SEE ALSO
.BR resize2fs (8),
.BR e2undo (8).

166
misc/e2patch.c Normal file
View File

@ -0,0 +1,166 @@
/**
* e2patch.c --- Utility to apply/restore patches created by patch_io_manager.
*
* Copyright (c) Vitaliy Filippov <vitalif@mail.ru> 2014
* License: GNU GPLv2 or later
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <errno.h>
#include "ext2fs/ext2_fs.h"
#include "ext2fs/ext2fs.h"
#include "ext2fs/patch.h"
#define BUF 0x10000
#define _(a) (a)
errcode_t make_backup_patch(char *device, char *io_options, char *patch_file, char *backup_file)
{
io_manager mgr = unix_io_manager;
io_channel io;
errcode_t retval;
blk64_t blk, start, buf_blocks;
int eq;
void *buf = NULL;
struct ext2fs_patch_file patch = { 0 }, backup = { 0 };
retval = mgr->open(device, IO_FLAG_EXCLUSIVE, &io);
if (retval) goto out;
if (io_options &&
(retval = io_channel_set_options(io, io_options)))
goto out;
retval = ext2fs_patch_open(&patch, patch_file, 0);
if (retval) goto out;
retval = ext2fs_patch_open(&backup, backup_file, O_CREAT);
if (retval) goto out;
backup.block_size = patch.block_size;
backup.size = patch.size;
ext2fs_patch_init_bmap(&backup, NULL);
buf_blocks = BUF/patch.block_size;
retval = mgr->set_blksize(io, patch.block_size);
if (retval) goto out;
buf = malloc(BUF);
for (start = 0, blk = 0; blk <= patch.size; blk++)
{
if ((eq = !ext2fs_test_generic_bitmap(patch.bmap, blk)) || blk >= patch.size || blk-start >= buf_blocks)
{
if (start != blk)
{
retval = io_channel_read_blk64(io, start, blk-start, buf);
if (retval) goto out;
retval = ext2fs_patch_write_blk64(&backup, start, blk-start, buf);
if (retval) goto out;
}
start = blk+eq;
}
}
out:
if (buf)
free(buf);
ext2fs_patch_close(&backup);
ext2fs_patch_close(&patch);
mgr->close(io);
return retval;
}
errcode_t apply_patch(char *device, char *io_options, char *patch_file)
{
io_manager mgr = unix_io_manager;
io_channel io;
errcode_t retval;
blk64_t blk, start, buf_blocks;
int eq;
void *buf = NULL;
struct ext2fs_patch_file patch = { 0 };
retval = mgr->open(device, IO_FLAG_EXCLUSIVE|IO_FLAG_RW, &io);
if (retval) goto out;
if (io_options &&
(retval = io_channel_set_options(io, io_options)))
goto out;
retval = ext2fs_patch_open(&patch, patch_file, 0);
if (retval) goto out;
buf_blocks = BUF/patch.block_size;
retval = mgr->set_blksize(io, patch.block_size);
if (retval) goto out;
buf = malloc(BUF);
for (start = 0, blk = 0; blk <= patch.size; blk++)
{
if ((eq = blk < patch.size && !ext2fs_test_generic_bitmap(patch.bmap, blk)) || blk >= patch.size || blk-start >= buf_blocks)
{
if (start != blk)
{
retval = ext2fs_patch_retry_read_at(patch.patch_fd, patch.offset + start*patch.block_size, (blk-start)*patch.block_size, buf);
if (retval) goto out;
retval = io_channel_write_blk64(io, start, blk-start, buf);
if (retval) goto out;
}
start = blk+eq;
}
}
out:
if (buf)
free(buf);
ext2fs_patch_close(&patch);
mgr->close(io);
return retval;
}
int main(int narg, char **args)
{
errcode_t retval;
char *io_options = NULL;
if (narg >= 5 && !strcmp(args[1], "backup"))
{
io_options = strchr(args[2], '?');
if (io_options)
*io_options++ = 0;
retval = make_backup_patch(args[2], io_options, args[3], args[4]);
}
else if (narg >= 4 && !strcmp(args[1], "apply"))
{
io_options = strchr(args[2], '?');
if (io_options)
*io_options++ = 0;
retval = apply_patch(args[2], io_options, args[3]);
}
else
{
printf(
"Patch tool for safely applying changes to block devices\n"
"License: GNU GPLv2 or later\n"
"Copyright (c) Vitaliy Filippov, 2014\n\n"
"To create a backup for restoring after bad patch:\n"
" e2patch backup <filesystem> <patch_file> <backup_file>\n"
"To apply a patch:\n"
" e2patch apply <filesystem> <patch_file>\n"
);
return 0;
}
if (retval)
{
com_err("e2patch", retval, _("while trying to %s"), args[1]);
}
return 0;
}

View File

@ -474,6 +474,10 @@ static int frag_report(const char *filename)
}
if (force_bmap || rc < 0) { /* FIEMAP failed, try FIBMAP instead */
if (numblocks > (unsigned long)-1L) {
fprintf(stderr, "%s: File too big to use FIBMAP\n", filename);
goto out_close;
}
expected = filefrag_fibmap(fd, blk_shift, &num_extents,
&st, numblocks, is_ext2);
if (expected < 0) {

View File

@ -43,6 +43,7 @@ misc/e2image.c
misc/e2initrd_helper.c
misc/e2label.c
misc/e2undo.c
misc/e2patch.c
misc/e4crypt.c
misc/e4defrag.c
misc/filefrag.c

BIN
po/ca.gmo

Binary file not shown.

4399
po/ca.po

File diff suppressed because it is too large Load Diff

BIN
po/cs.gmo

Binary file not shown.

683
po/cs.po

File diff suppressed because it is too large Load Diff

BIN
po/da.gmo

Binary file not shown.

1065
po/da.po

File diff suppressed because it is too large Load Diff

BIN
po/de.gmo

Binary file not shown.

4222
po/de.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

BIN
po/eo.gmo

Binary file not shown.

679
po/eo.po

File diff suppressed because it is too large Load Diff

BIN
po/es.gmo

Binary file not shown.

683
po/es.po

File diff suppressed because it is too large Load Diff

BIN
po/fr.gmo

Binary file not shown.

1504
po/fr.po

File diff suppressed because it is too large Load Diff

BIN
po/hu.gmo

Binary file not shown.

1452
po/hu.po

File diff suppressed because it is too large Load Diff

BIN
po/id.gmo

Binary file not shown.

683
po/id.po

File diff suppressed because it is too large Load Diff

BIN
po/it.gmo

Binary file not shown.

683
po/it.po

File diff suppressed because it is too large Load Diff

BIN
po/nl.gmo

Binary file not shown.

1325
po/nl.po

File diff suppressed because it is too large Load Diff

BIN
po/pl.gmo

Binary file not shown.

1196
po/pl.po

File diff suppressed because it is too large Load Diff

BIN
po/sr.gmo

Binary file not shown.

4220
po/sr.po

File diff suppressed because it is too large Load Diff

BIN
po/sv.gmo

Binary file not shown.

1173
po/sv.po

File diff suppressed because it is too large Load Diff

BIN
po/tr.gmo

Binary file not shown.

683
po/tr.po

File diff suppressed because it is too large Load Diff

BIN
po/uk.gmo

Binary file not shown.

1565
po/uk.po

File diff suppressed because it is too large Load Diff

BIN
po/vi.gmo

Binary file not shown.

683
po/vi.po

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -46,8 +46,8 @@ static char *device_name, *io_options;
static void usage (char *prog)
{
fprintf (stderr, _("Usage: %s [-d debug_flags] [-f] [-F] [-M] [-P] "
"[-p] device [-b|-s|new_size] [-z undo_file]\n\n"),
fprintf (stderr, _("Usage: %s [-d debug_flags] [-f] [-F] [-M] [-N new_inodes] [-P] "
"[-p] device [-b|-s|new_size] [-T patch_file] [-z undo_file]\n\n"),
prog);
exit (1);
@ -167,6 +167,20 @@ static void bigalloc_check(ext2_filsys fs, int force)
}
}
static int resize2fs_setup_patch(const char *device, char *patch_file,
io_manager *io_ptr)
{
set_patch_io_backing_manager(*io_ptr);
set_patch_io_patch_file(patch_file);
*io_ptr = patch_io_manager;
printf(_("To make backup before applying changes run:\n"
" e2patch backup %s %s %s.backup\n"
"Then, to apply the operation to the real filesystem run:\n"
" e2patch apply %s %s\n"),
device, patch_file, patch_file, device, patch_file);
return 0;
}
static int resize2fs_setup_tdb(const char *device, char *undo_file,
io_manager *io_ptr)
{
@ -258,6 +272,7 @@ int main (int argc, char ** argv)
blk64_t new_size = 0;
blk64_t max_size = 0;
blk64_t min_size = 0;
__u32 new_inodes = 0;
io_manager io_ptr;
char *new_size_str = 0;
int use_stride = -1;
@ -267,7 +282,7 @@ int main (int argc, char ** argv)
unsigned int blocksize;
long sysval;
int len, mount_flags;
char *mtpt, *undo_file = NULL;
char *mtpt, *undo_file = NULL, *patch_file = NULL;
#ifdef ENABLE_NLS
setlocale(LC_MESSAGES, "");
@ -284,7 +299,7 @@ int main (int argc, char ** argv)
if (argc && *argv)
program_name = *argv;
while ((c = getopt(argc, argv, "d:fFhMPpS:bsz:")) != EOF) {
while ((c = getopt(argc, argv, "d:fFhMPN:pS:bsT:z:")) != EOF) {
switch (c) {
case 'h':
usage(program_name);
@ -301,6 +316,9 @@ int main (int argc, char ** argv)
case 'P':
print_min_size = 1;
break;
case 'N':
new_inodes = strtoul(optarg, 0, 0);
break;
case 'd':
flags |= atoi(optarg);
break;
@ -316,6 +334,9 @@ int main (int argc, char ** argv)
case 's':
flags |= RESIZE_DISABLE_64BIT;
break;
case 'T':
patch_file = optarg;
break;
case 'z':
undo_file = optarg;
break;
@ -402,7 +423,11 @@ int main (int argc, char ** argv)
io_flags = EXT2_FLAG_RW | EXT2_FLAG_EXCLUSIVE;
io_flags |= EXT2_FLAG_64BITS;
if (undo_file) {
if (patch_file) {
retval = resize2fs_setup_patch(device_name, patch_file, &io_ptr);
if (retval)
exit(1);
} else if (undo_file) {
retval = resize2fs_setup_tdb(device_name, undo_file, &io_ptr);
if (retval)
exit(1);
@ -583,7 +608,7 @@ int main (int argc, char ** argv)
"feature.\n"));
exit(1);
}
} else if (new_size == ext2fs_blocks_count(fs->super)) {
} else if (new_size == ext2fs_blocks_count(fs->super) && !new_inodes) {
fprintf(stderr, _("The filesystem is already %llu (%dk) "
"blocks long. Nothing to do!\n\n"), new_size,
blocksize / 1024);
@ -612,7 +637,7 @@ int main (int argc, char ** argv)
printf(_("Resizing the filesystem on "
"%s to %llu (%dk) blocks.\n"),
device_name, new_size, blocksize / 1024);
retval = resize_fs(fs, &new_size, flags,
retval = resize_fs(fs, &new_size, new_inodes, flags,
((flags & RESIZE_PERCENT_COMPLETE) ?
resize_progress_func : 0));
}

View File

@ -159,6 +159,12 @@ program will heuristically determine the RAID stride that was specified
when the filesystem was created. This option allows the user to
explicitly specify a RAID stride setting to be used by resize2fs instead.
.TP
.BI \-T " patch_file"
Do not apply changes to the real filesystem; write updates into a sparse file
named 'patch_file' to safely apply them later with e2patch(8) utility.
You'll also be able to create a backup before applying patch and safely
restore it in case of power outage or system crash.
.TP
.BI \-z " undo_file"
Before overwriting a file system block, write the old contents of the block to
an undo file. This undo file can be used with e2undo(8) to restore the old

View File

@ -45,19 +45,21 @@ static void fix_uninit_block_bitmaps(ext2_filsys fs);
static errcode_t adjust_superblock(ext2_resize_t rfs, blk64_t new_size);
static errcode_t blocks_to_move(ext2_resize_t rfs);
static errcode_t block_mover(ext2_resize_t rfs);
static errcode_t inodes_to_move(ext2_resize_t rfs);
static errcode_t inode_scan_and_fix(ext2_resize_t rfs);
static errcode_t inode_ref_fix(ext2_resize_t rfs);
static errcode_t move_itables(ext2_resize_t rfs);
static errcode_t move_inode_tables(ext2_resize_t rfs);
static errcode_t fix_resize_inode(ext2_filsys fs);
static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs);
static errcode_t fix_sb_journal_backup(ext2_filsys fs);
static errcode_t mark_table_blocks(ext2_filsys fs,
ext2fs_block_bitmap bmap);
ext2fs_block_bitmap bmap, int skip_inode_tables);
static errcode_t clear_sparse_super2_last_group(ext2_resize_t rfs);
static errcode_t reserve_sparse_super2_last_group(ext2_resize_t rfs,
ext2fs_block_bitmap meta_bmap);
static errcode_t resize_group_descriptors(ext2_resize_t rfs, blk64_t new_size);
static errcode_t move_bg_metadata(ext2_resize_t rfs);
static errcode_t move_bg_metadata(ext2_resize_t rfs, __u32 new_inodes);
static errcode_t zero_high_bits_in_inodes(ext2_resize_t rfs);
/*
@ -94,7 +96,7 @@ static int lazy_itable_init;
/*
* This is the top-level routine which does the dirty deed....
*/
errcode_t resize_fs(ext2_filsys fs, blk64_t *new_size, int flags,
errcode_t resize_fs(ext2_filsys fs, blk64_t *new_size, __u32 new_inodes, int flags,
errcode_t (*progress)(ext2_resize_t rfs, int pass,
unsigned long cur,
unsigned long max_val))
@ -142,7 +144,7 @@ errcode_t resize_fs(ext2_filsys fs, blk64_t *new_size, int flags,
print_resource_track(rfs, &rtrack, fs->io);
init_resource_track(&rtrack, "move_bg_metadata", fs->io);
retval = move_bg_metadata(rfs);
retval = move_bg_metadata(rfs, new_inodes);
if (retval)
goto errout;
print_resource_track(rfs, &rtrack, fs->io);
@ -188,6 +190,18 @@ errcode_t resize_fs(ext2_filsys fs, blk64_t *new_size, int flags,
goto errout;
print_resource_track(rfs, &rtrack, fs->io);
init_resource_track(&rtrack, "inodes_to_move", fs->io);
retval = inodes_to_move(rfs);
if (retval)
goto errout;
print_resource_track(rfs, &rtrack, fs->io);
init_resource_track(&rtrack, "move_inode_tables", fs->io);
retval = move_inode_tables(rfs);
if (retval)
goto errout;
print_resource_track(rfs, &rtrack, fs->io);
init_resource_track(&rtrack, "inode_scan_and_fix", fs->io);
retval = inode_scan_and_fix(rfs);
if (retval)
@ -200,11 +214,11 @@ errcode_t resize_fs(ext2_filsys fs, blk64_t *new_size, int flags,
goto errout;
print_resource_track(rfs, &rtrack, fs->io);
init_resource_track(&rtrack, "move_itables", fs->io);
/* init_resource_track(&rtrack, "move_itables", fs->io);
retval = move_itables(rfs);
if (retval)
goto errout;
print_resource_track(rfs, &rtrack, fs->io);
print_resource_track(rfs, &rtrack, fs->io);*/
retval = clear_sparse_super2_last_group(rfs);
if (retval)
@ -344,8 +358,39 @@ static errcode_t resize_group_descriptors(ext2_resize_t rfs, blk64_t new_size)
return 0;
}
/**
* Inode table resizing:
* 1) move_bg_metadata(), calls set_inode_count(): set new inode count
* 2) adjust_superblock(): extend bitmaps, write group descriptors
* 3) blocks_to_move(): allocate new inode tables and, when extending inode tables,
* mark extra blocks needed for new inode tables as 'blocks to move'
* 4) block_mover(): move blocks out of the way as usual
* 5) inodes_to_move(): when shrinking inode tables, move inodes from the end
* of each group's inode table (still operating on old fs inode tables).
* it would be possible to rewrite blocks on step 7, but we need to read
* extents, and they may be overwritten by inode tables on step 6.
* so, rewrite blocks used by inodes here!
* 6) move_inode_tables(): move inode tables
* 7) inode_scan_and_fix(): rewrite all inode, extent, extattr and ACL checksums
* 8) inode_ref_fix(): translate inode numbers (operating on new fs inode tables)
*/
static int set_inode_count(ext2_filsys fs, __u32 new_inodes)
{
__u32 old_ipg = fs->super->s_inodes_per_group;
__u32 new_ipg = ((new_inodes + fs->group_desc_count - 1) / fs->group_desc_count);
new_ipg = (((new_ipg * EXT2_INODE_SIZE(fs->super)) + EXT2_BLOCK_SIZE(fs->super) - 1) / EXT2_BLOCK_SIZE(fs->super))
* EXT2_BLOCK_SIZE(fs->super) / EXT2_INODE_SIZE(fs->super);
if (new_ipg == old_ipg)
return -1;
fs->inode_blocks_per_group = new_ipg * EXT2_INODE_SIZE(fs->super) / EXT2_BLOCK_SIZE(fs->super);
fs->super->s_inodes_per_group = new_ipg;
fs->super->s_inodes_count = fs->group_desc_count * fs->super->s_inodes_per_group;
fs->super->s_free_inodes_count += fs->group_desc_count * (new_ipg - old_ipg);
return 0;
}
/* Move bitmaps/inode tables out of the way. */
static errcode_t move_bg_metadata(ext2_resize_t rfs)
static errcode_t move_bg_metadata(ext2_resize_t rfs, __u32 new_inodes)
{
dgrp_t i;
blk64_t b, c, d, old_desc_blocks, new_desc_blocks, j;
@ -354,7 +399,12 @@ static errcode_t move_bg_metadata(ext2_resize_t rfs)
errcode_t retval;
int cluster_ratio;
if (!(rfs->flags & (RESIZE_DISABLE_64BIT | RESIZE_ENABLE_64BIT)))
if (new_inodes) {
if (set_inode_count(rfs->new_fs, new_inodes) != 0)
new_inodes = 0;
}
if (!new_inodes && !(rfs->flags & (RESIZE_DISABLE_64BIT | RESIZE_ENABLE_64BIT)))
return 0;
retval = ext2fs_allocate_block_bitmap(rfs->old_fs, "oldfs", &old_map);
@ -644,7 +694,7 @@ static errcode_t free_gdp_blocks(ext2_filsys fs,
if (retval)
goto out;
retval = mark_table_blocks(fs, bg_map);
retval = mark_table_blocks(fs, bg_map, 0);
if (retval)
goto out;
}
@ -1011,7 +1061,7 @@ retry:
* number of the block group descriptors.
*/
if (reserve_blocks)
mark_table_blocks(fs, reserve_blocks);
mark_table_blocks(fs, reserve_blocks, 0);
errout:
return (retval);
@ -1145,7 +1195,7 @@ errout:
* filesystem meta-data blocks.
*/
static errcode_t mark_table_blocks(ext2_filsys fs,
ext2fs_block_bitmap bmap)
ext2fs_block_bitmap bmap, int skip_inode_tables)
{
dgrp_t i;
blk64_t blk;
@ -1156,10 +1206,12 @@ static errcode_t mark_table_blocks(ext2_filsys fs,
/*
* Mark the blocks used for the inode table
*/
blk = ext2fs_inode_table_loc(fs, i);
if (blk)
ext2fs_mark_block_bitmap_range2(bmap, blk,
fs->inode_blocks_per_group);
if (!skip_inode_tables) {
blk = ext2fs_inode_table_loc(fs, i);
if (blk)
ext2fs_mark_block_bitmap_range2(bmap, blk,
fs->inode_blocks_per_group);
}
/*
* Mark block used for the block bitmap
@ -1283,12 +1335,69 @@ static errcode_t blocks_to_move(ext2_resize_t rfs)
if (retval)
return retval;
retval = mark_table_blocks(old_fs, meta_bmap);
retval = mark_table_blocks(old_fs, meta_bmap, 0);
if (retval)
return retval;
fs = rfs->new_fs;
/**
* If we're resizing inode tables, we need to reallocate all of them
*/
if (rfs->old_fs->inode_blocks_per_group != fs->inode_blocks_per_group) {
dgrp_t flexbg_size, flex_count, grp_in_flex;
ext2fs_block_bitmap empty_bmap;
/* // this is how mke2fs allocates inode tables...
retval = ext2fs_make_generic_bitmap(EXT2_ET_MAGIC_BLOCK_BITMAP, fs,
fs->super->s_first_data_block,
ext2fs_blocks_count(fs->super)-1,
ext2fs_blocks_count(fs->super)-1, "subcluster inode table bitmap", 0, &empty_bmap);*/
retval = ext2fs_allocate_block_bitmap(fs, _("metadata without inode tables"), &empty_bmap);
if (retval) {
return retval;
}
retval = mark_table_blocks(fs, empty_bmap, 1);
if (retval) {
return retval;
}
if (EXT2_HAS_INCOMPAT_FEATURE(fs->super, EXT4_FEATURE_INCOMPAT_FLEX_BG)
&& fs->super->s_log_groups_per_flex) {
flexbg_size = 1 << fs->super->s_log_groups_per_flex;
} else {
flexbg_size = 1;
}
flex_count = (fs->group_desc_count + flexbg_size - 1) / flexbg_size;
for (g = 0; g < fs->group_desc_count; g++) {
ext2fs_inode_table_loc_set(fs, g, 0);
retval = ext2fs_allocate_group_table(fs, g, empty_bmap);
if (retval) {
return retval;
}
/* ext2fs_mark_block_bitmap_range2(empty_bmap,
ext2fs_inode_table_loc(fs, g), fs->inode_blocks_per_group);*/
group_blk = ext2fs_inode_table_loc(fs, g);
if (g > 0 && group_blk < ext2fs_inode_table_loc(fs, g-1)+fs->inode_blocks_per_group) {
ext2fs_unmark_block_bitmap_range2(fs->block_map, group_blk, fs->inode_blocks_per_group);
group_blk = ext2fs_inode_table_loc(fs, g-1)+fs->inode_blocks_per_group;
ext2fs_inode_table_loc_set(fs, g, group_blk);
ext2fs_group_desc_csum_set(fs, g);
ext2fs_mark_block_bitmap_range2(fs->block_map, group_blk, fs->inode_blocks_per_group);
}
group_blk += fs->inode_blocks_per_group;
// We may need to move some blocks away (mainly if extending inode tables)
for (blk = ext2fs_inode_table_loc(fs, g); blk < group_blk; blk++) {
if (blk < ext2fs_blocks_count(old_fs->super) &&
ext2fs_test_block_bitmap2(old_fs->block_map, blk) &&
!ext2fs_test_block_bitmap2(meta_bmap, blk)) {
ext2fs_mark_block_bitmap2(rfs->move_blocks, blk);
rfs->needed_blocks++;
}
ext2fs_mark_block_bitmap2(rfs->reserve_blocks, blk);
}
}
ext2fs_free_block_bitmap(empty_bmap);
}
/*
* If we're shrinking the filesystem, we need to move any
* group's metadata blocks (either allocation bitmaps or the
@ -1387,7 +1496,7 @@ static errcode_t blocks_to_move(ext2_resize_t rfs)
if (retval)
goto errout;
retval = mark_table_blocks(fs, new_meta_bmap);
retval = mark_table_blocks(fs, new_meta_bmap, 0);
if (retval)
goto errout;
}
@ -1848,7 +1957,7 @@ static int process_block(ext2_filsys fs, blk64_t *block_nr,
}
}
if (pb->is_dir) {
if (pb->is_dir && fs->dblist) {
retval = ext2fs_add_dir_block2(fs->dblist, pb->ino,
block, (int) blockcnt);
if (retval) {
@ -1895,27 +2004,27 @@ static errcode_t migrate_ea_block(ext2_resize_t rfs, ext2_ino_t ino,
errcode_t err = 0;
/* No EA block or no remapping? Quit early. */
if (ext2fs_file_acl_block(rfs->old_fs, inode) == 0 || !rfs->bmap)
if (ext2fs_file_acl_block(rfs->new_fs, inode) == 0 || !rfs->bmap)
return 0;
new_block = extent_translate(rfs->old_fs, rfs->bmap,
ext2fs_file_acl_block(rfs->old_fs, inode));
new_block = extent_translate(rfs->new_fs, rfs->bmap,
ext2fs_file_acl_block(rfs->new_fs, inode));
if (new_block == 0)
return 0;
/* Set the new ACL block */
ext2fs_file_acl_block_set(rfs->old_fs, inode, new_block);
ext2fs_file_acl_block_set(rfs->new_fs, inode, new_block);
/* Update checksum */
if (ext2fs_has_feature_metadata_csum(rfs->new_fs->super)) {
err = ext2fs_get_mem(rfs->old_fs->blocksize, &buf);
err = ext2fs_get_mem(rfs->new_fs->blocksize, &buf);
if (err)
return err;
rfs->old_fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
err = ext2fs_read_ext_attr3(rfs->old_fs, new_block, buf, ino);
rfs->old_fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
rfs->new_fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
err = ext2fs_read_ext_attr3(rfs->new_fs, new_block, buf, ino);
rfs->new_fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
if (err)
goto out;
err = ext2fs_write_ext_attr3(rfs->old_fs, new_block, buf, ino);
err = ext2fs_write_ext_attr3(rfs->new_fs, new_block, buf, ino);
if (err)
goto out;
}
@ -1986,52 +2095,62 @@ static void quiet_com_err_proc(const char *whoami EXT2FS_ATTR((unused)),
{
}
static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
#define TRANSLATE_IPG(ino,old_fs,new_fs) (1 + (((ino)-1) % (old_fs)->super->s_inodes_per_group) + \
((ino)-1) / (old_fs)->super->s_inodes_per_group * (new_fs)->super->s_inodes_per_group)
/**
* Move inodes and rewrite references to blocks moved in blocks_to_move()
*/
static errcode_t inodes_to_move(ext2_resize_t rfs)
{
struct process_block_struct pb;
ext2_ino_t ino, new_inode;
ext2_ino_t ino, new_inode, tr_ino;
struct ext2_inode *inode = NULL;
ext2_inode_scan scan = NULL;
errcode_t retval;
dgrp_t g, old_g;
char *block_buf = 0;
ext2_ino_t start_to_move;
int inode_size;
int shrink_inodes = rfs->old_fs->inode_blocks_per_group > rfs->new_fs->inode_blocks_per_group;
int change_inodes = rfs->old_fs->inode_blocks_per_group != rfs->new_fs->inode_blocks_per_group;
if ((rfs->old_fs->group_desc_count <=
rfs->new_fs->group_desc_count) &&
!rfs->bmap)
!rfs->bmap &&
!change_inodes)
return 0;
set_com_err_hook(quiet_com_err_proc);
retval = ext2fs_open_inode_scan(rfs->old_fs, 0, &scan);
if (retval) goto errout;
retval = ext2fs_init_dblist(rfs->old_fs, 0);
if (retval) goto errout;
retval = ext2fs_get_array(rfs->old_fs->blocksize, 3, &block_buf);
if (retval) goto errout;
start_to_move = (rfs->new_fs->group_desc_count *
rfs->new_fs->super->s_inodes_per_group);
if (rfs->progress) {
retval = (rfs->progress)(rfs, E2_RSZ_INODE_SCAN_PASS,
0, rfs->old_fs->group_desc_count);
if (retval)
goto errout;
rfs->old_fs->super->s_inodes_per_group);
for (ino = start_to_move+1; ino <= rfs->old_fs->group_desc_count * rfs->old_fs->super->s_inodes_per_group; ino++) {
ext2fs_mark_inode_bitmap2(rfs->old_fs->inode_map, ino);
}
ext2fs_set_inode_callback(scan, progress_callback, (void *) rfs);
pb.rfs = rfs;
pb.inode = inode;
pb.error = 0;
new_inode = EXT2_FIRST_INODE(rfs->new_fs->super);
if (shrink_inodes) {
for (g = 0; g < rfs->old_fs->group_desc_count; g++) {
ext2_ino_t first_ino = 1+rfs->old_fs->super->s_inodes_per_group*g;
for (ino = first_ino+rfs->new_fs->super->s_inodes_per_group; ino < first_ino+rfs->old_fs->super->s_inodes_per_group; ino++) {
ext2fs_mark_inode_bitmap2(rfs->old_fs->inode_map, ino);
}
}
}
retval = ext2fs_get_array(rfs->new_fs->blocksize, 3, &block_buf);
if (retval) goto errout;
inode_size = EXT2_INODE_SIZE(rfs->new_fs->super);
inode = malloc(inode_size);
if (!inode) {
retval = ENOMEM;
goto errout;
}
pb.rfs = rfs;
pb.inode = inode;
pb.error = 0;
/*
* First, copy all of the inodes that need to be moved
* elsewhere in the inode table
@ -2045,78 +2164,68 @@ static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
if (inode->i_links_count == 0 && ino != EXT2_RESIZE_INO)
continue; /* inode not in use */
pb.is_dir = LINUX_S_ISDIR(inode->i_mode);
pb.changed = 0;
/* Remap EA block */
retval = migrate_ea_block(rfs, ino, inode, &pb.changed);
if (retval)
goto errout;
new_inode = ino;
if (ino <= start_to_move)
goto remap_blocks; /* Don't need to move inode. */
if (ino > start_to_move ||
(shrink_inodes && (ino-1) % rfs->old_fs->super->s_inodes_per_group >= rfs->new_fs->super->s_inodes_per_group))
{
/*
* Find a new inode. Now that extents and directory blocks
* are tied to the inode number through the checksum, we must
* set up the new inode before we start rewriting blocks.
*/
retval = ext2fs_new_inode(rfs->old_fs, 0, 0, 0, &new_inode);
if (retval)
goto errout;
/*
* Find a new inode. Now that extents and directory blocks
* are tied to the inode number through the checksum, we must
* set up the new inode before we start rewriting blocks.
*/
retval = ext2fs_new_inode(rfs->new_fs, 0, 0, 0, &new_inode);
if (retval)
goto errout;
/* Translate inode number according to new inodes_per_group */
tr_ino = TRANSLATE_IPG(new_inode, rfs->old_fs, rfs->new_fs);
ext2fs_inode_alloc_stats2(rfs->new_fs, new_inode, +1,
pb.is_dir);
inode->i_ctime = time(0);
retval = ext2fs_write_inode_full(rfs->old_fs, new_inode,
inode, inode_size);
if (retval)
goto errout;
pb.changed = 0;
old_g = ext2fs_group_of_ino(rfs->old_fs, ino);
ext2fs_inode_alloc_stats2(rfs->old_fs, new_inode, +1, LINUX_S_ISDIR(inode->i_mode));
if (old_g < rfs->new_fs->group_desc_count)
{
/*
* Don't bother to adjust free_inodes_count for group because freed
* inodes will be accounted as part of inodes_per_group change
*/
if (LINUX_S_ISDIR(inode->i_mode))
ext2fs_bg_used_dirs_count_set(rfs->new_fs, old_g, ext2fs_bg_used_dirs_count(rfs->new_fs, old_g) - 1);
ext2fs_group_desc_csum_set(rfs->new_fs, old_g);
}
ext2fs_inode_alloc_stats2(rfs->new_fs, tr_ino, +1, LINUX_S_ISDIR(inode->i_mode));
inode->i_ctime = time(0);
retval = ext2fs_write_inode_full(rfs->old_fs, new_inode, inode, inode_size);
if (retval)
goto errout;
#ifdef RESIZE2FS_DEBUG
if (rfs->flags & RESIZE_DEBUG_INODEMAP)
printf("Inode moved %u->%u\n", ino, new_inode);
if (rfs->flags & RESIZE_DEBUG_INODEMAP)
printf("Inode moved %u->%u\n", ino, new_inode);
#endif
if (!rfs->imap) {
retval = ext2fs_create_extent_table(&rfs->imap, 0);
if (retval)
goto errout;
}
ext2fs_add_extent_entry(rfs->imap, ino, new_inode);
remap_blocks:
if (pb.changed)
retval = ext2fs_write_inode_full(rfs->old_fs,
new_inode,
inode, inode_size);
if (retval)
goto errout;
if (!rfs->imap) {
retval = ext2fs_create_extent_table(&rfs->imap, 0);
if (retval)
goto errout;
}
ext2fs_add_extent_entry(rfs->imap, ino, new_inode);
/* Rewrite extent block checksums with new inode number */
if (ext2fs_has_feature_metadata_csum(rfs->old_fs->super) &&
(inode->i_flags & EXT4_EXTENTS_FL)) {
rfs->old_fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
retval = rewrite_extents(rfs->old_fs, new_inode);
rfs->old_fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
if (retval)
goto errout;
// continue with rewritten inode number
ino = new_inode;
}
/*
* Update inodes to point to new blocks; schedule directory
* blocks for inode remapping. Need to write out dir blocks
* with new inode numbers if we have metadata_csum enabled.
* Update inodes to point to new blocks.
*/
if (ext2fs_inode_has_valid_blocks2(rfs->old_fs, inode) &&
(rfs->bmap || pb.is_dir)) {
pb.ino = new_inode;
pb.old_ino = ino;
if (ext2fs_inode_has_valid_blocks2(rfs->old_fs, inode) && rfs->bmap) {
pb.changed = 0;
pb.is_dir = LINUX_S_ISDIR(inode->i_mode);
pb.ino = ino;
pb.old_ino = ino; // FIXME debug output will show translated inodes
pb.has_extents = inode->i_flags & EXT4_EXTENTS_FL;
rfs->old_fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
retval = ext2fs_block_iterate3(rfs->old_fs,
new_inode, 0, block_buf,
ino, 0, block_buf,
process_block, &pb);
rfs->old_fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
if (retval)
@ -2125,16 +2234,134 @@ remap_blocks:
retval = pb.error;
goto errout;
}
} else if ((inode->i_flags & EXT4_INLINE_DATA_FL) &&
(rfs->bmap || pb.is_dir)) {
}
}
errout:
if (scan)
ext2fs_close_inode_scan(scan);
if (block_buf)
ext2fs_free_mem(&block_buf);
free(inode);
return retval;
}
/**
* Remap extattr blocks, rewrite inode and extattr checksums
* and schedule directory blocks for inode remapping
*/
static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
{
struct process_block_struct pb;
ext2_ino_t ino, tr_ino;
struct ext2_inode *inode = NULL;
ext2_inode_scan scan = NULL;
errcode_t retval;
dgrp_t g;
char *block_buf = 0;
int inode_size;
int change_inodes = rfs->old_fs->inode_blocks_per_group != rfs->new_fs->inode_blocks_per_group;
if ((rfs->old_fs->group_desc_count <=
rfs->new_fs->group_desc_count) &&
!rfs->bmap &&
!change_inodes)
return 0;
set_com_err_hook(quiet_com_err_proc);
retval = ext2fs_open_inode_scan(rfs->new_fs, 0, &scan);
if (retval) goto errout;
retval = ext2fs_init_dblist(rfs->new_fs, 0);
if (retval) goto errout;
retval = ext2fs_get_array(rfs->new_fs->blocksize, 3, &block_buf);
if (retval) goto errout;
if (rfs->progress) {
retval = (rfs->progress)(rfs, E2_RSZ_INODE_SCAN_PASS,
0, rfs->new_fs->group_desc_count);
if (retval)
goto errout;
}
ext2fs_set_inode_callback(scan, progress_callback, (void *) rfs);
inode_size = EXT2_INODE_SIZE(rfs->new_fs->super);
inode = malloc(inode_size);
if (!inode) {
retval = ENOMEM;
goto errout;
}
pb.rfs = rfs;
pb.inode = inode;
pb.error = 0;
/*
* First, copy all of the inodes that need to be moved
* elsewhere in the inode table
*/
while (1) {
rfs->new_fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
retval = ext2fs_get_next_inode_full(scan, &ino, inode, inode_size);
rfs->new_fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
if (retval) goto errout;
if (!ino)
break;
if (inode->i_links_count == 0 && ino != EXT2_RESIZE_INO)
continue; /* inode not in use */
pb.is_dir = LINUX_S_ISDIR(inode->i_mode);
pb.changed = change_inodes;
/* Remap EA block */
retval = migrate_ea_block(rfs, ino, inode, &pb.changed);
if (retval)
goto errout;
if (pb.changed)
retval = ext2fs_write_inode_full(rfs->new_fs,
ino,
inode, inode_size);
if (retval)
goto errout;
/* Rewrite extent block checksums with new inode number */
if (ext2fs_has_feature_metadata_csum(rfs->new_fs->super) &&
(inode->i_flags & EXT4_EXTENTS_FL)) {
rfs->new_fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
retval = rewrite_extents(rfs->new_fs, ino);
rfs->new_fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
if (retval)
goto errout;
}
/*
* Schedule directory blocks for inode remapping. Need to write out dir blocks
* with new inode numbers if we have metadata_csum enabled.
*/
if (ext2fs_inode_has_valid_blocks2(rfs->new_fs, inode) && pb.is_dir) {
pb.ino = ino;
pb.old_ino = ino; // FIXME: Debug output will show translated inodes
pb.has_extents = inode->i_flags & EXT4_EXTENTS_FL;
rfs->new_fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
retval = ext2fs_block_iterate3(rfs->new_fs,
ino, 0, block_buf,
process_block, &pb);
rfs->new_fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
if (retval)
goto errout;
if (pb.error) {
retval = pb.error;
goto errout;
}
} else if ((inode->i_flags & EXT4_INLINE_DATA_FL) && pb.is_dir) {
/* inline data dir; update it too */
retval = ext2fs_add_dir_block2(rfs->old_fs->dblist,
new_inode, 0, 0);
retval = ext2fs_add_dir_block2(rfs->new_fs->dblist,
tr_ino, 0, 0);
if (retval)
goto errout;
}
}
io_channel_flush(rfs->old_fs->io);
io_channel_flush(rfs->new_fs->io);
errout:
reset_com_err_hook();
@ -2150,6 +2377,140 @@ errout:
return retval;
}
static errcode_t move_inode_tables(ext2_resize_t rfs)
{
dgrp_t g, end_g, group_count;
dgrp_t move_start, move_count;
__u32 old_ipg = rfs->old_fs->super->s_inodes_per_group;
__u32 new_ipg = rfs->new_fs->super->s_inodes_per_group;
__u32 old_ibg = rfs->old_fs->inode_blocks_per_group;
__u32 new_ibg = rfs->new_fs->inode_blocks_per_group;
int retval;
blk64_t size, blk, ib;
int change_inodes = old_ibg != new_ibg;
__u32 unused, ino, old_ino, i;
ext2fs_block_bitmap meta_bmap = NULL;
retval = ext2fs_allocate_block_bitmap(rfs->new_fs, _("meta-data blocks"), &meta_bmap);
if (retval)
return retval;
retval = mark_table_blocks(rfs->new_fs, meta_bmap, 1);
printf("inode blocks per group: %u to %u\n", old_ibg, new_ibg);
size = old_ibg;
size = size < new_ibg ? size : new_ibg;
move_count = 0;
group_count = rfs->new_fs->group_desc_count;
group_count = group_count < rfs->old_fs->group_desc_count ? group_count : rfs->old_fs->group_desc_count;
for (g = 0; g < group_count; g++)
{
if (change_inodes)
{
/*
* new_fs may have incorrect itable_unused because we're not adjusting it
* before calling inode_alloc_stats2 in inodes_to_move().
* and it's OK to take free_inodes_count from old_fs because any inodes
* that are freed may only lay in shrinked inode table areas.
*/
unused = ext2fs_bg_itable_unused(rfs->old_fs, g);
if (new_ipg < old_ipg && unused < old_ipg-new_ipg)
unused = 0;
else
unused = unused + new_ipg - old_ipg;
ext2fs_bg_itable_unused_set(rfs->new_fs, g, unused);
ext2fs_bg_free_inodes_count_set(rfs->new_fs, g,
ext2fs_bg_free_inodes_count(rfs->old_fs, g) + new_ipg - old_ipg);
ext2fs_group_desc_csum_set(rfs->new_fs, g);
}
printf("g%u = [%u?] %u->%u free=%u->%u unused=%u->%u\n", g,
g > 0 ? ext2fs_inode_table_loc(rfs->old_fs, g-1)+old_ibg : 0,
ext2fs_inode_table_loc(rfs->old_fs, g),
ext2fs_inode_table_loc(rfs->new_fs, g),
ext2fs_bg_free_inodes_count(rfs->old_fs, g),
ext2fs_bg_free_inodes_count(rfs->new_fs, g),
ext2fs_bg_itable_unused(rfs->old_fs, g),
ext2fs_bg_itable_unused(rfs->new_fs, g));
if (change_inodes || ext2fs_inode_table_loc(rfs->new_fs, g) != ext2fs_inode_table_loc(rfs->old_fs, g))
{
move_count++;
if (move_count == 1)
move_start = g;
// check for overlap
if (g < rfs->new_fs->group_desc_count-1 &&
ext2fs_inode_table_loc(rfs->new_fs, g)+new_ibg > ext2fs_inode_table_loc(rfs->old_fs, g+1))
{
continue;
}
}
if (move_count > 0)
{
end_g = g;
for (i = 0, g = move_start+move_count-1; i < move_count; i++, g--)
{
if (!ext2fs_has_group_desc_csum(rfs->new_fs) ||
!ext2fs_bg_flags_test(rfs->new_fs, g, EXT2_BG_INODE_UNINIT))
{
retval = io_channel_read_blk64(rfs->new_fs->io, ext2fs_inode_table_loc(rfs->old_fs, g), size, rfs->itable_buf);
if (retval)
return retval;
retval = io_channel_write_blk64(rfs->new_fs->io, ext2fs_inode_table_loc(rfs->new_fs, g), size, rfs->itable_buf);
if (retval)
return retval;
if (new_ibg > old_ibg)
{
retval = ext2fs_zero_blocks2(rfs->new_fs,
ext2fs_inode_table_loc(rfs->new_fs, g)+old_ibg,
new_ibg-old_ibg, NULL, NULL);
if (retval)
return retval;
}
}
blk = ext2fs_inode_table_loc(rfs->old_fs, g);
for (ib = 0; ib < old_ibg; ib++)
if (!ext2fs_test_block_bitmap2(meta_bmap, blk+ib))
ext2fs_unmark_block_bitmap2(rfs->new_fs->block_map, blk+ib);
ext2fs_mark_block_bitmap_range2(rfs->new_fs->block_map, ext2fs_inode_table_loc(rfs->new_fs, g), new_ibg);
}
move_start = move_count = 0;
g = end_g;
}
}
if (old_ipg < new_ipg)
{
for (g = 0; g < group_count; g++)
{
for (i = 0, old_ino = 1 + old_ipg*g, ino = 1 + new_ipg*g; i < old_ipg; i++, ino++, old_ino++)
{
if (ext2fs_test_inode_bitmap2(rfs->old_fs->inode_map, old_ino))
ext2fs_mark_inode_bitmap2(rfs->new_fs->inode_map, ino);
else
ext2fs_unmark_inode_bitmap2(rfs->new_fs->inode_map, ino);
}
for (i = old_ipg, ino = 1 + new_ipg*g + old_ipg; i < new_ipg; i++, ino++)
ext2fs_unmark_inode_bitmap2(rfs->new_fs->inode_map, ino);
}
}
else if (old_ipg > new_ipg)
{
dgrp_t n;
for (n = 0, g = group_count-1; n < group_count; n++, g--)
{
for (i = 0, old_ino = 1 + old_ipg*g, ino = 1 + new_ipg*g; i < new_ipg; i++, ino++, old_ino++)
{
if (ext2fs_test_inode_bitmap2(rfs->old_fs->inode_map, old_ino))
ext2fs_mark_inode_bitmap2(rfs->new_fs->inode_map, ino);
else
ext2fs_unmark_inode_bitmap2(rfs->new_fs->inode_map, ino);
}
}
}
ext2fs_free_block_bitmap(meta_bmap);
return 0;
}
/* --------------------------------------------------------------------
*
* Resize processing, phase 4.
@ -2176,9 +2537,10 @@ static int check_and_change_inodes(ext2_ino_t dir,
ext2_ino_t new_inode;
errcode_t retval;
int ret = 0;
ext2_ino_t old_dir = TRANSLATE_IPG(dir, is->rfs->new_fs, is->rfs->old_fs);
if (is->rfs->progress && offset == 0) {
io_channel_flush(is->rfs->old_fs->io);
io_channel_flush(is->rfs->new_fs->io);
is->err = (is->rfs->progress)(is->rfs,
E2_RSZ_INODE_REF_UPD_PASS,
++is->num, is->max_dirs);
@ -2191,16 +2553,25 @@ static int check_and_change_inodes(ext2_ino_t dir,
* old fs, then we must rewrite all dir blocks with new checksums.
*/
if (ext2fs_has_feature_metadata_csum(is->rfs->old_fs->super) &&
!ext2fs_test_inode_bitmap2(is->rfs->old_fs->inode_map, dir))
!ext2fs_test_inode_bitmap2(is->rfs->old_fs->inode_map, old_dir))
ret |= DIRENT_CHANGED;
if (!dirent->inode)
{
if (old_dir != dir)
ret |= DIRENT_CHANGED;
return ret;
}
new_inode = ext2fs_extent_translate(is->rfs->imap, dirent->inode);
new_inode = 0;
if (is->rfs->imap)
new_inode = ext2fs_extent_translate(is->rfs->imap, dirent->inode);
if (!new_inode)
new_inode = dirent->inode;
new_inode = TRANSLATE_IPG(new_inode, is->rfs->old_fs, is->rfs->new_fs);
if (new_inode == dirent->inode && old_dir == dir)
return ret;
#ifdef RESIZE2FS_DEBUG
if (is->rfs->flags & RESIZE_DEBUG_INODEMAP)
printf("Inode translate (dir=%u, name=%.*s, %u->%u)\n",
@ -2211,10 +2582,10 @@ static int check_and_change_inodes(ext2_ino_t dir,
dirent->inode = new_inode;
/* Update the directory mtime and ctime */
retval = ext2fs_read_inode(is->rfs->old_fs, dir, &inode);
retval = ext2fs_read_inode(is->rfs->new_fs, dir, &inode);
if (retval == 0) {
inode.i_mtime = inode.i_ctime = time(0);
is->err = ext2fs_write_inode(is->rfs->old_fs, dir, &inode);
is->err = ext2fs_write_inode(is->rfs->new_fs, dir, &inode);
if (is->err)
return ret | DIRENT_ABORT;
}
@ -2226,8 +2597,9 @@ static errcode_t inode_ref_fix(ext2_resize_t rfs)
{
errcode_t retval;
struct istruct is;
int change_inodes = rfs->old_fs->inode_blocks_per_group != rfs->new_fs->inode_blocks_per_group;
if (!rfs->imap)
if (!change_inodes && !rfs->imap)
return 0;
/*
@ -2235,7 +2607,7 @@ static errcode_t inode_ref_fix(ext2_resize_t rfs)
* inode references
*/
is.num = 0;
is.max_dirs = ext2fs_dblist_count2(rfs->old_fs->dblist);
is.max_dirs = ext2fs_dblist_count2(rfs->new_fs->dblist);
is.rfs = rfs;
is.err = 0;
@ -2246,11 +2618,11 @@ static errcode_t inode_ref_fix(ext2_resize_t rfs)
goto errout;
}
rfs->old_fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
retval = ext2fs_dblist_dir_iterate(rfs->old_fs->dblist,
rfs->new_fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
retval = ext2fs_dblist_dir_iterate(rfs->new_fs->dblist,
DIRENT_FLAG_INCLUDE_EMPTY, 0,
check_and_change_inodes, &is);
rfs->old_fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
rfs->new_fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
if (retval)
goto errout;
if (is.err) {
@ -2263,7 +2635,8 @@ static errcode_t inode_ref_fix(ext2_resize_t rfs)
is.max_dirs, is.max_dirs);
errout:
ext2fs_free_extent_table(rfs->imap);
if (rfs->imap)
ext2fs_free_extent_table(rfs->imap);
rfs->imap = 0;
return retval;
}
@ -2319,7 +2692,7 @@ static errcode_t move_itables(ext2_resize_t rfs)
if (retval)
return retval;
retval = mark_table_blocks(fs, new_bmap);
retval = mark_table_blocks(fs, new_bmap, 0);
if (retval)
goto errout;
}
@ -2431,7 +2804,7 @@ static errcode_t move_itables(ext2_resize_t rfs)
goto errout;
}
}
mark_table_blocks(fs, fs->block_map);
mark_table_blocks(fs, fs->block_map, 0);
ext2fs_flush(fs);
#ifdef RESIZE2FS_DEBUG
if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE)

View File

@ -141,7 +141,7 @@ struct ext2_resize_struct {
/* prototypes */
extern errcode_t resize_fs(ext2_filsys fs, blk64_t *new_size, int flags,
extern errcode_t resize_fs(ext2_filsys fs, blk64_t *new_size, __u32 new_inodes, int flags,
errcode_t (*progress)(ext2_resize_t rfs,
int pass, unsigned long cur,
unsigned long max));

View File

@ -0,0 +1,13 @@
Bad required extra isize in superblock (1). Fix? yes
Bad desired extra isize in superblock (1024). Fix? yes
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: ***** FILE SYSTEM WAS MODIFIED *****
test_filesys: 11/32 files (0.0% non-contiguous), 28/200 blocks
Exit status is 1

View File

@ -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/32 files (0.0% non-contiguous), 28/200 blocks
Exit status is 0

Binary file not shown.

View File

@ -0,0 +1 @@
check invalid extra_isize fields in superblock

View File

@ -1,4 +1,7 @@
Pass 1: Checking inodes, blocks, and sizes
Inode 12 has a extra size (126) which is invalid
Fix? yes
Pass 2: Checking directory structure
Directory inode 12, block #0, offset 4: directory corrupted
Salvage? yes

View File

@ -7,5 +7,5 @@
* file may be redistributed under the GNU Public License v2.
*/
#define E2FSPROGS_VERSION "1.43.2"
#define E2FSPROGS_DATE "01-Sep-2016"
#define E2FSPROGS_VERSION "1.43.3"
#define E2FSPROGS_DATE "04-Sep-2016"