xfs: copy li_lsn before dropping AIL lock

Access to log items on the AIL is generally protected by m_ail_lock;
this is particularly needed when we're getting or setting the 64-bit
li_lsn on a 32-bit platform. This patch fixes a couple places where we
were accessing the log item after dropping the AIL lock on 32-bit
machines.

This can result in a partially-zeroed log->l_tail_lsn if
xfs_trans_ail_delete is racing with xfs_trans_ail_update, and in at
least some cases, this can leave the l_tail_lsn with a zero cycle
number, which means xlog_space_left will think the log is full (unless
CONFIG_XFS_DEBUG is set, in which case we'll trip an ASSERT), leading to
processes stuck forever in xlog_grant_log_space.

Thanks to Adrian VanderSpek for first spotting the race potential and to
Dave Chinner for debug assistance.

Signed-off-by: Nathaniel W. Turner <nate@houseofnate.net>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Alex Elder <aelder@sgi.com>

authored by Nathaniel W. Turner and committed by Alex Elder 6c06f072 8ec6dba2

+20 -3
+20 -3
fs/xfs/xfs_trans_ail.c
··· 467 { 468 xfs_log_item_t *dlip = NULL; 469 xfs_log_item_t *mlip; /* ptr to minimum lip */ 470 471 mlip = xfs_ail_min(ailp); 472 ··· 484 485 if (mlip == dlip) { 486 mlip = xfs_ail_min(ailp); 487 spin_unlock(&ailp->xa_lock); 488 - xfs_log_move_tail(ailp->xa_mount, mlip->li_lsn); 489 } else { 490 spin_unlock(&ailp->xa_lock); 491 } ··· 523 { 524 xfs_log_item_t *dlip; 525 xfs_log_item_t *mlip; 526 527 if (lip->li_flags & XFS_LI_IN_AIL) { 528 mlip = xfs_ail_min(ailp); ··· 537 538 if (mlip == dlip) { 539 mlip = xfs_ail_min(ailp); 540 spin_unlock(&ailp->xa_lock); 541 - xfs_log_move_tail(ailp->xa_mount, 542 - (mlip ? mlip->li_lsn : 0)); 543 } else { 544 spin_unlock(&ailp->xa_lock); 545 }
··· 467 { 468 xfs_log_item_t *dlip = NULL; 469 xfs_log_item_t *mlip; /* ptr to minimum lip */ 470 + xfs_lsn_t tail_lsn; 471 472 mlip = xfs_ail_min(ailp); 473 ··· 483 484 if (mlip == dlip) { 485 mlip = xfs_ail_min(ailp); 486 + /* 487 + * It is not safe to access mlip after the AIL lock is 488 + * dropped, so we must get a copy of li_lsn before we do 489 + * so. This is especially important on 32-bit platforms 490 + * where accessing and updating 64-bit values like li_lsn 491 + * is not atomic. 492 + */ 493 + tail_lsn = mlip->li_lsn; 494 spin_unlock(&ailp->xa_lock); 495 + xfs_log_move_tail(ailp->xa_mount, tail_lsn); 496 } else { 497 spin_unlock(&ailp->xa_lock); 498 } ··· 514 { 515 xfs_log_item_t *dlip; 516 xfs_log_item_t *mlip; 517 + xfs_lsn_t tail_lsn; 518 519 if (lip->li_flags & XFS_LI_IN_AIL) { 520 mlip = xfs_ail_min(ailp); ··· 527 528 if (mlip == dlip) { 529 mlip = xfs_ail_min(ailp); 530 + /* 531 + * It is not safe to access mlip after the AIL lock 532 + * is dropped, so we must get a copy of li_lsn 533 + * before we do so. This is especially important 534 + * on 32-bit platforms where accessing and updating 535 + * 64-bit values like li_lsn is not atomic. 536 + */ 537 + tail_lsn = mlip ? mlip->li_lsn : 0; 538 spin_unlock(&ailp->xa_lock); 539 + xfs_log_move_tail(ailp->xa_mount, tail_lsn); 540 } else { 541 spin_unlock(&ailp->xa_lock); 542 }