diff options
author | Christoph Hellwig <hch@infradead.org> | 2010-09-05 21:44:45 -0400 |
---|---|---|
committer | Alex Elder <aelder@sgi.com> | 2010-10-18 16:07:37 -0400 |
commit | acecf1b5d8a846bf818bf74df454330f0b444b0a (patch) | |
tree | 9d337467b6882bff99fec04cd30b6cc0a831da5f /fs/xfs | |
parent | 52fda114249578311776b25da9f73a9c34f4fd8c (diff) |
xfs: stop using xfs_qm_dqtobp in xfs_qm_dqflush
In xfs_qm_dqflush we know that q_blkno must be initialized already from a
previous xfs_qm_dqread. So instead of calling xfs_qm_dqtobp we can
simply read the quota buffer directly. This also saves us from a duplicate
xfs_qm_dqcheck call check and allows xfs_qm_dqtobp to be simplified now
that it is always called for a newly initialized inode. In addition to
that properly unwind all locks in xfs_qm_dqflush when xfs_qm_dqcheck
fails.
This mirrors a similar cleanup in the inode lookup done earlier.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Alex Elder <aelder@sgi.com>
Diffstat (limited to 'fs/xfs')
-rw-r--r-- | fs/xfs/quota/xfs_dquot.c | 164 |
1 files changed, 76 insertions, 88 deletions
diff --git a/fs/xfs/quota/xfs_dquot.c b/fs/xfs/quota/xfs_dquot.c index e1a2f6800e01..faf8e1a83a12 100644 --- a/fs/xfs/quota/xfs_dquot.c +++ b/fs/xfs/quota/xfs_dquot.c | |||
@@ -463,87 +463,68 @@ xfs_qm_dqtobp( | |||
463 | uint flags) | 463 | uint flags) |
464 | { | 464 | { |
465 | xfs_bmbt_irec_t map; | 465 | xfs_bmbt_irec_t map; |
466 | int nmaps, error; | 466 | int nmaps = 1, error; |
467 | xfs_buf_t *bp; | 467 | xfs_buf_t *bp; |
468 | xfs_inode_t *quotip; | 468 | xfs_inode_t *quotip = XFS_DQ_TO_QIP(dqp); |
469 | xfs_mount_t *mp; | 469 | xfs_mount_t *mp = dqp->q_mount; |
470 | xfs_disk_dquot_t *ddq; | 470 | xfs_disk_dquot_t *ddq; |
471 | xfs_dqid_t id; | 471 | xfs_dqid_t id = be32_to_cpu(dqp->q_core.d_id); |
472 | boolean_t newdquot; | ||
473 | xfs_trans_t *tp = (tpp ? *tpp : NULL); | 472 | xfs_trans_t *tp = (tpp ? *tpp : NULL); |
474 | 473 | ||
475 | mp = dqp->q_mount; | 474 | dqp->q_fileoffset = (xfs_fileoff_t)id / mp->m_quotainfo->qi_dqperchunk; |
476 | id = be32_to_cpu(dqp->q_core.d_id); | ||
477 | nmaps = 1; | ||
478 | newdquot = B_FALSE; | ||
479 | 475 | ||
480 | /* | 476 | xfs_ilock(quotip, XFS_ILOCK_SHARED); |
481 | * If we don't know where the dquot lives, find out. | 477 | if (XFS_IS_THIS_QUOTA_OFF(dqp)) { |
482 | */ | ||
483 | if (dqp->q_blkno == (xfs_daddr_t) 0) { | ||
484 | /* We use the id as an index */ | ||
485 | dqp->q_fileoffset = (xfs_fileoff_t)id / | ||
486 | mp->m_quotainfo->qi_dqperchunk; | ||
487 | nmaps = 1; | ||
488 | quotip = XFS_DQ_TO_QIP(dqp); | ||
489 | xfs_ilock(quotip, XFS_ILOCK_SHARED); | ||
490 | /* | 478 | /* |
491 | * Return if this type of quotas is turned off while we didn't | 479 | * Return if this type of quotas is turned off while we |
492 | * have an inode lock | 480 | * didn't have the quota inode lock. |
493 | */ | 481 | */ |
494 | if (XFS_IS_THIS_QUOTA_OFF(dqp)) { | 482 | xfs_iunlock(quotip, XFS_ILOCK_SHARED); |
495 | xfs_iunlock(quotip, XFS_ILOCK_SHARED); | 483 | return ESRCH; |
496 | return (ESRCH); | 484 | } |
497 | } | 485 | |
486 | /* | ||
487 | * Find the block map; no allocations yet | ||
488 | */ | ||
489 | error = xfs_bmapi(NULL, quotip, dqp->q_fileoffset, | ||
490 | XFS_DQUOT_CLUSTER_SIZE_FSB, XFS_BMAPI_METADATA, | ||
491 | NULL, 0, &map, &nmaps, NULL); | ||
492 | |||
493 | xfs_iunlock(quotip, XFS_ILOCK_SHARED); | ||
494 | if (error) | ||
495 | return error; | ||
496 | |||
497 | ASSERT(nmaps == 1); | ||
498 | ASSERT(map.br_blockcount == 1); | ||
499 | |||
500 | /* | ||
501 | * Offset of dquot in the (fixed sized) dquot chunk. | ||
502 | */ | ||
503 | dqp->q_bufoffset = (id % mp->m_quotainfo->qi_dqperchunk) * | ||
504 | sizeof(xfs_dqblk_t); | ||
505 | |||
506 | ASSERT(map.br_startblock != DELAYSTARTBLOCK); | ||
507 | if (map.br_startblock == HOLESTARTBLOCK) { | ||
498 | /* | 508 | /* |
499 | * Find the block map; no allocations yet | 509 | * We don't allocate unless we're asked to |
500 | */ | 510 | */ |
501 | error = xfs_bmapi(NULL, quotip, dqp->q_fileoffset, | 511 | if (!(flags & XFS_QMOPT_DQALLOC)) |
502 | XFS_DQUOT_CLUSTER_SIZE_FSB, | 512 | return ENOENT; |
503 | XFS_BMAPI_METADATA, | ||
504 | NULL, 0, &map, &nmaps, NULL); | ||
505 | 513 | ||
506 | xfs_iunlock(quotip, XFS_ILOCK_SHARED); | 514 | ASSERT(tp); |
515 | error = xfs_qm_dqalloc(tpp, mp, dqp, quotip, | ||
516 | dqp->q_fileoffset, &bp); | ||
507 | if (error) | 517 | if (error) |
508 | return (error); | 518 | return error; |
509 | ASSERT(nmaps == 1); | 519 | tp = *tpp; |
510 | ASSERT(map.br_blockcount == 1); | 520 | } else { |
521 | trace_xfs_dqtobp_read(dqp); | ||
511 | 522 | ||
512 | /* | 523 | /* |
513 | * offset of dquot in the (fixed sized) dquot chunk. | 524 | * store the blkno etc so that we don't have to do the |
525 | * mapping all the time | ||
514 | */ | 526 | */ |
515 | dqp->q_bufoffset = (id % mp->m_quotainfo->qi_dqperchunk) * | 527 | dqp->q_blkno = XFS_FSB_TO_DADDR(mp, map.br_startblock); |
516 | sizeof(xfs_dqblk_t); | ||
517 | if (map.br_startblock == HOLESTARTBLOCK) { | ||
518 | /* | ||
519 | * We don't allocate unless we're asked to | ||
520 | */ | ||
521 | if (!(flags & XFS_QMOPT_DQALLOC)) | ||
522 | return (ENOENT); | ||
523 | |||
524 | ASSERT(tp); | ||
525 | if ((error = xfs_qm_dqalloc(tpp, mp, dqp, quotip, | ||
526 | dqp->q_fileoffset, &bp))) | ||
527 | return (error); | ||
528 | tp = *tpp; | ||
529 | newdquot = B_TRUE; | ||
530 | } else { | ||
531 | /* | ||
532 | * store the blkno etc so that we don't have to do the | ||
533 | * mapping all the time | ||
534 | */ | ||
535 | dqp->q_blkno = XFS_FSB_TO_DADDR(mp, map.br_startblock); | ||
536 | } | ||
537 | } | ||
538 | ASSERT(dqp->q_blkno != DELAYSTARTBLOCK); | ||
539 | ASSERT(dqp->q_blkno != HOLESTARTBLOCK); | ||
540 | |||
541 | /* | ||
542 | * Read in the buffer, unless we've just done the allocation | ||
543 | * (in which case we already have the buf). | ||
544 | */ | ||
545 | if (!newdquot) { | ||
546 | trace_xfs_dqtobp_read(dqp); | ||
547 | 528 | ||
548 | error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, | 529 | error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, |
549 | dqp->q_blkno, | 530 | dqp->q_blkno, |
@@ -552,13 +533,14 @@ xfs_qm_dqtobp( | |||
552 | if (error || !bp) | 533 | if (error || !bp) |
553 | return XFS_ERROR(error); | 534 | return XFS_ERROR(error); |
554 | } | 535 | } |
536 | |||
555 | ASSERT(XFS_BUF_ISBUSY(bp)); | 537 | ASSERT(XFS_BUF_ISBUSY(bp)); |
556 | ASSERT(XFS_BUF_VALUSEMA(bp) <= 0); | 538 | ASSERT(XFS_BUF_VALUSEMA(bp) <= 0); |
557 | 539 | ||
558 | /* | 540 | /* |
559 | * calculate the location of the dquot inside the buffer. | 541 | * calculate the location of the dquot inside the buffer. |
560 | */ | 542 | */ |
561 | ddq = (xfs_disk_dquot_t *)((char *)XFS_BUF_PTR(bp) + dqp->q_bufoffset); | 543 | ddq = (struct xfs_disk_dquot *)(XFS_BUF_PTR(bp) + dqp->q_bufoffset); |
562 | 544 | ||
563 | /* | 545 | /* |
564 | * A simple sanity check in case we got a corrupted dquot... | 546 | * A simple sanity check in case we got a corrupted dquot... |
@@ -1176,18 +1158,18 @@ xfs_qm_dqflush( | |||
1176 | xfs_dquot_t *dqp, | 1158 | xfs_dquot_t *dqp, |
1177 | uint flags) | 1159 | uint flags) |
1178 | { | 1160 | { |
1179 | xfs_mount_t *mp; | 1161 | struct xfs_mount *mp = dqp->q_mount; |
1180 | xfs_buf_t *bp; | 1162 | struct xfs_buf *bp; |
1181 | xfs_disk_dquot_t *ddqp; | 1163 | struct xfs_disk_dquot *ddqp; |
1182 | int error; | 1164 | int error; |
1183 | 1165 | ||
1184 | ASSERT(XFS_DQ_IS_LOCKED(dqp)); | 1166 | ASSERT(XFS_DQ_IS_LOCKED(dqp)); |
1185 | ASSERT(!completion_done(&dqp->q_flush)); | 1167 | ASSERT(!completion_done(&dqp->q_flush)); |
1168 | |||
1186 | trace_xfs_dqflush(dqp); | 1169 | trace_xfs_dqflush(dqp); |
1187 | 1170 | ||
1188 | /* | 1171 | /* |
1189 | * If not dirty, or it's pinned and we are not supposed to | 1172 | * If not dirty, or it's pinned and we are not supposed to block, nada. |
1190 | * block, nada. | ||
1191 | */ | 1173 | */ |
1192 | if (!XFS_DQ_IS_DIRTY(dqp) || | 1174 | if (!XFS_DQ_IS_DIRTY(dqp) || |
1193 | (!(flags & SYNC_WAIT) && atomic_read(&dqp->q_pincount) > 0)) { | 1175 | (!(flags & SYNC_WAIT) && atomic_read(&dqp->q_pincount) > 0)) { |
@@ -1201,40 +1183,46 @@ xfs_qm_dqflush( | |||
1201 | * down forcibly. If that's the case we must not write this dquot | 1183 | * down forcibly. If that's the case we must not write this dquot |
1202 | * to disk, because the log record didn't make it to disk! | 1184 | * to disk, because the log record didn't make it to disk! |
1203 | */ | 1185 | */ |
1204 | if (XFS_FORCED_SHUTDOWN(dqp->q_mount)) { | 1186 | if (XFS_FORCED_SHUTDOWN(mp)) { |
1205 | dqp->dq_flags &= ~(XFS_DQ_DIRTY); | 1187 | dqp->dq_flags &= ~XFS_DQ_DIRTY; |
1206 | xfs_dqfunlock(dqp); | 1188 | xfs_dqfunlock(dqp); |
1207 | return XFS_ERROR(EIO); | 1189 | return XFS_ERROR(EIO); |
1208 | } | 1190 | } |
1209 | 1191 | ||
1210 | /* | 1192 | /* |
1211 | * Get the buffer containing the on-disk dquot | 1193 | * Get the buffer containing the on-disk dquot |
1212 | * We don't need a transaction envelope because we know that the | ||
1213 | * the ondisk-dquot has already been allocated for. | ||
1214 | */ | 1194 | */ |
1215 | if ((error = xfs_qm_dqtobp(NULL, dqp, &ddqp, &bp, XFS_QMOPT_DOWARN))) { | 1195 | error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, dqp->q_blkno, |
1196 | mp->m_quotainfo->qi_dqchunklen, 0, &bp); | ||
1197 | if (error) { | ||
1216 | ASSERT(error != ENOENT); | 1198 | ASSERT(error != ENOENT); |
1217 | /* | ||
1218 | * Quotas could have gotten turned off (ESRCH) | ||
1219 | */ | ||
1220 | xfs_dqfunlock(dqp); | 1199 | xfs_dqfunlock(dqp); |
1221 | return (error); | 1200 | return error; |
1222 | } | 1201 | } |
1223 | 1202 | ||
1224 | if (xfs_qm_dqcheck(&dqp->q_core, be32_to_cpu(ddqp->d_id), | 1203 | /* |
1225 | 0, XFS_QMOPT_DOWARN, "dqflush (incore copy)")) { | 1204 | * Calculate the location of the dquot inside the buffer. |
1226 | xfs_force_shutdown(dqp->q_mount, SHUTDOWN_CORRUPT_INCORE); | 1205 | */ |
1206 | ddqp = (struct xfs_disk_dquot *)(XFS_BUF_PTR(bp) + dqp->q_bufoffset); | ||
1207 | |||
1208 | /* | ||
1209 | * A simple sanity check in case we got a corrupted dquot.. | ||
1210 | */ | ||
1211 | if (xfs_qm_dqcheck(&dqp->q_core, be32_to_cpu(ddqp->d_id), 0, | ||
1212 | XFS_QMOPT_DOWARN, "dqflush (incore copy)")) { | ||
1213 | xfs_buf_relse(bp); | ||
1214 | xfs_dqfunlock(dqp); | ||
1215 | xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); | ||
1227 | return XFS_ERROR(EIO); | 1216 | return XFS_ERROR(EIO); |
1228 | } | 1217 | } |
1229 | 1218 | ||
1230 | /* This is the only portion of data that needs to persist */ | 1219 | /* This is the only portion of data that needs to persist */ |
1231 | memcpy(ddqp, &(dqp->q_core), sizeof(xfs_disk_dquot_t)); | 1220 | memcpy(ddqp, &dqp->q_core, sizeof(xfs_disk_dquot_t)); |
1232 | 1221 | ||
1233 | /* | 1222 | /* |
1234 | * Clear the dirty field and remember the flush lsn for later use. | 1223 | * Clear the dirty field and remember the flush lsn for later use. |
1235 | */ | 1224 | */ |
1236 | dqp->dq_flags &= ~(XFS_DQ_DIRTY); | 1225 | dqp->dq_flags &= ~XFS_DQ_DIRTY; |
1237 | mp = dqp->q_mount; | ||
1238 | 1226 | ||
1239 | xfs_trans_ail_copy_lsn(mp->m_ail, &dqp->q_logitem.qli_flush_lsn, | 1227 | xfs_trans_ail_copy_lsn(mp->m_ail, &dqp->q_logitem.qli_flush_lsn, |
1240 | &dqp->q_logitem.qli_item.li_lsn); | 1228 | &dqp->q_logitem.qli_item.li_lsn); |