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

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

jbd2: checksum descriptor blocks



Calculate and verify a checksum of each descriptor block.

Signed-off-by: default avatarDarrick J. Wong <djwong@us.ibm.com>
Signed-off-by: default avatar"Theodore Ts'o" <tytso@mit.edu>
parent 42a7106d
Loading
Loading
Loading
Loading
+24 −1
Original line number Diff line number Diff line
@@ -301,6 +301,24 @@ static void write_tag_block(int tag_bytes, journal_block_tag_t *tag,
		tag->t_blocknr_high = cpu_to_be32((block >> 31) >> 1);
}

static void jbd2_descr_block_csum_set(journal_t *j,
				      struct journal_head *descriptor)
{
	struct jbd2_journal_block_tail *tail;
	__u32 csum;

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

	tail = (struct jbd2_journal_block_tail *)
			(jh2bh(descriptor)->b_data + j->j_blocksize -
			sizeof(struct jbd2_journal_block_tail));
	tail->t_checksum = 0;
	csum = jbd2_chksum(j, j->j_csum_seed, jh2bh(descriptor)->b_data,
			   j->j_blocksize);
	tail->t_checksum = cpu_to_be32(csum);
}

/*
 * jbd2_journal_commit_transaction
 *
@@ -334,6 +352,10 @@ void jbd2_journal_commit_transaction(journal_t *journal)
	unsigned long first_block;
	tid_t first_tid;
	int update_tail;
	int csum_size = 0;

	if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2))
		csum_size = sizeof(struct jbd2_journal_block_tail);

	/*
	 * First job: lock down the current transaction and wait for
@@ -643,7 +665,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)

		if (bufs == journal->j_wbufsize ||
		    commit_transaction->t_buffers == NULL ||
		    space_left < tag_bytes + 16) {
		    space_left < tag_bytes + 16 + csum_size) {

			jbd_debug(4, "JBD2: Submit %d IOs\n", bufs);

@@ -653,6 +675,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)

			tag->t_flags |= cpu_to_be16(JBD2_FLAG_LAST_TAG);

			jbd2_descr_block_csum_set(journal, descriptor);
start_journal_io:
			for (i = 0; i < bufs; i++) {
				struct buffer_head *bh = wbuf[i];
+36 −1
Original line number Diff line number Diff line
@@ -174,6 +174,25 @@ static int jread(struct buffer_head **bhp, journal_t *journal,
	return 0;
}

static int jbd2_descr_block_csum_verify(journal_t *j,
					void *buf)
{
	struct jbd2_journal_block_tail *tail;
	__u32 provided, calculated;

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

	tail = (struct jbd2_journal_block_tail *)(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;

	provided = be32_to_cpu(provided);
	return provided == calculated;
}

/*
 * Count the number of in-use tags in a journal descriptor block.
@@ -186,6 +205,9 @@ static int count_tags(journal_t *journal, struct buffer_head *bh)
	int			nr = 0, size = journal->j_blocksize;
	int			tag_bytes = journal_tag_bytes(journal);

	if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2))
		size -= sizeof(struct jbd2_journal_block_tail);

	tagp = &bh->b_data[sizeof(journal_header_t)];

	while ((tagp - bh->b_data + tag_bytes) <= size) {
@@ -366,6 +388,7 @@ static int do_one_pass(journal_t *journal,
	int			blocktype;
	int			tag_bytes = journal_tag_bytes(journal);
	__u32			crc32_sum = ~0; /* Transactional Checksums */
	int			descr_csum_size = 0;

	/*
	 * First thing is to establish what we expect to find in the log
@@ -451,6 +474,18 @@ static int do_one_pass(journal_t *journal,

		switch(blocktype) {
		case JBD2_DESCRIPTOR_BLOCK:
			/* Verify checksum first */
			if (JBD2_HAS_INCOMPAT_FEATURE(journal,
					JBD2_FEATURE_INCOMPAT_CSUM_V2))
				descr_csum_size =
					sizeof(struct jbd2_journal_block_tail);
			if (descr_csum_size > 0 &&
			    !jbd2_descr_block_csum_verify(journal,
							  bh->b_data)) {
				err = -EIO;
				goto failed;
			}

			/* If it is a valid descriptor block, replay it
			 * in pass REPLAY; if journal_checksums enabled, then
			 * calculate checksums in PASS_SCAN, otherwise,
@@ -481,7 +516,7 @@ static int do_one_pass(journal_t *journal,

			tagp = &bh->b_data[sizeof(journal_header_t)];
			while ((tagp - bh->b_data + tag_bytes)
			       <= journal->j_blocksize) {
			       <= journal->j_blocksize - descr_csum_size) {
				unsigned long io_block;

				tag = (journal_block_tag_t *) tagp;