From nobody Fri Apr 3 02:56:57 2026 Received: from mail-pl1-f179.google.com (mail-pl1-f179.google.com [209.85.214.179]) (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 77FC620C490 for ; Wed, 25 Mar 2026 00:43:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.179 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774399440; cv=none; b=JyPKhMtHRQPe7r+7s7ZnXmiA35EXYWOMtqCdeUqnKsfH/GdASkEbj1PYFrc2sUF6/RluiIAXwKqY7fmfPQq3mt258ZxLlkAD/agV7nWATe67umMIjYT2P599TQ+USmMOiofFq+O9A6V8MP6Vh6mGenl9HUzFsD5Q4cfR/vV4Ybc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774399440; c=relaxed/simple; bh=Nd0atCCstaJ2Fwk9EQFaGAl7hAjSKTfwkXCd4sAxmjA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=hImT1h4VJPNfS+6fpEmRq2XlO1JKtDz6vsuKd060iqk27UKixM71Khqa15AgrAnynomRC+cnjkvQ7fJ13p76VPCST6/4N1FN7/OcC0FAoI0rpA1zNxNWkTDeMsTRqZP3hUZcOk4ICcu9xjAf3we+hqIVPxZw25AMZsozGWRiqR0= 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=ja/75nDU; arc=none smtp.client-ip=209.85.214.179 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="ja/75nDU" Received: by mail-pl1-f179.google.com with SMTP id d9443c01a7336-2a9296b3926so14991235ad.1 for ; Tue, 24 Mar 2026 17:43:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1774399435; x=1775004235; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=LTSd+cTo/0b497i3cXRpwad9mDPRGXICrLQ2yK5ereM=; b=ja/75nDUAZ8RNoAKD+mpQPfUtmkqwOwoUyNIV6bjCKpRoYoBQZlYR++w+LsYUXpzQI vEdDse2AqqK+2OKRu+PkqdTnBZ2eKr+p+PvVmiDxkH6sLwTvMMZWEXvHoGFiO2FLUuik Xr8Duz1OL41FE1GDnVQHpfjjYVbP7Qys0kB9sYTRIo84/PTA2Rrh+zffh9NDf2AMvbo2 sm9ZUj4kik/AxydwGRAdqK3tYrm/tuZ8C1DCZbIp9MFhFzwdv6CwrcUt+1wytM1fHBtN pVR9pagKvYP9LYS6r6mBKYqh83Gl59Ui3WlQpPgW39p5NpdibYQWL063URos4f2uk/PN b4qA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1774399435; x=1775004235; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=LTSd+cTo/0b497i3cXRpwad9mDPRGXICrLQ2yK5ereM=; b=GGb81FANHkNdRY8IVVz4SRSUvYbqTFe6+qCn4FrSgcvQkd1lKbNL5r4+vhqIO8PfQg 7i9t3S1cq+ewSE+U5slmhPINAX5BVb1YiSvViTKlmfiNKtAI8kgIVT3EcpzI25MSvJj2 89oXoOPLREhizUGfRlXZ176pZSa6DiOpZXkCUbwxH89aVQQL1ox/ysR+P1EJDinMnFRj DYVrbUMSWEXwpALwvTC8PQSV+8tF5VkzKEGwYHRd6rz3Zth2gbgIF6U48CQLPQkueM2S ST7C8pLwlY8piH4xiex6ffql9RhsqEOLxZGt1StrCZVw+l9ErlcGy6ZMQqN4CCzGz2wk ZmrA== X-Forwarded-Encrypted: i=1; AJvYcCWwuC8AvC3Wwiu0EJN/ehR22AEmzeR/VX6Nii/Gh4HaQNFAAKzHk+xL14GQOCsQawtCyPQGegWQO9W9cv8=@vger.kernel.org X-Gm-Message-State: AOJu0Yz+JgMzt5Zet9BWtRwyr8WBQqCR51NYmJHKto600fhKdBj2GuYw 5fQqVVV69kW4f0hkhLEI2QEvZWHPF+MD1I23CpTtYAjSH5NBZma6B8bY X-Gm-Gg: ATEYQzwcWfpdzvhdM3N7M57vxeQvZLAFWsOGWdyAR5iZaauc0tfWRUrfMed7vA0TLjp nE42zleMjYu4YSRGQs+yXK1GXA6cvnMj80y1E2iMnQ7sSle4W7SDkxNP9e0LmfGiCKVtfI7tpzV iSQNjuuiPvBOVMxaUPkf46aU2i39KMMBx3nbyXHfs+RDJL6uIQIOWHLGQYTRg/IyTXkSAv6qxig xa0bSMm0xWuNhM/MyVArGHyqNax2+hkfozt5m66tJjCkF/TNtoiPSqR4FEeFB3gymMc76HOTXBE KoM1hZx+nlI1vsvlXhIefbnGDLYWWoxL6wt3bfbcfmjSai/VAq7xt8tmujmnYriVxgsHCp8cISG h8qgZ9xzPiGa5WAmQTC5CbmR/PWuxAsxD07CrWN4WoQ8ODYCRu0+ezagMDtxQoJTEJxGIODJzKV TyRvmMz0hgmIIreTreny7aqqhpdCM9LGrUehtdldbHDRtYh9r0TvQ7iEAzP37F/30ntyETd8rZ3 jEwPatGLA== X-Received: by 2002:a17:903:22d2:b0:2b0:4f82:74ce with SMTP id d9443c01a7336-2b0b0b2f889mr15838615ad.46.1774399434637; Tue, 24 Mar 2026 17:43:54 -0700 (PDT) Received: from kernel-fuzz.. ([103.172.182.26]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2b0836554acsm207457015ad.51.2026.03.24.17.43.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 24 Mar 2026 17:43:53 -0700 (PDT) From: ZhengYuan Huang To: dsterba@suse.com, clm@fb.com, idryomov@gmail.com Cc: linux-btrfs@vger.kernel.org, linux-kernel@vger.kernel.org, baijiaju1990@gmail.com, r33s3n6@gmail.com, zzzccc427@gmail.com, ZhengYuan Huang Subject: [PATCH v3 1/4] btrfs: balance: fix null-ptr-deref in chunk_usage_filter Date: Wed, 25 Mar 2026 08:43:36 +0800 Message-ID: <20260325004339.2323838-2-gality369@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260325004339.2323838-1-gality369@gmail.com> References: <20260325004339.2323838-1-gality369@gmail.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 Content-Type: text/plain; charset="utf-8" [BUG] Running btrfs balance with a usage filter (-dusage=3DN) can trigger a null-ptr-deref when metadata corruption causes a chunk to have no corresponding block group in the in-memory cache: KASAN: null-ptr-deref in range [0x0000000000000070-0x0000000000000077] RIP: 0010:chunk_usage_filter fs/btrfs/volumes.c:3874 [inline] RIP: 0010:should_balance_chunk fs/btrfs/volumes.c:4018 [inline] RIP: 0010:__btrfs_balance fs/btrfs/volumes.c:4172 [inline] RIP: 0010:btrfs_balance+0x2024/0x42b0 fs/btrfs/volumes.c:4604 ... Call Trace: btrfs_ioctl_balance fs/btrfs/ioctl.c:3577 [inline] btrfs_ioctl+0x25cf/0x5b90 fs/btrfs/ioctl.c:5313 vfs_ioctl fs/ioctl.c:51 [inline] ... The bug is reproducible on next-20260312. [CAUSE] Two separate data structures are involved: 1. The on-disk chunk tree, which records every chunk (logical address space region) and is iterated by __btrfs_balance(). 2. The in-memory block group cache (fs_info->block_group_cache_tree), which is built at mount time by btrfs_read_block_groups() and holds a struct btrfs_block_group for each chunk. This cache is what the usage filter queries. On a well-formed filesystem, these two are kept in 1:1 correspondence. However, btrfs_read_block_groups() builds the cache from block group items in the extent tree, not directly from the chunk tree. A corrupted image can therefore contain a chunk item in the chunk tree whose corresponding block group item is absent from the extent tree; that chunk's block group is then never inserted into the in-memory cache. When balance iterates the chunk tree and reaches such an orphaned chunk, should_balance_chunk() calls chunk_usage_filter(), which queries the block group cache: cache =3D btrfs_lookup_block_group(fs_info, chunk_offset); chunk_used =3D cache->used; /* cache may be NULL */ btrfs_lookup_block_group() returns NULL silently when no cached entry covers chunk_offset. chunk_usage_filter() does not check the return value, so the immediately following dereference of cache->used triggers the crash. [FIX] Add a NULL check after btrfs_lookup_block_group() in chunk_usage_filter(). When the lookup fails, emit a btrfs_err() message identifying the affected bytenr and return -EUCLEAN to indicate filesystem corruption. Since chunk_usage_filter() now has an error path, change its return type from bool to int: negative errno on error, 0 if the chunk passes the usage filter, and 1 if it should be skipped. Update should_balance_chunk() accordingly to propagate negative errors from the usage filter path while still returning 0 for chunks that should not be balanced and 1 for chunks that should be balanced. Finally, handle the new negative return in __btrfs_balance() by jumping to the existing error path, which aborts the balance operation and reports the error to userspace. After the fix, the same corruption is correctly detected and reported by the filter, and the null-ptr-deref is no longer triggered. Fixes: 5ce5b3c0916b ("Btrfs: usage filter") Signed-off-by: ZhengYuan Huang --- fs/btrfs/volumes.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 2bec544d8ba3..1eca5fa6bdaa 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -3863,14 +3863,20 @@ static bool chunk_usage_range_filter(struct btrfs_f= s_info *fs_info, u64 chunk_of return ret; } =20 -static bool chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_of= fset, - struct btrfs_balance_args *bargs) +static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_off= set, + struct btrfs_balance_args *bargs) { struct btrfs_block_group *cache; u64 chunk_used, user_thresh; - bool ret =3D true; + int ret =3D 1; =20 cache =3D btrfs_lookup_block_group(fs_info, chunk_offset); + if (!cache) { + btrfs_err(fs_info, + "balance: chunk at bytenr %llu has no corresponding block group", + chunk_offset); + return -EUCLEAN; + } chunk_used =3D cache->used; =20 if (bargs->usage_min =3D=3D 0) @@ -3881,7 +3887,7 @@ static bool chunk_usage_filter(struct btrfs_fs_info *= fs_info, u64 chunk_offset, user_thresh =3D mult_perc(cache->length, bargs->usage); =20 if (chunk_used < user_thresh) - ret =3D false; + ret =3D 0; =20 btrfs_put_block_group(cache); return ret; @@ -3986,8 +3992,8 @@ static bool chunk_soft_convert_filter(u64 chunk_type,= struct btrfs_balance_args return false; } =20 -static bool should_balance_chunk(struct extent_buffer *leaf, struct btrfs_= chunk *chunk, - u64 chunk_offset) +static int should_balance_chunk(struct extent_buffer *leaf, struct btrfs_c= hunk *chunk, + u64 chunk_offset) { struct btrfs_fs_info *fs_info =3D leaf->fs_info; struct btrfs_balance_control *bctl =3D fs_info->balance_ctl; @@ -4014,9 +4020,13 @@ static bool should_balance_chunk(struct extent_buffe= r *leaf, struct btrfs_chunk } =20 /* usage filter */ - if ((bargs->flags & BTRFS_BALANCE_ARGS_USAGE) && - chunk_usage_filter(fs_info, chunk_offset, bargs)) { - return false; + if (bargs->flags & BTRFS_BALANCE_ARGS_USAGE) { + int ret2 =3D chunk_usage_filter(fs_info, chunk_offset, bargs); + + if (ret2 < 0) + return ret2; + if (ret2) + return false; } else if ((bargs->flags & BTRFS_BALANCE_ARGS_USAGE_RANGE) && chunk_usage_range_filter(fs_info, chunk_offset, bargs)) { return false; @@ -4172,6 +4182,10 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_= info) ret =3D should_balance_chunk(leaf, chunk, found_key.offset); =20 btrfs_release_path(path); + if (ret < 0) { + mutex_unlock(&fs_info->reclaim_bgs_lock); + goto error; + } if (!ret) { mutex_unlock(&fs_info->reclaim_bgs_lock); goto loop; --=20 2.43.0 From nobody Fri Apr 3 02:56:57 2026 Received: from mail-pg1-f180.google.com (mail-pg1-f180.google.com [209.85.215.180]) (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 B81B620010C for ; Wed, 25 Mar 2026 00:43:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.180 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774399441; cv=none; b=jjp8XRxJuMsb3kC7tJxqU6tLzMHnYyb5+4IYFZmYgp4dV1CuEmeAryqrReY3Q02tkqVL+2fFB68jJjQG34fboYm7QKlsGOZj5o5tBW2/DLVJ6YPE07WaNU8GehY4zroqbftwHoEaOBuHK43pJGgGpGphLoW/dZEbeZwIMJTTLFg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774399441; c=relaxed/simple; bh=X/ADdL55Wq79O+zgdY2NaaKquYurrKe1Xz1yObkBMZ4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=e2k31s3p2SAUaUm+2fwqACJW5aAeKuF+DgQM9yV55eHC4V+n38qqYMZ+o+oas1T+iCe3dQdGkza0nq4wo3AIm1SP5U29GL0jqFy2w+KCEU4ujCvlm7zFsQ251lnBGaYHEpcQmQe2Gw2M38xcF/sHT0G5tHTzZDlYCgSf/kCA+S0= 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=pLFrufiv; arc=none smtp.client-ip=209.85.215.180 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="pLFrufiv" Received: by mail-pg1-f180.google.com with SMTP id 41be03b00d2f7-c742824e1d3so1892437a12.1 for ; Tue, 24 Mar 2026 17:43:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1774399439; x=1775004239; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=XemfYTcNf/J0nNi8IYSOThdWpd+g/3/8cxAQ3WKtoik=; b=pLFrufivrQgJbX6XVMALGBiMDMhkdYQTDsa58b7ZPhLwfpew+xMbUoIAMISK65PTDc aGH1H4XAAO5Z/inw3IEkBPinZ3tv0wK5aCjDaZwyixYRVoen8QCzoqlfRSoFynnINRAP dPXvkc9VF00NET57oTnA3blCX8/GcXPkXFqa6sQW/m3swB0MKPP9mEjUDWIH3uc2dsjM foQUzfafl3vBSQj7U1wC+bS8Euo2pt+FeSai8p03Z7o/bXsLrTMblCLzG7DNDtQ2nrfN r5cC6WO3EAH6lRIkPlwkp5gYZtjPdXG1yTagNjynJq3VDw2da2DfkfvvQVWY0UOMiXLF uLPw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1774399439; x=1775004239; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=XemfYTcNf/J0nNi8IYSOThdWpd+g/3/8cxAQ3WKtoik=; b=KSSLD/ZbMDCtBkmahX5WdKfYJNbMIHprQbuRbh+kKfUQZRnXqXOBcSSlpvvgllfCj0 UDX/0ee5I8u56nWLa8hINRd/nhUWrXGRN8TQfDrmDNUNiQh8WpNUezVlgXeRZHJa7CKn yjDtf+5HUBqdjnFMAUkvu08zgnv6AJrbLsISz/aFel7erJeXrj4nor/K3TAZh6zCa7ID 8Q3s2vhxu3c9fq9mPNNnqrACaijczEskCxM3Sfb3DxCPh+bBxUVAesNnBK5YLiUnX7aN zk7FiP5aL/oYkYZOzId84aVTpD69HOalfvizqDCkxhCupr4NC4ZJGwCO3uobHylU4geM zHeA== X-Forwarded-Encrypted: i=1; AJvYcCXwtB6SKfYWl3UmINroxDt5LKCzlaROTzlWr9n78itbh4aBYzeKmQkKQMlusa9Dw/JXdq2AIiucAQ+BVBg=@vger.kernel.org X-Gm-Message-State: AOJu0Yy0DJ6rphNnxvDPlgKHwxXUYo9TtJynlYSqNVFj0f8NTNaO9yGM tXmkkjq2s7OqnTmOmWivsFgnY2OXKHIphMzehb5nLZH6qLwQJ/oGBo3A X-Gm-Gg: ATEYQzwVwjPVy5GrtxNCsOYfMjgW0G/sokYeiGfI5wYruafRilkWVepS2DhHFgShgLn TbM79i9JESSQqifQOjNhyELKniI9xX7AxGaJF2s5mhSw+y8sxxih4Oo18ECXjk4wvBLxNzbnuFQ K4IZXEV9CP7qdtKS6UQUVsaLVTxqEoFaT+X/DuiNV8Zo1X1ZjX02A3XrzEmlLpl+fdlBQ6XoRl0 0qrIhDNUlMVBPEHN6eYdRkTaWqMuHuS+5LKeRyhIHcnCK+zTfNXbst+t5hTe3OYOX0dMKPgdEsW DUCnCpNMEliTq7LmqFrhHH5kJgl22M60tCAs9AJrLmNh6QKk+ylZA7sV2+SRyy8nCi5F8WZO7UY yPiLOg11iMfjY/6sL3WGaolfYrcMYJODNGzM2+z9VetL4nQ0wOIDK1/d7BZUOaTvuHXRWHxTJ0v M6JuLWL8mPHpG8z44jQPSF0dAvOFUjHRZDLMKlqVuUHOvNiUQfM8YWNK8OrbEvp8rYm6c+j6Y= X-Received: by 2002:a17:903:1252:b0:2b0:5694:7b62 with SMTP id d9443c01a7336-2b0b0af42c3mr15993425ad.44.1774399439012; Tue, 24 Mar 2026 17:43:59 -0700 (PDT) Received: from kernel-fuzz.. ([103.172.182.26]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2b0836554acsm207457015ad.51.2026.03.24.17.43.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 24 Mar 2026 17:43:58 -0700 (PDT) From: ZhengYuan Huang To: dsterba@suse.com, clm@fb.com, idryomov@gmail.com Cc: linux-btrfs@vger.kernel.org, linux-kernel@vger.kernel.org, baijiaju1990@gmail.com, r33s3n6@gmail.com, zzzccc427@gmail.com, ZhengYuan Huang Subject: [PATCH v3 2/4] btrfs: balance: fix null-ptr-deref in chunk_usage_range_filter Date: Wed, 25 Mar 2026 08:43:37 +0800 Message-ID: <20260325004339.2323838-3-gality369@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260325004339.2323838-1-gality369@gmail.com> References: <20260325004339.2323838-1-gality369@gmail.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 Content-Type: text/plain; charset="utf-8" [BUG] Running btrfs balance with a usage range filter (-dusage=3Dmin..max) can trigger a null-ptr-deref when metadata corruption causes a chunk to have no corresponding block group in the in-memory cache: KASAN: null-ptr-deref in range [0x0000000000000070-0x0000000000000077] RIP: 0010:chunk_usage_range_filter fs/btrfs/volumes.c:3845 [inline] RIP: 0010:should_balance_chunk fs/btrfs/volumes.c:4031 [inline] RIP: 0010:__btrfs_balance fs/btrfs/volumes.c:4182 [inline] RIP: 0010:btrfs_balance+0x249e/0x4320 fs/btrfs/volumes.c:4618 ... Call Trace: btrfs_ioctl_balance fs/btrfs/ioctl.c:3577 [inline] btrfs_ioctl+0x25cf/0x5b90 fs/btrfs/ioctl.c:5313 vfs_ioctl fs/ioctl.c:51 [inline] ... The bug is reproducible on next-20260312. [CAUSE] Two separate data structures are involved: 1. The on-disk chunk tree, which records every chunk (logical address space region) and is iterated by __btrfs_balance(). 2. The in-memory block group cache (fs_info->block_group_cache_tree), which is built at mount time by btrfs_read_block_groups() and holds a struct btrfs_block_group for each chunk. This cache is what the usage range filter queries. On a well-formed filesystem, these two are kept in 1:1 correspondence. However, btrfs_read_block_groups() builds the cache from block group items in the extent tree, not directly from the chunk tree. A corrupted image can therefore contain a chunk item in the chunk tree whose corresponding block group item is absent from the extent tree; that chunk's block group is then never inserted into the in-memory cache. When balance iterates the chunk tree and reaches such an orphaned chunk, should_balance_chunk() calls chunk_usage_range_filter(), which queries the block group cache: cache =3D btrfs_lookup_block_group(fs_info, chunk_offset); chunk_used =3D cache->used; /* cache may be NULL */ btrfs_lookup_block_group() returns NULL silently when no cached entry covers chunk_offset. chunk_usage_range_filter() does not check the return value, so the immediately following dereference of cache->used triggers the crash. [FIX] Add a NULL check after btrfs_lookup_block_group() in chunk_usage_range_filter(). When the lookup fails, emit a btrfs_err() message identifying the affected bytenr and return -EUCLEAN to indicate filesystem corruption. Since chunk_usage_range_filter() now has an error path, change its return type from bool to int: negative errno on error, 0 if the chunk matches the usage range, and 1 if it should be filtered out. Update the BTRFS_BALANCE_ARGS_USAGE_RANGE branch in should_balance_chunk() to propagate negative errors from chunk_usage_range_filter() instead of treating them as a normal filter result. After the fix, the same corruption is correctly detected and reported by the filter, and the null-ptr-deref is no longer triggered. Fixes: bc3094673f22 ("btrfs: extend balance filter usage to take minimum an= d maximum") Signed-off-by: ZhengYuan Huang --- fs/btrfs/volumes.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 1eca5fa6bdaa..65df8652d760 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -3832,16 +3832,22 @@ static bool chunk_profiles_filter(u64 chunk_type, s= truct btrfs_balance_args *bar return true; } =20 -static bool chunk_usage_range_filter(struct btrfs_fs_info *fs_info, u64 ch= unk_offset, - struct btrfs_balance_args *bargs) +static int chunk_usage_range_filter(struct btrfs_fs_info *fs_info, u64 chu= nk_offset, + struct btrfs_balance_args *bargs) { struct btrfs_block_group *cache; u64 chunk_used; u64 user_thresh_min; u64 user_thresh_max; - bool ret =3D true; + int ret =3D 1; =20 cache =3D btrfs_lookup_block_group(fs_info, chunk_offset); + if (!cache) { + btrfs_err(fs_info, + "balance: chunk at bytenr %llu has no corresponding block group", + chunk_offset); + return -EUCLEAN; + } chunk_used =3D cache->used; =20 if (bargs->usage_min =3D=3D 0) @@ -3857,7 +3863,7 @@ static bool chunk_usage_range_filter(struct btrfs_fs_= info *fs_info, u64 chunk_of user_thresh_max =3D mult_perc(cache->length, bargs->usage_max); =20 if (user_thresh_min <=3D chunk_used && chunk_used < user_thresh_max) - ret =3D false; + ret =3D 0; =20 btrfs_put_block_group(cache); return ret; @@ -4027,9 +4033,13 @@ static int should_balance_chunk(struct extent_buffer= *leaf, struct btrfs_chunk * return ret2; if (ret2) return false; - } else if ((bargs->flags & BTRFS_BALANCE_ARGS_USAGE_RANGE) && - chunk_usage_range_filter(fs_info, chunk_offset, bargs)) { - return false; + } else if (bargs->flags & BTRFS_BALANCE_ARGS_USAGE_RANGE) { + int ret2 =3D chunk_usage_range_filter(fs_info, chunk_offset, bargs); + + if (ret2 < 0) + return ret2; + if (ret2) + return false; } =20 /* devid filter */ --=20 2.43.0 From nobody Fri Apr 3 02:56:57 2026 Received: from mail-pl1-f170.google.com (mail-pl1-f170.google.com [209.85.214.170]) (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 D8014217704 for ; Wed, 25 Mar 2026 00:44:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.170 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774399445; cv=none; b=KPnen0sHMzh9uTogd/bpr1Hm+pjqjeBQeAYfUyMIs3X65w5vPQ6Zo43VEid4yM2w2uA/fwZrU2d8iN+zav9ZtQE3KRnuHDk8C9jh0Of21TSnPmPJFQMP4wf6GX70HeHgWF6VdATNQZuO5r5uYFK/mLZP/PSPOkHVHHP5iqxLZGw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774399445; c=relaxed/simple; bh=JLF9UZfXxMEmFArZnVwjL4KjhH5VxvRV1eSsRU9KZpk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=jjIRQPI6V7w57gORp+Q4yt7EXn8CRlDXhxc/bJRUHdSbwr0bN52PpahC++HVcpHO1fp8xj3gifJJghYBElRMhEBJ9Bs/+YRK2GfNKxn03LB7ffcrisQvzAIAut9NFpvL5c3TRpOlAaxCsIVTT5KzDaXnFxMa5iAHEhq6NW0m8VQ= 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=gh80qZks; arc=none smtp.client-ip=209.85.214.170 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="gh80qZks" Received: by mail-pl1-f170.google.com with SMTP id d9443c01a7336-2aaed195901so25173745ad.0 for ; Tue, 24 Mar 2026 17:44:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1774399443; x=1775004243; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=KdSSlv0LVdyZD0+zj1U8PtUbtcqZsX166xUNgywcviU=; b=gh80qZks7xtAwFuN6XKzbKCQUPazOHz1wNDGGLqup+WrcOFLvwabb/J4esK//kgJmW JPG5IGJh3T+THqAO5M9Dz+zBrBwCR2KHvFNjkGa+E0o+M2DsD1BpNYGgSBDB0rQREJPf /qbRspZaQeENQ32nMEME0ZuHrPgsqFtX0SomCeJU0KUb+15gW+p9GJK5Y5tqUx7vm9vW pqAtcx/zzFxMC60F9BN+0fFOc8WpUTmGJj7SFfZHYK2EmD28M/rJkTpn2IIMhGp7cwiM 5FdpmioH5rdprtmEOP9hLxvs2AnSsN/3xe3cQxvS/X+QxUPyKWuoWp6SyyB/K3EslEN9 4reQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1774399443; x=1775004243; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=KdSSlv0LVdyZD0+zj1U8PtUbtcqZsX166xUNgywcviU=; b=Iy4Ck4qAl4EfI67KNUb1aSruUgVFGjCr+etCreaS6+Kk4LDY/jTGNRBYePsWIZbZ5I 184oe7UUYXo1KQS7mm+4mcRev8O0cZmD4DbiWtflnOjdh+3Zd/LkBU45knLe5pfHRdad uc45l4KnlshN9Is+Tqj59Q0QTf7XJIQadL52m4LzPDjUj93qecmaJVSKCESGeXQi2W8s geoaHU8/PqIOq7vDbKHOYZ5H4531v0NKWXr7WW59B2rqBMqxuZqEaJrdzDzKjSia+iC2 kgFOBSZlIZtFLIBhxLgqInHMpfvoHEz84vddO40ReVWP0QFPgFnD4vdnZ8dQzgFz2VcZ LGBQ== X-Forwarded-Encrypted: i=1; AJvYcCV9LYxzL80GIRVFTZOIFULtfrEtoEIRAIv6xMrjW3K2rkzEFoDKszcs8SMlv2uwrf/YudKEDAYz59U6wUI=@vger.kernel.org X-Gm-Message-State: AOJu0YxnYLg51M1YZ8e9WyxZTQYkTDr09QEtpPykkre1KPGICzTN+zJ5 yFmiQU3q7vLDhtIH8hZvHjJZKVoGzYeo8yo7S66e1l9WiYL8bhFhaz2n X-Gm-Gg: ATEYQzzpVDxQDZX8Il4qFh9RH5Mr6Ftt9xYZ/80Xi8/EXrytGJbXU7Q1c3jgcb5197P 4+538jRb9O1Ziffag0S88g6pxLrYbMVWbgvD7qMnvrR7QrJTCeGxwAli3Qx0YFc2ygb+vPHSKoH 0Zs/MhqVWgpZHXJ9PzjYFCngBRqCnX1MKQ8yYzwLfKNQGPsc7ptgXIm8mGXLqG2873+Lic+i4pN WbhPrcE9WUrn9o4YGFElmI8g3ADvJ1OCKQH7+fP+bDG5joGcdVGRNJDCUVZCyJTTC4/QxGsj8hJ sLti6mbRnoxR0tC6nIFByv9/8IuF1LNdF6NjHsCZ3nEebNPezzOvqZGYCjsIXUIFgf8aNEU4aQp 5NKT2EmyKbfKQ8YXVmzboZFhXjk2YkWEHEewyYEVG4zi7vwVsIdssstNxn3lWI4VEsR7nO9Zz9s lI75Un86moQUhtWBpbCVba9HlnU8u2IhrVxZ65pHqXH1qzeYP0GP0PF+pwe0+msXbKODuk8g8= X-Received: by 2002:a17:903:3c30:b0:2b0:5fa0:3afa with SMTP id d9443c01a7336-2b0b0af58a4mr15324275ad.27.1774399443065; Tue, 24 Mar 2026 17:44:03 -0700 (PDT) Received: from kernel-fuzz.. ([103.172.182.26]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2b0836554acsm207457015ad.51.2026.03.24.17.43.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 24 Mar 2026 17:44:02 -0700 (PDT) From: ZhengYuan Huang To: dsterba@suse.com, clm@fb.com, idryomov@gmail.com Cc: linux-btrfs@vger.kernel.org, linux-kernel@vger.kernel.org, baijiaju1990@gmail.com, r33s3n6@gmail.com, zzzccc427@gmail.com, ZhengYuan Huang Subject: [PATCH v3 3/4] btrfs: balance: fix null-ptr-deref in btrfs_may_alloc_data_chunk Date: Wed, 25 Mar 2026 08:43:38 +0800 Message-ID: <20260325004339.2323838-4-gality369@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260325004339.2323838-1-gality369@gmail.com> References: <20260325004339.2323838-1-gality369@gmail.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 Content-Type: text/plain; charset="utf-8" [BUG] Running btrfs balance can trigger a null-ptr-deref before relocating a data chunk when metadata corruption leaves a chunk in the chunk tree without a corresponding block group in the in-memory cache: KASAN: null-ptr-deref in range [0x0000000000000088-0x000000000000008f] RIP: 0010:btrfs_may_alloc_data_chunk+0x40/0x1c0 fs/btrfs/volumes.c:3601 Call Trace: __btrfs_balance fs/btrfs/volumes.c:4217 [inline] btrfs_balance+0x2516/0x42b0 fs/btrfs/volumes.c:4604 btrfs_ioctl_balance fs/btrfs/ioctl.c:3577 [inline] btrfs_ioctl+0x25cf/0x5b90 fs/btrfs/ioctl.c:5313 ... [CAUSE] __btrfs_balance() iterates the on-disk chunk tree and passes the chunk logical bytenr to btrfs_may_alloc_data_chunk() before relocating a data chunk. That helper then queries the in-memory block group cache: cache =3D btrfs_lookup_block_group(fs_info, chunk_offset); chunk_type =3D cache->flags; /* cache may be NULL */ A corrupt image can contain a chunk item whose matching block group item is missing, so no block group is ever inserted into the cache. In that case btrfs_lookup_block_group() returns NULL. The code only guards this with ASSERT(cache), which becomes a no-op when CONFIG_BTRFS_ASSERT is disabled. The subsequent dereference of cache->flags therefore crashes the kernel. [FIX] Add a NULL check after btrfs_lookup_block_group() in btrfs_may_alloc_data_chunk(). If the lookup fails, emit a btrfs_err() message identifying the affected bytenr and return -EUCLEAN to report filesystem corruption instead of dereferencing NULL. The caller already treats negative returns from btrfs_may_alloc_data_chunk() as fatal errors, so balance aborts cleanly and reports the corruption to userspace. Fixes: a6f93c71d412 ("Btrfs: avoid losing data raid profile when deleting a= device") Signed-off-by: ZhengYuan Huang --- fs/btrfs/volumes.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 65df8652d760..e89eb5c1dbc5 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -3597,7 +3597,12 @@ static int btrfs_may_alloc_data_chunk(struct btrfs_f= s_info *fs_info, u64 chunk_type; =20 cache =3D btrfs_lookup_block_group(fs_info, chunk_offset); - ASSERT(cache); + if (!cache) { + btrfs_err(fs_info, + "balance: chunk at bytenr %llu has no corresponding block group", + chunk_offset); + return -EUCLEAN; + } chunk_type =3D cache->flags; btrfs_put_block_group(cache); =20 --=20 2.43.0 From nobody Fri Apr 3 02:56:57 2026 Received: from mail-pl1-f174.google.com (mail-pl1-f174.google.com [209.85.214.174]) (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 F32C6222585 for ; Wed, 25 Mar 2026 00:44:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774399449; cv=none; b=WES+rbM0YEOjhBlrcn/FD+dDdeap8vqsJ72I9QqECpYDBK5KzHBUh+WdSiwdo8htrgLOJZokgFteqqt9FSNBSmeeI7ng/UL1XFRrgGdOcxxkj7YjBs1DXIKZQFkiVygpktwGLhf52McowUx0pOhwHNrVjWjqqh0xILNtqKP7q1c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774399449; c=relaxed/simple; bh=pJxBZfkEpVbsRmIxx3V5vwBM1L3AVHZCKc/i40H0bn0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=PnQ65PT9HYQHe9Y+m/7N5WyuuVisZHqbAIsN4WUqfXehhpsuJSvxNs25IP9KNAktaU+/y2VOpyq+lipjdPRE4oWPUgy2K/NrtbskwfNNft5hk3Nvf6Jchr15QrwTNomFRunYCYp28xDQ8lDnTSbAOjLcy59b35zZ1WeXl38Elak= 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=jzUylgCM; arc=none smtp.client-ip=209.85.214.174 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="jzUylgCM" Received: by mail-pl1-f174.google.com with SMTP id d9443c01a7336-2ad21f437eeso2934865ad.0 for ; Tue, 24 Mar 2026 17:44:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1774399447; x=1775004247; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=fUxVMW0Q6ViE/Zxq8+fERJmXmaxdxo0no4qCgJ6CNic=; b=jzUylgCMt2r/tBZvY9JHE8aVkhdiYXwiaTl+HpocxqxYP/09K21OuwSK0UTlSuRnHI rad3SI33jEq2SyJHyLfK/HUTDIQp6ekbETd7r19FzdKIh0RJrQD/zHy6i/Zs28SrnQ7U dbd67piv5jNI3eDshMf1Hl0URaWswGlLaPQg9/kT9ujU4WIiDWxBDgi04ZyQuBTcE8e8 WX1Zfcu6leaIOZ4u6/W25RyPiY7VRSg7iKhqahOIJ3iExRGnx8abQ/8xPjfFz1YHUkmF yVKzQu4CHzHgdzPh0tHyfJJ4Zkpo+Mm4o1Ujsj83C+gk+ztgITshUcLmfw5uEI7qtlnw vrTQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1774399447; x=1775004247; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=fUxVMW0Q6ViE/Zxq8+fERJmXmaxdxo0no4qCgJ6CNic=; b=DVWK6pIFStmM7lV3445ASivaa6J1iomtMdYncadfWYsm6TJn+qKbkLowK6mUb8pPBB P658gP/3I1Fd34XykGnXyQE5F6l6heIiVeiWANXIysUtxiuksV3BIW6SkKuPSO4r1OXs pWWKtX3JqQvnXrRZNAXLPuIDBFksw2+cWFk00E3m399Mzu8sO74TArZsgiKHps1U9MMu phPiYVcXKyzniZK+NCpQPKvbzwivHF0rh0npsedIi16orI+YNMvT8OzcWSZplcxOmpUm tJaD1pk25HyPiBwAEMeVKUMCIgZyA707ZoSMwsWjSuN7ckesN5FhJTt4xHqsAQMVrqfN N3Lg== X-Forwarded-Encrypted: i=1; AJvYcCWsgF0YNxMozaouXRuVSsNJjub2wy4ujzCr67TmljStpaQfhGcc0Py+MSmm7zsSlMDCWa4xxGCbUdIbEEQ=@vger.kernel.org X-Gm-Message-State: AOJu0YxoctruEd1R3WrpAVq1IMXpISnxtIhzMP+ecjGweiMh8rFU2O6V 8LyjI0T+0RsUPKGPwA5v2d2RN2EmTC8UzasE1x2L/b+S3Ainu/1dABJu X-Gm-Gg: ATEYQzxHwX0vX0OJ6eQZ8Z3cC8U4eQr4SlQK4OHEsd+67CBYGH/WfJD5sPdKNiyS4Kg VTxgLX/twRFwHCM7H6oxYbctcZ9qH7yq+jtQzqIWJdKr6iqMMeSotQ5zNBmE5JBLRXstF+a14Wh g/nYqaPuGu/xg7o5hvnFJS0gm+KoiKaDi0eQnu7oMcU3/GntjF2ys3OlybtvHw8oAV4oQRrcZcu 6Al82x3dxer3aZH+ZaM+0VQnbNr4WRyLK06J6ivbPUWbMlVSZC+LdjRh+dXhilgIDmvmvPcOYg5 qQ8hLAGOQQQKaHc4GJw6VWqQPJFh7g/xao9UiJKJmVfIlZz/PWa6LnWLXvuBtsFn7LuXN3wiaBE 59CvtPnvK7HkHHuhKKuA0wYh5THgcDH1jay4hmi8joSCOYVj5RbA5gpUeXMImeHiIWwktQ3XOiA i9727lFA6Sxk8MbuIZtNPn1jT8DPxPQVZYWG4aggEaXYvkdQad5uzgyo60RFUEkYFf8pkO0Rr75 mJnpz6JEQ== X-Received: by 2002:a17:903:37c5:b0:2ae:be67:722f with SMTP id d9443c01a7336-2b0b07f9bd5mr16343605ad.22.1774399447341; Tue, 24 Mar 2026 17:44:07 -0700 (PDT) Received: from kernel-fuzz.. ([103.172.182.26]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2b0836554acsm207457015ad.51.2026.03.24.17.44.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 24 Mar 2026 17:44:06 -0700 (PDT) From: ZhengYuan Huang To: dsterba@suse.com, clm@fb.com, idryomov@gmail.com Cc: linux-btrfs@vger.kernel.org, linux-kernel@vger.kernel.org, baijiaju1990@gmail.com, r33s3n6@gmail.com, zzzccc427@gmail.com, ZhengYuan Huang Subject: [PATCH v3 4/4] btrfs: fix check_chunk_block_group_mappings() to iterate all chunk maps Date: Wed, 25 Mar 2026 08:43:39 +0800 Message-ID: <20260325004339.2323838-5-gality369@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260325004339.2323838-1-gality369@gmail.com> References: <20260325004339.2323838-1-gality369@gmail.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 Content-Type: text/plain; charset="utf-8" [BUG] A corrupted image with a chunk present in the chunk tree but whose corresponding block group item is missing from the extent tree can be mounted successfully, even though check_chunk_block_group_mappings() is supposed to catch exactly this corruption at mount time. Once mounted, running btrfs balance with a usage filter (-dusage=3DN or -dusage=3Dmin..max) triggers a null-ptr-deref: KASAN: null-ptr-deref in range [0x0000000000000070-0x0000000000000077] RIP: 0010:chunk_usage_filter fs/btrfs/volumes.c:3874 [inline] RIP: 0010:should_balance_chunk fs/btrfs/volumes.c:4018 [inline] RIP: 0010:__btrfs_balance fs/btrfs/volumes.c:4172 [inline] RIP: 0010:btrfs_balance+0x2024/0x42b0 fs/btrfs/volumes.c:4604 [CAUSE] The crash occurs because __btrfs_balance() iterates the on-disk chunk tree, finds the orphaned chunk, calls chunk_usage_filter() (or chunk_usage_range_filter()), which queries the in-memory block group cache via btrfs_lookup_block_group(). Since no block group was ever inserted for this chunk, the lookup returns NULL, and the subsequent dereference of cache->used crashes. check_chunk_block_group_mappings() uses btrfs_find_chunk_map() to iterate the in-memory chunk map (fs_info->mapping_tree): map =3D btrfs_find_chunk_map(fs_info, start, 1); With @start =3D 0 and @length =3D 1, btrfs_find_chunk_map() looks for a chunk map that *contains* the logical address 0. If no chunk contains logical address 0, btrfs_find_chunk_map(fs_info, 0, 1) returns NULL immediately and the loop breaks after the very first iteration, having checked zero chunks. The entire verification function is therefore a no-op, and the corrupted image passes the mount-time check undetected. [FIX] Replace the btrfs_find_chunk_map() based loop with a direct in-order walk of fs_info->mapping_tree using rb_first_cached() + rb_next(). This guarantees that every chunk map in the tree is visited regardless of the logical addresses involved. No lock is taken around the traversal. This function is called during mount from btrfs_read_block_groups(), which is invoked from open_ctree() before any background threads (cleaner, transaction kthread, etc.) are started. There are therefore no concurrent writers that could modify mapping_tree at this point. An analogous lockless direct traversal of mapping_tree already exists in fill_dummy_bgs() in the same file. Since we walk the RB-tree directly via rb_entry() without going through btrfs_find_chunk_map(), no reference is taken on each map entry, so the btrfs_free_chunk_map() calls are also removed. Signed-off-by: ZhengYuan Huang --- fs/btrfs/block-group.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c index 5322ef2ae015..d1e075a8905a 100644 --- a/fs/btrfs/block-group.c +++ b/fs/btrfs/block-group.c @@ -2319,29 +2319,26 @@ static struct btrfs_block_group *btrfs_create_block= _group_cache( */ static int check_chunk_block_group_mappings(struct btrfs_fs_info *fs_info) { - u64 start =3D 0; + struct rb_node *node; int ret =3D 0; =20 - while (1) { + /* + * This is called during mount from btrfs_read_block_groups(), before + * any background threads are started, so no concurrent writers can + * modify the mapping_tree. No lock is needed here. + */ + for (node =3D rb_first_cached(&fs_info->mapping_tree); node; + node =3D rb_next(node)) { struct btrfs_chunk_map *map; struct btrfs_block_group *bg; =20 - /* - * btrfs_find_chunk_map() will return the first chunk map - * intersecting the range, so setting @length to 1 is enough to - * get the first chunk. - */ - map =3D btrfs_find_chunk_map(fs_info, start, 1); - if (!map) - break; - + map =3D rb_entry(node, struct btrfs_chunk_map, rb_node); bg =3D btrfs_lookup_block_group(fs_info, map->start); if (unlikely(!bg)) { btrfs_err(fs_info, "chunk start=3D%llu len=3D%llu doesn't have corresponding block group", map->start, map->chunk_len); ret =3D -EUCLEAN; - btrfs_free_chunk_map(map); break; } if (unlikely(bg->start !=3D map->start || bg->length !=3D map->chunk_len= || @@ -2354,12 +2351,9 @@ static int check_chunk_block_group_mappings(struct b= trfs_fs_info *fs_info) bg->start, bg->length, bg->flags & BTRFS_BLOCK_GROUP_TYPE_MASK); ret =3D -EUCLEAN; - btrfs_free_chunk_map(map); btrfs_put_block_group(bg); break; } - start =3D map->start + map->chunk_len; - btrfs_free_chunk_map(map); btrfs_put_block_group(bg); } return ret; --=20 2.43.0