Re: [PATCH 1/2] hfs: detect node 0 btree map corruption at mount time
Viacheslav Dubeyko <[email protected]>
| Newsgroups | org.kernel.vger.linux-fsdevel,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
On Fri, 2026-08-14 at 10:31 +0800, Tao Yu wrote: > HFS+ already validates that the btree map keeps node 0 marked as in- > use > when the tree is opened. HFS lacks the same check, so a corrupted > volume > can proceed past mount with a broken node bitmap and only fail later > in > write paths. > > Port the node 0 bitmap validation to HFS. If the header node is not > marked as allocated in the on-disk map, warn that the btree bitmap is > corrupted and force the filesystem read-only so users can repair it > with > fsck.hfs. > > This keeps the HFS mount-time behavior aligned with HFS+ and catches > the > corruption closer to where it becomes observable. > > Signed-off-by: Tao Yu <[email protected]> > --- > fs/hfs/btree.c | 60 > ++++++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 60 insertions(+) > > diff --git a/fs/hfs/btree.c b/fs/hfs/btree.c > index 2eb37a2f64e86..14114318ec724 100644 > --- a/fs/hfs/btree.c > +++ b/fs/hfs/btree.c > @@ -15,12 +15,59 @@ > > #include "btree.h" > > +static bool hfs_bmap_test_bit(struct hfs_bnode *node, u32 > node_bit_idx) > +{ > + u16 rec_idx, off, len; > + u32 byte_offset; > + u8 byte, mask; > + > + if (node->this == 0) { > + if (node->type != HFS_NODE_HEADER) { > + pr_err("hfs: invalid btree header node\n"); > + return false; > + } > + rec_idx = 2; > + } else { > + if (node->type != HFS_NODE_MAP) { > + pr_err("hfs: invalid btree map node\n"); > + return false; > + } > + rec_idx = 0; > + } > + > + len = hfs_brec_lenoff(node, rec_idx, &off); > + if (!len) > + return false; > + > + byte_offset = node_bit_idx / BITS_PER_BYTE; > + if (byte_offset >= len) > + return false; > + > + byte = hfs_bnode_read_u8(node, off + byte_offset); > + mask = 1 << (7 - (node_bit_idx % BITS_PER_BYTE)); > + > + return byte & mask; > +} > + > +static const char *hfs_btree_name(u32 cnid) > +{ > + switch (cnid) { > + case HFS_EXT_CNID: > + return "Extents Overflow File"; > + case HFS_CAT_CNID: > + return "Catalog File"; > + default: > + return "Unknown B-tree"; > + } > +} > + > /* Get a reference to a B*Tree and do some initial checks */ > struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id, > btree_keycmp keycmp) > { > struct hfs_btree *tree; > struct hfs_btree_header_rec *head; > struct address_space *mapping; > + struct hfs_bnode *node; > struct folio *folio; > struct buffer_head *bh; > unsigned int size; > @@ -155,6 +202,19 @@ struct hfs_btree *hfs_btree_open(struct > super_block *sb, u32 id, btree_keycmp ke > kunmap_local(head); > folio_unlock(folio); > folio_put(folio); > + > + node = hfs_bnode_find(tree, 0); > + if (IS_ERR(node)) > + goto free_inode; > + > + if (!hfs_bmap_test_bit(node, 0)) { > + pr_warn("(%s): %s (cnid 0x%x) map record invalid or > bitmap corruption detected, forcing read-only.\n", > + sb->s_id, hfs_btree_name(id), id); > + pr_warn("Run fsck.hfs to repair.\n"); > + sb->s_flags |= SB_RDONLY; > + } > + > + hfs_bnode_put(node); > return tree; > > fail_folio: Sorry, but this patch [1] already has implemented this functionality. And this patch is in HFS/HFS+ tree (for-next branch). Thanks, Slava. [1] https://lore.kernel.org/r/[email protected]