Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 22525c17 authored by Dave Chinner's avatar Dave Chinner Committed by Darrick J. Wong
Browse files

xfs: log item flags are racy



The log item flags contain a field that is protected by the AIL
lock - the XFS_LI_IN_AIL flag. We use non-atomic RMW operations to
set and clear these flags, but most of the updates and checks are
not done with the AIL lock held and so are susceptible to update
races.

Fix this by changing the log item flags to use atomic bitops rather
than be reliant on the AIL lock for update serialisation.

Signed-Off-By: default avatarDave Chinner <dchinner@redhat.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarBrian Foster <bfoster@redhat.com>
Reviewed-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
parent 52101dfe
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -160,7 +160,7 @@ STATIC void
xfs_bui_item_unlock(
	struct xfs_log_item	*lip)
{
	if (lip->li_flags & XFS_LI_ABORTED)
	if (test_bit(XFS_LI_ABORTED, &lip->li_flags))
		xfs_bui_release(BUI_ITEM(lip));
}

@@ -305,7 +305,7 @@ xfs_bud_item_unlock(
{
	struct xfs_bud_log_item	*budp = BUD_ITEM(lip);

	if (lip->li_flags & XFS_LI_ABORTED) {
	if (test_bit(XFS_LI_ABORTED, &lip->li_flags)) {
		xfs_bui_release(budp->bud_buip);
		kmem_zone_free(xfs_bud_zone, budp);
	}
+3 −1
Original line number Diff line number Diff line
@@ -568,13 +568,15 @@ xfs_buf_item_unlock(
{
	struct xfs_buf_log_item	*bip = BUF_ITEM(lip);
	struct xfs_buf		*bp = bip->bli_buf;
	bool			aborted = !!(lip->li_flags & XFS_LI_ABORTED);
	bool			aborted;
	bool			hold = !!(bip->bli_flags & XFS_BLI_HOLD);
	bool			dirty = !!(bip->bli_flags & XFS_BLI_DIRTY);
#if defined(DEBUG) || defined(XFS_WARN)
	bool			ordered = !!(bip->bli_flags & XFS_BLI_ORDERED);
#endif

	aborted = test_bit(XFS_LI_ABORTED, &lip->li_flags);

	/* Clear the buffer's association with this transaction. */
	bp->b_transp = NULL;

+3 −4
Original line number Diff line number Diff line
@@ -913,9 +913,9 @@ xfs_qm_dqflush_done(
	 * since it's cheaper, and then we recheck while
	 * holding the lock before removing the dquot from the AIL.
	 */
	if ((lip->li_flags & XFS_LI_IN_AIL) &&
	if (test_bit(XFS_LI_IN_AIL, &lip->li_flags) &&
	    ((lip->li_lsn == qip->qli_flush_lsn) ||
	     (lip->li_flags & XFS_LI_FAILED))) {
	     test_bit(XFS_LI_FAILED, &lip->li_flags))) {

		/* xfs_trans_ail_delete() drops the AIL lock. */
		spin_lock(&ailp->ail_lock);
@@ -926,7 +926,6 @@ xfs_qm_dqflush_done(
			 * Clear the failed state since we are about to drop the
			 * flush lock
			 */
			if (lip->li_flags & XFS_LI_FAILED)
			xfs_clear_li_failed(lip);
			spin_unlock(&ailp->ail_lock);
		}
+1 −1
Original line number Diff line number Diff line
@@ -173,7 +173,7 @@ xfs_qm_dquot_logitem_push(
	 * The buffer containing this item failed to be written back
	 * previously. Resubmit the buffer for IO
	 */
	if (lip->li_flags & XFS_LI_FAILED) {
	if (test_bit(XFS_LI_FAILED, &lip->li_flags)) {
		if (!xfs_buf_trylock(bp))
			return XFS_ITEM_LOCKED;

+2 −2
Original line number Diff line number Diff line
@@ -168,7 +168,7 @@ STATIC void
xfs_efi_item_unlock(
	struct xfs_log_item	*lip)
{
	if (lip->li_flags & XFS_LI_ABORTED)
	if (test_bit(XFS_LI_ABORTED, &lip->li_flags))
		xfs_efi_release(EFI_ITEM(lip));
}

@@ -402,7 +402,7 @@ xfs_efd_item_unlock(
{
	struct xfs_efd_log_item	*efdp = EFD_ITEM(lip);

	if (lip->li_flags & XFS_LI_ABORTED) {
	if (test_bit(XFS_LI_ABORTED, &lip->li_flags)) {
		xfs_efi_release(efdp->efd_efip);
		xfs_efd_item_free(efdp);
	}
Loading