aboutsummaryrefslogtreecommitdiffstats
path: root/fs/jbd2
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@us.ibm.com>2012-05-27 08:10:22 -0400
committerTheodore Ts'o <tytso@mit.edu>2012-05-27 08:10:22 -0400
commit3caa487f53f65fd1e3950a6b6ae1709e6c43b334 (patch)
tree02ee3f18422d9ffed974eb1019e98b2ee1ade01c /fs/jbd2
parent42a7106de636ebf9c0b93d25b4230e14f5f2682e (diff)
jbd2: checksum descriptor blocks
Calculate and verify a checksum of each descriptor block. Signed-off-by: Darrick J. Wong <djwong@us.ibm.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/jbd2')
-rw-r--r--fs/jbd2/commit.c25
-rw-r--r--fs/jbd2/recovery.c37
2 files changed, 60 insertions, 2 deletions
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
index 69d780310aea..5d505cfd21c2 100644
--- a/fs/jbd2/commit.c
+++ b/fs/jbd2/commit.c
@@ -301,6 +301,24 @@ static void write_tag_block(int tag_bytes, journal_block_tag_t *tag,
301 tag->t_blocknr_high = cpu_to_be32((block >> 31) >> 1); 301 tag->t_blocknr_high = cpu_to_be32((block >> 31) >> 1);
302} 302}
303 303
304static void jbd2_descr_block_csum_set(journal_t *j,
305 struct journal_head *descriptor)
306{
307 struct jbd2_journal_block_tail *tail;
308 __u32 csum;
309
310 if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2))
311 return;
312
313 tail = (struct jbd2_journal_block_tail *)
314 (jh2bh(descriptor)->b_data + j->j_blocksize -
315 sizeof(struct jbd2_journal_block_tail));
316 tail->t_checksum = 0;
317 csum = jbd2_chksum(j, j->j_csum_seed, jh2bh(descriptor)->b_data,
318 j->j_blocksize);
319 tail->t_checksum = cpu_to_be32(csum);
320}
321
304/* 322/*
305 * jbd2_journal_commit_transaction 323 * jbd2_journal_commit_transaction
306 * 324 *
@@ -334,6 +352,10 @@ void jbd2_journal_commit_transaction(journal_t *journal)
334 unsigned long first_block; 352 unsigned long first_block;
335 tid_t first_tid; 353 tid_t first_tid;
336 int update_tail; 354 int update_tail;
355 int csum_size = 0;
356
357 if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2))
358 csum_size = sizeof(struct jbd2_journal_block_tail);
337 359
338 /* 360 /*
339 * First job: lock down the current transaction and wait for 361 * First job: lock down the current transaction and wait for
@@ -643,7 +665,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)
643 665
644 if (bufs == journal->j_wbufsize || 666 if (bufs == journal->j_wbufsize ||
645 commit_transaction->t_buffers == NULL || 667 commit_transaction->t_buffers == NULL ||
646 space_left < tag_bytes + 16) { 668 space_left < tag_bytes + 16 + csum_size) {
647 669
648 jbd_debug(4, "JBD2: Submit %d IOs\n", bufs); 670 jbd_debug(4, "JBD2: Submit %d IOs\n", bufs);
649 671
@@ -653,6 +675,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)
653 675
654 tag->t_flags |= cpu_to_be16(JBD2_FLAG_LAST_TAG); 676 tag->t_flags |= cpu_to_be16(JBD2_FLAG_LAST_TAG);
655 677
678 jbd2_descr_block_csum_set(journal, descriptor);
656start_journal_io: 679start_journal_io:
657 for (i = 0; i < bufs; i++) { 680 for (i = 0; i < bufs; i++) {
658 struct buffer_head *bh = wbuf[i]; 681 struct buffer_head *bh = wbuf[i];
diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c
index 728ecd0705d9..066ee603db50 100644
--- a/fs/jbd2/recovery.c
+++ b/fs/jbd2/recovery.c
@@ -174,6 +174,25 @@ static int jread(struct buffer_head **bhp, journal_t *journal,
174 return 0; 174 return 0;
175} 175}
176 176
177static int jbd2_descr_block_csum_verify(journal_t *j,
178 void *buf)
179{
180 struct jbd2_journal_block_tail *tail;
181 __u32 provided, calculated;
182
183 if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2))
184 return 1;
185
186 tail = (struct jbd2_journal_block_tail *)(buf + j->j_blocksize -
187 sizeof(struct jbd2_journal_block_tail));
188 provided = tail->t_checksum;
189 tail->t_checksum = 0;
190 calculated = jbd2_chksum(j, j->j_csum_seed, buf, j->j_blocksize);
191 tail->t_checksum = provided;
192
193 provided = be32_to_cpu(provided);
194 return provided == calculated;
195}
177 196
178/* 197/*
179 * Count the number of in-use tags in a journal descriptor block. 198 * 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)
186 int nr = 0, size = journal->j_blocksize; 205 int nr = 0, size = journal->j_blocksize;
187 int tag_bytes = journal_tag_bytes(journal); 206 int tag_bytes = journal_tag_bytes(journal);
188 207
208 if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2))
209 size -= sizeof(struct jbd2_journal_block_tail);
210
189 tagp = &bh->b_data[sizeof(journal_header_t)]; 211 tagp = &bh->b_data[sizeof(journal_header_t)];
190 212
191 while ((tagp - bh->b_data + tag_bytes) <= size) { 213 while ((tagp - bh->b_data + tag_bytes) <= size) {
@@ -366,6 +388,7 @@ static int do_one_pass(journal_t *journal,
366 int blocktype; 388 int blocktype;
367 int tag_bytes = journal_tag_bytes(journal); 389 int tag_bytes = journal_tag_bytes(journal);
368 __u32 crc32_sum = ~0; /* Transactional Checksums */ 390 __u32 crc32_sum = ~0; /* Transactional Checksums */
391 int descr_csum_size = 0;
369 392
370 /* 393 /*
371 * First thing is to establish what we expect to find in the log 394 * 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,
451 474
452 switch(blocktype) { 475 switch(blocktype) {
453 case JBD2_DESCRIPTOR_BLOCK: 476 case JBD2_DESCRIPTOR_BLOCK:
477 /* Verify checksum first */
478 if (JBD2_HAS_INCOMPAT_FEATURE(journal,
479 JBD2_FEATURE_INCOMPAT_CSUM_V2))
480 descr_csum_size =
481 sizeof(struct jbd2_journal_block_tail);
482 if (descr_csum_size > 0 &&
483 !jbd2_descr_block_csum_verify(journal,
484 bh->b_data)) {
485 err = -EIO;
486 goto failed;
487 }
488
454 /* If it is a valid descriptor block, replay it 489 /* If it is a valid descriptor block, replay it
455 * in pass REPLAY; if journal_checksums enabled, then 490 * in pass REPLAY; if journal_checksums enabled, then
456 * calculate checksums in PASS_SCAN, otherwise, 491 * calculate checksums in PASS_SCAN, otherwise,
@@ -481,7 +516,7 @@ static int do_one_pass(journal_t *journal,
481 516
482 tagp = &bh->b_data[sizeof(journal_header_t)]; 517 tagp = &bh->b_data[sizeof(journal_header_t)];
483 while ((tagp - bh->b_data + tag_bytes) 518 while ((tagp - bh->b_data + tag_bytes)
484 <= journal->j_blocksize) { 519 <= journal->j_blocksize - descr_csum_size) {
485 unsigned long io_block; 520 unsigned long io_block;
486 521
487 tag = (journal_block_tag_t *) tagp; 522 tag = (journal_block_tag_t *) tagp;