Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c3900875 authored by Darrick J. Wong's avatar Darrick J. Wong Committed by Theodore Ts'o
Browse files

jbd2: checksum data blocks that are stored in the journal



Calculate and verify checksums of each data block being stored in the journal.

Signed-off-by: default avatarDarrick J. Wong <djwong@us.ibm.com>
Signed-off-by: default avatar"Theodore Ts'o" <tytso@mit.edu>
parent 1f56c589
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -338,6 +338,26 @@ static void jbd2_descr_block_csum_set(journal_t *j,
	tail->t_checksum = cpu_to_be32(csum);
}

static void jbd2_block_tag_csum_set(journal_t *j, journal_block_tag_t *tag,
				    struct buffer_head *bh, __u32 sequence)
{
	struct page *page = bh->b_page;
	__u8 *addr;
	__u32 csum;

	if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2))
		return;

	sequence = cpu_to_be32(sequence);
	addr = kmap_atomic(page, KM_USER0);
	csum = jbd2_chksum(j, j->j_csum_seed, (__u8 *)&sequence,
			  sizeof(sequence));
	csum = jbd2_chksum(j, csum, addr + offset_in_page(bh->b_data),
			  bh->b_size);
	kunmap_atomic(addr, KM_USER0);

	tag->t_checksum = cpu_to_be32(csum);
}
/*
 * jbd2_journal_commit_transaction
 *
@@ -669,6 +689,8 @@ void jbd2_journal_commit_transaction(journal_t *journal)
		tag = (journal_block_tag_t *) tagp;
		write_tag_block(tag_bytes, tag, jh2bh(jh)->b_blocknr);
		tag->t_flags = cpu_to_be16(tag_flag);
		jbd2_block_tag_csum_set(journal, tag, jh2bh(new_jh),
					commit_transaction->t_tid);
		tagp += tag_bytes;
		space_left -= tag_bytes;

+8 −2
Original line number Diff line number Diff line
@@ -2097,10 +2097,16 @@ int jbd2_journal_blocks_per_page(struct inode *inode)
 */
size_t journal_tag_bytes(journal_t *journal)
{
	journal_block_tag_t tag;
	size_t x = 0;

	if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2))
		x += sizeof(tag.t_checksum);

	if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT))
		return JBD2_TAG_SIZE64;
		return x + JBD2_TAG_SIZE64;
	else
		return JBD2_TAG_SIZE32;
		return x + JBD2_TAG_SIZE32;
}

/*
+30 −0
Original line number Diff line number Diff line
@@ -393,6 +393,23 @@ static int jbd2_commit_block_csum_verify(journal_t *j, void *buf)
	return provided == calculated;
}

static int jbd2_block_tag_csum_verify(journal_t *j, journal_block_tag_t *tag,
				      void *buf, __u32 sequence)
{
	__u32 provided, calculated;

	if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2))
		return 1;

	sequence = cpu_to_be32(sequence);
	calculated = jbd2_chksum(j, j->j_csum_seed, (__u8 *)&sequence,
				 sizeof(sequence));
	calculated = jbd2_chksum(j, calculated, buf, j->j_blocksize);
	provided = be32_to_cpu(tag->t_checksum);

	return provided == cpu_to_be32(calculated);
}

static int do_one_pass(journal_t *journal,
			struct recovery_info *info, enum passtype pass)
{
@@ -569,6 +586,19 @@ static int do_one_pass(journal_t *journal,
						goto skip_write;
					}

					/* Look for block corruption */
					if (!jbd2_block_tag_csum_verify(
						journal, tag, obh->b_data,
						be32_to_cpu(tmp->h_sequence))) {
						brelse(obh);
						success = -EIO;
						printk(KERN_ERR "JBD: Invalid "
						       "checksum recovering "
						       "block %llu in log\n",
						       blocknr);
						continue;
					}

					/* Find a buffer for the new
					 * data being restored */
					nbh = __getblk(journal->j_fs_dev,