summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2018-05-09 10:47:34 -0400
committerDarrick J. Wong <darrick.wong@oracle.com>2018-05-10 11:56:41 -0400
commit22525c17ed133202088f6f05acd9c53790a7121d (patch)
tree1447ecb5ace55b30f6ed03cf47f7121cce42418f
parent52101dfe56f71d8cb140c2440d95affa25a53746 (diff)
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: Dave Chinner <dchinner@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Brian Foster <bfoster@redhat.com> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
-rw-r--r--fs/xfs/xfs_bmap_item.c4
-rw-r--r--fs/xfs/xfs_buf_item.c4
-rw-r--r--fs/xfs/xfs_dquot.c7
-rw-r--r--fs/xfs/xfs_dquot_item.c2
-rw-r--r--fs/xfs/xfs_extfree_item.c4
-rw-r--r--fs/xfs/xfs_icache.c3
-rw-r--r--fs/xfs/xfs_icreate_item.c2
-rw-r--r--fs/xfs/xfs_inode.c4
-rw-r--r--fs/xfs/xfs_inode_item.c8
-rw-r--r--fs/xfs/xfs_log.c2
-rw-r--r--fs/xfs/xfs_qm.c2
-rw-r--r--fs/xfs/xfs_refcount_item.c4
-rw-r--r--fs/xfs/xfs_rmap_item.c4
-rw-r--r--fs/xfs/xfs_trace.h6
-rw-r--r--fs/xfs/xfs_trans.c4
-rw-r--r--fs/xfs/xfs_trans.h19
-rw-r--r--fs/xfs/xfs_trans_ail.c9
-rw-r--r--fs/xfs/xfs_trans_buf.c2
-rw-r--r--fs/xfs/xfs_trans_priv.h10
19 files changed, 52 insertions, 48 deletions
diff --git a/fs/xfs/xfs_bmap_item.c b/fs/xfs/xfs_bmap_item.c
index 2203465e63ea..618bb71535c8 100644
--- a/fs/xfs/xfs_bmap_item.c
+++ b/fs/xfs/xfs_bmap_item.c
@@ -160,7 +160,7 @@ STATIC void
160xfs_bui_item_unlock( 160xfs_bui_item_unlock(
161 struct xfs_log_item *lip) 161 struct xfs_log_item *lip)
162{ 162{
163 if (lip->li_flags & XFS_LI_ABORTED) 163 if (test_bit(XFS_LI_ABORTED, &lip->li_flags))
164 xfs_bui_release(BUI_ITEM(lip)); 164 xfs_bui_release(BUI_ITEM(lip));
165} 165}
166 166
@@ -305,7 +305,7 @@ xfs_bud_item_unlock(
305{ 305{
306 struct xfs_bud_log_item *budp = BUD_ITEM(lip); 306 struct xfs_bud_log_item *budp = BUD_ITEM(lip);
307 307
308 if (lip->li_flags & XFS_LI_ABORTED) { 308 if (test_bit(XFS_LI_ABORTED, &lip->li_flags)) {
309 xfs_bui_release(budp->bud_buip); 309 xfs_bui_release(budp->bud_buip);
310 kmem_zone_free(xfs_bud_zone, budp); 310 kmem_zone_free(xfs_bud_zone, budp);
311 } 311 }
diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c
index 82ad270e390e..df62082f2204 100644
--- a/fs/xfs/xfs_buf_item.c
+++ b/fs/xfs/xfs_buf_item.c
@@ -568,13 +568,15 @@ xfs_buf_item_unlock(
568{ 568{
569 struct xfs_buf_log_item *bip = BUF_ITEM(lip); 569 struct xfs_buf_log_item *bip = BUF_ITEM(lip);
570 struct xfs_buf *bp = bip->bli_buf; 570 struct xfs_buf *bp = bip->bli_buf;
571 bool aborted = !!(lip->li_flags & XFS_LI_ABORTED); 571 bool aborted;
572 bool hold = !!(bip->bli_flags & XFS_BLI_HOLD); 572 bool hold = !!(bip->bli_flags & XFS_BLI_HOLD);
573 bool dirty = !!(bip->bli_flags & XFS_BLI_DIRTY); 573 bool dirty = !!(bip->bli_flags & XFS_BLI_DIRTY);
574#if defined(DEBUG) || defined(XFS_WARN) 574#if defined(DEBUG) || defined(XFS_WARN)
575 bool ordered = !!(bip->bli_flags & XFS_BLI_ORDERED); 575 bool ordered = !!(bip->bli_flags & XFS_BLI_ORDERED);
576#endif 576#endif
577 577
578 aborted = test_bit(XFS_LI_ABORTED, &lip->li_flags);
579
578 /* Clear the buffer's association with this transaction. */ 580 /* Clear the buffer's association with this transaction. */
579 bp->b_transp = NULL; 581 bp->b_transp = NULL;
580 582
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index d0880c1add41..4ca9c39879ae 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -913,9 +913,9 @@ xfs_qm_dqflush_done(
913 * since it's cheaper, and then we recheck while 913 * since it's cheaper, and then we recheck while
914 * holding the lock before removing the dquot from the AIL. 914 * holding the lock before removing the dquot from the AIL.
915 */ 915 */
916 if ((lip->li_flags & XFS_LI_IN_AIL) && 916 if (test_bit(XFS_LI_IN_AIL, &lip->li_flags) &&
917 ((lip->li_lsn == qip->qli_flush_lsn) || 917 ((lip->li_lsn == qip->qli_flush_lsn) ||
918 (lip->li_flags & XFS_LI_FAILED))) { 918 test_bit(XFS_LI_FAILED, &lip->li_flags))) {
919 919
920 /* xfs_trans_ail_delete() drops the AIL lock. */ 920 /* xfs_trans_ail_delete() drops the AIL lock. */
921 spin_lock(&ailp->ail_lock); 921 spin_lock(&ailp->ail_lock);
@@ -926,8 +926,7 @@ xfs_qm_dqflush_done(
926 * Clear the failed state since we are about to drop the 926 * Clear the failed state since we are about to drop the
927 * flush lock 927 * flush lock
928 */ 928 */
929 if (lip->li_flags & XFS_LI_FAILED) 929 xfs_clear_li_failed(lip);
930 xfs_clear_li_failed(lip);
931 spin_unlock(&ailp->ail_lock); 930 spin_unlock(&ailp->ail_lock);
932 } 931 }
933 } 932 }
diff --git a/fs/xfs/xfs_dquot_item.c b/fs/xfs/xfs_dquot_item.c
index 4b331e354da7..57df98122156 100644
--- a/fs/xfs/xfs_dquot_item.c
+++ b/fs/xfs/xfs_dquot_item.c
@@ -173,7 +173,7 @@ xfs_qm_dquot_logitem_push(
173 * The buffer containing this item failed to be written back 173 * The buffer containing this item failed to be written back
174 * previously. Resubmit the buffer for IO 174 * previously. Resubmit the buffer for IO
175 */ 175 */
176 if (lip->li_flags & XFS_LI_FAILED) { 176 if (test_bit(XFS_LI_FAILED, &lip->li_flags)) {
177 if (!xfs_buf_trylock(bp)) 177 if (!xfs_buf_trylock(bp))
178 return XFS_ITEM_LOCKED; 178 return XFS_ITEM_LOCKED;
179 179
diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c
index b5b1e567b9f4..70b7d48af6d6 100644
--- a/fs/xfs/xfs_extfree_item.c
+++ b/fs/xfs/xfs_extfree_item.c
@@ -168,7 +168,7 @@ STATIC void
168xfs_efi_item_unlock( 168xfs_efi_item_unlock(
169 struct xfs_log_item *lip) 169 struct xfs_log_item *lip)
170{ 170{
171 if (lip->li_flags & XFS_LI_ABORTED) 171 if (test_bit(XFS_LI_ABORTED, &lip->li_flags))
172 xfs_efi_release(EFI_ITEM(lip)); 172 xfs_efi_release(EFI_ITEM(lip));
173} 173}
174 174
@@ -402,7 +402,7 @@ xfs_efd_item_unlock(
402{ 402{
403 struct xfs_efd_log_item *efdp = EFD_ITEM(lip); 403 struct xfs_efd_log_item *efdp = EFD_ITEM(lip);
404 404
405 if (lip->li_flags & XFS_LI_ABORTED) { 405 if (test_bit(XFS_LI_ABORTED, &lip->li_flags)) {
406 xfs_efi_release(efdp->efd_efip); 406 xfs_efi_release(efdp->efd_efip);
407 xfs_efd_item_free(efdp); 407 xfs_efd_item_free(efdp);
408 } 408 }
diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c
index 817899961f48..9deff136c5b9 100644
--- a/fs/xfs/xfs_icache.c
+++ b/fs/xfs/xfs_icache.c
@@ -107,7 +107,8 @@ xfs_inode_free_callback(
107 xfs_idestroy_fork(ip, XFS_COW_FORK); 107 xfs_idestroy_fork(ip, XFS_COW_FORK);
108 108
109 if (ip->i_itemp) { 109 if (ip->i_itemp) {
110 ASSERT(!(ip->i_itemp->ili_item.li_flags & XFS_LI_IN_AIL)); 110 ASSERT(!test_bit(XFS_LI_IN_AIL,
111 &ip->i_itemp->ili_item.li_flags));
111 xfs_inode_item_destroy(ip); 112 xfs_inode_item_destroy(ip);
112 ip->i_itemp = NULL; 113 ip->i_itemp = NULL;
113 } 114 }
diff --git a/fs/xfs/xfs_icreate_item.c b/fs/xfs/xfs_icreate_item.c
index 865ad1373e5e..a99a0f8aa528 100644
--- a/fs/xfs/xfs_icreate_item.c
+++ b/fs/xfs/xfs_icreate_item.c
@@ -91,7 +91,7 @@ xfs_icreate_item_unlock(
91{ 91{
92 struct xfs_icreate_item *icp = ICR_ITEM(lip); 92 struct xfs_icreate_item *icp = ICR_ITEM(lip);
93 93
94 if (icp->ic_item.li_flags & XFS_LI_ABORTED) 94 if (test_bit(XFS_LI_ABORTED, &lip->li_flags))
95 kmem_zone_free(xfs_icreate_zone, icp); 95 kmem_zone_free(xfs_icreate_zone, icp);
96 return; 96 return;
97} 97}
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index d9b91606d2a3..42781bae6794 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -498,7 +498,7 @@ again:
498 if (!try_lock) { 498 if (!try_lock) {
499 for (j = (i - 1); j >= 0 && !try_lock; j--) { 499 for (j = (i - 1); j >= 0 && !try_lock; j--) {
500 lp = (xfs_log_item_t *)ips[j]->i_itemp; 500 lp = (xfs_log_item_t *)ips[j]->i_itemp;
501 if (lp && (lp->li_flags & XFS_LI_IN_AIL)) 501 if (lp && test_bit(XFS_LI_IN_AIL, &lp->li_flags))
502 try_lock++; 502 try_lock++;
503 } 503 }
504 } 504 }
@@ -598,7 +598,7 @@ xfs_lock_two_inodes(
598 * and try again. 598 * and try again.
599 */ 599 */
600 lp = (xfs_log_item_t *)ip0->i_itemp; 600 lp = (xfs_log_item_t *)ip0->i_itemp;
601 if (lp && (lp->li_flags & XFS_LI_IN_AIL)) { 601 if (lp && test_bit(XFS_LI_IN_AIL, &lp->li_flags)) {
602 if (!xfs_ilock_nowait(ip1, xfs_lock_inumorder(ip1_mode, 1))) { 602 if (!xfs_ilock_nowait(ip1, xfs_lock_inumorder(ip1_mode, 1))) {
603 xfs_iunlock(ip0, ip0_mode); 603 xfs_iunlock(ip0, ip0_mode);
604 if ((++attempts % 5) == 0) 604 if ((++attempts % 5) == 0)
diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
index 34b91b789702..3e5b8574818e 100644
--- a/fs/xfs/xfs_inode_item.c
+++ b/fs/xfs/xfs_inode_item.c
@@ -518,7 +518,7 @@ xfs_inode_item_push(
518 * The buffer containing this item failed to be written back 518 * The buffer containing this item failed to be written back
519 * previously. Resubmit the buffer for IO. 519 * previously. Resubmit the buffer for IO.
520 */ 520 */
521 if (lip->li_flags & XFS_LI_FAILED) { 521 if (test_bit(XFS_LI_FAILED, &lip->li_flags)) {
522 if (!xfs_buf_trylock(bp)) 522 if (!xfs_buf_trylock(bp))
523 return XFS_ITEM_LOCKED; 523 return XFS_ITEM_LOCKED;
524 524
@@ -729,14 +729,14 @@ xfs_iflush_done(
729 */ 729 */
730 iip = INODE_ITEM(blip); 730 iip = INODE_ITEM(blip);
731 if ((iip->ili_logged && blip->li_lsn == iip->ili_flush_lsn) || 731 if ((iip->ili_logged && blip->li_lsn == iip->ili_flush_lsn) ||
732 (blip->li_flags & XFS_LI_FAILED)) 732 test_bit(XFS_LI_FAILED, &blip->li_flags))
733 need_ail++; 733 need_ail++;
734 } 734 }
735 735
736 /* make sure we capture the state of the initial inode. */ 736 /* make sure we capture the state of the initial inode. */
737 iip = INODE_ITEM(lip); 737 iip = INODE_ITEM(lip);
738 if ((iip->ili_logged && lip->li_lsn == iip->ili_flush_lsn) || 738 if ((iip->ili_logged && lip->li_lsn == iip->ili_flush_lsn) ||
739 lip->li_flags & XFS_LI_FAILED) 739 test_bit(XFS_LI_FAILED, &lip->li_flags))
740 need_ail++; 740 need_ail++;
741 741
742 /* 742 /*
@@ -803,7 +803,7 @@ xfs_iflush_abort(
803 xfs_inode_log_item_t *iip = ip->i_itemp; 803 xfs_inode_log_item_t *iip = ip->i_itemp;
804 804
805 if (iip) { 805 if (iip) {
806 if (iip->ili_item.li_flags & XFS_LI_IN_AIL) { 806 if (test_bit(XFS_LI_IN_AIL, &iip->ili_item.li_flags)) {
807 xfs_trans_ail_remove(&iip->ili_item, 807 xfs_trans_ail_remove(&iip->ili_item,
808 stale ? SHUTDOWN_LOG_IO_ERROR : 808 stale ? SHUTDOWN_LOG_IO_ERROR :
809 SHUTDOWN_CORRUPT_INCORE); 809 SHUTDOWN_CORRUPT_INCORE);
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
index 2fcd9ed5d075..e427864434c1 100644
--- a/fs/xfs/xfs_log.c
+++ b/fs/xfs/xfs_log.c
@@ -2132,7 +2132,7 @@ xlog_print_trans(
2132 2132
2133 xfs_warn(mp, "log item: "); 2133 xfs_warn(mp, "log item: ");
2134 xfs_warn(mp, " type = 0x%x", lip->li_type); 2134 xfs_warn(mp, " type = 0x%x", lip->li_type);
2135 xfs_warn(mp, " flags = 0x%x", lip->li_flags); 2135 xfs_warn(mp, " flags = 0x%lx", lip->li_flags);
2136 if (!lv) 2136 if (!lv)
2137 continue; 2137 continue;
2138 xfs_warn(mp, " niovecs = %d", lv->lv_niovecs); 2138 xfs_warn(mp, " niovecs = %d", lv->lv_niovecs);
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index c72a8da55703..62764f3e35e2 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -173,7 +173,7 @@ xfs_qm_dqpurge(
173 173
174 ASSERT(atomic_read(&dqp->q_pincount) == 0); 174 ASSERT(atomic_read(&dqp->q_pincount) == 0);
175 ASSERT(XFS_FORCED_SHUTDOWN(mp) || 175 ASSERT(XFS_FORCED_SHUTDOWN(mp) ||
176 !(dqp->q_logitem.qli_item.li_flags & XFS_LI_IN_AIL)); 176 !test_bit(XFS_LI_IN_AIL, &dqp->q_logitem.qli_item.li_flags));
177 177
178 xfs_dqfunlock(dqp); 178 xfs_dqfunlock(dqp);
179 xfs_dqunlock(dqp); 179 xfs_dqunlock(dqp);
diff --git a/fs/xfs/xfs_refcount_item.c b/fs/xfs/xfs_refcount_item.c
index 15c9393dd7a7..e5866b714d5f 100644
--- a/fs/xfs/xfs_refcount_item.c
+++ b/fs/xfs/xfs_refcount_item.c
@@ -159,7 +159,7 @@ STATIC void
159xfs_cui_item_unlock( 159xfs_cui_item_unlock(
160 struct xfs_log_item *lip) 160 struct xfs_log_item *lip)
161{ 161{
162 if (lip->li_flags & XFS_LI_ABORTED) 162 if (test_bit(XFS_LI_ABORTED, &lip->li_flags))
163 xfs_cui_release(CUI_ITEM(lip)); 163 xfs_cui_release(CUI_ITEM(lip));
164} 164}
165 165
@@ -310,7 +310,7 @@ xfs_cud_item_unlock(
310{ 310{
311 struct xfs_cud_log_item *cudp = CUD_ITEM(lip); 311 struct xfs_cud_log_item *cudp = CUD_ITEM(lip);
312 312
313 if (lip->li_flags & XFS_LI_ABORTED) { 313 if (test_bit(XFS_LI_ABORTED, &lip->li_flags)) {
314 xfs_cui_release(cudp->cud_cuip); 314 xfs_cui_release(cudp->cud_cuip);
315 kmem_zone_free(xfs_cud_zone, cudp); 315 kmem_zone_free(xfs_cud_zone, cudp);
316 } 316 }
diff --git a/fs/xfs/xfs_rmap_item.c b/fs/xfs/xfs_rmap_item.c
index 06a07846c9b3..e5b5b3e7ef82 100644
--- a/fs/xfs/xfs_rmap_item.c
+++ b/fs/xfs/xfs_rmap_item.c
@@ -158,7 +158,7 @@ STATIC void
158xfs_rui_item_unlock( 158xfs_rui_item_unlock(
159 struct xfs_log_item *lip) 159 struct xfs_log_item *lip)
160{ 160{
161 if (lip->li_flags & XFS_LI_ABORTED) 161 if (test_bit(XFS_LI_ABORTED, &lip->li_flags))
162 xfs_rui_release(RUI_ITEM(lip)); 162 xfs_rui_release(RUI_ITEM(lip));
163} 163}
164 164
@@ -331,7 +331,7 @@ xfs_rud_item_unlock(
331{ 331{
332 struct xfs_rud_log_item *rudp = RUD_ITEM(lip); 332 struct xfs_rud_log_item *rudp = RUD_ITEM(lip);
333 333
334 if (lip->li_flags & XFS_LI_ABORTED) { 334 if (test_bit(XFS_LI_ABORTED, &lip->li_flags)) {
335 xfs_rui_release(rudp->rud_ruip); 335 xfs_rui_release(rudp->rud_ruip);
336 kmem_zone_free(xfs_rud_zone, rudp); 336 kmem_zone_free(xfs_rud_zone, rudp);
337 } 337 }
diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
index 24892259301e..989708d06e10 100644
--- a/fs/xfs/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
@@ -442,7 +442,7 @@ DECLARE_EVENT_CLASS(xfs_buf_item_class,
442 __field(int, bli_refcount) 442 __field(int, bli_refcount)
443 __field(unsigned, bli_flags) 443 __field(unsigned, bli_flags)
444 __field(void *, li_desc) 444 __field(void *, li_desc)
445 __field(unsigned, li_flags) 445 __field(unsigned long, li_flags)
446 ), 446 ),
447 TP_fast_assign( 447 TP_fast_assign(
448 __entry->dev = bip->bli_buf->b_target->bt_dev; 448 __entry->dev = bip->bli_buf->b_target->bt_dev;
@@ -1018,7 +1018,7 @@ DECLARE_EVENT_CLASS(xfs_log_item_class,
1018 __field(dev_t, dev) 1018 __field(dev_t, dev)
1019 __field(void *, lip) 1019 __field(void *, lip)
1020 __field(uint, type) 1020 __field(uint, type)
1021 __field(uint, flags) 1021 __field(unsigned long, flags)
1022 __field(xfs_lsn_t, lsn) 1022 __field(xfs_lsn_t, lsn)
1023 ), 1023 ),
1024 TP_fast_assign( 1024 TP_fast_assign(
@@ -1070,7 +1070,7 @@ DECLARE_EVENT_CLASS(xfs_ail_class,
1070 __field(dev_t, dev) 1070 __field(dev_t, dev)
1071 __field(void *, lip) 1071 __field(void *, lip)
1072 __field(uint, type) 1072 __field(uint, type)
1073 __field(uint, flags) 1073 __field(unsigned long, flags)
1074 __field(xfs_lsn_t, old_lsn) 1074 __field(xfs_lsn_t, old_lsn)
1075 __field(xfs_lsn_t, new_lsn) 1075 __field(xfs_lsn_t, new_lsn)
1076 ), 1076 ),
diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c
index 06adb1a3e31f..83f2032641cf 100644
--- a/fs/xfs/xfs_trans.c
+++ b/fs/xfs/xfs_trans.c
@@ -792,7 +792,7 @@ xfs_trans_free_items(
792 if (commit_lsn != NULLCOMMITLSN) 792 if (commit_lsn != NULLCOMMITLSN)
793 lip->li_ops->iop_committing(lip, commit_lsn); 793 lip->li_ops->iop_committing(lip, commit_lsn);
794 if (abort) 794 if (abort)
795 lip->li_flags |= XFS_LI_ABORTED; 795 set_bit(XFS_LI_ABORTED, &lip->li_flags);
796 lip->li_ops->iop_unlock(lip); 796 lip->li_ops->iop_unlock(lip);
797 797
798 xfs_trans_free_item_desc(lidp); 798 xfs_trans_free_item_desc(lidp);
@@ -863,7 +863,7 @@ xfs_trans_committed_bulk(
863 xfs_lsn_t item_lsn; 863 xfs_lsn_t item_lsn;
864 864
865 if (aborted) 865 if (aborted)
866 lip->li_flags |= XFS_LI_ABORTED; 866 set_bit(XFS_LI_ABORTED, &lip->li_flags);
867 item_lsn = lip->li_ops->iop_committed(lip, commit_lsn); 867 item_lsn = lip->li_ops->iop_committed(lip, commit_lsn);
868 868
869 /* item_lsn of -1 means the item needs no further processing */ 869 /* item_lsn of -1 means the item needs no further processing */
diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
index 834388c2c9de..ca449036f820 100644
--- a/fs/xfs/xfs_trans.h
+++ b/fs/xfs/xfs_trans.h
@@ -48,7 +48,7 @@ typedef struct xfs_log_item {
48 struct xfs_mount *li_mountp; /* ptr to fs mount */ 48 struct xfs_mount *li_mountp; /* ptr to fs mount */
49 struct xfs_ail *li_ailp; /* ptr to AIL */ 49 struct xfs_ail *li_ailp; /* ptr to AIL */
50 uint li_type; /* item type */ 50 uint li_type; /* item type */
51 uint li_flags; /* misc flags */ 51 unsigned long li_flags; /* misc flags */
52 struct xfs_buf *li_buf; /* real buffer pointer */ 52 struct xfs_buf *li_buf; /* real buffer pointer */
53 struct list_head li_bio_list; /* buffer item list */ 53 struct list_head li_bio_list; /* buffer item list */
54 void (*li_cb)(struct xfs_buf *, 54 void (*li_cb)(struct xfs_buf *,
@@ -64,14 +64,19 @@ typedef struct xfs_log_item {
64 xfs_lsn_t li_seq; /* CIL commit seq */ 64 xfs_lsn_t li_seq; /* CIL commit seq */
65} xfs_log_item_t; 65} xfs_log_item_t;
66 66
67#define XFS_LI_IN_AIL 0x1 67/*
68#define XFS_LI_ABORTED 0x2 68 * li_flags use the (set/test/clear)_bit atomic interfaces because updates can
69#define XFS_LI_FAILED 0x4 69 * race with each other and we don't want to have to use the AIL lock to
70 * serialise all updates.
71 */
72#define XFS_LI_IN_AIL 0
73#define XFS_LI_ABORTED 1
74#define XFS_LI_FAILED 2
70 75
71#define XFS_LI_FLAGS \ 76#define XFS_LI_FLAGS \
72 { XFS_LI_IN_AIL, "IN_AIL" }, \ 77 { (1 << XFS_LI_IN_AIL), "IN_AIL" }, \
73 { XFS_LI_ABORTED, "ABORTED" }, \ 78 { (1 << XFS_LI_ABORTED), "ABORTED" }, \
74 { XFS_LI_FAILED, "FAILED" } 79 { (1 << XFS_LI_FAILED), "FAILED" }
75 80
76struct xfs_item_ops { 81struct xfs_item_ops {
77 void (*iop_size)(xfs_log_item_t *, int *, int *); 82 void (*iop_size)(xfs_log_item_t *, int *, int *);
diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c
index d4a2445215e6..50611d2bcbc2 100644
--- a/fs/xfs/xfs_trans_ail.c
+++ b/fs/xfs/xfs_trans_ail.c
@@ -46,7 +46,7 @@ xfs_ail_check(
46 /* 46 /*
47 * Check the next and previous entries are valid. 47 * Check the next and previous entries are valid.
48 */ 48 */
49 ASSERT((lip->li_flags & XFS_LI_IN_AIL) != 0); 49 ASSERT(test_bit(XFS_LI_IN_AIL, &lip->li_flags));
50 prev_lip = list_entry(lip->li_ail.prev, xfs_log_item_t, li_ail); 50 prev_lip = list_entry(lip->li_ail.prev, xfs_log_item_t, li_ail);
51 if (&prev_lip->li_ail != &ailp->ail_head) 51 if (&prev_lip->li_ail != &ailp->ail_head)
52 ASSERT(XFS_LSN_CMP(prev_lip->li_lsn, lip->li_lsn) <= 0); 52 ASSERT(XFS_LSN_CMP(prev_lip->li_lsn, lip->li_lsn) <= 0);
@@ -684,7 +684,7 @@ xfs_trans_ail_update_bulk(
684 684
685 for (i = 0; i < nr_items; i++) { 685 for (i = 0; i < nr_items; i++) {
686 struct xfs_log_item *lip = log_items[i]; 686 struct xfs_log_item *lip = log_items[i];
687 if (lip->li_flags & XFS_LI_IN_AIL) { 687 if (test_and_set_bit(XFS_LI_IN_AIL, &lip->li_flags)) {
688 /* check if we really need to move the item */ 688 /* check if we really need to move the item */
689 if (XFS_LSN_CMP(lsn, lip->li_lsn) <= 0) 689 if (XFS_LSN_CMP(lsn, lip->li_lsn) <= 0)
690 continue; 690 continue;
@@ -694,7 +694,6 @@ xfs_trans_ail_update_bulk(
694 if (mlip == lip) 694 if (mlip == lip)
695 mlip_changed = 1; 695 mlip_changed = 1;
696 } else { 696 } else {
697 lip->li_flags |= XFS_LI_IN_AIL;
698 trace_xfs_ail_insert(lip, 0, lsn); 697 trace_xfs_ail_insert(lip, 0, lsn);
699 } 698 }
700 lip->li_lsn = lsn; 699 lip->li_lsn = lsn;
@@ -725,7 +724,7 @@ xfs_ail_delete_one(
725 trace_xfs_ail_delete(lip, mlip->li_lsn, lip->li_lsn); 724 trace_xfs_ail_delete(lip, mlip->li_lsn, lip->li_lsn);
726 xfs_ail_delete(ailp, lip); 725 xfs_ail_delete(ailp, lip);
727 xfs_clear_li_failed(lip); 726 xfs_clear_li_failed(lip);
728 lip->li_flags &= ~XFS_LI_IN_AIL; 727 clear_bit(XFS_LI_IN_AIL, &lip->li_flags);
729 lip->li_lsn = 0; 728 lip->li_lsn = 0;
730 729
731 return mlip == lip; 730 return mlip == lip;
@@ -761,7 +760,7 @@ xfs_trans_ail_delete(
761 struct xfs_mount *mp = ailp->ail_mount; 760 struct xfs_mount *mp = ailp->ail_mount;
762 bool mlip_changed; 761 bool mlip_changed;
763 762
764 if (!(lip->li_flags & XFS_LI_IN_AIL)) { 763 if (!test_bit(XFS_LI_IN_AIL, &lip->li_flags)) {
765 spin_unlock(&ailp->ail_lock); 764 spin_unlock(&ailp->ail_lock);
766 if (!XFS_FORCED_SHUTDOWN(mp)) { 765 if (!XFS_FORCED_SHUTDOWN(mp)) {
767 xfs_alert_tag(mp, XFS_PTAG_AILDELETE, 766 xfs_alert_tag(mp, XFS_PTAG_AILDELETE,
diff --git a/fs/xfs/xfs_trans_buf.c b/fs/xfs/xfs_trans_buf.c
index a5d9dfc45d98..0081e9b3decf 100644
--- a/fs/xfs/xfs_trans_buf.c
+++ b/fs/xfs/xfs_trans_buf.c
@@ -442,7 +442,7 @@ xfs_trans_brelse(
442 ASSERT(bp->b_pincount == 0); 442 ASSERT(bp->b_pincount == 0);
443***/ 443***/
444 ASSERT(atomic_read(&bip->bli_refcount) == 0); 444 ASSERT(atomic_read(&bip->bli_refcount) == 0);
445 ASSERT(!(bip->bli_item.li_flags & XFS_LI_IN_AIL)); 445 ASSERT(!test_bit(XFS_LI_IN_AIL, &bip->bli_item.li_flags));
446 ASSERT(!(bip->bli_flags & XFS_BLI_INODE_ALLOC_BUF)); 446 ASSERT(!(bip->bli_flags & XFS_BLI_INODE_ALLOC_BUF));
447 xfs_buf_item_relse(bp); 447 xfs_buf_item_relse(bp);
448 } 448 }
diff --git a/fs/xfs/xfs_trans_priv.h b/fs/xfs/xfs_trans_priv.h
index be24b0c8a332..43f773297b9d 100644
--- a/fs/xfs/xfs_trans_priv.h
+++ b/fs/xfs/xfs_trans_priv.h
@@ -119,7 +119,7 @@ xfs_trans_ail_remove(
119 119
120 spin_lock(&ailp->ail_lock); 120 spin_lock(&ailp->ail_lock);
121 /* xfs_trans_ail_delete() drops the AIL lock */ 121 /* xfs_trans_ail_delete() drops the AIL lock */
122 if (lip->li_flags & XFS_LI_IN_AIL) 122 if (test_bit(XFS_LI_IN_AIL, &lip->li_flags))
123 xfs_trans_ail_delete(ailp, lip, shutdown_type); 123 xfs_trans_ail_delete(ailp, lip, shutdown_type);
124 else 124 else
125 spin_unlock(&ailp->ail_lock); 125 spin_unlock(&ailp->ail_lock);
@@ -171,11 +171,10 @@ xfs_clear_li_failed(
171{ 171{
172 struct xfs_buf *bp = lip->li_buf; 172 struct xfs_buf *bp = lip->li_buf;
173 173
174 ASSERT(lip->li_flags & XFS_LI_IN_AIL); 174 ASSERT(test_bit(XFS_LI_IN_AIL, &lip->li_flags));
175 lockdep_assert_held(&lip->li_ailp->ail_lock); 175 lockdep_assert_held(&lip->li_ailp->ail_lock);
176 176
177 if (lip->li_flags & XFS_LI_FAILED) { 177 if (test_and_clear_bit(XFS_LI_FAILED, &lip->li_flags)) {
178 lip->li_flags &= ~XFS_LI_FAILED;
179 lip->li_buf = NULL; 178 lip->li_buf = NULL;
180 xfs_buf_rele(bp); 179 xfs_buf_rele(bp);
181 } 180 }
@@ -188,9 +187,8 @@ xfs_set_li_failed(
188{ 187{
189 lockdep_assert_held(&lip->li_ailp->ail_lock); 188 lockdep_assert_held(&lip->li_ailp->ail_lock);
190 189
191 if (!(lip->li_flags & XFS_LI_FAILED)) { 190 if (!test_and_set_bit(XFS_LI_FAILED, &lip->li_flags)) {
192 xfs_buf_hold(bp); 191 xfs_buf_hold(bp);
193 lip->li_flags |= XFS_LI_FAILED;
194 lip->li_buf = bp; 192 lip->li_buf = bp;
195 } 193 }
196} 194}