diff options
| -rw-r--r-- | fs/xfs/xfs_trans_ail.c | 35 | ||||
| -rw-r--r-- | fs/xfs/xfs_trans_priv.h | 1 |
2 files changed, 33 insertions, 3 deletions
diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c index 9c514483e599..6011ee661339 100644 --- a/fs/xfs/xfs_trans_ail.c +++ b/fs/xfs/xfs_trans_ail.c | |||
| @@ -383,6 +383,12 @@ xfsaild_push( | |||
| 383 | } | 383 | } |
| 384 | 384 | ||
| 385 | spin_lock(&ailp->xa_lock); | 385 | spin_lock(&ailp->xa_lock); |
| 386 | |||
| 387 | /* barrier matches the xa_target update in xfs_ail_push() */ | ||
| 388 | smp_rmb(); | ||
| 389 | target = ailp->xa_target; | ||
| 390 | ailp->xa_target_prev = target; | ||
| 391 | |||
| 386 | lip = xfs_trans_ail_cursor_first(ailp, &cur, ailp->xa_last_pushed_lsn); | 392 | lip = xfs_trans_ail_cursor_first(ailp, &cur, ailp->xa_last_pushed_lsn); |
| 387 | if (!lip) { | 393 | if (!lip) { |
| 388 | /* | 394 | /* |
| @@ -397,7 +403,6 @@ xfsaild_push( | |||
| 397 | XFS_STATS_INC(xs_push_ail); | 403 | XFS_STATS_INC(xs_push_ail); |
| 398 | 404 | ||
| 399 | lsn = lip->li_lsn; | 405 | lsn = lip->li_lsn; |
| 400 | target = ailp->xa_target; | ||
| 401 | while ((XFS_LSN_CMP(lip->li_lsn, target) <= 0)) { | 406 | while ((XFS_LSN_CMP(lip->li_lsn, target) <= 0)) { |
| 402 | int lock_result; | 407 | int lock_result; |
| 403 | 408 | ||
| @@ -527,8 +532,32 @@ xfsaild( | |||
| 527 | __set_current_state(TASK_KILLABLE); | 532 | __set_current_state(TASK_KILLABLE); |
| 528 | else | 533 | else |
| 529 | __set_current_state(TASK_INTERRUPTIBLE); | 534 | __set_current_state(TASK_INTERRUPTIBLE); |
| 530 | schedule_timeout(tout ? | 535 | |
| 531 | msecs_to_jiffies(tout) : MAX_SCHEDULE_TIMEOUT); | 536 | spin_lock(&ailp->xa_lock); |
| 537 | |||
| 538 | /* | ||
| 539 | * Idle if the AIL is empty and we are not racing with a target | ||
| 540 | * update. We check the AIL after we set the task to a sleep | ||
| 541 | * state to guarantee that we either catch an xa_target update | ||
| 542 | * or that a wake_up resets the state to TASK_RUNNING. | ||
| 543 | * Otherwise, we run the risk of sleeping indefinitely. | ||
| 544 | * | ||
| 545 | * The barrier matches the xa_target update in xfs_ail_push(). | ||
| 546 | */ | ||
| 547 | smp_rmb(); | ||
| 548 | if (!xfs_ail_min(ailp) && | ||
| 549 | ailp->xa_target == ailp->xa_target_prev) { | ||
| 550 | spin_unlock(&ailp->xa_lock); | ||
| 551 | schedule(); | ||
| 552 | tout = 0; | ||
| 553 | continue; | ||
| 554 | } | ||
| 555 | spin_unlock(&ailp->xa_lock); | ||
| 556 | |||
| 557 | if (tout) | ||
| 558 | schedule_timeout(msecs_to_jiffies(tout)); | ||
| 559 | |||
| 560 | __set_current_state(TASK_RUNNING); | ||
| 532 | 561 | ||
| 533 | try_to_freeze(); | 562 | try_to_freeze(); |
| 534 | 563 | ||
diff --git a/fs/xfs/xfs_trans_priv.h b/fs/xfs/xfs_trans_priv.h index fb62377d1cbc..53b7c9b0f8f7 100644 --- a/fs/xfs/xfs_trans_priv.h +++ b/fs/xfs/xfs_trans_priv.h | |||
| @@ -67,6 +67,7 @@ struct xfs_ail { | |||
| 67 | struct task_struct *xa_task; | 67 | struct task_struct *xa_task; |
| 68 | struct list_head xa_ail; | 68 | struct list_head xa_ail; |
| 69 | xfs_lsn_t xa_target; | 69 | xfs_lsn_t xa_target; |
| 70 | xfs_lsn_t xa_target_prev; | ||
| 70 | struct list_head xa_cursors; | 71 | struct list_head xa_cursors; |
| 71 | spinlock_t xa_lock; | 72 | spinlock_t xa_lock; |
| 72 | xfs_lsn_t xa_last_pushed_lsn; | 73 | xfs_lsn_t xa_last_pushed_lsn; |
