#include <ext2fs/kernel-jbd.h>
+#define JSB_HAS_INCOMPAT_FEATURE(jsb, mask) \
+ ((jsb)->s_header.h_blocktype == ext2fs_cpu_to_be32(JFS_SUPERBLOCK_V2) && \
+ ((jsb)->s_feature_incompat & ext2fs_cpu_to_be32((mask))))
+static inline size_t journal_super_tag_bytes(journal_superblock_t *jsb)
+{
+ size_t sz;
+
+ if (JSB_HAS_INCOMPAT_FEATURE(jsb, JFS_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))
+ sz += sizeof(__u16);
+
+ if (JSB_HAS_INCOMPAT_FEATURE(jsb, JFS_FEATURE_INCOMPAT_64BIT))
+ return sz;
+
+ return sz - sizeof(__u32);
+}
+
#endif /* _JFS_USER_H */
unsigned int *blockp, int blocksize,
tid_t transaction)
{
- int offset, tag_size = JBD_TAG_SIZE32;
+ int offset, tag_size, csum_size = 0;
char *tagp;
journal_block_tag_t *tag;
unsigned int blocknr;
__u32 tag_block;
__u32 tag_flags;
- if (be32_to_cpu(jsb->s_feature_incompat) & JFS_FEATURE_INCOMPAT_64BIT)
- tag_size = JBD_TAG_SIZE64;
-
+ tag_size = journal_super_tag_bytes(jsb);
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 (dump_all)
fprintf(out_file, "Dumping descriptor block, sequence %u, at "
"block %u:\n", transaction, blocknr);
/* ... and if we have gone too far, then we've reached the
end of this block. */
- if (offset > blocksize)
+ if (offset > blocksize - csum_size)
break;
tag_block = be32_to_cpu(tag->t_blocknr);
static int e2fsck_journal_verify_csum_type(journal_t *j,
journal_superblock_t *jsb)
{
- if (!JFS_HAS_INCOMPAT_FEATURE(j, JFS_FEATURE_INCOMPAT_CSUM_V2))
+ if (!journal_has_csum_v2or3(j))
return 1;
return jsb->s_checksum_type == JBD2_CRC32C_CHKSUM;
{
__u32 provided, calculated;
- if (!JFS_HAS_INCOMPAT_FEATURE(j, JFS_FEATURE_INCOMPAT_CSUM_V2))
+ if (!journal_has_csum_v2or3(j))
return 1;
provided = ext2fs_be32_to_cpu(jsb->s_checksum);
{
__u32 crc;
- if (!JFS_HAS_INCOMPAT_FEATURE(j, JFS_FEATURE_INCOMPAT_CSUM_V2))
+ if (!journal_has_csum_v2or3(j))
return 0;
crc = e2fsck_journal_sb_csum(jsb);
if (JFS_HAS_RO_COMPAT_FEATURE(journal, ~JFS_KNOWN_ROCOMPAT_FEATURES))
return EXT2_ET_RO_UNSUPP_FEATURE;
- /* Checksum v1 and v2 are mutually exclusive features. */
+ /* Checksum v1-3 are mutually exclusive features. */
if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_CSUM_V2) &&
+ JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_CSUM_V3))
+ return EXT2_ET_CORRUPT_SUPERBLOCK;
+
+ if (journal_has_csum_v2or3(journal) &&
JFS_HAS_COMPAT_FEATURE(journal, JFS_FEATURE_COMPAT_CHECKSUM))
return EXT2_ET_CORRUPT_SUPERBLOCK;
!e2fsck_journal_sb_csum_verify(journal, jsb))
return EXT2_ET_CORRUPT_SUPERBLOCK;
- if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_CSUM_V2))
+ if (journal_has_csum_v2or3(journal))
journal->j_csum_seed = jbd2_chksum(journal, ~0, jsb->s_uuid,
sizeof(jsb->s_uuid));
__u32 provided;
__u32 calculated;
- if (!JFS_HAS_INCOMPAT_FEATURE(j, JFS_FEATURE_INCOMPAT_CSUM_V2))
+ if (!journal_has_csum_v2or3(j))
return 1;
tail = (struct journal_block_tail *)(buf + j->j_blocksize -
int nr = 0, size = journal->j_blocksize;
int tag_bytes = journal_tag_bytes(journal);
- if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_CSUM_V2))
+ if (journal_has_csum_v2or3(journal))
size -= sizeof(struct journal_block_tail);
tagp = &bh->b_data[sizeof(journal_header_t)];
return err;
}
-static inline unsigned long long read_tag_block(int tag_bytes, journal_block_tag_t *tag)
+static inline unsigned long long read_tag_block(journal_t *journal,
+ journal_block_tag_t *tag)
{
unsigned long long block = ext2fs_be32_to_cpu(tag->t_blocknr);
- if (tag_bytes > JFS_TAG_SIZE32)
+ if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_64BIT))
block |= (u64)ext2fs_be32_to_cpu(tag->t_blocknr_high) << 32;
return block;
}
__u32 provided;
__u32 calculated;
- if (!JFS_HAS_INCOMPAT_FEATURE(j, JFS_FEATURE_INCOMPAT_CSUM_V2))
+ if (!journal_has_csum_v2or3(j))
return 1;
h = buf;
static int jbd2_block_tag_csum_verify(journal_t *j, journal_block_tag_t *tag,
void *buf, __u32 sequence)
{
+ journal_block_tag3_t *tag3 = (journal_block_tag3_t *)tag;
__u32 csum32;
__u32 seq;
- if (!JFS_HAS_INCOMPAT_FEATURE(j, JFS_FEATURE_INCOMPAT_CSUM_V2))
+ if (!journal_has_csum_v2or3(j))
return 1;
seq = ext2fs_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_INCOMPAT_FEATURE(j, JFS_FEATURE_INCOMPAT_CSUM_V3))
+ return tag3->t_checksum == ext2fs_cpu_to_be32(csum32);
+
return tag->t_checksum == ext2fs_cpu_to_be16(csum32);
}
switch(blocktype) {
case JFS_DESCRIPTOR_BLOCK:
/* Verify checksum first */
- if (JFS_HAS_INCOMPAT_FEATURE(journal,
- JFS_FEATURE_INCOMPAT_CSUM_V2))
+ if (journal_has_csum_v2or3(journal))
descr_csum_size =
sizeof(struct journal_block_tail);
if (descr_csum_size > 0 &&
unsigned long long blocknr;
J_ASSERT(obh != NULL);
- blocknr = read_tag_block(tag_bytes,
+ blocknr = read_tag_block(journal,
tag);
/* If the block has been
__u32 provided;
__u32 calculated;
- if (!JFS_HAS_INCOMPAT_FEATURE(j, JFS_FEATURE_INCOMPAT_CSUM_V2))
+ if (!journal_has_csum_v2or3(j))
return 1;
tail = (struct journal_revoke_tail *)(buf + j->j_blocksize -
offset = *offsetp;
/* Do we need to leave space at the end for a checksum? */
- if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_CSUM_V2))
+ if (journal_has_csum_v2or3(journal))
csum_size = sizeof(struct journal_revoke_tail);
/* Make sure we have a descriptor with space left for the record */
struct journal_revoke_tail *tail;
__u32 csum;
- if (!JFS_HAS_INCOMPAT_FEATURE(j, JFS_FEATURE_INCOMPAT_CSUM_V2))
+ if (!journal_has_csum_v2or3(j))
return;
tail = (struct journal_revoke_tail *)(bh->b_data + j->j_blocksize -
"journal_async_commit" },
{ E2P_FEATURE_INCOMPAT, JFS_FEATURE_INCOMPAT_CSUM_V2,
"journal_checksum_v2" },
+ { E2P_FEATURE_INCOMPAT, JFS_FEATURE_INCOMPAT_CSUM_V3,
+ "journal_checksum_v3" },
{ 0, 0, 0 },
};
* journal_block_tag (in the descriptor). The other h_chksum* fields are
* not used.
*
- * Checksum v1 and v2 are mutually exclusive features.
+ * If FEATURE_INCOMPAT_CSUM_V3 is set, the descriptor block uses
+ * journal_block_tag3_t to store a full 32-bit checksum. Everything else
+ * is the same as v2.
+ *
+ * Checksum v1, v2, and v3 are mutually exclusive features.
*/
struct commit_header {
__u32 h_magic;
/*
* The block tag: used to describe a single buffer in the journal
*/
+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) */
+} journal_block_tag3_t;
+
typedef struct journal_block_tag_s
{
__u32 t_blocknr; /* The on-disk block number */
__u32 t_blocknr_high; /* most-significant high 32bits. */
} journal_block_tag_t;
-#define JBD_TAG_SIZE64 (sizeof(journal_block_tag_t))
-#define JBD_TAG_SIZE32 (8)
-
/* Tail of descriptor block, for checksumming */
struct journal_block_tail {
__u32 t_checksum;
#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
/* Features known to this kernel version: */
#define JFS_KNOWN_COMPAT_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_V2|\
+ JFS_FEATURE_INCOMPAT_CSUM_V3)
#if (defined(E2FSCK_INCLUDE_INLINE_FUNCS) || !defined(NO_INLINE_FUNCS))
#ifdef E2FSCK_INCLUDE_INLINE_FUNCS
*/
_INLINE_ size_t journal_tag_bytes(journal_t *journal)
{
- journal_block_tag_t tag;
- size_t x = 0;
+ size_t sz;
+
+ if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_CSUM_V3))
+ return sizeof(journal_block_tag3_t);
+
+ sz = sizeof(journal_block_tag_t);
if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_CSUM_V2))
- x += sizeof(tag.t_checksum);
+ sz += sizeof(__u16);
if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_64BIT))
- return x + JBD_TAG_SIZE64;
- else
- return x + JBD_TAG_SIZE32;
+ return sz;
+
+ return sz - sizeof(__u32);
+}
+
+_INLINE_ int journal_has_csum_v2or3(journal_t *journal)
+{
+ if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_CSUM_V2) ||
+ JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_CSUM_V3))
+ return 1;
+
+ return 0;
}
#undef _INLINE_
#endif
if (jsb->s_feature_compat &
ext2fs_cpu_to_be32(JFS_FEATURE_COMPAT_CHECKSUM))
printf("%s", _("Journal checksum type: crc32\n"));
- if (jsb->s_feature_incompat &
- ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_CSUM_V2))
+ if ((jsb->s_feature_incompat &
+ ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_CSUM_V3)) ||
+ (jsb->s_feature_incompat &
+ ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_CSUM_V2)))
printf(_("Journal checksum type: %s\n"
"Journal checksum: 0x%08x\n"),
journal_checksum_type_str(jsb->s_checksum_type),
if (jsb->s_feature_compat &
ext2fs_cpu_to_be32(JFS_FEATURE_COMPAT_CHECKSUM))
printf("%s", _("Journal checksum type: crc32\n"));
- if (jsb->s_feature_incompat &
- ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_CSUM_V2))
+ if ((jsb->s_feature_incompat &
+ ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_CSUM_V3)) ||
+ (jsb->s_feature_incompat &
+ ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_CSUM_V2)))
printf(_("Journal checksum type: %s\n"
"Journal checksum: 0x%08x\n"),
journal_checksum_type_str(jsb->s_checksum_type),