diff options
author | Joel Becker <joel.becker@oracle.com> | 2008-11-13 17:49:12 -0500 |
---|---|---|
committer | Mark Fasheh <mfasheh@suse.com> | 2009-01-05 11:36:52 -0500 |
commit | 10995aa2451afa20b721cc7de856cae1a13dba57 (patch) | |
tree | 63129e7d752fb018dc76aa42de136baa4a8a4232 | |
parent | b657c95c11088d77fc1bfc9c84d940f778bf9d12 (diff) |
ocfs2: Morph the haphazard OCFS2_IS_VALID_DINODE() checks.
Random places in the code would check a dinode bh to see if it was
valid. Not only did they do different levels of validation, they
handled errors in different ways.
The previous commit unified inode block reads, validating all block
reads in the same place. Thus, these haphazard checks are no longer
necessary. Rather than eliminate them, however, we change them to
BUG_ON() checks. This ensures the assumptions remain true. All of the
code paths to these checks have been audited to ensure they come from a
validated inode read.
Signed-off-by: Joel Becker <joel.becker@oracle.com>
Signed-off-by: Mark Fasheh <mfasheh@suse.com>
-rw-r--r-- | fs/ocfs2/alloc.c | 50 | ||||
-rw-r--r-- | fs/ocfs2/journal.c | 17 | ||||
-rw-r--r-- | fs/ocfs2/ocfs2.h | 8 | ||||
-rw-r--r-- | fs/ocfs2/resize.c | 10 | ||||
-rw-r--r-- | fs/ocfs2/suballoc.c | 36 |
5 files changed, 46 insertions, 75 deletions
diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index 9c598adc9475..320545b9fe12 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c | |||
@@ -187,20 +187,12 @@ static int ocfs2_dinode_insert_check(struct inode *inode, | |||
187 | static int ocfs2_dinode_sanity_check(struct inode *inode, | 187 | static int ocfs2_dinode_sanity_check(struct inode *inode, |
188 | struct ocfs2_extent_tree *et) | 188 | struct ocfs2_extent_tree *et) |
189 | { | 189 | { |
190 | int ret = 0; | 190 | struct ocfs2_dinode *di = et->et_object; |
191 | struct ocfs2_dinode *di; | ||
192 | 191 | ||
193 | BUG_ON(et->et_ops != &ocfs2_dinode_et_ops); | 192 | BUG_ON(et->et_ops != &ocfs2_dinode_et_ops); |
193 | BUG_ON(!OCFS2_IS_VALID_DINODE(di)); | ||
194 | 194 | ||
195 | di = et->et_object; | 195 | return 0; |
196 | if (!OCFS2_IS_VALID_DINODE(di)) { | ||
197 | ret = -EIO; | ||
198 | ocfs2_error(inode->i_sb, | ||
199 | "Inode %llu has invalid path root", | ||
200 | (unsigned long long)OCFS2_I(inode)->ip_blkno); | ||
201 | } | ||
202 | |||
203 | return ret; | ||
204 | } | 196 | } |
205 | 197 | ||
206 | static void ocfs2_dinode_fill_root_el(struct ocfs2_extent_tree *et) | 198 | static void ocfs2_dinode_fill_root_el(struct ocfs2_extent_tree *et) |
@@ -5380,13 +5372,13 @@ int ocfs2_truncate_log_append(struct ocfs2_super *osb, | |||
5380 | start_cluster = ocfs2_blocks_to_clusters(osb->sb, start_blk); | 5372 | start_cluster = ocfs2_blocks_to_clusters(osb->sb, start_blk); |
5381 | 5373 | ||
5382 | di = (struct ocfs2_dinode *) tl_bh->b_data; | 5374 | di = (struct ocfs2_dinode *) tl_bh->b_data; |
5383 | tl = &di->id2.i_dealloc; | ||
5384 | if (!OCFS2_IS_VALID_DINODE(di)) { | ||
5385 | OCFS2_RO_ON_INVALID_DINODE(osb->sb, di); | ||
5386 | status = -EIO; | ||
5387 | goto bail; | ||
5388 | } | ||
5389 | 5375 | ||
5376 | /* tl_bh is loaded from ocfs2_truncate_log_init(). It's validated | ||
5377 | * by the underlying call to ocfs2_read_inode_block(), so any | ||
5378 | * corruption is a code bug */ | ||
5379 | BUG_ON(!OCFS2_IS_VALID_DINODE(di)); | ||
5380 | |||
5381 | tl = &di->id2.i_dealloc; | ||
5390 | tl_count = le16_to_cpu(tl->tl_count); | 5382 | tl_count = le16_to_cpu(tl->tl_count); |
5391 | mlog_bug_on_msg(tl_count > ocfs2_truncate_recs_per_inode(osb->sb) || | 5383 | mlog_bug_on_msg(tl_count > ocfs2_truncate_recs_per_inode(osb->sb) || |
5392 | tl_count == 0, | 5384 | tl_count == 0, |
@@ -5536,13 +5528,13 @@ int __ocfs2_flush_truncate_log(struct ocfs2_super *osb) | |||
5536 | BUG_ON(mutex_trylock(&tl_inode->i_mutex)); | 5528 | BUG_ON(mutex_trylock(&tl_inode->i_mutex)); |
5537 | 5529 | ||
5538 | di = (struct ocfs2_dinode *) tl_bh->b_data; | 5530 | di = (struct ocfs2_dinode *) tl_bh->b_data; |
5539 | tl = &di->id2.i_dealloc; | ||
5540 | if (!OCFS2_IS_VALID_DINODE(di)) { | ||
5541 | OCFS2_RO_ON_INVALID_DINODE(osb->sb, di); | ||
5542 | status = -EIO; | ||
5543 | goto out; | ||
5544 | } | ||
5545 | 5531 | ||
5532 | /* tl_bh is loaded from ocfs2_truncate_log_init(). It's validated | ||
5533 | * by the underlying call to ocfs2_read_inode_block(), so any | ||
5534 | * corruption is a code bug */ | ||
5535 | BUG_ON(!OCFS2_IS_VALID_DINODE(di)); | ||
5536 | |||
5537 | tl = &di->id2.i_dealloc; | ||
5546 | num_to_flush = le16_to_cpu(tl->tl_used); | 5538 | num_to_flush = le16_to_cpu(tl->tl_used); |
5547 | mlog(0, "Flush %u records from truncate log #%llu\n", | 5539 | mlog(0, "Flush %u records from truncate log #%llu\n", |
5548 | num_to_flush, (unsigned long long)OCFS2_I(tl_inode)->ip_blkno); | 5540 | num_to_flush, (unsigned long long)OCFS2_I(tl_inode)->ip_blkno); |
@@ -5697,13 +5689,13 @@ int ocfs2_begin_truncate_log_recovery(struct ocfs2_super *osb, | |||
5697 | } | 5689 | } |
5698 | 5690 | ||
5699 | di = (struct ocfs2_dinode *) tl_bh->b_data; | 5691 | di = (struct ocfs2_dinode *) tl_bh->b_data; |
5700 | tl = &di->id2.i_dealloc; | ||
5701 | if (!OCFS2_IS_VALID_DINODE(di)) { | ||
5702 | OCFS2_RO_ON_INVALID_DINODE(tl_inode->i_sb, di); | ||
5703 | status = -EIO; | ||
5704 | goto bail; | ||
5705 | } | ||
5706 | 5692 | ||
5693 | /* tl_bh is loaded from ocfs2_get_truncate_log_info(). It's | ||
5694 | * validated by the underlying call to ocfs2_read_inode_block(), | ||
5695 | * so any corruption is a code bug */ | ||
5696 | BUG_ON(!OCFS2_IS_VALID_DINODE(di)); | ||
5697 | |||
5698 | tl = &di->id2.i_dealloc; | ||
5707 | if (le16_to_cpu(tl->tl_used)) { | 5699 | if (le16_to_cpu(tl->tl_used)) { |
5708 | mlog(0, "We'll have %u logs to recover\n", | 5700 | mlog(0, "We'll have %u logs to recover\n", |
5709 | le16_to_cpu(tl->tl_used)); | 5701 | le16_to_cpu(tl->tl_used)); |
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c index 877aaa05e199..9223bfcca3ba 100644 --- a/fs/ocfs2/journal.c +++ b/fs/ocfs2/journal.c | |||
@@ -587,17 +587,11 @@ static int ocfs2_journal_toggle_dirty(struct ocfs2_super *osb, | |||
587 | mlog_entry_void(); | 587 | mlog_entry_void(); |
588 | 588 | ||
589 | fe = (struct ocfs2_dinode *)bh->b_data; | 589 | fe = (struct ocfs2_dinode *)bh->b_data; |
590 | if (!OCFS2_IS_VALID_DINODE(fe)) { | 590 | |
591 | /* This is called from startup/shutdown which will | 591 | /* The journal bh on the osb always comes from ocfs2_journal_init() |
592 | * handle the errors in a specific manner, so no need | 592 | * and was validated there inside ocfs2_inode_lock_full(). It's a |
593 | * to call ocfs2_error() here. */ | 593 | * code bug if we mess it up. */ |
594 | mlog(ML_ERROR, "Journal dinode %llu has invalid " | 594 | BUG_ON(!OCFS2_IS_VALID_DINODE(fe)); |
595 | "signature: %.*s", | ||
596 | (unsigned long long)le64_to_cpu(fe->i_blkno), 7, | ||
597 | fe->i_signature); | ||
598 | status = -EIO; | ||
599 | goto out; | ||
600 | } | ||
601 | 595 | ||
602 | flags = le32_to_cpu(fe->id1.journal1.ij_flags); | 596 | flags = le32_to_cpu(fe->id1.journal1.ij_flags); |
603 | if (dirty) | 597 | if (dirty) |
@@ -613,7 +607,6 @@ static int ocfs2_journal_toggle_dirty(struct ocfs2_super *osb, | |||
613 | if (status < 0) | 607 | if (status < 0) |
614 | mlog_errno(status); | 608 | mlog_errno(status); |
615 | 609 | ||
616 | out: | ||
617 | mlog_exit(status); | 610 | mlog_exit(status); |
618 | return status; | 611 | return status; |
619 | } | 612 | } |
diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h index 25d07ff1d3cd..467bdb6f71e1 100644 --- a/fs/ocfs2/ocfs2.h +++ b/fs/ocfs2/ocfs2.h | |||
@@ -444,14 +444,6 @@ static inline int ocfs2_uses_extended_slot_map(struct ocfs2_super *osb) | |||
444 | #define OCFS2_IS_VALID_DINODE(ptr) \ | 444 | #define OCFS2_IS_VALID_DINODE(ptr) \ |
445 | (!strcmp((ptr)->i_signature, OCFS2_INODE_SIGNATURE)) | 445 | (!strcmp((ptr)->i_signature, OCFS2_INODE_SIGNATURE)) |
446 | 446 | ||
447 | #define OCFS2_RO_ON_INVALID_DINODE(__sb, __di) do { \ | ||
448 | typeof(__di) ____di = (__di); \ | ||
449 | ocfs2_error((__sb), \ | ||
450 | "Dinode # %llu has bad signature %.*s", \ | ||
451 | (unsigned long long)le64_to_cpu((____di)->i_blkno), 7, \ | ||
452 | (____di)->i_signature); \ | ||
453 | } while (0) | ||
454 | |||
455 | #define OCFS2_IS_VALID_EXTENT_BLOCK(ptr) \ | 447 | #define OCFS2_IS_VALID_EXTENT_BLOCK(ptr) \ |
456 | (!strcmp((ptr)->h_signature, OCFS2_EXTENT_BLOCK_SIGNATURE)) | 448 | (!strcmp((ptr)->h_signature, OCFS2_EXTENT_BLOCK_SIGNATURE)) |
457 | 449 | ||
diff --git a/fs/ocfs2/resize.c b/fs/ocfs2/resize.c index ffd48db229a7..739d452f6174 100644 --- a/fs/ocfs2/resize.c +++ b/fs/ocfs2/resize.c | |||
@@ -314,6 +314,10 @@ int ocfs2_group_extend(struct inode * inode, int new_clusters) | |||
314 | 314 | ||
315 | fe = (struct ocfs2_dinode *)main_bm_bh->b_data; | 315 | fe = (struct ocfs2_dinode *)main_bm_bh->b_data; |
316 | 316 | ||
317 | /* main_bm_bh is validated by inode read inside ocfs2_inode_lock(), | ||
318 | * so any corruption is a code bug. */ | ||
319 | BUG_ON(!OCFS2_IS_VALID_DINODE(fe)); | ||
320 | |||
317 | if (le16_to_cpu(fe->id2.i_chain.cl_cpg) != | 321 | if (le16_to_cpu(fe->id2.i_chain.cl_cpg) != |
318 | ocfs2_group_bitmap_size(osb->sb) * 8) { | 322 | ocfs2_group_bitmap_size(osb->sb) * 8) { |
319 | mlog(ML_ERROR, "The disk is too old and small. " | 323 | mlog(ML_ERROR, "The disk is too old and small. " |
@@ -322,12 +326,6 @@ int ocfs2_group_extend(struct inode * inode, int new_clusters) | |||
322 | goto out_unlock; | 326 | goto out_unlock; |
323 | } | 327 | } |
324 | 328 | ||
325 | if (!OCFS2_IS_VALID_DINODE(fe)) { | ||
326 | OCFS2_RO_ON_INVALID_DINODE(main_bm_inode->i_sb, fe); | ||
327 | ret = -EIO; | ||
328 | goto out_unlock; | ||
329 | } | ||
330 | |||
331 | first_new_cluster = le32_to_cpu(fe->i_clusters); | 329 | first_new_cluster = le32_to_cpu(fe->i_clusters); |
332 | lgd_blkno = ocfs2_which_cluster_group(main_bm_inode, | 330 | lgd_blkno = ocfs2_which_cluster_group(main_bm_inode, |
333 | first_new_cluster - 1); | 331 | first_new_cluster - 1); |
diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c index c5ff18b46b57..95d432b694e4 100644 --- a/fs/ocfs2/suballoc.c +++ b/fs/ocfs2/suballoc.c | |||
@@ -441,11 +441,11 @@ static int ocfs2_reserve_suballoc_bits(struct ocfs2_super *osb, | |||
441 | ac->ac_alloc_slot = slot; | 441 | ac->ac_alloc_slot = slot; |
442 | 442 | ||
443 | fe = (struct ocfs2_dinode *) bh->b_data; | 443 | fe = (struct ocfs2_dinode *) bh->b_data; |
444 | if (!OCFS2_IS_VALID_DINODE(fe)) { | 444 | |
445 | OCFS2_RO_ON_INVALID_DINODE(alloc_inode->i_sb, fe); | 445 | /* The bh was validated by the inode read inside |
446 | status = -EIO; | 446 | * ocfs2_inode_lock(). Any corruption is a code bug. */ |
447 | goto bail; | 447 | BUG_ON(!OCFS2_IS_VALID_DINODE(fe)); |
448 | } | 448 | |
449 | if (!(fe->i_flags & cpu_to_le32(OCFS2_CHAIN_FL))) { | 449 | if (!(fe->i_flags & cpu_to_le32(OCFS2_CHAIN_FL))) { |
450 | ocfs2_error(alloc_inode->i_sb, "Invalid chain allocator %llu", | 450 | ocfs2_error(alloc_inode->i_sb, "Invalid chain allocator %llu", |
451 | (unsigned long long)le64_to_cpu(fe->i_blkno)); | 451 | (unsigned long long)le64_to_cpu(fe->i_blkno)); |
@@ -931,11 +931,6 @@ static int ocfs2_relink_block_group(handle_t *handle, | |||
931 | struct ocfs2_group_desc *bg = (struct ocfs2_group_desc *) bg_bh->b_data; | 931 | struct ocfs2_group_desc *bg = (struct ocfs2_group_desc *) bg_bh->b_data; |
932 | struct ocfs2_group_desc *prev_bg = (struct ocfs2_group_desc *) prev_bg_bh->b_data; | 932 | struct ocfs2_group_desc *prev_bg = (struct ocfs2_group_desc *) prev_bg_bh->b_data; |
933 | 933 | ||
934 | if (!OCFS2_IS_VALID_DINODE(fe)) { | ||
935 | OCFS2_RO_ON_INVALID_DINODE(alloc_inode->i_sb, fe); | ||
936 | status = -EIO; | ||
937 | goto out; | ||
938 | } | ||
939 | if (!OCFS2_IS_VALID_GROUP_DESC(bg)) { | 934 | if (!OCFS2_IS_VALID_GROUP_DESC(bg)) { |
940 | OCFS2_RO_ON_INVALID_GROUP_DESC(alloc_inode->i_sb, bg); | 935 | OCFS2_RO_ON_INVALID_GROUP_DESC(alloc_inode->i_sb, bg); |
941 | status = -EIO; | 936 | status = -EIO; |
@@ -1392,11 +1387,11 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_super *osb, | |||
1392 | BUG_ON(!ac->ac_bh); | 1387 | BUG_ON(!ac->ac_bh); |
1393 | 1388 | ||
1394 | fe = (struct ocfs2_dinode *) ac->ac_bh->b_data; | 1389 | fe = (struct ocfs2_dinode *) ac->ac_bh->b_data; |
1395 | if (!OCFS2_IS_VALID_DINODE(fe)) { | 1390 | |
1396 | OCFS2_RO_ON_INVALID_DINODE(osb->sb, fe); | 1391 | /* The bh was validated by the inode read during |
1397 | status = -EIO; | 1392 | * ocfs2_reserve_suballoc_bits(). Any corruption is a code bug. */ |
1398 | goto bail; | 1393 | BUG_ON(!OCFS2_IS_VALID_DINODE(fe)); |
1399 | } | 1394 | |
1400 | if (le32_to_cpu(fe->id1.bitmap1.i_used) >= | 1395 | if (le32_to_cpu(fe->id1.bitmap1.i_used) >= |
1401 | le32_to_cpu(fe->id1.bitmap1.i_total)) { | 1396 | le32_to_cpu(fe->id1.bitmap1.i_total)) { |
1402 | ocfs2_error(osb->sb, "Chain allocator dinode %llu has %u used " | 1397 | ocfs2_error(osb->sb, "Chain allocator dinode %llu has %u used " |
@@ -1782,11 +1777,12 @@ int ocfs2_free_suballoc_bits(handle_t *handle, | |||
1782 | 1777 | ||
1783 | mlog_entry_void(); | 1778 | mlog_entry_void(); |
1784 | 1779 | ||
1785 | if (!OCFS2_IS_VALID_DINODE(fe)) { | 1780 | /* The alloc_bh comes from ocfs2_free_dinode() or |
1786 | OCFS2_RO_ON_INVALID_DINODE(alloc_inode->i_sb, fe); | 1781 | * ocfs2_free_clusters(). The callers have all locked the |
1787 | status = -EIO; | 1782 | * allocator and gotten alloc_bh from the lock call. This |
1788 | goto bail; | 1783 | * validates the dinode buffer. Any corruption that has happended |
1789 | } | 1784 | * is a code bug. */ |
1785 | BUG_ON(!OCFS2_IS_VALID_DINODE(fe)); | ||
1790 | BUG_ON((count + start_bit) > ocfs2_bits_per_group(cl)); | 1786 | BUG_ON((count + start_bit) > ocfs2_bits_per_group(cl)); |
1791 | 1787 | ||
1792 | mlog(0, "%llu: freeing %u bits from group %llu, starting at %u\n", | 1788 | mlog(0, "%llu: freeing %u bits from group %llu, starting at %u\n", |