Skip to content

Commit

Permalink
xfs: copy li_lsn before dropping AIL lock
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Nathaniel W. Turner authored and Alex Elder committed Nov 17, 2009
1 parent 8ec6dba commit 6c06f07
Showing 1 changed file with 20 additions and 3 deletions.
23 changes: 20 additions & 3 deletions fs/xfs/xfs_trans_ail.c
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,7 @@ xfs_trans_ail_update(
{
xfs_log_item_t *dlip = NULL;
xfs_log_item_t *mlip; /* ptr to minimum lip */
xfs_lsn_t tail_lsn;

mlip = xfs_ail_min(ailp);

Expand All @@ -483,8 +484,16 @@ xfs_trans_ail_update(

if (mlip == dlip) {
mlip = xfs_ail_min(ailp);
/*
* It is not safe to access mlip after the AIL lock is
* dropped, so we must get a copy of li_lsn before we do
* so. This is especially important on 32-bit platforms
* where accessing and updating 64-bit values like li_lsn
* is not atomic.
*/
tail_lsn = mlip->li_lsn;
spin_unlock(&ailp->xa_lock);
xfs_log_move_tail(ailp->xa_mount, mlip->li_lsn);
xfs_log_move_tail(ailp->xa_mount, tail_lsn);
} else {
spin_unlock(&ailp->xa_lock);
}
Expand Down Expand Up @@ -514,6 +523,7 @@ xfs_trans_ail_delete(
{
xfs_log_item_t *dlip;
xfs_log_item_t *mlip;
xfs_lsn_t tail_lsn;

if (lip->li_flags & XFS_LI_IN_AIL) {
mlip = xfs_ail_min(ailp);
Expand All @@ -527,9 +537,16 @@ xfs_trans_ail_delete(

if (mlip == dlip) {
mlip = xfs_ail_min(ailp);
/*
* It is not safe to access mlip after the AIL lock
* is dropped, so we must get a copy of li_lsn
* before we do so. This is especially important
* on 32-bit platforms where accessing and updating
* 64-bit values like li_lsn is not atomic.
*/
tail_lsn = mlip ? mlip->li_lsn : 0;
spin_unlock(&ailp->xa_lock);
xfs_log_move_tail(ailp->xa_mount,
(mlip ? mlip->li_lsn : 0));
xfs_log_move_tail(ailp->xa_mount, tail_lsn);
} else {
spin_unlock(&ailp->xa_lock);
}
Expand Down

0 comments on commit 6c06f07

Please sign in to comment.