PKG_CONFIG_LIBDIR
PKG_CONFIG_PATH
PKG_CONFIG
+DEV_FEATURES_CMT
TEST_IO_CMT
PRIVATE_LIBS_CMT
LDFLAG_DYNAMIC
enable_jbd_debug
enable_blkid_debug
enable_testio_debug
+enable_developer_features
enable_libuuid
enable_libblkid
enable_subset
--enable-jbd-debug enable journal debugging
--enable-blkid-debug enable blkid debugging
--disable-testio-debug disable the use of the test I/O manager for debugging
+ --enable-developer-features enable features for use by ext4 developers
--enable-libuuid build and use private uuid library
--enable-libblkid build and use private blkid library
--enable-subset enable subset-only build
fi
+# Check whether --enable-developer-features was given.
+if test "${enable_developer_features+set}" = set; then :
+ enableval=$enable_developer_features;
+if test "$enableval" = "yes"
+then
+ DEV_FEATURES_CMT=
+ $as_echo "#define CONFIG_DEVELOPER_FEATURES 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: Enabling ext4 developer features" >&5
+$as_echo "Enabling ext4 developer features" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: Disabling ext4 developer features" >&5
+$as_echo "Disabling ext4 developer features" >&6; }
+ DEV_FEATURES_CMT="#"
+fi
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: Disabling ext4 developer features by default" >&5
+$as_echo "Disabling ext4 developer features by default" >&6; }
+DEV_FEATURES_CMT=
+
+fi
+
+
)
AC_SUBST(TEST_IO_CMT)
dnl
+dnl handle --enable-developer-features
+dnl
+AC_ARG_ENABLE([developer-features],
+[ --enable-developer-features enable features for use by ext4 developers],
+AH_TEMPLATE([CONFIG_DEVELOPER_FEATURES],
+ [Define to 1 for features for use by ext4 developers])
+if test "$enableval" = "yes"
+then
+ DEV_FEATURES_CMT=
+ AC_DEFINE(CONFIG_DEVELOPER_FEATURES, 1)
+ AC_MSG_RESULT([Enabling ext4 developer features])
+else
+ AC_MSG_RESULT([Disabling ext4 developer features])
+ DEV_FEATURES_CMT="#"
+fi
+,
+AC_MSG_RESULT([Disabling ext4 developer features by default])
+DEV_FEATURES_CMT=
+)
+AC_SUBST(DEV_FEATURES_CMT)
+dnl
dnl handle --disable-libuuid
dnl
PKG_PROG_PKG_CONFIG
--- /dev/null
+/*
+ * Test program to trigger various ext4 ioctl's
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#if (!defined(EXT4_IOC_ALLOC_DA_BLKS) && defined(__linux__))
+#define EXT4_IOC_ALLOC_DA_BLKS _IO('f', 12)
+#endif
+
+#if (!defined(EXT4_IOC_SWAP_BOOT) && defined(__linux__))
+#define EXT4_IOC_SWAP_BOOT _IO('f', 17)
+#endif
+
+#if (!defined(EXT4_IOC_PRECACHE_EXTENTS) && defined(__linux__))
+#define EXT4_IOC_PRECACHE_EXTENTS _IO('f', 18)
+#endif
+
+#if (!defined(EXT4_IOC_CLEAR_ES_CACHE) && defined(__linux__))
+#define EXT4_IOC_CLEAR_ES_CACHE _IO('f', 40)
+#endif
+
+
+#define EXT4_F_RW 0x0001
+
+struct cmd {
+ const char *cmd;
+ unsigned long ioc;
+ int flags;
+};
+
+struct cmd cmds[] = {
+ { "alloc_da_blks", EXT4_IOC_ALLOC_DA_BLKS, EXT4_F_RW },
+ { "precache", EXT4_IOC_PRECACHE_EXTENTS, 0 },
+ { "swap_boot", EXT4_IOC_SWAP_BOOT, EXT4_F_RW },
+ { "clear_es_cache", EXT4_IOC_CLEAR_ES_CACHE, EXT4_F_RW },
+ { NULL, 0 }
+};
+
+const char *progname;
+
+void usage()
+{
+ struct cmd *p;
+
+ fprintf(stderr, "Usage: %s <cmd> <file>\n\n", progname);
+ fprintf(stderr, "Available commands:\n");
+ for (p = cmds; p->cmd; p++) {
+ fprintf(stderr, "\t%s\n", p->cmd);
+ }
+ exit(1);
+}
+
+int do_single_cmd(const char *fn, struct cmd *p)
+{
+ int fd;
+ int oflags = O_RDONLY;
+
+ if (p->flags & EXT4_F_RW)
+ oflags = O_RDWR;
+ fd = open(fn, oflags, 0);
+ if (fd < 0) {
+ perror("open");
+ return 1;
+ }
+ if (ioctl(fd, p->ioc) < 0) {
+ perror("ioctl");
+ return 1;
+ }
+ close(fd);
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ int i, fails = 0;
+ struct cmd *p;
+
+ progname = argv[0];
+ if (argc < 3 || strcmp(argv[1], "help") == 0)
+ usage();
+ for (p = cmds; p->cmd; p++) {
+ if (strcmp(argv[1], p->cmd) == 0)
+ break;
+ }
+ if (p->cmd == NULL) {
+ fprintf(stderr, "Invalid command: %s\n", argv[1]);
+ usage();
+ }
+ for (i = 2; i < argc; i++)
+ fails += do_single_cmd(argv[i], p);
+ return fails;
+}
+++ /dev/null
-#!/bin/bash
-
-if [ -z "$1" -o -z "$2" ]; then
- echo "Usage: $0 kernel-file e2fsprogs-file"
- exit 0
-fi
-
-# Transform a few things to fit the compatibility things defined in jfs_user.h.
-# Use the ext2fs_ endian conversion functions because they truncate oversized
-# inputs (e.g. passing a u32 to cpu_to_be16()) like the kernel versions and
-# unlike the libc6 versions.
-exec sed -e 's/JBD_/JFS_/g' \
- -e 's/JBD2_/JFS_/g' \
- -e 's/jbd2_journal_/journal_/g' \
- -e 's/__be/__u/g' \
- -e 's/struct kmem_cache/lkmem_cache_t/g' \
- -e 's/cpu_to_be/ext2fs_cpu_to_be/g' \
- -e 's/be\([0-9][0-9]\)_to_cpu/ext2fs_be\1_to_cpu/g' \
- < "$1" > "$2"
-- Theodore Y. Ts'o <tytso@mit.edu> Tue, 07 Jan 2020 09:18:39 -0500
+e2fsprogs (1.46~WIP.2019.10.09-1) experimental; urgency=medium
+
+ * Add (minimal) support to enable the fast commit feaure. This is just
+ enough to enable kernel development work; e2fsck replay of journals
+ with the fast commit feature is *not* available.
+ * E2fsck will now check encryption policies for consistency
+
+ -- Theodore Y. Ts'o <tytso@mit.edu> Wed, 09 Oct 2019 20:22:50 -0400
+
e2fsprogs (1.45.4-1) unstable; urgency=medium
* New upstream feature
ext2fs_div_ceil@Base 1.40
ext2fs_djb2_hash@Base 1.44.3~rc1
ext2fs_dup_handle@Base 1.37
+ ext2fs_dx_csum@Base 1.46~WIP.2019.10.09
ext2fs_expand_dir@Base 1.37
ext2fs_ext_attr_block_csum_set@Base 1.43
ext2fs_ext_attr_block_csum_verify@Base 1.43
__u32 supp[3] = { EXT2_LIB_FEATURE_COMPAT_SUPP,
EXT2_LIB_FEATURE_INCOMPAT_SUPP,
EXT2_LIB_FEATURE_RO_COMPAT_SUPP };
- __u32 jrnl_supp[3] = { JFS_KNOWN_COMPAT_FEATURES,
- JFS_KNOWN_INCOMPAT_FEATURES,
- JFS_KNOWN_ROCOMPAT_FEATURES };
+ __u32 jrnl_supp[3] = { JBD2_KNOWN_COMPAT_FEATURES,
+ JBD2_KNOWN_INCOMPAT_FEATURES,
+ JBD2_KNOWN_ROCOMPAT_FEATURES };
if (argc > 1) {
ret = find_supp_feature(supp, E2P_FS_FEATURE, argv[1]);
/* write the descriptor block header */
commit = (struct commit_header *)bh->b_data;
- commit->h_magic = ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER);
- commit->h_blocktype = ext2fs_cpu_to_be32(JFS_COMMIT_BLOCK);
+ commit->h_magic = ext2fs_cpu_to_be32(JBD2_MAGIC_NUMBER);
+ commit->h_blocktype = ext2fs_cpu_to_be32(JBD2_COMMIT_BLOCK);
commit->h_sequence = ext2fs_cpu_to_be32(trans->tid);
- if (jfs_has_feature_checksum(trans->journal)) {
+ if (jbd2_has_feature_checksum(trans->journal)) {
__u32 csum_v1 = ~0;
blk64_t cblk;
}
for (cblk = trans->start; cblk < trans->block; cblk++) {
- err = journal_bmap(trans->journal, cblk,
- &cbh->b_blocknr);
+ err = jbd2_journal_bmap(trans->journal, cblk,
+ &cbh->b_blocknr);
if (err)
goto error;
mark_buffer_uptodate(cbh, 0);
- ll_rw_block(READ, 1, &cbh);
+ ll_rw_block(REQ_OP_READ, 0, 1, &cbh);
err = cbh->b_err;
if (err)
goto error;
cbh->b_size);
}
- commit->h_chksum_type = JFS_CRC32_CHKSUM;
- commit->h_chksum_size = JFS_CRC32_CHKSUM_SIZE;
+ commit->h_chksum_type = JBD2_CRC32_CHKSUM;
+ commit->h_chksum_size = JBD2_CRC32_CHKSUM_SIZE;
commit->h_chksum[0] = ext2fs_cpu_to_be32(csum_v1);
} else {
commit->h_chksum_type = 0;
/* Write block */
jbd2_commit_block_csum_set(trans->journal, bh);
- err = journal_bmap(trans->journal, trans->block, &bh->b_blocknr);
+ err = jbd2_journal_bmap(trans->journal, trans->block, &bh->b_blocknr);
if (err)
goto error;
dbg_printf("Writing commit block at %llu:%llu\n", trans->block,
bh->b_blocknr);
mark_buffer_dirty(bh);
- ll_rw_block(WRITE, 1, &bh);
+ ll_rw_block(REQ_OP_WRITE, 0, 1, &bh);
err = bh->b_err;
if (err)
goto error;
blk64_t *revoke_list,
size_t revoke_len)
{
- journal_revoke_header_t *jrb;
+ jbd2_journal_revoke_header_t *jrb;
void *buf;
size_t i, offset;
blk64_t curr_blk;
return 0;
/* Do we need to leave space at the end for a checksum? */
- if (journal_has_csum_v2or3(trans->journal))
- csum_size = sizeof(struct journal_revoke_tail);
+ if (jbd2_journal_has_csum_v2or3(trans->journal))
+ csum_size = sizeof(struct jbd2_journal_block_tail);
curr_blk = trans->block;
if (bh == NULL)
return ENOMEM;
jrb = buf = bh->b_data;
- jrb->r_header.h_magic = ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER);
- jrb->r_header.h_blocktype = ext2fs_cpu_to_be32(JFS_REVOKE_BLOCK);
+ jrb->r_header.h_magic = ext2fs_cpu_to_be32(JBD2_MAGIC_NUMBER);
+ jrb->r_header.h_blocktype = ext2fs_cpu_to_be32(JBD2_REVOKE_BLOCK);
jrb->r_header.h_sequence = ext2fs_cpu_to_be32(trans->tid);
offset = sizeof(*jrb);
- if (jfs_has_feature_64bit(trans->journal))
+ if (jbd2_has_feature_64bit(trans->journal))
sz = 8;
else
sz = 4;
jrb->r_count = ext2fs_cpu_to_be32(offset);
jbd2_revoke_csum_set(trans->journal, bh);
- err = journal_bmap(trans->journal, curr_blk,
- &bh->b_blocknr);
+ err = jbd2_journal_bmap(trans->journal, curr_blk,
+ &bh->b_blocknr);
if (err)
goto error;
dbg_printf("Writing revoke block at %llu:%llu\n",
curr_blk, bh->b_blocknr);
mark_buffer_dirty(bh);
- ll_rw_block(WRITE, 1, &bh);
+ ll_rw_block(REQ_OP_WRITE, 0, 1, &bh);
err = bh->b_err;
if (err)
goto error;
goto error;
}
- if (jfs_has_feature_64bit(trans->journal))
+ if (jbd2_has_feature_64bit(trans->journal))
*((__u64 *)(&((char *)buf)[offset])) =
ext2fs_cpu_to_be64(revoke_list[i]);
else
jrb->r_count = ext2fs_cpu_to_be32(offset);
jbd2_revoke_csum_set(trans->journal, bh);
- err = journal_bmap(trans->journal, curr_blk, &bh->b_blocknr);
+ err = jbd2_journal_bmap(trans->journal, curr_blk,
+ &bh->b_blocknr);
if (err)
goto error;
dbg_printf("Writing revoke block at %llu:%llu\n",
curr_blk, bh->b_blocknr);
mark_buffer_dirty(bh);
- ll_rw_block(WRITE, 1, &bh);
+ ll_rw_block(REQ_OP_WRITE, 0, 1, &bh);
err = bh->b_err;
if (err)
goto error;
return 0;
/* Do we need to leave space at the end for a checksum? */
- if (journal_has_csum_v2or3(trans->journal))
- csum_size = sizeof(struct journal_block_tail);
+ if (jbd2_journal_has_csum_v2or3(trans->journal))
+ csum_size = sizeof(struct jbd2_journal_block_tail);
curr_blk = jdb_blk = trans->block;
goto error;
}
jdb = jdb_buf = bh->b_data;
- jdb->h_magic = ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER);
- jdb->h_blocktype = ext2fs_cpu_to_be32(JFS_DESCRIPTOR_BLOCK);
+ jdb->h_magic = ext2fs_cpu_to_be32(JBD2_MAGIC_NUMBER);
+ jdb->h_blocktype = ext2fs_cpu_to_be32(JBD2_DESCRIPTOR_BLOCK);
jdb->h_sequence = ext2fs_cpu_to_be32(trans->tid);
jdbt = (journal_block_tag_t *)(jdb + 1);
if ((char *)jdbt + tag_bytes >
(char *)jdb_buf + trans->journal->j_blocksize - csum_size) {
jbd2_descr_block_csum_set(trans->journal, bh);
- err = journal_bmap(trans->journal, jdb_blk,
+ err = jbd2_journal_bmap(trans->journal, jdb_blk,
&bh->b_blocknr);
if (err)
goto error;
dbg_printf("Writing descriptor block at %llu:%llu\n",
jdb_blk, bh->b_blocknr);
mark_buffer_dirty(bh);
- ll_rw_block(WRITE, 1, &bh);
+ ll_rw_block(REQ_OP_WRITE, 0, 1, &bh);
err = bh->b_err;
if (err)
goto error;
jdbt->t_blocknr = ext2fs_cpu_to_be32(block_list[i] & 0xFFFFFFFF);
jdbt->t_flags = 0;
if (jdbt != (journal_block_tag_t *)(jdb + 1))
- jdbt->t_flags |= ext2fs_cpu_to_be16(JFS_FLAG_SAME_UUID);
+ jdbt->t_flags |= ext2fs_cpu_to_be16(JBD2_FLAG_SAME_UUID);
else {
memcpy(jdbt + tag_bytes,
trans->journal->j_superblock->s_uuid,
tag_bytes += 16;
}
if (i == block_len - 1)
- jdbt->t_flags |= ext2fs_cpu_to_be16(JFS_FLAG_LAST_TAG);
- if (*((__u32 *)buf) == ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER)) {
+ jdbt->t_flags |= ext2fs_cpu_to_be16(JBD2_FLAG_LAST_TAG);
+ if (*((__u32 *)buf) == ext2fs_cpu_to_be32(JBD2_MAGIC_NUMBER)) {
*((__u32 *)buf) = 0;
- jdbt->t_flags |= ext2fs_cpu_to_be16(JFS_FLAG_ESCAPE);
+ jdbt->t_flags |= ext2fs_cpu_to_be16(JBD2_FLAG_ESCAPE);
}
- if (jfs_has_feature_64bit(trans->journal))
+ if (jbd2_has_feature_64bit(trans->journal))
jdbt->t_blocknr_high = ext2fs_cpu_to_be32(block_list[i] >> 32);
jbd2_block_tag_csum_set(trans->journal, jdbt, data_bh,
trans->tid);
/* Write the data block */
- err = journal_bmap(trans->journal, curr_blk,
- &data_bh->b_blocknr);
+ err = jbd2_journal_bmap(trans->journal, curr_blk,
+ &data_bh->b_blocknr);
if (err)
goto error;
dbg_printf("Writing data block %llu at %llu:%llu tag %d\n",
block_list[i], curr_blk, data_bh->b_blocknr,
tag_bytes);
mark_buffer_dirty(data_bh);
- ll_rw_block(WRITE, 1, &data_bh);
+ ll_rw_block(REQ_OP_WRITE, 0, 1, &data_bh);
err = data_bh->b_err;
if (err)
goto error;
/* Write out the last descriptor block */
if (jdbt != (journal_block_tag_t *)(jdb + 1)) {
jbd2_descr_block_csum_set(trans->journal, bh);
- err = journal_bmap(trans->journal, jdb_blk, &bh->b_blocknr);
+ err = jbd2_journal_bmap(trans->journal, jdb_blk,
+ &bh->b_blocknr);
if (err)
goto error;
dbg_printf("Writing descriptor block at %llu:%llu\n",
jdb_blk, bh->b_blocknr);
mark_buffer_dirty(bh);
- ll_rw_block(WRITE, 1, &bh);
+ ll_rw_block(REQ_OP_WRITE, 0, 1, &bh);
err = bh->b_err;
if (err)
goto error;
/* Estimate # of revoke blocks */
bs = journal->j_blocksize;
- if (journal_has_csum_v2or3(journal))
- bs -= sizeof(struct journal_revoke_tail);
- sz = jfs_has_feature_64bit(journal) ? sizeof(__u64) : sizeof(__u32);
+ if (jbd2_journal_has_csum_v2or3(journal))
+ bs -= sizeof(struct jbd2_journal_block_tail);
+ sz = jbd2_has_feature_64bit(journal) ? sizeof(__u64) : sizeof(__u32);
ret += revoke_blocks * sz / bs;
/* Estimate # of data blocks */
bs = journal->j_blocksize - 16;
- if (journal_has_csum_v2or3(journal))
- bs -= sizeof(struct journal_block_tail);
+ if (jbd2_journal_has_csum_v2or3(journal))
+ bs -= sizeof(struct jbd2_journal_block_tail);
sz = journal_tag_bytes(journal);
ret += data_blocks * sz / bs;
errcode_t err;
if (revoke_len > 0) {
- jfs_set_feature_revoke(journal);
+ jbd2_set_feature_revoke(journal);
mark_buffer_dirty(journal->j_sb_buffer);
}
int nr = 0, size = journal->j_blocksize;
int tag_bytes = journal_tag_bytes(journal);
- if (journal_has_csum_v2or3(journal))
- size -= sizeof(struct journal_block_tail);
+ if (jbd2_journal_has_csum_v2or3(journal))
+ size -= sizeof(struct jbd2_journal_block_tail);
tagp = buf + sizeof(journal_header_t);
nr++;
tagp += tag_bytes;
- if (!(tag->t_flags & ext2fs_cpu_to_be16(JFS_FLAG_SAME_UUID)))
+ if (!(tag->t_flags & ext2fs_cpu_to_be16(JBD2_FLAG_SAME_UUID)))
tagp += 16;
- if (tag->t_flags & ext2fs_cpu_to_be16(JFS_FLAG_LAST_TAG))
+ if (tag->t_flags & ext2fs_cpu_to_be16(JBD2_FLAG_LAST_TAG))
break;
}
/* Skip over each chunk of the transaction looking
* either the next descriptor block or the final commit
* record. */
- err = journal_bmap(journal, next_log_block, &bh->b_blocknr);
+ err = jbd2_journal_bmap(journal, next_log_block,
+ &bh->b_blocknr);
if (err)
goto err;
mark_buffer_uptodate(bh, 0);
- ll_rw_block(READ, 1, &bh);
+ ll_rw_block(REQ_OP_READ, 0, 1, &bh);
err = bh->b_err;
if (err)
goto err;
tmp = (journal_header_t *)bh->b_data;
- if (tmp->h_magic != ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER)) {
+ if (tmp->h_magic != ext2fs_cpu_to_be32(JBD2_MAGIC_NUMBER)) {
dbg_printf("JBD2: wrong magic 0x%x\n", tmp->h_magic);
goto err;
}
* to do with it? That depends on the pass... */
switch (blocktype) {
- case JFS_DESCRIPTOR_BLOCK:
+ case JBD2_DESCRIPTOR_BLOCK:
next_log_block += count_tags(journal, bh->b_data);
wrap(journal, next_log_block);
continue;
- case JFS_COMMIT_BLOCK:
+ case JBD2_COMMIT_BLOCK:
head_block = next_log_block;
next_commit_ID++;
continue;
- case JFS_REVOKE_BLOCK:
+ case JBD2_REVOKE_BLOCK:
continue;
default:
printf("Setting csum v%d\n", ver);
switch (ver) {
case 2:
- jfs_clear_feature_csum3(journal);
- jfs_set_feature_csum2(journal);
- jfs_clear_feature_checksum(journal);
+ jbd2_clear_feature_csum3(journal);
+ jbd2_set_feature_csum2(journal);
+ jbd2_clear_feature_checksum(journal);
break;
case 3:
- jfs_set_feature_csum3(journal);
- jfs_clear_feature_csum2(journal);
- jfs_clear_feature_checksum(journal);
+ jbd2_set_feature_csum3(journal);
+ jbd2_clear_feature_csum2(journal);
+ jbd2_clear_feature_checksum(journal);
break;
default:
printf("Unknown checksum v%d\n", ver);
journal->j_csum_seed = jbd2_chksum(journal, ~0, jsb->s_uuid,
sizeof(jsb->s_uuid));
} else {
- jfs_clear_feature_csum3(journal);
- jfs_clear_feature_csum2(journal);
- jfs_set_feature_checksum(journal);
+ jbd2_clear_feature_csum3(journal);
+ jbd2_clear_feature_csum2(journal);
+ jbd2_set_feature_checksum(journal);
}
}
if (!ext2fs_has_feature_64bit(fs->super))
return;
- if (jfs_has_feature_64bit(journal) &&
+ if (jbd2_has_feature_64bit(journal) &&
ext2fs_has_feature_64bit(fs->super))
return;
if (!ext2fs_has_feature_64bit(journal->j_fs_dev->k_fs->super))
return;
- if (jfs_has_feature_64bit(journal) &&
+ if (jbd2_has_feature_64bit(journal) &&
ext2fs_has_feature_64bit(journal->j_fs_dev->k_fs->super))
return;
return;
}
- jfs_set_feature_64bit(journal);
+ jbd2_set_feature_64bit(journal);
}
void do_journal_open(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
static void htree_dump_int_node(ext2_filsys fs, ext2_ino_t ino,
struct ext2_inode *inode,
struct ext2_dx_root_info * rootnode,
- struct ext2_dx_entry *ent,
+ struct ext2_dx_entry *ent, __u32 crc,
char *buf, int level)
{
struct ext2_dx_countlimit dx_countlimit;
if (ext2fs_has_feature_metadata_csum(fs->super) &&
remainder == sizeof(struct ext2_dx_tail)) {
tail = (struct ext2_dx_tail *)(ent + limit);
- fprintf(pager, "Checksum: 0x%08x\n",
+ fprintf(pager, "Checksum: 0x%08x",
ext2fs_le32_to_cpu(tail->dt_checksum));
+ if (tail->dt_checksum != crc)
+ fprintf(pager, " --- EXPECTED: 0x%08x", crc);
+ fputc('\n', pager);
}
for (i=0; i < count; i++) {
char *cbuf;
errcode_t errcode;
blk64_t pblk;
+ __u32 crc;
cbuf = malloc(fs->blocksize);
if (!cbuf) {
errcode = io_channel_read_blk64(current_fs->io, pblk, 1, buf);
if (errcode) {
com_err("htree_dump_int_block", errcode,
- "while reading block %llu\n", blk);
+ "while reading block %llu\n", blk);
goto errout;
}
+ errcode = ext2fs_dx_csum(current_fs, ino,
+ (struct ext2_dir_entry *) buf, &crc, NULL);
+ if (errcode) {
+ com_err("htree_dump_int_block", errcode,
+ "while calculating checksum for logical block %llu\n",
+ (unsigned long long) blk);
+ crc = (unsigned int) -1;
+ }
htree_dump_int_node(fs, ino, inode, rootnode,
(struct ext2_dx_entry *) (buf+8),
- cbuf, level);
+ crc, cbuf, level);
errout:
free(cbuf);
}
struct ext2_dx_root_info *rootnode;
struct ext2_dx_entry *ent;
errcode_t errcode;
+ __u32 crc;
if (check_fs_open(argv[0]))
return;
ent = (struct ext2_dx_entry *)
((char *)rootnode + rootnode->info_length);
- htree_dump_int_node(current_fs, ino, &inode, rootnode, ent,
+ errcode = ext2fs_dx_csum(current_fs, ino,
+ (struct ext2_dir_entry *) buf, &crc, NULL);
+ if (errcode) {
+ com_err("htree_dump_int_block", errcode,
+ "while calculating checksum for htree root\n");
+ crc = (unsigned int) -1;
+ }
+ htree_dump_int_node(current_fs, ino, &inode, rootnode, ent, crc,
buf + current_fs->blocksize,
rootnode->indirect_levels);
static int ext2fs_journal_verify_csum_type(journal_t *j,
journal_superblock_t *jsb)
{
- if (!journal_has_csum_v2or3(j))
+ if (!jbd2_journal_has_csum_v2or3(j))
return 1;
return jsb->s_checksum_type == JBD2_CRC32C_CHKSUM;
{
__u32 provided, calculated;
- if (!journal_has_csum_v2or3(j))
+ if (!jbd2_journal_has_csum_v2or3(j))
return 1;
provided = ext2fs_be32_to_cpu(jsb->s_checksum);
{
__u32 crc;
- if (!journal_has_csum_v2or3(j))
+ if (!jbd2_journal_has_csum_v2or3(j))
return 0;
crc = ext2fs_journal_sb_csum(jsb);
* to use the recovery.c file virtually unchanged from the kernel, so we
* don't have to do much to keep kernel and user recovery in sync.
*/
-int journal_bmap(journal_t *journal, blk64_t block, unsigned long long *phys)
+int jbd2_journal_bmap(journal_t *journal, unsigned long block,
+ unsigned long long *phys)
{
#ifdef USE_INODE_IO
*phys = block;
}
retval = ext2fs_bmap2(inode->i_fs, inode->i_ino,
- &inode->i_ext2, NULL, 0, block, 0, &pblk);
+ &inode->i_ext2, NULL, 0, (blk64_t) block,
+ 0, &pblk);
*phys = pblk;
return (int) retval;
#endif
}
-struct buffer_head *getblk(kdev_t kdev, blk64_t blocknr, int blocksize)
+struct buffer_head *getblk(kdev_t kdev, unsigned long long blocknr,
+ int blocksize)
{
struct buffer_head *bh;
int bufsize = sizeof(*bh) + kdev->k_fs->blocksize -
bh_count++;
#endif
jfs_debug(4, "getblk for block %llu (%d bytes)(total %d)\n",
- (unsigned long long) blocknr, blocksize, bh_count);
+ blocknr, blocksize, bh_count);
bh->b_fs = kdev->k_fs;
if (kdev->k_dev == K_DEV_FS)
return io_channel_flush(io) ? EIO : 0;
}
-void ll_rw_block(int rw, int nr, struct buffer_head *bhp[])
+void ll_rw_block(int rw, int op_flags, int nr, struct buffer_head *bhp[])
{
errcode_t retval;
struct buffer_head *bh;
for (; nr > 0; --nr) {
bh = *bhp++;
- if (rw == READ && !bh->b_uptodate) {
+ if (rw == REQ_OP_READ && !bh->b_uptodate) {
jfs_debug(3, "reading block %llu/%p\n",
bh->b_blocknr, (void *) bh);
retval = io_channel_read_blk64(bh->b_io,
continue;
}
bh->b_uptodate = 1;
- } else if (rw == WRITE && bh->b_dirty) {
+ } else if (rw == REQ_OP_WRITE && bh->b_dirty) {
jfs_debug(3, "writing block %llu/%p\n",
bh->b_blocknr,
(void *) bh);
bh->b_uptodate = 1;
} else {
jfs_debug(3, "no-op %s for block %llu\n",
- rw == READ ? "read" : "write",
+ rw == REQ_OP_READ ? "read" : "write",
bh->b_blocknr);
}
}
void brelse(struct buffer_head *bh)
{
if (bh->b_dirty)
- ll_rw_block(WRITE, 1, &bh);
+ ll_rw_block(REQ_OP_WRITE, 0, 1, &bh);
jfs_debug(3, "freeing block %llu/%p (total %d)\n",
bh->b_blocknr, (void *) bh, --bh_count);
ext2fs_free_mem(&bh);
void wait_on_buffer(struct buffer_head *bh)
{
if (!bh->b_uptodate)
- ll_rw_block(READ, 1, &bh);
+ ll_rw_block(REQ_OP_READ, 0, 1, &bh);
}
goto try_backup_journal;
}
if (EXT2_I_SIZE(&j_inode->i_ext2) / journal->j_blocksize <
- JFS_MIN_JOURNAL_BLOCKS) {
+ JBD2_MIN_JOURNAL_BLOCKS) {
retval = EXT2_ET_JOURNAL_TOO_SMALL;
goto try_backup_journal;
}
#else
journal->j_inode = j_inode;
fs->journal_io = fs->io;
- retval = (errcode_t)journal_bmap(journal, 0, &start);
+ retval = (errcode_t) jbd2_journal_bmap(journal, 0, &start);
if (retval)
goto errout;
#endif
retval = EXT2_ET_NO_MEMORY;
goto errout;
}
- ll_rw_block(READ, 1, &bh);
+ ll_rw_block(REQ_OP_READ, 0, 1, &bh);
retval = bh->b_err;
if (retval) {
brelse(bh);
journal_superblock_t *jsb;
struct buffer_head *jbh = journal->j_sb_buffer;
- ll_rw_block(READ, 1, &jbh);
+ ll_rw_block(REQ_OP_READ, 0, 1, &jbh);
if (jbh->b_err)
return jbh->b_err;
jsb = journal->j_superblock;
- /* If we don't even have JFS_MAGIC, we probably have a wrong inode */
- if (jsb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER))
+ /* If we don't even have JBD2_MAGIC, we probably have a wrong inode */
+ if (jsb->s_header.h_magic != htonl(JBD2_MAGIC_NUMBER))
return ext2fs_journal_fix_bad_inode(fs);
switch (ntohl(jsb->s_header.h_blocktype)) {
- case JFS_SUPERBLOCK_V1:
+ case JBD2_SUPERBLOCK_V1:
journal->j_format_version = 1;
if (jsb->s_feature_compat ||
jsb->s_feature_incompat ||
clear_v2_journal_fields(journal);
break;
- case JFS_SUPERBLOCK_V2:
+ case JBD2_SUPERBLOCK_V2:
journal->j_format_version = 2;
if (ntohl(jsb->s_nr_users) > 1 &&
uuid_is_null(fs->super->s_journal_uuid))
* These should never appear in a journal super block, so if
* they do, the journal is badly corrupted.
*/
- case JFS_DESCRIPTOR_BLOCK:
- case JFS_COMMIT_BLOCK:
- case JFS_REVOKE_BLOCK:
+ case JBD2_DESCRIPTOR_BLOCK:
+ case JBD2_COMMIT_BLOCK:
+ case JBD2_REVOKE_BLOCK:
return EXT2_ET_CORRUPT_JOURNAL_SB;
/* If we don't understand the superblock major type, but there
return EXT2_ET_JOURNAL_UNSUPP_VERSION;
}
- if (JFS_HAS_INCOMPAT_FEATURE(journal, ~JFS_KNOWN_INCOMPAT_FEATURES))
+ if (JBD2_HAS_INCOMPAT_FEATURE(journal, ~JBD2_KNOWN_INCOMPAT_FEATURES))
return EXT2_ET_UNSUPP_FEATURE;
- if (JFS_HAS_RO_COMPAT_FEATURE(journal, ~JFS_KNOWN_ROCOMPAT_FEATURES))
+ if (JBD2_HAS_RO_COMPAT_FEATURE(journal, ~JBD2_KNOWN_ROCOMPAT_FEATURES))
return EXT2_ET_RO_UNSUPP_FEATURE;
/* Checksum v1-3 are mutually exclusive features. */
- if (jfs_has_feature_csum2(journal) && jfs_has_feature_csum3(journal))
+ if (jbd2_has_feature_csum2(journal) && jbd2_has_feature_csum3(journal))
return EXT2_ET_CORRUPT_JOURNAL_SB;
- if (journal_has_csum_v2or3(journal) &&
- jfs_has_feature_checksum(journal))
+ if (jbd2_journal_has_csum_v2or3(journal) &&
+ jbd2_has_feature_checksum(journal))
return EXT2_ET_CORRUPT_JOURNAL_SB;
if (!ext2fs_journal_verify_csum_type(journal, jsb) ||
!ext2fs_journal_sb_csum_verify(journal, jsb))
return EXT2_ET_CORRUPT_JOURNAL_SB;
- if (journal_has_csum_v2or3(journal))
+ if (jbd2_journal_has_csum_v2or3(journal))
journal->j_csum_seed = jbd2_chksum(journal, ~0, jsb->s_uuid,
sizeof(jsb->s_uuid));
journal_t *journal;
errcode_t retval;
- journal_init_revoke_caches();
+ retval = jbd2_journal_init_revoke_record_cache();
+ if (retval)
+ return retval;
+
+ retval = jbd2_journal_init_revoke_table_cache();
+ if (retval)
+ return retval;
+
retval = ext2fs_get_journal(fs, &journal);
if (retval)
return retval;
if (retval)
goto errout;
- retval = journal_init_revoke(journal, 1024);
+ retval = jbd2_journal_init_revoke(journal, 1024);
if (retval)
goto errout;
- retval = -journal_recover(journal);
+ retval = -jbd2_journal_recover(journal);
if (retval)
goto errout;
}
errout:
- journal_destroy_revoke(journal);
- journal_destroy_revoke_caches();
+ jbd2_journal_destroy_revoke(journal);
+ jbd2_journal_destroy_revoke_record_cache();
+ jbd2_journal_destroy_revoke_table_cache();
ext2fs_journal_release(fs, journal, 1, 0);
return retval;
}
journal_t *journal;
errcode_t retval;
- journal_init_revoke_caches();
+ retval = jbd2_journal_init_revoke_record_cache();
+ if (retval)
+ return retval;
+
+ retval = jbd2_journal_init_revoke_table_cache();
+ if (retval)
+ return retval;
+
retval = ext2fs_get_journal(fs, &journal);
if (retval)
return retval;
if (retval)
goto errout;
- retval = journal_init_revoke(journal, 1024);
+ retval = jbd2_journal_init_revoke(journal, 1024);
if (retval)
goto errout;
return 0;
errout:
- journal_destroy_revoke(journal);
- journal_destroy_revoke_caches();
+ jbd2_journal_destroy_revoke(journal);
+ jbd2_journal_destroy_revoke_record_cache();
+ jbd2_journal_destroy_revoke_table_cache();
ext2fs_journal_release(fs, journal, 1, 0);
return retval;
}
{
journal_t *journal = *j;
- journal_destroy_revoke(journal);
- journal_destroy_revoke_caches();
+ jbd2_journal_destroy_revoke(journal);
+ jbd2_journal_destroy_revoke_record_cache();
+ jbd2_journal_destroy_revoke_table_cache();
ext2fs_journal_release(fs, journal, 0, 0);
*j = NULL;
struct commit_header *h;
__u32 csum;
- if (!journal_has_csum_v2or3(j))
+ if (!jbd2_journal_has_csum_v2or3(j))
return;
h = (struct commit_header *)(bh->b_data);
void jbd2_revoke_csum_set(journal_t *j, struct buffer_head *bh)
{
- struct journal_revoke_tail *tail;
- __u32 csum;
-
- if (!journal_has_csum_v2or3(j))
- return;
-
- tail = (struct journal_revoke_tail *)(bh->b_data + j->j_blocksize -
- sizeof(struct journal_revoke_tail));
- tail->r_checksum = 0;
- csum = jbd2_chksum(j, j->j_csum_seed, bh->b_data, j->j_blocksize);
- tail->r_checksum = ext2fs_cpu_to_be32(csum);
+ jbd2_descr_block_csum_set(j, bh);
}
void jbd2_descr_block_csum_set(journal_t *j, struct buffer_head *bh)
{
- struct journal_block_tail *tail;
+ struct jbd2_journal_block_tail *tail;
__u32 csum;
- if (!journal_has_csum_v2or3(j))
+ if (!jbd2_journal_has_csum_v2or3(j))
return;
- tail = (struct journal_block_tail *)(bh->b_data + j->j_blocksize -
- sizeof(struct journal_block_tail));
+ 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 = ext2fs_cpu_to_be32(csum);
__u32 csum32;
__be32 seq;
- if (!journal_has_csum_v2or3(j))
+ if (!jbd2_journal_has_csum_v2or3(j))
return;
seq = ext2fs_cpu_to_be32(sequence);
csum32 = jbd2_chksum(j, j->j_csum_seed, (__u8 *)&seq, sizeof(seq));
csum32 = jbd2_chksum(j, csum32, bh->b_data, bh->b_size);
- if (jfs_has_feature_csum3(j))
+ if (jbd2_has_feature_csum3(j))
tag3->t_checksum = ext2fs_cpu_to_be32(csum32);
else
tag->t_checksum = ext2fs_cpu_to_be16(csum32);
static const char *type_to_name(int btype)
{
switch (btype) {
- case JFS_DESCRIPTOR_BLOCK:
+ case JBD2_DESCRIPTOR_BLOCK:
return "descriptor block";
- case JFS_COMMIT_BLOCK:
+ case JBD2_COMMIT_BLOCK:
return "commit block";
- case JFS_SUPERBLOCK_V1:
+ case JBD2_SUPERBLOCK_V1:
return "V1 superblock";
- case JFS_SUPERBLOCK_V2:
+ case JBD2_SUPERBLOCK_V2:
return "V2 superblock";
- case JFS_REVOKE_BLOCK:
+ case JBD2_REVOKE_BLOCK:
return "revoke table";
}
return "unrecognised type";
ext2fs_swap_super(sb);
#endif
- if ((be32_to_cpu(jsb->s_header.h_magic) != JFS_MAGIC_NUMBER) &&
+ if ((be32_to_cpu(jsb->s_header.h_magic) != JBD2_MAGIC_NUMBER) &&
(sb->s_magic == EXT2_SUPER_MAGIC) &&
ext2fs_has_feature_journal_dev(sb)) {
blocksize = EXT2_BLOCK_SIZE(sb);
}
jsb = (journal_superblock_t *) jsb_buffer;
- if (be32_to_cpu(jsb->s_header.h_magic) != JFS_MAGIC_NUMBER) {
+ if (be32_to_cpu(jsb->s_header.h_magic) != JBD2_MAGIC_NUMBER) {
fprintf(out_file,
"Journal superblock magic number invalid!\n");
return;
sequence = be32_to_cpu(header->h_sequence);
blocktype = be32_to_cpu(header->h_blocktype);
- if (magic != JFS_MAGIC_NUMBER) {
+ if (magic != JBD2_MAGIC_NUMBER) {
fprintf (out_file, "No magic number at block %u: "
"end of journal.\n", blocknr);
return;
}
switch (blocktype) {
- case JFS_DESCRIPTOR_BLOCK:
+ case JBD2_DESCRIPTOR_BLOCK:
dump_descriptor_block(out_file, source, buf, jsb,
&blocknr, blocksize,
transaction);
continue;
- case JFS_COMMIT_BLOCK:
+ case JBD2_COMMIT_BLOCK:
transaction++;
blocknr++;
WRAP(jsb, blocknr);
continue;
- case JFS_REVOKE_BLOCK:
+ case JBD2_REVOKE_BLOCK:
dump_revoke_block(out_file, buf, jsb,
blocknr, blocksize,
transaction);
{
size_t sz;
- if (JSB_HAS_INCOMPAT_FEATURE(jsb, JFS_FEATURE_INCOMPAT_CSUM_V3))
+ if (JSB_HAS_INCOMPAT_FEATURE(jsb, JBD2_FEATURE_INCOMPAT_CSUM_V3))
return sizeof(journal_block_tag3_t);
sz = sizeof(journal_block_tag_t);
- if (JSB_HAS_INCOMPAT_FEATURE(jsb, JFS_FEATURE_INCOMPAT_CSUM_V2))
+ if (JSB_HAS_INCOMPAT_FEATURE(jsb, JBD2_FEATURE_INCOMPAT_CSUM_V2))
sz += sizeof(__u16);
- if (JSB_HAS_INCOMPAT_FEATURE(jsb, JFS_FEATURE_INCOMPAT_64BIT))
+ if (JSB_HAS_INCOMPAT_FEATURE(jsb, JBD2_FEATURE_INCOMPAT_64BIT))
return sz;
return sz - sizeof(__u32);
offset = sizeof(journal_header_t);
blocknr = *blockp;
- if (JSB_HAS_INCOMPAT_FEATURE(jsb, JFS_FEATURE_INCOMPAT_CSUM_V3) ||
- JSB_HAS_INCOMPAT_FEATURE(jsb, JFS_FEATURE_INCOMPAT_CSUM_V2))
- csum_size = sizeof(struct journal_block_tail);
+ if (JSB_HAS_INCOMPAT_FEATURE(jsb, JBD2_FEATURE_INCOMPAT_CSUM_V3) ||
+ JSB_HAS_INCOMPAT_FEATURE(jsb, JBD2_FEATURE_INCOMPAT_CSUM_V2))
+ csum_size = sizeof(struct jbd2_journal_block_tail);
if (dump_all)
fprintf(out_file, "Dumping descriptor block, sequence %u, at "
tag_block = be32_to_cpu(tag->t_blocknr);
tag_flags = be16_to_cpu(tag->t_flags);
- if (!(tag_flags & JFS_FLAG_SAME_UUID))
+ if (!(tag_flags & JBD2_FLAG_SAME_UUID))
offset += 16;
dump_metadata_block(out_file, source, jsb,
++blocknr;
WRAP(jsb, blocknr);
- } while (!(tag_flags & JFS_FLAG_LAST_TAG));
+ } while (!(tag_flags & JBD2_FLAG_LAST_TAG));
*blockp = blocknr;
}
tid_t transaction)
{
int offset, max;
- journal_revoke_header_t *header;
+ jbd2_journal_revoke_header_t *header;
unsigned long long rblock;
int tag_size = sizeof(__u32);
fprintf(out_file, "Dumping revoke block, sequence %u, at "
"block %u:\n", transaction, blocknr);
- if (be32_to_cpu(jsb->s_feature_incompat) & JFS_FEATURE_INCOMPAT_64BIT)
+ if (be32_to_cpu(jsb->s_feature_incompat) & JBD2_FEATURE_INCOMPAT_64BIT)
tag_size = sizeof(__u64);
- header = (journal_revoke_header_t *) buf;
- offset = sizeof(journal_revoke_header_t);
+ header = (jbd2_journal_revoke_header_t *) buf;
+ offset = sizeof(jbd2_journal_revoke_header_t);
max = be32_to_cpu(header->r_count);
while (offset < max) {
"sigcatcher.c",
"readahead.c",
"extents.c",
+ "encrypted_files.c",
],
cflags: [
"-Wno-sign-compare",
dx_dirinfo.o ehandler.o problem.o message.o quota.o recovery.o \
region.o revoke.o ea_refcount.o rehash.o \
logfile.o sigcatcher.o $(MTRACE_OBJ) readahead.o \
- extents.o
+ extents.o encrypted_files.o
PROFILED_OBJS= profiled/unix.o profiled/e2fsck.o \
profiled/super.o profiled/pass1.o profiled/pass1b.o \
profiled/recovery.o profiled/region.o profiled/revoke.o \
profiled/ea_refcount.o profiled/rehash.o \
profiled/logfile.o profiled/sigcatcher.o \
- profiled/readahead.o profiled/extents.o
+ profiled/readahead.o profiled/extents.o \
+ profiled/encrypted_files.o
SRCS= $(srcdir)/e2fsck.c \
$(srcdir)/super.c \
$(srcdir)/logfile.c \
$(srcdir)/quota.c \
$(srcdir)/extents.c \
+ $(srcdir)/encrypted_files.c \
$(MTRACE_SRC)
all:: profiled $(PROGS) e2fsck $(MANPAGES) $(FMANPAGES)
$(top_builddir)/lib/support/prof_err.h $(top_srcdir)/lib/support/quotaio.h \
$(top_srcdir)/lib/support/dqblk_v2.h \
$(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/problem.h
+encrypted_files.o: $(srcdir)/encrypted_files.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/e2fsck.h \
+ $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
+ $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
+ $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
+ $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/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 \
+ $(top_srcdir)/lib/support/dqblk_v2.h \
+ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/problem.h \
+ $(top_srcdir)/lib/ext2fs/rbtree.h
ext2fs_u32_list_free(ctx->dirs_to_hash);
ctx->dirs_to_hash = 0;
}
+ destroy_encrypted_file_info(ctx);
/*
* Clear the array of invalid meta-data flags
ext2fs_free_mem(&ctx->invalid_inode_table_flag);
ctx->invalid_inode_table_flag = 0;
}
- if (ctx->encrypted_dirs) {
- ext2fs_u32_list_free(ctx->encrypted_dirs);
- ctx->encrypted_dirs = 0;
- }
if (ctx->inode_count) {
ext2fs_free_icount(ctx->inode_count);
ctx->inode_count = 0;
#define DX_FLAG_FIRST 4
#define DX_FLAG_LAST 8
+struct encrypted_file_info;
+
#define RESOURCE_TRACK
#ifdef RESOURCE_TRACK
#define E2F_OPT_NOOPT_EXTENTS 0x10000 /* don't optimize extents */
#define E2F_OPT_ICOUNT_FULLMAP 0x20000 /* use an array for inode counts */
#define E2F_OPT_UNSHARE_BLOCKS 0x40000
+#define E2F_OPT_CLEAR_UNINIT 0x80000 /* Hack to clear the uninit bit */
/*
* E2fsck flags
*/
ext2_u32_list dirs_to_hash;
+ /*
+ * Encrypted file information
+ */
+ struct encrypted_file_info *encrypted_files;
+
/*
* Tuning parameters
*/
int ext_attr_ver;
profile_t profile;
int blocks_per_page;
- ext2_u32_list encrypted_dirs;
/* Reserve blocks for root and l+f re-creation */
blk64_t root_repair_block, lnf_repair_block;
extern const char *ehandler_operation(const char *op);
extern void ehandler_init(io_channel channel);
-/* extents.c */
+/* encrypted_files.c */
+
struct problem_context;
+int add_encrypted_file(e2fsck_t ctx, struct problem_context *pctx);
+
+#define NO_ENCRYPTION_POLICY ((__u32)-1)
+#define CORRUPT_ENCRYPTION_POLICY ((__u32)-2)
+#define UNRECOGNIZED_ENCRYPTION_POLICY ((__u32)-3)
+__u32 find_encryption_policy(e2fsck_t ctx, ext2_ino_t ino);
+
+void destroy_encryption_policy_map(e2fsck_t ctx);
+void destroy_encrypted_file_info(e2fsck_t ctx);
+
+/* extents.c */
errcode_t e2fsck_rebuild_extents_later(e2fsck_t ctx, ext2_ino_t ino);
int e2fsck_ino_will_be_rebuilt(e2fsck_t ctx, ext2_ino_t ino);
void e2fsck_pass1e(e2fsck_t ctx);
--- /dev/null
+/*
+ * encrypted_files.c --- save information about encrypted files
+ *
+ * Copyright 2019 Google LLC
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+/*
+ * e2fsck pass 1 (inode table scan) creates a map from inode number to
+ * encryption policy for all encrypted inodes. But it's optimized so that the
+ * full xattrs aren't saved but rather only 32-bit "policy IDs", since usually
+ * many inodes share the same encryption policy. This requires also maintaining
+ * a second map, from policy to policy ID. See add_encrypted_file().
+ *
+ * We also use run-length encoding to save memory when many adjacent inodes
+ * share the same encryption policy, which is often the case too.
+ *
+ * e2fsck pass 2 (directory structure check) uses the inode => policy ID map to
+ * verify that all regular files, directories, and symlinks in encrypted
+ * directories use the directory's encryption policy.
+ */
+
+#include "config.h"
+
+#include "e2fsck.h"
+#include "problem.h"
+#include "ext2fs/rbtree.h"
+
+#define FSCRYPT_KEY_DESCRIPTOR_SIZE 8
+#define FSCRYPT_KEY_IDENTIFIER_SIZE 16
+#define FS_KEY_DERIVATION_NONCE_SIZE 16
+
+struct fscrypt_context_v1 {
+ __u8 version;
+ __u8 contents_encryption_mode;
+ __u8 filenames_encryption_mode;
+ __u8 flags;
+ __u8 master_key_descriptor[FSCRYPT_KEY_DESCRIPTOR_SIZE];
+ __u8 nonce[FS_KEY_DERIVATION_NONCE_SIZE];
+};
+
+struct fscrypt_context_v2 {
+ __u8 version;
+ __u8 contents_encryption_mode;
+ __u8 filenames_encryption_mode;
+ __u8 flags;
+ __u8 __reserved[4];
+ __u8 master_key_identifier[FSCRYPT_KEY_IDENTIFIER_SIZE];
+ __u8 nonce[FS_KEY_DERIVATION_NONCE_SIZE];
+};
+
+/* On-disk format of encryption xattr */
+union fscrypt_context {
+ __u8 version;
+ struct fscrypt_context_v1 v1;
+ struct fscrypt_context_v2 v2;
+};
+
+struct fscrypt_policy_v1 {
+ __u8 version;
+ __u8 contents_encryption_mode;
+ __u8 filenames_encryption_mode;
+ __u8 flags;
+ __u8 master_key_descriptor[FSCRYPT_KEY_DESCRIPTOR_SIZE];
+};
+
+struct fscrypt_policy_v2 {
+ __u8 version;
+ __u8 contents_encryption_mode;
+ __u8 filenames_encryption_mode;
+ __u8 flags;
+ __u8 __reserved[4];
+ __u8 master_key_identifier[FSCRYPT_KEY_IDENTIFIER_SIZE];
+};
+
+/* The encryption "policy" is the fscrypt_context excluding the nonce. */
+union fscrypt_policy {
+ __u8 version;
+ struct fscrypt_policy_v1 v1;
+ struct fscrypt_policy_v2 v2;
+};
+
+/* A range of inodes which share the same encryption policy */
+struct encrypted_file_range {
+ ext2_ino_t first_ino;
+ ext2_ino_t last_ino;
+ __u32 policy_id;
+};
+
+/* Information about the encrypted files which have been seen so far */
+struct encrypted_file_info {
+ /*
+ * Map from inode number to encryption policy ID, implemented as a
+ * sorted array of inode ranges, each of which shares the same policy.
+ * Inodes are added in order of increasing inode number.
+ *
+ * Freed after pass 2.
+ */
+ struct encrypted_file_range *file_ranges;
+ size_t file_ranges_count;
+ size_t file_ranges_capacity;
+
+ /*
+ * Map from encryption policy to encryption policy ID, for the unique
+ * encryption policies that have been seen so far. next_policy_id is
+ * the next available ID, starting at 0.
+ *
+ * Freed after pass 1.
+ */
+ struct rb_root policies;
+ __u32 next_policy_id;
+};
+
+/* Entry in encrypted_file_info::policies */
+struct policy_map_entry {
+ union fscrypt_policy policy;
+ __u32 policy_id;
+ struct rb_node node;
+};
+
+static int cmp_fscrypt_policies(e2fsck_t ctx, const union fscrypt_policy *a,
+ const union fscrypt_policy *b)
+{
+ if (a->version != b->version)
+ return (int)a->version - (int)b->version;
+
+ switch (a->version) {
+ case 1:
+ return memcmp(a, b, sizeof(a->v1));
+ case 2:
+ return memcmp(a, b, sizeof(a->v2));
+ }
+ fatal_error(ctx, "Unhandled encryption policy version");
+ return 0;
+}
+
+/* Read an inode's encryption xattr. */
+static errcode_t read_encryption_xattr(e2fsck_t ctx, ext2_ino_t ino,
+ void **value, size_t *value_len)
+{
+ struct ext2_xattr_handle *h;
+ errcode_t retval;
+
+ retval = ext2fs_xattrs_open(ctx->fs, ino, &h);
+ if (retval)
+ return retval;
+
+ retval = ext2fs_xattrs_read(h);
+ if (retval == 0)
+ retval = ext2fs_xattr_get(h, "c", value, value_len);
+
+ ext2fs_xattrs_close(&h);
+ return retval;
+}
+
+/*
+ * Convert an fscrypt_context to an fscrypt_policy. Returns 0,
+ * CORRUPT_ENCRYPTION_POLICY, or UNRECOGNIZED_ENCRYPTION_POLICY.
+ */
+static __u32 fscrypt_context_to_policy(const void *xattr, size_t xattr_size,
+ union fscrypt_policy *policy_u)
+{
+ const union fscrypt_context *ctx_u = xattr;
+
+ if (xattr_size < 1)
+ return CORRUPT_ENCRYPTION_POLICY;
+ switch (ctx_u->version) {
+ case 0:
+ return CORRUPT_ENCRYPTION_POLICY;
+ case 1: {
+ struct fscrypt_policy_v1 *policy = &policy_u->v1;
+ const struct fscrypt_context_v1 *ctx = &ctx_u->v1;
+
+ if (xattr_size != sizeof(*ctx))
+ return CORRUPT_ENCRYPTION_POLICY;
+ policy->version = ctx->version;
+ policy->contents_encryption_mode =
+ ctx->contents_encryption_mode;
+ policy->filenames_encryption_mode =
+ ctx->filenames_encryption_mode;
+ policy->flags = ctx->flags;
+ memcpy(policy->master_key_descriptor,
+ ctx->master_key_descriptor,
+ sizeof(policy->master_key_descriptor));
+ return 0;
+ }
+ case 2: {
+ struct fscrypt_policy_v2 *policy = &policy_u->v2;
+ const struct fscrypt_context_v2 *ctx = &ctx_u->v2;
+
+ if (xattr_size != sizeof(*ctx))
+ return CORRUPT_ENCRYPTION_POLICY;
+ policy->version = ctx->version;
+ policy->contents_encryption_mode =
+ ctx->contents_encryption_mode;
+ policy->filenames_encryption_mode =
+ ctx->filenames_encryption_mode;
+ policy->flags = ctx->flags;
+ memcpy(policy->__reserved, ctx->__reserved,
+ sizeof(policy->__reserved));
+ memcpy(policy->master_key_identifier,
+ ctx->master_key_identifier,
+ sizeof(policy->master_key_identifier));
+ return 0;
+ }
+ }
+ return UNRECOGNIZED_ENCRYPTION_POLICY;
+}
+
+/*
+ * Read an inode's encryption xattr and get/allocate its encryption policy ID,
+ * or alternatively use one of the special IDs NO_ENCRYPTION_POLICY,
+ * CORRUPT_ENCRYPTION_POLICY, or UNRECOGNIZED_ENCRYPTION_POLICY.
+ *
+ * Returns nonzero only if out of memory.
+ */
+static errcode_t get_encryption_policy_id(e2fsck_t ctx, ext2_ino_t ino,
+ __u32 *policy_id_ret)
+{
+ struct encrypted_file_info *info = ctx->encrypted_files;
+ struct rb_node **new = &info->policies.rb_node;
+ struct rb_node *parent = NULL;
+ void *xattr;
+ size_t xattr_size;
+ union fscrypt_policy policy;
+ __u32 policy_id;
+ struct policy_map_entry *entry;
+ errcode_t retval;
+
+ retval = read_encryption_xattr(ctx, ino, &xattr, &xattr_size);
+ if (retval == EXT2_ET_NO_MEMORY)
+ return retval;
+ if (retval) {
+ *policy_id_ret = NO_ENCRYPTION_POLICY;
+ return 0;
+ }
+
+ /* Translate the xattr to an fscrypt_policy, if possible. */
+ policy_id = fscrypt_context_to_policy(xattr, xattr_size, &policy);
+ ext2fs_free_mem(&xattr);
+ if (policy_id != 0)
+ goto out;
+
+ /* Check if the policy was already seen. */
+ while (*new) {
+ int res;
+
+ parent = *new;
+ entry = ext2fs_rb_entry(parent, struct policy_map_entry, node);
+ res = cmp_fscrypt_policies(ctx, &policy, &entry->policy);
+ if (res < 0) {
+ new = &parent->rb_left;
+ } else if (res > 0) {
+ new = &parent->rb_right;
+ } else {
+ /* Policy already seen. Use existing ID. */
+ policy_id = entry->policy_id;
+ goto out;
+ }
+ }
+
+ /* First time seeing this policy. Allocate a new policy ID. */
+ retval = ext2fs_get_mem(sizeof(*entry), &entry);
+ if (retval)
+ goto out;
+ policy_id = info->next_policy_id++;
+ entry->policy_id = policy_id;
+ entry->policy = policy;
+ ext2fs_rb_link_node(&entry->node, parent, new);
+ ext2fs_rb_insert_color(&entry->node, &info->policies);
+out:
+ *policy_id_ret = policy_id;
+ return retval;
+}
+
+static int handle_nomem(e2fsck_t ctx, struct problem_context *pctx,
+ size_t size_needed)
+{
+ pctx->num = size_needed;
+ fix_problem(ctx, PR_1_ALLOCATE_ENCRYPTED_INODE_LIST, pctx);
+ /* Should never get here */
+ ctx->flags |= E2F_FLAG_ABORT;
+ return 0;
+}
+
+static int append_ino_and_policy_id(e2fsck_t ctx, struct problem_context *pctx,
+ ext2_ino_t ino, __u32 policy_id)
+{
+ struct encrypted_file_info *info = ctx->encrypted_files;
+ struct encrypted_file_range *range;
+
+ /* See if we can just extend the last range. */
+ if (info->file_ranges_count > 0) {
+ range = &info->file_ranges[info->file_ranges_count - 1];
+
+ if (ino <= range->last_ino) {
+ /* Should never get here */
+ fatal_error(ctx,
+ "Encrypted inodes processed out of order");
+ }
+
+ if (ino == range->last_ino + 1 &&
+ policy_id == range->policy_id) {
+ range->last_ino++;
+ return 0;
+ }
+ }
+ /* Nope, a new range is needed. */
+
+ if (info->file_ranges_count == info->file_ranges_capacity) {
+ /* Double the capacity by default. */
+ size_t new_capacity = info->file_ranges_capacity * 2;
+
+ /* ... but go from 0 to 128 right away. */
+ if (new_capacity < 128)
+ new_capacity = 128;
+
+ /* We won't need more than the filesystem's inode count. */
+ if (new_capacity > ctx->fs->super->s_inodes_count)
+ new_capacity = ctx->fs->super->s_inodes_count;
+
+ /* To be safe, ensure the capacity really increases. */
+ if (new_capacity < info->file_ranges_capacity + 1)
+ new_capacity = info->file_ranges_capacity + 1;
+
+ if (ext2fs_resize_mem(info->file_ranges_capacity *
+ sizeof(*range),
+ new_capacity * sizeof(*range),
+ &info->file_ranges) != 0)
+ return handle_nomem(ctx, pctx,
+ new_capacity * sizeof(*range));
+
+ info->file_ranges_capacity = new_capacity;
+ }
+ range = &info->file_ranges[info->file_ranges_count++];
+ range->first_ino = ino;
+ range->last_ino = ino;
+ range->policy_id = policy_id;
+ return 0;
+}
+
+/*
+ * Handle an inode that has EXT4_ENCRYPT_FL set during pass 1. Normally this
+ * just finds the unique ID that identifies the inode's encryption policy
+ * (allocating a new ID if needed), and adds the inode number and its policy ID
+ * to the encrypted_file_info so that it's available in pass 2.
+ *
+ * But this also handles:
+ * - If the inode doesn't have an encryption xattr at all, offer to clear the
+ * encrypt flag.
+ * - If the encryption xattr is clearly corrupt, tell the caller that the whole
+ * inode should be cleared.
+ * - To be future-proof: if the encryption xattr has an unrecognized version
+ * number, it *might* be valid, so we don't consider it invalid. But we can't
+ * do much with it, so give all such policies the same ID,
+ * UNRECOGNIZED_ENCRYPTION_POLICY.
+ *
+ * Returns -1 if the inode should be cleared, otherwise 0.
+ */
+int add_encrypted_file(e2fsck_t ctx, struct problem_context *pctx)
+{
+ struct encrypted_file_info *info = ctx->encrypted_files;
+ ext2_ino_t ino = pctx->ino;
+ __u32 policy_id;
+
+ /* Allocate the encrypted_file_info if needed. */
+ if (info == NULL) {
+ if (ext2fs_get_memzero(sizeof(*info), &info) != 0)
+ return handle_nomem(ctx, pctx, sizeof(*info));
+ ctx->encrypted_files = info;
+ }
+
+ /* Get a unique ID for this inode's encryption policy. */
+ if (get_encryption_policy_id(ctx, ino, &policy_id) != 0)
+ return handle_nomem(ctx, pctx, 0 /* unknown size */);
+ if (policy_id == NO_ENCRYPTION_POLICY) {
+ if (fix_problem(ctx, PR_1_MISSING_ENCRYPTION_XATTR, pctx)) {
+ pctx->inode->i_flags &= ~EXT4_ENCRYPT_FL;
+ e2fsck_write_inode(ctx, ino, pctx->inode, "pass1");
+ }
+ return 0;
+ } else if (policy_id == CORRUPT_ENCRYPTION_POLICY) {
+ if (fix_problem(ctx, PR_1_CORRUPT_ENCRYPTION_XATTR, pctx))
+ return -1;
+ return 0;
+ }
+
+ /* Store this ino => policy_id mapping in the encrypted_file_info. */
+ return append_ino_and_policy_id(ctx, pctx, ino, policy_id);
+}
+
+/*
+ * Find the ID of an inode's encryption policy, using the information saved
+ * earlier.
+ *
+ * If the inode is encrypted, returns the policy ID or
+ * UNRECOGNIZED_ENCRYPTION_POLICY. Else, returns NO_ENCRYPTION_POLICY.
+ */
+__u32 find_encryption_policy(e2fsck_t ctx, ext2_ino_t ino)
+{
+ const struct encrypted_file_info *info = ctx->encrypted_files;
+ size_t l, r;
+
+ if (info == NULL)
+ return NO_ENCRYPTION_POLICY;
+ l = 0;
+ r = info->file_ranges_count;
+ while (l < r) {
+ size_t m = l + (r - l) / 2;
+ const struct encrypted_file_range *range =
+ &info->file_ranges[m];
+
+ if (ino < range->first_ino)
+ r = m;
+ else if (ino > range->last_ino)
+ l = m + 1;
+ else
+ return range->policy_id;
+ }
+ return NO_ENCRYPTION_POLICY;
+}
+
+/* Destroy ctx->encrypted_files->policies */
+void destroy_encryption_policy_map(e2fsck_t ctx)
+{
+ struct encrypted_file_info *info = ctx->encrypted_files;
+
+ if (info) {
+ struct rb_root *policies = &info->policies;
+
+ while (!ext2fs_rb_empty_root(policies)) {
+ struct policy_map_entry *entry;
+
+ entry = ext2fs_rb_entry(policies->rb_node,
+ struct policy_map_entry, node);
+ ext2fs_rb_erase(&entry->node, policies);
+ ext2fs_free_mem(&entry);
+ }
+ info->next_policy_id = 0;
+ }
+}
+
+/* Destroy ctx->encrypted_files */
+void destroy_encrypted_file_info(e2fsck_t ctx)
+{
+ struct encrypted_file_info *info = ctx->encrypted_files;
+
+ if (info) {
+ destroy_encryption_policy_map(ctx);
+ ext2fs_free_mem(&info->file_ranges);
+ ext2fs_free_mem(&info);
+ ctx->encrypted_files = NULL;
+ }
+}
#define buffer_req(bh) 1
#define do_readahead(journal, start) do {} while (0)
-typedef struct {
+typedef struct kmem_cache {
int object_length;
-} lkmem_cache_t;
+} kmem_cache_t;
#define kmem_cache_alloc(cache, flags) malloc((cache)->object_length)
#define kmem_cache_free(cache, obj) free(obj)
#define kmalloc(len, flags) malloc(len)
#define kfree(p) free(p)
+static inline void *kmalloc_array(unsigned n, unsigned size, int flags)
+{
+ if (n && (~0U)/n < size)
+ return NULL;
+ return malloc(n * size);
+}
+
#define cond_resched() do { } while (0)
#define __init
* functions.
*/
#ifdef NO_INLINE_FUNCS
-extern lkmem_cache_t *do_cache_create(int len);
-extern void do_cache_destroy(lkmem_cache_t *cache);
+extern kmem_cache_t *do_cache_create(int len);
+extern void do_cache_destroy(kmem_cache_t *cache);
extern size_t journal_tag_bytes(journal_t *journal);
extern __u32 __hash_32(__u32 val);
extern __u32 hash_32(__u32 val, unsigned int bits);
#endif /* __STDC_VERSION__ >= 199901L */
#endif /* E2FSCK_INCLUDE_INLINE_FUNCS */
-_INLINE_ lkmem_cache_t *do_cache_create(int len)
+_INLINE_ kmem_cache_t *do_cache_create(int len)
{
- lkmem_cache_t *new_cache;
+ kmem_cache_t *new_cache;
new_cache = malloc(sizeof(*new_cache));
if (new_cache)
return new_cache;
}
-_INLINE_ void do_cache_destroy(lkmem_cache_t *cache)
+_INLINE_ void do_cache_destroy(kmem_cache_t *cache)
{
free(cache);
}
/*
* Kernel compatibility functions are defined in journal.c
*/
-int journal_bmap(journal_t *journal, blk64_t block, unsigned long long *phys);
-struct buffer_head *getblk(kdev_t ctx, blk64_t blocknr, int blocksize);
+int jbd2_journal_bmap(journal_t *journal, unsigned long block,
+ unsigned long long *phys);
+struct buffer_head *getblk(kdev_t ctx, unsigned long long blocknr,
+ int blocksize);
int sync_blockdev(kdev_t kdev);
-void ll_rw_block(int rw, int dummy, struct buffer_head *bh[]);
+void ll_rw_block(int rw, int op_flags, int nr, struct buffer_head *bh[]);
void mark_buffer_dirty(struct buffer_head *bh);
void mark_buffer_uptodate(struct buffer_head *bh, int val);
void brelse(struct buffer_head *bh);
#define J_ASSERT(x) assert(x)
#define JSB_HAS_INCOMPAT_FEATURE(jsb, mask) \
- ((jsb)->s_header.h_blocktype == ext2fs_cpu_to_be32(JFS_SUPERBLOCK_V2) && \
+ ((jsb)->s_header.h_blocktype == ext2fs_cpu_to_be32(JBD2_SUPERBLOCK_V2) && \
((jsb)->s_feature_incompat & ext2fs_cpu_to_be32((mask))))
#else /* !DEBUGFS */
#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 journal_recover (journal_t *journal);
-extern int journal_skip_recovery (journal_t *);
+extern int jbd2_journal_recover (journal_t *journal);
+extern int jbd2_journal_skip_recovery (journal_t *);
/* revoke.c */
-extern int journal_init_revoke(journal_t *, int);
-extern void journal_destroy_revoke(journal_t *);
-extern void journal_destroy_revoke_caches(void);
-extern int journal_init_revoke_caches(void);
-
-extern int journal_set_revoke(journal_t *, unsigned long long, tid_t);
-extern int journal_test_revoke(journal_t *, unsigned long long, tid_t);
-extern void journal_clear_revoke(journal_t *);
+extern int jbd2_journal_init_revoke(journal_t *, int);
+extern void jbd2_journal_destroy_revoke(journal_t *);
+extern void jbd2_journal_destroy_revoke_record_cache(void);
+extern void jbd2_journal_destroy_revoke_table_cache(void);
+extern int jbd2_journal_init_revoke_record_cache(void);
+extern int jbd2_journal_init_revoke_table_cache(void);
+
+
+extern int jbd2_journal_set_revoke(journal_t *, unsigned long long, tid_t);
+extern int jbd2_journal_test_revoke(journal_t *, unsigned long long, tid_t);
+extern void jbd2_journal_clear_revoke(journal_t *);
#endif /* _JFS_USER_H */
static int e2fsck_journal_verify_csum_type(journal_t *j,
journal_superblock_t *jsb)
{
- if (!journal_has_csum_v2or3(j))
+ if (!jbd2_journal_has_csum_v2or3(j))
return 1;
return jsb->s_checksum_type == JBD2_CRC32C_CHKSUM;
{
__u32 provided, calculated;
- if (!journal_has_csum_v2or3(j))
+ if (!jbd2_journal_has_csum_v2or3(j))
return 1;
provided = ext2fs_be32_to_cpu(jsb->s_checksum);
{
__u32 crc;
- if (!journal_has_csum_v2or3(j))
+ if (!jbd2_journal_has_csum_v2or3(j))
return 0;
crc = e2fsck_journal_sb_csum(jsb);
* to use the recovery.c file virtually unchanged from the kernel, so we
* don't have to do much to keep kernel and user recovery in sync.
*/
-int journal_bmap(journal_t *journal, blk64_t block, unsigned long long *phys)
+int jbd2_journal_bmap(journal_t *journal, unsigned long block,
+ unsigned long long *phys)
{
#ifdef USE_INODE_IO
*phys = block;
}
retval= ext2fs_bmap2(inode->i_ctx->fs, inode->i_ino,
- &inode->i_ext2, NULL, 0, block, 0, &pblk);
+ &inode->i_ext2, NULL, 0, (blk64_t) block,
+ 0, &pblk);
*phys = pblk;
return -1 * ((int) retval);
#endif
}
-struct buffer_head *getblk(kdev_t kdev, blk64_t blocknr, int blocksize)
+struct buffer_head *getblk(kdev_t kdev, unsigned long long blocknr,
+ int blocksize)
{
struct buffer_head *bh;
int bufsize = sizeof(*bh) + kdev->k_ctx->fs->blocksize -
bh_count++;
#endif
jfs_debug(4, "getblk for block %llu (%d bytes)(total %d)\n",
- (unsigned long long) blocknr, blocksize, bh_count);
+ blocknr, blocksize, bh_count);
bh->b_ctx = kdev->k_ctx;
if (kdev->k_dev == K_DEV_FS)
return io_channel_flush(io) ? -EIO : 0;
}
-void ll_rw_block(int rw, int nr, struct buffer_head *bhp[])
+void ll_rw_block(int rw, int op_flags, int nr, struct buffer_head *bhp[])
{
errcode_t retval;
struct buffer_head *bh;
for (; nr > 0; --nr) {
bh = *bhp++;
- if (rw == READ && !bh->b_uptodate) {
+ if (rw == REQ_OP_READ && !bh->b_uptodate) {
jfs_debug(3, "reading block %llu/%p\n",
bh->b_blocknr, (void *) bh);
retval = io_channel_read_blk64(bh->b_io,
continue;
}
bh->b_uptodate = 1;
- } else if (rw == WRITE && bh->b_dirty) {
+ } else if (rw == REQ_OP_WRITE && bh->b_dirty) {
jfs_debug(3, "writing block %llu/%p\n",
bh->b_blocknr,
(void *) bh);
bh->b_uptodate = 1;
} else {
jfs_debug(3, "no-op %s for block %llu\n",
- rw == READ ? "read" : "write",
+ rw == REQ_OP_READ ? "read" : "write",
bh->b_blocknr);
}
}
void brelse(struct buffer_head *bh)
{
if (bh->b_dirty)
- ll_rw_block(WRITE, 1, &bh);
+ ll_rw_block(REQ_OP_WRITE, 0, 1, &bh);
jfs_debug(3, "freeing block %llu/%p (total %d)\n",
bh->b_blocknr, (void *) bh, --bh_count);
ext2fs_free_mem(&bh);
void wait_on_buffer(struct buffer_head *bh)
{
if (!bh->b_uptodate)
- ll_rw_block(READ, 1, &bh);
+ ll_rw_block(REQ_OP_READ, 0, 1, &bh);
}
goto try_backup_journal;
}
if (EXT2_I_SIZE(&j_inode->i_ext2) / journal->j_blocksize <
- JFS_MIN_JOURNAL_BLOCKS) {
+ JBD2_MIN_JOURNAL_BLOCKS) {
retval = EXT2_ET_JOURNAL_TOO_SMALL;
goto try_backup_journal;
}
#else
journal->j_inode = j_inode;
ctx->journal_io = ctx->fs->io;
- if ((ret = journal_bmap(journal, 0, &start)) != 0) {
+ if ((ret = jbd2_journal_bmap(journal, 0, &start)) != 0) {
retval = (errcode_t) (-1 * ret);
goto errout;
}
retval = EXT2_ET_NO_MEMORY;
goto errout;
}
- ll_rw_block(READ, 1, &bh);
+ ll_rw_block(REQ_OP_READ, 0, 1, &bh);
if ((retval = bh->b_err) != 0) {
brelse(bh);
goto errout;
clear_problem_context(&pctx);
- ll_rw_block(READ, 1, &jbh);
+ ll_rw_block(REQ_OP_READ, 0, 1, &jbh);
if (jbh->b_err) {
com_err(ctx->device_name, jbh->b_err, "%s",
_("reading journal superblock\n"));
}
jsb = journal->j_superblock;
- /* If we don't even have JFS_MAGIC, we probably have a wrong inode */
- if (jsb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER))
+ /* If we don't even have JBD2_MAGIC, we probably have a wrong inode */
+ if (jsb->s_header.h_magic != htonl(JBD2_MAGIC_NUMBER))
return e2fsck_journal_fix_bad_inode(ctx, &pctx);
switch (ntohl(jsb->s_header.h_blocktype)) {
- case JFS_SUPERBLOCK_V1:
+ case JBD2_SUPERBLOCK_V1:
journal->j_format_version = 1;
if (jsb->s_feature_compat ||
jsb->s_feature_incompat ||
clear_v2_journal_fields(journal);
break;
- case JFS_SUPERBLOCK_V2:
+ case JBD2_SUPERBLOCK_V2:
journal->j_format_version = 2;
if (ntohl(jsb->s_nr_users) > 1 &&
uuid_is_null(ctx->fs->super->s_journal_uuid))
* These should never appear in a journal super block, so if
* they do, the journal is badly corrupted.
*/
- case JFS_DESCRIPTOR_BLOCK:
- case JFS_COMMIT_BLOCK:
- case JFS_REVOKE_BLOCK:
+ case JBD2_DESCRIPTOR_BLOCK:
+ case JBD2_COMMIT_BLOCK:
+ case JBD2_REVOKE_BLOCK:
return EXT2_ET_CORRUPT_JOURNAL_SB;
/* If we don't understand the superblock major type, but there
return EXT2_ET_JOURNAL_UNSUPP_VERSION;
}
- if (JFS_HAS_INCOMPAT_FEATURE(journal, ~JFS_KNOWN_INCOMPAT_FEATURES))
+ if (JBD2_HAS_INCOMPAT_FEATURE(journal, ~JBD2_KNOWN_INCOMPAT_FEATURES))
return EXT2_ET_UNSUPP_FEATURE;
- if (JFS_HAS_RO_COMPAT_FEATURE(journal, ~JFS_KNOWN_ROCOMPAT_FEATURES))
+ if (JBD2_HAS_RO_COMPAT_FEATURE(journal, ~JBD2_KNOWN_ROCOMPAT_FEATURES))
return EXT2_ET_RO_UNSUPP_FEATURE;
/* Checksum v1-3 are mutually exclusive features. */
- if (jfs_has_feature_csum2(journal) && jfs_has_feature_csum3(journal))
+ if (jbd2_has_feature_csum2(journal) && jbd2_has_feature_csum3(journal))
return EXT2_ET_CORRUPT_JOURNAL_SB;
- if (journal_has_csum_v2or3(journal) &&
- jfs_has_feature_checksum(journal))
+ if (jbd2_journal_has_csum_v2or3(journal) &&
+ jbd2_has_feature_checksum(journal))
return EXT2_ET_CORRUPT_JOURNAL_SB;
if (!e2fsck_journal_verify_csum_type(journal, jsb) ||
!e2fsck_journal_sb_csum_verify(journal, jsb))
return EXT2_ET_CORRUPT_JOURNAL_SB;
- if (journal_has_csum_v2or3(journal))
+ if (jbd2_journal_has_csum_v2or3(journal))
journal->j_csum_seed = jbd2_chksum(journal, ~0, jsb->s_uuid,
sizeof(jsb->s_uuid));
* Anything unrecognisable we overwrite with a new V2
* signature. */
- if (jsb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER) ||
- jsb->s_header.h_blocktype != htonl(JFS_SUPERBLOCK_V1)) {
- jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER);
- jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2);
+ if (jsb->s_header.h_magic != htonl(JBD2_MAGIC_NUMBER) ||
+ jsb->s_header.h_blocktype != htonl(JBD2_SUPERBLOCK_V1)) {
+ jsb->s_header.h_magic = htonl(JBD2_MAGIC_NUMBER);
+ jsb->s_header.h_blocktype = htonl(JBD2_SUPERBLOCK_V2);
}
/* Zero out everything else beyond the superblock header */
e2fsck_journal_sb_csum_set(journal, jsb);
mark_buffer_dirty(journal->j_sb_buffer);
- ll_rw_block(WRITE, 1, &journal->j_sb_buffer);
+ ll_rw_block(REQ_OP_WRITE, 0, 1, &journal->j_sb_buffer);
}
static errcode_t e2fsck_journal_fix_corrupt_super(e2fsck_t ctx,
clear_problem_context(&pctx);
- journal_init_revoke_caches();
+ retval = jbd2_journal_init_revoke_record_cache();
+ if (retval)
+ return retval;
+
+ retval = jbd2_journal_init_revoke_table_cache();
+ if (retval)
+ return retval;
+
retval = e2fsck_get_journal(ctx, &journal);
if (retval)
return retval;
if (retval)
goto errout;
- retval = journal_init_revoke(journal, 1024);
+ retval = jbd2_journal_init_revoke(journal, 1024);
if (retval)
goto errout;
- retval = -journal_recover(journal);
+ retval = -jbd2_journal_recover(journal);
if (retval)
goto errout;
journal->j_tail_sequence = journal->j_transaction_sequence;
errout:
- journal_destroy_revoke(journal);
- journal_destroy_revoke_caches();
+ jbd2_journal_destroy_revoke(journal);
+ jbd2_journal_destroy_revoke_record_cache();
+ jbd2_journal_destroy_revoke_table_cache();
e2fsck_journal_release(ctx, journal, 1, 0);
return retval;
}
* - A bitmap of which blocks are in use by two inodes (block_dup_map)
* - The data blocks of the directory inodes. (dir_map)
* - Ref counts for ea_inodes. (ea_inode_refs)
+ * - The encryption policy ID of each encrypted inode. (encrypted_files)
*
* Pass 1 is designed to stash away enough information so that the
* other passes should not need to read in the inode information
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_encrypted_dir(e2fsck_t ctx, 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);
failed_csum = 0;
}
+ if ((inode->i_flags & EXT4_ENCRYPT_FL) &&
+ add_encrypted_file(ctx, &pctx) < 0)
+ goto clear_inode;
+
if (LINUX_S_ISDIR(inode->i_mode)) {
ext2fs_mark_inode_bitmap2(ctx->inode_dir_map, ino);
e2fsck_add_dir_info(ctx, ino, 0);
ctx->fs_directory_count++;
- if (inode->i_flags & EXT4_ENCRYPT_FL)
- add_encrypted_dir(ctx, ino);
} else if (LINUX_S_ISREG (inode->i_mode)) {
ext2fs_mark_inode_bitmap2(ctx->inode_reg_map, ino);
ctx->fs_regular_count++;
ctx->block_ea_map = 0;
}
+ /* We don't need the encryption policy => ID map any more */
+ destroy_encryption_policy_map(ctx);
+
if (ctx->flags & E2F_FLAG_RESIZE_INODE) {
clear_problem_context(&pctx);
pctx.errcode = ext2fs_create_resize_inode(fs);
ext2fs_mark_inode_bitmap2(ctx->inode_bad_map, ino);
}
-static void add_encrypted_dir(e2fsck_t ctx, ino_t ino)
-{
- struct problem_context pctx;
-
- if (!ctx->encrypted_dirs) {
- pctx.errcode = ext2fs_u32_list_create(&ctx->encrypted_dirs, 0);
- if (pctx.errcode)
- goto error;
- }
- pctx.errcode = ext2fs_u32_list_add(ctx->encrypted_dirs, ino);
- if (pctx.errcode == 0)
- return;
-error:
- fix_problem(ctx, PR_1_ALLOCATE_ENCRYPTED_DIRLIST, &pctx);
- /* Should never get here */
- ctx->flags |= E2F_FLAG_ABORT;
-}
-
/*
* This procedure will allocate the inode "bb" (badblock) map table
*/
return;
failed_csum = 0;
}
-
+#ifdef CONFIG_DEVELOPER_FEATURES
+ if (try_repairs && !is_dir && problem == 0 &&
+ (ctx->options & E2F_OPT_CLEAR_UNINIT) &&
+ (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT) &&
+ fix_problem(ctx, PR_1_CLEAR_UNINIT_EXTENT, pctx)) {
+ extent.e_flags &= ~EXT2_EXTENT_FLAGS_UNINIT;
+ pb->inode_modified = 1;
+ pctx->errcode = ext2fs_extent_replace(ehandle, 0,
+ &extent);
+ if (pctx->errcode)
+ return;
+ failed_csum = 0;
+ }
+#endif
if (try_repairs && problem) {
report_problem:
if (fix_problem(ctx, problem, pctx)) {
* - The inode_used_map bitmap
* - The inode_bad_map bitmap
* - The inode_dir_map bitmap
+ * - The encrypted_file_info
*
* Pass 2 frees the following data structures
* - The inode_bad_map bitmap
* - The inode_reg_map bitmap
+ * - The encrypted_file_info
*/
#define _GNU_SOURCE 1 /* get strnlen() */
ext2fs_free_inode_bitmap(ctx->inode_reg_map);
ctx->inode_reg_map = 0;
}
- if (ctx->encrypted_dirs) {
- ext2fs_u32_list_free(ctx->encrypted_dirs);
- ctx->encrypted_dirs = 0;
- }
+ destroy_encrypted_file_info(ctx);
clear_problem_context(&pctx);
if (ctx->large_files) {
}
static int encrypted_check_name(e2fsck_t ctx,
- struct ext2_dir_entry *dirent,
+ const struct ext2_dir_entry *dirent,
struct problem_context *pctx)
{
if (ext2fs_dirent_name_len(dirent) < EXT4_CRYPTO_BLOCK_SIZE) {
- if (fix_problem(ctx, PR_2_BAD_ENCRYPTED_NAME, pctx)) {
- dirent->inode = 0;
+ if (fix_problem(ctx, PR_2_BAD_ENCRYPTED_NAME, pctx))
return 1;
- }
ext2fs_unmark_valid(ctx->fs);
}
return 0;
return retval;
}
+/* Return true if this type of file needs encryption */
+static int needs_encryption(e2fsck_t ctx, const struct ext2_dir_entry *dirent)
+{
+ int filetype = ext2fs_dirent_file_type(dirent);
+ ext2_ino_t ino = dirent->inode;
+ struct ext2_inode inode;
+
+ if (filetype != EXT2_FT_UNKNOWN)
+ return filetype == EXT2_FT_REG_FILE ||
+ filetype == EXT2_FT_DIR ||
+ filetype == EXT2_FT_SYMLINK;
+
+ if (ext2fs_test_inode_bitmap2(ctx->inode_reg_map, ino) ||
+ ext2fs_test_inode_bitmap2(ctx->inode_dir_map, ino))
+ return 1;
+
+ e2fsck_read_inode(ctx, ino, &inode, "check_encryption_policy");
+ return LINUX_S_ISREG(inode.i_mode) ||
+ LINUX_S_ISDIR(inode.i_mode) ||
+ LINUX_S_ISLNK(inode.i_mode);
+}
+
+/*
+ * All regular files, directories, and symlinks in encrypted directories must be
+ * encrypted using the same encryption policy as their directory.
+ *
+ * Returns 1 if the dirent should be cleared, otherwise 0.
+ */
+static int check_encryption_policy(e2fsck_t ctx,
+ const struct ext2_dir_entry *dirent,
+ __u32 dir_encpolicy_id,
+ struct problem_context *pctx)
+{
+ __u32 file_encpolicy_id = find_encryption_policy(ctx, dirent->inode);
+
+ /* Same policy or both UNRECOGNIZED_ENCRYPTION_POLICY? */
+ if (file_encpolicy_id == dir_encpolicy_id)
+ return 0;
+
+ if (file_encpolicy_id == NO_ENCRYPTION_POLICY) {
+ if (!needs_encryption(ctx, dirent))
+ return 0;
+ return fix_problem(ctx, PR_2_UNENCRYPTED_FILE, pctx);
+ }
+
+ return fix_problem(ctx, PR_2_INCONSISTENT_ENCRYPTION_POLICY, pctx);
+}
+
+/*
+ * Check an encrypted directory entry.
+ *
+ * Returns 1 if the dirent should be cleared, otherwise 0.
+ */
+static int check_encrypted_dirent(e2fsck_t ctx,
+ const struct ext2_dir_entry *dirent,
+ __u32 dir_encpolicy_id,
+ struct problem_context *pctx)
+{
+ if (encrypted_check_name(ctx, dirent, pctx))
+ return 1;
+ if (check_encryption_policy(ctx, dirent, dir_encpolicy_id, pctx))
+ return 1;
+ return 0;
+}
+
static int check_dir_block2(ext2_filsys fs,
struct ext2_db_entry2 *db,
void *priv_data)
int is_leaf = 1;
size_t inline_data_size = 0;
int filetype = 0;
- int encrypted = 0;
+ __u32 dir_encpolicy_id = NO_ENCRYPTION_POLICY;
size_t max_block_size;
int hash_flags = 0;
static char *eop_read_dirblock = NULL;
} else
max_block_size = fs->blocksize - de_csum_size;
- if (ctx->encrypted_dirs)
- encrypted = ext2fs_u32_list_test(ctx->encrypted_dirs, ino);
+ dir_encpolicy_id = find_encryption_policy(ctx, ino);
dict_init(&de_dict, DICTCOUNT_T_MAX, dict_de_cmp);
prev = 0;
}
}
- if (!encrypted && check_name(ctx, dirent, &cd->pctx))
+ if (check_filetype(ctx, dirent, ino, &cd->pctx))
dir_modified++;
- if (encrypted && (dot_state) > 1 &&
- encrypted_check_name(ctx, dirent, &cd->pctx)) {
- dir_modified++;
- goto next;
+ if (dir_encpolicy_id == NO_ENCRYPTION_POLICY) {
+ /* Unencrypted directory */
+ if (check_name(ctx, dirent, &cd->pctx))
+ dir_modified++;
+ } else {
+ /* Encrypted directory */
+ if (dot_state > 1 &&
+ check_encrypted_dirent(ctx, dirent,
+ dir_encpolicy_id,
+ &cd->pctx)) {
+ dirent->inode = 0;
+ dir_modified++;
+ goto next;
+ }
}
- if (check_filetype(ctx, dirent, ino, &cd->pctx))
- dir_modified++;
-
if (dx_db) {
if (dx_dir->casefolded_hash)
hash_flags = EXT4_CASEFOLD_FL;
N_("@i %i has a duplicate @x mapping\n\t(logical @b %c, @n physical @b %b, len %N)\n"),
PROMPT_CLEAR, 0, 0, 0, 0 },
- /* Error allocating memory for encrypted directory list */
- { PR_1_ALLOCATE_ENCRYPTED_DIRLIST,
- N_("@A memory for encrypted @d list\n"),
+ /* Error allocating memory for encrypted inode list */
+ { PR_1_ALLOCATE_ENCRYPTED_INODE_LIST,
+ N_("@A %N bytes of memory for encrypted @i list\n"),
PROMPT_NONE, PR_FATAL, 0, 0, 0 },
/* Inode extent tree could be more shallow */
N_("EA @i %N for parent @i %i missing EA_INODE flag.\n "),
PROMPT_FIX, PR_PREEN_OK, 0, 0, 0 },
+ /* Offer to clear uninitialized flag on an extent */
+ { PR_1_CLEAR_UNINIT_EXTENT,
+ /* xgettext:no-c-format */
+ N_("@i %i has @x marked uninitialized at @b %c (len %N). "),
+ PROMPT_CLEAR, PR_PREEN_OK, 0, 0, 0 },
+
/* Casefold flag set on a non-directory */
{ PR_1_CASEFOLD_NONDIR,
N_("@i %i has the casefold flag set but is not a directory. "),
N_("@d %p has the casefold flag, but the\ncasefold feature is not enabled. "),
PROMPT_CLEAR_FLAG, 0, 0, 0, 0 },
+ /* Inode has encrypt flag but no encryption extended attribute */
+ { PR_1_MISSING_ENCRYPTION_XATTR,
+ N_("@i %i has encrypt flag but no encryption @a.\n"),
+ PROMPT_CLEAR_FLAG, 0, 0, 0, 0 },
+
+ /* Encrypted inode has corrupt encryption extended attribute */
+ { PR_1_CORRUPT_ENCRYPTION_XATTR,
+ N_("Encrypted @i %i has corrupt encryption @a.\n"),
+ PROMPT_CLEAR_INODE, 0, 0, 0, 0 },
+
/* Pass 1b errors */
/* Pass 1B: Rescan for duplicate/bad blocks */
N_("Encrypted @E is too short.\n"),
PROMPT_CLEAR, 0, 0, 0, 0 },
+ /* Encrypted directory contains unencrypted file */
+ { PR_2_UNENCRYPTED_FILE,
+ N_("Encrypted @E references unencrypted @i %Di.\n"),
+ PROMPT_CLEAR, 0, 0, 0, 0 },
+
+ /* Encrypted directory contains file with different encryption policy */
+ { PR_2_INCONSISTENT_ENCRYPTION_POLICY,
+ N_("Encrypted @E references @i %Di, which has a different encryption policy.\n"),
+ PROMPT_CLEAR, 0, 0, 0, 0 },
+
/* Pass 3 errors */
/* Pass 3: Checking directory connectivity */
/* Inode leaf has a duplicate extent mapping */
#define PR_1_EXTENT_COLLISION 0x01007D
-/* Error allocating memory for encrypted directory list */
-#define PR_1_ALLOCATE_ENCRYPTED_DIRLIST 0x01007E
+/* Error allocating memory for encrypted inode list */
+#define PR_1_ALLOCATE_ENCRYPTED_INODE_LIST 0x01007E
/* Inode extent tree could be more shallow */
#define PR_1_EXTENT_BAD_MAX_DEPTH 0x01007F
/* Casefold flag set, but file system is missing the casefold feature */
#define PR_1_CASEFOLD_FEATURE 0x010089
+/* Inode has encrypt flag but no encryption extended attribute */
+#define PR_1_MISSING_ENCRYPTION_XATTR 0x01008A
+
+/* Encrypted inode has corrupt encryption extended attribute */
+#define PR_1_CORRUPT_ENCRYPTION_XATTR 0x01008B
/*
* Pass 1b errors
/* Encrypted directory entry is too short */
#define PR_2_BAD_ENCRYPTED_NAME 0x020050
+/* Encrypted directory contains unencrypted file */
+#define PR_2_UNENCRYPTED_FILE 0x020051
+
+/* Encrypted directory contains file with different encryption policy */
+#define PR_2_INCONSISTENT_ENCRYPTION_POLICY 0x020052
+
/*
* Pass 3 errors
*/
+// SPDX-License-Identifier: GPL-2.0+
/*
* linux/fs/jbd2/recovery.c
*
*
* Copyright 1999-2000 Red Hat Software --- All Rights Reserved
*
- * This file is part of the Linux kernel and is made available under
- * the terms of the GNU General Public License, version 2, or at your
- * option, any later version, incorporated herein by reference.
- *
* Journal recovery routines for the generic filesystem journaling code;
* part of the ext2fs journaling system.
*/
nbufs = 0;
for (next = start; next < max; next++) {
- err = journal_bmap(journal, next, &blocknr);
+ err = jbd2_journal_bmap(journal, next, &blocknr);
if (err) {
printk(KERN_ERR "JBD2: bad block at offset %u\n",
if (!buffer_uptodate(bh) && !buffer_locked(bh)) {
bufs[nbufs++] = bh;
if (nbufs == MAXBUF) {
- ll_rw_block(READ, nbufs, bufs);
+ ll_rw_block(REQ_OP_READ, 0, nbufs, bufs);
journal_brelse_array(bufs, nbufs);
nbufs = 0;
}
}
if (nbufs)
- ll_rw_block(READ, nbufs, bufs);
+ ll_rw_block(REQ_OP_READ, 0, nbufs, bufs);
err = 0;
failed:
return -EFSCORRUPTED;
}
- err = journal_bmap(journal, offset, &blocknr);
+ err = jbd2_journal_bmap(journal, offset, &blocknr);
if (err) {
printk(KERN_ERR "JBD2: bad block at offset %u\n",
return 0;
}
-static int jbd2_descr_block_csum_verify(journal_t *j,
- void *buf)
+static int jbd2_descriptor_block_csum_verify(journal_t *j, void *buf)
{
- struct journal_block_tail *tail;
- __u32 provided;
+ struct jbd2_journal_block_tail *tail;
+ __be32 provided;
__u32 calculated;
- if (!journal_has_csum_v2or3(j))
+ if (!jbd2_journal_has_csum_v2or3(j))
return 1;
- tail = (struct journal_block_tail *)((char *)buf + j->j_blocksize -
- sizeof(struct 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);
tail->t_checksum = provided;
- return provided == ext2fs_cpu_to_be32(calculated);
+ return provided == cpu_to_be32(calculated);
}
/*
int nr = 0, size = journal->j_blocksize;
int tag_bytes = journal_tag_bytes(journal);
- if (journal_has_csum_v2or3(journal))
- size -= sizeof(struct journal_block_tail);
+ if (jbd2_journal_has_csum_v2or3(journal))
+ size -= sizeof(struct jbd2_journal_block_tail);
tagp = &bh->b_data[sizeof(journal_header_t)];
nr++;
tagp += tag_bytes;
- if (!(get_be16(&tag->t_flags) & JFS_FLAG_SAME_UUID))
+ if (!(get_be16(&tag->t_flags) & JBD2_FLAG_SAME_UUID))
tagp += 16;
- if (get_be16(&tag->t_flags) & JFS_FLAG_LAST_TAG)
+ if (get_be16(&tag->t_flags) & JBD2_FLAG_LAST_TAG)
break;
}
} while (0)
/**
- * journal_recover - recovers a on-disk journal
+ * jbd2_journal_recover - recovers a on-disk journal
* @journal: the journal to recover
*
* The primary function for recovering the log contents when mounting a
* blocks. In the third and final pass, we replay any un-revoked blocks
* in the log.
*/
-int journal_recover(journal_t *journal)
+int jbd2_journal_recover(journal_t *journal)
{
int err, err2;
journal_superblock_t * sb;
if (!sb->s_start) {
jbd_debug(1, "No recovery required, last transaction %d\n",
- ext2fs_be32_to_cpu(sb->s_sequence));
- journal->j_transaction_sequence = ext2fs_be32_to_cpu(sb->s_sequence) + 1;
+ be32_to_cpu(sb->s_sequence));
+ journal->j_transaction_sequence = be32_to_cpu(sb->s_sequence) + 1;
return 0;
}
* any existing commit records in the log. */
journal->j_transaction_sequence = ++info.end_transaction;
- journal_clear_revoke(journal);
+ jbd2_journal_clear_revoke(journal);
err2 = sync_blockdev(journal->j_fs_dev);
if (!err)
err = err2;
/* Make sure all replayed data is on permanent storage */
- if (journal->j_flags & JFS_BARRIER) {
+ if (journal->j_flags & JBD2_BARRIER) {
err2 = blkdev_issue_flush(journal->j_fs_dev, GFP_KERNEL, NULL);
if (!err)
err = err2;
}
/**
- * journal_skip_recovery - Start journal and wipe exiting records
+ * jbd2_journal_skip_recovery - Start journal and wipe exiting records
* @journal: journal to startup
*
* Locate any valid recovery information from the journal and set up the
* much recovery information is being erased, and to let us initialise
* the journal transaction sequence numbers to the next unused ID.
*/
-int journal_skip_recovery(journal_t *journal)
+int jbd2_journal_skip_recovery(journal_t *journal)
{
int err;
printk(KERN_ERR "JBD2: error %d scanning journal\n", err);
++journal->j_transaction_sequence;
} else {
-#ifdef CONFIG_JFS_DEBUG
- int dropped = info.end_transaction -
- ext2fs_be32_to_cpu(journal->j_superblock->s_sequence);
+#ifdef CONFIG_JBD2_DEBUG
+ int dropped = info.end_transaction -
+ be32_to_cpu(journal->j_superblock->s_sequence);
jbd_debug(1,
"JBD2: ignoring %d transaction%s from the journal.\n",
dropped, (dropped == 1) ? "" : "s");
journal_block_tag_t *tag)
{
unsigned long long block = get_be32(&tag->t_blocknr);
- if (jfs_has_feature_64bit(journal))
+ if (jbd2_has_feature_64bit(journal))
block |= (u64)get_be32(&tag->t_blocknr_high) << 32;
return block;
}
static int jbd2_commit_block_csum_verify(journal_t *j, void *buf)
{
struct commit_header *h;
- __u32 provided;
+ __be32 provided;
__u32 calculated;
- if (!journal_has_csum_v2or3(j))
+ if (!jbd2_journal_has_csum_v2or3(j))
return 1;
h = buf;
calculated = jbd2_chksum(j, j->j_csum_seed, buf, j->j_blocksize);
h->h_chksum[0] = provided;
- return provided == ext2fs_cpu_to_be32(calculated);
+ return provided == cpu_to_be32(calculated);
}
static int jbd2_block_tag_csum_verify(journal_t *j, journal_block_tag_t *tag,
{
journal_block_tag3_t *tag3 = (journal_block_tag3_t *)tag;
__u32 csum32;
- __u32 seq;
+ __be32 seq;
- if (!journal_has_csum_v2or3(j))
+ if (!jbd2_journal_has_csum_v2or3(j))
return 1;
- seq = ext2fs_cpu_to_be32(sequence);
+ seq = cpu_to_be32(sequence);
csum32 = jbd2_chksum(j, j->j_csum_seed, (__u8 *)&seq, sizeof(seq));
csum32 = jbd2_chksum(j, csum32, buf, j->j_blocksize);
- if (jfs_has_feature_csum3(j))
+ if (jbd2_has_feature_csum3(j))
return get_be32(&tag3->t_checksum) == csum32;
return get_be16(&tag->t_checksum) == (csum32 & 0xFFFF);
*/
sb = journal->j_superblock;
- next_commit_ID = ext2fs_be32_to_cpu(sb->s_sequence);
- next_log_block = ext2fs_be32_to_cpu(sb->s_start);
+ next_commit_ID = be32_to_cpu(sb->s_sequence);
+ next_log_block = be32_to_cpu(sb->s_start);
first_commit_ID = next_commit_ID;
if (pass == PASS_SCAN)
tmp = (journal_header_t *)bh->b_data;
- if (tmp->h_magic != ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER)) {
+ if (tmp->h_magic != cpu_to_be32(JBD2_MAGIC_NUMBER)) {
brelse(bh);
break;
}
- blocktype = ext2fs_be32_to_cpu(tmp->h_blocktype);
- sequence = ext2fs_be32_to_cpu(tmp->h_sequence);
+ blocktype = be32_to_cpu(tmp->h_blocktype);
+ sequence = be32_to_cpu(tmp->h_sequence);
jbd_debug(3, "Found magic %d, sequence %d\n",
blocktype, sequence);
* to do with it? That depends on the pass... */
switch(blocktype) {
- case JFS_DESCRIPTOR_BLOCK:
+ case JBD2_DESCRIPTOR_BLOCK:
/* Verify checksum first */
- if (journal_has_csum_v2or3(journal))
+ if (jbd2_journal_has_csum_v2or3(journal))
descr_csum_size =
- sizeof(struct journal_block_tail);
+ sizeof(struct jbd2_journal_block_tail);
if (descr_csum_size > 0 &&
- !jbd2_descr_block_csum_verify(journal,
- bh->b_data)) {
+ !jbd2_descriptor_block_csum_verify(journal,
+ bh->b_data)) {
err = -EFSBADCRC;
brelse(bh);
goto failed;
* just skip over the blocks it describes. */
if (pass != PASS_REPLAY) {
if (pass == PASS_SCAN &&
- jfs_has_feature_checksum(journal) &&
+ jbd2_has_feature_checksum(journal) &&
!info->end_transaction) {
if (calc_chksums(journal, bh,
&next_log_block,
/* If the block has been
* revoked, then we're all done
* here. */
- if (journal_test_revoke
+ if (jbd2_journal_test_revoke
(journal, blocknr,
next_commit_ID)) {
brelse(obh);
/* Look for block corruption */
if (!jbd2_block_tag_csum_verify(
journal, tag, obh->b_data,
- ext2fs_be32_to_cpu(tmp->h_sequence))) {
+ be32_to_cpu(tmp->h_sequence))) {
brelse(obh);
success = -EFSBADCRC;
printk(KERN_ERR "JBD2: Invalid "
"checksum recovering "
- "block %llu in log\n",
- blocknr);
+ "data block %llu in "
+ "log\n", blocknr);
block_error = 1;
goto skip_write;
}
lock_buffer(nbh);
memcpy(nbh->b_data, obh->b_data,
journal->j_blocksize);
- if (flags & JFS_FLAG_ESCAPE) {
- __u32 magic = ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER);
+ if (flags & JBD2_FLAG_ESCAPE) {
+ __be32 magic = cpu_to_be32(JBD2_MAGIC_NUMBER);
memcpy(nbh->b_data, &magic,
sizeof(magic));
}
skip_write:
tagp += tag_bytes;
- if (!(flags & JFS_FLAG_SAME_UUID))
+ if (!(flags & JBD2_FLAG_SAME_UUID))
tagp += 16;
- if (flags & JFS_FLAG_LAST_TAG)
+ if (flags & JBD2_FLAG_LAST_TAG)
break;
}
brelse(bh);
continue;
- case JFS_COMMIT_BLOCK:
+ case JBD2_COMMIT_BLOCK:
/* How to differentiate between interrupted commit
* and journal corruption ?
*
* much to do other than move on to the next sequence
* number. */
if (pass == PASS_SCAN &&
- jfs_has_feature_checksum(journal)) {
+ jbd2_has_feature_checksum(journal)) {
int chksum_err, chksum_seen;
struct commit_header *cbh =
(struct commit_header *)bh->b_data;
unsigned found_chksum =
- ext2fs_be32_to_cpu(cbh->h_chksum[0]);
+ be32_to_cpu(cbh->h_chksum[0]);
chksum_err = chksum_seen = 0;
}
if (crc32_sum == found_chksum &&
- cbh->h_chksum_type == JFS_CRC32_CHKSUM &&
+ cbh->h_chksum_type == JBD2_CRC32_CHKSUM &&
cbh->h_chksum_size ==
- JFS_CRC32_CHKSUM_SIZE)
+ JBD2_CRC32_CHKSUM_SIZE)
chksum_seen = 1;
else if (!(cbh->h_chksum_type == 0 &&
cbh->h_chksum_size == 0 &&
if (chksum_err) {
info->end_transaction = next_commit_ID;
- if (!jfs_has_feature_async_commit(journal)){
+ if (!jbd2_has_feature_async_commit(journal)) {
journal->j_failed_commit =
next_commit_ID;
brelse(bh);
bh->b_data)) {
info->end_transaction = next_commit_ID;
- if (!jfs_has_feature_async_commit(journal)) {
+ if (!jbd2_has_feature_async_commit(journal)) {
journal->j_failed_commit =
next_commit_ID;
brelse(bh);
next_commit_ID++;
continue;
- case JFS_REVOKE_BLOCK:
+ case JBD2_REVOKE_BLOCK:
/* If we aren't in the REVOKE pass, then we can
* just skip over this block. */
if (pass != PASS_REVOKE) {
return err;
}
-static int jbd2_revoke_block_csum_verify(journal_t *j,
- void *buf)
-{
- struct journal_revoke_tail *tail;
- __u32 provided;
- __u32 calculated;
-
- if (!journal_has_csum_v2or3(j))
- return 1;
-
- tail = (struct journal_revoke_tail *)((char *)buf + j->j_blocksize -
- sizeof(struct journal_revoke_tail));
- provided = tail->r_checksum;
- tail->r_checksum = 0;
- calculated = jbd2_chksum(j, j->j_csum_seed, buf, j->j_blocksize);
- tail->r_checksum = provided;
-
- return provided == ext2fs_cpu_to_be32(calculated);
-}
-
/* Scan a revoke record, marking all blocks mentioned as revoked. */
static int scan_revoke_records(journal_t *journal, struct buffer_head *bh,
tid_t sequence, struct recovery_info *info)
{
- journal_revoke_header_t *header;
+ jbd2_journal_revoke_header_t *header;
int offset, max;
unsigned csum_size = 0;
__u32 rcount;
int record_len = 4;
- header = (journal_revoke_header_t *) bh->b_data;
- offset = sizeof(journal_revoke_header_t);
- rcount = ext2fs_be32_to_cpu(header->r_count);
+ header = (jbd2_journal_revoke_header_t *) bh->b_data;
+ offset = sizeof(jbd2_journal_revoke_header_t);
+ rcount = be32_to_cpu(header->r_count);
- if (!jbd2_revoke_block_csum_verify(journal, header))
+ if (!jbd2_descriptor_block_csum_verify(journal, header))
return -EFSBADCRC;
- if (journal_has_csum_v2or3(journal))
- csum_size = sizeof(struct journal_revoke_tail);
+ if (jbd2_journal_has_csum_v2or3(journal))
+ csum_size = sizeof(struct jbd2_journal_block_tail);
if (rcount > journal->j_blocksize - csum_size)
return -EINVAL;
max = rcount;
- if (jfs_has_feature_64bit(journal))
+ if (jbd2_has_feature_64bit(journal))
record_len = 8;
while (offset + record_len <= max) {
int err;
if (record_len == 4)
- blocknr = ext2fs_be32_to_cpu(* ((__u32 *) (bh->b_data+offset)));
+ blocknr = be32_to_cpu(* ((__be32 *) (bh->b_data+offset)));
else
- blocknr = ext2fs_be64_to_cpu(* ((__u64 *) (bh->b_data+offset)));
+ blocknr = be64_to_cpu(* ((__be64 *) (bh->b_data+offset)));
offset += record_len;
- err = journal_set_revoke(journal, blocknr, sequence);
+ err = jbd2_journal_set_revoke(journal, blocknr, sequence);
if (err)
return err;
++info->nr_revokes;
+// SPDX-License-Identifier: GPL-2.0+
/*
* linux/fs/jbd2/revoke.c
*
*
* Copyright 2000 Red Hat corp --- All Rights Reserved
*
- * This file is part of the Linux kernel and is made available under
- * the terms of the GNU General Public License, version 2, or at your
- * option, any later version, incorporated herein by reference.
- *
* Journal revoke routines for the generic filesystem journaling code;
* part of the ext2fs journaling system.
*
#include <linux/init.h>
#include <linux/bio.h>
#include <linux/log2.h>
+#include <linux/hash.h>
#endif
-static lkmem_cache_t *jbd2_revoke_record_cache;
-static lkmem_cache_t *jbd2_revoke_table_cache;
+static struct kmem_cache *jbd2_revoke_record_cache;
+static struct kmem_cache *jbd2_revoke_table_cache;
/* Each revoke record represents one single revoked block. During
journal replay, this involves recording the transaction ID of the
#ifdef __KERNEL__
-static void write_one_revoke_record(journal_t *, transaction_t *,
+static void write_one_revoke_record(transaction_t *,
struct list_head *,
struct buffer_head **, int *,
- struct jbd2_revoke_record_s *, int);
-static void flush_descriptor(journal_t *, struct buffer_head *, int, int);
+ struct jbd2_revoke_record_s *);
+static void flush_descriptor(journal_t *, struct buffer_head *, int);
#endif
/* Utility functions to maintain the revoke table */
-/* Borrowed from buffer.c: this is a tried and tested block hash function */
static inline int hash(journal_t *journal, unsigned long long block)
{
- struct jbd2_revoke_table_s *table = journal->j_revoke;
-
- return (hash_64(block, table->hash_shift));
+ return hash_64(block, journal->j_revoke->hash_shift);
}
static int insert_revoke_hash(journal_t *journal, unsigned long long blocknr,
{
struct list_head *hash_list;
struct jbd2_revoke_record_s *record;
+ gfp_t gfp_mask = GFP_NOFS;
-repeat:
- record = kmem_cache_alloc(jbd2_revoke_record_cache, GFP_NOFS);
+ if (journal_oom_retry)
+ gfp_mask |= __GFP_NOFAIL;
+ record = kmem_cache_alloc(jbd2_revoke_record_cache, gfp_mask);
if (!record)
- goto oom;
+ return -ENOMEM;
record->sequence = seq;
record->blocknr = blocknr;
list_add(&record->hash, hash_list);
spin_unlock(&journal->j_revoke_lock);
return 0;
-
-oom:
- if (!journal_oom_retry)
- return -ENOMEM;
- jbd_debug(1, "ENOMEM in %s, retrying\n", __func__);
- yield();
- goto repeat;
}
/* Find a revoke record in the journal's hash table. */
return NULL;
}
-void journal_destroy_revoke_caches(void)
+void jbd2_journal_destroy_revoke_record_cache(void)
{
- if (jbd2_revoke_record_cache) {
- kmem_cache_destroy(jbd2_revoke_record_cache);
- jbd2_revoke_record_cache = NULL;
- }
- if (jbd2_revoke_table_cache) {
- kmem_cache_destroy(jbd2_revoke_table_cache);
- jbd2_revoke_table_cache = NULL;
- }
+ kmem_cache_destroy(jbd2_revoke_record_cache);
+ jbd2_revoke_record_cache = NULL;
}
-int __init journal_init_revoke_caches(void)
+void jbd2_journal_destroy_revoke_table_cache(void)
{
- J_ASSERT(!jbd2_revoke_record_cache);
- J_ASSERT(!jbd2_revoke_table_cache);
+ kmem_cache_destroy(jbd2_revoke_table_cache);
+ jbd2_revoke_table_cache = NULL;
+}
+int __init jbd2_journal_init_revoke_record_cache(void)
+{
+ J_ASSERT(!jbd2_revoke_record_cache);
jbd2_revoke_record_cache = KMEM_CACHE(jbd2_revoke_record_s,
SLAB_HWCACHE_ALIGN|SLAB_TEMPORARY);
- if (!jbd2_revoke_record_cache)
- goto record_cache_failure;
+ if (!jbd2_revoke_record_cache) {
+ pr_emerg("JBD2: failed to create revoke_record cache\n");
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+int __init jbd2_journal_init_revoke_table_cache(void)
+{
+ J_ASSERT(!jbd2_revoke_table_cache);
jbd2_revoke_table_cache = KMEM_CACHE(jbd2_revoke_table_s,
SLAB_TEMPORARY);
- if (!jbd2_revoke_table_cache)
- goto table_cache_failure;
- return 0;
-table_cache_failure:
- journal_destroy_revoke_caches();
-record_cache_failure:
+ if (!jbd2_revoke_table_cache) {
+ pr_emerg("JBD2: failed to create revoke_table cache\n");
return -ENOMEM;
+ }
+ return 0;
}
-static struct jbd2_revoke_table_s *journal_init_revoke_table(int hash_size)
+static struct jbd2_revoke_table_s *jbd2_journal_init_revoke_table(int hash_size)
{
int shift = 0;
int tmp = hash_size;
table->hash_size = hash_size;
table->hash_shift = shift;
table->hash_table =
- kmalloc(hash_size * sizeof(struct list_head), GFP_KERNEL);
+ kmalloc_array(hash_size, sizeof(struct list_head), GFP_KERNEL);
if (!table->hash_table) {
kmem_cache_free(jbd2_revoke_table_cache, table);
table = NULL;
return table;
}
-static void journal_destroy_revoke_table(struct jbd2_revoke_table_s *table)
+static void jbd2_journal_destroy_revoke_table(struct jbd2_revoke_table_s *table)
{
int i;
struct list_head *hash_list;
}
/* Initialise the revoke table for a given journal to a given size. */
-int journal_init_revoke(journal_t *journal, int hash_size)
+int jbd2_journal_init_revoke(journal_t *journal, int hash_size)
{
J_ASSERT(journal->j_revoke_table[0] == NULL);
J_ASSERT(is_power_of_2(hash_size));
- journal->j_revoke_table[0] = journal_init_revoke_table(hash_size);
+ journal->j_revoke_table[0] = jbd2_journal_init_revoke_table(hash_size);
if (!journal->j_revoke_table[0])
goto fail0;
- journal->j_revoke_table[1] = journal_init_revoke_table(hash_size);
+ journal->j_revoke_table[1] = jbd2_journal_init_revoke_table(hash_size);
if (!journal->j_revoke_table[1])
goto fail1;
return 0;
fail1:
- journal_destroy_revoke_table(journal->j_revoke_table[0]);
+ jbd2_journal_destroy_revoke_table(journal->j_revoke_table[0]);
+ journal->j_revoke_table[0] = NULL;
fail0:
return -ENOMEM;
}
/* Destroy a journal's revoke table. The table must already be empty! */
-void journal_destroy_revoke(journal_t *journal)
+void jbd2_journal_destroy_revoke(journal_t *journal)
{
journal->j_revoke = NULL;
if (journal->j_revoke_table[0])
- journal_destroy_revoke_table(journal->j_revoke_table[0]);
+ jbd2_journal_destroy_revoke_table(journal->j_revoke_table[0]);
if (journal->j_revoke_table[1])
- journal_destroy_revoke_table(journal->j_revoke_table[1]);
+ jbd2_journal_destroy_revoke_table(journal->j_revoke_table[1]);
}
#ifdef __KERNEL__
/*
- * journal_revoke: revoke a given buffer_head from the journal. This
+ * jbd2_journal_revoke: revoke a given buffer_head from the journal. This
* prevents the block from being replayed during recovery if we take a
* crash after this current transaction commits. Any subsequent
* metadata writes of the buffer in this transaction cancel the
* revoke before clearing the block bitmap when we are deleting
* metadata.
*
- * Revoke performs a journal_forget on any buffer_head passed in as a
+ * Revoke performs a jbd2_journal_forget on any buffer_head passed in as a
* parameter, but does _not_ forget the buffer_head if the bh was only
* found implicitly.
*
* bh_in may not be a journalled buffer - it may have come off
* the hash tables without an attached journal_head.
*
- * If bh_in is non-zero, journal_revoke() will decrement its b_count
+ * If bh_in is non-zero, jbd2_journal_revoke() will decrement its b_count
* by one.
*/
-int journal_revoke(handle_t *handle, unsigned long long blocknr,
+int jbd2_journal_revoke(handle_t *handle, unsigned long long blocknr,
struct buffer_head *bh_in)
{
struct buffer_head *bh = NULL;
BUFFER_TRACE(bh_in, "enter");
journal = handle->h_transaction->t_journal;
- if (!journal_set_features(journal, 0, 0, JFS_FEATURE_INCOMPAT_REVOKE)){
+ if (!jbd2_journal_set_features(journal, 0, 0, JBD2_FEATURE_INCOMPAT_REVOKE)){
J_ASSERT (!"Cannot set revoke feature!");
return -EINVAL;
}
if (bh)
BUFFER_TRACE(bh, "found on hash");
}
-#ifdef JFS_EXPENSIVE_CHECKING
+#ifdef JBD2_EXPENSIVE_CHECKING
else {
struct buffer_head *bh2;
}
#endif
+ if (WARN_ON_ONCE(handle->h_revoke_credits <= 0)) {
+ if (!bh_in)
+ brelse(bh);
+ return -EIO;
+ }
/* We really ought not ever to revoke twice in a row without
first having the revoke cancelled: it's illegal to free a
block twice without allocating it in between! */
set_buffer_revoked(bh);
set_buffer_revokevalid(bh);
if (bh_in) {
- BUFFER_TRACE(bh_in, "call journal_forget");
- journal_forget(handle, bh_in);
+ BUFFER_TRACE(bh_in, "call jbd2_journal_forget");
+ jbd2_journal_forget(handle, bh_in);
} else {
BUFFER_TRACE(bh, "call brelse");
__brelse(bh);
}
}
+ handle->h_revoke_credits--;
jbd_debug(2, "insert revoke for block %llu, bh_in=%p\n",blocknr, bh_in);
err = insert_revoke_hash(journal, blocknr,
/*
* Cancel an outstanding revoke. For use only internally by the
- * journaling code (called from journal_get_write_access).
+ * journaling code (called from jbd2_journal_get_write_access).
*
* We trust buffer_revoked() on the buffer if the buffer is already
* being journaled: if there is no revoke pending on the buffer, then we
* do not trust the Revoked bit on buffers unless RevokeValid is also
* set.
*/
-int journal_cancel_revoke(handle_t *handle, struct journal_head *jh)
+int jbd2_journal_cancel_revoke(handle_t *handle, struct journal_head *jh)
{
struct jbd2_revoke_record_s *record;
journal_t *journal = handle->h_transaction->t_journal;
int did_revoke = 0; /* akpm: debug */
struct buffer_head *bh = jh2bh(jh);
- jbd_debug(4, "journal_head %p, canceling revoke\n", jh);
+ jbd_debug(4, "journal_head %p, cancelling revoke\n", jh);
/* Is the existing Revoke bit valid? If so, we trust it, and
* only perform the full cancel if the revoke bit is set. If
}
}
-#ifdef JFS_EXPENSIVE_CHECKING
+#ifdef JBD2_EXPENSIVE_CHECKING
/* There better not be one left behind by now! */
record = find_revoke_record(journal, bh->b_blocknr);
J_ASSERT_JH(jh, record == NULL);
* we do not want to suspend any processing until all revokes are
* written -bzzz
*/
-void journal_switch_revoke_table(journal_t *journal)
+void jbd2_journal_switch_revoke_table(journal_t *journal)
{
int i;
* Write revoke records to the journal for all entries in the current
* revoke hash, deleting the entries as we go.
*/
-void journal_write_revoke_records(journal_t *journal,
- transaction_t *transaction,
- struct list_head *log_bufs,
- int write_op)
+void jbd2_journal_write_revoke_records(transaction_t *transaction,
+ struct list_head *log_bufs)
{
+ journal_t *journal = transaction->t_journal;
struct buffer_head *descriptor;
struct jbd2_revoke_record_s *record;
struct jbd2_revoke_table_s *revoke;
while (!list_empty(hash_list)) {
record = (struct jbd2_revoke_record_s *)
hash_list->next;
- write_one_revoke_record(journal, transaction, log_bufs,
- &descriptor, &offset,
- record, write_op);
+ write_one_revoke_record(transaction, log_bufs,
+ &descriptor, &offset, record);
count++;
list_del(&record->hash);
kmem_cache_free(jbd2_revoke_record_cache, record);
}
}
if (descriptor)
- flush_descriptor(journal, descriptor, offset, write_op);
+ flush_descriptor(journal, descriptor, offset);
jbd_debug(1, "Wrote %d revoke records\n", count);
}
* block if the old one is full or if we have not already created one.
*/
-static void write_one_revoke_record(journal_t *journal,
- transaction_t *transaction,
+static void write_one_revoke_record(transaction_t *transaction,
struct list_head *log_bufs,
struct buffer_head **descriptorp,
int *offsetp,
- struct jbd2_revoke_record_s *record,
- int write_op)
+ struct jbd2_revoke_record_s *record)
{
+ journal_t *journal = transaction->t_journal;
int csum_size = 0;
struct buffer_head *descriptor;
int sz, offset;
- journal_header_t *header;
/* If we are already aborting, this all becomes a noop. We
still need to go round the loop in
- journal_write_revoke_records in order to free all of the
+ jbd2_journal_write_revoke_records in order to free all of the
revoke records: only the IO to the journal is omitted. */
if (is_journal_aborted(journal))
return;
offset = *offsetp;
/* Do we need to leave space at the end for a checksum? */
- if (journal_has_csum_v2or3(journal))
- csum_size = sizeof(struct journal_revoke_tail);
+ if (jbd2_journal_has_csum_v2or3(journal))
+ csum_size = sizeof(struct jbd2_journal_block_tail);
- if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT))
+ if (jbd2_has_feature_64bit(journal))
sz = 8;
else
sz = 4;
/* Make sure we have a descriptor with space left for the record */
if (descriptor) {
if (offset + sz > journal->j_blocksize - csum_size) {
- flush_descriptor(journal, descriptor, offset, write_op);
+ flush_descriptor(journal, descriptor, offset);
descriptor = NULL;
}
}
if (!descriptor) {
- descriptor = journal_get_descriptor_buffer(journal);
+ descriptor = jbd2_journal_get_descriptor_buffer(transaction,
+ JBD2_REVOKE_BLOCK);
if (!descriptor)
return;
- header = (journal_header_t *)descriptor->b_data;
- header->h_magic = ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER);
- header->h_blocktype = ext2fs_cpu_to_be32(JFS_REVOKE_BLOCK);
- header->h_sequence = ext2fs_cpu_to_be32(transaction->t_tid);
/* Record it so that we can wait for IO completion later */
BUFFER_TRACE(descriptor, "file in log_bufs");
jbd2_file_log_bh(log_bufs, descriptor);
- offset = sizeof(journal_revoke_header_t);
+ offset = sizeof(jbd2_journal_revoke_header_t);
*descriptorp = descriptor;
}
- if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT)) {
+ if (jbd2_has_feature_64bit(journal))
* ((__be64 *)(&descriptor->b_data[offset])) =
cpu_to_be64(record->blocknr);
else
*offsetp = offset;
}
-static void jbd2_revoke_csum_set(journal_t *j, struct buffer_head *bh)
-{
- struct journal_revoke_tail *tail;
- __u32 csum;
-
- if (!journal_has_csum_v2or3(j))
- return;
-
- tail = (struct journal_revoke_tail *)(bh->b_data + j->j_blocksize -
- sizeof(struct journal_revoke_tail));
- tail->r_checksum = 0;
- csum = jbd2_chksum(j, j->j_csum_seed, bh->b_data, j->j_blocksize);
- tail->r_checksum = ext2fs_cpu_to_be32(csum);
-}
-
/*
* Flush a revoke descriptor out to the journal. If we are aborting,
* this is a noop; otherwise we are generating a buffer which needs to
static void flush_descriptor(journal_t *journal,
struct buffer_head *descriptor,
- int offset, int write_op)
+ int offset)
{
- journal_revoke_header_t *header;
+ jbd2_journal_revoke_header_t *header;
- if (is_journal_aborted(journal)) {
- put_bh(descriptor);
+ if (is_journal_aborted(journal))
return;
- }
- header = (journal_revoke_header_t *)descriptor->b_data;
- header->r_count = ext2fs_cpu_to_be32(offset);
- jbd2_revoke_csum_set(journal, descriptor);
+ header = (jbd2_journal_revoke_header_t *)descriptor->b_data;
+ header->r_count = cpu_to_be32(offset);
+ jbd2_descriptor_block_csum_set(journal, descriptor);
set_buffer_jwrite(descriptor);
BUFFER_TRACE(descriptor, "write");
set_buffer_dirty(descriptor);
- write_dirty_buffer(descriptor, write_op);
+ write_dirty_buffer(descriptor, REQ_SYNC);
}
#endif
* single block.
*/
-int journal_set_revoke(journal_t *journal,
+int jbd2_journal_set_revoke(journal_t *journal,
unsigned long long blocknr,
tid_t sequence)
{
* ones, but later transactions still need replayed.
*/
-int journal_test_revoke(journal_t *journal,
+int jbd2_journal_test_revoke(journal_t *journal,
unsigned long long blocknr,
tid_t sequence)
{
* that it can be reused by the running filesystem.
*/
-void journal_clear_revoke(journal_t *journal)
+void jbd2_journal_clear_revoke(journal_t *journal)
{
int i;
struct list_head *hash_list;
ctx->options |= E2F_OPT_UNSHARE_BLOCKS;
ctx->options |= E2F_OPT_FORCE;
continue;
+#ifdef CONFIG_DEVELOPER_FEATURES
+ } else if (strcmp(token, "clear_all_uninit_bits") == 0) {
+ ctx->options |= E2F_OPT_CLEAR_UNINIT;
+ continue;
+#endif
} else {
fprintf(stderr, _("Unknown extended option: %s\n"),
token);
/* Define to 1 to compile findfs */
#undef CONFIG_BUILD_FINDFS
+/* Define to 1 for features for use by ext4 developers */
+#undef CONFIG_DEVELOPER_FEATURES
+
/* Define to 1 if debugging ext3/4 journal code */
#undef CONFIG_JBD_DEBUG
"sparse_super2" },
{ E2P_FEATURE_COMPAT, EXT4_FEATURE_COMPAT_FAST_COMMIT,
"fast_commit" },
+ { E2P_FEATURE_COMPAT, EXT4_FEATURE_COMPAT_STABLE_INODES,
+ "stable_inodes" },
{ E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER,
"sparse_super" },
};
static struct feature jrnl_feature_list[] = {
- { E2P_FEATURE_COMPAT, JFS_FEATURE_COMPAT_CHECKSUM,
+ { E2P_FEATURE_COMPAT, JBD2_FEATURE_COMPAT_CHECKSUM,
"journal_checksum" },
- { E2P_FEATURE_INCOMPAT, JFS_FEATURE_INCOMPAT_REVOKE,
+ { E2P_FEATURE_INCOMPAT, JBD2_FEATURE_INCOMPAT_REVOKE,
"journal_incompat_revoke" },
- { E2P_FEATURE_INCOMPAT, JFS_FEATURE_INCOMPAT_64BIT,
+ { E2P_FEATURE_INCOMPAT, JBD2_FEATURE_INCOMPAT_64BIT,
"journal_64bit" },
- { E2P_FEATURE_INCOMPAT, JFS_FEATURE_INCOMPAT_ASYNC_COMMIT,
+ { E2P_FEATURE_INCOMPAT, JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT,
"journal_async_commit" },
- { E2P_FEATURE_INCOMPAT, JFS_FEATURE_INCOMPAT_CSUM_V2,
+ { E2P_FEATURE_INCOMPAT, JBD2_FEATURE_INCOMPAT_CSUM_V2,
"journal_checksum_v2" },
- { E2P_FEATURE_INCOMPAT, JFS_FEATURE_INCOMPAT_CSUM_V3,
+ { E2P_FEATURE_INCOMPAT, JBD2_FEATURE_INCOMPAT_CSUM_V3,
"journal_checksum_v3" },
{ 0, 0, 0 },
};
(unsigned int)ntohl(jsb->s_start));
if (nr_users != 1)
fprintf(f, "Journal number of users: %u\n", nr_users);
- if (jsb->s_feature_compat & e2p_be32(JFS_FEATURE_COMPAT_CHECKSUM))
+ if (jsb->s_feature_compat & e2p_be32(JBD2_FEATURE_COMPAT_CHECKSUM))
fprintf(f, "%s", "Journal checksum type: crc32\n");
if ((jsb->s_feature_incompat &
- e2p_be32(JFS_FEATURE_INCOMPAT_CSUM_V3)) ||
+ e2p_be32(JBD2_FEATURE_INCOMPAT_CSUM_V3)) ||
(jsb->s_feature_incompat &
- e2p_be32(JFS_FEATURE_INCOMPAT_CSUM_V2)))
+ e2p_be32(JBD2_FEATURE_INCOMPAT_CSUM_V2)))
fprintf(f, "Journal checksum type: %s\n"
"Journal checksum: 0x%08x\n",
journal_checksum_type_str(jsb->s_checksum_type),
e2p_be32(jsb->s_checksum));
if ((nr_users > 1) ||
!e2p_is_null_uuid(&jsb->s_users[0])) {
- for (i=0; i < nr_users && i < JFS_USERS_MAX; i++) {
+ for (i=0; i < nr_users && i < JBD2_USERS_MAX; i++) {
printf(i ? " %s\n"
: "Journal users: %s\n",
e2p_uuid2str(&jsb->s_users[i * UUID_SIZE]));
struct opaque_ext2_group_desc *gdp,
dgrp_t group)
{
- int desc_size = EXT2_DESC_SIZE(fs->super) & ~7;
-
- return (struct ext2_group_desc *)((char *)gdp + group * desc_size);
+ struct ext2_group_desc *ret_gdp;
+ errcode_t retval;
+ static char *buf = 0;
+ static int bufsize = 0;
+ blk64_t blk;
+ int desc_size = EXT2_DESC_SIZE(fs->super) & ~7;
+ int desc_per_blk = EXT2_DESC_PER_BLOCK(fs->super);
+
+ if (group > fs->group_desc_count)
+ return NULL;
+ if (gdp)
+ return (struct ext2_group_desc *)((char *)gdp +
+ group * desc_size);
+ /*
+ * If fs->group_desc wasn't read in when the file system was
+ * opened, then read it on demand here.
+ */
+ if (bufsize < fs->blocksize)
+ ext2fs_free_mem(&buf);
+ if (!buf) {
+ retval = ext2fs_get_mem(fs->blocksize, &buf);
+ if (retval)
+ return NULL;
+ bufsize = fs->blocksize;
+ }
+ blk = ext2fs_descriptor_block_loc2(fs, fs->super->s_first_data_block,
+ group / desc_per_blk);
+ retval = io_channel_read_blk(fs->io, blk, 1, buf);
+ if (retval)
+ return NULL;
+ ret_gdp = (struct ext2_group_desc *)
+ (buf + ((group % desc_per_blk) * desc_size));
+#ifdef WORDS_BIGENDIAN
+ ext2fs_swap_group_desc2(fs, ret_gdp);
+#endif
+ return ret_gdp;
}
/* Do the same but as an ext4 group desc for internal use here */
return 0;
}
-static errcode_t ext2fs_dx_csum(ext2_filsys fs, ext2_ino_t inum,
- struct ext2_dir_entry *dirent,
- __u32 *crc, int count_offset, int count,
- struct ext2_dx_tail *t)
+errcode_t ext2fs_dx_csum(ext2_filsys fs, ext2_ino_t inum,
+ struct ext2_dir_entry *dirent,
+ __u32 *crc, struct ext2_dx_tail **ret_t)
{
errcode_t retval;
char *buf = (char *)dirent;
int size;
- __u32 old_csum, gen;
+ __u32 gen, dummy_csum = 0;
struct ext2_inode inode;
+ struct ext2_dx_tail *t;
+ struct ext2_dx_countlimit *c;
+ int count_offset, limit, count;
+
+ retval = __get_dx_countlimit(fs, dirent, &c, &count_offset, 1);
+ if (retval)
+ return retval;
+ limit = ext2fs_le16_to_cpu(c->limit);
+ count = ext2fs_le16_to_cpu(c->count);
+ if (count_offset + (limit * sizeof(struct ext2_dx_entry)) >
+ fs->blocksize - sizeof(struct ext2_dx_tail))
+ return EXT2_ET_DIR_NO_SPACE_FOR_CSUM;
+ /* htree structs are accessed in LE order */
+ t = (struct ext2_dx_tail *)(((struct ext2_dx_entry *)c) + limit);
size = count_offset + (count * sizeof(struct ext2_dx_entry));
- old_csum = t->dt_checksum;
- t->dt_checksum = 0;
retval = ext2fs_read_inode(fs, inum, &inode);
if (retval)
sizeof(inum));
*crc = ext2fs_crc32c_le(*crc, (unsigned char *)&gen, sizeof(gen));
*crc = ext2fs_crc32c_le(*crc, (unsigned char *)buf, size);
- *crc = ext2fs_crc32c_le(*crc, (unsigned char *)t,
- sizeof(struct ext2_dx_tail));
- t->dt_checksum = old_csum;
+ *crc = ext2fs_crc32c_le(*crc, (unsigned char *)t, 4);
+ *crc = ext2fs_crc32c_le(*crc, (unsigned char *)&dummy_csum, 4);
+ if (ret_t)
+ *ret_t = t;
return 0;
}
{
__u32 calculated;
errcode_t retval;
- struct ext2_dx_countlimit *c;
struct ext2_dx_tail *t;
- int count_offset, limit, count;
- retval = __get_dx_countlimit(fs, dirent, &c, &count_offset, 1);
- if (retval)
- return 1;
- limit = ext2fs_le16_to_cpu(c->limit);
- count = ext2fs_le16_to_cpu(c->count);
- if (count_offset + (limit * sizeof(struct ext2_dx_entry)) >
- fs->blocksize - sizeof(struct ext2_dx_tail))
- return 0;
- /* htree structs are accessed in LE order */
- t = (struct ext2_dx_tail *)(((struct ext2_dx_entry *)c) + limit);
- retval = ext2fs_dx_csum(fs, inum, dirent, &calculated, count_offset,
- count, t);
+ retval = ext2fs_dx_csum(fs, inum, dirent, &calculated, &t);
if (retval)
return 0;
{
__u32 crc;
errcode_t retval = 0;
- struct ext2_dx_countlimit *c;
struct ext2_dx_tail *t;
- int count_offset, limit, count;
- retval = __get_dx_countlimit(fs, dirent, &c, &count_offset, 1);
- if (retval)
- return retval;
- limit = ext2fs_le16_to_cpu(c->limit);
- count = ext2fs_le16_to_cpu(c->count);
- if (count_offset + (limit * sizeof(struct ext2_dx_entry)) >
- fs->blocksize - sizeof(struct ext2_dx_tail))
- return EXT2_ET_DIR_NO_SPACE_FOR_CSUM;
- t = (struct ext2_dx_tail *)(((struct ext2_dx_entry *)c) + limit);
-
- /* htree structs are accessed in LE order */
- retval = ext2fs_dx_csum(fs, inum, dirent, &crc, count_offset, count, t);
+ retval = ext2fs_dx_csum(fs, inum, dirent, &crc, &t);
if (retval)
return retval;
t->dt_checksum = ext2fs_cpu_to_le32(crc);
#define EXT2_FEATURE_COMPAT_EXCLUDE_BITMAP 0x0100
#define EXT4_FEATURE_COMPAT_SPARSE_SUPER2 0x0200
#define EXT4_FEATURE_COMPAT_FAST_COMMIT 0x0400
+#define EXT4_FEATURE_COMPAT_STABLE_INODES 0x0800
#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
EXT4_FEATURE_COMPAT_FUNCS(exclude_bitmap, 2, EXCLUDE_BITMAP)
EXT4_FEATURE_COMPAT_FUNCS(sparse_super2, 4, SPARSE_SUPER2)
EXT4_FEATURE_COMPAT_FUNCS(fast_commit, 4, FAST_COMMIT)
+EXT4_FEATURE_COMPAT_FUNCS(stable_inodes, 4, STABLE_INODES)
EXT4_FEATURE_RO_COMPAT_FUNCS(sparse_super, 2, SPARSE_SUPER)
EXT4_FEATURE_RO_COMPAT_FUNCS(large_file, 2, LARGE_FILE)
EXT2_FEATURE_COMPAT_RESIZE_INODE|\
EXT2_FEATURE_COMPAT_DIR_INDEX|\
EXT2_FEATURE_COMPAT_EXT_ATTR|\
- EXT4_FEATURE_COMPAT_SPARSE_SUPER2)
+ EXT4_FEATURE_COMPAT_SPARSE_SUPER2|\
+ EXT4_FEATURE_COMPAT_FAST_COMMIT|\
+ EXT4_FEATURE_COMPAT_STABLE_INODES)
#ifdef CONFIG_MMP
#define EXT4_LIB_INCOMPAT_MMP EXT4_FEATURE_INCOMPAT_MMP
struct ext2_dir_entry *dirent,
struct ext2_dx_countlimit **cc,
int *offset);
+extern errcode_t ext2fs_dx_csum(ext2_filsys fs, ext2_ino_t inum,
+ struct ext2_dir_entry *dirent,
+ __u32 *crc, struct ext2_dx_tail **ret_t);
extern errcode_t ext2fs_extent_block_csum_set(ext2_filsys fs,
ext2_ino_t inum,
struct ext3_extent_header *eh);
* if needed
*/
groups_per_block = EXT2_DESC_PER_BLOCK(fs->super);
- gdp = (struct ext2_group_desc *) cp;
for (j=0; j < groups_per_block*fs->desc_blocks; j++) {
gdp = ext2fs_group_desc(fs, fs->group_desc, j);
- ext2fs_swap_group_desc2(fs, gdp);
+ if (gdp)
+ ext2fs_swap_group_desc2(fs, gdp);
}
#endif
#ifdef WORDS_BIGENDIAN
groups_per_block = EXT2_DESC_PER_BLOCK(fs->super);
- gdp = (struct ext2_group_desc *) cp;
for (j=0; j < groups_per_block*fs->desc_blocks; j++) {
gdp = ext2fs_group_desc(fs, fs->group_desc, j);
- ext2fs_swap_group_desc2(fs, gdp);
+ if (gdp)
+ ext2fs_swap_group_desc2(fs, gdp);
}
#endif
#define KERN_ERR ""
#define KERN_DEBUG ""
-#define READ 0
-#define WRITE 1
+#define REQ_OP_READ 0
+#define REQ_OP_WRITE 1
-#define cpu_to_be32(n) htonl(n)
-#define be32_to_cpu(n) ntohl(n)
-#define cpu_to_be16(n) htons(n)
-#define be16_to_cpu(n) ntohs(n)
+#define cpu_to_be16(x) ext2fs_cpu_to_be16(x)
+#define cpu_to_be32(x) ext2fs_cpu_to_be32(x)
+#define cpu_to_be64(x) ext2fs_cpu_to_be64(x)
+
+#define be16_to_cpu(x) ext2fs_be16_to_cpu(x)
+#define be32_to_cpu(x) ext2fs_be32_to_cpu(x)
+#define be64_to_cpu(x) ext2fs_be64_to_cpu(x)
typedef unsigned int tid_t;
typedef struct journal_s journal_t;
struct buffer_head;
struct inode;
+typedef unsigned int gfp_t;
#define GFP_KERNEL 0
-#define JFS_TAG_SIZE32 JBD_TAG_SIZE32
-#define JFS_BARRIER 0
+#define GFP_NOFS 0
+#define __GFP_NOFAIL 0
+#define JBD2_TAG_SIZE32 JBD_TAG_SIZE32
+#define JBD2_BARRIER 0
typedef __u64 u64;
-#define JFS_CRC32_CHKSUM JBD2_CRC32_CHKSUM
-#define JFS_CRC32_CHKSUM_SIZE JBD2_CRC32_CHKSUM_SIZE
#define put_bh(x) brelse(x)
-#define be64_to_cpu(x) ext2fs_be64_to_cpu(x)
static inline __u32 jbd2_chksum(journal_t *j EXT2FS_ATTR((unused)),
__u32 crc, const void *address,
#define spin_lock_init(x)
#define spin_lock(x)
#define spin_unlock(x)
-#define yield()
#define SLAB_HWCACHE_ALIGN 0
#define SLAB_TEMPORARY 0
#define KMEM_CACHE(__struct, __flags) kmem_cache_create(#__struct,\
#define blkdev_issue_flush(kdev, a, b) sync_blockdev(kdev)
#define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0))
+#define pr_emerg(fmt)
struct journal_s
{
#define __FUNCTION__ ""
#endif
-#define journal_oom_retry 1
+#define journal_oom_retry 0
#ifdef __STDC__
#ifdef CONFIG_JBD_DEBUG
#define jbd_rep_kmalloc(size, flags) \
__jbd_kmalloc(__FUNCTION__, (size), (flags), 1)
-#define JFS_MIN_JOURNAL_BLOCKS 1024
+#define JBD2_MIN_JOURNAL_BLOCKS 1024
/*
* Internal structures used by the logging mechanism:
*/
-#define JFS_MAGIC_NUMBER 0xc03b3998U /* The first 4 bytes of /dev/random! */
+#define JBD2_MAGIC_NUMBER 0xc03b3998U /* The first 4 bytes of /dev/random! */
/*
* On-disk structures
* Descriptor block types:
*/
-#define JFS_DESCRIPTOR_BLOCK 1
-#define JFS_COMMIT_BLOCK 2
-#define JFS_SUPERBLOCK_V1 3
-#define JFS_SUPERBLOCK_V2 4
-#define JFS_REVOKE_BLOCK 5
+#define JBD2_DESCRIPTOR_BLOCK 1
+#define JBD2_COMMIT_BLOCK 2
+#define JBD2_SUPERBLOCK_V1 3
+#define JBD2_SUPERBLOCK_V2 4
+#define JBD2_REVOKE_BLOCK 5
/*
* Standard header for all descriptor blocks:
*/
typedef struct journal_header_s
{
- __u32 h_magic;
- __u32 h_blocktype;
- __u32 h_sequence;
+ __be32 h_magic;
+ __be32 h_blocktype;
+ __be32 h_sequence;
} journal_header_t;
/*
* Checksum v1, v2, and v3 are mutually exclusive features.
*/
struct commit_header {
- __u32 h_magic;
- __u32 h_blocktype;
- __u32 h_sequence;
+ __be32 h_magic;
+ __be32 h_blocktype;
+ __be32 h_sequence;
unsigned char h_chksum_type;
unsigned char h_chksum_size;
unsigned char h_padding[2];
- __u32 h_chksum[JBD2_CHECKSUM_BYTES];
- __u64 h_commit_sec;
- __u32 h_commit_nsec;
+ __be32 h_chksum[JBD2_CHECKSUM_BYTES];
+ __be64 h_commit_sec;
+ __be32 h_commit_nsec;
};
/*
*/
typedef struct journal_block_tag3_s
{
- __u32 t_blocknr; /* The on-disk block number */
- __u32 t_flags; /* See below */
- __u32 t_blocknr_high; /* most-significant high 32bits. */
- __u32 t_checksum; /* crc32c(uuid+seq+block) */
+ __be32 t_blocknr; /* The on-disk block number */
+ __be32 t_flags; /* See below */
+ __be32 t_blocknr_high; /* most-significant high 32bits. */
+ __be32 t_checksum; /* crc32c(uuid+seq+block) */
} journal_block_tag3_t;
typedef struct journal_block_tag_s
{
- __u32 t_blocknr; /* The on-disk block number */
- __u16 t_checksum; /* truncated crc32c(uuid+seq+block) */
- __u16 t_flags; /* See below */
- __u32 t_blocknr_high; /* most-significant high 32bits. */
+ __be32 t_blocknr; /* The on-disk block number */
+ __be16 t_checksum; /* truncated crc32c(uuid+seq+block) */
+ __be16 t_flags; /* See below */
+ __be32 t_blocknr_high; /* most-significant high 32bits. */
} journal_block_tag_t;
-/* Tail of descriptor block, for checksumming */
-struct journal_block_tail {
+/* Tail of descriptor or revoke block, for checksumming */
+struct jbd2_journal_block_tail {
__be32 t_checksum;
};
typedef struct journal_revoke_header_s
{
journal_header_t r_header;
- int r_count; /* Count of bytes used in the block */
-} journal_revoke_header_t;
-
-/* Tail of revoke block, for checksumming */
-struct journal_revoke_tail {
- __be32 r_checksum;
-};
+ __be32 r_count; /* Count of bytes used in the block */
+} jbd2_journal_revoke_header_t;
/* Definitions for the journal tag flags word: */
-#define JFS_FLAG_ESCAPE 1 /* on-disk block is escaped */
-#define JFS_FLAG_SAME_UUID 2 /* block has same uuid as previous */
-#define JFS_FLAG_DELETED 4 /* block deleted by this transaction */
-#define JFS_FLAG_LAST_TAG 8 /* last tag in this descriptor block */
+#define JBD2_FLAG_ESCAPE 1 /* on-disk block is escaped */
+#define JBD2_FLAG_SAME_UUID 2 /* block has same uuid as previous */
+#define JBD2_FLAG_DELETED 4 /* block deleted by this transaction */
+#define JBD2_FLAG_LAST_TAG 8 /* last tag in this descriptor block */
#define UUID_SIZE 16
-#define JFS_USERS_MAX 48
-#define JFS_USERS_SIZE (UUID_SIZE * JFS_USERS_MAX)
+#define JBD2_USERS_MAX 48
+#define JBD2_USERS_SIZE (UUID_SIZE * JBD2_USERS_MAX)
/*
* The journal superblock. All fields are in big-endian byte order.
*/
/* 0x000C */
/* Static information describing the journal */
- __u32 s_blocksize; /* journal device blocksize */
- __u32 s_maxlen; /* total blocks in journal file */
- __u32 s_first; /* first block of log information */
+ __be32 s_blocksize; /* journal device blocksize */
+ __be32 s_maxlen; /* total blocks in journal file */
+ __be32 s_first; /* first block of log information */
/* 0x0018 */
/* Dynamic information describing the current state of the log */
- __u32 s_sequence; /* first commit ID expected in log */
- __u32 s_start; /* blocknr of start of log */
+ __be32 s_sequence; /* first commit ID expected in log */
+ __be32 s_start; /* blocknr of start of log */
/* 0x0020 */
/* Error value, as set by journal_abort(). */
/* 0x0024 */
/* Remaining fields are only valid in a version-2 superblock */
- __u32 s_feature_compat; /* compatible feature set */
- __u32 s_feature_incompat; /* incompatible feature set */
- __u32 s_feature_ro_compat; /* readonly-compatible feature set */
+ __be32 s_feature_compat; /* compatible feature set */
+ __be32 s_feature_incompat; /* incompatible feature set */
+ __be32 s_feature_ro_compat; /* readonly-compatible feature set */
/* 0x0030 */
__u8 s_uuid[16]; /* 128-bit uuid for journal */
/* 0x0040 */
- __u32 s_nr_users; /* Nr of filesystems sharing log */
+ __be32 s_nr_users; /* Nr of filesystems sharing log */
- __u32 s_dynsuper; /* Blocknr of dynamic superblock copy*/
+ __be32 s_dynsuper; /* Blocknr of dynamic superblock copy*/
/* 0x0048 */
- __u32 s_max_transaction; /* Limit of journal blocks per trans.*/
- __u32 s_max_trans_data; /* Limit of data blocks per trans. */
+ __be32 s_max_transaction; /* Limit of journal blocks per trans.*/
+ __be32 s_max_trans_data; /* Limit of data blocks per trans. */
/* 0x0050 */
__u8 s_checksum_type; /* checksum type */
__u8 s_padding2[3];
- __u32 s_padding[42];
- __u32 s_checksum; /* crc32c(superblock) */
+ __be32 s_padding[42];
+ __be32 s_checksum; /* crc32c(superblock) */
/* 0x0100 */
- __u8 s_users[JFS_USERS_SIZE]; /* ids of all fs'es sharing the log */
+ __u8 s_users[JBD2_USERS_SIZE]; /* ids of all fs'es sharing the log */
/* 0x0400 */
} journal_superblock_t;
-#define JFS_HAS_COMPAT_FEATURE(j,mask) \
+#define JBD2_HAS_COMPAT_FEATURE(j,mask) \
((j)->j_format_version >= 2 && \
((j)->j_superblock->s_feature_compat & ext2fs_cpu_to_be32((mask))))
-#define JFS_HAS_RO_COMPAT_FEATURE(j,mask) \
+#define JBD2_HAS_RO_COMPAT_FEATURE(j,mask) \
((j)->j_format_version >= 2 && \
((j)->j_superblock->s_feature_ro_compat & ext2fs_cpu_to_be32((mask))))
-#define JFS_HAS_INCOMPAT_FEATURE(j,mask) \
+#define JBD2_HAS_INCOMPAT_FEATURE(j,mask) \
((j)->j_format_version >= 2 && \
((j)->j_superblock->s_feature_incompat & ext2fs_cpu_to_be32((mask))))
-#define JFS_FEATURE_COMPAT_CHECKSUM 0x00000001
+#define JBD2_FEATURE_COMPAT_CHECKSUM 0x00000001
-#define JFS_FEATURE_INCOMPAT_REVOKE 0x00000001
-#define JFS_FEATURE_INCOMPAT_64BIT 0x00000002
-#define JFS_FEATURE_INCOMPAT_ASYNC_COMMIT 0x00000004
-#define JFS_FEATURE_INCOMPAT_CSUM_V2 0x00000008
-#define JFS_FEATURE_INCOMPAT_CSUM_V3 0x00000010
+#define JBD2_FEATURE_INCOMPAT_REVOKE 0x00000001
+#define JBD2_FEATURE_INCOMPAT_64BIT 0x00000002
+#define JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT 0x00000004
+#define JBD2_FEATURE_INCOMPAT_CSUM_V2 0x00000008
+#define JBD2_FEATURE_INCOMPAT_CSUM_V3 0x00000010
/* Features known to this kernel version: */
-#define JFS_KNOWN_COMPAT_FEATURES 0
-#define JFS_KNOWN_ROCOMPAT_FEATURES 0
-#define JFS_KNOWN_INCOMPAT_FEATURES (JFS_FEATURE_INCOMPAT_REVOKE|\
- JFS_FEATURE_INCOMPAT_ASYNC_COMMIT|\
- JFS_FEATURE_INCOMPAT_64BIT|\
- JFS_FEATURE_INCOMPAT_CSUM_V2|\
- JFS_FEATURE_INCOMPAT_CSUM_V3)
+#define JBD2_KNOWN_COMPAT_FEATURES 0
+#define JBD2_KNOWN_ROCOMPAT_FEATURES 0
+#define JBD2_KNOWN_INCOMPAT_FEATURES (JBD2_FEATURE_INCOMPAT_REVOKE|\
+ JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT| \
+ JBD2_FEATURE_INCOMPAT_64BIT|\
+ JBD2_FEATURE_INCOMPAT_CSUM_V2| \
+ JBD2_FEATURE_INCOMPAT_CSUM_V3)
#ifdef NO_INLINE_FUNCS
extern size_t journal_tag_bytes(journal_t *journal);
-extern int journal_has_csum_v2or3(journal_t *journal);
+extern int jbd2_journal_has_csum_v2or3(journal_t *journal);
extern int tid_gt(tid_t x, tid_t y) EXT2FS_ATTR((unused));
extern int tid_geq(tid_t x, tid_t y) EXT2FS_ATTR((unused));
#endif
#endif /* INCLUDE_INLINE_FUNCS */
/* journal feature predicate functions */
-#define JFS_FEATURE_COMPAT_FUNCS(name, flagname) \
-_INLINE_ int jfs_has_feature_##name(journal_t *j); \
-_INLINE_ int jfs_has_feature_##name(journal_t *j) \
+#define JBD2_FEATURE_COMPAT_FUNCS(name, flagname) \
+_INLINE_ int jbd2_has_feature_##name(journal_t *j); \
+_INLINE_ int jbd2_has_feature_##name(journal_t *j) \
{ \
return ((j)->j_format_version >= 2 && \
((j)->j_superblock->s_feature_compat & \
- ext2fs_cpu_to_be32(JFS_FEATURE_COMPAT_##flagname)) != 0); \
+ ext2fs_cpu_to_be32(JBD2_FEATURE_COMPAT_##flagname)) != 0); \
} \
-_INLINE_ void jfs_set_feature_##name(journal_t *j); \
-_INLINE_ void jfs_set_feature_##name(journal_t *j) \
+_INLINE_ void jbd2_set_feature_##name(journal_t *j); \
+_INLINE_ void jbd2_set_feature_##name(journal_t *j) \
{ \
(j)->j_superblock->s_feature_compat |= \
- ext2fs_cpu_to_be32(JFS_FEATURE_COMPAT_##flagname); \
+ ext2fs_cpu_to_be32(JBD2_FEATURE_COMPAT_##flagname); \
} \
-_INLINE_ void jfs_clear_feature_##name(journal_t *j); \
-_INLINE_ void jfs_clear_feature_##name(journal_t *j) \
+_INLINE_ void jbd2_clear_feature_##name(journal_t *j); \
+_INLINE_ void jbd2_clear_feature_##name(journal_t *j) \
{ \
(j)->j_superblock->s_feature_compat &= \
- ~ext2fs_cpu_to_be32(JFS_FEATURE_COMPAT_##flagname); \
+ ~ext2fs_cpu_to_be32(JBD2_FEATURE_COMPAT_##flagname); \
}
-#define JFS_FEATURE_RO_COMPAT_FUNCS(name, flagname) \
-_INLINE_ int jfs_has_feature_##name(journal_t *j); \
-_INLINE_ int jfs_has_feature_##name(journal_t *j) \
+#define JBD2_FEATURE_RO_COMPAT_FUNCS(name, flagname) \
+_INLINE_ int jbd2_has_feature_##name(journal_t *j); \
+_INLINE_ int jbd2_has_feature_##name(journal_t *j) \
{ \
return ((j)->j_format_version >= 2 && \
((j)->j_superblock->s_feature_ro_compat & \
- ext2fs_cpu_to_be32(JFS_FEATURE_RO_COMPAT_##flagname)) != 0); \
+ ext2fs_cpu_to_be32(JBD2_FEATURE_RO_COMPAT_##flagname)) != 0); \
} \
-_INLINE_ void jfs_set_feature_##name(journal_t *j); \
-_INLINE_ void jfs_set_feature_##name(journal_t *j) \
+_INLINE_ void jbd2_set_feature_##name(journal_t *j); \
+_INLINE_ void jbd2_set_feature_##name(journal_t *j) \
{ \
(j)->j_superblock->s_feature_ro_compat |= \
- ext2fs_cpu_to_be32(JFS_FEATURE_RO_COMPAT_##flagname); \
+ ext2fs_cpu_to_be32(JBD2_FEATURE_RO_COMPAT_##flagname); \
} \
-_INLINE_ void jfs_clear_feature_##name(journal_t *j); \
-_INLINE_ void jfs_clear_feature_##name(journal_t *j) \
+_INLINE_ void jbd2_clear_feature_##name(journal_t *j); \
+_INLINE_ void jbd2_clear_feature_##name(journal_t *j) \
{ \
(j)->j_superblock->s_feature_ro_compat &= \
- ~ext2fs_cpu_to_be32(JFS_FEATURE_RO_COMPAT_##flagname); \
+ ~ext2fs_cpu_to_be32(JBD2_FEATURE_RO_COMPAT_##flagname); \
}
-#define JFS_FEATURE_INCOMPAT_FUNCS(name, flagname) \
-_INLINE_ int jfs_has_feature_##name(journal_t *j); \
-_INLINE_ int jfs_has_feature_##name(journal_t *j) \
+#define JBD2_FEATURE_INCOMPAT_FUNCS(name, flagname) \
+_INLINE_ int jbd2_has_feature_##name(journal_t *j); \
+_INLINE_ int jbd2_has_feature_##name(journal_t *j) \
{ \
return ((j)->j_format_version >= 2 && \
((j)->j_superblock->s_feature_incompat & \
- ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_##flagname)) != 0); \
+ ext2fs_cpu_to_be32(JBD2_FEATURE_INCOMPAT_##flagname)) != 0); \
} \
-_INLINE_ void jfs_set_feature_##name(journal_t *j); \
-_INLINE_ void jfs_set_feature_##name(journal_t *j) \
+_INLINE_ void jbd2_set_feature_##name(journal_t *j); \
+_INLINE_ void jbd2_set_feature_##name(journal_t *j) \
{ \
(j)->j_superblock->s_feature_incompat |= \
- ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_##flagname); \
+ ext2fs_cpu_to_be32(JBD2_FEATURE_INCOMPAT_##flagname); \
} \
-_INLINE_ void jfs_clear_feature_##name(journal_t *j); \
-_INLINE_ void jfs_clear_feature_##name(journal_t *j) \
+_INLINE_ void jbd2_clear_feature_##name(journal_t *j); \
+_INLINE_ void jbd2_clear_feature_##name(journal_t *j) \
{ \
(j)->j_superblock->s_feature_incompat &= \
- ~ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_##flagname); \
+ ~ext2fs_cpu_to_be32(JBD2_FEATURE_INCOMPAT_##flagname); \
}
#else
-#define JFS_FEATURE_COMPAT_FUNCS(name, flagname) \
-extern int jfs_has_feature_##name(journal_t *j); \
-extern void jfs_set_feature_##name(journal_t *j); \
-extern void jfs_clear_feature_##name(journal_t *j);
+#define JBD2_FEATURE_COMPAT_FUNCS(name, flagname) \
+extern int jbd2_has_feature_##name(journal_t *j); \
+extern void jbd2_set_feature_##name(journal_t *j); \
+extern void jbd2_clear_feature_##name(journal_t *j);
-#define JFS_FEATURE_RO_COMPAT_FUNCS(name, flagname) \
-extern int jfs_has_feature_##name(journal_t *j); \
-extern void jfs_set_feature_##name(journal_t *j); \
-extern void jfs_clear_feature_##name(journal_t *j);
+#define JBD2_FEATURE_RO_COMPAT_FUNCS(name, flagname) \
+extern int jbd2_has_feature_##name(journal_t *j); \
+extern void jbd2_set_feature_##name(journal_t *j); \
+extern void jbd2_clear_feature_##name(journal_t *j);
-#define JFS_FEATURE_INCOMPAT_FUNCS(name, flagname) \
-extern int jfs_has_feature_##name(journal_t *j); \
-extern void jfs_set_feature_##name(journal_t *j); \
-extern void jfs_clear_feature_##name(journal_t *j);
+#define JBD2_FEATURE_INCOMPAT_FUNCS(name, flagname) \
+extern int jbd2_has_feature_##name(journal_t *j); \
+extern void jbd2_set_feature_##name(journal_t *j); \
+extern void jbd2_clear_feature_##name(journal_t *j);
#endif /* (defined(E2FSCK_INCLUDE_INLINE_FUNCS) || !defined(NO_INLINE_FUNCS)) */
-JFS_FEATURE_COMPAT_FUNCS(checksum, CHECKSUM)
+JBD2_FEATURE_COMPAT_FUNCS(checksum, CHECKSUM)
-JFS_FEATURE_INCOMPAT_FUNCS(revoke, REVOKE)
-JFS_FEATURE_INCOMPAT_FUNCS(64bit, 64BIT)
-JFS_FEATURE_INCOMPAT_FUNCS(async_commit, ASYNC_COMMIT)
-JFS_FEATURE_INCOMPAT_FUNCS(csum2, CSUM_V2)
-JFS_FEATURE_INCOMPAT_FUNCS(csum3, CSUM_V3)
+JBD2_FEATURE_INCOMPAT_FUNCS(revoke, REVOKE)
+JBD2_FEATURE_INCOMPAT_FUNCS(64bit, 64BIT)
+JBD2_FEATURE_INCOMPAT_FUNCS(async_commit, ASYNC_COMMIT)
+JBD2_FEATURE_INCOMPAT_FUNCS(csum2, CSUM_V2)
+JBD2_FEATURE_INCOMPAT_FUNCS(csum3, CSUM_V3)
#if (defined(E2FSCK_INCLUDE_INLINE_FUNCS) || !defined(NO_INLINE_FUNCS))
/*
{
size_t sz;
- if (jfs_has_feature_csum3(journal))
+ if (jbd2_has_feature_csum3(journal))
return sizeof(journal_block_tag3_t);
sz = sizeof(journal_block_tag_t);
- if (jfs_has_feature_csum2(journal))
+ if (jbd2_has_feature_csum2(journal))
sz += sizeof(__u16);
- if (jfs_has_feature_64bit(journal))
+ if (jbd2_has_feature_64bit(journal))
return sz;
return sz - sizeof(__u32);
}
-_INLINE_ int journal_has_csum_v2or3(journal_t *journal)
+_INLINE_ int jbd2_journal_has_csum_v2or3(journal_t *journal)
{
- if (jfs_has_feature_csum2(journal) || jfs_has_feature_csum3(journal))
+ if (jbd2_has_feature_csum2(journal) || jbd2_has_feature_csum3(journal))
return 1;
return 0;
errcode_t retval;
journal_superblock_t *jsb;
- if (num_blocks < JFS_MIN_JOURNAL_BLOCKS)
+ if (num_blocks < JBD2_MIN_JOURNAL_BLOCKS)
return EXT2_ET_JOURNAL_TOO_SMALL;
if ((retval = ext2fs_get_mem(fs->blocksize, &jsb)))
memset (jsb, 0, fs->blocksize);
- jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER);
+ jsb->s_header.h_magic = htonl(JBD2_MAGIC_NUMBER);
if (flags & EXT2_MKJOURNAL_V1_SUPER)
- jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V1);
+ jsb->s_header.h_blocktype = htonl(JBD2_SUPERBLOCK_V1);
else
- jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2);
+ jsb->s_header.h_blocktype = htonl(JBD2_SUPERBLOCK_V2);
jsb->s_blocksize = htonl(fs->blocksize);
jsb->s_maxlen = htonl(num_blocks);
jsb->s_nr_users = htonl(1);
return retval;
jsb = (journal_superblock_t *) buf;
- if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) ||
- (jsb->s_header.h_blocktype != (unsigned) ntohl(JFS_SUPERBLOCK_V2)))
+ if ((jsb->s_header.h_magic != (unsigned) ntohl(JBD2_MAGIC_NUMBER)) ||
+ (jsb->s_header.h_blocktype != (unsigned) ntohl(JBD2_SUPERBLOCK_V2)))
return EXT2_ET_NO_JOURNAL_SB;
if (ntohl(jsb->s_blocksize) != (unsigned long) fs->blocksize)
/* Check and see if this filesystem has already been added */
nr_users = ntohl(jsb->s_nr_users);
- if (nr_users > JFS_USERS_MAX)
+ if (nr_users > JBD2_USERS_MAX)
return EXT2_ET_CORRUPT_JOURNAL_SB;
for (i=0; i < nr_users; i++) {
if (memcmp(fs->super->s_uuid,
exit(1);
}
- retval = ext2fs_add_journal_inode(fs, JFS_MIN_JOURNAL_BLOCKS, 0);
+ retval = ext2fs_add_journal_inode(fs, JBD2_MIN_JOURNAL_BLOCKS, 0);
if (retval) {
com_err(argv[0], retval, "while adding journal to %s",
device_name);
}
fs->desc_blocks = ext2fs_div_ceil(fs->group_desc_count,
EXT2_DESC_PER_BLOCK(fs->super));
+ if (flags & EXT2_FLAG_SUPER_ONLY)
+ goto skip_read_bg;
retval = ext2fs_get_array(fs->desc_blocks, fs->blocksize,
&fs->group_desc);
if (retval)
gdp = (struct ext2_group_desc *) dest;
for (j=0; j < groups_per_block*first_meta_bg; j++) {
gdp = ext2fs_group_desc(fs, fs->group_desc, j);
- ext2fs_swap_group_desc2(fs, gdp);
+ if (gdp)
+ ext2fs_swap_group_desc2(fs, gdp);
}
#endif
dest += fs->blocksize*first_meta_bg;
for (j=0; j < groups_per_block; j++) {
gdp = ext2fs_group_desc(fs, fs->group_desc,
i * groups_per_block + j);
- ext2fs_swap_group_desc2(fs, gdp);
+ if (gdp)
+ ext2fs_swap_group_desc2(fs, gdp);
}
#endif
dest += fs->blocksize;
if (fs->flags & EXT2_FLAG_RW)
ext2fs_mark_super_dirty(fs);
}
-
+skip_read_bg:
if (ext2fs_has_feature_mmp(fs->super) &&
!(flags & EXT2_FLAG_SKIP_MMP) &&
(flags & (EXT2_FLAG_RW | EXT2_FLAG_EXCLUSIVE))) {
}
ext2fs_file_close(journal_file);
jsb = (journal_superblock_t *) buf;
- if (be32_to_cpu(jsb->s_header.h_magic) != JFS_MAGIC_NUMBER) {
+ if (be32_to_cpu(jsb->s_header.h_magic) != JBD2_MAGIC_NUMBER) {
fprintf(stderr, "%s",
_("Journal superblock magic number invalid!\n"));
exit(1);
exit(1);
}
jsb = (journal_superblock_t *) buf;
- if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) ||
+ if ((jsb->s_header.h_magic != (unsigned) ntohl(JBD2_MAGIC_NUMBER)) ||
(jsb->s_header.h_blocktype !=
- (unsigned) ntohl(JFS_SUPERBLOCK_V2))) {
+ (unsigned) ntohl(JBD2_SUPERBLOCK_V2))) {
com_err(program_name, 0, "%s",
_("Couldn't find journal superblock magic numbers"));
exit(1);
flags |= EXT2_FLAG_FORCE;
if (image_dump)
flags |= EXT2_FLAG_IMAGE_FILE;
+ if (header_only)
+ flags |= EXT2_FLAG_SUPER_ONLY;
try_open_again:
if (use_superblock && !use_blocksize) {
for (use_blocksize = EXT2_MIN_BLOCK_SIZE;
\fB-o\fR no_default_opts
do not include default fuse options
.TP
+\fB-o\fR norecovery
+do not replay the journal and mount the file system read-only
+.TP
\fB-o\fR fuse2fs_debug
enable fuse2fs debugging
.SS "FUSE options:"
int minixdf;
int fakeroot;
int alloc_all_blocks;
+ int norecovery;
FILE *err_fp;
unsigned int next_generation;
};
FUSE2FS_OPT("fakeroot", fakeroot, 1),
FUSE2FS_OPT("fuse2fs_debug", debug, 1),
FUSE2FS_OPT("no_default_opts", no_default_opts, 1),
+ FUSE2FS_OPT("norecovery", norecovery, 1),
FUSE_OPT_KEY("-V", FUSE2FS_VERSION),
FUSE_OPT_KEY("--version", FUSE2FS_VERSION),
" -o minixdf minix-style df\n"
" -o fakeroot pretend to be root for permission checks\n"
" -o no_default_opts do not include default fuse options\n"
+ " -o norecovery don't replay the journal (implies ro)\n"
" -o fuse2fs_debug enable fuse2fs debugging\n"
"\n",
outargs->argv[0]);
exit(1);
}
+ if (fctx.norecovery)
+ fctx.ro = 1;
if (fctx.ro)
printf("%s", _("Mounting read-only.\n"));
ret = 3;
if (ext2fs_has_feature_journal_needs_recovery(global_fs->super)) {
- if (!fctx.ro) {
+ if (fctx.norecovery) {
+ printf(_("%s: mounting read-only without "
+ "recovering journal\n"),
+ fctx.device);
+ } else if (!fctx.ro) {
printf(_("%s: recovering journal\n"), fctx.device);
err = ext2fs_run_ext3_journal(&global_fs);
if (err) {
EXT2_FEATURE_COMPAT_RESIZE_INODE |
EXT2_FEATURE_COMPAT_DIR_INDEX |
EXT2_FEATURE_COMPAT_EXT_ATTR |
- EXT4_FEATURE_COMPAT_SPARSE_SUPER2,
+ EXT4_FEATURE_COMPAT_SPARSE_SUPER2 |
+ EXT4_FEATURE_COMPAT_FAST_COMMIT |
+ EXT4_FEATURE_COMPAT_STABLE_INODES,
/* Incompat */
EXT2_FEATURE_INCOMPAT_FILETYPE|
EXT3_FEATURE_INCOMPAT_EXTENTS|
static __u32 ok_features[3] = {
/* Compat */
EXT3_FEATURE_COMPAT_HAS_JOURNAL |
- EXT2_FEATURE_COMPAT_DIR_INDEX,
+ EXT2_FEATURE_COMPAT_DIR_INDEX |
+ EXT4_FEATURE_COMPAT_FAST_COMMIT |
+ EXT4_FEATURE_COMPAT_STABLE_INODES,
/* Incompat */
EXT2_FEATURE_INCOMPAT_FILETYPE |
EXT3_FEATURE_INCOMPAT_EXTENTS |
/* Compat */
EXT3_FEATURE_COMPAT_HAS_JOURNAL |
EXT2_FEATURE_COMPAT_RESIZE_INODE |
- EXT2_FEATURE_COMPAT_DIR_INDEX,
+ EXT2_FEATURE_COMPAT_DIR_INDEX |
+ EXT4_FEATURE_COMPAT_FAST_COMMIT |
+ EXT4_FEATURE_COMPAT_STABLE_INODES,
/* Incompat */
EXT2_FEATURE_INCOMPAT_FILETYPE |
EXT4_FEATURE_INCOMPAT_FLEX_BG |
}
jsb = (journal_superblock_t *) buf;
- if ((jsb->s_header.h_magic != (unsigned)ntohl(JFS_MAGIC_NUMBER)) ||
- (jsb->s_header.h_blocktype != (unsigned)ntohl(JFS_SUPERBLOCK_V2))) {
+ if ((jsb->s_header.h_magic != (unsigned)ntohl(JBD2_MAGIC_NUMBER)) ||
+ (jsb->s_header.h_blocktype != (unsigned)ntohl(JBD2_SUPERBLOCK_V2))) {
fputs(_("Journal superblock not found!\n"), stderr);
return EXT2_ET_BAD_MAGIC;
}
return 0;
}
-static __u8 *journal_user(__u8 uuid[UUID_SIZE], __u8 s_users[JFS_USERS_SIZE],
+static __u8 *journal_user(__u8 uuid[UUID_SIZE], __u8 s_users[JBD2_USERS_SIZE],
int nr_users)
{
int i;
jsb = (journal_superblock_t *) buf;
/* Find the filesystem UUID */
nr_users = ntohl(jsb->s_nr_users);
- if (nr_users > JFS_USERS_MAX) {
+ if (nr_users > JBD2_USERS_MAX) {
fprintf(stderr, _("Journal superblock is corrupted, nr_users\n"
"is too high (%d).\n"), nr_users);
commit_remove_journal = 1;
argv[1]);
exit(1);
}
- open_flag = EXT2_FLAG_JOURNAL_DEV_OK;
+ open_flag = EXT2_FLAG_JOURNAL_DEV_OK | EXT2_FLAG_SUPER_ONLY;
if (argc == 3) {
open_flag |= EXT2_FLAG_RW;
L_flag = 1;
jsb = (journal_superblock_t *) buf;
/* Find the filesystem UUID */
nr_users = ntohl(jsb->s_nr_users);
- if (nr_users > JFS_USERS_MAX) {
+ if (nr_users > JBD2_USERS_MAX) {
fprintf(stderr, _("Journal superblock is corrupted, nr_users\n"
"is too high (%d).\n"), nr_users);
return EXT2_ET_CORRUPT_JOURNAL_SB;
e2fsck/ea_refcount.c
e2fsck/ehandler.c
e2fsck/emptydir.c
+e2fsck/encrypted_files.c
e2fsck/extend.c
e2fsck/extents.c
e2fsck/flushb.c
fprintf(stderr, _("The filesystem is already 32-bit.\n"));
exit(0);
}
+ if (new_size < ext2fs_blocks_count(fs->super) &&
+ ext2fs_has_feature_stable_inodes(fs->super)) {
+ fprintf(stderr, _("Cannot shrink this filesystem "
+ "because it has the stable_inodes feature flag.\n"));
+ exit(1);
+ }
if (mount_flags & EXT2_MF_MOUNTED) {
retval = online_resize_fs(fs, mtpt, &new_size, flags);
} else {
--- /dev/null
+Pass 1: Checking inodes, blocks, and sizes
+Inode 17 has encrypt flag but no encryption extended attribute.
+Clear flag? yes
+
+Inode 18 has encrypt flag but no encryption extended attribute.
+Clear flag? yes
+
+Encrypted inode 19 has corrupt encryption extended attribute.
+Clear inode? yes
+
+Encrypted inode 20 has corrupt encryption extended attribute.
+Clear inode? yes
+
+Encrypted inode 21 has corrupt encryption extended attribute.
+Clear inode? yes
+
+Encrypted inode 22 has corrupt encryption extended attribute.
+Clear inode? yes
+
+Pass 2: Checking directory structure
+Encrypted entry 'd6M->'M-#I^VM-^KM-F~^WSJ+M-uM-zM-zXM-^' in /edir (12) references unencrypted inode 17.
+Clear? yes
+
+Encrypted entry '\M-!M-Y%DhM-OM-VM-zM-CM-gVM-R3M-^RM-IkE^JM-^S' in /edir (12) references unencrypted inode 18.
+Clear? yes
+
+Entry 'M-{^Qp-M-sM-U7eM-^C^L^PG^ZM-FM-,M-B' in /edir (12) has deleted/unused inode 19. Clear? yes
+
+Entry 'M-f0M-f3/M-NM-GM-:M-^YM-jM-XM-91DM-^_M-V' in /edir (12) has deleted/unused inode 20. Clear? yes
+
+Entry '^M-R"M-^K^P7M-'M-EM-C}^MM-yM-^LwM-^N^Z' in /edir (12) has deleted/unused inode 21. Clear? yes
+
+Entry 'M-s^J_;uIvM-^Z[M-nIM-5vM-^AcM-o' in /edir (12) has deleted/unused inode 22. Clear? yes
+
+Encrypted entry 'kK=,M-bM-^AM-{M-YM-^J6M-hM-y^XM-^W}M-M' in /edir (12) references unencrypted inode 23.
+Clear? yes
+
+Encrypted entry 'M-VM-cxM-jM-zM-b^WM-o*M-jM-uM-,R^PM-hM-2' in /edir (12) references unencrypted inode 24.
+Clear? yes
+
+Encrypted entry 'UqM-AM-#KM-^PM-_^kM-9P0M-^FM-_^@;A^J"R' in /edir (12) references unencrypted inode 25.
+Clear? yes
+
+Encrypted entry 'M-TM-N8^[M-3M-( M-[A^FR}^ZhkM-^?=M-c^Mo' in /edir (12) references inode 26, which has a different encryption policy.
+Clear? yes
+
+Encrypted entry 'M--aM-^?~M-^\M-u^FM-/!^YM-OZM-^LM-)M-p1' in /edir (12) references inode 27, which has a different encryption policy.
+Clear? yes
+
+Encrypted entry '(M-8RKM-LM-eM-^W^[M-'M-SM-@uM-^VM-|M-GiM-^JbM-nM-z' in /edir (12) references inode 28, which has a different encryption policy.
+Clear? yes
+
+Encrypted entry '\M-ggCeM-/?M-^BM-{(M-^OM-9M-^QQAM-^N=M-c^Mo' in /edir (12) references inode 29, which has a different encryption policy.
+Clear? yes
+
+Pass 3: Checking directory connectivity
+Unconnected directory inode 18 (/edir/???)
+Connect to /lost+found? yes
+
+Unconnected directory inode 24 (/edir/???)
+Connect to /lost+found? yes
+
+Unconnected directory inode 27 (/edir/???)
+Connect to /lost+found? yes
+
+Pass 4: Checking reference counts
+Unattached inode 17
+Connect to /lost+found? yes
+
+Inode 17 ref count is 2, should be 1. Fix? yes
+
+Inode 18 ref count is 3, should be 2. Fix? yes
+
+Unattached inode 23
+Connect to /lost+found? yes
+
+Inode 23 ref count is 2, should be 1. Fix? yes
+
+Inode 24 ref count is 3, should be 2. Fix? yes
+
+Unattached inode 25
+Connect to /lost+found? yes
+
+Inode 25 ref count is 2, should be 1. Fix? yes
+
+Unattached inode 26
+Connect to /lost+found? yes
+
+Inode 26 ref count is 2, should be 1. Fix? yes
+
+Inode 27 ref count is 3, should be 2. Fix? yes
+
+Unattached inode 28
+Connect to /lost+found? yes
+
+Inode 28 ref count is 2, should be 1. Fix? yes
+
+Unattached inode 29
+Connect to /lost+found? yes
+
+Inode 29 ref count is 2, should be 1. Fix? yes
+
+Pass 5: Checking group summary information
+Block bitmap differences: -(25--32)
+Fix? yes
+
+Free blocks count wrong for group #0 (75, counted=83).
+Fix? yes
+
+Free blocks count wrong (75, counted=83).
+Fix? yes
+
+Inode bitmap differences: -(19--22)
+Fix? yes
+
+Free inodes count wrong for group #0 (95, counted=99).
+Fix? yes
+
+Free inodes count wrong (95, counted=99).
+Fix? yes
+
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 29/128 files (0.0% non-contiguous), 45/128 blocks
+Exit status is 1
--- /dev/null
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 29/128 files (0.0% non-contiguous), 45/128 blocks
+Exit status is 0
--- /dev/null
+#!/bin/bash
+#
+# This is the script that was used to create the image.gz in this directory.
+#
+# This requires a patched version of debugfs that understands the "fscrypt."
+# xattr name prefix, so that the encryption xattrs can be manipulated.
+
+set -e -u
+umask 0022
+
+do_debugfs() {
+ umount mnt
+ debugfs -w "$@" image
+ mount image mnt
+}
+
+create_encrypted_file() {
+ local file=$1
+ local ino
+
+ echo foo > "$file"
+
+ # not needed, but makes image more compressible
+ ino=$(stat -c %i "$file")
+ do_debugfs -R "zap_block -f <$ino> 0"
+}
+
+set_encryption_xattr() {
+ local file=$1
+ local value=$2
+ local ino
+
+ ino=$(stat -c %i "$file")
+ do_debugfs -R "ea_set <$ino> fscrypt.c $value"
+}
+
+rm_encryption_xattr() {
+ local file=$1
+ local ino
+
+ ino=$(stat -c %i "$file")
+ do_debugfs -R "ea_rm <$ino> fscrypt.c"
+}
+
+clear_encrypt_flag() {
+ local file=$1
+ local ino
+
+ ino=$(stat -c %i "$file")
+ do_debugfs -R "set_inode_field <$ino> flags 0"
+}
+
+clear_encryption() {
+ local file=$1
+ local ino
+ local is_symlink=false
+
+ if [ -L "$file" ]; then
+ is_symlink=true
+ fi
+ ino=$(stat -c %i "$file")
+
+ do_debugfs -R "ea_rm <$ino> fscrypt.c"
+ do_debugfs -R "set_inode_field <$ino> flags 0"
+ if $is_symlink; then
+ do_debugfs -R "set_inode_field <$ino> block[0] 0xAAAAAAAA"
+ do_debugfs -R "set_inode_field <$ino> block[1] 0"
+ do_debugfs -R "set_inode_field <$ino> size 4"
+ fi
+}
+
+mkdir -p mnt
+umount mnt &> /dev/null || true
+
+dd if=/dev/zero of=image bs=4096 count=128
+mke2fs -O encrypt -b 4096 -N 128 image
+mount image mnt
+
+# Create an encrypted directory (ino 12)
+dir=mnt/edir
+mkdir $dir
+echo password | e4crypt add_key $dir
+
+# Control cases: valid encrypted regular file, dir, and symlink (ino 13-15)
+create_encrypted_file $dir/encrypted_file
+mkdir $dir/encrypted_dir
+ln -s target $dir/encrypted_symlink
+
+# Control case: file type that is never encrypted (ino 16)
+mkfifo $dir/fifo
+
+# Inodes with missing encryption xattr (ino 17-18).
+# e2fsck should offer to clear the encrypt flag on these inodes.
+
+create_encrypted_file $dir/missing_xattr_file
+rm_encryption_xattr $dir/missing_xattr_file
+
+mkdir $dir/missing_xattr_dir
+rm_encryption_xattr $dir/missing_xattr_dir
+
+# Inodes with corrupt encryption xattr (ino 19-22).
+# e2fsck should offer to clear these inodes.
+
+create_encrypted_file $dir/corrupt_xattr_1
+set_encryption_xattr $dir/corrupt_xattr_1 '\0'
+
+create_encrypted_file $dir/corrupt_xattr_2
+set_encryption_xattr $dir/corrupt_xattr_2 \
+ '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0'
+
+create_encrypted_file $dir/corrupt_xattr_3
+set_encryption_xattr $dir/corrupt_xattr_3 '\1'
+
+create_encrypted_file $dir/corrupt_xattr_4
+set_encryption_xattr $dir/corrupt_xattr_4 '\2'
+
+# Unencrypted inodes in encrypted directory (ino 23-25).
+# e2fsck should offer to clear these directory entries.
+
+create_encrypted_file $dir/unencrypted_file
+clear_encryption $dir/unencrypted_file
+
+mkdir $dir/unencrypted_dir
+clear_encryption $dir/unencrypted_dir
+
+ln -s target $dir/unencrypted_symlink
+clear_encryption $dir/unencrypted_symlink
+
+# Inodes with different encryption policy in encrypted directory (ino 26-29).
+# e2fsck should offer to clear these directory entries.
+
+xattr='\1\1\4\0AAAAAAAABBBBBBBBBBBBBBBB'
+
+create_encrypted_file $dir/inconsistent_file_1
+set_encryption_xattr $dir/inconsistent_file_1 $xattr
+
+mkdir $dir/inconsistent_dir
+set_encryption_xattr $dir/inconsistent_dir $xattr
+
+ln -s target $dir/inconsistent_symlink
+set_encryption_xattr $dir/inconsistent_symlink $xattr
+
+xattr='\2\1\4\0\0\0\0\0AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBB'
+create_encrypted_file $dir/inconsistent_file_2
+set_encryption_xattr $dir/inconsistent_file_2 $xattr
+
+# Encrypted file and directory with valid v2 encryption policy (ino 30-31).
+# e2fsck shouldn't change these.
+dir2=mnt/edir2
+mkdir $dir2
+echo password | e4crypt add_key $dir2
+xattr='\2\1\4\0\0\0\0\0AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBB'
+create_encrypted_file $dir2/file
+set_encryption_xattr $dir2/file $xattr
+set_encryption_xattr $dir2 $xattr
+
+# Encrypted file and directory with unrecognized encryption policy version
+# (ino 32-33). e2fsck shouldn't change these.
+dir3=mnt/edir3
+mkdir $dir3
+echo password | e4crypt add_key $dir3
+xattr='\3'
+create_encrypted_file $dir3/file
+set_encryption_xattr $dir3/file $xattr
+set_encryption_xattr $dir3 $xattr
+
+umount mnt
+rmdir mnt
+gzip -9 -f image
--- /dev/null
+missing, corrupt, and inconsistent encryption policies
--- /dev/null
+Pass 1: Checking inodes, blocks, and sizes
+Deleted inode 26363 has zero dtime. Fix? yes
+
+Pass 2: Checking directory structure
+Entry 'nlink_eq_0' in / (2) has deleted/unused inode 26363. Clear? yes
+
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Inode 2 ref count is 9, should be 8. Fix? yes
+
+Inode 13201 ref count is 1, should be 2. Fix? yes
+
+Inode 19763 ref count is 65535, should be 2. Fix? yes
+
+Directory exceeds max links, but no DIR_NLINK feature in superblock.
+Fix? yes
+
+Inode 32963 ref count is 65000, should be 2. Fix? yes
+
+Pass 5: Checking group summary information
+Block bitmap differences: -73383
+Fix? yes
+
+Free blocks count wrong for group #8 (0, counted=1).
+Fix? yes
+
+Free blocks count wrong (5388, counted=5389).
+Fix? yes
+
+Inode bitmap differences: -26363
+Fix? yes
+
+Free inodes count wrong for group #3 (37, counted=38).
+Fix? yes
+
+Directories count wrong for group #3 (6563, counted=6562).
+Fix? yes
+
+Free inodes count wrong (382, counted=383).
+Fix? yes
+
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 65617/66000 files (0.0% non-contiguous), 76531/81920 blocks
+Exit status is 1
--- /dev/null
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 65617/66000 files (0.0% non-contiguous), 76531/81920 blocks
+Exit status is 0
--- /dev/null
+directory with more than 65000 sub-directories
Pass 5: Checking group summary information
test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
-test_filesys: 13/16 files (0.0% non-contiguous), 23/100 blocks
+test_filesys: 13/16 files (0.0% non-contiguous), 24/100 blocks
Exit status is 1
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
-test_filesys: 13/16 files (0.0% non-contiguous), 23/100 blocks
+test_filesys: 13/16 files (0.0% non-contiguous), 24/100 blocks
Exit status is 0
--- /dev/null
+Group descriptor 1 has invalid unused inodes count 2048. Fix? yes
+
+Group descriptor 2 has invalid unused inodes count 1344. Fix? yes
+
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+Free inodes count wrong for group #1 (490, counted=2048).
+Fix? yes
+
+Free inodes count wrong for group #2 (250, counted=1344).
+Fix? yes
+
+Free inodes count wrong for group #3 (1967, counted=1969).
+Fix? yes
+
+Free inodes count wrong (4744, counted=7398).
+Fix? yes
+
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 794/8192 files (0.4% non-contiguous), 8473/32768 blocks
+Exit status is 1
--- /dev/null
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 794/8192 files (0.4% non-contiguous), 8473/32768 blocks
+Exit status is 0
--- /dev/null
+bad free inode count, but good checksum
--- /dev/null
+Group descriptor 1 has invalid unused inodes count 2048. Fix? yes
+
+Group descriptor 2 has invalid unused inodes count 2048. Fix? yes
+
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+Group 1 block(s) in use but group is marked BLOCK_UNINIT
+Fix? yes
+
+Block bitmap differences: +(8585--8777)
+Fix? yes
+
+Free blocks count wrong for group #2 (0, counted=7934).
+Fix? yes
+
+Free blocks count wrong (19530, counted=27464).
+Fix? yes
+
+Free inodes count wrong for group #1 (0, counted=2048).
+Fix? yes
+
+Free inodes count wrong for group #2 (0, counted=2048).
+Fix? yes
+
+Free inodes count wrong (4084, counted=8180).
+Fix? yes
+
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 12/8192 files (8.3% non-contiguous), 5304/32768 blocks
+Exit status is 1
--- /dev/null
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 12/8192 files (8.3% non-contiguous), 5304/32768 blocks
+Exit status is 0
--- /dev/null
+blocks used but block uninit set
--- /dev/null
+One or more block group descriptor checksums are invalid. Fix? yes
+
+Group descriptor 1 checksum is 0xbbaa, should be 0xff0b. FIXED.
+Group descriptor 2 has invalid unused inodes count 2048. Fix? yes
+
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+Free blocks count wrong for group #2 (0, counted=7934).
+Fix? yes
+
+Free blocks count wrong (19286, counted=27220).
+Fix? yes
+
+Free inodes count wrong for group #1 (0, counted=2048).
+Fix? yes
+
+Free inodes count wrong for group #2 (0, counted=2048).
+Fix? yes
+
+Free inodes count wrong (4085, counted=8181).
+Fix? yes
+
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 11/8192 files (0.0% non-contiguous), 5548/32768 blocks
+Exit status is 1
--- /dev/null
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 11/8192 files (0.0% non-contiguous), 5548/32768 blocks
+Exit status is 0
--- /dev/null
+invalid group descriptor checksum
--- /dev/null
+Group descriptor 0 marked uninitialized without feature set.
+Fix? yes
+
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 11/2048 files (0.0% non-contiguous), 306/8192 blocks
+Exit status is 1
--- /dev/null
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 11/2048 files (0.0% non-contiguous), 306/8192 blocks
+Exit status is 0
--- /dev/null
+disable uninit_bg feature
--- /dev/null
+One or more block group descriptor checksums are invalid. Fix? yes
+
+Group descriptor 0 checksum is 0x0000, should be 0x13f6. FIXED.
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 11/2048 files (0.0% non-contiguous), 306/8192 blocks
+Exit status is 1
--- /dev/null
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 11/2048 files (0.0% non-contiguous), 306/8192 blocks
+Exit status is 0
--- /dev/null
+enable uninit_bg feature
--- /dev/null
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Entry 'foo' in / (2) references inode 14 found in group 0's unused inodes area.
+Fix? yes
+
+Restarting e2fsck from the beginning...
+One or more block group descriptor checksums are invalid. Fix? yes
+
+Group descriptor 0 checksum is 0x4c72, should be 0xde74. FIXED.
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+Inode bitmap differences: -12
+Fix? yes
+
+Free inodes count wrong for group #0 (2037, counted=2035).
+Fix? yes
+
+Free inodes count wrong (4073, counted=2035).
+Fix? yes
+
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 13/2048 files (0.0% non-contiguous), 1336/8192 blocks
+Exit status is 1
--- /dev/null
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 13/2048 files (0.0% non-contiguous), 1336/8192 blocks
+Exit status is 0
--- /dev/null
+inode in use beyond bg_itable_unused
--- /dev/null
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Entry 'foo2' in /d1 (1881) references inode 500 found in group 0's unused inodes area.
+Fix? yes
+
+Entry 'foo2' in /d1 (1881) has an incorrect filetype (was 1, should be 0).
+Fix? yes
+
+Entry 'bar2' in /d2 (3761) references inode 2100 found in group 1's unused inodes area.
+Fix? yes
+
+Entry 'bar2' in /d2 (3761) has an incorrect filetype (was 1, should be 0).
+Fix? yes
+
+Restarting e2fsck from the beginning...
+One or more block group descriptor checksums are invalid. Fix? yes
+
+Group descriptor 0 checksum is 0xb92b, should be 0x2b5f. FIXED.
+Group descriptor 1 checksum is 0x2f53, should be 0x8d2f. FIXED.
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Entry 'foo2' in /d1 (1881) has deleted/unused inode 500. Clear? yes
+
+Entry 'bar2' in /d2 (3761) has deleted/unused inode 2100. Clear? yes
+
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Unattached zero-length inode 1883. Clear? yes
+
+Unattached zero-length inode 3763. Clear? yes
+
+Pass 5: Checking group summary information
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 21/7520 files (0.0% non-contiguous), 2352/30000 blocks
+Exit status is 1
--- /dev/null
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 21/7520 files (0.0% non-contiguous), 2352/30000 blocks
+Exit status is 0
--- /dev/null
+re-start e2fsck only once for inodes in uninit space
--- /dev/null
+Group descriptor 1 has invalid unused inodes count 1464. Fix? yes
+
+Group descriptor 2 has invalid unused inodes count 1849. Fix? yes
+
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+Group 1 block(s) in use but group is marked BLOCK_UNINIT
+Fix? yes
+
+Block bitmap differences: +(9729--14621)
+Fix? yes
+
+Free inodes count wrong for group #1 (0, counted=1464).
+Fix? yes
+
+Free inodes count wrong for group #2 (0, counted=1849).
+Fix? yes
+
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 794/8192 files (0.3% non-contiguous), 8473/32768 blocks
+Exit status is 1
--- /dev/null
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 794/8192 files (0.3% non-contiguous), 8473/32768 blocks
+Exit status is 0
--- /dev/null
+block uninit set but inode uninit not set
test_filesys: recovering journal
-JBD2: Invalid checksum recovering block 1090 in log
+JBD2: Invalid checksum recovering data block 1090 in log
Journal checksum error found in test_filesys
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
* file may be redistributed under the GNU Public License v2.
*/
-#define E2FSPROGS_VERSION "1.45.5"
-#define E2FSPROGS_DATE "07-Jan-2020"
+#define E2FSPROGS_VERSION "1.46-WIP"
+#define E2FSPROGS_DATE "09-Oct-2019"