diff options
Diffstat (limited to 'fs/xfs/libxfs/xfs_dir2_node.c')
-rw-r--r-- | fs/xfs/libxfs/xfs_dir2_node.c | 51 |
1 files changed, 49 insertions, 2 deletions
diff --git a/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c index 75a557432d0f..bbd1238852b3 100644 --- a/fs/xfs/libxfs/xfs_dir2_node.c +++ b/fs/xfs/libxfs/xfs_dir2_node.c | |||
@@ -155,6 +155,42 @@ const struct xfs_buf_ops xfs_dir3_free_buf_ops = { | |||
155 | .verify_write = xfs_dir3_free_write_verify, | 155 | .verify_write = xfs_dir3_free_write_verify, |
156 | }; | 156 | }; |
157 | 157 | ||
158 | /* Everything ok in the free block header? */ | ||
159 | static bool | ||
160 | xfs_dir3_free_header_check( | ||
161 | struct xfs_inode *dp, | ||
162 | xfs_dablk_t fbno, | ||
163 | struct xfs_buf *bp) | ||
164 | { | ||
165 | struct xfs_mount *mp = dp->i_mount; | ||
166 | unsigned int firstdb; | ||
167 | int maxbests; | ||
168 | |||
169 | maxbests = dp->d_ops->free_max_bests(mp->m_dir_geo); | ||
170 | firstdb = (xfs_dir2_da_to_db(mp->m_dir_geo, fbno) - | ||
171 | xfs_dir2_byte_to_db(mp->m_dir_geo, XFS_DIR2_FREE_OFFSET)) * | ||
172 | maxbests; | ||
173 | if (xfs_sb_version_hascrc(&mp->m_sb)) { | ||
174 | struct xfs_dir3_free_hdr *hdr3 = bp->b_addr; | ||
175 | |||
176 | if (be32_to_cpu(hdr3->firstdb) != firstdb) | ||
177 | return false; | ||
178 | if (be32_to_cpu(hdr3->nvalid) > maxbests) | ||
179 | return false; | ||
180 | if (be32_to_cpu(hdr3->nvalid) < be32_to_cpu(hdr3->nused)) | ||
181 | return false; | ||
182 | } else { | ||
183 | struct xfs_dir2_free_hdr *hdr = bp->b_addr; | ||
184 | |||
185 | if (be32_to_cpu(hdr->firstdb) != firstdb) | ||
186 | return false; | ||
187 | if (be32_to_cpu(hdr->nvalid) > maxbests) | ||
188 | return false; | ||
189 | if (be32_to_cpu(hdr->nvalid) < be32_to_cpu(hdr->nused)) | ||
190 | return false; | ||
191 | } | ||
192 | return true; | ||
193 | } | ||
158 | 194 | ||
159 | static int | 195 | static int |
160 | __xfs_dir3_free_read( | 196 | __xfs_dir3_free_read( |
@@ -168,11 +204,22 @@ __xfs_dir3_free_read( | |||
168 | 204 | ||
169 | err = xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp, | 205 | err = xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp, |
170 | XFS_DATA_FORK, &xfs_dir3_free_buf_ops); | 206 | XFS_DATA_FORK, &xfs_dir3_free_buf_ops); |
207 | if (err || !*bpp) | ||
208 | return err; | ||
209 | |||
210 | /* Check things that we can't do in the verifier. */ | ||
211 | if (!xfs_dir3_free_header_check(dp, fbno, *bpp)) { | ||
212 | xfs_buf_ioerror(*bpp, -EFSCORRUPTED); | ||
213 | xfs_verifier_error(*bpp); | ||
214 | xfs_trans_brelse(tp, *bpp); | ||
215 | return -EFSCORRUPTED; | ||
216 | } | ||
171 | 217 | ||
172 | /* try read returns without an error or *bpp if it lands in a hole */ | 218 | /* try read returns without an error or *bpp if it lands in a hole */ |
173 | if (!err && tp && *bpp) | 219 | if (tp) |
174 | xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_FREE_BUF); | 220 | xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_FREE_BUF); |
175 | return err; | 221 | |
222 | return 0; | ||
176 | } | 223 | } |
177 | 224 | ||
178 | int | 225 | int |