aboutsummaryrefslogtreecommitdiff
path: root/e2fsck
diff options
context:
space:
mode:
Diffstat (limited to 'e2fsck')
-rw-r--r--e2fsck/Android.bp4
-rw-r--r--e2fsck/Makefile.in6
-rw-r--r--e2fsck/dirinfo.c2
-rw-r--r--e2fsck/dx_dirinfo.c2
-rw-r--r--e2fsck/e2fsck.8.in66
-rw-r--r--e2fsck/e2fsck.conf.5.in26
-rw-r--r--e2fsck/e2fsck.h15
-rw-r--r--e2fsck/extents.c12
-rw-r--r--e2fsck/iscan.c11
-rw-r--r--e2fsck/jfs_user.h131
-rw-r--r--e2fsck/journal.c227
-rw-r--r--e2fsck/logfile.c5
-rw-r--r--e2fsck/pass1.c54
-rw-r--r--e2fsck/pass1b.c73
-rw-r--r--e2fsck/pass2.c68
-rw-r--r--e2fsck/pass3.c19
-rw-r--r--e2fsck/problem.c68
-rw-r--r--e2fsck/problem.h3
-rw-r--r--e2fsck/recovery.c31
-rw-r--r--e2fsck/rehash.c18
-rw-r--r--e2fsck/super.c15
-rw-r--r--e2fsck/unix.c59
-rw-r--r--e2fsck/util.c11
23 files changed, 526 insertions, 400 deletions
diff --git a/e2fsck/Android.bp b/e2fsck/Android.bp
index 22396c4e..b42de9d7 100644
--- a/e2fsck/Android.bp
+++ b/e2fsck/Android.bp
@@ -47,10 +47,6 @@ cc_defaults {
"extents.c",
"encrypted_files.c",
],
- cflags: [
- "-Wno-sign-compare",
- "-fno-strict-aliasing",
- ],
}
e2fsck_libs = [
diff --git a/e2fsck/Makefile.in b/e2fsck/Makefile.in
index 71ac3cf5..fbb7b156 100644
--- a/e2fsck/Makefile.in
+++ b/e2fsck/Makefile.in
@@ -454,9 +454,9 @@ unix.o: $(srcdir)/unix.c $(top_builddir)/lib/config.h \
$(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/e2p/e2p.h \
$(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
$(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/support/plausible.h \
- $(srcdir)/e2fsck.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
- $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/support/devname.h $(srcdir)/e2fsck.h \
+ $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.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/hashmap.h \
$(top_srcdir)/lib/ext2fs/bitops.h $(top_srcdir)/lib/support/profile.h \
$(top_builddir)/lib/support/prof_err.h $(top_srcdir)/lib/support/quotaio.h \
diff --git a/e2fsck/dirinfo.c b/e2fsck/dirinfo.c
index 49d624c5..9873e385 100644
--- a/e2fsck/dirinfo.c
+++ b/e2fsck/dirinfo.c
@@ -376,7 +376,7 @@ void e2fsck_dir_info_iter_end(e2fsck_t ctx EXT2FS_ATTR((unused)),
}
/*
- * A simple interator function
+ * A simple iterator function
*/
struct dir_info *e2fsck_dir_info_iter(e2fsck_t ctx, struct dir_info_iter *iter)
{
diff --git a/e2fsck/dx_dirinfo.c b/e2fsck/dx_dirinfo.c
index caca3e30..4b764b0f 100644
--- a/e2fsck/dx_dirinfo.c
+++ b/e2fsck/dx_dirinfo.c
@@ -143,7 +143,7 @@ ext2_ino_t e2fsck_get_num_dx_dirinfo(e2fsck_t ctx)
}
/*
- * A simple interator function
+ * A simple iterator function
*/
struct dx_dir_info *e2fsck_dx_dir_info_iter(e2fsck_t ctx, ext2_ino_t *control)
{
diff --git a/e2fsck/e2fsck.8.in b/e2fsck/e2fsck.8.in
index 019a34ec..dc6a5856 100644
--- a/e2fsck/e2fsck.8.in
+++ b/e2fsck/e2fsck.8.in
@@ -42,10 +42,10 @@ e2fsck \- check a Linux ext2/ext3/ext4 file system
.SH DESCRIPTION
.B e2fsck
is used to check the ext2/ext3/ext4 family of file systems.
-For ext3 and ext4 filesystems that use a journal, if the system has been
+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 filesystems that use journalling,
+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.
@@ -57,7 +57,7 @@ or file containing the file system.
.PP
Note that in general it is not safe to run
.B e2fsck
-on mounted filesystems. The only exception is if the
+on mounted file systems. The only exception is if the
.B \-n
option is specified, and
.BR \-c ,
@@ -68,9 +68,9 @@ options are
.I not
specified. However, even if it is safe to do so, the results printed by
.B e2fsck
-are not valid if the filesystem is mounted. If
+are not valid if the file system is mounted. If
.B e2fsck
-asks whether or not you should check a filesystem which is mounted,
+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
they are doing should consider answering this question in any other way.
.PP
@@ -82,7 +82,7 @@ is run in interactive mode (meaning that none of
or
.BR \-p
are specified), the program will ask the user to fix each problem found in the
-filesystem. A response of 'y' will fix the error; 'n' will leave the error
+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.
@@ -102,7 +102,7 @@ specified by
.IR superblock .
This option is normally used when the primary superblock has been
corrupted. The location of backup superblocks is dependent on the
-filesystem's blocksize, the number of blocks per group, and features
+file system's blocksize, the number of blocks per group, and features
such as
.BR sparse_super .
.IP
@@ -112,15 +112,15 @@ program using the
.B \-n
option to print out where the superblocks exist, supposing
.B mke2fs
-is supplied with arguments that are consistent with the filesystem's layout
+is supplied with arguments that are consistent with the file system's layout
(e.g. blocksize, blocks per group,
.BR sparse_super ,
etc.).
.IP
If an alternative superblock is specified and
-the filesystem is not opened read-only, e2fsck will make sure that the
+the file system is not opened read-only, e2fsck will make sure that the
primary superblock is updated appropriately upon completion of the
-filesystem check.
+file system check.
.TP
.BI \-B " blocksize"
Normally,
@@ -149,7 +149,7 @@ using a non-destructive read-write test.
This option causes
.B e2fsck
to write completion information to the specified file descriptor
-so that the progress of the filesystem
+so that the progress of the file system
check can be monitored. This option is typically used by programs
which are running
.BR e2fsck .
@@ -168,10 +168,10 @@ Print debugging output (useless unless you are debugging
.BR e2fsck ).
.TP
.B \-D
-Optimize directories in filesystem. This option causes e2fsck to
-try to optimize all directories, either by reindexing them if the
-filesystem supports directory indexing, or by sorting and compressing
-directories for smaller directories, or for filesystems using
+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
+directories for smaller directories, or for file systems using
traditional linear directories.
.IP
Even without the
@@ -183,7 +183,7 @@ directory indexing is enabled and a directory is not indexed and would
benefit from being indexed, or if the index structures are corrupted
and need to be rebuilt. The
.B \-D
-option forces all directories in the filesystem to be optimized. This can
+option forces all directories in the file system to be optimized. This can
sometimes make them a little smaller and slightly faster to search, but
in practice, you should rarely need to use this option.
.IP
@@ -201,7 +201,7 @@ following options are supported:
.BI ea_ver= extended_attribute_version
Set the version of the extended attribute blocks which
.B e2fsck
-will require while checking the filesystem. The version number may
+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
@@ -210,13 +210,13 @@ or repairs.
.TP
.BI fragcheck
During pass 1, print a detailed report of any discontiguous blocks for
-files in the filesystem.
+files in the file system.
.TP
.BI discard
Attempt to discard free blocks and unused inode blocks after the full
-filesystem check (discarding blocks is useful on solid state devices and sparse
+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
-filesystem has been fully checked and only if it does not contain recognizable
+file system has been fully checked and only if it does not contain recognizable
errors. However there might be cases where
.B e2fsck
does not fully recognize a problem and hence in this case this
@@ -255,7 +255,7 @@ optimization. This is the default unless otherwise specified in
.BI 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 filesystem); if this amount is more
+tables (typically 4MiB 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
@@ -269,13 +269,13 @@ options.
.TP
.BI check_encoding
Force verification of encoded filenames in case-insensitive directories.
-This is the default mode if the filesystem has the strict flag enabled.
+This is the default mode if the file system has the strict flag enabled.
.TP
.BI unshare_blocks
-If the filesystem has shared blocks, with the shared blocks read-only feature
+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.
-If the filesystem does not have the read-only feature bit, but has shared
+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
option, if there is no free space to clone blocks, there is no prompt to
delete files and instead the operation will fail.
@@ -290,13 +290,13 @@ be non-zero.
Force checking even if the file system seems clean.
.TP
.B \-F
-Flush the filesystem device's buffer caches before beginning. Only
+Flush the file system device's buffer caches before beginning. Only
really useful for doing
.B e2fsck
time trials.
@JDEV@.TP
@JDEV@.BI \-j " external-journal"
-@JDEV@Set the pathname where the external-journal for this filesystem can be
+@JDEV@Set the pathname where the external-journal for this file system can be
@JDEV@found.
.TP
.BI \-k
@@ -314,9 +314,9 @@ to the list of bad blocks. The format of this file is the same as the
one generated by the
.BR badblocks (8)
program. Note that the block numbers are based on the blocksize
-of the filesystem. Hence,
+of the file system. Hence,
.BR badblocks (8)
-must be given the blocksize of the filesystem in order to obtain correct
+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
option to
@@ -334,7 +334,7 @@ option, except the bad blocks list is cleared before the blocks listed
in the file are added to the bad blocks list.)
.TP
.B \-n
-Open the filesystem read-only, and assume an answer of `no' to all
+Open the file system read-only, and assume an answer of `no' to all
questions. Allows
.B e2fsck
to be used non-interactively. This option
@@ -348,7 +348,7 @@ options.
Automatically repair ("preen") the file system. This option will cause
.B e2fsck
to automatically
-fix any filesystem problems that can be safely fixed without human
+fix any file system problems that can be safely fixed without human
intervention. If
.B e2fsck
discovers a problem which may require the system administrator
@@ -439,7 +439,7 @@ This signal causes
to stop displaying a completion bar or emitting progress information.
.SH REPORTING BUGS
Almost any piece of software will have bugs. If you manage to find a
-filesystem which causes
+file system which causes
.B e2fsck
to crash, or which
.B e2fsck
@@ -460,7 +460,7 @@ environment variable to
.B C
so that the transcript of e2fsck's output will be useful to me.)
If you
-have a writable filesystem where the transcript can be stored, the
+have a writable file system where the transcript can be stored, the
.BR script (1)
program is a handy way to save the output of
.B e2fsck
@@ -481,7 +481,7 @@ command will allow you to extract the contents of the directory inode,
which can sent to me after being first run through
.BR uuencode (1).
The most useful data you can send to help reproduce
-the bug is a compressed raw image dump of the filesystem, generated using
+the bug is a compressed raw image dump of the file system, generated using
.BR e2image (8).
See the
.BR e2image (8)
diff --git a/e2fsck/e2fsck.conf.5.in b/e2fsck/e2fsck.conf.5.in
index 48ad0fde..e82610d3 100644
--- a/e2fsck/e2fsck.conf.5.in
+++ b/e2fsck/e2fsck.conf.5.in
@@ -11,7 +11,7 @@ is the configuration file for
.BR e2fsck (8).
It controls the default behavior of
.BR e2fsck (8)
-while it is checking ext2, ext3, or ext4 filesystems.
+while it is checking ext2, ext3, or ext4 file systems.
.PP
The
.I e2fsck.conf
@@ -77,7 +77,7 @@ provided by the user.
.TP
.I [problems]
This stanza allows the administrator to reconfigure how e2fsck handles
-various filesystem inconsistencies.
+various file system inconsistencies.
@TDB_MAN_COMMENT@.TP
@TDB_MAN_COMMENT@.I [scratch_files]
@TDB_MAN_COMMENT@This stanza controls when e2fsck will attempt to use
@@ -89,7 +89,7 @@ stanza.
.TP
.I allow_cancellation
If this relation is set to a boolean value of true, then if the user
-interrupts e2fsck using ^C, and the filesystem is not explicitly flagged
+interrupts e2fsck using ^C, and the file system is not explicitly flagged
as containing errors, e2fsck will exit with an exit status of 0 instead
of 32. This setting defaults to false.
.TP
@@ -144,12 +144,12 @@ we changed the default, we also renamed this boolean relation to
This boolean relation controls whether or not
.BR e2fsck (8)
will offer to clear
-the test_fs flag if the ext4 filesystem is available on the system. It
+the test_fs flag if the ext4 file system is available on the system. It
defaults to true.
.TP
.I defer_check_on_battery
This boolean relation controls whether or not the interval between
-filesystem checks (either based on time or number of mounts) should
+file system checks (either based on time or number of mounts) should
be doubled if the system is running on battery. This setting defaults to
true.
.TP
@@ -248,7 +248,7 @@ for more details.
Use this amount of memory to read in metadata blocks ahead of the main checking
thread. Setting this value to zero disables readahead entirely. By default,
this is set the size of two block groups' inode tables (typically 4MiB on a
-regular ext4 filesystem); if this amount is more than 1/50th of total physical
+regular ext4 file system); if this amount is more than 1/50th of total physical
memory, readahead is disabled.
.TP
.I report_features
@@ -298,12 +298,12 @@ not be making changes to this section without referring to source code.
Within each problem code's subsection, the following tags may be used:
.TP
.I description
-This relation allows the message which is printed when this filesystem
+This relation allows the message which is printed when this file system
inconsistency is detected to be overridden.
.TP
.I preen_ok
This boolean relation overrides the default behavior controlling
-whether this filesystem problem should be automatically fixed when
+whether this file system problem should be automatically fixed when
.B e2fsck
is running in preen mode.
.TP
@@ -314,7 +314,7 @@ parameter (set in the options section) for this particular problem.
.TP
.I no_ok
This boolean relation overrides the default behavior determining
-whether or not the filesystem will be marked as inconsistent if the user
+whether or not the file system will be marked as inconsistent if the user
declines to fix the reported problem.
.TP
.I no_default
@@ -323,14 +323,14 @@ problem (or question) should be "no".
.TP
.I preen_nomessage
This boolean relation overrides the default behavior controlling
-whether or not the description for this filesystem problem should
+whether or not the description for this file system problem should
be suppressed when
.B e2fsck
is running in preen mode.
.TP
.I no_nomsg
This boolean relation overrides the default behavior controlling
-whether or not the description for this filesystem problem should
+whether or not the description for this file system problem should
be suppressed when a problem forced not to be fixed, either because
.B e2fsck
is run with the
@@ -367,7 +367,7 @@ data structure, such as pruning an extent tree.
@TDB_MAN_COMMENT@.TP
@TDB_MAN_COMMENT@.I numdirs_threshold
@TDB_MAN_COMMENT@If this relation is set, then in-memory data structures
-@TDB_MAN_COMMENT@will be used if the number of directories in the filesystem
+@TDB_MAN_COMMENT@will be used if the number of directories in the file system
@TDB_MAN_COMMENT@are fewer than amount specified.
@TDB_MAN_COMMENT@.TP
@TDB_MAN_COMMENT@.I dirinfo
@@ -453,7 +453,7 @@ The last two digits of the current year (00..99)
The current year (i.e., 2012).
.SH EXAMPLES
The following recipe will prevent e2fsck from aborting during the boot
-process when a filesystem contains orphaned files. (Of course, this is
+process when a file system contains orphaned files. (Of course, this is
not always a good idea, since critical files that are needed for the
security of the system could potentially end up in lost+found, and
starting the system without first having a system administrator check
diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h
index 15d043ee..b8caa43b 100644
--- a/e2fsck/e2fsck.h
+++ b/e2fsck/e2fsck.h
@@ -68,7 +68,14 @@
#endif
#include "support/quotaio.h"
+#if __GNUC_PREREQ (4, 6)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-function"
+#endif
#include "ext2fs/fast_commit.h"
+#if __GNUC_PREREQ (4, 6)
+#pragma GCC diagnostic pop
+#endif
/*
* Exit codes used by fsck-type programs
@@ -226,10 +233,10 @@ typedef struct ea_refcount *ext2_refcount_t;
*/
typedef struct e2fsck_struct *e2fsck_t;
-#define MAX_EXTENT_DEPTH_COUNT 5
+#define MAX_EXTENT_DEPTH_COUNT 8
/*
- * This strucutre is used to manage the list of extents in a file. Placing
+ * This structure is used to manage the list of extents in a file. Placing
* it here since this is used by fast_commit.h.
*/
struct extent_list {
@@ -247,9 +254,9 @@ struct e2fsck_fc_replay_state {
struct extent_list fc_extent_list;
int fc_replay_num_tags;
int fc_replay_expected_off;
- int fc_current_pass;
+ enum passtype fc_current_pass;
int fc_cur_tag;
- int fc_crc;
+ unsigned int fc_crc;
__u16 fc_super_state;
};
diff --git a/e2fsck/extents.c b/e2fsck/extents.c
index 0274e053..70798f34 100644
--- a/e2fsck/extents.c
+++ b/e2fsck/extents.c
@@ -196,7 +196,7 @@ static int find_blocks(ext2_filsys fs, blk64_t *blocknr, e2_blkcnt_t blockcnt,
return 0;
}
-errcode_t rewrite_extent_replay(e2fsck_t ctx, struct extent_list *list,
+static errcode_t rewrite_extent_replay(e2fsck_t ctx, struct extent_list *list,
struct ext2_inode_large *inode)
{
errcode_t retval;
@@ -526,7 +526,8 @@ errcode_t e2fsck_check_rebuild_extents(e2fsck_t ctx, ext2_ino_t ino,
*/
if (info.curr_entry == 1 &&
!(extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT) &&
- !eti.force_rebuild) {
+ !eti.force_rebuild &&
+ info.curr_level < MAX_EXTENT_DEPTH_COUNT) {
struct extent_tree_level *etl;
etl = eti.ext_info + info.curr_level;
@@ -580,6 +581,13 @@ errcode_t e2fsck_should_rebuild_extents(e2fsck_t ctx,
extents_per_block = (ctx->fs->blocksize -
sizeof(struct ext3_extent_header)) /
sizeof(struct ext3_extent);
+
+ /* If the extent tree is too deep, then rebuild it. */
+ if (info->max_depth > MAX_EXTENT_DEPTH_COUNT-1) {
+ pctx->blk = info->max_depth;
+ op = PR_1E_CAN_COLLAPSE_EXTENT_TREE;
+ goto rebuild;
+ }
/*
* If we can consolidate a level or shorten the tree, schedule the
* extent tree to be rebuilt.
diff --git a/e2fsck/iscan.c b/e2fsck/iscan.c
index 607e4752..33c6a4cd 100644
--- a/e2fsck/iscan.c
+++ b/e2fsck/iscan.c
@@ -109,7 +109,16 @@ void print_resource_track(const char *desc,
printf("%s: ", desc);
#define kbytes(x) (((unsigned long long)(x) + 1023) / 1024)
-#ifdef HAVE_MALLINFO
+#ifdef HAVE_MALLINFO2
+ if (1) {
+ struct mallinfo2 malloc_info = mallinfo2();
+
+ printf("Memory used: %lluk/%lluk (%lluk/%lluk), ",
+ kbytes(malloc_info.arena), kbytes(malloc_info.hblkhd),
+ kbytes(malloc_info.uordblks),
+ kbytes(malloc_info.fordblks));
+ } 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) {
struct mallinfo malloc_info = mallinfo();
diff --git a/e2fsck/jfs_user.h b/e2fsck/jfs_user.h
index 3b91765c..5928a8a8 100644
--- a/e2fsck/jfs_user.h
+++ b/e2fsck/jfs_user.h
@@ -82,24 +82,9 @@ struct kdev_s {
#define buffer_req(bh) 1
#define do_readahead(journal, start) do {} while (0)
-typedef struct kmem_cache {
- int object_length;
-} kmem_cache_t;
-
-#define kmem_cache_alloc(cache, flags) malloc((cache)->object_length)
-#define kmem_cache_free(cache, obj) free(obj)
-#define kmem_cache_create(name, len, a, b, c) do_cache_create(len)
-#define kmem_cache_destroy(cache) do_cache_destroy(cache)
-#define kmalloc(len, flags) malloc(len)
-#define kfree(p) free(p)
-
-static inline void *kmalloc_array(unsigned n, unsigned size,
- int flags EXT2FS_ATTR((unused)))
-{
- if (n && (~0U)/n < size)
- return NULL;
- return malloc(n * size);
-}
+struct kmem_cache {
+ unsigned int object_size;
+};
#define cond_resched() do { } while (0)
@@ -115,12 +100,25 @@ static inline void *kmalloc_array(unsigned n, unsigned size,
* functions.
*/
#ifdef NO_INLINE_FUNCS
-extern kmem_cache_t *do_cache_create(int len);
-extern void do_cache_destroy(kmem_cache_t *cache);
+extern struct kmem_cache *kmem_cache_create(const char *name,
+ unsigned int size,
+ unsigned int align,
+ unsigned int flags,
+ void (*ctor)(void *));
+extern void kmem_cache_destroy(struct kmem_cache *s);
+extern void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags);
+extern void kmem_cache_free(struct kmem_cache *s, void *objp);
+extern void *kmalloc(size_t size, gfp_t flags);
+extern void kfree(const void *objp);
extern size_t journal_tag_bytes(journal_t *journal);
extern __u32 __hash_32(__u32 val);
extern __u32 hash_32(__u32 val, unsigned int bits);
extern __u32 hash_64(__u64 val, unsigned int bits);
+extern void *kmalloc_array(unsigned n, unsigned size, int flags);
+extern __u32 jbd2_chksum(journal_t *j, __u32 crc, const void *address,
+ unsigned int length);
+extern void jbd2_descriptor_block_csum_set(journal_t *j,
+ struct buffer_head *bh);
#endif
#if (defined(E2FSCK_INCLUDE_INLINE_FUNCS) || !defined(NO_INLINE_FUNCS))
@@ -142,19 +140,56 @@ extern __u32 hash_64(__u64 val, unsigned int bits);
#endif /* __STDC_VERSION__ >= 199901L */
#endif /* E2FSCK_INCLUDE_INLINE_FUNCS */
-_INLINE_ kmem_cache_t *do_cache_create(int len)
+_INLINE_ struct kmem_cache *
+kmem_cache_create(const char *name EXT2FS_ATTR((unused)),
+ unsigned int size,
+ unsigned int align EXT2FS_ATTR((unused)),
+ unsigned int flags EXT2FS_ATTR((unused)),
+ void (*ctor)(void *) EXT2FS_ATTR((unused)))
{
- kmem_cache_t *new_cache;
+ struct kmem_cache *new_cache;
new_cache = malloc(sizeof(*new_cache));
if (new_cache)
- new_cache->object_length = len;
+ new_cache->object_size = size;
return new_cache;
}
-_INLINE_ void do_cache_destroy(kmem_cache_t *cache)
+_INLINE_ void kmem_cache_destroy(struct kmem_cache *s)
+{
+ free(s);
+}
+
+_INLINE_ void *kmem_cache_alloc(struct kmem_cache *cachep,
+ gfp_t flags EXT2FS_ATTR((unused)))
+{
+ return malloc(cachep->object_size);
+}
+
+_INLINE_ void kmem_cache_free(struct kmem_cache *s EXT2FS_ATTR((unused)),
+ void *objp)
+{
+ free(objp);
+}
+
+_INLINE_ void *kmalloc(size_t size, gfp_t flags EXT2FS_ATTR((unused)))
{
- free(cache);
+ return malloc(size);
+}
+
+_INLINE_ void kfree(const void *objp)
+{
+#ifdef HAVE_INTPTR_T
+ /*
+ * Work around a botch in the C standard, which triggers
+ * compiler warnings. For better or for worse, the kernel
+ * uses const void * for kfree, while the C standard mandates
+ * the use of void *. See: https://yarchive.net/comp/const.html
+ */
+ free((void *)(intptr_t)objp);
+#else
+ free((void *)objp);
+#endif
}
/* generic hashing taken from the Linux kernel */
@@ -183,6 +218,36 @@ _INLINE_ __u32 hash_64(__u64 val, unsigned int bits)
}
}
+_INLINE_ void *kmalloc_array(unsigned n, unsigned size,
+ int flags EXT2FS_ATTR((unused)))
+{
+ if (n && (~0U)/n < size)
+ return NULL;
+ return malloc(n * size);
+}
+
+_INLINE_ __u32 jbd2_chksum(journal_t *j EXT2FS_ATTR((unused)),
+ __u32 crc, const void *address,
+ unsigned int length)
+{
+ return ext2fs_crc32c_le(crc, address, length);
+}
+
+_INLINE_ void jbd2_descriptor_block_csum_set(journal_t *j,
+ struct buffer_head *bh)
+{
+ struct jbd2_journal_block_tail *tail;
+ __u32 csum;
+
+ if (!jbd2_journal_has_csum_v2or3(j))
+ return;
+
+ tail = (struct jbd2_journal_block_tail *)(bh->b_data + j->j_blocksize -
+ sizeof(struct jbd2_journal_block_tail));
+ tail->t_checksum = 0;
+ csum = jbd2_chksum(j, j->j_csum_seed, bh->b_data, j->j_blocksize);
+ tail->t_checksum = cpu_to_be32(csum);
+}
#undef _INLINE_
#endif
@@ -236,22 +301,6 @@ extern e2fsck_t e2fsck_global_ctx; /* Try your very best not to use this! */
#define EFSCORRUPTED EXT2_ET_FILESYSTEM_CORRUPTED
#endif
-static inline void jbd2_descriptor_block_csum_set(journal_t *j,
- struct buffer_head *bh)
-{
- struct jbd2_journal_block_tail *tail;
- __u32 csum;
-
- if (!jbd2_journal_has_csum_v2or3(j))
- return;
-
- tail = (struct jbd2_journal_block_tail *)(bh->b_data + j->j_blocksize -
- sizeof(struct jbd2_journal_block_tail));
- tail->t_checksum = 0;
- csum = jbd2_chksum(j, j->j_csum_seed, bh->b_data, j->j_blocksize);
- tail->t_checksum = cpu_to_be32(csum);
-}
-
/* recovery.c */
extern int jbd2_journal_recover (journal_t *journal);
extern int jbd2_journal_skip_recovery (journal_t *);
diff --git a/e2fsck/journal.c b/e2fsck/journal.c
index 0aeaf416..8ae89bf7 100644
--- a/e2fsck/journal.c
+++ b/e2fsck/journal.c
@@ -281,11 +281,11 @@ static int ext4_fc_replay_scan(journal_t *j, struct buffer_head *bh,
e2fsck_t ctx = j->j_fs_dev->k_ctx;
struct e2fsck_fc_replay_state *state;
int ret = JBD2_FC_REPLAY_CONTINUE;
- struct ext4_fc_add_range *ext;
- struct ext4_fc_tl *tl;
- struct ext4_fc_tail *tail;
- __u8 *start, *end;
- struct ext4_fc_head *head;
+ struct ext4_fc_add_range ext;
+ struct ext4_fc_tl tl;
+ struct ext4_fc_tail tail;
+ __u8 *start, *cur, *end, *val;
+ struct ext4_fc_head head;
struct ext2fs_extent ext2fs_ex = {0};
state = &ctx->fc_replay_state;
@@ -310,14 +310,18 @@ static int ext4_fc_replay_scan(journal_t *j, struct buffer_head *bh,
}
state->fc_replay_expected_off++;
- fc_for_each_tl(start, end, tl) {
+ for (cur = start; cur < end; cur = cur + le16_to_cpu(tl.fc_len) + sizeof(tl)) {
+ memcpy(&tl, cur, sizeof(tl));
+ val = cur + sizeof(tl);
+
jbd_debug(3, "Scan phase, tag:%s, blk %lld\n",
- tag2str(le16_to_cpu(tl->fc_tag)), bh->b_blocknr);
- switch (le16_to_cpu(tl->fc_tag)) {
+ tag2str(le16_to_cpu(tl.fc_tag)), bh->b_blocknr);
+ switch (le16_to_cpu(tl.fc_tag)) {
case EXT4_FC_TAG_ADD_RANGE:
- ext = (struct ext4_fc_add_range *)ext4_fc_tag_val(tl);
- ret = ext2fs_decode_extent(&ext2fs_ex, (void *)&ext->fc_ex,
- sizeof(ext->fc_ex));
+ memcpy(&ext, val, sizeof(ext));
+ ret = ext2fs_decode_extent(&ext2fs_ex,
+ (void *)&ext.fc_ex,
+ sizeof(ext.fc_ex));
if (ret)
ret = JBD2_FC_REPLAY_STOP;
else
@@ -330,21 +334,20 @@ static int ext4_fc_replay_scan(journal_t *j, struct buffer_head *bh,
case EXT4_FC_TAG_INODE:
case EXT4_FC_TAG_PAD:
state->fc_cur_tag++;
- state->fc_crc = jbd2_chksum(j, state->fc_crc, tl,
- sizeof(*tl) + ext4_fc_tag_len(tl));
+ state->fc_crc = jbd2_chksum(j, state->fc_crc, cur,
+ sizeof(tl) + ext4_fc_tag_len(&tl));
break;
case EXT4_FC_TAG_TAIL:
state->fc_cur_tag++;
- tail = (struct ext4_fc_tail *)ext4_fc_tag_val(tl);
- state->fc_crc = jbd2_chksum(j, state->fc_crc, tl,
- sizeof(*tl) +
+ memcpy(&tail, val, sizeof(tail));
+ state->fc_crc = jbd2_chksum(j, state->fc_crc, cur,
+ sizeof(tl) +
offsetof(struct ext4_fc_tail,
fc_crc));
jbd_debug(1, "tail tid %d, expected %d\n",
- le32_to_cpu(tail->fc_tid),
- expected_tid);
- if (le32_to_cpu(tail->fc_tid) == expected_tid &&
- le32_to_cpu(tail->fc_crc) == state->fc_crc) {
+ le32_to_cpu(tail.fc_tid), expected_tid);
+ if (le32_to_cpu(tail.fc_tid) == expected_tid &&
+ le32_to_cpu(tail.fc_crc) == state->fc_crc) {
state->fc_replay_num_tags = state->fc_cur_tag;
} else {
ret = state->fc_replay_num_tags ?
@@ -353,19 +356,19 @@ static int ext4_fc_replay_scan(journal_t *j, struct buffer_head *bh,
state->fc_crc = 0;
break;
case EXT4_FC_TAG_HEAD:
- head = (struct ext4_fc_head *)ext4_fc_tag_val(tl);
- if (le32_to_cpu(head->fc_features) &
- ~EXT4_FC_SUPPORTED_FEATURES) {
+ memcpy(&head, val, sizeof(head));
+ if (le32_to_cpu(head.fc_features) &
+ ~EXT4_FC_SUPPORTED_FEATURES) {
ret = -EOPNOTSUPP;
break;
}
- if (le32_to_cpu(head->fc_tid) != expected_tid) {
+ if (le32_to_cpu(head.fc_tid) != expected_tid) {
ret = -EINVAL;
break;
}
state->fc_cur_tag++;
- state->fc_crc = jbd2_chksum(j, state->fc_crc, tl,
- sizeof(*tl) + ext4_fc_tag_len(tl));
+ state->fc_crc = jbd2_chksum(j, state->fc_crc, cur,
+ sizeof(tl) + ext4_fc_tag_len(&tl));
break;
default:
ret = state->fc_replay_num_tags ?
@@ -416,8 +419,8 @@ static int make_room(struct extent_list *list, int i)
static int ex_compar(const void *arg1, const void *arg2)
{
- struct ext2fs_extent *ex1 = (struct ext2fs_extent *)arg1;
- struct ext2fs_extent *ex2 = (struct ext2fs_extent *)arg2;
+ const struct ext2fs_extent *ex1 = (const struct ext2fs_extent *)arg1;
+ const struct ext2fs_extent *ex2 = (const struct ext2fs_extent *)arg2;
if (ex1->e_lblk < ex2->e_lblk)
return -1;
@@ -428,8 +431,8 @@ static int ex_compar(const void *arg1, const void *arg2)
static int ex_len_compar(const void *arg1, const void *arg2)
{
- struct ext2fs_extent *ex1 = (struct ext2fs_extent *)arg1;
- struct ext2fs_extent *ex2 = (struct ext2fs_extent *)arg2;
+ const struct ext2fs_extent *ex1 = (const struct ext2fs_extent *)arg1;
+ const struct ext2fs_extent *ex2 = (const struct ext2fs_extent *)arg2;
if (ex1->e_len < ex2->e_len)
return 1;
@@ -442,7 +445,7 @@ static int ex_len_compar(const void *arg1, const void *arg2)
static void ex_sort_and_merge(struct extent_list *list)
{
- int i, j;
+ unsigned int i, j;
if (list->count < 2)
return;
@@ -461,6 +464,9 @@ static void ex_sort_and_merge(struct extent_list *list)
}
}
+ if (list->count == 0)
+ return;
+
/* Now sort by logical offset */
qsort(list->extents, list->count, sizeof(list->extents[0]),
ex_compar);
@@ -487,8 +493,8 @@ static void ex_sort_and_merge(struct extent_list *list)
static int ext4_modify_extent_list(e2fsck_t ctx, struct extent_list *list,
struct ext2fs_extent *ex, int del)
{
- int ret;
- int i, offset;
+ int ret, offset;
+ unsigned int i;
struct ext2fs_extent add_ex = *ex;
/* First let's create a hole from ex->e_lblk of length ex->e_len */
@@ -572,7 +578,7 @@ static int ext4_del_extent_from_list(e2fsck_t ctx, struct extent_list *list,
return ext4_modify_extent_list(ctx, list, ex, 1 /* delete */);
}
-static int ext4_fc_read_extents(e2fsck_t ctx, int ino)
+static int ext4_fc_read_extents(e2fsck_t ctx, ext2_ino_t ino)
{
struct extent_list *extent_list = &ctx->fc_replay_state.fc_extent_list;
@@ -591,7 +597,7 @@ static int ext4_fc_read_extents(e2fsck_t ctx, int ino)
* for the inode so that we can flush all of them at once and it also saves us
* from continuously growing and shrinking the extent tree.
*/
-static void ext4_fc_flush_extents(e2fsck_t ctx, int ino)
+static void ext4_fc_flush_extents(e2fsck_t ctx, ext2_ino_t ino)
{
struct extent_list *extent_list = &ctx->fc_replay_state.fc_extent_list;
@@ -604,56 +610,65 @@ static void ext4_fc_flush_extents(e2fsck_t ctx, int ino)
/* Helper struct for dentry replay routines */
struct dentry_info_args {
- int parent_ino, dname_len, ino, inode_len;
+ ext2_ino_t parent_ino;
+ int dname_len;
+ ext2_ino_t ino;
char *dname;
};
-static inline void tl_to_darg(struct dentry_info_args *darg,
- struct ext4_fc_tl *tl)
+static inline int tl_to_darg(struct dentry_info_args *darg,
+ struct ext4_fc_tl *tl, __u8 *val)
{
- struct ext4_fc_dentry_info *fcd;
- int tag = le16_to_cpu(tl->fc_tag);
+ struct ext4_fc_dentry_info fcd;
- fcd = (struct ext4_fc_dentry_info *)ext4_fc_tag_val(tl);
+ memcpy(&fcd, val, sizeof(fcd));
- darg->parent_ino = le32_to_cpu(fcd->fc_parent_ino);
- darg->ino = le32_to_cpu(fcd->fc_ino);
- darg->dname = (char *) fcd->fc_dname;
+ darg->parent_ino = le32_to_cpu(fcd.fc_parent_ino);
+ darg->ino = le32_to_cpu(fcd.fc_ino);
darg->dname_len = ext4_fc_tag_len(tl) -
sizeof(struct ext4_fc_dentry_info);
darg->dname = malloc(darg->dname_len + 1);
- memcpy(darg->dname, fcd->fc_dname, darg->dname_len);
+ if (!darg->dname)
+ return -ENOMEM;
+ memcpy(darg->dname,
+ val + sizeof(struct ext4_fc_dentry_info),
+ darg->dname_len);
darg->dname[darg->dname_len] = 0;
- jbd_debug(1, "%s: %s, ino %d, parent %d\n",
- tag == EXT4_FC_TAG_CREAT ? "create" :
- (tag == EXT4_FC_TAG_LINK ? "link" :
- (tag == EXT4_FC_TAG_UNLINK ? "unlink" : "error")),
- darg->dname, darg->ino, darg->parent_ino);
+ jbd_debug(1, "%s: %s, ino %u, parent %u\n",
+ le16_to_cpu(tl->fc_tag) == EXT4_FC_TAG_CREAT ? "create" :
+ (le16_to_cpu(tl->fc_tag) == EXT4_FC_TAG_LINK ? "link" :
+ (le16_to_cpu(tl->fc_tag) == EXT4_FC_TAG_UNLINK ? "unlink" :
+ "error")), darg->dname, darg->ino, darg->parent_ino);
+ return 0;
}
-static int ext4_fc_handle_unlink(e2fsck_t ctx, struct ext4_fc_tl *tl)
+static int ext4_fc_handle_unlink(e2fsck_t ctx, struct ext4_fc_tl *tl, __u8 *val)
{
struct dentry_info_args darg;
int ret;
- tl_to_darg(&darg, tl);
+ ret = tl_to_darg(&darg, tl, val);
+ if (ret)
+ return ret;
ext4_fc_flush_extents(ctx, darg.ino);
- ret = errcode_to_errno(
- ext2fs_unlink(ctx->fs, darg.parent_ino,
- darg.dname, darg.ino, 0));
+ ret = errcode_to_errno(ext2fs_unlink(ctx->fs, darg.parent_ino,
+ darg.dname, darg.ino, 0));
/* It's okay if the above call fails */
free(darg.dname);
+
return ret;
}
-static int ext4_fc_handle_link_and_create(e2fsck_t ctx, struct ext4_fc_tl *tl)
+static int ext4_fc_handle_link_and_create(e2fsck_t ctx, struct ext4_fc_tl *tl, __u8 *val)
{
struct dentry_info_args darg;
ext2_filsys fs = ctx->fs;
struct ext2_inode_large inode_large;
int ret, filetype, mode;
- tl_to_darg(&darg, tl);
+ ret = tl_to_darg(&darg, tl, val);
+ if (ret)
+ return ret;
ext4_fc_flush_extents(ctx, 0);
ret = errcode_to_errno(ext2fs_read_inode(fs, darg.ino,
(struct ext2_inode *)&inode_large));
@@ -719,21 +734,32 @@ static void ext4_fc_replay_fixup_iblocks(struct ext2_inode_large *ondisk_inode,
}
}
-static int ext4_fc_handle_inode(e2fsck_t ctx, struct ext4_fc_tl *tl)
+static int ext4_fc_handle_inode(e2fsck_t ctx, __u8 *val)
{
int ino, inode_len = EXT2_GOOD_OLD_INODE_SIZE;
struct ext2_inode_large *inode = NULL, *fc_inode = NULL;
- struct ext4_fc_inode *fc_inode_val;
+ __le32 fc_ino;
+ __u8 *fc_raw_inode;
errcode_t err;
blk64_t blks;
- fc_inode_val = (struct ext4_fc_inode *)ext4_fc_tag_val(tl);
- ino = le32_to_cpu(fc_inode_val->fc_ino);
+ memcpy(&fc_ino, val, sizeof(fc_ino));
+ fc_raw_inode = val + sizeof(fc_ino);
+ ino = le32_to_cpu(fc_ino);
+
+ if (EXT2_INODE_SIZE(ctx->fs->super) > EXT2_GOOD_OLD_INODE_SIZE) {
+ __u16 extra_isize = ext2fs_le16_to_cpu(
+ ((struct ext2_inode_large *)fc_raw_inode)->i_extra_isize);
- if (EXT2_INODE_SIZE(ctx->fs->super) > EXT2_GOOD_OLD_INODE_SIZE)
- inode_len += ext2fs_le16_to_cpu(
- ((struct ext2_inode_large *)fc_inode_val->fc_raw_inode)
- ->i_extra_isize);
+ if ((extra_isize < (sizeof(inode->i_extra_isize) +
+ sizeof(inode->i_checksum_hi))) ||
+ (extra_isize > (EXT2_INODE_SIZE(ctx->fs->super) -
+ EXT2_GOOD_OLD_INODE_SIZE))) {
+ err = EFSCORRUPTED;
+ goto out;
+ }
+ inode_len += extra_isize;
+ }
err = ext2fs_get_mem(inode_len, &inode);
if (err)
goto out;
@@ -746,12 +772,9 @@ static int ext4_fc_handle_inode(e2fsck_t ctx, struct ext4_fc_tl *tl)
inode_len);
if (err)
goto out;
+ memcpy(fc_inode, fc_raw_inode, inode_len);
#ifdef WORDS_BIGENDIAN
- ext2fs_swap_inode_full(ctx->fs, fc_inode,
- (struct ext2_inode_large *)fc_inode_val->fc_raw_inode,
- 0, sizeof(*inode));
-#else
- memcpy(fc_inode, fc_inode_val->fc_raw_inode, inode_len);
+ ext2fs_swap_inode_full(ctx->fs, fc_inode, fc_inode, 0, inode_len);
#endif
memcpy(inode, fc_inode, offsetof(struct ext2_inode_large, i_block));
memcpy(&inode->i_generation, &fc_inode->i_generation,
@@ -782,14 +805,15 @@ out:
/*
* Handle add extent replay tag.
*/
-static int ext4_fc_handle_add_extent(e2fsck_t ctx, struct ext4_fc_tl *tl)
+static int ext4_fc_handle_add_extent(e2fsck_t ctx, __u8 *val)
{
struct ext2fs_extent extent;
- struct ext4_fc_add_range *add_range;
- int ret = 0, ino;
+ struct ext4_fc_add_range add_range;
+ ext2_ino_t ino;
+ int ret = 0;
- add_range = (struct ext4_fc_add_range *)ext4_fc_tag_val(tl);
- ino = le32_to_cpu(add_range->fc_ino);
+ memcpy(&add_range, val, sizeof(add_range));
+ ino = le32_to_cpu(add_range.fc_ino);
ext4_fc_flush_extents(ctx, ino);
ret = ext4_fc_read_extents(ctx, ino);
@@ -797,8 +821,8 @@ static int ext4_fc_handle_add_extent(e2fsck_t ctx, struct ext4_fc_tl *tl)
return ret;
memset(&extent, 0, sizeof(extent));
ret = errcode_to_errno(ext2fs_decode_extent(
- &extent, (void *)(add_range->fc_ex),
- sizeof(add_range->fc_ex)));
+ &extent, (void *)add_range.fc_ex,
+ sizeof(add_range.fc_ex)));
if (ret)
return ret;
return ext4_add_extent_to_list(ctx,
@@ -808,19 +832,19 @@ static int ext4_fc_handle_add_extent(e2fsck_t ctx, struct ext4_fc_tl *tl)
/*
* Handle delete logical range replay tag.
*/
-static int ext4_fc_handle_del_range(e2fsck_t ctx, struct ext4_fc_tl *tl)
+static int ext4_fc_handle_del_range(e2fsck_t ctx, __u8 *val)
{
struct ext2fs_extent extent;
- struct ext4_fc_del_range *del_range;
+ struct ext4_fc_del_range del_range;
int ret, ino;
- del_range = (struct ext4_fc_del_range *)ext4_fc_tag_val(tl);
- ino = le32_to_cpu(del_range->fc_ino);
+ memcpy(&del_range, val, sizeof(del_range));
+ ino = le32_to_cpu(del_range.fc_ino);
ext4_fc_flush_extents(ctx, ino);
memset(&extent, 0, sizeof(extent));
- extent.e_lblk = ext2fs_le32_to_cpu(del_range->fc_lblk);
- extent.e_len = ext2fs_le32_to_cpu(del_range->fc_len);
+ extent.e_lblk = le32_to_cpu(del_range.fc_lblk);
+ extent.e_len = le32_to_cpu(del_range.fc_len);
ret = ext4_fc_read_extents(ctx, ino);
if (ret)
return ret;
@@ -839,8 +863,8 @@ static int ext4_fc_replay(journal_t *journal, struct buffer_head *bh,
e2fsck_t ctx = journal->j_fs_dev->k_ctx;
struct e2fsck_fc_replay_state *state = &ctx->fc_replay_state;
int ret = JBD2_FC_REPLAY_CONTINUE;
- struct ext4_fc_tl *tl;
- __u8 *start, *end;
+ struct ext4_fc_tl tl;
+ __u8 *start, *end, *cur, *val;
if (pass == PASS_SCAN) {
state->fc_current_pass = PASS_SCAN;
@@ -864,7 +888,7 @@ static int ext4_fc_replay(journal_t *journal, struct buffer_head *bh,
/*
* Mark the file system to indicate it contains errors. That's
* because the updates performed by fast commit replay code are
- * not atomic and may result in incosistent file system if it
+ * not atomic and may result in inconsistent file system if it
* crashes before the replay is complete.
*/
ctx->fs->super->s_state |= EXT2_ERROR_FS;
@@ -876,28 +900,31 @@ static int ext4_fc_replay(journal_t *journal, struct buffer_head *bh,
start = (__u8 *)bh->b_data;
end = (__u8 *)bh->b_data + journal->j_blocksize - 1;
- fc_for_each_tl(start, end, tl) {
+ for (cur = start; cur < end; cur = cur + le16_to_cpu(tl.fc_len) + sizeof(tl)) {
+ memcpy(&tl, cur, sizeof(tl));
+ val = cur + sizeof(tl);
+
if (state->fc_replay_num_tags == 0)
goto replay_done;
jbd_debug(3, "Replay phase processing %s tag\n",
- tag2str(le16_to_cpu(tl->fc_tag)));
+ tag2str(le16_to_cpu(tl.fc_tag)));
state->fc_replay_num_tags--;
- switch (le16_to_cpu(tl->fc_tag)) {
+ switch (le16_to_cpu(tl.fc_tag)) {
case EXT4_FC_TAG_CREAT:
case EXT4_FC_TAG_LINK:
- ret = ext4_fc_handle_link_and_create(ctx, tl);
+ ret = ext4_fc_handle_link_and_create(ctx, &tl, val);
break;
case EXT4_FC_TAG_UNLINK:
- ret = ext4_fc_handle_unlink(ctx, tl);
+ ret = ext4_fc_handle_unlink(ctx, &tl, val);
break;
case EXT4_FC_TAG_ADD_RANGE:
- ret = ext4_fc_handle_add_extent(ctx, tl);
+ ret = ext4_fc_handle_add_extent(ctx, val);
break;
case EXT4_FC_TAG_DEL_RANGE:
- ret = ext4_fc_handle_del_range(ctx, tl);
+ ret = ext4_fc_handle_del_range(ctx, val);
break;
case EXT4_FC_TAG_INODE:
- ret = ext4_fc_handle_inode(ctx, tl);
+ ret = ext4_fc_handle_inode(ctx, val);
break;
case EXT4_FC_TAG_TAIL:
ext4_fc_flush_extents(ctx, 0);
@@ -971,7 +998,14 @@ static errcode_t e2fsck_get_journal(e2fsck_t ctx, journal_t **ret_journal)
journal->j_blocksize = ctx->fs->blocksize;
if (uuid_is_null(sb->s_journal_uuid)) {
- if (!sb->s_journal_inum) {
+ /*
+ * The full set of superblock sanity checks haven't
+ * been performed yet, so we need to do some basic
+ * checks here to avoid potential array overruns.
+ */
+ if (!sb->s_journal_inum ||
+ (sb->s_journal_inum >
+ (ctx->fs->group_desc_count * sb->s_inodes_per_group))) {
retval = EXT2_ET_BAD_INODE_NUM;
goto errout;
}
@@ -1005,7 +1039,8 @@ static errcode_t e2fsck_get_journal(e2fsck_t ctx, journal_t **ret_journal)
tried_backup_jnl++;
}
if (!j_inode->i_ext2.i_links_count ||
- !LINUX_S_ISREG(j_inode->i_ext2.i_mode)) {
+ !LINUX_S_ISREG(j_inode->i_ext2.i_mode) ||
+ (j_inode->i_ext2.i_flags & EXT4_ENCRYPT_FL)) {
retval = EXT2_ET_NO_JOURNAL;
goto try_backup_journal;
}
diff --git a/e2fsck/logfile.c b/e2fsck/logfile.c
index 63e9a12f..9d79eed2 100644
--- a/e2fsck/logfile.c
+++ b/e2fsck/logfile.c
@@ -32,7 +32,7 @@ static void alloc_string(struct string *s, int len)
{
s->s = malloc(len);
/* e2fsck_allocate_memory(ctx, len, "logfile name"); */
- s->len = len;
+ s->len = s->s ? len : 0;
s->end = 0;
}
@@ -155,6 +155,9 @@ static void expand_percent_expression(e2fsck_t ctx, char ch,
case 'Y':
sprintf(buf, "%d", tm->tm_year + 1900);
break;
+ default:
+ sprintf(buf, "%%%c", ch);
+ break;
}
append_string(s, buf, 0);
}
diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index 9d430895..78540119 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -79,8 +79,8 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
static void mark_table_blocks(e2fsck_t ctx);
static void alloc_bb_map(e2fsck_t ctx);
static void alloc_imagic_map(e2fsck_t ctx);
-static void mark_inode_bad(e2fsck_t ctx, ino_t ino);
-static void add_casefolded_dir(e2fsck_t ctx, ino_t ino);
+static void mark_inode_bad(e2fsck_t ctx, ext2_ino_t ino);
+static void add_casefolded_dir(e2fsck_t ctx, ext2_ino_t ino);
static void handle_fs_bad_blocks(e2fsck_t ctx);
static void process_inodes(e2fsck_t ctx, char *block_buf);
static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b);
@@ -331,7 +331,7 @@ static problem_t check_large_ea_inode(e2fsck_t ctx,
blk64_t *quota_blocks)
{
struct ext2_inode inode;
- __u32 hash;
+ __u32 hash, signed_hash;
errcode_t retval;
/* Check if inode is within valid range */
@@ -343,7 +343,8 @@ static problem_t check_large_ea_inode(e2fsck_t ctx,
e2fsck_read_inode(ctx, entry->e_value_inum, &inode, "pass1");
- retval = ext2fs_ext_attr_hash_entry2(ctx->fs, entry, NULL, &hash);
+ retval = ext2fs_ext_attr_hash_entry3(ctx->fs, entry, NULL, &hash,
+ &signed_hash);
if (retval) {
com_err("check_large_ea_inode", retval,
_("while hashing entry with e_value_inum = %u"),
@@ -351,7 +352,7 @@ static problem_t check_large_ea_inode(e2fsck_t ctx,
fatal_error(ctx, 0);
}
- if (hash == entry->e_hash) {
+ if ((hash == entry->e_hash) || (signed_hash == entry->e_hash)) {
*quota_blocks = size_to_quota_blocks(ctx->fs,
entry->e_value_size);
} else {
@@ -389,13 +390,13 @@ static problem_t check_large_ea_inode(e2fsck_t ctx,
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;
+ struct ext2_ext_attr_entry *entry = first;
+ struct ext2_ext_attr_entry *np = EXT2_EXT_ATTR_NEXT(entry);
- for (entry = first;
- (void *)entry < end && !EXT2_EXT_IS_LAST_ENTRY(entry);
- entry = EXT2_EXT_ATTR_NEXT(entry)) {
+ while ((void *) entry < end && (void *) np < end &&
+ !EXT2_EXT_IS_LAST_ENTRY(entry)) {
if (!entry->e_value_inum)
- continue;
+ goto next;
if (!ctx->ea_inode_refs) {
pctx->errcode = ea_refcount_create(0,
&ctx->ea_inode_refs);
@@ -408,6 +409,9 @@ static void inc_ea_inode_refs(e2fsck_t ctx, struct problem_context *pctx,
}
ea_refcount_increment(ctx->ea_inode_refs, entry->e_value_inum,
0);
+ next:
+ entry = np;
+ np = EXT2_EXT_ATTR_NEXT(entry);
}
}
@@ -492,7 +496,10 @@ static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx,
}
hash = ext2fs_ext_attr_hash_entry(entry,
- start + entry->e_value_offs);
+ start + entry->e_value_offs);
+ if (entry->e_hash != 0 && entry->e_hash != hash)
+ hash = ext2fs_ext_attr_hash_entry_signed(entry,
+ start + entry->e_value_offs);
/* e_hash may be 0 in older inode's ea */
if (entry->e_hash != 0 && entry->e_hash != hash) {
@@ -1326,7 +1333,7 @@ void e2fsck_pass1(e2fsck_t ctx)
goto endit;
}
block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 3,
- "block interate buffer");
+ "block iterate buffer");
if (EXT2_INODE_SIZE(fs->super) == EXT2_GOOD_OLD_INODE_SIZE)
e2fsck_use_inode_shortcuts(ctx, 1);
e2fsck_intercept_block_allocations(ctx);
@@ -2058,9 +2065,7 @@ void e2fsck_pass1(e2fsck_t ctx)
goto endit;
}
- if (ctx->large_dirs && !ext2fs_has_feature_largedir(ctx->fs->super)) {
- ext2_filsys fs = ctx->fs;
-
+ if (ctx->large_dirs && !ext2fs_has_feature_largedir(fs->super)) {
if (fix_problem(ctx, PR_2_FEATURE_LARGE_DIRS, &pctx)) {
ext2fs_set_feature_largedir(fs->super);
fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
@@ -2204,7 +2209,7 @@ static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b)
/*
* Mark an inode as being bad in some what
*/
-static void mark_inode_bad(e2fsck_t ctx, ino_t ino)
+static void mark_inode_bad(e2fsck_t ctx, ext2_ino_t ino)
{
struct problem_context pctx;
@@ -2225,7 +2230,7 @@ static void mark_inode_bad(e2fsck_t ctx, ino_t ino)
ext2fs_mark_inode_bitmap2(ctx->inode_bad_map, ino);
}
-static void add_casefolded_dir(e2fsck_t ctx, ino_t ino)
+static void add_casefolded_dir(e2fsck_t ctx, ext2_ino_t ino)
{
struct problem_context pctx;
@@ -2555,8 +2560,9 @@ static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
break;
}
if (entry->e_value_inum == 0) {
- if (entry->e_value_offs + entry->e_value_size >
- fs->blocksize) {
+ if (entry->e_value_size > EXT2_XATTR_SIZE_MAX ||
+ (entry->e_value_offs + entry->e_value_size >
+ fs->blocksize)) {
if (fix_problem(ctx, PR_1_EA_BAD_VALUE, pctx))
goto clear_extattr;
break;
@@ -2571,6 +2577,9 @@ static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
hash = ext2fs_ext_attr_hash_entry(entry, block_buf +
entry->e_value_offs);
+ if (entry->e_hash != hash)
+ hash = ext2fs_ext_attr_hash_entry_signed(entry,
+ block_buf + entry->e_value_offs);
if (entry->e_hash != hash) {
pctx->num = entry->e_hash;
@@ -2728,7 +2737,7 @@ static int handle_htree(e2fsck_t ctx, struct problem_context *pctx,
if (root->indirect_levels > ext2_dir_htree_level(fs) &&
!ext2fs_has_feature_largedir(fs->super)) {
int blockbits = EXT2_BLOCK_SIZE_BITS(fs->super) + 10;
- int idx_pb = 1 << (blockbits - 3);
+ unsigned idx_pb = 1 << (blockbits - 3);
/* compare inode size/blocks vs. max-sized 2-level htree */
if (EXT2_I_SIZE(pctx->inode) <
@@ -2840,7 +2849,8 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
if (pctx->errcode)
return;
if (!(ctx->options & E2F_OPT_FIXES_ONLY) &&
- !pb->eti.force_rebuild) {
+ !pb->eti.force_rebuild &&
+ info.curr_level < MAX_EXTENT_DEPTH_COUNT) {
struct extent_tree_level *etl;
etl = pb->eti.ext_info + info.curr_level;
@@ -4064,7 +4074,7 @@ static void new_table_block(e2fsck_t ctx, blk64_t first_block, dgrp_t group,
*/
is_flexbg = ext2fs_has_feature_flex_bg(fs->super);
if (is_flexbg) {
- flexbg_size = 1 << fs->super->s_log_groups_per_flex;
+ flexbg_size = 1U << fs->super->s_log_groups_per_flex;
flexbg = group / flexbg_size;
first_block = ext2fs_group_first_block2(fs,
flexbg_size * flexbg);
diff --git a/e2fsck/pass1b.c b/e2fsck/pass1b.c
index 92c746c1..950af5be 100644
--- a/e2fsck/pass1b.c
+++ b/e2fsck/pass1b.c
@@ -90,7 +90,7 @@ static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
struct dup_inode *dp, char *block_buf);
static errcode_t clone_file(e2fsck_t ctx, ext2_ino_t ino,
struct dup_inode *dp, char* block_buf);
-static int check_if_fs_block(e2fsck_t ctx, blk64_t test_block);
+static int check_if_fs_block(e2fsck_t ctx, blk64_t block);
static int check_if_fs_cluster(e2fsck_t ctx, blk64_t cluster);
static void pass1b(e2fsck_t ctx, char *block_buf);
@@ -815,8 +815,6 @@ static int clone_file_block(ext2_filsys fs,
should_write = 0;
c = EXT2FS_B2C(fs, blockcnt);
- if (check_if_fs_cluster(ctx, EXT2FS_B2C(fs, *block_nr)))
- is_meta = 1;
if (c == cs->dup_cluster && cs->alloc_block) {
new_block = cs->alloc_block;
@@ -894,6 +892,8 @@ cluster_alloc_ok:
return BLOCK_ABORT;
}
}
+ if (check_if_fs_cluster(ctx, EXT2FS_B2C(fs, *block_nr)))
+ is_meta = 1;
cs->save_dup_cluster = (is_meta ? NULL : p);
cs->save_blocknr = *block_nr;
*block_nr = new_block;
@@ -1021,37 +1021,9 @@ errout:
* This routine returns 1 if a block overlaps with one of the superblocks,
* group descriptors, inode bitmaps, or block bitmaps.
*/
-static int check_if_fs_block(e2fsck_t ctx, blk64_t test_block)
+static int check_if_fs_block(e2fsck_t ctx, blk64_t block)
{
- ext2_filsys fs = ctx->fs;
- blk64_t first_block;
- dgrp_t i;
-
- first_block = fs->super->s_first_data_block;
- for (i = 0; i < fs->group_desc_count; i++) {
-
- /* Check superblocks/block group descriptors */
- if (ext2fs_bg_has_super(fs, i)) {
- if (test_block >= first_block &&
- (test_block <= first_block + fs->desc_blocks))
- return 1;
- }
-
- /* Check the inode table */
- if ((ext2fs_inode_table_loc(fs, i)) &&
- (test_block >= ext2fs_inode_table_loc(fs, i)) &&
- (test_block < (ext2fs_inode_table_loc(fs, i) +
- fs->inode_blocks_per_group)))
- return 1;
-
- /* Check the bitmap blocks */
- if ((test_block == ext2fs_block_bitmap_loc(fs, i)) ||
- (test_block == ext2fs_inode_bitmap_loc(fs, i)))
- return 1;
-
- first_block += fs->super->s_blocks_per_group;
- }
- return 0;
+ return ext2fs_test_block_bitmap2(ctx->block_metadata_map, block);
}
/*
@@ -1061,37 +1033,14 @@ static int check_if_fs_block(e2fsck_t ctx, blk64_t test_block)
static int check_if_fs_cluster(e2fsck_t ctx, blk64_t cluster)
{
ext2_filsys fs = ctx->fs;
- blk64_t first_block;
- dgrp_t i;
-
- first_block = fs->super->s_first_data_block;
- for (i = 0; i < fs->group_desc_count; i++) {
-
- /* Check superblocks/block group descriptors */
- if (ext2fs_bg_has_super(fs, i)) {
- if (cluster >= EXT2FS_B2C(fs, first_block) &&
- (cluster <= EXT2FS_B2C(fs, first_block +
- fs->desc_blocks)))
- return 1;
- }
+ blk64_t block = EXT2FS_C2B(fs, cluster);
+ int i;
- /* Check the inode table */
- if ((ext2fs_inode_table_loc(fs, i)) &&
- (cluster >= EXT2FS_B2C(fs,
- ext2fs_inode_table_loc(fs, i))) &&
- (cluster <= EXT2FS_B2C(fs,
- ext2fs_inode_table_loc(fs, i) +
- fs->inode_blocks_per_group - 1)))
+ for (i = 0; i < EXT2FS_CLUSTER_RATIO(fs); i++) {
+ if (ext2fs_test_block_bitmap2(ctx->block_metadata_map,
+ block + i))
return 1;
-
- /* Check the bitmap blocks */
- if ((cluster == EXT2FS_B2C(fs,
- ext2fs_block_bitmap_loc(fs, i))) ||
- (cluster == EXT2FS_B2C(fs,
- ext2fs_inode_bitmap_loc(fs, i))))
- return 1;
-
- first_block += fs->super->s_blocks_per_group;
}
+
return 0;
}
diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c
index 1b2cb94a..28736094 100644
--- a/e2fsck/pass2.c
+++ b/e2fsck/pass2.c
@@ -150,6 +150,7 @@ void e2fsck_pass2(e2fsck_t ctx)
mtrace_print("Pass 2");
#endif
+ fs->flags |= EXT2_FLAG_IGNORE_SWAP_DIRENT;
if (!(ctx->options & E2F_OPT_PREEN))
fix_problem(ctx, PR_2_PASS_HEADER, &cd.pctx);
@@ -317,6 +318,7 @@ void e2fsck_pass2(e2fsck_t ctx)
print_resource_track(ctx, _("Pass 2"), &rtrack, fs->io);
cleanup:
ext2fs_free_mem(&buf);
+ fs->flags &= ~EXT2_FLAG_IGNORE_SWAP_DIRENT;
}
#define MAX_DEPTH 32000
@@ -360,8 +362,9 @@ static int dict_de_cf_cmp(const void *cmp_ctx, const void *a, const void *b)
de_b = (const struct ext2_dir_entry *) b;
b_len = ext2fs_dirent_name_len(de_b);
- return ext2fs_casefold_cmp(tbl, (unsigned char *) de_a->name, a_len,
- (unsigned char *) de_b->name, b_len);
+ return ext2fs_casefold_cmp(tbl,
+ (const unsigned char *) de_a->name, a_len,
+ (const unsigned char *) de_b->name, b_len);
}
/*
@@ -406,6 +409,7 @@ static int check_dot(e2fsck_t ctx,
int status = 0;
int created = 0;
problem_t problem = 0;
+ int ftype = EXT2_FT_DIR;
if (!dirent->inode)
problem = PR_2_MISSING_DOT;
@@ -417,12 +421,14 @@ static int check_dot(e2fsck_t ctx,
(void) ext2fs_get_rec_len(ctx->fs, dirent, &rec_len);
if (problem) {
+ if (!ext2fs_has_feature_filetype(ctx->fs->super))
+ ftype = EXT2_FT_UNKNOWN;
if (fix_problem(ctx, problem, pctx)) {
if (rec_len < 12)
rec_len = dirent->rec_len = 12;
dirent->inode = ino;
ext2fs_dirent_set_name_len(dirent, 1);
- ext2fs_dirent_set_file_type(dirent, EXT2_FT_UNKNOWN);
+ ext2fs_dirent_set_file_type(dirent, ftype);
dirent->name[0] = '.';
dirent->name[1] = '\0';
status = 1;
@@ -443,12 +449,24 @@ static int check_dot(e2fsck_t ctx,
nextdir = (struct ext2_dir_entry *)
((char *) dirent + 12);
dirent->rec_len = 12;
- (void) ext2fs_set_rec_len(ctx->fs, new_len,
- nextdir);
- nextdir->inode = 0;
- ext2fs_dirent_set_name_len(nextdir, 0);
- ext2fs_dirent_set_file_type(nextdir,
- EXT2_FT_UNKNOWN);
+ /* if the next entry looks like "..", leave it
+ * and let check_dotdot() verify the dirent,
+ * otherwise zap the following entry. */
+ if (strncmp(nextdir->name, "..", 3) != 0) {
+ (void)ext2fs_set_rec_len(ctx->fs,
+ new_len,
+ nextdir);
+ nextdir->inode = 0;
+ ext2fs_dirent_set_name_len(nextdir, 0);
+ ext2fs_dirent_set_file_type(nextdir,
+ ftype);
+#ifdef WORDS_BIGENDIAN
+ } else {
+ (void) ext2fs_dirent_swab_in2(ctx->fs,
+ (char *) nextdir,
+ ctx->fs->blocksize - 12, 0);
+#endif
+ }
status = 1;
}
}
@@ -467,6 +485,7 @@ static int check_dotdot(e2fsck_t ctx,
{
problem_t problem = 0;
unsigned int rec_len;
+ int ftype = EXT2_FT_DIR;
if (!dirent->inode)
problem = PR_2_MISSING_DOT_DOT;
@@ -479,6 +498,8 @@ static int check_dotdot(e2fsck_t ctx,
(void) ext2fs_get_rec_len(ctx->fs, dirent, &rec_len);
if (problem) {
+ if (!ext2fs_has_feature_filetype(ctx->fs->super))
+ ftype = EXT2_FT_UNKNOWN;
if (fix_problem(ctx, problem, pctx)) {
if (rec_len < 12)
dirent->rec_len = 12;
@@ -489,7 +510,7 @@ static int check_dotdot(e2fsck_t ctx,
*/
dirent->inode = EXT2_ROOT_INO;
ext2fs_dirent_set_name_len(dirent, 2);
- ext2fs_dirent_set_file_type(dirent, EXT2_FT_UNKNOWN);
+ ext2fs_dirent_set_file_type(dirent, ftype);
dirent->name[0] = '.';
dirent->name[1] = '.';
dirent->name[2] = '\0';
@@ -779,7 +800,7 @@ static void salvage_directory(ext2_filsys fs,
* Special case of directory entry of size 8: copy what's left
* of the directory block up to cover up the invalid hole.
*/
- if ((left >= ext2fs_dir_rec_len(1, hash_in_dirent)) &&
+ if ((left >= (int) ext2fs_dir_rec_len(1, hash_in_dirent)) &&
(rec_len == EXT2_DIR_ENTRY_HEADER_LEN)) {
memmove(cp, cp+EXT2_DIR_ENTRY_HEADER_LEN, left);
memset(cp + left, 0, EXT2_DIR_ENTRY_HEADER_LEN);
@@ -1285,7 +1306,7 @@ skip_checksum:
if (cf_dir) {
dict_init(&de_dict, DICTCOUNT_T_MAX, dict_de_cf_cmp);
- dict_set_cmp_context(&de_dict, (void *)ctx->fs->encoding);
+ dict_set_cmp_context(&de_dict, (const void *)ctx->fs->encoding);
} else {
dict_init(&de_dict, DICTCOUNT_T_MAX, dict_de_cmp);
}
@@ -1301,7 +1322,7 @@ skip_checksum:
unsigned int name_len;
/* csum entry is not checked here, so don't worry about it */
int extended = (dot_state > 1) && hash_in_dirent;
- int min_dir_len = ext2fs_dir_rec_len(1, extended);
+ unsigned int min_dir_len = ext2fs_dir_rec_len(1, extended);
problem = 0;
if (!inline_data_size || dot_state > 1) {
@@ -1357,12 +1378,14 @@ skip_checksum:
hash_in_dirent);
#ifdef WORDS_BIGENDIAN
if (need_reswab) {
+ unsigned int len;
+
(void) ext2fs_get_rec_len(fs,
- dirent, &rec_len);
- ext2fs_dirent_swab_in2(fs,
- ((char *)dirent) + offset + rec_len,
- max_block_size - offset - rec_len,
- 0);
+ 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++;
@@ -1420,7 +1443,10 @@ skip_checksum:
name_len = ext2fs_dirent_name_len(dirent);
if (((dirent->inode != EXT2_ROOT_INO) &&
(dirent->inode < EXT2_FIRST_INODE(fs->super))) ||
- (dirent->inode > fs->super->s_inodes_count)) {
+ (dirent->inode > fs->super->s_inodes_count) ||
+ (dirent->inode == fs->super->s_usr_quota_inum) ||
+ (dirent->inode == fs->super->s_grp_quota_inum) ||
+ (dirent->inode == fs->super->s_prj_quota_inum)) {
problem = PR_2_BAD_INO;
} else if (ctx->inode_bb_map &&
(ext2fs_test_inode_bitmap2(ctx->inode_bb_map,
@@ -1515,6 +1541,7 @@ skip_checksum:
&cd->pctx)){
ext2fs_bg_flags_clear(fs, group,
EXT2_BG_INODE_UNINIT);
+ ext2fs_group_desc_csum_set(fs, group);
ext2fs_mark_super_dirty(fs);
ctx->flags |= E2F_FLAG_RESTART_LATER;
} else {
@@ -1526,6 +1553,7 @@ skip_checksum:
pctx.num = dirent->inode;
if (fix_problem(ctx, PR_2_INOREF_IN_UNUSED, &cd->pctx)){
ext2fs_bg_itable_unused_set(fs, group, 0);
+ ext2fs_group_desc_csum_set(fs, group);
ext2fs_mark_super_dirty(fs);
ctx->flags |= E2F_FLAG_RESTART_LATER;
} else {
@@ -1783,7 +1811,7 @@ struct del_block {
};
/*
- * This function is called to deallocate a block, and is an interator
+ * This function is called to deallocate a block, and is an iterator
* functioned called by deallocate inode via ext2fs_iterate_block().
*/
static int deallocate_inode_block(ext2_filsys fs,
diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c
index cedaaf5a..16d243f6 100644
--- a/e2fsck/pass3.c
+++ b/e2fsck/pass3.c
@@ -22,7 +22,7 @@
* will offer to reconnect it to /lost+found. While it is chasing
* parent pointers up the filesystem tree, if pass3 sees a directory
* twice, then it has detected a filesystem loop, and it will again
- * offer to reconnect the directory to /lost+found in to break the
+ * offer to reconnect the directory to /lost+found in order to break the
* filesystem loop.
*
* Pass 3 also contains the subroutine, e2fsck_reconnect_file() to
@@ -304,7 +304,7 @@ static int check_directory(e2fsck_t ctx, ext2_ino_t dir,
* If it was marked done already, then we've reached a
* parent we've already checked.
*/
- if (ext2fs_mark_inode_bitmap2(inode_done_map, ino))
+ if (ext2fs_mark_inode_bitmap2(inode_done_map, ino))
break;
if (e2fsck_dir_info_get_parent(ctx, ino, &parent)) {
@@ -319,13 +319,18 @@ static int check_directory(e2fsck_t ctx, ext2_ino_t dir,
*/
if (!parent ||
(loop_pass &&
- (ext2fs_test_inode_bitmap2(inode_loop_detect,
- parent)))) {
+ ext2fs_test_inode_bitmap2(inode_loop_detect, parent))) {
pctx->ino = ino;
- if (fix_problem(ctx, PR_3_UNCONNECTED_DIR, pctx)) {
- if (e2fsck_reconnect_file(ctx, pctx->ino))
+ if (parent)
+ pctx->dir = parent;
+ else
+ (void) ext2fs_lookup(fs, ino, "..", 2, NULL,
+ &pctx->dir);
+ if (fix_problem(ctx, !parent ? PR_3_UNCONNECTED_DIR :
+ PR_3_LOOPED_DIR, pctx)) {
+ if (e2fsck_reconnect_file(ctx, pctx->ino)) {
ext2fs_unmark_valid(fs);
- else {
+ } else {
fix_dotdot(ctx, pctx->ino,
ctx->lost_and_found);
parent = ctx->lost_and_found;
diff --git a/e2fsck/problem.c b/e2fsck/problem.c
index eb2824f3..e2572f59 100644
--- a/e2fsck/problem.c
+++ b/e2fsck/problem.c
@@ -50,29 +50,29 @@
* to fix a problem.
*/
static const char *prompt[] = {
- N_("(no prompt)"), /* 0 */
- N_("Fix"), /* 1 */
- N_("Clear"), /* 2 */
- N_("Relocate"), /* 3 */
- N_("Allocate"), /* 4 */
- N_("Expand"), /* 5 */
- N_("Connect to /lost+found"), /* 6 */
- N_("Create"), /* 7 */
- N_("Salvage"), /* 8 */
- N_("Truncate"), /* 9 */
- N_("Clear inode"), /* 10 */
- N_("Abort"), /* 11 */
- N_("Split"), /* 12 */
- N_("Continue"), /* 13 */
- N_("Clone multiply-claimed blocks"), /* 14 */
- N_("Delete file"), /* 15 */
- N_("Suppress messages"),/* 16 */
- N_("Unlink"), /* 17 */
- N_("Clear HTree index"),/* 18 */
- N_("Recreate"), /* 19 */
- N_("Optimize"), /* 20 */
- N_("Clear flag"), /* 21 */
- "", /* 22 */
+ N_("(no prompt)"), /* PROMPT_NONE = 0 */
+ N_("Fix"), /* PROMPT_FIX = 1 */
+ N_("Clear"), /* PROMPT_CLEAR = 2 */
+ N_("Relocate"), /* PROMPT_RELOCATE = 3 */
+ N_("Allocate"), /* PROMPT_CREATE = 4 */
+ N_("Expand"), /* PROMPT_EXPAND = 5 */
+ N_("Connect to /lost+found"), /* PROMPT_CONNECT = 6 */
+ N_("Create"), /* PROMPT_CREATE = 7 */
+ N_("Salvage"), /* PROMPT_SALVAGE = 8 */
+ N_("Truncate"), /* PROMPT_TRUNCATE = 9 */
+ N_("Clear inode"), /* PROMPT_CLEAR_INODE = 10 */
+ N_("Abort"), /* PROMPT_ABORT = 11 */
+ N_("Split"), /* PROMPT_SPLIT = 12 */
+ N_("Continue"), /* PROMPT_CONTINUE = 13 */
+ N_("Clone multiply-claimed blocks"), /* PROMPT_CLONE = 14 */
+ N_("Delete file"), /* PROMPT_DELETE = 15 */
+ N_("Suppress messages"), /* PROMPT_SUPPRESS = 16 */
+ N_("Unlink"), /* PROMPT_UNLINK = 17 */
+ N_("Clear HTree index"), /* PROMPT_CLEAR_HTREE = 18 */
+ N_("Recreate"), /* PROMPT_RECREATE = 19 */
+ N_("Optimize"), /* PROMPT_OPTIMIZE = 20 */
+ N_("Clear flag"), /* PROMPT_CLEAR_FLAG = 21 */
+ "", /* PROMPT_NULL = 22 */
};
/*
@@ -379,7 +379,7 @@ static struct e2fsck_problem problem_table[] = {
/* group descriptor N checksum is invalid, should be yyyy. */
{ PR_0_GDT_CSUM,
N_("@g descriptor %g checksum is %04x, should be %04y. "),
- PROMPT_FIX, PR_LATCH_BG_CHECKSUM, 0, 0, 0 },
+ PROMPT_FIX, PR_PREEN_OK | PR_LATCH_BG_CHECKSUM, 0, 0, 0 },
/* group descriptor N marked uninitialized without feature set. */
{ PR_0_GDT_UNINIT,
@@ -1852,7 +1852,7 @@ static struct e2fsck_problem problem_table[] = {
/* Unconnected directory inode */
{ PR_3_UNCONNECTED_DIR,
/* xgettext:no-c-format */
- N_("Unconnected @d @i %i (%p)\n"),
+ N_("Unconnected @d @i %i (was in %q)\n"),
PROMPT_CONNECT, 0, 0, 0, 0 },
/* /lost+found not found */
@@ -1989,6 +1989,12 @@ static struct e2fsck_problem problem_table[] = {
N_("/@l is encrypted\n"),
PROMPT_CLEAR, 0, 0, 0, 0 },
+ /* Recursively looped directory inode */
+ { PR_3_LOOPED_DIR,
+ /* xgettext:no-c-format */
+ N_("Recursively looped @d @i %i (%p)\n"),
+ PROMPT_CONNECT, 0, 0, 0, 0 },
+
/* Pass 3A Directory Optimization */
/* Pass 3A: Optimizing directories */
@@ -2315,6 +2321,8 @@ int end_problem_latch(e2fsck_t ctx, int mask)
int answer = -1;
ldesc = find_latch(mask);
+ if (!ldesc)
+ return answer;
if (ldesc->end_message && (ldesc->flags & PRL_LATCHED)) {
clear_problem_context(&pctx);
answer = fix_problem(ctx, ldesc->end_message, &pctx);
@@ -2461,8 +2469,8 @@ int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx)
* Do special latch processing. This is where we ask the
* latch question, if it exists
*/
- if (ptr->flags & PR_LATCH_MASK) {
- ldesc = find_latch(ptr->flags & PR_LATCH_MASK);
+ if (ptr->flags & PR_LATCH_MASK &&
+ (ldesc = find_latch(ptr->flags & PR_LATCH_MASK)) != NULL) {
if (ldesc->question && !(ldesc->flags & PRL_LATCHED)) {
ans = fix_problem(ctx, ldesc->question, pctx);
if (ans == 1)
@@ -2486,8 +2494,7 @@ int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx)
if ((ctx->options & E2F_OPT_PREEN) &&
(ptr->flags & PR_PREEN_OK))
suppress++;
- if ((ptr->flags & PR_LATCH_MASK) &&
- (ldesc->flags & (PRL_YES | PRL_NO)))
+ if (ldesc && (ldesc->flags & (PRL_YES | PRL_NO)))
suppress++;
if (ptr->count == ptr->max_count + 1) {
if (ctx->problem_logf)
@@ -2532,8 +2539,7 @@ int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx)
answer = def_yn;
if (!(ptr->flags & PR_PREEN_NOMSG))
print_answer = 1;
- } else if ((ptr->flags & PR_LATCH_MASK) &&
- (ldesc->flags & (PRL_YES | PRL_NO))) {
+ } else if (ldesc && (ldesc->flags & (PRL_YES | PRL_NO))) {
print_answer = 1;
if (ldesc->flags & PRL_YES)
answer = 1;
diff --git a/e2fsck/problem.h b/e2fsck/problem.h
index 24cdcf9b..e86bc889 100644
--- a/e2fsck/problem.h
+++ b/e2fsck/problem.h
@@ -1132,6 +1132,9 @@ struct problem_context {
/* Lost+found is encrypted */
#define PR_3_LPF_ENCRYPTED 0x03001B
+/* Recursively looped directory inode */
+#define PR_3_LOOPED_DIR 0x03001D
+
/*
* Pass 3a --- rehashing directories
*/
diff --git a/e2fsck/recovery.c b/e2fsck/recovery.c
index 1e07dfac..8ca35271 100644
--- a/e2fsck/recovery.c
+++ b/e2fsck/recovery.c
@@ -179,8 +179,8 @@ static int jbd2_descriptor_block_csum_verify(journal_t *j, void *buf)
if (!jbd2_journal_has_csum_v2or3(j))
return 1;
- tail = (struct jbd2_journal_block_tail *)(buf + j->j_blocksize -
- sizeof(struct jbd2_journal_block_tail));
+ tail = (struct jbd2_journal_block_tail *)((char *)buf +
+ j->j_blocksize - sizeof(struct jbd2_journal_block_tail));
provided = tail->t_checksum;
tail->t_checksum = 0;
calculated = jbd2_chksum(j, j->j_csum_seed, buf, j->j_blocksize);
@@ -196,7 +196,7 @@ static int jbd2_descriptor_block_csum_verify(journal_t *j, void *buf)
static int count_tags(journal_t *journal, struct buffer_head *bh)
{
char * tagp;
- journal_block_tag_t * tag;
+ journal_block_tag_t tag;
int nr = 0, size = journal->j_blocksize;
int tag_bytes = journal_tag_bytes(journal);
@@ -206,14 +206,14 @@ static int count_tags(journal_t *journal, struct buffer_head *bh)
tagp = &bh->b_data[sizeof(journal_header_t)];
while ((tagp - bh->b_data + tag_bytes) <= size) {
- tag = (journal_block_tag_t *) tagp;
+ memcpy(&tag, tagp, sizeof(tag));
nr++;
tagp += tag_bytes;
- if (!(tag->t_flags & cpu_to_be16(JBD2_FLAG_SAME_UUID)))
+ if (!(tag.t_flags & cpu_to_be16(JBD2_FLAG_SAME_UUID)))
tagp += 16;
- if (tag->t_flags & cpu_to_be16(JBD2_FLAG_LAST_TAG))
+ if (tag.t_flags & cpu_to_be16(JBD2_FLAG_LAST_TAG))
break;
}
@@ -325,7 +325,7 @@ int jbd2_journal_recover(journal_t *journal)
err = err2;
/* Make sure all replayed data is on permanent storage */
if (journal->j_flags & JBD2_BARRIER) {
- err2 = blkdev_issue_flush(journal->j_fs_dev, GFP_KERNEL);
+ err2 = blkdev_issue_flush(journal->j_fs_dev);
if (!err)
err = err2;
}
@@ -433,9 +433,9 @@ static int jbd2_commit_block_csum_verify(journal_t *j, void *buf)
}
static int jbd2_block_tag_csum_verify(journal_t *j, journal_block_tag_t *tag,
+ journal_block_tag3_t *tag3,
void *buf, __u32 sequence)
{
- journal_block_tag3_t *tag3 = (journal_block_tag3_t *)tag;
__u32 csum32;
__be32 seq;
@@ -496,7 +496,7 @@ static int do_one_pass(journal_t *journal,
while (1) {
int flags;
char * tagp;
- journal_block_tag_t * tag;
+ journal_block_tag_t tag;
struct buffer_head * obh;
struct buffer_head * nbh;
@@ -613,8 +613,8 @@ static int do_one_pass(journal_t *journal,
<= journal->j_blocksize - descr_csum_size) {
unsigned long io_block;
- tag = (journal_block_tag_t *) tagp;
- flags = be16_to_cpu(tag->t_flags);
+ memcpy(&tag, tagp, sizeof(tag));
+ flags = be16_to_cpu(tag.t_flags);
io_block = next_log_block++;
wrap(journal, next_log_block);
@@ -632,7 +632,7 @@ static int do_one_pass(journal_t *journal,
J_ASSERT(obh != NULL);
blocknr = read_tag_block(journal,
- tag);
+ &tag);
/* If the block has been
* revoked, then we're all done
@@ -647,8 +647,8 @@ static int do_one_pass(journal_t *journal,
/* Look for block corruption */
if (!jbd2_block_tag_csum_verify(
- journal, tag, obh->b_data,
- be32_to_cpu(tmp->h_sequence))) {
+ journal, &tag, (journal_block_tag3_t *)tagp,
+ obh->b_data, be32_to_cpu(tmp->h_sequence))) {
brelse(obh);
success = -EFSBADCRC;
printk(KERN_ERR "JBD2: Invalid "
@@ -760,7 +760,6 @@ static int do_one_pass(journal_t *journal,
*/
jbd_debug(1, "JBD2: Invalid checksum ignored in transaction %u, likely stale data\n",
next_commit_ID);
- err = 0;
brelse(bh);
goto done;
}
@@ -897,7 +896,7 @@ static int scan_revoke_records(journal_t *journal, struct buffer_head *bh,
{
jbd2_journal_revoke_header_t *header;
int offset, max;
- int csum_size = 0;
+ unsigned csum_size = 0;
__u32 rcount;
int record_len = 4;
diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c
index 7d30ff00..8235e468 100644
--- a/e2fsck/rehash.c
+++ b/e2fsck/rehash.c
@@ -91,7 +91,7 @@ struct fill_dir_struct {
struct hash_entry {
ext2_dirhash_t hash;
ext2_dirhash_t minor_hash;
- ino_t ino;
+ ext2_ino_t ino;
struct ext2_dir_entry *dir;
};
@@ -164,7 +164,7 @@ static int fill_dir_block(ext2_filsys fs,
/* While the directory block is "hot", index it. */
dir_offset = 0;
while (dir_offset < fs->blocksize) {
- int min_rec = EXT2_DIR_ENTRY_HEADER_LEN;
+ unsigned int min_rec = EXT2_DIR_ENTRY_HEADER_LEN;
int extended = hash_in_entry && !is_fake_entry(fs, blockcnt, dir_offset);
if (extended)
@@ -414,6 +414,8 @@ static void mutate_name(char *str, unsigned int *len)
l += 2;
else
l = (l+3) & ~3;
+ if (l > 255)
+ l = 255;
str[l-2] = '~';
str[l-1] = '0';
*len = l;
@@ -548,7 +550,7 @@ static errcode_t copy_dir_entries(e2fsck_t ctx,
int csum_size = 0;
struct ext2_dir_entry_tail *t;
int hash_in_entry = ext4_hash_in_dirent(fd->inode);
- int min_rec_len = ext2fs_dir_rec_len(1, hash_in_entry);
+ unsigned int min_rec_len = ext2fs_dir_rec_len(1, hash_in_entry);
if (ctx->htree_slack_percentage == 255) {
profile_get_uint(ctx->profile, "options",
@@ -1051,13 +1053,11 @@ retry_nohash:
/* Sort the list */
resort:
if (fd.compress && fd.num_array > 1)
- sort_r_simple(fd.harray+2, fd.num_array-2,
- sizeof(struct hash_entry),
- hash_cmp, &name_cmp_ctx);
+ sort_r(fd.harray+2, fd.num_array-2, sizeof(struct hash_entry),
+ hash_cmp, &name_cmp_ctx);
else
- sort_r_simple(fd.harray, fd.num_array,
- sizeof(struct hash_entry),
- hash_cmp, &name_cmp_ctx);
+ sort_r(fd.harray, fd.num_array, sizeof(struct hash_entry),
+ hash_cmp, &name_cmp_ctx);
/*
* Look for duplicates
diff --git a/e2fsck/super.c b/e2fsck/super.c
index e1c3f935..123813be 100644
--- a/e2fsck/super.c
+++ b/e2fsck/super.c
@@ -281,7 +281,8 @@ static errcode_t e2fsck_read_all_quotas(e2fsck_t ctx)
if (qf_ino == 0)
continue;
- retval = quota_update_limits(ctx->qctx, qf_ino, qtype);
+ retval = quota_read_all_dquots(ctx->qctx, qf_ino, qtype,
+ QREAD_USAGE | QREAD_LIMITS);
if (retval)
break;
}
@@ -1038,9 +1039,9 @@ void check_super_block(e2fsck_t ctx)
* Check to see if the superblock last mount time or last
* write time is in the future.
*/
- if (!broken_system_clock && fs->super->s_checkinterval &&
- !(ctx->flags & E2F_FLAG_TIME_INSANE) &&
- fs->super->s_mtime > (__u32) ctx->now) {
+ 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;
problem = PR_0_FUTURE_SB_LAST_MOUNT;
if (fs->super->s_mtime <= (__u32) ctx->now + ctx->time_fudge)
@@ -1050,9 +1051,9 @@ void check_super_block(e2fsck_t ctx)
fs->flags |= EXT2_FLAG_DIRTY;
}
}
- if (!broken_system_clock && fs->super->s_checkinterval &&
- !(ctx->flags & E2F_FLAG_TIME_INSANE) &&
- fs->super->s_wtime > (__u32) ctx->now) {
+ 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;
problem = PR_0_FUTURE_SB_LAST_WRITE;
if (fs->super->s_wtime <= (__u32) ctx->now + ctx->time_fudge)
diff --git a/e2fsck/unix.c b/e2fsck/unix.c
index c5f9e441..853eb296 100644
--- a/e2fsck/unix.c
+++ b/e2fsck/unix.c
@@ -52,6 +52,7 @@ extern int optind;
#include "e2p/e2p.h"
#include "uuid/uuid.h"
#include "support/plausible.h"
+#include "support/devname.h"
#include "e2fsck.h"
#include "problem.h"
#include "jfs_user.h"
@@ -78,7 +79,7 @@ static void usage(e2fsck_t ctx)
_("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"),
- ctx->program_name);
+ ctx->program_name ? ctx->program_name : "e2fsck");
fprintf(stderr, "%s", _("\nEmergency help:\n"
" -p Automatic repair (no questions)\n"
@@ -304,7 +305,7 @@ static int is_on_batt(void)
}
f = fopen("/proc/apm", "r");
if (f) {
- if (fscanf(f, "%s %s %s %x", tmp, tmp, tmp, &acflag) != 4)
+ if (fscanf(f, "%79s %79s %79s %x", tmp, tmp, tmp, &acflag) != 4)
acflag = 1;
fclose(f);
return (acflag != 1);
@@ -320,7 +321,7 @@ static int is_on_batt(void)
f = fopen(fname, "r");
if (!f)
continue;
- if (fscanf(f, "%s %s", tmp2, tmp) != 2)
+ if (fscanf(f, "%79s %79s", tmp2, tmp) != 2)
tmp[0] = 0;
fclose(f);
if (strncmp(tmp, "off-line", 8) == 0) {
@@ -849,7 +850,7 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
if (argc && *argv)
ctx->program_name = *argv;
else
- ctx->program_name = "e2fsck";
+ usage(NULL);
phys_mem_kb = get_memory_size() / 1024;
ctx->readahead_kb = ~0ULL;
@@ -939,8 +940,8 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
goto sscanf_err;
break;
case 'j':
- ctx->journal_name = blkid_get_devname(ctx->blkid,
- optarg, NULL);
+ ctx->journal_name = get_devname(ctx->blkid,
+ optarg, NULL);
if (!ctx->journal_name) {
com_err(ctx->program_name, 0,
_("Unable to resolve '%s'"),
@@ -1019,7 +1020,7 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
ctx->io_options = strchr(argv[optind], '?');
if (ctx->io_options)
*ctx->io_options++ = 0;
- ctx->filesystem_name = blkid_get_devname(ctx->blkid, argv[optind], 0);
+ ctx->filesystem_name = get_devname(ctx->blkid, argv[optind], 0);
if (!ctx->filesystem_name) {
com_err(ctx->program_name, 0, _("Unable to resolve '%s'"),
argv[optind]);
@@ -1171,25 +1172,32 @@ static errcode_t try_open_fs(e2fsck_t ctx, int flags, io_manager io_ptr,
errcode_t retval;
*ret_fs = NULL;
- if (ctx->superblock && ctx->blocksize) {
- retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options,
- flags, ctx->superblock, ctx->blocksize,
- io_ptr, ret_fs);
- } else if (ctx->superblock) {
- int blocksize;
- for (blocksize = EXT2_MIN_BLOCK_SIZE;
- blocksize <= EXT2_MAX_BLOCK_SIZE; blocksize *= 2) {
- if (*ret_fs) {
- ext2fs_free(*ret_fs);
- *ret_fs = NULL;
+
+ if (ctx->superblock) {
+ unsigned long blocksize = ctx->blocksize;
+
+ if (!blocksize) {
+ for (blocksize = EXT2_MIN_BLOCK_SIZE;
+ blocksize <= EXT2_MAX_BLOCK_SIZE; blocksize *= 2) {
+
+ retval = ext2fs_open2(ctx->filesystem_name,
+ ctx->io_options, flags,
+ ctx->superblock, blocksize,
+ unix_io_manager, ret_fs);
+ if (*ret_fs) {
+ ext2fs_free(*ret_fs);
+ *ret_fs = NULL;
+ }
+ if (!retval)
+ break;
}
- retval = ext2fs_open2(ctx->filesystem_name,
- ctx->io_options, flags,
- ctx->superblock, blocksize,
- io_ptr, ret_fs);
- if (!retval)
- break;
+ if (retval)
+ return retval;
}
+
+ retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options,
+ flags, ctx->superblock, blocksize,
+ io_ptr, ret_fs);
} else
retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options,
flags, 0, 0, io_ptr, ret_fs);
@@ -1619,7 +1627,8 @@ failure:
* so that we are able to recover from more errors
* (e.g. some tool messing up some value in the sb).
*/
- if ((retval == EXT2_ET_CORRUPT_SUPERBLOCK) &&
+ if (((retval == EXT2_ET_CORRUPT_SUPERBLOCK) ||
+ (retval == EXT2_ET_BAD_DESC_SIZE)) &&
!(flags & EXT2_FLAG_IGNORE_SB_ERRORS)) {
if (fs)
ext2fs_close_free(&fs);
diff --git a/e2fsck/util.c b/e2fsck/util.c
index 3fe3c988..42740d9e 100644
--- a/e2fsck/util.c
+++ b/e2fsck/util.c
@@ -430,7 +430,16 @@ void print_resource_track(e2fsck_t ctx, const char *desc,
log_out(ctx, "%s: ", desc);
#define kbytes(x) (((unsigned long long)(x) + 1023) / 1024)
-#ifdef HAVE_MALLINFO
+#ifdef HAVE_MALLINFO2
+ if (1) {
+ struct mallinfo2 malloc_info = mallinfo2();
+
+ log_out(ctx, _("Memory used: %lluk/%lluk (%lluk/%lluk), "),
+ kbytes(malloc_info.arena), kbytes(malloc_info.hblkhd),
+ kbytes(malloc_info.uordblks),
+ kbytes(malloc_info.fordblks));
+ } 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) {
struct mallinfo malloc_info = mallinfo();