aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2011-05-05 22:54:07 -0400
committerAlex Elder <aelder@sgi.com>2011-05-09 19:35:04 -0400
commitfe0da767311933d1c1907cb8d326beea7a3cbd9c (patch)
treee48cc699e05b10c61b332023a3ab8107a5d5a01a
parent50e86686dfb287d720af8b0f977202d205c04215 (diff)
xfs: make AIL target updates and compares 32bit safe.
The recent conversion of the xfsaild functionality to a work queue introduced a hard-to-hit log space grant hang. One of the problems noticed was that updates of the push target are not 32 bit safe as the target is a 64 bit value. We cannot copy a 64 bit LSN without the possibility of corrupting the result when racing with another updating thread. We have function to do this update safely without needing to care about 32/64 bit issues - xfs_trans_ail_copy_lsn() - so use that when updating the AIL push target. Also move the reading of the target in the push work inside the AIL lock, and use XFS_LSN_CMP() for the unlocked comparison during work termination to close read holes as well. Signed-off-by: Dave Chinner <david@fromorbit.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Alex Elder <aelder@sgi.com> (cherry picked from commit fd5670f22fce247754243cf2ed41941e5762d990)
-rw-r--r--fs/xfs/xfs_trans_ail.c7
1 files changed, 4 insertions, 3 deletions
diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c
index 9f427c2597bb..d7eebbf71362 100644
--- a/fs/xfs/xfs_trans_ail.c
+++ b/fs/xfs/xfs_trans_ail.c
@@ -354,7 +354,7 @@ xfs_ail_worker(
354 struct xfs_ail_cursor *cur = &ailp->xa_cursors; 354 struct xfs_ail_cursor *cur = &ailp->xa_cursors;
355 xfs_log_item_t *lip; 355 xfs_log_item_t *lip;
356 xfs_lsn_t lsn; 356 xfs_lsn_t lsn;
357 xfs_lsn_t target = ailp->xa_target; 357 xfs_lsn_t target;
358 long tout = 10; 358 long tout = 10;
359 int flush_log = 0; 359 int flush_log = 0;
360 int stuck = 0; 360 int stuck = 0;
@@ -362,6 +362,7 @@ xfs_ail_worker(
362 int push_xfsbufd = 0; 362 int push_xfsbufd = 0;
363 363
364 spin_lock(&ailp->xa_lock); 364 spin_lock(&ailp->xa_lock);
365 target = ailp->xa_target;
365 xfs_trans_ail_cursor_init(ailp, cur); 366 xfs_trans_ail_cursor_init(ailp, cur);
366 lip = xfs_trans_ail_cursor_first(ailp, cur, ailp->xa_last_pushed_lsn); 367 lip = xfs_trans_ail_cursor_first(ailp, cur, ailp->xa_last_pushed_lsn);
367 if (!lip || XFS_FORCED_SHUTDOWN(mp)) { 368 if (!lip || XFS_FORCED_SHUTDOWN(mp)) {
@@ -491,7 +492,7 @@ out_done:
491 * work to do. Wait a bit longer before starting that work. 492 * work to do. Wait a bit longer before starting that work.
492 */ 493 */
493 smp_rmb(); 494 smp_rmb();
494 if (ailp->xa_target == target) { 495 if (XFS_LSN_CMP(ailp->xa_target, target) == 0) {
495 clear_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags); 496 clear_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags);
496 return; 497 return;
497 } 498 }
@@ -553,7 +554,7 @@ xfs_ail_push(
553 * the XFS_AIL_PUSHING_BIT. 554 * the XFS_AIL_PUSHING_BIT.
554 */ 555 */
555 smp_wmb(); 556 smp_wmb();
556 ailp->xa_target = threshold_lsn; 557 xfs_trans_ail_copy_lsn(ailp, &ailp->xa_target, &threshold_lsn);
557 if (!test_and_set_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags)) 558 if (!test_and_set_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags))
558 queue_delayed_work(xfs_syncd_wq, &ailp->xa_work, 0); 559 queue_delayed_work(xfs_syncd_wq, &ailp->xa_work, 0);
559} 560}