From 439b802e77166e3a58cfd364105a711798ca0743 Mon Sep 17 00:00:00 2001 From: Gality <68463495+Gality369@users.noreply.github.com> Date: Fri, 8 May 2026 04:20:44 +0800 Subject: [PATCH] sa: fix sa_add_projid lock ordering sa_add_projid() currently acquires hdl->sa_lock before zp->z_lock. Several same-znode update paths take zp->z_lock and then call sa_update() or sa_bulk_update() on the same SA handle. On Linux, FS_IOC_FSSETXATTR reaches zfs_setattr() through zpl_ioctl_setxattr() without outer inode serialization. This makes the reversed lock order a real ABBA deadlock rather than a lockdep false positive when projid is added to an old-format inode while another thread updates the same znode. Acquire zp->z_lock before hdl->sa_lock in sa_add_projid() to match the existing znode update ordering. Reviewed-by: Brian Behlendorf Signed-off-by: ZhengYuan Huang Co-authored-by: gality369 Closes #18503 --- module/zfs/sa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/module/zfs/sa.c b/module/zfs/sa.c index bd565bb7101..c6b36474b9f 100644 --- a/module/zfs/sa.c +++ b/module/zfs/sa.c @@ -1605,8 +1605,8 @@ sa_add_projid(sa_handle_t *hdl, dmu_tx_t *tx, uint64_t projid) bulk = kmem_zalloc(sizeof (sa_bulk_attr_t) * ZPL_END, KM_SLEEP); attrs = kmem_zalloc(sizeof (sa_bulk_attr_t) * ZPL_END, KM_SLEEP); - mutex_enter(&hdl->sa_lock); mutex_enter(&zp->z_lock); + mutex_enter(&hdl->sa_lock); err = sa_lookup_locked(hdl, SA_ZPL_PROJID(zfsvfs), &projid, sizeof (uint64_t)); @@ -1750,8 +1750,8 @@ sa_add_projid(sa_handle_t *hdl, dmu_tx_t *tx, uint64_t projid) zp->z_is_sa = B_TRUE; out: - mutex_exit(&zp->z_lock); mutex_exit(&hdl->sa_lock); + mutex_exit(&zp->z_lock); kmem_free(attrs, sizeof (sa_bulk_attr_t) * ZPL_END); kmem_free(bulk, sizeof (sa_bulk_attr_t) * ZPL_END); if (dxattr_obj)