diff options
author | Joel Becker <joel.becker@oracle.com> | 2008-12-10 20:58:22 -0500 |
---|---|---|
committer | Mark Fasheh <mfasheh@suse.com> | 2009-01-05 11:40:34 -0500 |
commit | c175a518b4a1d514483abf61813ce5d855917164 (patch) | |
tree | e437a3d1377fab38c1d8ef6289fd9ea3590d09b2 /fs | |
parent | 87d35a74b15ec703910a63e0667692fb5e267be0 (diff) |
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>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ocfs2/dir.c | 37 | ||||
-rw-r--r-- | fs/ocfs2/dir.h | 2 | ||||
-rw-r--r-- | fs/ocfs2/journal.c | 31 | ||||
-rw-r--r-- | fs/ocfs2/ocfs2_fs.h | 2 |
4 files changed, 67 insertions, 5 deletions
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index 1efd0ab680cf..f2c4098cf337 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c | |||
@@ -48,6 +48,7 @@ | |||
48 | #include "ocfs2.h" | 48 | #include "ocfs2.h" |
49 | 49 | ||
50 | #include "alloc.h" | 50 | #include "alloc.h" |
51 | #include "blockcheck.h" | ||
51 | #include "dir.h" | 52 | #include "dir.h" |
52 | #include "dlmglue.h" | 53 | #include "dlmglue.h" |
53 | #include "extent_map.h" | 54 | #include "extent_map.h" |
@@ -107,6 +108,17 @@ static inline unsigned int ocfs2_dir_trailer_blk_off(struct super_block *sb) | |||
107 | 108 | ||
108 | #define ocfs2_trailer_from_bh(_bh, _sb) ((struct ocfs2_dir_block_trailer *) ((_bh)->b_data + ocfs2_dir_trailer_blk_off((_sb)))) | 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 | * XXX: This is executed once on every dirent. We should consider optimizing | 123 | * XXX: This is executed once on every dirent. We should consider optimizing |
112 | * it. | 124 | * it. |
@@ -268,14 +280,35 @@ out: | |||
268 | static int ocfs2_validate_dir_block(struct super_block *sb, | 280 | static int ocfs2_validate_dir_block(struct super_block *sb, |
269 | struct buffer_head *bh) | 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 | * in-place when the code walks them. | 290 | * in-place when the code walks them. |
274 | */ | 291 | */ |
275 | mlog(0, "Validating dirblock %llu\n", | 292 | mlog(0, "Validating dirblock %llu\n", |
276 | (unsigned long long)bh->b_blocknr); | 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 | /* |
diff --git a/fs/ocfs2/dir.h b/fs/ocfs2/dir.h index ce48b9080d87..c511e2e18e9f 100644 --- a/fs/ocfs2/dir.h +++ b/fs/ocfs2/dir.h | |||
@@ -83,4 +83,6 @@ int ocfs2_fill_new_dir(struct ocfs2_super *osb, | |||
83 | struct buffer_head *fe_bh, | 83 | struct buffer_head *fe_bh, |
84 | struct ocfs2_alloc_context *data_ac); | 84 | struct ocfs2_alloc_context *data_ac); |
85 | 85 | ||
86 | struct ocfs2_dir_block_trailer *ocfs2_dir_trailer_from_size(int blocksize, | ||
87 | void *data); | ||
86 | #endif /* OCFS2_DIR_H */ | 88 | #endif /* OCFS2_DIR_H */ |
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c index 3b54dba0f74b..57d7d25a2b9a 100644 --- a/fs/ocfs2/journal.c +++ b/fs/ocfs2/journal.c | |||
@@ -415,6 +415,26 @@ static void ocfs2_dq_commit_trigger(struct jbd2_buffer_trigger_type *triggers, | |||
415 | ocfs2_block_check_compute(data, size, &dqt->dq_check); | 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 | static void ocfs2_abort_trigger(struct jbd2_buffer_trigger_type *triggers, | 438 | static void ocfs2_abort_trigger(struct jbd2_buffer_trigger_type *triggers, |
419 | struct buffer_head *bh) | 439 | struct buffer_head *bh) |
420 | { | 440 | { |
@@ -454,6 +474,13 @@ static struct ocfs2_triggers gd_triggers = { | |||
454 | .ot_offset = offsetof(struct ocfs2_group_desc, bg_check), | 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 | static struct ocfs2_triggers xb_triggers = { | 484 | static struct ocfs2_triggers xb_triggers = { |
458 | .ot_triggers = { | 485 | .ot_triggers = { |
459 | .t_commit = ocfs2_commit_trigger, | 486 | .t_commit = ocfs2_commit_trigger, |
@@ -555,8 +582,8 @@ int ocfs2_journal_access_gd(handle_t *handle, struct inode *inode, | |||
555 | int ocfs2_journal_access_db(handle_t *handle, struct inode *inode, | 582 | int ocfs2_journal_access_db(handle_t *handle, struct inode *inode, |
556 | struct buffer_head *bh, int type) | 583 | struct buffer_head *bh, int type) |
557 | { | 584 | { |
558 | /* Right now, nothing for dirblocks */ | 585 | return __ocfs2_journal_access(handle, inode, bh, &db_triggers, |
559 | return __ocfs2_journal_access(handle, inode, bh, NULL, type); | 586 | type); |
560 | } | 587 | } |
561 | 588 | ||
562 | int ocfs2_journal_access_xb(handle_t *handle, struct inode *inode, | 589 | int ocfs2_journal_access_xb(handle_t *handle, struct inode *inode, |
diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h index af0013b9c17f..698ef3d27121 100644 --- a/fs/ocfs2/ocfs2_fs.h +++ b/fs/ocfs2/ocfs2_fs.h | |||
@@ -776,7 +776,7 @@ struct ocfs2_dir_block_trailer { | |||
776 | /*20*/ __le64 db_blkno; /* Offset on disk, in blocks */ | 776 | /*20*/ __le64 db_blkno; /* Offset on disk, in blocks */ |
777 | __le64 db_parent_dinode; /* dinode which owns me, in | 777 | __le64 db_parent_dinode; /* dinode which owns me, in |
778 | blocks */ | 778 | blocks */ |
779 | /*30*/ __le64 db_check; /* Error checking */ | 779 | /*30*/ struct ocfs2_block_check db_check; /* Error checking */ |
780 | /*40*/ | 780 | /*40*/ |
781 | }; | 781 | }; |
782 | 782 | ||