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 467 { 468 468 xfs_log_item_t *dlip = NULL; 469 469 xfs_log_item_t *mlip; /* ptr to minimum lip */ 470 + xfs_lsn_t tail_lsn; 470 471 471 472 mlip = xfs_ail_min(ailp); 472 473 ··· 484 483 485 484 if (mlip == dlip) { 486 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; 487 494 spin_unlock(&ailp->xa_lock); 488 - xfs_log_move_tail(ailp->xa_mount, mlip->li_lsn); 495 + xfs_log_move_tail(ailp->xa_mount, tail_lsn); 489 496 } else { 490 497 spin_unlock(&ailp->xa_lock); 491 498 } ··· 523 514 { 524 515 xfs_log_item_t *dlip; 525 516 xfs_log_item_t *mlip; 517 + xfs_lsn_t tail_lsn; 526 518 527 519 if (lip->li_flags & XFS_LI_IN_AIL) { 528 520 mlip = xfs_ail_min(ailp); ··· 537 527 538 528 if (mlip == dlip) { 539 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; 540 538 spin_unlock(&ailp->xa_lock); 541 - xfs_log_move_tail(ailp->xa_mount, 542 - (mlip ? mlip->li_lsn : 0)); 539 + xfs_log_move_tail(ailp->xa_mount, tail_lsn); 543 540 } else { 544 541 spin_unlock(&ailp->xa_lock); 545 542 }