From nobody Sat Jul 25 19:29:02 2026 Received: from mail-pl1-f172.google.com (mail-pl1-f172.google.com [209.85.214.172]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9D2D935C19F for ; Tue, 14 Jul 2026 11:35:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784028933; cv=none; b=Stwd8brFpH3biAXsEyIbPiLqoS3gS9d3+8VOzqCXO0G4k0+9ISqJaQz8qps96fYf4A5zsJMKMFPyuPo/jBD/YWXTNfltMe4JMVG2ebPhOZFceJEUviVCITvGfs5/56WH3Z77rl2VUj7uDquYN94UrAgZO3/i5jJ4jvkWL1BGQMg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784028933; c=relaxed/simple; bh=WjnUawCLeFwHSvXkapZrGBL5/JyH1weZ6fe5N5IsYV8=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=MnfTGmP9fKI8T0jGT6nvkLxE0bPZZUYhyiKwifpKhYIdOrHFJYOR72tNgQxbkIdzTaH1d0NeJL5zea0i7PtoVSCykdKY97grb6vrPaCJDuxXtTGQjr4q6oLClBDwwml0f7uiRM1DkyZjxmuJtzoGPBfRW5uyELFT24vmnMzxojg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=kKpCcav8; arc=none smtp.client-ip=209.85.214.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="kKpCcav8" Received: by mail-pl1-f172.google.com with SMTP id d9443c01a7336-2cc891373e0so49350565ad.2 for ; Tue, 14 Jul 2026 04:35:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1784028932; x=1784633732; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to:content-type; bh=jvrHeqvmCVB3+5coRQtr0R7Of7xWrHzHhep15z+ep+E=; b=kKpCcav8zVhspyEvN9esTMHkyXjUFgDw/Qmprm8bhMnKpIQNxHgPhNunhFe3qYIdx7 pf/EuWVcR3Ub9WTjFH9SPOIAIYsTHfzeUPuudQFBpWYsQXcOH7p03aye2aSxZIWc9wGi w6Bo9m0yFBX6dLGweTRRNx43XtshFqSjMuBnTgi79x06BxCPHpqcS58AGUKOX8qSwbP4 dpbixcosvN2EOoHJnG8tbfTRbkrFcazBSzZQixSEPxL2asRmQ+2ekv/hk/jCGJUE3Woh 0ywa/xiDSSC1lRvKYB3CgPuUEZvcj1tr9ebDEvZEALQaGumCszux0q5Waqnk7GKO+Otn eSnw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784028932; x=1784633732; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=jvrHeqvmCVB3+5coRQtr0R7Of7xWrHzHhep15z+ep+E=; b=i890UvdXPIefLAIhOUYqJmbGw7MdLqNYgs3zYqf4/B/C/bfk4stxqv91fe2VR8cfCt xMKGqtJy+X6C6W5AW/v+B0V/SdLSI8NX+lLfvDswRBq2QB/KPKkWR8jdMK2I61pDysEN KGRYhDadPafegiDR2wd5noeaKNgmZsk4bk866YeELIjcMOTyYYRTEgkYq/3wfjS+kDt7 AlJi0dQoViaXUxFT7FJCfY+l1KeOqsCmOdndcQsQ7LQNA4kHJy3aVzfmh8RYUOgHQ5PU hJFBF3N0zfP5d3D/+pDxNaO9rHAxCPNSH5NE+d6sRbPjAMnujQYLYy0L9Hp2m623nw9o 3FCQ== X-Forwarded-Encrypted: i=1; AHgh+RpK39lRYve+ql27XDeTrhezjP0C8m1i5C0WGKKDRjS0QINqeUzJWDvBHPeGfILRPoOBOusbnbkoIiFO/L4=@vger.kernel.org X-Gm-Message-State: AOJu0YzwKYGnvt0f0SpG10E4NCgAa/PBevTwcC/gReEIIJtFu0feuSfa qrz55hm5Xnf2SUIVj6IRwglz4B4xZfH4tIJLi4WVYqQh6bxIfE4CMND0 X-Gm-Gg: AfdE7cnVu4QKCyUaQqRjkWw3Uh2XFnve2uO0Rs+919f7zgLm1E3ief0mACAV2r19csy 4kHosv2jtn/nUElfo3dwwJdahXREHlcy84VBzzE3EzGF6BMcOaGPARqYBPlTstgjznTUPXj0Eah DK01LrfsJ2MQkizhCl5ufqY47kKDYSLs+NkgfzNwCqFZVyD9RZtsvyUDgwV5/b42dX1tjWyDUq3 +KjNpmUaD91RTb1udbU7a3WzYrJmFRthHO3/ox4fvQvVPAZ+r07w1RjTdCyC647PuPsxt+0ju2y 6tu2IC+RZhX/NHCxxDQ3lu5F3vd9PgiPmv34Lj6RzQwc8DjlyrEmKTqI6bNiT+/oZd4xG+nkF3z qlsxu3gA7s2D617jXa8VGiXhx2MJlVK1wvK5KuDPmIxQwtBtVZYlsMq3TeLh+joON/whR0cGuXA UbmT2apnoor+H1 X-Received: by 2002:a17:903:240c:b0:2c9:da58:17dd with SMTP id d9443c01a7336-2ce9f050e8emr116205925ad.34.1784028931848; Tue, 14 Jul 2026 04:35:31 -0700 (PDT) Received: from lgs.. ([101.36.106.46]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2ccc9d3bbaesm114482675ad.57.2026.07.14.04.35.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 14 Jul 2026 04:35:31 -0700 (PDT) From: Guangshuo Li To: Mark Fasheh , Joel Becker , Joseph Qi , Tristan Ye , ocfs2-devel@lists.linux.dev, linux-kernel@vger.kernel.org Cc: Guangshuo Li Subject: [PATCH v2] ocfs2: free unused clusters on defrag move errors Date: Tue, 14 Jul 2026 19:35:17 +0800 Message-ID: <20260714113517.1381604-1-lgs201920130244@gmail.com> X-Mailer: git-send-email 2.43.0 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 Content-Type: text/plain; charset="utf-8" ocfs2_defrag_extent() claims new clusters before calling __ocfs2_move_extent(). If the move fails before the extent tree update is attempted, the claimed clusters are not referenced by the inode and must be released. The current error path only logs the error and continues to ocfs2_cow_sync_writeback(), which can overwrite the original error with zero. The claimed clusters are also left allocated. Not every __ocfs2_move_extent() error can free the new clusters, however. Once ocfs2_split_extent() has been called, the extent tree may already reference them even if a later operation fails. Freeing them in that case would leave the extent tree pointing to clusters marked free. Track whether the extent split has been started. On errors before that point, report that the new clusters remain unused so the defrag caller can release them. Once the split has started, leave the clusters allocated. Return all move errors through the transaction cleanup path without allowing writeback to overwrite them. Fixes: 202ee5facb2c ("Ocfs2/move_extents: defrag a range of extent.") Signed-off-by: Guangshuo Li --- v2: - Do not free the new clusters after the extent-tree update has started, as pointed out by Joseph Qi. - Track whether the new clusters remain unused on error. - Preserve __ocfs2_move_extent() errors instead of allowing the subsequent writeback call to overwrite them. fs/ocfs2/move_extents.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/fs/ocfs2/move_extents.c b/fs/ocfs2/move_extents.c index ad1678ee7cc4..138c65d21668 100644 --- a/fs/ocfs2/move_extents.c +++ b/fs/ocfs2/move_extents.c @@ -49,9 +49,10 @@ struct ocfs2_move_extents_context { static int __ocfs2_move_extent(handle_t *handle, struct ocfs2_move_extents_context *context, u32 cpos, u32 len, u32 p_cpos, u32 new_p_cpos, - int ext_flags) + int ext_flags, bool *new_clusters_unused) { int ret =3D 0, index; + bool split_started =3D false; struct inode *inode =3D context->inode; struct ocfs2_super *osb =3D OCFS2_SB(inode->i_sb); struct ocfs2_extent_rec *rec, replace_rec; @@ -59,6 +60,10 @@ static int __ocfs2_move_extent(handle_t *handle, struct ocfs2_extent_list *el; u64 ino =3D ocfs2_metadata_cache_owner(context->et.et_ci); u64 old_blkno =3D ocfs2_clusters_to_blocks(inode->i_sb, p_cpos); + bool split_started =3D false; + + if (new_clusters_unused) + *new_clusters_unused =3D false; =20 ret =3D ocfs2_duplicate_clusters_by_page(handle, inode, cpos, p_cpos, new_p_cpos, len); @@ -111,6 +116,7 @@ static int __ocfs2_move_extent(handle_t *handle, */ replace_rec.e_flags =3D ext_flags & ~OCFS2_EXT_REFCOUNTED; =20 + split_started =3D true; ret =3D ocfs2_split_extent(handle, &context->et, path, index, &replace_rec, context->meta_ac, &context->dealloc); @@ -138,6 +144,9 @@ static int __ocfs2_move_extent(handle_t *handle, =20 ocfs2_update_inode_fsync_trans(handle, inode, 0); out: + if (ret && !split_started && new_clusters_unused) + *new_clusters_unused =3D true; + ocfs2_free_path(path); return ret; } @@ -209,6 +218,7 @@ static int ocfs2_defrag_extent(struct ocfs2_move_extent= s_context *context, struct ocfs2_refcount_tree *ref_tree =3D NULL; u32 new_phys_cpos, new_len; u64 phys_blkno =3D ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos); + bool new_clusters_unused; int need_free =3D 0; =20 if ((ext_flags & OCFS2_EXT_REFCOUNTED) && *len) { @@ -309,9 +319,14 @@ static int ocfs2_defrag_extent(struct ocfs2_move_exten= ts_context *context, phys_cpos, new_phys_cpos); =20 ret =3D __ocfs2_move_extent(handle, context, cpos, new_len, phys_cpos, - new_phys_cpos, ext_flags); - if (ret) + new_phys_cpos, ext_flags, + &new_clusters_unused); + if (ret) { mlog_errno(ret); + if (new_clusters_unused) + need_free =3D 1; + goto out_commit; + } =20 if (partial && (new_len !=3D *len)) *len =3D new_len; @@ -684,7 +699,7 @@ static int ocfs2_move_extent(struct ocfs2_move_extents_= context *context, } =20 ret =3D __ocfs2_move_extent(handle, context, cpos, len, phys_cpos, - *new_phys_cpos, ext_flags); + *new_phys_cpos, ext_flags, NULL); if (ret) { mlog_errno(ret); goto out_commit; --=20 2.43.0