diff options
author | Mark Fasheh <mark.fasheh@oracle.com> | 2006-05-03 20:46:50 -0400 |
---|---|---|
committer | Mark Fasheh <mark.fasheh@oracle.com> | 2006-08-07 14:04:38 -0400 |
commit | 7bf72edee614e10b8d470c40a326f47bfdd69992 (patch) | |
tree | 8309812d2e256da821d2774a5a719663038093fa /fs | |
parent | 101ebf256de54e78e6d3277adacf656e125a2c5a (diff) |
ocfs2: better group descriptor consistency checks
Try to catch corrupted group descriptors with some stronger checks placed in
a couple of strategic locations. Detect a failed resizefs and refuse to
allocate past what bitmap i_clusters allows.
Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ocfs2/suballoc.c | 114 |
1 files changed, 94 insertions, 20 deletions
diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c index 195523090c87..7ac68cac041d 100644 --- a/fs/ocfs2/suballoc.c +++ b/fs/ocfs2/suballoc.c | |||
@@ -85,11 +85,6 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_super *osb, | |||
85 | u64 *bg_blkno); | 85 | u64 *bg_blkno); |
86 | static int ocfs2_test_bg_bit_allocatable(struct buffer_head *bg_bh, | 86 | static int ocfs2_test_bg_bit_allocatable(struct buffer_head *bg_bh, |
87 | int nr); | 87 | int nr); |
88 | static int ocfs2_block_group_find_clear_bits(struct ocfs2_super *osb, | ||
89 | struct buffer_head *bg_bh, | ||
90 | unsigned int bits_wanted, | ||
91 | u16 *bit_off, | ||
92 | u16 *bits_found); | ||
93 | static inline int ocfs2_block_group_set_bits(struct ocfs2_journal_handle *handle, | 88 | static inline int ocfs2_block_group_set_bits(struct ocfs2_journal_handle *handle, |
94 | struct inode *alloc_inode, | 89 | struct inode *alloc_inode, |
95 | struct ocfs2_group_desc *bg, | 90 | struct ocfs2_group_desc *bg, |
@@ -143,6 +138,64 @@ static u32 ocfs2_bits_per_group(struct ocfs2_chain_list *cl) | |||
143 | return (u32)le16_to_cpu(cl->cl_cpg) * (u32)le16_to_cpu(cl->cl_bpc); | 138 | return (u32)le16_to_cpu(cl->cl_cpg) * (u32)le16_to_cpu(cl->cl_bpc); |
144 | } | 139 | } |
145 | 140 | ||
141 | /* somewhat more expensive than our other checks, so use sparingly. */ | ||
142 | static int ocfs2_check_group_descriptor(struct super_block *sb, | ||
143 | struct ocfs2_dinode *di, | ||
144 | struct ocfs2_group_desc *gd) | ||
145 | { | ||
146 | unsigned int max_bits; | ||
147 | |||
148 | if (!OCFS2_IS_VALID_GROUP_DESC(gd)) { | ||
149 | OCFS2_RO_ON_INVALID_GROUP_DESC(sb, gd); | ||
150 | return -EIO; | ||
151 | } | ||
152 | |||
153 | if (di->i_blkno != gd->bg_parent_dinode) { | ||
154 | ocfs2_error(sb, "Group descriptor # %llu has bad parent " | ||
155 | "pointer (%llu, expected %llu)", | ||
156 | (unsigned long long)le64_to_cpu(gd->bg_blkno), | ||
157 | (unsigned long long)le64_to_cpu(gd->bg_parent_dinode), | ||
158 | (unsigned long long)le64_to_cpu(di->i_blkno)); | ||
159 | return -EIO; | ||
160 | } | ||
161 | |||
162 | max_bits = le16_to_cpu(di->id2.i_chain.cl_cpg) * le16_to_cpu(di->id2.i_chain.cl_bpc); | ||
163 | if (le16_to_cpu(gd->bg_bits) > max_bits) { | ||
164 | ocfs2_error(sb, "Group descriptor # %llu has bit count of %u", | ||
165 | (unsigned long long)le64_to_cpu(gd->bg_blkno), | ||
166 | le16_to_cpu(gd->bg_bits)); | ||
167 | return -EIO; | ||
168 | } | ||
169 | |||
170 | if (le16_to_cpu(gd->bg_chain) >= | ||
171 | le16_to_cpu(di->id2.i_chain.cl_next_free_rec)) { | ||
172 | ocfs2_error(sb, "Group descriptor # %llu has bad chain %u", | ||
173 | (unsigned long long)le64_to_cpu(gd->bg_blkno), | ||
174 | le16_to_cpu(gd->bg_chain)); | ||
175 | return -EIO; | ||
176 | } | ||
177 | |||
178 | if (le16_to_cpu(gd->bg_free_bits_count) > le16_to_cpu(gd->bg_bits)) { | ||
179 | ocfs2_error(sb, "Group descriptor # %llu has bit count %u but " | ||
180 | "claims that %u are free", | ||
181 | (unsigned long long)le64_to_cpu(gd->bg_blkno), | ||
182 | le16_to_cpu(gd->bg_bits), | ||
183 | le16_to_cpu(gd->bg_free_bits_count)); | ||
184 | return -EIO; | ||
185 | } | ||
186 | |||
187 | if (le16_to_cpu(gd->bg_bits) > (8 * le16_to_cpu(gd->bg_size))) { | ||
188 | ocfs2_error(sb, "Group descriptor # %llu has bit count %u but " | ||
189 | "max bitmap bits of %u", | ||
190 | (unsigned long long)le64_to_cpu(gd->bg_blkno), | ||
191 | le16_to_cpu(gd->bg_bits), | ||
192 | 8 * le16_to_cpu(gd->bg_size)); | ||
193 | return -EIO; | ||
194 | } | ||
195 | |||
196 | return 0; | ||
197 | } | ||
198 | |||
146 | static int ocfs2_block_group_fill(struct ocfs2_journal_handle *handle, | 199 | static int ocfs2_block_group_fill(struct ocfs2_journal_handle *handle, |
147 | struct inode *alloc_inode, | 200 | struct inode *alloc_inode, |
148 | struct buffer_head *bg_bh, | 201 | struct buffer_head *bg_bh, |
@@ -663,6 +716,7 @@ static int ocfs2_test_bg_bit_allocatable(struct buffer_head *bg_bh, | |||
663 | static int ocfs2_block_group_find_clear_bits(struct ocfs2_super *osb, | 716 | static int ocfs2_block_group_find_clear_bits(struct ocfs2_super *osb, |
664 | struct buffer_head *bg_bh, | 717 | struct buffer_head *bg_bh, |
665 | unsigned int bits_wanted, | 718 | unsigned int bits_wanted, |
719 | unsigned int total_bits, | ||
666 | u16 *bit_off, | 720 | u16 *bit_off, |
667 | u16 *bits_found) | 721 | u16 *bits_found) |
668 | { | 722 | { |
@@ -679,10 +733,8 @@ static int ocfs2_block_group_find_clear_bits(struct ocfs2_super *osb, | |||
679 | found = start = best_offset = best_size = 0; | 733 | found = start = best_offset = best_size = 0; |
680 | bitmap = bg->bg_bitmap; | 734 | bitmap = bg->bg_bitmap; |
681 | 735 | ||
682 | while((offset = ocfs2_find_next_zero_bit(bitmap, | 736 | while((offset = ocfs2_find_next_zero_bit(bitmap, total_bits, start)) != -1) { |
683 | le16_to_cpu(bg->bg_bits), | 737 | if (offset == total_bits) |
684 | start)) != -1) { | ||
685 | if (offset == le16_to_cpu(bg->bg_bits)) | ||
686 | break; | 738 | break; |
687 | 739 | ||
688 | if (!ocfs2_test_bg_bit_allocatable(bg_bh, offset)) { | 740 | if (!ocfs2_test_bg_bit_allocatable(bg_bh, offset)) { |
@@ -911,14 +963,35 @@ static int ocfs2_cluster_group_search(struct inode *inode, | |||
911 | { | 963 | { |
912 | int search = -ENOSPC; | 964 | int search = -ENOSPC; |
913 | int ret; | 965 | int ret; |
914 | struct ocfs2_group_desc *bg = (struct ocfs2_group_desc *) group_bh->b_data; | 966 | struct ocfs2_group_desc *gd = (struct ocfs2_group_desc *) group_bh->b_data; |
915 | u16 tmp_off, tmp_found; | 967 | u16 tmp_off, tmp_found; |
968 | unsigned int max_bits, gd_cluster_off; | ||
916 | 969 | ||
917 | BUG_ON(!ocfs2_is_cluster_bitmap(inode)); | 970 | BUG_ON(!ocfs2_is_cluster_bitmap(inode)); |
918 | 971 | ||
919 | if (bg->bg_free_bits_count) { | 972 | if (gd->bg_free_bits_count) { |
973 | max_bits = le16_to_cpu(gd->bg_bits); | ||
974 | |||
975 | /* Tail groups in cluster bitmaps which aren't cpg | ||
976 | * aligned are prone to partial extention by a failed | ||
977 | * fs resize. If the file system resize never got to | ||
978 | * update the dinode cluster count, then we don't want | ||
979 | * to trust any clusters past it, regardless of what | ||
980 | * the group descriptor says. */ | ||
981 | gd_cluster_off = ocfs2_blocks_to_clusters(inode->i_sb, | ||
982 | le64_to_cpu(gd->bg_blkno)); | ||
983 | if ((gd_cluster_off + max_bits) > | ||
984 | OCFS2_I(inode)->ip_clusters) { | ||
985 | max_bits = OCFS2_I(inode)->ip_clusters - gd_cluster_off; | ||
986 | mlog(0, "Desc %llu, bg_bits %u, clusters %u, use %u\n", | ||
987 | (unsigned long long)le64_to_cpu(gd->bg_blkno), | ||
988 | le16_to_cpu(gd->bg_bits), | ||
989 | OCFS2_I(inode)->ip_clusters, max_bits); | ||
990 | } | ||
991 | |||
920 | ret = ocfs2_block_group_find_clear_bits(OCFS2_SB(inode->i_sb), | 992 | ret = ocfs2_block_group_find_clear_bits(OCFS2_SB(inode->i_sb), |
921 | group_bh, bits_wanted, | 993 | group_bh, bits_wanted, |
994 | max_bits, | ||
922 | &tmp_off, &tmp_found); | 995 | &tmp_off, &tmp_found); |
923 | if (ret) | 996 | if (ret) |
924 | return ret; | 997 | return ret; |
@@ -951,6 +1024,7 @@ static int ocfs2_block_group_search(struct inode *inode, | |||
951 | if (bg->bg_free_bits_count) | 1024 | if (bg->bg_free_bits_count) |
952 | ret = ocfs2_block_group_find_clear_bits(OCFS2_SB(inode->i_sb), | 1025 | ret = ocfs2_block_group_find_clear_bits(OCFS2_SB(inode->i_sb), |
953 | group_bh, bits_wanted, | 1026 | group_bh, bits_wanted, |
1027 | le16_to_cpu(bg->bg_bits), | ||
954 | bit_off, bits_found); | 1028 | bit_off, bits_found); |
955 | 1029 | ||
956 | return ret; | 1030 | return ret; |
@@ -988,9 +1062,9 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac, | |||
988 | goto bail; | 1062 | goto bail; |
989 | } | 1063 | } |
990 | bg = (struct ocfs2_group_desc *) group_bh->b_data; | 1064 | bg = (struct ocfs2_group_desc *) group_bh->b_data; |
991 | if (!OCFS2_IS_VALID_GROUP_DESC(bg)) { | 1065 | status = ocfs2_check_group_descriptor(alloc_inode->i_sb, fe, bg); |
992 | OCFS2_RO_ON_INVALID_GROUP_DESC(alloc_inode->i_sb, bg); | 1066 | if (status) { |
993 | status = -EIO; | 1067 | mlog_errno(status); |
994 | goto bail; | 1068 | goto bail; |
995 | } | 1069 | } |
996 | 1070 | ||
@@ -1018,9 +1092,9 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac, | |||
1018 | goto bail; | 1092 | goto bail; |
1019 | } | 1093 | } |
1020 | bg = (struct ocfs2_group_desc *) group_bh->b_data; | 1094 | bg = (struct ocfs2_group_desc *) group_bh->b_data; |
1021 | if (!OCFS2_IS_VALID_GROUP_DESC(bg)) { | 1095 | status = ocfs2_check_group_descriptor(alloc_inode->i_sb, fe, bg); |
1022 | OCFS2_RO_ON_INVALID_GROUP_DESC(alloc_inode->i_sb, bg); | 1096 | if (status) { |
1023 | status = -EIO; | 1097 | mlog_errno(status); |
1024 | goto bail; | 1098 | goto bail; |
1025 | } | 1099 | } |
1026 | } | 1100 | } |
@@ -1494,9 +1568,9 @@ static int ocfs2_free_suballoc_bits(struct ocfs2_journal_handle *handle, | |||
1494 | } | 1568 | } |
1495 | 1569 | ||
1496 | group = (struct ocfs2_group_desc *) group_bh->b_data; | 1570 | group = (struct ocfs2_group_desc *) group_bh->b_data; |
1497 | if (!OCFS2_IS_VALID_GROUP_DESC(group)) { | 1571 | status = ocfs2_check_group_descriptor(alloc_inode->i_sb, fe, group); |
1498 | OCFS2_RO_ON_INVALID_GROUP_DESC(alloc_inode->i_sb, group); | 1572 | if (status) { |
1499 | status = -EIO; | 1573 | mlog_errno(status); |
1500 | goto bail; | 1574 | goto bail; |
1501 | } | 1575 | } |
1502 | BUG_ON((count + start_bit) > le16_to_cpu(group->bg_bits)); | 1576 | BUG_ON((count + start_bit) > le16_to_cpu(group->bg_bits)); |