diff options
author | Christoph Hellwig <hch@lst.de> | 2013-04-03 01:11:16 -0400 |
---|---|---|
committer | Ben Myers <bpm@sgi.com> | 2013-04-21 15:58:22 -0400 |
commit | 3fe58f30b4fc3f8a9084b035a02bc0c67bee8d00 (patch) | |
tree | 4b46222d26f3e74d65c6741ddcaed7eaa48948eb /fs/xfs/xfs_dquot.c | |
parent | 983d09ffe396ed5d5339a1b9ff994dd0b0f2069f (diff) |
xfs: add CRC checks for quota blocks
Use the reserved space in struct xfs_dqblk to store a UUID and a crc
for the quota blocks.
[dchinner@redhat.com] Add a LSN field and update for current verifier
infrastructure.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Ben Myers <bpm@sgi.com>
Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs/xfs/xfs_dquot.c')
-rw-r--r-- | fs/xfs/xfs_dquot.c | 112 |
1 files changed, 99 insertions, 13 deletions
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c index 45bb08f6ba17..a41f8bf1da37 100644 --- a/fs/xfs/xfs_dquot.c +++ b/fs/xfs/xfs_dquot.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include "xfs_trans_space.h" | 36 | #include "xfs_trans_space.h" |
37 | #include "xfs_trans_priv.h" | 37 | #include "xfs_trans_priv.h" |
38 | #include "xfs_qm.h" | 38 | #include "xfs_qm.h" |
39 | #include "xfs_cksum.h" | ||
39 | #include "xfs_trace.h" | 40 | #include "xfs_trace.h" |
40 | 41 | ||
41 | /* | 42 | /* |
@@ -248,6 +249,8 @@ xfs_qm_init_dquot_blk( | |||
248 | d->dd_diskdq.d_version = XFS_DQUOT_VERSION; | 249 | d->dd_diskdq.d_version = XFS_DQUOT_VERSION; |
249 | d->dd_diskdq.d_id = cpu_to_be32(curid); | 250 | d->dd_diskdq.d_id = cpu_to_be32(curid); |
250 | d->dd_diskdq.d_flags = type; | 251 | d->dd_diskdq.d_flags = type; |
252 | if (xfs_sb_version_hascrc(&mp->m_sb)) | ||
253 | uuid_copy(&d->dd_uuid, &mp->m_sb.sb_uuid); | ||
251 | } | 254 | } |
252 | 255 | ||
253 | xfs_trans_dquot_buf(tp, bp, | 256 | xfs_trans_dquot_buf(tp, bp, |
@@ -283,25 +286,87 @@ xfs_dquot_set_prealloc_limits(struct xfs_dquot *dqp) | |||
283 | dqp->q_low_space[XFS_QLOWSP_5_PCNT] = space * 5; | 286 | dqp->q_low_space[XFS_QLOWSP_5_PCNT] = space * 5; |
284 | } | 287 | } |
285 | 288 | ||
286 | static void | 289 | STATIC void |
290 | xfs_dquot_buf_calc_crc( | ||
291 | struct xfs_mount *mp, | ||
292 | struct xfs_buf *bp) | ||
293 | { | ||
294 | struct xfs_dqblk *d = (struct xfs_dqblk *)bp->b_addr; | ||
295 | int i; | ||
296 | |||
297 | if (!xfs_sb_version_hascrc(&mp->m_sb)) | ||
298 | return; | ||
299 | |||
300 | for (i = 0; i < mp->m_quotainfo->qi_dqperchunk; i++, d++) { | ||
301 | xfs_update_cksum((char *)d, sizeof(struct xfs_dqblk), | ||
302 | offsetof(struct xfs_dqblk, dd_crc)); | ||
303 | } | ||
304 | } | ||
305 | |||
306 | STATIC bool | ||
307 | xfs_dquot_buf_verify_crc( | ||
308 | struct xfs_mount *mp, | ||
309 | struct xfs_buf *bp) | ||
310 | { | ||
311 | struct xfs_dqblk *d = (struct xfs_dqblk *)bp->b_addr; | ||
312 | int ndquots; | ||
313 | int i; | ||
314 | |||
315 | if (!xfs_sb_version_hascrc(&mp->m_sb)) | ||
316 | return true; | ||
317 | |||
318 | /* | ||
319 | * if we are in log recovery, the quota subsystem has not been | ||
320 | * initialised so we have no quotainfo structure. In that case, we need | ||
321 | * to manually calculate the number of dquots in the buffer. | ||
322 | */ | ||
323 | if (mp->m_quotainfo) | ||
324 | ndquots = mp->m_quotainfo->qi_dqperchunk; | ||
325 | else | ||
326 | ndquots = xfs_qm_calc_dquots_per_chunk(mp, | ||
327 | XFS_BB_TO_FSB(mp, bp->b_length)); | ||
328 | |||
329 | for (i = 0; i < ndquots; i++, d++) { | ||
330 | if (!xfs_verify_cksum((char *)d, sizeof(struct xfs_dqblk), | ||
331 | offsetof(struct xfs_dqblk, dd_crc))) | ||
332 | return false; | ||
333 | if (!uuid_equal(&d->dd_uuid, &mp->m_sb.sb_uuid)) | ||
334 | return false; | ||
335 | } | ||
336 | |||
337 | return true; | ||
338 | } | ||
339 | |||
340 | STATIC bool | ||
287 | xfs_dquot_buf_verify( | 341 | xfs_dquot_buf_verify( |
342 | struct xfs_mount *mp, | ||
288 | struct xfs_buf *bp) | 343 | struct xfs_buf *bp) |
289 | { | 344 | { |
290 | struct xfs_mount *mp = bp->b_target->bt_mount; | ||
291 | struct xfs_dqblk *d = (struct xfs_dqblk *)bp->b_addr; | 345 | struct xfs_dqblk *d = (struct xfs_dqblk *)bp->b_addr; |
292 | struct xfs_disk_dquot *ddq; | ||
293 | xfs_dqid_t id = 0; | 346 | xfs_dqid_t id = 0; |
347 | int ndquots; | ||
294 | int i; | 348 | int i; |
295 | 349 | ||
296 | /* | 350 | /* |
351 | * if we are in log recovery, the quota subsystem has not been | ||
352 | * initialised so we have no quotainfo structure. In that case, we need | ||
353 | * to manually calculate the number of dquots in the buffer. | ||
354 | */ | ||
355 | if (mp->m_quotainfo) | ||
356 | ndquots = mp->m_quotainfo->qi_dqperchunk; | ||
357 | else | ||
358 | ndquots = xfs_qm_calc_dquots_per_chunk(mp, bp->b_length); | ||
359 | |||
360 | /* | ||
297 | * On the first read of the buffer, verify that each dquot is valid. | 361 | * On the first read of the buffer, verify that each dquot is valid. |
298 | * We don't know what the id of the dquot is supposed to be, just that | 362 | * We don't know what the id of the dquot is supposed to be, just that |
299 | * they should be increasing monotonically within the buffer. If the | 363 | * they should be increasing monotonically within the buffer. If the |
300 | * first id is corrupt, then it will fail on the second dquot in the | 364 | * first id is corrupt, then it will fail on the second dquot in the |
301 | * buffer so corruptions could point to the wrong dquot in this case. | 365 | * buffer so corruptions could point to the wrong dquot in this case. |
302 | */ | 366 | */ |
303 | for (i = 0; i < mp->m_quotainfo->qi_dqperchunk; i++) { | 367 | for (i = 0; i < ndquots; i++) { |
304 | int error; | 368 | struct xfs_disk_dquot *ddq; |
369 | int error; | ||
305 | 370 | ||
306 | ddq = &d[i].dd_diskdq; | 371 | ddq = &d[i].dd_diskdq; |
307 | 372 | ||
@@ -309,27 +374,37 @@ xfs_dquot_buf_verify( | |||
309 | id = be32_to_cpu(ddq->d_id); | 374 | id = be32_to_cpu(ddq->d_id); |
310 | 375 | ||
311 | error = xfs_qm_dqcheck(mp, ddq, id + i, 0, XFS_QMOPT_DOWARN, | 376 | error = xfs_qm_dqcheck(mp, ddq, id + i, 0, XFS_QMOPT_DOWARN, |
312 | "xfs_dquot_read_verify"); | 377 | "xfs_dquot_buf_verify"); |
313 | if (error) { | 378 | if (error) |
314 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, d); | 379 | return false; |
315 | xfs_buf_ioerror(bp, EFSCORRUPTED); | ||
316 | break; | ||
317 | } | ||
318 | } | 380 | } |
381 | return true; | ||
319 | } | 382 | } |
320 | 383 | ||
321 | static void | 384 | static void |
322 | xfs_dquot_buf_read_verify( | 385 | xfs_dquot_buf_read_verify( |
323 | struct xfs_buf *bp) | 386 | struct xfs_buf *bp) |
324 | { | 387 | { |
325 | xfs_dquot_buf_verify(bp); | 388 | struct xfs_mount *mp = bp->b_target->bt_mount; |
389 | |||
390 | if (!xfs_dquot_buf_verify_crc(mp, bp) || !xfs_dquot_buf_verify(mp, bp)) { | ||
391 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); | ||
392 | xfs_buf_ioerror(bp, EFSCORRUPTED); | ||
393 | } | ||
326 | } | 394 | } |
327 | 395 | ||
328 | void | 396 | void |
329 | xfs_dquot_buf_write_verify( | 397 | xfs_dquot_buf_write_verify( |
330 | struct xfs_buf *bp) | 398 | struct xfs_buf *bp) |
331 | { | 399 | { |
332 | xfs_dquot_buf_verify(bp); | 400 | struct xfs_mount *mp = bp->b_target->bt_mount; |
401 | |||
402 | if (!xfs_dquot_buf_verify(mp, bp)) { | ||
403 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); | ||
404 | xfs_buf_ioerror(bp, EFSCORRUPTED); | ||
405 | return; | ||
406 | } | ||
407 | xfs_dquot_buf_calc_crc(mp, bp); | ||
333 | } | 408 | } |
334 | 409 | ||
335 | const struct xfs_buf_ops xfs_dquot_buf_ops = { | 410 | const struct xfs_buf_ops xfs_dquot_buf_ops = { |
@@ -1073,6 +1148,17 @@ xfs_qm_dqflush( | |||
1073 | &dqp->q_logitem.qli_item.li_lsn); | 1148 | &dqp->q_logitem.qli_item.li_lsn); |
1074 | 1149 | ||
1075 | /* | 1150 | /* |
1151 | * copy the lsn into the on-disk dquot now while we have the in memory | ||
1152 | * dquot here. This can't be done later in the write verifier as we | ||
1153 | * can't get access to the log item at that point in time. | ||
1154 | */ | ||
1155 | if (xfs_sb_version_hascrc(&mp->m_sb)) { | ||
1156 | struct xfs_dqblk *dqb = (struct xfs_dqblk *)ddqp; | ||
1157 | |||
1158 | dqb->dd_lsn = cpu_to_be64(dqp->q_logitem.qli_item.li_lsn); | ||
1159 | } | ||
1160 | |||
1161 | /* | ||
1076 | * Attach an iodone routine so that we can remove this dquot from the | 1162 | * Attach an iodone routine so that we can remove this dquot from the |
1077 | * AIL and release the flush lock once the dquot is synced to disk. | 1163 | * AIL and release the flush lock once the dquot is synced to disk. |
1078 | */ | 1164 | */ |