[PATCH v2] xfs: use xfs_trans_ail_copy_lsn for lockless li_lsn read in CIL formatting
From: Cen Zhang
Date: Mon Mar 23 2026 - 03:29:21 EST
xfs_inode_item_format_core() reads lip->li_lsn without holding any lock
to embed the last on-disk LSN into the log dinode during CIL commit:
xfs_inode_to_log_dinode(ip, dic, ip->i_itemp->ili_item.li_lsn);
Concurrently, xfs_trans_ail_update_bulk() writes lip->li_lsn under
ail_lock when inserting items into the AIL after log IO completion:
lip->li_lsn = lsn;
The CIL context lock (xc_ctx_lock) and the AIL lock (ail_lock) are
independent and provide no mutual exclusion between these paths.
On 64-bit architectures this is benign since li_lsn monotonically
increases and both old/new values are valid checkpoint LSNs. On 32-bit
architectures the 64-bit xfs_lsn_t can be torn into two 32-bit loads,
producing a bogus LSN that could cause log recovery to make incorrect
replay decisions.
Use xfs_trans_ail_copy_lsn() to safely snapshot li_lsn, which takes
ail_lock on 32-bit architectures to prevent torn reads.
Fixes: 93f958f9c41f ("xfs: cull unnecessary icdinode fields")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Cen Zhang <zzzccc427@xxxxxxxxx>
---
fs/xfs/xfs_inode_item.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
index 8913036b8024..0171f4527f40 100644
--- a/fs/xfs/xfs_inode_item.c
+++ b/fs/xfs/xfs_inode_item.c
@@ -622,9 +622,12 @@ xfs_inode_item_format_core(
struct xlog_format_buf *lfb)
{
struct xfs_log_dinode *dic;
+ xfs_lsn_t lsn;
+ xfs_trans_ail_copy_lsn(ip->i_mount->m_ail, &lsn,
+ &ip->i_itemp->ili_item.li_lsn);
dic = xlog_format_start(lfb, XLOG_REG_TYPE_ICORE);
- xfs_inode_to_log_dinode(ip, dic, ip->i_itemp->ili_item.li_lsn);
+ xfs_inode_to_log_dinode(ip, dic, lsn);
xlog_format_commit(lfb, xfs_log_dinode_size(ip->i_mount));
}
--
2.34.1