Commit c175a518b4a1d514483abf61813ce5d855917164
Committed by
Mark Fasheh
1 parent
87d35a74b1
Exists in
master
and in
7 other branches
ocfs2: Checksum and ECC for directory blocks.
Use the db_check field of ocfs2_dir_block_trailer to crc/ecc the dirblocks. Signed-off-by: Joel Becker <joel.becker@oracle.com> Signed-off-by: Mark Fasheh <mfasheh@suse.com>
Showing 4 changed files with 67 additions and 5 deletions Side-by-side Diff
fs/ocfs2/dir.c
... | ... | @@ -48,6 +48,7 @@ |
48 | 48 | #include "ocfs2.h" |
49 | 49 | |
50 | 50 | #include "alloc.h" |
51 | +#include "blockcheck.h" | |
51 | 52 | #include "dir.h" |
52 | 53 | #include "dlmglue.h" |
53 | 54 | #include "extent_map.h" |
... | ... | @@ -107,6 +108,17 @@ |
107 | 108 | |
108 | 109 | #define ocfs2_trailer_from_bh(_bh, _sb) ((struct ocfs2_dir_block_trailer *) ((_bh)->b_data + ocfs2_dir_trailer_blk_off((_sb)))) |
109 | 110 | |
111 | +/* XXX ocfs2_block_dqtrailer() is similar but not quite - can we make | |
112 | + * them more consistent? */ | |
113 | +struct ocfs2_dir_block_trailer *ocfs2_dir_trailer_from_size(int blocksize, | |
114 | + void *data) | |
115 | +{ | |
116 | + char *p = data; | |
117 | + | |
118 | + p += blocksize - sizeof(struct ocfs2_dir_block_trailer); | |
119 | + return (struct ocfs2_dir_block_trailer *)p; | |
120 | +} | |
121 | + | |
110 | 122 | /* |
111 | 123 | * XXX: This is executed once on every dirent. We should consider optimizing |
112 | 124 | * it. |
113 | 125 | |
114 | 126 | |
... | ... | @@ -268,14 +280,35 @@ |
268 | 280 | static int ocfs2_validate_dir_block(struct super_block *sb, |
269 | 281 | struct buffer_head *bh) |
270 | 282 | { |
283 | + int rc; | |
284 | + struct ocfs2_dir_block_trailer *trailer = | |
285 | + ocfs2_trailer_from_bh(bh, sb); | |
286 | + | |
287 | + | |
271 | 288 | /* |
272 | - * Nothing yet. We don't validate dirents here, that's handled | |
289 | + * We don't validate dirents here, that's handled | |
273 | 290 | * in-place when the code walks them. |
274 | 291 | */ |
275 | 292 | mlog(0, "Validating dirblock %llu\n", |
276 | 293 | (unsigned long long)bh->b_blocknr); |
277 | 294 | |
278 | - return 0; | |
295 | + BUG_ON(!buffer_uptodate(bh)); | |
296 | + | |
297 | + /* | |
298 | + * If the ecc fails, we return the error but otherwise | |
299 | + * leave the filesystem running. We know any error is | |
300 | + * local to this block. | |
301 | + * | |
302 | + * Note that we are safe to call this even if the directory | |
303 | + * doesn't have a trailer. Filesystems without metaecc will do | |
304 | + * nothing, and filesystems with it will have one. | |
305 | + */ | |
306 | + rc = ocfs2_validate_meta_ecc(sb, bh->b_data, &trailer->db_check); | |
307 | + if (rc) | |
308 | + mlog(ML_ERROR, "Checksum failed for dinode %llu\n", | |
309 | + (unsigned long long)bh->b_blocknr); | |
310 | + | |
311 | + return rc; | |
279 | 312 | } |
280 | 313 | |
281 | 314 | /* |
fs/ocfs2/dir.h
fs/ocfs2/journal.c
... | ... | @@ -415,6 +415,26 @@ |
415 | 415 | ocfs2_block_check_compute(data, size, &dqt->dq_check); |
416 | 416 | } |
417 | 417 | |
418 | +/* | |
419 | + * Directory blocks also have their own trigger because the | |
420 | + * struct ocfs2_block_check offset depends on the blocksize. | |
421 | + */ | |
422 | +static void ocfs2_db_commit_trigger(struct jbd2_buffer_trigger_type *triggers, | |
423 | + struct buffer_head *bh, | |
424 | + void *data, size_t size) | |
425 | +{ | |
426 | + struct ocfs2_dir_block_trailer *trailer = | |
427 | + ocfs2_dir_trailer_from_size(size, data); | |
428 | + | |
429 | + /* | |
430 | + * We aren't guaranteed to have the superblock here, so we | |
431 | + * must unconditionally compute the ecc data. | |
432 | + * __ocfs2_journal_access() will only set the triggers if | |
433 | + * metaecc is enabled. | |
434 | + */ | |
435 | + ocfs2_block_check_compute(data, size, &trailer->db_check); | |
436 | +} | |
437 | + | |
418 | 438 | static void ocfs2_abort_trigger(struct jbd2_buffer_trigger_type *triggers, |
419 | 439 | struct buffer_head *bh) |
420 | 440 | { |
... | ... | @@ -454,6 +474,13 @@ |
454 | 474 | .ot_offset = offsetof(struct ocfs2_group_desc, bg_check), |
455 | 475 | }; |
456 | 476 | |
477 | +static struct ocfs2_triggers db_triggers = { | |
478 | + .ot_triggers = { | |
479 | + .t_commit = ocfs2_db_commit_trigger, | |
480 | + .t_abort = ocfs2_abort_trigger, | |
481 | + }, | |
482 | +}; | |
483 | + | |
457 | 484 | static struct ocfs2_triggers xb_triggers = { |
458 | 485 | .ot_triggers = { |
459 | 486 | .t_commit = ocfs2_commit_trigger, |
... | ... | @@ -555,8 +582,8 @@ |
555 | 582 | int ocfs2_journal_access_db(handle_t *handle, struct inode *inode, |
556 | 583 | struct buffer_head *bh, int type) |
557 | 584 | { |
558 | - /* Right now, nothing for dirblocks */ | |
559 | - return __ocfs2_journal_access(handle, inode, bh, NULL, type); | |
585 | + return __ocfs2_journal_access(handle, inode, bh, &db_triggers, | |
586 | + type); | |
560 | 587 | } |
561 | 588 | |
562 | 589 | int ocfs2_journal_access_xb(handle_t *handle, struct inode *inode, |
fs/ocfs2/ocfs2_fs.h
... | ... | @@ -776,7 +776,7 @@ |
776 | 776 | /*20*/ __le64 db_blkno; /* Offset on disk, in blocks */ |
777 | 777 | __le64 db_parent_dinode; /* dinode which owns me, in |
778 | 778 | blocks */ |
779 | -/*30*/ __le64 db_check; /* Error checking */ | |
779 | +/*30*/ struct ocfs2_block_check db_check; /* Error checking */ | |
780 | 780 | /*40*/ |
781 | 781 | }; |
782 | 782 |