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 |
