From mboxrd@z Thu Jan 1 00:00:00 1970 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 B00EC3A8758 for ; Tue, 23 Jun 2026 09:38:10 +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=1782207492; cv=none; b=OyPRHXLqJxULPkO6g43HuQnV5LeE97D0W5uPKhclFcfIyAdSryl0KwknQWbjPa7DfiHT19QRkmtjo5zQ6YWq4Te9eLzQLu7ZsP8LsKmW9G0R3Hl9aFIbnjzX3SF/i0sjSnzL/DYt8kY11stQNKETNSKbNBaspP7Q2ANnNQqTK2M= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782207492; c=relaxed/simple; bh=0LH2Wk96XCyQ9QPmB3zJdq3TVqhmoWH8uSvEK9uSjdA=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=HWYR1AUdWcErL1EK0ckobfVXp4sdsVP9g9ypKodY+SF8tqYn53YAaKJpa3aZoyC6q8AqfTkJLBbFMD+/t8gmBTy5BK+Nye5G+MYPI4IG/InffnuIHHwnbabOSX/YJK3bOkkMpKCxJsklcwVEm9LRpeQVLa/DvVZn5Ehm/+0UHGw= 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=tJBg1hfO; 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="tJBg1hfO" Received: by mail-pl1-f174.google.com with SMTP id d9443c01a7336-2c6d3851e09so27604345ad.0 for ; Tue, 23 Jun 2026 02:38:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1782207490; x=1782812290; 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; bh=WNVcLnkL3WxXcfZi/S6Z0bWfgjPDQAPL7NsbQXzozmw=; b=tJBg1hfORfazvw5I7UhaNG3MffF9CrY9a0PCJk+rIeKsKyiGlwuU7co9I1IcAybDRu psjMlL+ARoATOQ3CxNP+6WLWi/vsPOzRq1zQHK3mFnrzSvsm4MmYAAI4ZxSe7rmfVm/A zNT7RhMkUR3TqnVrpvESvGdrpRHCDaCarHfUZzHEw5uefRf8GwfjCUlJCLNf1ns0oJiL rZiuKIMLUpjNajdjOK7awW/G26Q2HqPWDX1RmiCvalmIfLbcwNqqWVBcJs/LzdePQzhE PMYvnrf4pfQB5pA1pgbkJHPZaI620hxteTpbzBxO3rzWY6YpSG06XQLL4aK/gK5AD/y9 HR6w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1782207490; x=1782812290; 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; bh=WNVcLnkL3WxXcfZi/S6Z0bWfgjPDQAPL7NsbQXzozmw=; b=kgytFnBupNDQWNdORZX160KEb1gISqavlBgU1lRJr9AXOsPtrWOHFjODnXTYsilbdc EsUFs7zfLmVr098YUfMYHj/AgyTS9QNiPfZ501vz37NHnMULYAeZ7MaYhz2gyOYA8r9n 0os52CCYzbZPXuocvtjhJaJdJPUzLorFpBp/leQIAsRlS9sfd9+d1YoUyzruR2rguzPl guAbdtIWtklIxuA0cEye2Wb5fV6c+LrgqIHa/qt/zs6NHLpRYi5LAwT/NPaQJHpQ+bG0 kY4/wByrwZvNKyjoN0GbzcBucDPEr/Nf66lgPT+wjngFUv7Xn6TIxqdnDCO5CFNdKuR9 dcpg== X-Forwarded-Encrypted: i=1; AHgh+Rohj2mjxtdA29/mamLxksk78cUyyTQpAfDXlUBCqR05rVK6ReTPWtROc2Eu7HbJ/0VtTqMfvAMdejLRAyk=@vger.kernel.org X-Gm-Message-State: AOJu0YyaKhOpbOaGTniq78niDyYt41Or7pS4Nu9gCZFjPi0i7/ASbzoz HjdCsUyU+Rrd2K0EFk3S8RIiEGMQSFNkOFGywdDHMX60+LHSdFsB0Rzy X-Gm-Gg: AfdE7ck/CqceIkemFlAFDau4PVAL07WKQZeU935gc09a4hxyiQdUHzarN/1Ov2PkQOE 9axyAAWn7dn7rSpCBVuuWVZGyCOXrptNf1oX3DlXk0xO2eMI6+jiddkQWEqoo0Y+IJRvzM6WI0L RrxjYra1/2Pqb+mGw9ZOZmlTAScLTLutZpWngaE0DgOBsZulXKHiJ5TjRTRX/ef/4dcD3WTH0ud rdgrHnn97bbBsw0CfsSTsCO+xaHEc4vG/jfGjiA34ivldtHoqXxFz9XvmCInxhe4+4QhvZGlkG9 ha9SnqRGCrSV9f98+RaYDf9kdrNMwraqLoSdsdfzAHSlTTRqxeF+s1G70I/Szy8Dbm5s0cAR9sP vdrKrUHILBxoChSi0+Pc8JgYfuCb0jqmgIGKu+y7WKSBGuLA3ac7xjjgGS/jdmjfP/1XVoKrxXm oKv6xHsIPdyyS37e4OEREhfENGmQyPR7MvXsWLvUEyId+8KyLwpspfgncPeHPlWgmEkS/5UYx1B IGFndZUFlwNTiAU1ryqqbFSNLEfaZ3PJAAyL+JzMIQap67MXyH1lXQy7ROaPWLIGi4K6B+6qYeS JHAlf6xWKNPId1Wmcw2SNE5aKQ== X-Received: by 2002:a17:902:cf43:b0:2c7:d4ba:4885 with SMTP id d9443c01a7336-2c7d4ba4c8fmr6598755ad.3.1782207489828; Tue, 23 Jun 2026 02:38:09 -0700 (PDT) Received: from cs-1047136853211-default.asia-southeast1-a.c.d33bddc1d573818c7-tp.internal (69.129.240.35.bc.googleusercontent.com. [35.240.129.69]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2c7436aff98sm100841445ad.3.2026.06.23.02.38.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Jun 2026 02:38:09 -0700 (PDT) From: Aditya Srivastava To: slava@dubeyko.com Cc: glaubitz@physik.fu-berlin.de, frank.li@vivo.com, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, Aditya Prakash Srivastava Subject: [PATCH] hfs: port HFS+ b-tree bitmap corruption check Date: Tue, 23 Jun 2026 09:37:50 +0000 Message-ID: <20260623093750.2311-1-aditya.ansh182@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: 8bit From: Aditya Prakash Srivastava In HFS+ filesystems, during b-tree open (hfs_btree_open()), the code verifies that the allocation map bit for the tree header (node 0) is set. If not, it indicates a corrupted map record/bitmap and mounts the volume as read-only (SB_RDONLY) to prevent further damage. HFS filesystems share the same b-tree structure but currently lack this corruption detection check, which was highlighted by the maintainer. Port this check to HFS: 1. Implement hfs_bmap_test_bit() in fs/hfs/btree.c (which safely traverses the b-tree map nodes to inspect the desired bit, identical to HFS+). 2. Invoke hfs_bmap_test_bit() for node 0 at the end of hfs_btree_open(), warning and forcing read-only if corruption is detected. Suggested-by: Viacheslav Dubeyko Link: https://lore.kernel.org/all/6a36101b.be22b350.2a3e9.0001.GAE@google.com/T/#r446d0fed2a2900bd805534bbcb799d86619ae2ea Signed-off-by: Aditya Prakash Srivastava --- fs/hfs/btree.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++ fs/hfs/btree.h | 1 + 2 files changed, 53 insertions(+) diff --git a/fs/hfs/btree.c b/fs/hfs/btree.c index 2eb37a2f64e8..4293399d377e 100644 --- a/fs/hfs/btree.c +++ b/fs/hfs/btree.c @@ -155,6 +155,14 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id, btree_keycmp ke kunmap_local(head); folio_unlock(folio); folio_put(folio); + + if (!hfs_bmap_test_bit(tree, 0)) { + pr_warn("(%s): %s (cnid 0x%x) map record invalid or bitmap corruption detected, forcing read-only.\n", + sb->s_id, id == HFS_EXT_CNID ? "extents" : "catalog", id); + pr_warn("Run fsck.hfs to repair.\n"); + sb->s_flags |= SB_RDONLY; + } + return tree; fail_folio: @@ -356,6 +364,50 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree) } } +bool hfs_bmap_test_bit(struct hfs_btree *tree, u32 nidx) +{ + struct hfs_bnode *node; + struct page *page; + u16 off, len; + u8 *data, byte, m; + bool res = false; + + node = hfs_bnode_find(tree, 0); + if (IS_ERR(node)) + return false; + + len = hfs_brec_lenoff(node, 2, &off); + while (nidx >= len * 8) { + u32 i; + + nidx -= len * 8; + i = node->next; + if (!i) { + hfs_bnode_put(node); + return false; + } + hfs_bnode_put(node); + node = hfs_bnode_find(tree, i); + if (IS_ERR(node)) + return false; + if (node->type != HFS_NODE_MAP) { + hfs_bnode_put(node); + return false; + } + len = hfs_brec_lenoff(node, 0, &off); + } + off += node->page_offset + nidx / 8; + page = node->page[off >> PAGE_SHIFT]; + data = kmap_local_page(page); + off &= ~PAGE_MASK; + m = 1 << (~nidx & 7); + byte = data[off]; + res = (byte & m) != 0; + kunmap_local(data); + hfs_bnode_put(node); + return res; +} + void hfs_bmap_free(struct hfs_bnode *node) { struct hfs_btree *tree; diff --git a/fs/hfs/btree.h b/fs/hfs/btree.h index 99be858b2446..efe88f66c856 100644 --- a/fs/hfs/btree.h +++ b/fs/hfs/btree.h @@ -93,6 +93,7 @@ extern void hfs_btree_write(struct hfs_btree *tree); extern int hfs_bmap_reserve(struct hfs_btree *tree, u32 rsvd_nodes); extern struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree); extern void hfs_bmap_free(struct hfs_bnode *node); +extern bool hfs_bmap_test_bit(struct hfs_btree *tree, u32 nidx); /* bnode.c */ extern void hfs_bnode_read(struct hfs_bnode *node, void *buf, u32 off, u32 len); -- 2.47.3