diff options
Diffstat (limited to 'fs/xfs/xfs_trans_ail.c')
-rw-r--r-- | fs/xfs/xfs_trans_ail.c | 47 |
1 files changed, 26 insertions, 21 deletions
diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c index acdb92f14d51..5fc2380092c8 100644 --- a/fs/xfs/xfs_trans_ail.c +++ b/fs/xfs/xfs_trans_ail.c | |||
@@ -346,20 +346,23 @@ xfs_ail_delete( | |||
346 | */ | 346 | */ |
347 | STATIC void | 347 | STATIC void |
348 | xfs_ail_worker( | 348 | xfs_ail_worker( |
349 | struct work_struct *work) | 349 | struct work_struct *work) |
350 | { | 350 | { |
351 | struct xfs_ail *ailp = container_of(to_delayed_work(work), | 351 | struct xfs_ail *ailp = container_of(to_delayed_work(work), |
352 | struct xfs_ail, xa_work); | 352 | struct xfs_ail, xa_work); |
353 | long tout; | 353 | xfs_mount_t *mp = ailp->xa_mount; |
354 | xfs_lsn_t target = ailp->xa_target; | ||
355 | xfs_lsn_t lsn; | ||
356 | xfs_log_item_t *lip; | ||
357 | int flush_log, count, stuck; | ||
358 | xfs_mount_t *mp = ailp->xa_mount; | ||
359 | struct xfs_ail_cursor *cur = &ailp->xa_cursors; | 354 | struct xfs_ail_cursor *cur = &ailp->xa_cursors; |
360 | int push_xfsbufd = 0; | 355 | xfs_log_item_t *lip; |
356 | xfs_lsn_t lsn; | ||
357 | xfs_lsn_t target; | ||
358 | long tout = 10; | ||
359 | int flush_log = 0; | ||
360 | int stuck = 0; | ||
361 | int count = 0; | ||
362 | int push_xfsbufd = 0; | ||
361 | 363 | ||
362 | spin_lock(&ailp->xa_lock); | 364 | spin_lock(&ailp->xa_lock); |
365 | target = ailp->xa_target; | ||
363 | xfs_trans_ail_cursor_init(ailp, cur); | 366 | xfs_trans_ail_cursor_init(ailp, cur); |
364 | 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); |
365 | if (!lip || XFS_FORCED_SHUTDOWN(mp)) { | 368 | if (!lip || XFS_FORCED_SHUTDOWN(mp)) { |
@@ -368,8 +371,7 @@ xfs_ail_worker( | |||
368 | */ | 371 | */ |
369 | xfs_trans_ail_cursor_done(ailp, cur); | 372 | xfs_trans_ail_cursor_done(ailp, cur); |
370 | spin_unlock(&ailp->xa_lock); | 373 | spin_unlock(&ailp->xa_lock); |
371 | ailp->xa_last_pushed_lsn = 0; | 374 | goto out_done; |
372 | return; | ||
373 | } | 375 | } |
374 | 376 | ||
375 | XFS_STATS_INC(xs_push_ail); | 377 | XFS_STATS_INC(xs_push_ail); |
@@ -386,8 +388,7 @@ xfs_ail_worker( | |||
386 | * lots of contention on the AIL lists. | 388 | * lots of contention on the AIL lists. |
387 | */ | 389 | */ |
388 | lsn = lip->li_lsn; | 390 | lsn = lip->li_lsn; |
389 | flush_log = stuck = count = 0; | 391 | while ((XFS_LSN_CMP(lip->li_lsn, target) <= 0)) { |
390 | while ((XFS_LSN_CMP(lip->li_lsn, target) < 0)) { | ||
391 | int lock_result; | 392 | int lock_result; |
392 | /* | 393 | /* |
393 | * If we can lock the item without sleeping, unlock the AIL | 394 | * If we can lock the item without sleeping, unlock the AIL |
@@ -480,21 +481,25 @@ xfs_ail_worker( | |||
480 | } | 481 | } |
481 | 482 | ||
482 | /* assume we have more work to do in a short while */ | 483 | /* assume we have more work to do in a short while */ |
483 | tout = 10; | 484 | out_done: |
484 | if (!count) { | 485 | if (!count) { |
485 | /* We're past our target or empty, so idle */ | 486 | /* We're past our target or empty, so idle */ |
486 | ailp->xa_last_pushed_lsn = 0; | 487 | ailp->xa_last_pushed_lsn = 0; |
487 | 488 | ||
488 | /* | 489 | /* |
489 | * Check for an updated push target before clearing the | 490 | * We clear the XFS_AIL_PUSHING_BIT first before checking |
490 | * XFS_AIL_PUSHING_BIT. If the target changed, we've got more | 491 | * whether the target has changed. If the target has changed, |
491 | * work to do. Wait a bit longer before starting that work. | 492 | * this pushes the requeue race directly onto the result of the |
493 | * atomic test/set bit, so we are guaranteed that either the | ||
494 | * the pusher that changed the target or ourselves will requeue | ||
495 | * the work (but not both). | ||
492 | */ | 496 | */ |
497 | clear_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags); | ||
493 | smp_rmb(); | 498 | smp_rmb(); |
494 | if (ailp->xa_target == target) { | 499 | if (XFS_LSN_CMP(ailp->xa_target, target) == 0 || |
495 | clear_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags); | 500 | test_and_set_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags)) |
496 | return; | 501 | return; |
497 | } | 502 | |
498 | tout = 50; | 503 | tout = 50; |
499 | } else if (XFS_LSN_CMP(lsn, target) >= 0) { | 504 | } else if (XFS_LSN_CMP(lsn, target) >= 0) { |
500 | /* | 505 | /* |
@@ -553,7 +558,7 @@ xfs_ail_push( | |||
553 | * the XFS_AIL_PUSHING_BIT. | 558 | * the XFS_AIL_PUSHING_BIT. |
554 | */ | 559 | */ |
555 | smp_wmb(); | 560 | smp_wmb(); |
556 | ailp->xa_target = threshold_lsn; | 561 | xfs_trans_ail_copy_lsn(ailp, &ailp->xa_target, &threshold_lsn); |
557 | if (!test_and_set_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags)) | 562 | if (!test_and_set_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags)) |
558 | queue_delayed_work(xfs_syncd_wq, &ailp->xa_work, 0); | 563 | queue_delayed_work(xfs_syncd_wq, &ailp->xa_work, 0); |
559 | } | 564 | } |