#endif /* __KERNEL__ */
+static inline __u32 get_be32(__be32 *p)
+{
+ unsigned char *cp = (unsigned char *) p;
+ __u32 ret;
+
+ ret = *cp++;
+ ret = (ret << 8) + *cp++;
+ ret = (ret << 8) + *cp++;
+ ret = (ret << 8) + *cp++;
+ return ret;
+}
+
+static inline __u16 get_be16(__be16 *p)
+{
+ unsigned char *cp = (unsigned char *) p;
+ __u16 ret;
+
+ ret = *cp++;
+ ret = (ret << 8) + *cp++;
+ return ret;
+}
/*
* Read a block from the journal
if (offset >= journal->j_maxlen) {
printk(KERN_ERR "JBD2: corrupted journal superblock\n");
- return -EIO;
+ return -EFSCORRUPTED;
}
err = journal_bmap(journal, offset, &blocknr);
__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 -
+ tail = (struct journal_block_tail *)((char *)buf + j->j_blocksize -
sizeof(struct journal_block_tail));
provided = tail->t_checksum;
tail->t_checksum = 0;
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)];
nr++;
tagp += tag_bytes;
- if (!(tag->t_flags & ext2fs_cpu_to_be16(JFS_FLAG_SAME_UUID)))
+ if (!(get_be16(&tag->t_flags) & JFS_FLAG_SAME_UUID))
tagp += 16;
- if (tag->t_flags & ext2fs_cpu_to_be16(JFS_FLAG_LAST_TAG))
+ if (get_be16(&tag->t_flags) & JFS_FLAG_LAST_TAG)
break;
}
* Locate any valid recovery information from the journal and set up the
* journal structures in memory to ignore it (presumably because the
* caller has evidence that it is out of date).
- * This function does'nt appear to be exorted..
+ * This function doesn't appear to be exported..
*
* We perform one pass over the journal to allow us to tell the user how
* much recovery information is being erased, and to let us initialise
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)
- block |= (u64)ext2fs_be32_to_cpu(tag->t_blocknr_high) << 32;
+ unsigned long long block = get_be32(&tag->t_blocknr);
+ if (jfs_has_feature_64bit(journal))
+ block |= (u64)get_be32(&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);
- return tag->t_checksum == ext2fs_cpu_to_be16(csum32);
+ if (jfs_has_feature_csum3(j))
+ return get_be32(&tag3->t_checksum) == csum32;
+
+ return get_be16(&tag->t_checksum) == (csum32 & 0xFFFF);
}
static int do_one_pass(journal_t *journal,
int tag_bytes = journal_tag_bytes(journal);
__u32 crc32_sum = ~0; /* Transactional Checksums */
int descr_csum_size = 0;
+ int block_error = 0;
/*
* First thing is to establish what we expect to find in the log
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 &&
!jbd2_descr_block_csum_verify(journal,
bh->b_data)) {
- err = -EIO;
+ err = -EFSBADCRC;
+ brelse(bh);
goto failed;
}
* just skip over the blocks it describes. */
if (pass != PASS_REPLAY) {
if (pass == PASS_SCAN &&
- JFS_HAS_COMPAT_FEATURE(journal,
- JFS_FEATURE_COMPAT_CHECKSUM) &&
+ jfs_has_feature_checksum(journal) &&
!info->end_transaction) {
if (calc_chksums(journal, bh,
&next_log_block,
unsigned long io_block;
tag = (journal_block_tag_t *) tagp;
- flags = ext2fs_be16_to_cpu(tag->t_flags);
+ flags = get_be16(&tag->t_flags);
io_block = next_log_block++;
wrap(journal, next_log_block);
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
journal, tag, obh->b_data,
ext2fs_be32_to_cpu(tmp->h_sequence))) {
brelse(obh);
- success = -EIO;
+ success = -EFSBADCRC;
printk(KERN_ERR "JBD2: Invalid "
"checksum recovering "
"block %llu in log\n",
blocknr);
- continue;
+ block_error = 1;
+ goto skip_write;
}
/* Find a buffer for the new
memcpy(nbh->b_data, obh->b_data,
journal->j_blocksize);
if (flags & JFS_FLAG_ESCAPE) {
- *((__u32 *)nbh->b_data) =
- ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER);
+ __u32 magic = ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER);
+ memcpy(nbh->b_data, &magic,
+ sizeof(magic));
}
BUFFER_TRACE(nbh, "marking dirty");
* | GO TO NEXT "Journal Corruption"
* | TRANSACTION
* |
- * {(n+1)th transanction}
+ * {(n+1)th transaction}
* |
* _______|______________
* | |
* much to do other than move on to the next sequence
* number. */
if (pass == PASS_SCAN &&
- JFS_HAS_COMPAT_FEATURE(journal,
- JFS_FEATURE_COMPAT_CHECKSUM)) {
+ jfs_has_feature_checksum(journal)) {
int chksum_err, chksum_seen;
struct commit_header *cbh =
(struct commit_header *)bh->b_data;
if (chksum_err) {
info->end_transaction = next_commit_ID;
- if (!JFS_HAS_INCOMPAT_FEATURE(journal,
- JFS_FEATURE_INCOMPAT_ASYNC_COMMIT)){
+ if (!jfs_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_INCOMPAT_FEATURE(journal,
- JFS_FEATURE_INCOMPAT_ASYNC_COMMIT)) {
+ if (!jfs_has_feature_async_commit(journal)) {
journal->j_failed_commit =
next_commit_ID;
brelse(bh);
success = -EIO;
}
}
-
+ if (block_error && success == 0)
+ success = -EIO;
return success;
failed:
__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 -
+ tail = (struct journal_revoke_tail *)((char *)buf + j->j_blocksize -
sizeof(struct journal_revoke_tail));
provided = tail->r_checksum;
tail->r_checksum = 0;
{
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);
- max = ext2fs_be32_to_cpu(header->r_count);
+ rcount = ext2fs_be32_to_cpu(header->r_count);
if (!jbd2_revoke_block_csum_verify(journal, header))
+ return -EFSBADCRC;
+
+ if (journal_has_csum_v2or3(journal))
+ csum_size = sizeof(struct journal_revoke_tail);
+ if (rcount > journal->j_blocksize - csum_size)
return -EINVAL;
+ max = rcount;
- if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_64BIT))
+ if (jfs_has_feature_64bit(journal))
record_len = 8;
while (offset + record_len <= max) {