[XFS] Fixes a bug in the quota code when allocating a new dquot record
which can cause an extent hole to be filled and a free extent to be processed. In this case, we make a few mistakes: forget to pass back the transaction, forget to put a hold on the buffer and forget to add the buf to the new transaction. SGI-PV: 940366 SGI-Modid: xfs-linux:xfs-kern:23594a Signed-off-by: Tim Shimmin <tes@sgi.com> Signed-off-by: Nathan Scott <nathans@sgi.com>
This commit is contained in:
parent
0f9fffbcc1
commit
efa092f3d4
@ -421,7 +421,7 @@ xfs_qm_init_dquot_blk(
|
|||||||
*/
|
*/
|
||||||
STATIC int
|
STATIC int
|
||||||
xfs_qm_dqalloc(
|
xfs_qm_dqalloc(
|
||||||
xfs_trans_t *tp,
|
xfs_trans_t **tpp,
|
||||||
xfs_mount_t *mp,
|
xfs_mount_t *mp,
|
||||||
xfs_dquot_t *dqp,
|
xfs_dquot_t *dqp,
|
||||||
xfs_inode_t *quotip,
|
xfs_inode_t *quotip,
|
||||||
@ -433,6 +433,7 @@ xfs_qm_dqalloc(
|
|||||||
xfs_bmbt_irec_t map;
|
xfs_bmbt_irec_t map;
|
||||||
int nmaps, error, committed;
|
int nmaps, error, committed;
|
||||||
xfs_buf_t *bp;
|
xfs_buf_t *bp;
|
||||||
|
xfs_trans_t *tp = *tpp;
|
||||||
|
|
||||||
ASSERT(tp != NULL);
|
ASSERT(tp != NULL);
|
||||||
xfs_dqtrace_entry(dqp, "DQALLOC");
|
xfs_dqtrace_entry(dqp, "DQALLOC");
|
||||||
@ -492,10 +493,32 @@ xfs_qm_dqalloc(
|
|||||||
xfs_qm_init_dquot_blk(tp, mp, INT_GET(dqp->q_core.d_id, ARCH_CONVERT),
|
xfs_qm_init_dquot_blk(tp, mp, INT_GET(dqp->q_core.d_id, ARCH_CONVERT),
|
||||||
dqp->dq_flags & XFS_DQ_ALLTYPES, bp);
|
dqp->dq_flags & XFS_DQ_ALLTYPES, bp);
|
||||||
|
|
||||||
if ((error = xfs_bmap_finish(&tp, &flist, firstblock, &committed))) {
|
/*
|
||||||
|
* xfs_bmap_finish() may commit the current transaction and
|
||||||
|
* start a second transaction if the freelist is not empty.
|
||||||
|
*
|
||||||
|
* Since we still want to modify this buffer, we need to
|
||||||
|
* ensure that the buffer is not released on commit of
|
||||||
|
* the first transaction and ensure the buffer is added to the
|
||||||
|
* second transaction.
|
||||||
|
*
|
||||||
|
* If there is only one transaction then don't stop the buffer
|
||||||
|
* from being released when it commits later on.
|
||||||
|
*/
|
||||||
|
|
||||||
|
xfs_trans_bhold(tp, bp);
|
||||||
|
|
||||||
|
if ((error = xfs_bmap_finish(tpp, &flist, firstblock, &committed))) {
|
||||||
goto error1;
|
goto error1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (committed) {
|
||||||
|
tp = *tpp;
|
||||||
|
xfs_trans_bjoin(tp, bp);
|
||||||
|
} else {
|
||||||
|
xfs_trans_bhold_release(tp, bp);
|
||||||
|
}
|
||||||
|
|
||||||
*O_bpp = bp;
|
*O_bpp = bp;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -514,7 +537,7 @@ xfs_qm_dqalloc(
|
|||||||
*/
|
*/
|
||||||
STATIC int
|
STATIC int
|
||||||
xfs_qm_dqtobp(
|
xfs_qm_dqtobp(
|
||||||
xfs_trans_t *tp,
|
xfs_trans_t **tpp,
|
||||||
xfs_dquot_t *dqp,
|
xfs_dquot_t *dqp,
|
||||||
xfs_disk_dquot_t **O_ddpp,
|
xfs_disk_dquot_t **O_ddpp,
|
||||||
xfs_buf_t **O_bpp,
|
xfs_buf_t **O_bpp,
|
||||||
@ -528,6 +551,7 @@ xfs_qm_dqtobp(
|
|||||||
xfs_disk_dquot_t *ddq;
|
xfs_disk_dquot_t *ddq;
|
||||||
xfs_dqid_t id;
|
xfs_dqid_t id;
|
||||||
boolean_t newdquot;
|
boolean_t newdquot;
|
||||||
|
xfs_trans_t *tp = (tpp ? *tpp : NULL);
|
||||||
|
|
||||||
mp = dqp->q_mount;
|
mp = dqp->q_mount;
|
||||||
id = INT_GET(dqp->q_core.d_id, ARCH_CONVERT);
|
id = INT_GET(dqp->q_core.d_id, ARCH_CONVERT);
|
||||||
@ -579,9 +603,10 @@ xfs_qm_dqtobp(
|
|||||||
return (ENOENT);
|
return (ENOENT);
|
||||||
|
|
||||||
ASSERT(tp);
|
ASSERT(tp);
|
||||||
if ((error = xfs_qm_dqalloc(tp, mp, dqp, quotip,
|
if ((error = xfs_qm_dqalloc(tpp, mp, dqp, quotip,
|
||||||
dqp->q_fileoffset, &bp)))
|
dqp->q_fileoffset, &bp)))
|
||||||
return (error);
|
return (error);
|
||||||
|
tp = *tpp;
|
||||||
newdquot = B_TRUE;
|
newdquot = B_TRUE;
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
@ -645,7 +670,7 @@ xfs_qm_dqtobp(
|
|||||||
/* ARGSUSED */
|
/* ARGSUSED */
|
||||||
STATIC int
|
STATIC int
|
||||||
xfs_qm_dqread(
|
xfs_qm_dqread(
|
||||||
xfs_trans_t *tp,
|
xfs_trans_t **tpp,
|
||||||
xfs_dqid_t id,
|
xfs_dqid_t id,
|
||||||
xfs_dquot_t *dqp, /* dquot to get filled in */
|
xfs_dquot_t *dqp, /* dquot to get filled in */
|
||||||
uint flags)
|
uint flags)
|
||||||
@ -653,15 +678,19 @@ xfs_qm_dqread(
|
|||||||
xfs_disk_dquot_t *ddqp;
|
xfs_disk_dquot_t *ddqp;
|
||||||
xfs_buf_t *bp;
|
xfs_buf_t *bp;
|
||||||
int error;
|
int error;
|
||||||
|
xfs_trans_t *tp;
|
||||||
|
|
||||||
|
ASSERT(tpp);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get a pointer to the on-disk dquot and the buffer containing it
|
* get a pointer to the on-disk dquot and the buffer containing it
|
||||||
* dqp already knows its own type (GROUP/USER).
|
* dqp already knows its own type (GROUP/USER).
|
||||||
*/
|
*/
|
||||||
xfs_dqtrace_entry(dqp, "DQREAD");
|
xfs_dqtrace_entry(dqp, "DQREAD");
|
||||||
if ((error = xfs_qm_dqtobp(tp, dqp, &ddqp, &bp, flags))) {
|
if ((error = xfs_qm_dqtobp(tpp, dqp, &ddqp, &bp, flags))) {
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
tp = *tpp;
|
||||||
|
|
||||||
/* copy everything from disk dquot to the incore dquot */
|
/* copy everything from disk dquot to the incore dquot */
|
||||||
memcpy(&dqp->q_core, ddqp, sizeof(xfs_disk_dquot_t));
|
memcpy(&dqp->q_core, ddqp, sizeof(xfs_disk_dquot_t));
|
||||||
@ -740,7 +769,7 @@ xfs_qm_idtodq(
|
|||||||
* Read it from disk; xfs_dqread() takes care of
|
* Read it from disk; xfs_dqread() takes care of
|
||||||
* all the necessary initialization of dquot's fields (locks, etc)
|
* all the necessary initialization of dquot's fields (locks, etc)
|
||||||
*/
|
*/
|
||||||
if ((error = xfs_qm_dqread(tp, id, dqp, flags))) {
|
if ((error = xfs_qm_dqread(&tp, id, dqp, flags))) {
|
||||||
/*
|
/*
|
||||||
* This can happen if quotas got turned off (ESRCH),
|
* This can happen if quotas got turned off (ESRCH),
|
||||||
* or if the dquot didn't exist on disk and we ask to
|
* or if the dquot didn't exist on disk and we ask to
|
||||||
|
@ -999,6 +999,7 @@ struct xfs_buf *xfs_trans_getsb(xfs_trans_t *, struct xfs_mount *, int);
|
|||||||
void xfs_trans_brelse(xfs_trans_t *, struct xfs_buf *);
|
void xfs_trans_brelse(xfs_trans_t *, struct xfs_buf *);
|
||||||
void xfs_trans_bjoin(xfs_trans_t *, struct xfs_buf *);
|
void xfs_trans_bjoin(xfs_trans_t *, struct xfs_buf *);
|
||||||
void xfs_trans_bhold(xfs_trans_t *, struct xfs_buf *);
|
void xfs_trans_bhold(xfs_trans_t *, struct xfs_buf *);
|
||||||
|
void xfs_trans_bhold_release(xfs_trans_t *, struct xfs_buf *);
|
||||||
void xfs_trans_binval(xfs_trans_t *, struct xfs_buf *);
|
void xfs_trans_binval(xfs_trans_t *, struct xfs_buf *);
|
||||||
void xfs_trans_inode_buf(xfs_trans_t *, struct xfs_buf *);
|
void xfs_trans_inode_buf(xfs_trans_t *, struct xfs_buf *);
|
||||||
void xfs_trans_inode_buf(xfs_trans_t *, struct xfs_buf *);
|
void xfs_trans_inode_buf(xfs_trans_t *, struct xfs_buf *);
|
||||||
|
@ -713,6 +713,29 @@ xfs_trans_bhold(xfs_trans_t *tp,
|
|||||||
xfs_buf_item_trace("BHOLD", bip);
|
xfs_buf_item_trace("BHOLD", bip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Cancel the previous buffer hold request made on this buffer
|
||||||
|
* for this transaction.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
xfs_trans_bhold_release(xfs_trans_t *tp,
|
||||||
|
xfs_buf_t *bp)
|
||||||
|
{
|
||||||
|
xfs_buf_log_item_t *bip;
|
||||||
|
|
||||||
|
ASSERT(XFS_BUF_ISBUSY(bp));
|
||||||
|
ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp);
|
||||||
|
ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL);
|
||||||
|
|
||||||
|
bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *);
|
||||||
|
ASSERT(!(bip->bli_flags & XFS_BLI_STALE));
|
||||||
|
ASSERT(!(bip->bli_format.blf_flags & XFS_BLI_CANCEL));
|
||||||
|
ASSERT(atomic_read(&bip->bli_refcount) > 0);
|
||||||
|
ASSERT(bip->bli_flags & XFS_BLI_HOLD);
|
||||||
|
bip->bli_flags &= ~XFS_BLI_HOLD;
|
||||||
|
xfs_buf_item_trace("BHOLD RELEASE", bip);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is called to mark bytes first through last inclusive of the given
|
* This is called to mark bytes first through last inclusive of the given
|
||||||
* buffer as needing to be logged when the transaction is committed.
|
* buffer as needing to be logged when the transaction is committed.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user