diff options
| author | Dave Chinner <dchinner@redhat.com> | 2011-05-05 22:54:07 -0400 |
|---|---|---|
| committer | Alex Elder <aelder@sgi.com> | 2011-05-09 13:17:04 -0400 |
| commit | fd5670f22fce247754243cf2ed41941e5762d990 (patch) | |
| tree | 4574bf415df6d3c8a5c501ee3b02727dd573ba03 | |
| parent | cb64026b6e8af50db598ec7c3f59d504259b00bb (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>
| -rw-r--r-- | fs/xfs/xfs_trans_ail.c | 7 |
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 | } |
