summaryrefslogtreecommitdiffstats
path: root/e2fsck
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-21 04:59:34 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-21 04:59:34 +0000
commit6187d406bede6461086d6e5263f42ae4826675c4 (patch)
tree32a35120c4385929cfd5a7b9c584b9dd8396b108 /e2fsck
parentReleasing progress-linux version 1.47.0-2.4~progress7.99u1. (diff)
downloade2fsprogs-6187d406bede6461086d6e5263f42ae4826675c4.tar.xz
e2fsprogs-6187d406bede6461086d6e5263f42ae4826675c4.zip
Merging upstream version 1.47.1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'e2fsck')
-rw-r--r--e2fsck/e2fsck.8.in112
-rw-r--r--e2fsck/e2fsck.h9
-rw-r--r--e2fsck/ea_refcount.c4
-rw-r--r--e2fsck/ehandler.c10
-rw-r--r--e2fsck/extents.c9
-rw-r--r--e2fsck/iscan.c3
-rw-r--r--e2fsck/journal.c5
-rw-r--r--e2fsck/message.c2
-rw-r--r--e2fsck/pass1.c104
-rw-r--r--e2fsck/pass2.c168
-rw-r--r--e2fsck/pass3.c8
-rw-r--r--e2fsck/pass4.c53
-rw-r--r--e2fsck/problem.c22
-rw-r--r--e2fsck/problem.h12
-rw-r--r--e2fsck/rehash.c27
-rw-r--r--e2fsck/sigcatcher.c2
-rw-r--r--e2fsck/super.c25
-rw-r--r--e2fsck/unix.c13
-rw-r--r--e2fsck/util.c92
19 files changed, 454 insertions, 226 deletions
diff --git a/e2fsck/e2fsck.8.in b/e2fsck/e2fsck.8.in
index dc6a585..ea0f514 100644
--- a/e2fsck/e2fsck.8.in
+++ b/e2fsck/e2fsck.8.in
@@ -44,8 +44,9 @@ e2fsck \- check a Linux ext2/ext3/ext4 file system
is used to check the ext2/ext3/ext4 family of file systems.
For ext3 and ext4 file systems that use a journal, if the system has been
shut down uncleanly without any errors, normally, after replaying the
-committed transactions in the journal, the file system should be
-marked as clean. Hence, for file systems that use journaling,
+committed transactions in the journal, the file system should be
+marked as clean.
+Hence, for file systems that use journaling,
.B e2fsck
will normally replay the journal and exit, unless its superblock
indicates that further checking is required.
@@ -63,12 +64,14 @@ option is specified, and
.BR \-c ,
.BR \-l ,
or
-.B -L
+.B \-L
options are
.I not
-specified. However, even if it is safe to do so, the results printed by
+specified.
+However, even if it is safe to do so, the results printed by
.B e2fsck
-are not valid if the file system is mounted. If
+are not valid if the file system is mounted.
+If
.B e2fsck
asks whether or not you should check a file system which is mounted,
the only correct answer is ``no''. Only experts who really know what
@@ -80,10 +83,10 @@ is run in interactive mode (meaning that none of
.BR \-y ,
.BR \-n ,
or
-.BR \-p
+.B \-p
are specified), the program will ask the user to fix each problem found in the
-file system. A response of 'y' will fix the error; 'n' will leave the error
-unfixed; and 'a' will fix the problem and all subsequent problems; pressing
+file system. A response of \&'y' will fix the error; \&'n' will leave the error
+unfixed; and \&'a' will fix the problem and all subsequent problems; pressing
Enter will proceed with the default response, which is printed before the
question mark. Pressing Control-C terminates e2fsck immediately.
.SH OPTIONS
@@ -113,7 +116,7 @@ program using the
option to print out where the superblocks exist, supposing
.B mke2fs
is supplied with arguments that are consistent with the file system's layout
-(e.g. blocksize, blocks per group,
+(e.g.\& blocksize, blocks per group,
.BR sparse_super ,
etc.).
.IP
@@ -170,7 +173,7 @@ Print debugging output (useless unless you are debugging
.B \-D
Optimize directories in file system. This option causes e2fsck to
try to optimize all directories, either by re-indexing them if the
-file system supports directory indexing, or by sorting and compressing
+file system supports directory indexing, or by sorting and compressing
directories for smaller directories, or for file systems using
traditional linear directories.
.IP
@@ -204,86 +207,92 @@ Set the version of the extended attribute blocks which
will require while checking the file system. The version number may
be 1 or 2. The default extended attribute version format is 2.
.TP
-.BI journal_only
+.B journal_only
Only replay the journal if required, but do not perform any further checks
or repairs.
.TP
-.BI fragcheck
+.B fragcheck
During pass 1, print a detailed report of any discontiguous blocks for
files in the file system.
.TP
-.BI discard
+.B discard
Attempt to discard free blocks and unused inode blocks after the full
file system check (discarding blocks is useful on solid state devices and sparse
-/ thin-provisioned storage). Note that discard is done in pass 5 AFTER the
+/ thin-provisioned storage).
+Note that discard is done in pass 5 AFTER the
file system has been fully checked and only if it does not contain recognizable
-errors. However there might be cases where
+errors.
+However there might be cases where
.B e2fsck
does not fully recognize a problem and hence in this case this
option may prevent you from further manual data recovery.
.TP
-.BI nodiscard
-Do not attempt to discard free blocks and unused inode blocks. This option is
-exactly the opposite of discard option. This is set as default.
+.B nodiscard
+Do not attempt to discard free blocks and unused inode blocks.
+This option is exactly the opposite of discard option.
+This is set as default.
.TP
-.BI no_optimize_extents
+.B no_optimize_extents
Do not offer to optimize the extent tree by eliminating unnecessary
width or depth. This can also be enabled in the options section of
.BR /etc/e2fsck.conf .
.TP
-.BI optimize_extents
+.B optimize_extents
Offer to optimize the extent tree by eliminating unnecessary
width or depth. This is the default unless otherwise specified in
.BR /etc/e2fsck.conf .
.TP
-.BI inode_count_fullmap
+.B inode_count_fullmap
Trade off using memory for speed when checking a file system with a
large number of hard-linked files. The amount of memory required is
proportional to the number of inodes in the file system. For large file
-systems, this can be gigabytes of memory. (For example, a 40TB file system
+systems, this can be gigabytes of memory. (For example, a 40\ TB file system
with 2.8 billion inodes will consume an additional 5.7 GB memory if this
optimization is enabled.) This optimization can also be enabled in the
options section of
.BR /etc/e2fsck.conf .
.TP
-.BI no_inode_count_fullmap
+.B no_inode_count_fullmap
Disable the
.B inode_count_fullmap
optimization. This is the default unless otherwise specified in
.BR /etc/e2fsck.conf .
.TP
-.BI readahead_kb
+.B readahead_kb
Use this many KiB of memory to pre-fetch metadata in the hopes of reducing
e2fsck runtime. By default, this is set to the size of two block groups' inode
-tables (typically 4MiB on a regular ext4 file system); if this amount is more
+tables (typically 4\ MiB on a regular ext4 file system); if this amount is more
than 1/50th of total physical memory, readahead is disabled. Set this to zero
to disable readahead entirely.
.TP
-.BI bmap2extent
+.B bmap2extent
Convert block-mapped files to extent-mapped files.
.TP
-.BI fixes_only
+.B fixes_only
Only fix damaged metadata; do not optimize htree directories or compress
-extent trees. This option is incompatible with the -D and -E bmap2extent
+extent trees. This option is incompatible with the \-D and \-E bmap2extent
options.
.TP
-.BI check_encoding
+.B check_encoding
Force verification of encoded filenames in case-insensitive directories.
This is the default mode if the file system has the strict flag enabled.
.TP
-.BI unshare_blocks
+.B unshare_blocks
If the file system has shared blocks, with the shared blocks read-only feature
enabled, then this will unshare all shared blocks and unset the read-only
-feature bit. If there is not enough free space then the operation will fail.
+feature bit.
+If there is not enough free space then the operation will fail.
If the file system does not have the read-only feature bit, but has shared
-blocks anyway, then this option will have no effect. Note when using this
+blocks anyway, then this option will have no effect.
+Note when using this
option, if there is no free space to clone blocks, there is no prompt to
delete files and instead the operation will fail.
.IP
-Note that unshare_blocks implies the "-f" option to ensure that all passes
-are run. Additionally, if "-n" is also specified, e2fsck will simulate trying
-to allocate enough space to deduplicate. If this fails, the exit code will
-be non-zero.
+Note that unshare_blocks implies the "\-f" option to ensure that all passes
+are run.
+Additionally, if "\-n" is also specified, e2fsck will simulate trying
+to allocate enough space to deduplicate.
+If this fails, the exit code will be non-zero.
.RE
.TP
.B \-f
@@ -299,7 +308,7 @@ time trials.
@JDEV@Set the pathname where the external-journal for this file system can be
@JDEV@found.
.TP
-.BI \-k
+.B \-k
When combined with the
.B \-c
option, any existing bad blocks in the bad blocks list are preserved,
@@ -318,7 +327,7 @@ of the file system. Hence,
.BR badblocks (8)
must be given the blocksize of the file system in order to obtain correct
results. As a result, it is much simpler and safer to use the
-.B -c
+.B \-c
option to
.BR e2fsck ,
since it will assure that the correct parameters are passed to the
@@ -391,7 +400,9 @@ options.
.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
+an undo file. This undo file can be used with
+.BR e2undo (8)
+to restore the old
contents of the file system should something go wrong. If the empty string is
passed as the undo_file argument, the undo file will be written to a file named
e2fsck-\fIdevice\fR.e2undo in the directory specified via the
@@ -403,24 +414,23 @@ The exit code returned by
.B e2fsck
is the sum of the following conditions:
.br
-\ 0\ \-\ No errors
-.br
-\ 1\ \-\ File system errors corrected
+ 0 \-\ No errors
.br
-\ 2\ \-\ File system errors corrected, system should
+ 1 \-\ File system errors corrected
.br
-\ \ \ \ be rebooted
+ 2 \-\ File system errors corrected, system should
.br
-\ 4\ \-\ File system errors left uncorrected
+ \ \ be rebooted
.br
-\ 8\ \-\ Operational error
+ 4 \-\ File system errors left uncorrected
.br
-\ 16\ \-\ Usage or syntax error
+ 8 \-\ Operational error
.br
-\ 32\ \-\ E2fsck canceled by user request
+ 16 \-\ Usage or syntax error
.br
-\ 128\ \-\ Shared library error
+ 32 \-\ E2fsck canceled by user request
.br
+ 128 \-\ Shared library error
.SH SIGNALS
The following signals have the following effect when sent to
.BR e2fsck .
@@ -454,7 +464,7 @@ the messages printed by
are in English; if your system has been
configured so that
.BR e2fsck 's
-messages have been translated into another language, please set the the
+messages have been translated into another language, please set the
.B LC_ALL
environment variable to
.B C
@@ -492,7 +502,7 @@ Always include the full version string which
displays when it is run, so I know which version you are running.
.SH ENVIRONMENT
.TP
-.BI E2FSCK_CONFIG
+.B E2FSCK_CONFIG
Determines the location of the configuration file (see
.BR e2fsck.conf (5)).
.SH AUTHOR
diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h
index 3f2dc30..ae1273d 100644
--- a/e2fsck/e2fsck.h
+++ b/e2fsck/e2fsck.h
@@ -533,6 +533,12 @@ extern struct dx_dir_info *e2fsck_dx_dir_info_iter(e2fsck_t ctx,
typedef __u64 ea_key_t;
typedef __u64 ea_value_t;
+/*
+ * Special refcount value we use for inodes which have EA_INODE flag set but we
+ * do not yet know about any references.
+ */
+#define EA_INODE_NO_REFS (~(ea_value_t)0)
+
extern errcode_t ea_refcount_create(size_t size, ext2_refcount_t *ret);
extern void ea_refcount_free(ext2_refcount_t refcount);
extern errcode_t ea_refcount_fetch(ext2_refcount_t refcount, ea_key_t ea_key,
@@ -663,7 +669,8 @@ extern void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned long size,
const char *description);
extern int ask(e2fsck_t ctx, const char * string, int def);
extern int ask_yn(e2fsck_t ctx, const char * string, int def);
-extern void fatal_error(e2fsck_t ctx, const char * fmt_string);
+extern void fatal_error(e2fsck_t ctx, const char * fmt_string)
+ E2FSCK_ATTR((noreturn));
extern void log_out(e2fsck_t ctx, const char *fmt, ...)
E2FSCK_ATTR((format(printf, 2, 3)));
extern void log_err(e2fsck_t ctx, const char *fmt, ...)
diff --git a/e2fsck/ea_refcount.c b/e2fsck/ea_refcount.c
index 7154b47..7ca5669 100644
--- a/e2fsck/ea_refcount.c
+++ b/e2fsck/ea_refcount.c
@@ -120,7 +120,7 @@ static struct ea_refcount_el *insert_refcount_el(ext2_refcount_t refcount,
if (refcount->count >= refcount->size) {
new_size = refcount->size + 100;
#ifdef DEBUG
- printf("Reallocating refcount %d entries...\n", new_size);
+ printf("Reallocating refcount %zu entries...\n", new_size);
#endif
retval = ext2fs_resize_mem((size_t) refcount->size *
sizeof(struct ea_refcount_el),
@@ -177,7 +177,7 @@ retry:
if (ea_key == refcount->list[refcount->cursor].ea_key)
return &refcount->list[refcount->cursor++];
#ifdef DEBUG
- printf("Non-cursor get_refcount_el: %u\n", ea_key);
+ printf("Non-cursor get_refcount_el: %llu\n", (unsigned long long) ea_key);
#endif
while (low <= high) {
mid = (low+high)/2;
diff --git a/e2fsck/ehandler.c b/e2fsck/ehandler.c
index 71ca301..14e9549 100644
--- a/e2fsck/ehandler.c
+++ b/e2fsck/ehandler.c
@@ -31,6 +31,7 @@ static errcode_t e2fsck_handle_read_error(io_channel channel,
int i;
char *p;
ext2_filsys fs = (ext2_filsys) channel->app_data;
+ errcode_t retval;
e2fsck_t ctx;
ctx = (e2fsck_t) fs->priv_data;
@@ -64,8 +65,13 @@ static errcode_t e2fsck_handle_read_error(io_channel channel,
return 0;
if (ask(ctx, _("Ignore error"), 1)) {
- if (ask(ctx, _("Force rewrite"), 1))
- io_channel_write_blk64(channel, block, count, data);
+ if (ask(ctx, _("Force rewrite"), 1)) {
+ retval = io_channel_write_blk64(channel, block,
+ count, data);
+ if (retval)
+ printf(_("Error rewriting block %lu (%s)\n"),
+ block, error_message(retval));
+ }
return 0;
}
diff --git a/e2fsck/extents.c b/e2fsck/extents.c
index 70798f3..652e938 100644
--- a/e2fsck/extents.c
+++ b/e2fsck/extents.c
@@ -201,7 +201,10 @@ static errcode_t rewrite_extent_replay(e2fsck_t ctx, struct extent_list *list,
{
errcode_t retval;
ext2_extent_handle_t handle;
- unsigned int i, ext_written;
+ unsigned int i;
+#if defined(DEBUG) || defined(DEBUG_SUMMARY)
+ unsigned int ext_written = 0;
+#endif
struct ext2fs_extent *ex, extent;
blk64_t start_val, delta;
@@ -223,8 +226,6 @@ static errcode_t rewrite_extent_replay(e2fsck_t ctx, struct extent_list *list,
if (retval)
return retval;
- ext_written = 0;
-
start_val = ext2fs_get_stat_i_blocks(ctx->fs, EXT2_INODE(inode));
for (i = 0, ex = list->extents; i < list->count; i++, ex++) {
@@ -263,7 +264,9 @@ static errcode_t rewrite_extent_replay(e2fsck_t ctx, struct extent_list *list,
retval = ext2fs_extent_fix_parents(handle);
if (retval)
goto err;
+#if defined(DEBUG) || defined(DEBUG_SUMMARY)
ext_written++;
+#endif
}
delta = ext2fs_get_stat_i_blocks(ctx->fs, EXT2_INODE(inode)) -
diff --git a/e2fsck/iscan.c b/e2fsck/iscan.c
index 33c6a4c..1253f52 100644
--- a/e2fsck/iscan.c
+++ b/e2fsck/iscan.c
@@ -120,7 +120,8 @@ void print_resource_track(const char *desc,
} else
#elif defined HAVE_MALLINFO
/* don't use mallinfo() if over 2GB used, since it returns "int" */
- if ((char *)sbrk(0) - (char *)track->brk_start < 2LL << 30) {
+ if ((unsigned long)((char *)sbrk(0) - (char *)track->brk_start) <
+ 2UL << 30) {
struct mallinfo malloc_info = mallinfo();
printf("Memory used: %lluk/%lluk (%lluk/%lluk), ",
diff --git a/e2fsck/journal.c b/e2fsck/journal.c
index c7868d8..19d68b4 100644
--- a/e2fsck/journal.c
+++ b/e2fsck/journal.c
@@ -1683,6 +1683,7 @@ errcode_t e2fsck_run_ext3_journal(e2fsck_t ctx)
errcode_t retval, recover_retval;
io_stats stats = 0;
unsigned long long kbytes_written = 0;
+ __u16 s_error_state;
printf(_("%s: recovering journal\n"), ctx->device_name);
if (ctx->options & E2F_OPT_READONLY) {
@@ -1705,6 +1706,7 @@ errcode_t e2fsck_run_ext3_journal(e2fsck_t ctx)
ctx->fs->io->manager->get_stats(ctx->fs->io, &stats);
if (stats && stats->bytes_written)
kbytes_written = stats->bytes_written >> 10;
+ s_error_state = ctx->fs->super->s_state & EXT2_ERROR_FS;
ext2fs_mmp_stop(ctx->fs);
ext2fs_free(ctx->fs);
@@ -1721,6 +1723,7 @@ errcode_t e2fsck_run_ext3_journal(e2fsck_t ctx)
ctx->fs->now = ctx->now;
ctx->fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
ctx->fs->super->s_kbytes_written += kbytes_written;
+ ctx->fs->super->s_state |= s_error_state;
/* Set the superblock flags */
e2fsck_clear_recover(ctx, recover_retval != 0);
@@ -1841,7 +1844,7 @@ void e2fsck_move_ext3_journal(e2fsck_t ctx)
ext2fs_mark_super_dirty(fs);
fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
inode.i_links_count = 0;
- inode.i_dtime = ctx->now;
+ ext2fs_set_dtime(fs, &inode);
if ((retval = ext2fs_write_inode(fs, ino, &inode)) != 0)
goto err_out;
diff --git a/e2fsck/message.c b/e2fsck/message.c
index ba38038..9c42b13 100644
--- a/e2fsck/message.c
+++ b/e2fsck/message.c
@@ -301,7 +301,7 @@ static _INLINE_ void expand_inode_expression(FILE *f, ext2_filsys fs, char ch,
fprintf(f, "0%o", inode->i_mode);
break;
case 'M':
- print_time(f, inode->i_mtime);
+ print_time(f, ext2fs_inode_xtime_get(inode, i_mtime));
break;
case 'F':
fprintf(f, "%u", inode->i_faddr);
diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index a341c72..eb73922 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -387,34 +387,71 @@ static problem_t check_large_ea_inode(e2fsck_t ctx,
return 0;
}
+static int alloc_ea_inode_refs(e2fsck_t ctx, struct problem_context *pctx)
+{
+ pctx->errcode = ea_refcount_create(0, &ctx->ea_inode_refs);
+ if (pctx->errcode) {
+ pctx->num = 4;
+ fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return 0;
+ }
+ return 1;
+}
+
static void inc_ea_inode_refs(e2fsck_t ctx, struct problem_context *pctx,
struct ext2_ext_attr_entry *first, void *end)
{
struct ext2_ext_attr_entry *entry = first;
struct ext2_ext_attr_entry *np = EXT2_EXT_ATTR_NEXT(entry);
+ ea_value_t refs;
while ((void *) entry < end && (void *) np < end &&
!EXT2_EXT_IS_LAST_ENTRY(entry)) {
if (!entry->e_value_inum)
goto next;
- if (!ctx->ea_inode_refs) {
- pctx->errcode = ea_refcount_create(0,
- &ctx->ea_inode_refs);
- if (pctx->errcode) {
- pctx->num = 4;
- fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx);
- ctx->flags |= E2F_FLAG_ABORT;
- return;
- }
- }
- ea_refcount_increment(ctx->ea_inode_refs, entry->e_value_inum,
- 0);
+ if (!ctx->ea_inode_refs && !alloc_ea_inode_refs(ctx, pctx))
+ return;
+ ea_refcount_fetch(ctx->ea_inode_refs, entry->e_value_inum,
+ &refs);
+ if (refs == EA_INODE_NO_REFS)
+ refs = 1;
+ else
+ refs += 1;
+ ea_refcount_store(ctx->ea_inode_refs, entry->e_value_inum, refs);
next:
entry = np;
np = EXT2_EXT_ATTR_NEXT(entry);
}
}
+/*
+ * Make sure inode is tracked as EA inode. We use special EA_INODE_NO_REFS
+ * value if we didn't find any xattrs referencing this inode yet.
+ */
+static int track_ea_inode(e2fsck_t ctx, struct problem_context *pctx,
+ ext2_ino_t ino)
+{
+ ea_value_t refs;
+
+ if (!ctx->ea_inode_refs && !alloc_ea_inode_refs(ctx, pctx))
+ return 0;
+
+ ea_refcount_fetch(ctx->ea_inode_refs, ino, &refs);
+ if (refs > 0)
+ return 1;
+
+ pctx->errcode = ea_refcount_store(ctx->ea_inode_refs, ino,
+ EA_INODE_NO_REFS);
+ if (pctx->errcode) {
+ pctx->num = 5;
+ fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ return 0;
+ }
+ return 1;
+}
+
static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx,
struct ea_quota *ea_ibody_quota)
{
@@ -510,6 +547,12 @@ static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx,
} else {
blk64_t quota_blocks;
+ if (!ext2fs_has_feature_ea_inode(sb) &&
+ fix_problem(ctx, PR_1_EA_INODE_FEATURE, pctx)) {
+ ext2fs_set_feature_ea_inode(sb);
+ ext2fs_mark_super_dirty(ctx->fs);
+ }
+
problem = check_large_ea_inode(ctx, entry, pctx,
&quota_blocks);
if (problem != 0)
@@ -1181,6 +1224,7 @@ void e2fsck_pass1(e2fsck_t ctx)
ext2_ino_t ino_threshold = 0;
dgrp_t ra_group = 0;
struct ea_quota ea_ibody_quota;
+ time_t tm;
init_resource_track(&rtrack, ctx->fs->io);
clear_problem_context(&pctx);
@@ -1357,12 +1401,13 @@ void e2fsck_pass1(e2fsck_t ctx)
if (ctx->progress && ((ctx->progress)(ctx, 1, 0,
ctx->fs->group_desc_count)))
goto endit;
- if ((fs->super->s_wtime &&
- fs->super->s_wtime < fs->super->s_inodes_count) ||
- (fs->super->s_mtime &&
- fs->super->s_mtime < fs->super->s_inodes_count) ||
- (fs->super->s_mkfs_time &&
- fs->super->s_mkfs_time < fs->super->s_inodes_count))
+
+ if (((tm = ext2fs_get_tstamp(fs->super, s_wtime)) &&
+ tm < fs->super->s_inodes_count) ||
+ ((tm = ext2fs_get_tstamp(fs->super, s_mtime)) &&
+ tm < fs->super->s_inodes_count) ||
+ ((tm = ext2fs_get_tstamp(fs->super, s_mkfs_time)) &&
+ tm < fs->super->s_inodes_count))
low_dtime_check = 0;
if (ext2fs_has_feature_mmp(fs->super) &&
@@ -1481,7 +1526,7 @@ void e2fsck_pass1(e2fsck_t ctx)
if (!inode->i_dtime && inode->i_mode) {
if (fix_problem(ctx,
PR_1_ZERO_DTIME, &pctx)) {
- inode->i_dtime = ctx->now;
+ ext2fs_set_dtime(fs, inode);
e2fsck_write_inode(ctx, ino, inode,
"pass1");
failed_csum = 0;
@@ -1500,6 +1545,17 @@ void e2fsck_pass1(e2fsck_t ctx)
e2fsck_write_inode(ctx, ino, inode, "pass1");
}
+ if (inode->i_flags & EXT4_EA_INODE_FL) {
+ if (!LINUX_S_ISREG(inode->i_mode) &&
+ fix_problem(ctx, PR_1_EA_INODE_NONREG, &pctx)) {
+ inode->i_flags &= ~EXT4_EA_INODE_FL;
+ e2fsck_write_inode(ctx, ino, inode, "pass1");
+ }
+ if (inode->i_flags & EXT4_EA_INODE_FL)
+ if (!track_ea_inode(ctx, &pctx, ino))
+ continue;
+ }
+
/* Conflicting inlinedata/extents inode flags? */
if ((inode->i_flags & EXT4_INLINE_DATA_FL) &&
(inode->i_flags & EXT4_EXTENTS_FL)) {
@@ -2076,7 +2132,7 @@ void e2fsck_pass1(e2fsck_t ctx)
if (!pctx.errcode) {
e2fsck_read_inode(ctx, EXT2_RESIZE_INO, inode,
"recreate inode");
- inode->i_mtime = ctx->now;
+ ext2fs_inode_xtime_set(inode, i_mtime, ctx->now);
e2fsck_write_inode(ctx, EXT2_RESIZE_INO, inode,
"recreate inode");
}
@@ -2620,6 +2676,12 @@ static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
problem_t problem;
blk64_t entry_quota_blocks;
+ if (!ext2fs_has_feature_ea_inode(fs->super) &&
+ fix_problem(ctx, PR_1_EA_INODE_FEATURE, pctx)) {
+ ext2fs_set_feature_ea_inode(fs->super);
+ ext2fs_mark_super_dirty(fs);
+ }
+
problem = check_large_ea_inode(ctx, entry, pctx,
&entry_quota_blocks);
if (problem && fix_problem(ctx, problem, pctx))
@@ -2791,7 +2853,7 @@ void e2fsck_clear_inode(e2fsck_t ctx, ext2_ino_t ino,
inode->i_flags = 0;
inode->i_links_count = 0;
ext2fs_icount_store(ctx->inode_link_info, ino, 0);
- inode->i_dtime = ctx->now;
+ ext2fs_set_dtime(ctx->fs, inode);
/*
* If a special inode has such rotten block mappings that we
diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c
index 410edd1..036c002 100644
--- a/e2fsck/pass2.c
+++ b/e2fsck/pass2.c
@@ -1341,57 +1341,68 @@ skip_checksum:
(rec_len < min_dir_len) ||
((rec_len % 4) != 0) ||
((ext2fs_dir_rec_len(ext2fs_dirent_name_len(dirent),
- extended)) > rec_len)) {
- if (fix_problem(ctx, PR_2_DIR_CORRUPTED,
- &cd->pctx)) {
+ extended)) > rec_len))
+ problem = PR_2_DIR_CORRUPTED;
+ if (problem) {
+ if ((offset == 0) &&
+ (rec_len == fs->blocksize) &&
+ (dirent->inode == 0) &&
+ e2fsck_dir_will_be_rehashed(ctx, ino)) {
+ problem = 0;
+ max_block_size = fs->blocksize;
+ }
+ }
+ if (problem) {
#ifdef WORDS_BIGENDIAN
- /*
- * On big-endian systems, if the dirent
- * swap routine finds a rec_len that it
- * doesn't like, it continues
- * processing the block as if rec_len
- * == EXT2_DIR_ENTRY_HEADER_LEN. This means that the name
- * field gets byte swapped, which means
- * that salvage will not detect the
- * correct name length (unless the name
- * has a length that's an exact
- * multiple of four bytes), and it'll
- * discard the entry (unnecessarily)
- * and the rest of the dirent block.
- * Therefore, swap the rest of the
- * block back to disk order, run
- * salvage, and re-swap anything after
- * the salvaged dirent.
- */
- int need_reswab = 0;
- if (rec_len < EXT2_DIR_ENTRY_HEADER_LEN || rec_len % 4) {
- need_reswab = 1;
- ext2fs_dirent_swab_in2(fs,
- ((char *)dirent) + EXT2_DIR_ENTRY_HEADER_LEN,
- max_block_size - offset - EXT2_DIR_ENTRY_HEADER_LEN,
- 0);
- }
+ int need_reswab = 0;
#endif
- salvage_directory(fs, dirent, prev,
- &offset,
- max_block_size,
- hash_in_dirent);
+
+ if (!fix_problem(ctx, PR_2_DIR_CORRUPTED,
+ &cd->pctx))
+ goto abort_free_dict;
#ifdef WORDS_BIGENDIAN
- if (need_reswab) {
- unsigned int len;
-
- (void) ext2fs_get_rec_len(fs,
- dirent, &len);
- len += offset;
- if (max_block_size > len)
- ext2fs_dirent_swab_in2(fs,
- ((char *)dirent) + len, max_block_size - len, 0);
- }
+ /*
+ * On big-endian systems, if the dirent
+ * swap routine finds a rec_len that it
+ * doesn't like, it continues processing
+ * the block as if rec_len ==
+ * EXT2_DIR_ENTRY_HEADER_LEN. This means
+ * that the name field gets byte swapped,
+ * which means that salvage will not detect
+ * the correct name length (unless the name
+ * has a length that's an exact multiple of
+ * four bytes), and it'll discard the entry
+ * (unnecessarily) and the rest of the
+ * dirent block. Therefore, swap the rest
+ * of the block back to disk order, run
+ * salvage, and re-swap anything after the
+ * salvaged dirent.
+ */
+ if (rec_len < EXT2_DIR_ENTRY_HEADER_LEN ||
+ rec_len % 4) {
+ need_reswab = 1;
+ ext2fs_dirent_swab_in2(fs,
+ ((char *)dirent) + EXT2_DIR_ENTRY_HEADER_LEN,
+ max_block_size - offset - EXT2_DIR_ENTRY_HEADER_LEN, 0);
+ }
#endif
- dir_modified++;
- continue;
- } else
- goto abort_free_dict;
+ salvage_directory(fs, dirent, prev, &offset,
+ max_block_size,
+ hash_in_dirent);
+#ifdef WORDS_BIGENDIAN
+ if (need_reswab) {
+ unsigned int len;
+
+ (void) ext2fs_get_rec_len(fs, dirent,
+ &len);
+ len += offset;
+ if (max_block_size > len)
+ ext2fs_dirent_swab_in2(fs,
+ ((char *)dirent) + len, max_block_size - len, 0);
+ }
+#endif
+ dir_modified++;
+ continue;
}
} else {
if (dot_state == 0) {
@@ -1490,6 +1501,21 @@ skip_checksum:
problem = PR_2_NULL_NAME;
}
+ /*
+ * Check if inode was tracked as EA inode and has actual
+ * references from xattrs. In that case dir entry is likely
+ * bogus and we want to clear it. The case of EA inode without
+ * references from xattrs will be handled in pass 4.
+ */
+ if (!problem && ctx->ea_inode_refs) {
+ ea_value_t refs;
+
+ ea_refcount_fetch(ctx->ea_inode_refs, dirent->inode,
+ &refs);
+ if (refs && refs != EA_INODE_NO_REFS)
+ problem = PR_2_EA_INODE_DIR_LINK;
+ }
+
if (problem) {
if (fix_problem(ctx, problem, &cd->pctx)) {
dirent->inode = 0;
@@ -1513,7 +1539,7 @@ skip_checksum:
dirent->inode)) {
if (e2fsck_process_bad_inode(ctx, ino,
dirent->inode,
- buf + fs->blocksize)) {
+ cd->buf + fs->blocksize)) {
dirent->inode = 0;
dir_modified++;
goto next;
@@ -1574,7 +1600,8 @@ skip_checksum:
*/
if (!(ctx->flags & E2F_FLAG_RESTART_LATER) &&
!(ext2fs_test_inode_bitmap2(ctx->inode_used_map,
- dirent->inode)))
+ dirent->inode))
+ )
problem = PR_2_UNUSED_INODE;
if (problem) {
@@ -1842,17 +1869,26 @@ static int deallocate_inode_block(ext2_filsys fs,
}
/*
- * This function deallocates an inode
+ * This function reverts various counters and bitmaps incremented in
+ * pass1 for the inode, blocks, and quotas before it was decided the
+ * inode was corrupt and needed to be cleared. This avoids the need
+ * to run e2fsck a second time (or have it restart itself) to repair
+ * these counters.
+ *
+ * It does not modify any on-disk state, so even if the inode is bad
+ * it _should_ reset in-memory state to before the inode was first
+ * processed.
*/
static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf)
{
ext2_filsys fs = ctx->fs;
- struct ext2_inode inode;
+ struct ext2_inode_large inode;
struct problem_context pctx;
__u32 count;
struct del_block del_block;
- e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode");
+ e2fsck_read_inode_full(ctx, ino, EXT2_INODE(&inode),
+ sizeof(inode), "deallocate_inode");
clear_problem_context(&pctx);
pctx.ino = ino;
@@ -1862,29 +1898,29 @@ static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf)
e2fsck_read_bitmaps(ctx);
ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
- if (ext2fs_file_acl_block(fs, &inode) &&
+ if (ext2fs_file_acl_block(fs, EXT2_INODE(&inode)) &&
ext2fs_has_feature_xattr(fs->super)) {
pctx.errcode = ext2fs_adjust_ea_refcount3(fs,
- ext2fs_file_acl_block(fs, &inode),
+ ext2fs_file_acl_block(fs, EXT2_INODE(&inode)),
block_buf, -1, &count, ino);
if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) {
pctx.errcode = 0;
count = 1;
}
if (pctx.errcode) {
- pctx.blk = ext2fs_file_acl_block(fs, &inode);
+ pctx.blk = ext2fs_file_acl_block(fs, EXT2_INODE(&inode));
fix_problem(ctx, PR_2_ADJ_EA_REFCOUNT, &pctx);
ctx->flags |= E2F_FLAG_ABORT;
return;
}
if (count == 0) {
ext2fs_block_alloc_stats2(fs,
- ext2fs_file_acl_block(fs, &inode), -1);
+ ext2fs_file_acl_block(fs, EXT2_INODE(&inode)), -1);
}
- ext2fs_file_acl_block_set(fs, &inode, 0);
+ ext2fs_file_acl_block_set(fs, EXT2_INODE(&inode), 0);
}
- if (!ext2fs_inode_has_valid_blocks2(fs, &inode))
+ if (!ext2fs_inode_has_valid_blocks2(fs, EXT2_INODE(&inode)))
goto clear_inode;
/* Inline data inodes don't have blocks to iterate */
@@ -1909,10 +1945,22 @@ static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf)
ctx->flags |= E2F_FLAG_ABORT;
return;
}
+
+ if ((ino != quota_type2inum(PRJQUOTA, fs->super)) &&
+ (ino != fs->super->s_orphan_file_inum) &&
+ (ino == EXT2_ROOT_INO || ino >= EXT2_FIRST_INODE(ctx->fs->super)) &&
+ !(inode.i_flags & EXT4_EA_INODE_FL)) {
+ if (del_block.num > 0)
+ quota_data_sub(ctx->qctx, &inode, ino,
+ del_block.num * EXT2_CLUSTER_SIZE(fs->super));
+ quota_data_inodes(ctx->qctx, (struct ext2_inode_large *)&inode,
+ ino, -1);
+ }
+
clear_inode:
/* Inode may have changed by block_iterate, so reread it */
- e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode");
- e2fsck_clear_inode(ctx, ino, &inode, 0, "deallocate_inode");
+ e2fsck_read_inode(ctx, ino, EXT2_INODE(&inode), "deallocate_inode");
+ e2fsck_clear_inode(ctx, ino, EXT2_INODE(&inode), 0, "deallocate_inode");
}
/*
diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c
index 16d243f..ba79416 100644
--- a/e2fsck/pass3.c
+++ b/e2fsck/pass3.c
@@ -212,7 +212,9 @@ skip_new_block:
memset(&inode, 0, sizeof(inode));
inode.i_mode = 040755;
inode.i_size = fs->blocksize;
- inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now;
+ ext2fs_inode_xtime_set(&inode, i_atime, ctx->now);
+ ext2fs_inode_xtime_set(&inode, i_ctime, ctx->now);
+ ext2fs_inode_xtime_set(&inode, i_mtime, ctx->now);
inode.i_links_count = 2;
ext2fs_iblk_set(fs, iptr, 1);
inode.i_block[0] = blk;
@@ -528,7 +530,9 @@ skip_new_block:
memset(&inode, 0, sizeof(inode));
inode.i_mode = 040700;
inode.i_size = fs->blocksize;
- inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now;
+ ext2fs_inode_xtime_set(&inode, i_atime, ctx->now);
+ ext2fs_inode_xtime_set(&inode, i_ctime, ctx->now);
+ ext2fs_inode_xtime_set(&inode, i_mtime, ctx->now);
inode.i_links_count = 2;
ext2fs_iblk_set(fs, EXT2_INODE(&inode), 1);
inode.i_block[0] = blk;
diff --git a/e2fsck/pass4.c b/e2fsck/pass4.c
index d2dda02..cf0cf7c 100644
--- a/e2fsck/pass4.c
+++ b/e2fsck/pass4.c
@@ -96,9 +96,10 @@ static int disconnect_inode(e2fsck_t ctx, ext2_ino_t i, ext2_ino_t *last_ino,
* an xattr inode at all. Return immediately if EA_INODE flag is not set.
*/
static void check_ea_inode(e2fsck_t ctx, ext2_ino_t i, ext2_ino_t *last_ino,
- struct ext2_inode_large *inode, __u16 *link_counted)
+ struct ext2_inode_large *inode, __u16 *link_counted,
+ ea_value_t actual_refs)
{
- __u64 actual_refs = 0;
+ struct problem_context pctx;
__u64 ref_count;
if (*last_ino != i) {
@@ -107,13 +108,26 @@ static void check_ea_inode(e2fsck_t ctx, ext2_ino_t i, ext2_ino_t *last_ino,
"pass4: check_ea_inode");
*last_ino = i;
}
- if (!(inode->i_flags & EXT4_EA_INODE_FL))
- return;
- if (ctx->ea_inode_refs)
- ea_refcount_fetch(ctx->ea_inode_refs, i, &actual_refs);
- if (!actual_refs)
+ clear_problem_context(&pctx);
+ pctx.ino = i;
+ pctx.inode = EXT2_INODE(inode);
+
+ /* No references to the inode from xattrs? */
+ if (actual_refs == EA_INODE_NO_REFS) {
+ /*
+ * No references from directory hierarchy either? Inode will
+ * will get attached to lost+found so clear EA_INODE_FL.
+ * Otherwise this is likely a spuriously set flag so clear it.
+ */
+ if (*link_counted == 0 ||
+ fix_problem(ctx, PR_4_EA_INODE_SPURIOUS_FLAG, &pctx)) {
+ /* Clear EA_INODE_FL (likely a normal file) */
+ inode->i_flags &= ~EXT4_EA_INODE_FL;
+ e2fsck_write_inode(ctx, i, EXT2_INODE(inode), "pass4");
+ }
return;
+ }
/*
* There are some attribute references, link_counted is now considered
@@ -127,10 +141,6 @@ static void check_ea_inode(e2fsck_t ctx, ext2_ino_t i, ext2_ino_t *last_ino,
* However, their i_ctime and i_atime should be the same.
*/
if (ref_count != actual_refs && inode->i_ctime != inode->i_atime) {
- struct problem_context pctx;
-
- clear_problem_context(&pctx);
- pctx.ino = i;
pctx.num = ref_count;
pctx.num2 = actual_refs;
if (fix_problem(ctx, PR_4_EA_INODE_REF_COUNT, &pctx)) {
@@ -188,6 +198,7 @@ void e2fsck_pass4(e2fsck_t ctx)
/* Protect loop from wrap-around if s_inodes_count maxed */
for (i = 1; i <= fs->super->s_inodes_count && i > 0; i++) {
ext2_ino_t last_ino = 0;
+ ea_value_t ea_refs;
int isdir;
if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
@@ -211,13 +222,19 @@ void e2fsck_pass4(e2fsck_t ctx)
ext2fs_icount_fetch(ctx->inode_link_info, i, &link_count);
ext2fs_icount_fetch(ctx->inode_count, i, &link_counted);
- if (link_counted == 0) {
- /*
- * link_counted is expected to be 0 for an ea_inode.
- * check_ea_inode() will update link_counted if
- * necessary.
- */
- check_ea_inode(ctx, i, &last_ino, inode, &link_counted);
+ if (ctx->ea_inode_refs) {
+ ea_refcount_fetch(ctx->ea_inode_refs, i, &ea_refs);
+ if (ea_refs) {
+ /*
+ * Final consolidation of EA inodes. We either
+ * decide the inode is fine and set link_counted
+ * to one, or we decide this is actually a
+ * normal file and clear EA_INODE flag, or
+ * decide the inode should just be deleted.
+ */
+ check_ea_inode(ctx, i, &last_ino, inode,
+ &link_counted, ea_refs);
+ }
}
if (link_counted == 0) {
diff --git a/e2fsck/problem.c b/e2fsck/problem.c
index 6ad6fb8..e433281 100644
--- a/e2fsck/problem.c
+++ b/e2fsck/problem.c
@@ -1309,6 +1309,16 @@ static struct e2fsck_problem problem_table[] = {
N_("Orphan file @i %i is not in use, but contains data. "),
PROMPT_CLEAR, PR_PREEN_OK },
+ /* EA_INODE flag set on a non-regular file */
+ { PR_1_EA_INODE_NONREG,
+ N_("@i %i has the ea_inode flag set but is not a regular file. "),
+ PROMPT_CLEAR_FLAG, 0, 0, 0, 0 },
+
+ /* EA_INODE present but the file system is missing the ea_inode feature */
+ { PR_1_EA_INODE_FEATURE,
+ N_("@i %i references EA inode but @S is missing EA_INODE feature\n"),
+ PROMPT_FIX, PR_PREEN_OK, 0, 0, 0 },
+
/* Pass 1b errors */
/* Pass 1B: Rescan for duplicate/bad blocks */
@@ -1860,6 +1870,10 @@ static struct e2fsck_problem problem_table[] = {
N_("Duplicate filename @E found. "),
PROMPT_CLEAR, 0, 0, 0, 0 },
+ /* Directory filename is null */
+ { PR_2_EA_INODE_DIR_LINK,
+ N_("@E references EA @i %Di.\n"),
+ PROMPT_CLEAR, 0, 0, 0, 0 },
/* Pass 3 errors */
@@ -2102,6 +2116,10 @@ static struct e2fsck_problem problem_table[] = {
N_("@d @i %i ref count set to overflow but could be exact value %N. "),
PROMPT_FIX, PR_PREEN_OK, 0, 0, 0 },
+ { PR_4_EA_INODE_SPURIOUS_FLAG,
+ N_("Regular @f @i %i has EA_INODE flag set. "),
+ PROMPT_CLEAR, PR_PREEN_OK, 0, 0, 0 },
+
/* Pass 5 errors */
/* Pass 5: Checking group summary information */
@@ -2327,7 +2345,7 @@ static struct e2fsck_problem problem_table[] = {
/* orphan_present set but orphan file is empty */
{ PR_6_ORPHAN_PRESENT_CLEAN_FILE,
N_("Feature orphan_present is set but orphan file is clean.\n"),
- PROMPT_CLEAR, PR_PREEN_OK },
+ PROMPT_CLEAR, PR_PREEN_OK | PR_NO_OK | PR_PREEN_NOMSG },
/* orphan_present set but orphan_file is not */
{ PR_6_ORPHAN_PRESENT_NO_FILE,
@@ -2689,7 +2707,7 @@ void print_e2fsck_message(FILE *f, e2fsck_t ctx, const char *msg,
void fatal_error(e2fsck_t ctx, const char *msg)
{
- return;
+ exit(0);
}
void preenhalt(e2fsck_t ctx)
diff --git a/e2fsck/problem.h b/e2fsck/problem.h
index b47b0c6..ef15b8c 100644
--- a/e2fsck/problem.h
+++ b/e2fsck/problem.h
@@ -734,6 +734,12 @@ struct problem_context {
/* Orphan file inode is not in use, but contains data */
#define PR_1_ORPHAN_FILE_NOT_CLEAR 0x010090
+/* Inode has EA_INODE_FL set but is not a regular file */
+#define PR_1_EA_INODE_NONREG 0x010091
+
+/* Inode references EA inode but ea_inode feature is not enabled */
+#define PR_1_EA_INODE_FEATURE 0x010092
+
/*
* Pass 1b errors
*/
@@ -1061,6 +1067,9 @@ struct problem_context {
/* Non-unique filename found, but can't rename */
#define PR_2_NON_UNIQUE_FILE_NO_RENAME 0x020054
+/* EA inode referenced from directory */
+#define PR_2_EA_INODE_DIR_LINK 0x020055
+
/*
* Pass 3 errors
*/
@@ -1203,6 +1212,9 @@ struct problem_context {
/* Directory ref count set to overflow but it doesn't have to be */
#define PR_4_DIR_OVERFLOW_REF_COUNT 0x040007
+/* EA_INODE_FL set on normal file linked from directory hierarchy */
+#define PR_4_EA_INODE_SPURIOUS_FLAG 0x040008
+
/*
* Pass 5 errors
*/
diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c
index c1da7d5..4847d17 100644
--- a/e2fsck/rehash.c
+++ b/e2fsck/rehash.c
@@ -987,14 +987,18 @@ errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino,
{
ext2_filsys fs = ctx->fs;
errcode_t retval;
- struct ext2_inode inode;
+ struct ext2_inode_large inode;
char *dir_buf = 0;
struct fill_dir_struct fd = { NULL, NULL, 0, 0, 0, NULL,
0, 0, 0, 0, 0, 0 };
struct out_dir outdir = { 0, 0, 0, 0 };
- struct name_cmp_ctx name_cmp_ctx = {0, NULL};
+ struct name_cmp_ctx name_cmp_ctx = {0, NULL};
+ __u64 osize;
- e2fsck_read_inode(ctx, ino, &inode, "rehash_dir");
+ e2fsck_read_inode_full(ctx, ino, EXT2_INODE(&inode),
+ sizeof(inode), "rehash_dir");
+
+ osize = EXT2_I_SIZE(&inode);
if (ext2fs_has_feature_inline_data(fs->super) &&
(inode.i_flags & EXT4_INLINE_DATA_FL))
@@ -1013,7 +1017,7 @@ errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino,
fd.ino = ino;
fd.ctx = ctx;
fd.buf = dir_buf;
- fd.inode = &inode;
+ fd.inode = EXT2_INODE(&inode);
fd.dir = ino;
if (!ext2fs_has_feature_dir_index(fs->super) ||
(inode.i_size / fs->blocksize) < 2)
@@ -1092,14 +1096,25 @@ resort:
goto errout;
}
- retval = write_directory(ctx, fs, &outdir, ino, &inode, fd.compress);
+ retval = write_directory(ctx, fs, &outdir, ino, EXT2_INODE(&inode),
+ fd.compress);
if (retval)
goto errout;
+ if ((osize > EXT2_I_SIZE(&inode)) &&
+ (ino != quota_type2inum(PRJQUOTA, fs->super)) &&
+ (ino != fs->super->s_orphan_file_inum) &&
+ (ino == EXT2_ROOT_INO || ino >= EXT2_FIRST_INODE(ctx->fs->super)) &&
+ !(inode.i_flags & EXT4_EA_INODE_FL)) {
+ quota_data_sub(ctx->qctx, &inode,
+ ino, osize - EXT2_I_SIZE(&inode));
+ }
+
if (ctx->options & E2F_OPT_CONVERT_BMAP)
retval = e2fsck_rebuild_extents_later(ctx, ino);
else
- retval = e2fsck_check_rebuild_extents(ctx, ino, &inode, pctx);
+ retval = e2fsck_check_rebuild_extents(ctx, ino,
+ EXT2_INODE(&inode), pctx);
errout:
ext2fs_free_mem(&dir_buf);
ext2fs_free_mem(&fd.harray);
diff --git a/e2fsck/sigcatcher.c b/e2fsck/sigcatcher.c
index a9d3b7f..e202734 100644
--- a/e2fsck/sigcatcher.c
+++ b/e2fsck/sigcatcher.c
@@ -413,7 +413,7 @@ int main(int argc, char** argv)
struct sigaction sa;
char *p = 0;
int i, c;
- volatile x=0;
+ volatile int x = 0;
memset(&sa, 0, sizeof(struct sigaction));
sa.sa_sigaction = die_signal_handler;
diff --git a/e2fsck/super.c b/e2fsck/super.c
index 9495e02..04d6dde 100644
--- a/e2fsck/super.c
+++ b/e2fsck/super.c
@@ -196,7 +196,7 @@ static int release_inode_blocks(e2fsck_t ctx, ext2_ino_t ino,
__u32 count;
if (!ext2fs_inode_has_valid_blocks2(fs, EXT2_INODE(inode)))
- return 0;
+ goto release_acl;
pb.buf = block_buf + 3 * ctx->fs->blocksize;
pb.ctx = ctx;
@@ -235,7 +235,7 @@ static int release_inode_blocks(e2fsck_t ctx, ext2_ino_t ino,
if (pb.truncated_blocks)
ext2fs_iblk_sub_blocks(fs, EXT2_INODE(inode),
pb.truncated_blocks);
-
+release_acl:
blk = ext2fs_file_acl_block(fs, EXT2_INODE(inode));
if (blk) {
retval = ext2fs_adjust_ea_refcount3(fs, blk, block_buf, -1,
@@ -348,7 +348,7 @@ static int release_orphan_inode(e2fsck_t ctx, ext2_ino_t *ino, char *block_buf)
ext2fs_inode_alloc_stats2(fs, *ino, -1,
LINUX_S_ISDIR(inode.i_mode));
ctx->free_inodes++;
- inode.i_dtime = ctx->now;
+ ext2fs_set_dtime(fs, EXT2_INODE(&inode));
} else {
inode.i_dtime = 0;
}
@@ -1320,25 +1320,25 @@ void check_super_block(e2fsck_t ctx)
*/
if (((ctx->options & E2F_OPT_FORCE) || fs->super->s_checkinterval) &&
!broken_system_clock && !(ctx->flags & E2F_FLAG_TIME_INSANE) &&
- (fs->super->s_mtime > (__u32) ctx->now)) {
- pctx.num = fs->super->s_mtime;
+ (ext2fs_get_tstamp(fs->super, s_mtime) > ctx->now)) {
+ pctx.num = ext2fs_get_tstamp(fs->super, s_mtime);
problem = PR_0_FUTURE_SB_LAST_MOUNT;
- if (fs->super->s_mtime <= (__u32) ctx->now + ctx->time_fudge)
+ if ((time_t) pctx.num <= ctx->now + ctx->time_fudge)
problem = PR_0_FUTURE_SB_LAST_MOUNT_FUDGED;
if (fix_problem(ctx, problem, &pctx)) {
- fs->super->s_mtime = ctx->now;
+ ext2fs_set_tstamp(fs->super, s_mtime, ctx->now);
fs->flags |= EXT2_FLAG_DIRTY;
}
}
if (((ctx->options & E2F_OPT_FORCE) || fs->super->s_checkinterval) &&
!broken_system_clock && !(ctx->flags & E2F_FLAG_TIME_INSANE) &&
- (fs->super->s_wtime > (__u32) ctx->now)) {
- pctx.num = fs->super->s_wtime;
+ (ext2fs_get_tstamp(fs->super, s_wtime) > ctx->now)) {
+ pctx.num = ext2fs_get_tstamp(fs->super, s_wtime);
problem = PR_0_FUTURE_SB_LAST_WRITE;
- if (fs->super->s_wtime <= (__u32) ctx->now + ctx->time_fudge)
+ if ((time_t) pctx.num <= ctx->now + ctx->time_fudge)
problem = PR_0_FUTURE_SB_LAST_WRITE_FUDGED;
if (fix_problem(ctx, problem, &pctx)) {
- fs->super->s_wtime = ctx->now;
+ ext2fs_set_tstamp(fs->super, s_wtime, ctx->now);
fs->flags |= EXT2_FLAG_DIRTY;
}
}
@@ -1388,7 +1388,8 @@ void check_super_block(e2fsck_t ctx)
* away.
*/
#define FEATURE_RO_COMPAT_IGNORE (EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
- EXT4_FEATURE_RO_COMPAT_DIR_NLINK)
+ EXT4_FEATURE_RO_COMPAT_DIR_NLINK| \
+ EXT4_FEATURE_RO_COMPAT_ORPHAN_PRESENT)
#define FEATURE_INCOMPAT_IGNORE (EXT3_FEATURE_INCOMPAT_EXTENTS| \
EXT3_FEATURE_INCOMPAT_RECOVER)
diff --git a/e2fsck/unix.c b/e2fsck/unix.c
index e5b672a..de20b21 100644
--- a/e2fsck/unix.c
+++ b/e2fsck/unix.c
@@ -342,6 +342,7 @@ static int is_on_batt(void)
static void check_if_skip(e2fsck_t ctx)
{
ext2_filsys fs = ctx->fs;
+ struct ext2_super_block *sb = fs->super;
struct problem_context pctx;
const char *reason = NULL;
unsigned int reason_arg = 0;
@@ -370,7 +371,7 @@ static void check_if_skip(e2fsck_t ctx)
if (ctx->options & E2F_OPT_JOURNAL_ONLY)
goto skip;
- lastcheck = fs->super->s_lastcheck;
+ lastcheck = ext2fs_get_tstamp(sb, s_lastcheck);
if (lastcheck > ctx->now)
lastcheck -= ctx->time_fudge;
if ((fs->super->s_state & EXT2_ERROR_FS) ||
@@ -397,8 +398,9 @@ static void check_if_skip(e2fsck_t ctx)
((ctx->now - lastcheck) >=
((time_t) fs->super->s_checkinterval))) {
reason = _(" has gone %u days without being checked");
- reason_arg = (ctx->now - fs->super->s_lastcheck)/(3600*24);
- if (batt && ((ctx->now - fs->super->s_lastcheck) <
+ reason_arg = (ctx->now - ext2fs_get_tstamp(sb, s_lastcheck)) /
+ (3600*24);
+ if (batt && ((ctx->now - ext2fs_get_tstamp(sb, s_lastcheck)) <
fs->super->s_checkinterval*2))
reason = 0;
} else if (broken_system_clock && fs->super->s_checkinterval) {
@@ -457,7 +459,8 @@ static void check_if_skip(e2fsck_t ctx)
next_check = 1;
}
if (!broken_system_clock && fs->super->s_checkinterval &&
- ((ctx->now - fs->super->s_lastcheck) >= fs->super->s_checkinterval))
+ ((ctx->now - ext2fs_get_tstamp(sb, s_lastcheck)) >=
+ fs->super->s_checkinterval))
next_check = 1;
if (next_check <= 5) {
if (next_check == 1) {
@@ -2080,7 +2083,7 @@ cleanup:
} else
sb->s_state &= ~EXT2_VALID_FS;
if (!(ctx->flags & E2F_FLAG_TIME_INSANE))
- sb->s_lastcheck = ctx->now;
+ ext2fs_set_tstamp(sb, s_lastcheck, ctx->now);
sb->s_mnt_count = 0;
memset(((char *) sb) + EXT4_S_ERR_START, 0, EXT4_S_ERR_LEN);
pctx.errcode = ext2fs_set_gdt_csum(ctx->fs);
diff --git a/e2fsck/util.c b/e2fsck/util.c
index 42740d9..27b3a0d 100644
--- a/e2fsck/util.c
+++ b/e2fsck/util.c
@@ -441,7 +441,8 @@ void print_resource_track(e2fsck_t ctx, const char *desc,
} else
#elif defined HAVE_MALLINFO
/* don't use mallinfo() if over 2GB used, since it returns "int" */
- if ((char *)sbrk(0) - (char *)track->brk_start < 2LL << 30) {
+ if ((unsigned long)((char *)sbrk(0) - (char *)track->brk_start) <
+ 2UL << 30) {
struct mallinfo malloc_info = mallinfo();
log_out(ctx, _("Memory used: %lluk/%lluk (%lluk/%lluk), "),
@@ -559,29 +560,20 @@ blk64_t get_backup_sb(e2fsck_t ctx, ext2_filsys fs, const char *name,
struct ext2_super_block *sb;
io_channel io = NULL;
void *buf = NULL;
- int blocksize;
- blk64_t superblock, ret_sb = 8193;
+ unsigned int blocksize = EXT2_MIN_BLOCK_SIZE;
+ int blocksize_known = 0;
+ blk_t bpg = 0;
+ blk64_t ret_sb = 8193;
if (fs && fs->super) {
- ret_sb = (fs->super->s_blocks_per_group +
- fs->super->s_first_data_block);
- if (ctx) {
- ctx->superblock = ret_sb;
- ctx->blocksize = fs->blocksize;
- }
- return ret_sb;
+ blocksize = fs->blocksize;
+ blocksize_known = 1;
+ bpg = fs->super->s_blocks_per_group;
}
- if (ctx) {
- if (ctx->blocksize) {
- ret_sb = ctx->blocksize * 8;
- if (ctx->blocksize == 1024)
- ret_sb++;
- ctx->superblock = ret_sb;
- return ret_sb;
- }
- ctx->superblock = ret_sb;
- ctx->blocksize = 1024;
+ if (ctx && ctx->blocksize) {
+ blocksize = ctx->blocksize;
+ blocksize_known = 1;
}
if (!name || !manager)
@@ -594,28 +586,54 @@ blk64_t get_backup_sb(e2fsck_t ctx, ext2_filsys fs, const char *name,
goto cleanup;
sb = (struct ext2_super_block *) buf;
- for (blocksize = EXT2_MIN_BLOCK_SIZE;
- blocksize <= EXT2_MAX_BLOCK_SIZE ; blocksize *= 2) {
- superblock = blocksize*8;
- if (blocksize == 1024)
- superblock++;
+ for (; blocksize <= EXT2_MAX_BLOCK_SIZE; blocksize *= 2) {
+ dgrp_t grp, three = 1, five = 5, seven = 7;
+ dgrp_t limit;
+ blk_t this_bpg = bpg ? bpg : blocksize * 8;
+ blk64_t num_blocks;
+
+ if (fs && fs->super) {
+ limit = ext2fs_blocks_count(fs->super) / this_bpg;
+ } else if (ctx && ext2fs_get_device_size2(ctx->filesystem_name,
+ blocksize,
+ &num_blocks) == 0) {
+ limit = num_blocks / this_bpg;
+ } else {
+ /* If we can't figure out the device size,
+ * arbitrarily set a limit which is enough for
+ * 8 block groups or so...
+ */
+ limit = 128;
+ }
+
io_channel_set_blksize(io, blocksize);
- if (io_channel_read_blk64(io, superblock,
- -SUPERBLOCK_SIZE, buf))
- continue;
+
+ while ((grp = ext2fs_list_backups(NULL, &three,
+ &five, &seven)) <= limit) {
+ blk64_t superblock = (blk64_t)grp * this_bpg;
+
+ if (blocksize == 1024)
+ superblock++;
+ if (io_channel_read_blk64(io, superblock,
+ -SUPERBLOCK_SIZE, buf))
+ continue;
#ifdef WORDS_BIGENDIAN
- if (sb->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
- ext2fs_swap_super(sb);
+ if (sb->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
+ ext2fs_swap_super(sb);
#endif
- if ((sb->s_magic == EXT2_SUPER_MAGIC) &&
- (EXT2_BLOCK_SIZE(sb) == blocksize)) {
- ret_sb = superblock;
- if (ctx) {
- ctx->superblock = superblock;
- ctx->blocksize = blocksize;
+ if ((sb->s_magic == EXT2_SUPER_MAGIC) &&
+ ((unsigned) EXT2_BLOCK_SIZE(sb) == blocksize)) {
+ ret_sb = superblock;
+ if (ctx) {
+ ctx->superblock = superblock;
+ ctx->blocksize = blocksize;
+ }
+ goto cleanup;
}
- break;
}
+
+ if (blocksize_known)
+ break;
}
cleanup: