From nobody Sun Jul 26 01:57:25 2026 Received: from mx0b-0064b401.pphosted.com (mx0b-0064b401.pphosted.com [205.220.178.238]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D15C9364042; Fri, 10 Jul 2026 03:14:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.178.238 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783653268; cv=none; b=XjlUQqYwHS558mTgbP7opAW3EdsnwYbgqC+HM9OKTvoabk5VyyM68xqwTFMasODonTA7Qyh6t61pAKq6Ey/7X3/JfZoG6IErco///nOWP8rfjq2B5xytK7iap1k2HF193EycVDao3646SECjptS/KBe8RJz/96d85WXvDoGM0Ac= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783653268; c=relaxed/simple; bh=Wx/QOvXFisSTYK6TZWMSOaJZ4tgu59e9kAIEl5Zq9do=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=pNj4yW46Myw8vOuuRUDoEU9YsEg8V4jan92filECtlX+eIEGmPlx5DotAZgOVl+KAEvlwP5PwK29JgYwRrtG0n03Rn/94tRpM9w5bDkQ7PTd7get8QZA0U6AurxauuoHiWtdOa7Q/ttBCu5ihmC+G4VxTBFeWQpjQCX2p/QCh0k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=windriver.com; spf=pass smtp.mailfrom=windriver.com; dkim=pass (2048-bit key) header.d=windriver.com header.i=@windriver.com header.b=OiY6AXkd; arc=none smtp.client-ip=205.220.178.238 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=windriver.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=windriver.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=windriver.com header.i=@windriver.com header.b="OiY6AXkd" Received: from pps.filterd (m0250811.ppops.net [127.0.0.1]) by mx0a-0064b401.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 66A1t3tN3753799; Fri, 10 Jul 2026 03:09:00 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=windriver.com; h=cc:content-transfer-encoding:content-type:date:from :in-reply-to:message-id:mime-version:references:subject:to; s= PPS06212021; bh=C8Ra/lEdlkhDbix2aNrnAVbHIhjzmCUXip2VQkyA2q0=; b= OiY6AXkdUK1YlLFSQkLvCE0h6Qzr2ferR7EqvbRvmvsa5Pcs4gQuyhrPIAC8RG0u vn+ADJASGBcNzfPgBdDykx9Erl8X7qOQp4hiuwEABUk13haDmfvAd7aLNMbWv5H0 l+3qK1aamnCPAw5B4fWLe9b4IOqAJRSwkJCrl66MzG2L75yKkgOv+sw0TIccFbz6 RledHlNT3On2wfqiEVuqh0Lbx/xvGVUaeYd4GIyb3PnnKiK57MjSNZb+3T3fmQZP t8oQA5w65LOJPVuKkTk95aq7P+Ebr6fnNe3eyRPU+7Hp8RLZczFNOjVTnl61WZaz rPIT8f1tFx3UeoeQqWGnTA== Received: from ala-exchng01.corp.ad.wrs.com (ala-exchng01.wrs.com [128.224.246.36]) by mx0a-0064b401.pphosted.com (PPS) with ESMTPS id 4fa1aqa18h-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT); Fri, 10 Jul 2026 03:09:00 +0000 (GMT) Received: from ala-exchng01.corp.ad.wrs.com (10.11.224.121) by ala-exchng01.corp.ad.wrs.com (10.11.224.121) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.61; Thu, 9 Jul 2026 20:08:59 -0700 Received: from pek-yzhou-d3.wrs.com (10.11.232.110) by ala-exchng01.corp.ad.wrs.com (10.11.224.121) with Microsoft SMTP Server id 15.1.2507.61 via Frontend Transport; Thu, 9 Jul 2026 20:08:56 -0700 From: Yun Zhou To: , , , , , , , , CC: , , , Subject: [PATCH v14 1/4] fs: add iput_if_not_last() helper Date: Fri, 10 Jul 2026 11:08:48 +0800 Message-ID: <20260710030851.2791589-2-yun.zhou@windriver.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260710030851.2791589-1-yun.zhou@windriver.com> References: <20260710030851.2791589-1-yun.zhou@windriver.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Proofpoint-ORIG-GUID: nSpXEtNkB3wel51yIOraLY5MbPCqk2Qe X-Proofpoint-Spam-Info: AW1haW4tMjYwNzEwMDAyNiBTYWx0ZWRfXzml8HkWzX7bE fJGkvhgXBQ0ROhMviIB3WihdavlbttE0fsdJbMIpoTyzDoL10NNgBQPMZBk9lBy3WV0Z3FfB7yL MaNrXpI8h4hgOZBNBK5mf0V7iLfwGGvCk8lHSwtBfwlUUtzdfrvY X-Authority-Analysis: v=2.4 cv=XIkAjwhE c=1 sm=1 tr=0 ts=6a50624c cx=c_pps a=AbJuCvi4Y3V6hpbCNWx0WA==:117 a=AbJuCvi4Y3V6hpbCNWx0WA==:17 a=RAioF0-LDSMA:10 a=VkNPw1HP01LnGYTKEx00:22 a=bi6dqmuHe4P4UrxVR6um:22 a=klDOsUkWDRETUCZYPvoE:22 a=t7CeM3EgAAAA:8 a=pGLkceISAAAA:8 a=VwQbUJbxAAAA:8 a=vCr0if_IiwaKUNF-nsEA:9 a=FdTzh2GWekK77mhwV6Dw:22 X-Proofpoint-GUID: nSpXEtNkB3wel51yIOraLY5MbPCqk2Qe X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNzEwMDAyNiBTYWx0ZWRfX+rZ/jgQQCK95 DBlcuZAA5xviyyDGghNAwSrOuzCM0MAz/NFlTHoq3Dx8bFx/3GIbcbZkJ8cDDLbBsWIZuYVwQTD 3y7duNcw5vN2JYJr7UYsU8iIRAFvpJqjjxNCYwUl/VRdM+6y10ReKjo/mCn+FXZOL4B2d0NBC2D RQVHvHTVVHHBFcaTIaiTujiz5WcR1V9Cq37RDuvowJFXI5ezgUFGI2gQzVny2f5PjoHpPeMV7n6 VIv55LInGc5uuQK4YCzglyQyylEzZPY07iOv/yuFtbdKZhB3sxwh7lQ2YPAXUJoUyL0c8+jtuyX 0JWGKhSdjgK1JlI9a7CFye2q9Cx9l1Uzdbv37F0XRmuqbIrMiPddDi8qsgsqo5ZRQIeIm2VaDe2 j0uEhlT+mp5LfWgkvhMrtKiUM2s9EDx8iQE8yi7Ejl97hLQzrIEfSNhI4bj17E8jN8b6CABxpeW hTcy/YKOlERBWmcI78w== X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-07-09_04,2026-07-09_04,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 phishscore=0 adultscore=0 impostorscore=0 malwarescore=0 spamscore=0 clxscore=1015 lowpriorityscore=0 suspectscore=0 priorityscore=1501 bulkscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2606150000 definitions=main-2607100026 Content-Type: text/plain; charset="utf-8" Add a helper that drops an inode reference only if the caller does not hold the last one. Returns true if the reference was dropped, false otherwise. This is useful for filesystems that need to release inode references in contexts where triggering final iput (and thus eviction) would be unsafe due to lock ordering constraints. The caller can check the return value and defer the final iput to a safe context. Unlike iput_not_last() which BUG_ON's if called with the last ref, this variant is designed to be called speculatively. Signed-off-by: Yun Zhou Suggested-by: Jan Kara Suggested-by: Mateusz Guzik Reviewed-by: Jan Kara Reviewed-by: Christian Brauner (Amutable) --- include/linux/fs.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/include/linux/fs.h b/include/linux/fs.h index d10897b3a1e3..709519617c7a 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2413,6 +2413,21 @@ static inline void super_set_sysfs_name_generic(stru= ct super_block *sb, const ch extern void ihold(struct inode * inode); extern void iput(struct inode *); void iput_not_last(struct inode *); + +/** + * iput_if_not_last - drop an inode reference only if it is not the last o= ne + * @inode: inode to put + * + * Returns true if the reference was dropped, false if this was the last + * reference and the caller must arrange for final iput() in a safe contex= t. + */ +static inline bool __must_check iput_if_not_last(struct inode *inode) +{ + VFS_BUG_ON_INODE(inode_state_read_once(inode) & (I_FREEING | I_CLEAR), in= ode); + VFS_BUG_ON_INODE(icount_read_once(inode) < 1, inode); + return atomic_add_unless(&inode->i_count, -1, 1); +} + int inode_update_time(struct inode *inode, enum fs_update_time type, unsigned int flags); int generic_update_time(struct inode *inode, enum fs_update_time type, --=20 2.43.0 From nobody Sun Jul 26 01:57:25 2026 Received: from mx0b-0064b401.pphosted.com (mx0b-0064b401.pphosted.com [205.220.178.238]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A8213126C03; Fri, 10 Jul 2026 03:09:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.178.238 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783652976; cv=none; b=MEpjTSS1zIKmPbjD4yaBwvY/XpuYPoJtboxPLdCnLP6zhjciVFAw8cw2s2CaqzWncxkeD+Q8IQPY5qCVcDPUWkPbxs+51sRc1upYRjytOfU7CcEvkfZIF4yOBVd8CXfFS+/zACXCPSvxmO3ukKUyRPxWGWv/1pSktkVAKWJK6TE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783652976; c=relaxed/simple; bh=e7U2bg2KHotaUnScjR9ib01HG9inHKsyBHE27+0hAv4=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=jdLlothGTvQL9W/S6KQfdoD+2PbEZjwTNI6XZGWe3dUzZFgW+uzas8WfPLB70mroTR+QpTBrui6yJNGl7mMB3xv6QadEkZ6upieUCHErDY7poFh07fx3tx27BlcL7xiwD3MuRxBK8TVHkE57Td/+xPg868ZAT2Jxyuboz8Q6X3Q= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=windriver.com; spf=pass smtp.mailfrom=windriver.com; dkim=pass (2048-bit key) header.d=windriver.com header.i=@windriver.com header.b=Zr98w+/m; arc=none smtp.client-ip=205.220.178.238 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=windriver.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=windriver.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=windriver.com header.i=@windriver.com header.b="Zr98w+/m" Received: from pps.filterd (m0250812.ppops.net [127.0.0.1]) by mx0a-0064b401.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 66A351Gs3727693; Fri, 10 Jul 2026 03:09:04 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=windriver.com; h=cc:content-transfer-encoding:content-type:date:from :in-reply-to:message-id:mime-version:references:subject:to; s= PPS06212021; bh=Y0dK+TVS6R3bh3Ra04gctK+A4xVLuoSzw5C3p0CNjSs=; b= Zr98w+/mwd2hlusYrW7rX0JaBFZYzscBKkK2FiSLyxscqXQPE5Fg2SvmSufGZT9a A5RwPwOvjkxy2Jewpgda3V5viU08tDD55Ut2RiR5yUpJ9ODUM+d7Yzhb33f6IImq DBHJ64ZWt+yydkVqHv8aiLe6GYehQguzpqZlJDqDCysivf7pE/C75R0olWTNWo6k lEuA9LtxAp6NuAJFv1reY8RgkU/jXUyFVB0XDj32vCBdaPthU/do5lOVpAbWkAgI AJeloPPlRNEqRUmC5PaFc8OookX6mncfSvfs3Uql2ANh2hd1ifaax7znCvoOvOXZ Np5S/35Zo1+UAkiOs7+0eQ== Received: from ala-exchng02.corp.ad.wrs.com (ala-exchng02.wrs.com [128.224.246.37]) by mx0a-0064b401.pphosted.com (PPS) with ESMTPS id 4fa1h2217t-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT); Fri, 10 Jul 2026 03:09:03 +0000 (GMT) Received: from ala-exchng01.corp.ad.wrs.com (10.11.224.121) by ALA-EXCHNG02.corp.ad.wrs.com (10.11.224.122) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.61; Thu, 9 Jul 2026 20:09:02 -0700 Received: from pek-yzhou-d3.wrs.com (10.11.232.110) by ala-exchng01.corp.ad.wrs.com (10.11.224.121) with Microsoft SMTP Server id 15.1.2507.61 via Frontend Transport; Thu, 9 Jul 2026 20:08:59 -0700 From: Yun Zhou To: , , , , , , , , CC: , , , Subject: [PATCH v14 2/4] ext4: introduce ext4_put_ea_inode() for safe deferred iput Date: Fri, 10 Jul 2026 11:08:49 +0800 Message-ID: <20260710030851.2791589-3-yun.zhou@windriver.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260710030851.2791589-1-yun.zhou@windriver.com> References: <20260710030851.2791589-1-yun.zhou@windriver.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Authority-Analysis: v=2.4 cv=LbIMLDfi c=1 sm=1 tr=0 ts=6a50624f cx=c_pps a=Lg6ja3A245NiLSnFpY5YKQ==:117 a=Lg6ja3A245NiLSnFpY5YKQ==:17 a=RAioF0-LDSMA:10 a=VkNPw1HP01LnGYTKEx00:22 a=bi6dqmuHe4P4UrxVR6um:22 a=fTW__CHxibyLmBMfj2wP:22 a=t7CeM3EgAAAA:8 a=WjeYnjZXhi5Nt7IBOn4A:9 a=FdTzh2GWekK77mhwV6Dw:22 X-Proofpoint-Spam-Info: AW1haW4tMjYwNzEwMDAyNiBTYWx0ZWRfXyakV2a/Zdpzu +0WrzFKL7FEMDGHo1k2eZ8hnxJO4NZK/rm31wBfv3Zv+s2K6renZlj8ND5ES742uRTCcTZpVftg EXJ73WSDL+1C/wRNS6Qa3LuFTMpjfKAMfl9SIb2gYHSgE2cR9QNt X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNzEwMDAyNiBTYWx0ZWRfX36qY3A8zN3Jd DcXWgdhuprbpN78/oDQyKqx6ahELWVsT6o5sqquC7rqgL3TCb4IXKyVSwm2Wl0EVrQEdqd2SRx6 Asv+FPg5xhTyqkjlSVLsOI5R1zs5XbfwwZBOO7ngOIqFKUee2HuAscx/Nl1DkvdcQ5qwXRNZT+i opL8BRun31nWe4AWVz7iZpkynMREoRCuFYFipkGxlRQLazvo5ALBFDIYF6jQ3wKvBW9TNwOa5e0 9sETOn8YaLy90lk9uj20sXjb3EOBfgCHxxlEVjBUKRH4vcNKTbrNnkgc73I31hUIZNdvr+/JDv4 JIFC0QV+oCcQIbAJjW5PDfNzh80Sr7U+okpD0P8Sx1J711lRdu9OAsYZurVSGkr3jIVdHDbTHfw 0aWklL8Pt+kBFNKwDXJxJJKo00WSZpX2knnVAlOhFhMHNBrXUEeHPCenA9pl0AB1FembLvoritQ 5C81yFabc6aA4QPwQ+w== X-Proofpoint-ORIG-GUID: PfDc-f2h8Ik6moIq-DKzowxSYcpsn7X_ X-Proofpoint-GUID: PfDc-f2h8Ik6moIq-DKzowxSYcpsn7X_ X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-07-09_04,2026-07-09_04,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 adultscore=0 phishscore=0 priorityscore=1501 malwarescore=0 clxscore=1015 lowpriorityscore=0 bulkscore=0 suspectscore=0 spamscore=0 impostorscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2606150000 definitions=main-2607100026 Content-Type: text/plain; charset="utf-8" Calling iput() on EA inodes while holding xattr_sem or a jbd2 handle can trigger write_inode_now() -> ext4_writepages() -> s_writepages_rwsem, creating a lock ordering issue during mount (!SB_ACTIVE). Add ext4_put_ea_inode() which uses iput_if_not_last() as a fast path. If this is not the last reference, it is dropped immediately. If this is the last reference, the inode is linked onto a per-sb lock-free llist via i_ea_iput_node (embedded in ext4_inode_info, sharing space with the unused xattr_sem of EA inodes via a union) and a delayed worker (1 jiffie) performs the final iput() in a clean context. This avoids per-iput memory allocation. Flush points ensure all pending EA inode evictions complete before dependent resources become unavailable: - ext4_put_super / failed_mount9: before quota shutdown - failed_mount_wq: before freeing xattr caches - failed_mount3a: before freeing shrinker (journal replay case) - ext4_sync_fs: before remount-ro, freeze, or sync completes Initialization is placed before journal loading since fast commit replay may trigger evictions that call ext4_put_ea_inode(). Also moves init_rwsem(xattr_sem) from init_once to ext4_alloc_inode to handle slab object reuse after the union field has been overwritten. Signed-off-by: Yun Zhou Suggested-by: Jan Kara Reviewed-by: Jan Kara --- fs/ext4/ext4.h | 13 ++++++++++- fs/ext4/super.c | 19 +++++++++++++++- fs/ext4/xattr.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++ fs/ext4/xattr.h | 2 ++ 4 files changed, 92 insertions(+), 2 deletions(-) diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index b37c136ea3ab..b9b0ada7774b 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -1070,8 +1070,14 @@ struct ext4_inode_info { * between readers of EAs and writers of regular file data, so * instead we synchronize on xattr_sem when reading or changing * EAs. + * + * EA inodes (EXT4_EA_INODE_FL) do not use xattr_sem; they reuse + * the space for deferred iput linkage. */ - struct rw_semaphore xattr_sem; + union { + struct rw_semaphore xattr_sem; + struct llist_node i_ea_iput_node; + }; =20 /* * Inodes with EXT4_STATE_ORPHAN_FILE use i_orphan_idx. Otherwise @@ -1770,6 +1776,11 @@ struct ext4_sb_info { struct ext4_es_stats s_es_stats; struct mb_cache *s_ea_block_cache; struct mb_cache *s_ea_inode_cache; + + /* Deferred iput for EA inodes to avoid lock ordering issues */ + struct llist_head s_ea_inode_to_free; + struct delayed_work s_ea_inode_work; + spinlock_t s_es_lock ____cacheline_aligned_in_smp; =20 /* Journal triggers for checksum computation */ diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 245f67d10ded..898d8c6431ba 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1303,6 +1303,8 @@ static void ext4_put_super(struct super_block *sb) &sb->s_uuid); =20 ext4_unregister_li_request(sb); + /* Drain deferred EA inode iputs while quota is still active. */ + flush_delayed_work(&sbi->s_ea_inode_work); ext4_quotas_off(sb, EXT4_MAXQUOTAS); =20 destroy_workqueue(sbi->rsv_conversion_wq); @@ -1423,6 +1425,13 @@ static struct inode *ext4_alloc_inode(struct super_b= lock *sb) memset(&ei->i_dquot, 0, sizeof(ei->i_dquot)); #endif ei->jinode =3D NULL; + /* + * Reinitialize xattr_sem every allocation because EA inodes + * share this space with i_ea_iput_node (via union) which may + * have overwritten the semaphore when the slab object was + * previously used as an EA inode. + */ + init_rwsem(&ei->xattr_sem); INIT_LIST_HEAD(&ei->i_rsv_conversion_list); spin_lock_init(&ei->i_completed_io_lock); ei->i_sync_tid =3D 0; @@ -1488,7 +1497,6 @@ static void init_once(void *foo) struct ext4_inode_info *ei =3D foo; =20 INIT_LIST_HEAD(&ei->i_orphan); - init_rwsem(&ei->xattr_sem); init_rwsem(&ei->i_data_sem); inode_init_once(&ei->vfs_inode); ext4_fc_init_inode(&ei->vfs_inode); @@ -5497,6 +5505,8 @@ static int __ext4_fill_super(struct fs_context *fc, s= truct super_block *sb) ext4_has_feature_orphan_present(sb) || ext4_has_feature_journal_needs_recovery(sb)); =20 + ext4_init_ea_inode_work(sbi); + if (ext4_has_feature_mmp(sb) && !sb_rdonly(sb)) { err =3D ext4_multi_mount_protect(sb, le64_to_cpu(es->s_mmp_block)); if (err) @@ -5747,6 +5757,8 @@ static int __ext4_fill_super(struct fs_context *fc, s= truct super_block *sb) return 0; =20 failed_mount9: + /* Drain deferred EA inode iputs before quota shutdown */ + flush_delayed_work(&sbi->s_ea_inode_work); ext4_quotas_off(sb, EXT4_MAXQUOTAS); failed_mount8: __maybe_unused ext4_release_orphan_info(sb); @@ -5767,6 +5779,8 @@ failed_mount8: __maybe_unused if (EXT4_SB(sb)->rsv_conversion_wq) destroy_workqueue(EXT4_SB(sb)->rsv_conversion_wq); failed_mount_wq: + /* Drain deferred EA inode iputs before freeing structures */ + flush_delayed_work(&sbi->s_ea_inode_work); ext4_xattr_destroy_cache(sbi->s_ea_inode_cache); sbi->s_ea_inode_cache =3D NULL; =20 @@ -5777,6 +5791,8 @@ failed_mount8: __maybe_unused ext4_journal_destroy(sbi, sbi->s_journal); } failed_mount3a: + /* Drain deferred EA inode iputs from journal replay */ + flush_delayed_work(&sbi->s_ea_inode_work); ext4_es_unregister_shrinker(sbi); failed_mount3: /* flush s_sb_upd_work before sbi destroy */ @@ -6447,6 +6463,7 @@ static int ext4_sync_fs(struct super_block *sb, int w= ait) =20 trace_ext4_sync_fs(sb, wait); flush_workqueue(sbi->rsv_conversion_wq); + flush_delayed_work(&sbi->s_ea_inode_work); /* * Writeback quota in non-journalled quota case - journalled quota has * no dirty dquots diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 982a1f831e22..d5bccc64b032 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -3025,6 +3025,66 @@ void ext4_xattr_inode_array_free(struct ext4_xattr_i= node_array *ea_inode_array) kfree(ea_inode_array); } =20 + +/* + * Worker function for deferred EA inode iput. Processes all inodes queued + * on s_ea_inode_to_free in a context free of xattr_sem/jbd2 handle locks. + */ +static void ext4_ea_inode_work(struct work_struct *work) +{ + struct ext4_sb_info *sbi =3D container_of(to_delayed_work(work), + struct ext4_sb_info, + s_ea_inode_work); + struct llist_node *node =3D llist_del_all(&sbi->s_ea_inode_to_free); + + while (node) { + struct ext4_inode_info *ei =3D container_of(node, + struct ext4_inode_info, i_ea_iput_node); + node =3D node->next; + iput(&ei->vfs_inode); + } +} + +/* + * Release a VFS reference on an EA inode. Must be used instead of iput() + * in any context where xattr_sem or a jbd2 handle is held. + * + * If this is not the last reference, drops it immediately via + * iput_if_not_last() with no further action needed. + * + * If this is the last reference, the inode is linked onto a per-sb + * llist via i_ea_iput_node (embedded in ext4_inode_info, sharing space + * with the unused xattr_sem) and a delayed worker performs the final + * iput() in a clean context. + * + * Note: while an inode is on s_ea_inode_to_free, the unconsumed i_count + * reference (still 1) keeps it in the inode cache, so any concurrent + * iget() bumps i_count to >=3D 2 and iput_if_not_last() will succeed. + * Nobody will add the inode a second time until ext4_ea_inode_work() + * drops that reference via iput(). + */ +void ext4_put_ea_inode(struct inode *inode) +{ + if (!inode) + return; + WARN_ON_ONCE(!(EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL)); + if (iput_if_not_last(inode)) + return; + llist_add(&EXT4_I(inode)->i_ea_iput_node, + &EXT4_SB(inode->i_sb)->s_ea_inode_to_free); + /* + * Use a short delay to allow multiple EA inodes to accumulate, + * reducing workqueue wakeups when several are released together. + */ + schedule_delayed_work(&EXT4_SB(inode->i_sb)->s_ea_inode_work, 1); +} + +void ext4_init_ea_inode_work(struct ext4_sb_info *sbi) +{ + init_llist_head(&sbi->s_ea_inode_to_free); + INIT_DELAYED_WORK(&sbi->s_ea_inode_work, ext4_ea_inode_work); +} + /* * ext4_xattr_block_cache_insert() * diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h index 1fedf44d4fb6..2ff4b6eccd40 100644 --- a/fs/ext4/xattr.h +++ b/fs/ext4/xattr.h @@ -190,6 +190,8 @@ extern int ext4_xattr_delete_inode(handle_t *handle, st= ruct inode *inode, struct ext4_xattr_inode_array **array, int extra_credits); extern void ext4_xattr_inode_array_free(struct ext4_xattr_inode_array *arr= ay); +extern void ext4_init_ea_inode_work(struct ext4_sb_info *sbi); +extern void ext4_put_ea_inode(struct inode *inode); =20 extern int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_i= size, struct ext4_inode *raw_inode, handle_t *handle); --=20 2.43.0 From nobody Sun Jul 26 01:57:25 2026 Received: from mx0b-0064b401.pphosted.com (mx0b-0064b401.pphosted.com [205.220.178.238]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BAE20362133; Fri, 10 Jul 2026 03:09:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.178.238 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783652977; cv=none; b=X14NlCzRVBa4eUJLKpYrNiJQsPtvIIXRYO4PWswSh9lq/R0TKyXspELc4ngimP4PXt6HETWuxYxoTq1UaMuGy1SXnjStrXis2nR2oyr52Xa7ZquDBCH0dzHPzMl6ge6qAcJ+rknVx3YTOQtkOz9yYyKkn0X7njHjzuPtPeNAkcg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783652977; c=relaxed/simple; bh=jQIKINSzk9Y2T21NmTC3f3QYFbiOQbaIKvTXdgpO8u0=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=HBhtjiYQiH8WiQGuYTZ1s40aUJ6pMgEJIfGp5Eiq8Ovc58eiaDSgeEvvEFO2lJYQ3vXoGwmxrACypyx9z9jnq6iIwH1fc0PiKH8RWBnd0N5qirBGtXFJSMVAOmg9lGdlUqFEEDlCcCEWP8+8ytsjGKOPHa+LSRLct0JBjSGsqoQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=windriver.com; spf=pass smtp.mailfrom=windriver.com; dkim=pass (2048-bit key) header.d=windriver.com header.i=@windriver.com header.b=OdEmVgrK; arc=none smtp.client-ip=205.220.178.238 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=windriver.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=windriver.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=windriver.com header.i=@windriver.com header.b="OdEmVgrK" Received: from pps.filterd (m0250811.ppops.net [127.0.0.1]) by mx0a-0064b401.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 66A2baY53827148; Fri, 10 Jul 2026 03:09:07 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=windriver.com; h=cc:content-transfer-encoding:content-type:date:from :in-reply-to:message-id:mime-version:references:subject:to; s= PPS06212021; bh=W3Cc5ozYmAkjhyRVzpLa8art99yxwG3VN7yO3jCcXrU=; b= OdEmVgrKVQQzstJQsyFefarFTe+ZhuLOOvORUx6H8iWPD6SxLQUyk2DMo02hP+h7 y2YurKVsrG8WL0KaYiYp9UyURPEDER41/u+eFzLK7JdobvmTT+UiTx2CRZC1OiWg msMxKu89O0KezTJh6sYIaYZi4NiF+gxYdIJeGkwI6982IjQ0NpRMEr4KAbqN8sDr yZJcYV2Nqil263XagaOupzsqmE65dEfrb10bJy+I3Aim6uNhUzp3KVfAIQVrNd0U 4jiwstQacwu+rgh9agqCXxGtgcwjSJkYfbRrz96+eeKO8Y6ksiaaKY4A+yQDL7CJ OzKCWboHqmFtZpdMX1+BAA== Received: from ala-exchng02.corp.ad.wrs.com (ala-exchng02.wrs.com [128.224.246.37]) by mx0a-0064b401.pphosted.com (PPS) with ESMTPS id 4fa1aqa18n-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT); Fri, 10 Jul 2026 03:09:07 +0000 (GMT) Received: from ala-exchng01.corp.ad.wrs.com (10.11.224.121) by ALA-EXCHNG02.corp.ad.wrs.com (10.11.224.122) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.61; Thu, 9 Jul 2026 20:09:06 -0700 Received: from pek-yzhou-d3.wrs.com (10.11.232.110) by ala-exchng01.corp.ad.wrs.com (10.11.224.121) with Microsoft SMTP Server id 15.1.2507.61 via Frontend Transport; Thu, 9 Jul 2026 20:09:02 -0700 From: Yun Zhou To: , , , , , , , , CC: , , , Subject: [PATCH v14 3/4] ext4: convert all EA inode iput() calls to ext4_put_ea_inode() Date: Fri, 10 Jul 2026 11:08:50 +0800 Message-ID: <20260710030851.2791589-4-yun.zhou@windriver.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260710030851.2791589-1-yun.zhou@windriver.com> References: <20260710030851.2791589-1-yun.zhou@windriver.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Proofpoint-ORIG-GUID: Z9-jB4qOddmhJuitRbtQYZ5No7EriTn- X-Proofpoint-Spam-Info: AW1haW4tMjYwNzEwMDAyNiBTYWx0ZWRfX3Y2TGKME/Tph q5TQDbCiJmSJ7yR8JI5ZYRHOfqarte+GUN/hLBEEWahfvGrAH9m5UF2VoygyPZM6o3/fTBjO+57 tnL4S6NmKRzd+5ItGvVPTZ/v6T35ZYRU+gWIX2EFJADXOlzP0QuA X-Authority-Analysis: v=2.4 cv=XIkAjwhE c=1 sm=1 tr=0 ts=6a506253 cx=c_pps a=Lg6ja3A245NiLSnFpY5YKQ==:117 a=Lg6ja3A245NiLSnFpY5YKQ==:17 a=RAioF0-LDSMA:10 a=VkNPw1HP01LnGYTKEx00:22 a=bi6dqmuHe4P4UrxVR6um:22 a=klDOsUkWDRETUCZYPvoE:22 a=t7CeM3EgAAAA:8 a=o_jFod6Xf73EBe-g21MA:9 a=+jEqtf1s3R9VXZ0wqowq2kgwd+I=:19 a=FdTzh2GWekK77mhwV6Dw:22 X-Proofpoint-GUID: Z9-jB4qOddmhJuitRbtQYZ5No7EriTn- X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNzEwMDAyNiBTYWx0ZWRfXzZHD5T3mcB1V eNuWG16/AgWKUPYhS4rZdj0ixs1Tx9/8pSSz+FMfku9TdW5vY5/2rI7hb5P/F1MKd6mCo5eiblg 7NJ2y3xNNsjSYz6Ke0PL+8y+r0kSYT/eKonA3JxAbVHrBapmGnv2eQ6uKllSZvT3wkxjp7NYbIV cxo53DosaVu3j3aQY2Hwe7XSpkNO9rIWcqHut+cLjFpKM3FXdsbnHYUNXUdz65WS0OtMAkj5Wjt hV/STe1Gcmeo6v3xAnRRGXrWzaXyP++7qVNNKHc+Q0AdaMNC/aEIwmuusJH/1a36Crl2B29vNcx JT/dRR5l2jhrA7lTavR6IFA914ENsAbqWVrVX2zpdppjup6HSG+nvkk+nQAvOO3/DhAFHUJoeEU L4zz0qayxmYQaaPn3MCzubUvd36Gt3fKgjDyB28RWTs9j/nDdn40p9KcY2wRkpfT0wFnaolYwWU 4e8F4M12nB/PKKHl3gQ== X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-07-09_04,2026-07-09_04,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 phishscore=0 adultscore=0 impostorscore=0 malwarescore=0 spamscore=0 clxscore=1015 lowpriorityscore=0 suspectscore=0 priorityscore=1501 bulkscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2606150000 definitions=main-2607100026 Content-Type: text/plain; charset="utf-8" Convert all iput() calls on EA inodes in xattr code paths to use ext4_put_ea_inode(). This establishes a uniform rule: every EA inode reference release in ext4 xattr code goes through ext4_put_ea_inode(), eliminating the need to analyze each call site individually for lock safety. Converted sites: - ext4_xattr_inode_get() read path - ext4_xattr_inode_inc_ref_all() main loop and cleanup path - ext4_xattr_inode_dec_ref_all() error paths - ext4_xattr_inode_create() error path - ext4_xattr_inode_cache_find() mismatch path - ext4_xattr_inode_lookup_create() out_err - ext4_xattr_set_entry() old_ea_inode - ext4_xattr_block_set() new block path, cleanup, and tmp_inode - ext4_xattr_ibody_set() error and success paths - ext4_xattr_delete_inode() quota loop For most of these, iput_if_not_last() will succeed (the EA inode has other references) making the overhead a single atomic operation. Signed-off-by: Yun Zhou Reviewed-by: Jan Kara --- fs/ext4/xattr.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index d5bccc64b032..6a1f2bdb6ff8 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -567,7 +567,7 @@ ext4_xattr_inode_get(struct inode *inode, struct ext4_x= attr_entry *entry, ea_inode->i_ino, true /* reusable */); } out: - iput(ea_inode); + ext4_put_ea_inode(ea_inode); return err; } =20 @@ -1104,10 +1104,10 @@ static int ext4_xattr_inode_inc_ref_all(handle_t *h= andle, struct inode *parent, err =3D ext4_xattr_inode_inc_ref(handle, ea_inode); if (err) { ext4_warning_inode(ea_inode, "inc ref error %d", err); - iput(ea_inode); + ext4_put_ea_inode(ea_inode); goto cleanup; } - iput(ea_inode); + ext4_put_ea_inode(ea_inode); } return 0; =20 @@ -1133,7 +1133,7 @@ static int ext4_xattr_inode_inc_ref_all(handle_t *han= dle, struct inode *parent, if (err) ext4_warning_inode(ea_inode, "cleanup dec ref error %d", err); - iput(ea_inode); + ext4_put_ea_inode(ea_inode); } return saved_err; } @@ -1201,7 +1201,7 @@ ext4_xattr_inode_dec_ref_all(handle_t *handle, struct= inode *parent, if (err) { ext4_warning_inode(ea_inode, "Expand inode array err=3D%d", err); - iput(ea_inode); + ext4_put_ea_inode(ea_inode); continue; } =20 @@ -1505,7 +1505,7 @@ static struct inode *ext4_xattr_inode_create(handle_t= *handle, if (ext4_xattr_inode_dec_ref(handle, ea_inode)) ext4_warning_inode(ea_inode, "cleanup dec ref error %d", err); - iput(ea_inode); + ext4_put_ea_inode(ea_inode); return ERR_PTR(err); } =20 @@ -1564,7 +1564,7 @@ ext4_xattr_inode_cache_find(struct inode *inode, cons= t void *value, kvfree(ea_data); return ea_inode; } - iput(ea_inode); + ext4_put_ea_inode(ea_inode); next_entry: ce =3D mb_cache_entry_find_next(ea_inode_cache, ce); } @@ -1615,7 +1615,7 @@ static struct inode *ext4_xattr_inode_lookup_create(h= andle_t *handle, ea_inode->i_ino, true /* reusable */); return ea_inode; out_err: - iput(ea_inode); + ext4_put_ea_inode(ea_inode); ext4_xattr_inode_free_quota(inode, NULL, value_len); return ERR_PTR(err); } @@ -1848,7 +1848,7 @@ static int ext4_xattr_set_entry(struct ext4_xattr_inf= o *i, =20 ret =3D 0; out: - iput(old_ea_inode); + ext4_put_ea_inode(old_ea_inode); return ret; } =20 @@ -2010,7 +2010,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *= inode, old_ea_inode_quota =3D le32_to_cpu( s->here->e_value_size); } - iput(tmp_inode); + ext4_put_ea_inode(tmp_inode); =20 s->here->e_value_inum =3D 0; s->here->e_value_size =3D 0; @@ -2150,7 +2150,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *= inode, ext4_warning_inode(ea_inode, "dec ref error=3D%d", error); - iput(ea_inode); + ext4_put_ea_inode(ea_inode); ea_inode =3D NULL; } =20 @@ -2203,7 +2203,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *= inode, ext4_xattr_inode_free_quota(inode, ea_inode, i_size_read(ea_inode)); } - iput(ea_inode); + ext4_put_ea_inode(ea_inode); } if (ce) mb_cache_entry_put(ea_block_cache, ce); @@ -2285,7 +2285,7 @@ int ext4_xattr_ibody_set(handle_t *handle, struct ino= de *inode, =20 ext4_xattr_inode_free_quota(inode, ea_inode, i_size_read(ea_inode)); - iput(ea_inode); + ext4_put_ea_inode(ea_inode); } return error; } @@ -2297,7 +2297,7 @@ int ext4_xattr_ibody_set(handle_t *handle, struct ino= de *inode, header->h_magic =3D cpu_to_le32(0); ext4_clear_inode_state(inode, EXT4_STATE_XATTR); } - iput(ea_inode); + ext4_put_ea_inode(ea_inode); return 0; } =20 @@ -2986,7 +2986,7 @@ int ext4_xattr_delete_inode(handle_t *handle, struct = inode *inode, continue; ext4_xattr_inode_free_quota(inode, ea_inode, le32_to_cpu(entry->e_value_size)); - iput(ea_inode); + ext4_put_ea_inode(ea_inode); } =20 } --=20 2.43.0 From nobody Sun Jul 26 01:57:25 2026 Received: from mx0b-0064b401.pphosted.com (mx0b-0064b401.pphosted.com [205.220.178.238]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A79B7363C57; Fri, 10 Jul 2026 03:09:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.178.238 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783652985; cv=none; b=p83rk7+pL9OPWjjuG0k72qdyjXfUmF71WcavygeOdiVHskl7mU9QdS80MY5BdrFyOYKvwLDEOuUqetMIlJ2eCDgWCsts1RacObJPzE4XSBC7J/M98q2/lGBVrnaiIZXLYjGUoB1/W5yT1Jmf8XTVruxtUtrq/qqQJ7Sl5zp0amU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783652985; c=relaxed/simple; bh=SOf7QzaOdKb5UDC5ib22qQNoRljcias0Iyk9mez5TlU=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=l4DdQFZjcCWZokApmk5kwb7Uaz/QGqPqR3Q+QY7xbiukqKkQkhJQExcX85m6Q5umo+XYHEmKFZRMeG7sOIKplwU22R2LEKUyCqJ5VY/flKd4Y2/5gwAfHQogSB8Np768EkcjlfOmT+iL8bcmqIhWRiDmbEcrN6YsCRt7AjKcrHQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=windriver.com; spf=pass smtp.mailfrom=windriver.com; dkim=pass (2048-bit key) header.d=windriver.com header.i=@windriver.com header.b=YiPDSrjL; arc=none smtp.client-ip=205.220.178.238 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=windriver.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=windriver.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=windriver.com header.i=@windriver.com header.b="YiPDSrjL" Received: from pps.filterd (m0250812.ppops.net [127.0.0.1]) by mx0a-0064b401.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 66A0eC4c3479797; Fri, 10 Jul 2026 03:09:11 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=windriver.com; h=cc:content-transfer-encoding:content-type:date:from :in-reply-to:message-id:mime-version:references:subject:to; s= PPS06212021; bh=49PQtnUUgJMDnBTi8inNSLjUToxTS2gPArRnSjk6vds=; b= YiPDSrjL1rFlt3ejC3YlEes86u8DYvfI9EQKvw50GcSvRHVh0UiT9ATyCkwJrg6d xghHg1X9Zc6kqKSdWinMkUp6H4+f15LvX2odki3ehrZ8diqk0+4T75WGO4H7DSIp Sei55Z2QOEoj7fyc/7gYK74z7i5d3N9nfh3ZqAUUj4jCdZECyF2phabwwV41zHCH 7CYAdv5GwTLCJ5NRN0i7EpKqfHeHOcHa2l4Q2+BtRwUSH6hxkGhVSGpUl5XcmauA +YmPsO1xNDgtKNT6fG/deVm4Ef4Eofth3D0vkgb5DAb7tO/vjoMngAtuqBPScb1f VOEx4bZ2apNg/ZoRbjAuaQ== Received: from ala-exchng02.corp.ad.wrs.com (ala-exchng02.wrs.com [128.224.246.37]) by mx0a-0064b401.pphosted.com (PPS) with ESMTPS id 4fa1h2217y-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT); Fri, 10 Jul 2026 03:09:10 +0000 (GMT) Received: from ala-exchng01.corp.ad.wrs.com (10.11.224.121) by ALA-EXCHNG02.corp.ad.wrs.com (10.11.224.122) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.61; Thu, 9 Jul 2026 20:09:09 -0700 Received: from pek-yzhou-d3.wrs.com (10.11.232.110) by ala-exchng01.corp.ad.wrs.com (10.11.224.121) with Microsoft SMTP Server id 15.1.2507.61 via Frontend Transport; Thu, 9 Jul 2026 20:09:06 -0700 From: Yun Zhou To: , , , , , , , , CC: , , , Subject: [PATCH v14 4/4] ext4: remove ea_inode_array mechanism in favor of ext4_put_ea_inode() Date: Fri, 10 Jul 2026 11:08:51 +0800 Message-ID: <20260710030851.2791589-5-yun.zhou@windriver.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260710030851.2791589-1-yun.zhou@windriver.com> References: <20260710030851.2791589-1-yun.zhou@windriver.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Authority-Analysis: v=2.4 cv=LbIMLDfi c=1 sm=1 tr=0 ts=6a506256 cx=c_pps a=Lg6ja3A245NiLSnFpY5YKQ==:117 a=Lg6ja3A245NiLSnFpY5YKQ==:17 a=RAioF0-LDSMA:10 a=VkNPw1HP01LnGYTKEx00:22 a=bi6dqmuHe4P4UrxVR6um:22 a=fTW__CHxibyLmBMfj2wP:22 a=t7CeM3EgAAAA:8 a=EeJwDUQJ61IywSGq5aMA:9 a=FdTzh2GWekK77mhwV6Dw:22 X-Proofpoint-Spam-Info: AW1haW4tMjYwNzEwMDAyNiBTYWx0ZWRfX8XzxWvPbIWTJ 2earteke2umWk+NQgea2i/RMKX/1To9KbGsXcqTU8HeF2uu3LIAmeLQzb31nWXfwFDQpE2s5Rh0 CSSXtGl89i+4aH6Tn+bpHT/W1oRgGOw3v4jmTvjPJLklZuWLPNqx X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNzEwMDAyNiBTYWx0ZWRfXzE/dOTeGbNuO mUvIPbYA3SKJeu/RbTmfNLBzVAIoY45O9ffueyhB/Onda0qbaI2vSvMnFcho63yLdHp1dTziaxb oiQ4u/klCH2KNZqpLyfeD4GEhamWidgFwiQnmbEnlrSp1xbpxMlyzLodOBSKVZLCXmHIdHMFmgo NLzdLtjq8UxRFW1g82BhcCHeVaAEktjVaKwgieggWJn20ylfrMQe90E/GHvYBi2CSqVcBCuz5PS r+07Cg6fac6qQVPaVy+yXbeWFPAJmAD9KxHCVKBpuhN2Pg91QicwDYvuj3OgpGjmSClCJkJ9NTb fLYQk6YXiTm33udLVKt7Z5ltzeAiQgm+4wbsEPYUqWGYeQppHRUw5tcvk0LYFTj9JmVSPK/VHYZ uTX2tAD1bGju4W0/VCpBPd4yuEGHaW9wJ3xV75vzpACxFecsc5zk8PwWe/mHb6NhBKg9jH2VFC4 WzCSaRmRU3C/xfYrLBA== X-Proofpoint-ORIG-GUID: bu66mHIjzeZIB6qdv09DF1n68Ea9ZmRX X-Proofpoint-GUID: bu66mHIjzeZIB6qdv09DF1n68Ea9ZmRX X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-07-09_04,2026-07-09_04,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 adultscore=0 phishscore=0 priorityscore=1501 malwarescore=0 clxscore=1015 lowpriorityscore=0 bulkscore=0 suspectscore=0 spamscore=0 impostorscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2606150000 definitions=main-2607100026 Content-Type: text/plain; charset="utf-8" Now that ext4_put_ea_inode() handles deferred iput safely for all cases (using iput_if_not_last + embedded llist_node), the ea_inode_array mechanism for batching deferred iputs is redundant. Remove: - ext4_expand_inode_array() and ext4_xattr_inode_array_free() - struct ext4_xattr_inode_array and EIA_INCR/EIA_MASK defines - ea_inode_array parameter from ext4_xattr_inode_dec_ref_all(), ext4_xattr_release_block(), and ext4_xattr_delete_inode() - ea_inode_array variable from ext4_evict_inode() Instead, ext4_xattr_inode_dec_ref_all() now calls ext4_put_ea_inode() directly after processing each EA inode. This simplifies the code by eliminating multi-layer parameter threading and removes the need for callers to manage array lifetime. Signed-off-by: Yun Zhou Suggested-by: Jan Kara Reviewed-by: Jan Kara --- fs/ext4/inode.c | 6 +--- fs/ext4/xattr.c | 80 ++++--------------------------------------------- fs/ext4/xattr.h | 7 ----- 3 files changed, 6 insertions(+), 87 deletions(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 0d131371ad3d..6f1b84e46a2e 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -176,7 +176,6 @@ void ext4_evict_inode(struct inode *inode) * (xattr block freeing), bitmap, group descriptor (inode freeing) */ int extra_credits =3D 6; - struct ext4_xattr_inode_array *ea_inode_array =3D NULL; bool freeze_protected =3D false; =20 trace_ext4_evict_inode(inode); @@ -282,8 +281,7 @@ void ext4_evict_inode(struct inode *inode) } =20 /* Remove xattr references. */ - err =3D ext4_xattr_delete_inode(handle, inode, &ea_inode_array, - extra_credits); + err =3D ext4_xattr_delete_inode(handle, inode, extra_credits); if (err) { ext4_warning(inode->i_sb, "xattr delete (err %d)", err); stop_handle: @@ -291,7 +289,6 @@ void ext4_evict_inode(struct inode *inode) ext4_orphan_del(NULL, inode); if (freeze_protected) sb_end_intwrite(inode->i_sb); - ext4_xattr_inode_array_free(ea_inode_array); goto no_delete; } =20 @@ -321,7 +318,6 @@ void ext4_evict_inode(struct inode *inode) ext4_journal_stop(handle); if (freeze_protected) sb_end_intwrite(inode->i_sb); - ext4_xattr_inode_array_free(ea_inode_array); return; no_delete: /* diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 6a1f2bdb6ff8..4ae6ce111566 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -114,10 +114,6 @@ const struct xattr_handler * const ext4_xattr_handlers= [] =3D { #define EA_INODE_CACHE(inode) (((struct ext4_sb_info *) \ inode->i_sb->s_fs_info)->s_ea_inode_cache) =20 -static int -ext4_expand_inode_array(struct ext4_xattr_inode_array **ea_inode_array, - struct inode *inode); - #ifdef CONFIG_LOCKDEP void ext4_xattr_inode_set_class(struct inode *ea_inode) { @@ -1160,7 +1156,6 @@ static void ext4_xattr_inode_dec_ref_all(handle_t *handle, struct inode *parent, struct buffer_head *bh, struct ext4_xattr_entry *first, bool block_csum, - struct ext4_xattr_inode_array **ea_inode_array, int extra_credits, bool skip_quota) { struct inode *ea_inode; @@ -1197,14 +1192,6 @@ ext4_xattr_inode_dec_ref_all(handle_t *handle, struc= t inode *parent, if (err) continue; =20 - err =3D ext4_expand_inode_array(ea_inode_array, ea_inode); - if (err) { - ext4_warning_inode(ea_inode, - "Expand inode array err=3D%d", err); - ext4_put_ea_inode(ea_inode); - continue; - } - err =3D ext4_journal_ensure_credits_fn(handle, credits, credits, ext4_free_metadata_revoke_credits(parent->i_sb, 1), ext4_xattr_restart_fn(handle, parent, bh, block_csum, @@ -1212,6 +1199,7 @@ ext4_xattr_inode_dec_ref_all(handle_t *handle, struct= inode *parent, if (err < 0) { ext4_warning_inode(ea_inode, "Ensure credits err=3D%d", err); + ext4_put_ea_inode(ea_inode); continue; } if (err > 0) { @@ -1221,6 +1209,7 @@ ext4_xattr_inode_dec_ref_all(handle_t *handle, struct= inode *parent, ext4_warning_inode(ea_inode, "Re-get write access err=3D%d", err); + ext4_put_ea_inode(ea_inode); continue; } } @@ -1229,6 +1218,7 @@ ext4_xattr_inode_dec_ref_all(handle_t *handle, struct= inode *parent, if (err) { ext4_warning_inode(ea_inode, "ea_inode dec ref err=3D%d", err); + ext4_put_ea_inode(ea_inode); continue; } =20 @@ -1245,6 +1235,7 @@ ext4_xattr_inode_dec_ref_all(handle_t *handle, struct= inode *parent, entry->e_value_inum =3D 0; entry->e_value_size =3D 0; =20 + ext4_put_ea_inode(ea_inode); dirty =3D true; } =20 @@ -1271,7 +1262,6 @@ ext4_xattr_inode_dec_ref_all(handle_t *handle, struct= inode *parent, static void ext4_xattr_release_block(handle_t *handle, struct inode *inode, struct buffer_head *bh, - struct ext4_xattr_inode_array **ea_inode_array, int extra_credits) { struct mb_cache *ea_block_cache =3D EA_BLOCK_CACHE(inode); @@ -1313,7 +1303,6 @@ ext4_xattr_release_block(handle_t *handle, struct ino= de *inode, ext4_xattr_inode_dec_ref_all(handle, inode, bh, BFIRST(bh), true /* block_csum */, - ea_inode_array, extra_credits, true /* skip_quota */); ext4_free_blocks(handle, inode, bh, 0, 1, @@ -2182,12 +2171,8 @@ ext4_xattr_block_set(handle_t *handle, struct inode = *inode, =20 /* Drop the previous xattr block. */ if (bs->bh && bs->bh !=3D new_bh) { - struct ext4_xattr_inode_array *ea_inode_array =3D NULL; - ext4_xattr_release_block(handle, inode, bs->bh, - &ea_inode_array, 0 /* extra_credits */); - ext4_xattr_inode_array_free(ea_inode_array); } error =3D 0; =20 @@ -2863,46 +2848,6 @@ int ext4_expand_extra_isize_ea(struct inode *inode, = int new_extra_isize, return error; } =20 -#define EIA_INCR 16 /* must be 2^n */ -#define EIA_MASK (EIA_INCR - 1) - -/* Add the large xattr @inode into @ea_inode_array for deferred iput(). - * If @ea_inode_array is new or full it will be grown and the old - * contents copied over. - */ -static int -ext4_expand_inode_array(struct ext4_xattr_inode_array **ea_inode_array, - struct inode *inode) -{ - if (*ea_inode_array =3D=3D NULL) { - /* - * Start with 15 inodes, so it fits into a power-of-two size. - */ - (*ea_inode_array) =3D kmalloc_flex(**ea_inode_array, inodes, - EIA_MASK, GFP_NOFS); - if (*ea_inode_array =3D=3D NULL) - return -ENOMEM; - (*ea_inode_array)->count =3D 0; - } else if (((*ea_inode_array)->count & EIA_MASK) =3D=3D EIA_MASK) { - /* expand the array once all 15 + n * 16 slots are full */ - struct ext4_xattr_inode_array *new_array =3D NULL; - - new_array =3D kmalloc_flex(**ea_inode_array, inodes, - (*ea_inode_array)->count + EIA_INCR, - GFP_NOFS); - if (new_array =3D=3D NULL) - return -ENOMEM; - memcpy(new_array, *ea_inode_array, - struct_size(*ea_inode_array, inodes, - (*ea_inode_array)->count)); - kfree(*ea_inode_array); - *ea_inode_array =3D new_array; - } - (*ea_inode_array)->count++; - (*ea_inode_array)->inodes[(*ea_inode_array)->count - 1] =3D inode; - return 0; -} - /* * ext4_xattr_delete_inode() * @@ -2913,7 +2858,6 @@ ext4_expand_inode_array(struct ext4_xattr_inode_array= **ea_inode_array, * references on xattr block and xattr inodes. */ int ext4_xattr_delete_inode(handle_t *handle, struct inode *inode, - struct ext4_xattr_inode_array **ea_inode_array, int extra_credits) { struct buffer_head *bh =3D NULL; @@ -2952,7 +2896,6 @@ int ext4_xattr_delete_inode(handle_t *handle, struct = inode *inode, ext4_xattr_inode_dec_ref_all(handle, inode, iloc.bh, IFIRST(header), false /* block_csum */, - ea_inode_array, extra_credits, false /* skip_quota */); } @@ -2991,7 +2934,7 @@ int ext4_xattr_delete_inode(handle_t *handle, struct = inode *inode, =20 } =20 - ext4_xattr_release_block(handle, inode, bh, ea_inode_array, + ext4_xattr_release_block(handle, inode, bh, extra_credits); /* * Update i_file_acl value in the same transaction that releases @@ -3013,19 +2956,6 @@ int ext4_xattr_delete_inode(handle_t *handle, struct= inode *inode, return error; } =20 -void ext4_xattr_inode_array_free(struct ext4_xattr_inode_array *ea_inode_a= rray) -{ - int idx; - - if (ea_inode_array =3D=3D NULL) - return; - - for (idx =3D 0; idx < ea_inode_array->count; ++idx) - iput(ea_inode_array->inodes[idx]); - kfree(ea_inode_array); -} - - /* * Worker function for deferred EA inode iput. Processes all inodes queued * on s_ea_inode_to_free in a context free of xattr_sem/jbd2 handle locks. diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h index 2ff4b6eccd40..821dc6a50e51 100644 --- a/fs/ext4/xattr.h +++ b/fs/ext4/xattr.h @@ -131,11 +131,6 @@ struct ext4_xattr_ibody_find { struct ext4_iloc iloc; }; =20 -struct ext4_xattr_inode_array { - unsigned int count; - struct inode *inodes[] __counted_by(count); -}; - extern const struct xattr_handler ext4_xattr_user_handler; extern const struct xattr_handler ext4_xattr_trusted_handler; extern const struct xattr_handler ext4_xattr_security_handler; @@ -187,9 +182,7 @@ extern int __ext4_xattr_set_credits(struct super_block = *sb, struct inode *inode, bool is_create); =20 extern int ext4_xattr_delete_inode(handle_t *handle, struct inode *inode, - struct ext4_xattr_inode_array **array, int extra_credits); -extern void ext4_xattr_inode_array_free(struct ext4_xattr_inode_array *arr= ay); extern void ext4_init_ea_inode_work(struct ext4_sb_info *sbi); extern void ext4_put_ea_inode(struct inode *inode); =20 --=20 2.43.0