162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  linux/fs/hfs/btree.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2001
662306a36Sopenharmony_ci * Brad Boyer (flar@allandria.com)
762306a36Sopenharmony_ci * (C) 2003 Ardis Technologies <roman@ardistech.com>
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Handle opening/closing btree
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/pagemap.h>
1362306a36Sopenharmony_ci#include <linux/slab.h>
1462306a36Sopenharmony_ci#include <linux/log2.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include "btree.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci/* Get a reference to a B*Tree and do some initial checks */
1962306a36Sopenharmony_cistruct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id, btree_keycmp keycmp)
2062306a36Sopenharmony_ci{
2162306a36Sopenharmony_ci	struct hfs_btree *tree;
2262306a36Sopenharmony_ci	struct hfs_btree_header_rec *head;
2362306a36Sopenharmony_ci	struct address_space *mapping;
2462306a36Sopenharmony_ci	struct page *page;
2562306a36Sopenharmony_ci	unsigned int size;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	tree = kzalloc(sizeof(*tree), GFP_KERNEL);
2862306a36Sopenharmony_ci	if (!tree)
2962306a36Sopenharmony_ci		return NULL;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	mutex_init(&tree->tree_lock);
3262306a36Sopenharmony_ci	spin_lock_init(&tree->hash_lock);
3362306a36Sopenharmony_ci	/* Set the correct compare function */
3462306a36Sopenharmony_ci	tree->sb = sb;
3562306a36Sopenharmony_ci	tree->cnid = id;
3662306a36Sopenharmony_ci	tree->keycmp = keycmp;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	tree->inode = iget_locked(sb, id);
3962306a36Sopenharmony_ci	if (!tree->inode)
4062306a36Sopenharmony_ci		goto free_tree;
4162306a36Sopenharmony_ci	BUG_ON(!(tree->inode->i_state & I_NEW));
4262306a36Sopenharmony_ci	{
4362306a36Sopenharmony_ci	struct hfs_mdb *mdb = HFS_SB(sb)->mdb;
4462306a36Sopenharmony_ci	HFS_I(tree->inode)->flags = 0;
4562306a36Sopenharmony_ci	mutex_init(&HFS_I(tree->inode)->extents_lock);
4662306a36Sopenharmony_ci	switch (id) {
4762306a36Sopenharmony_ci	case HFS_EXT_CNID:
4862306a36Sopenharmony_ci		hfs_inode_read_fork(tree->inode, mdb->drXTExtRec, mdb->drXTFlSize,
4962306a36Sopenharmony_ci				    mdb->drXTFlSize, be32_to_cpu(mdb->drXTClpSiz));
5062306a36Sopenharmony_ci		if (HFS_I(tree->inode)->alloc_blocks >
5162306a36Sopenharmony_ci					HFS_I(tree->inode)->first_blocks) {
5262306a36Sopenharmony_ci			pr_err("invalid btree extent records\n");
5362306a36Sopenharmony_ci			unlock_new_inode(tree->inode);
5462306a36Sopenharmony_ci			goto free_inode;
5562306a36Sopenharmony_ci		}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci		tree->inode->i_mapping->a_ops = &hfs_btree_aops;
5862306a36Sopenharmony_ci		break;
5962306a36Sopenharmony_ci	case HFS_CAT_CNID:
6062306a36Sopenharmony_ci		hfs_inode_read_fork(tree->inode, mdb->drCTExtRec, mdb->drCTFlSize,
6162306a36Sopenharmony_ci				    mdb->drCTFlSize, be32_to_cpu(mdb->drCTClpSiz));
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci		if (!HFS_I(tree->inode)->first_blocks) {
6462306a36Sopenharmony_ci			pr_err("invalid btree extent records (0 size)\n");
6562306a36Sopenharmony_ci			unlock_new_inode(tree->inode);
6662306a36Sopenharmony_ci			goto free_inode;
6762306a36Sopenharmony_ci		}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci		tree->inode->i_mapping->a_ops = &hfs_btree_aops;
7062306a36Sopenharmony_ci		break;
7162306a36Sopenharmony_ci	default:
7262306a36Sopenharmony_ci		BUG();
7362306a36Sopenharmony_ci	}
7462306a36Sopenharmony_ci	}
7562306a36Sopenharmony_ci	unlock_new_inode(tree->inode);
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	mapping = tree->inode->i_mapping;
7862306a36Sopenharmony_ci	page = read_mapping_page(mapping, 0, NULL);
7962306a36Sopenharmony_ci	if (IS_ERR(page))
8062306a36Sopenharmony_ci		goto free_inode;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	/* Load the header */
8362306a36Sopenharmony_ci	head = (struct hfs_btree_header_rec *)(kmap_local_page(page) +
8462306a36Sopenharmony_ci					       sizeof(struct hfs_bnode_desc));
8562306a36Sopenharmony_ci	tree->root = be32_to_cpu(head->root);
8662306a36Sopenharmony_ci	tree->leaf_count = be32_to_cpu(head->leaf_count);
8762306a36Sopenharmony_ci	tree->leaf_head = be32_to_cpu(head->leaf_head);
8862306a36Sopenharmony_ci	tree->leaf_tail = be32_to_cpu(head->leaf_tail);
8962306a36Sopenharmony_ci	tree->node_count = be32_to_cpu(head->node_count);
9062306a36Sopenharmony_ci	tree->free_nodes = be32_to_cpu(head->free_nodes);
9162306a36Sopenharmony_ci	tree->attributes = be32_to_cpu(head->attributes);
9262306a36Sopenharmony_ci	tree->node_size = be16_to_cpu(head->node_size);
9362306a36Sopenharmony_ci	tree->max_key_len = be16_to_cpu(head->max_key_len);
9462306a36Sopenharmony_ci	tree->depth = be16_to_cpu(head->depth);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	size = tree->node_size;
9762306a36Sopenharmony_ci	if (!is_power_of_2(size))
9862306a36Sopenharmony_ci		goto fail_page;
9962306a36Sopenharmony_ci	if (!tree->node_count)
10062306a36Sopenharmony_ci		goto fail_page;
10162306a36Sopenharmony_ci	switch (id) {
10262306a36Sopenharmony_ci	case HFS_EXT_CNID:
10362306a36Sopenharmony_ci		if (tree->max_key_len != HFS_MAX_EXT_KEYLEN) {
10462306a36Sopenharmony_ci			pr_err("invalid extent max_key_len %d\n",
10562306a36Sopenharmony_ci			       tree->max_key_len);
10662306a36Sopenharmony_ci			goto fail_page;
10762306a36Sopenharmony_ci		}
10862306a36Sopenharmony_ci		break;
10962306a36Sopenharmony_ci	case HFS_CAT_CNID:
11062306a36Sopenharmony_ci		if (tree->max_key_len != HFS_MAX_CAT_KEYLEN) {
11162306a36Sopenharmony_ci			pr_err("invalid catalog max_key_len %d\n",
11262306a36Sopenharmony_ci			       tree->max_key_len);
11362306a36Sopenharmony_ci			goto fail_page;
11462306a36Sopenharmony_ci		}
11562306a36Sopenharmony_ci		break;
11662306a36Sopenharmony_ci	default:
11762306a36Sopenharmony_ci		BUG();
11862306a36Sopenharmony_ci	}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	tree->node_size_shift = ffs(size) - 1;
12162306a36Sopenharmony_ci	tree->pages_per_bnode = (tree->node_size + PAGE_SIZE - 1) >> PAGE_SHIFT;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	kunmap_local(head);
12462306a36Sopenharmony_ci	put_page(page);
12562306a36Sopenharmony_ci	return tree;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cifail_page:
12862306a36Sopenharmony_ci	kunmap_local(head);
12962306a36Sopenharmony_ci	put_page(page);
13062306a36Sopenharmony_cifree_inode:
13162306a36Sopenharmony_ci	tree->inode->i_mapping->a_ops = &hfs_aops;
13262306a36Sopenharmony_ci	iput(tree->inode);
13362306a36Sopenharmony_cifree_tree:
13462306a36Sopenharmony_ci	kfree(tree);
13562306a36Sopenharmony_ci	return NULL;
13662306a36Sopenharmony_ci}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci/* Release resources used by a btree */
13962306a36Sopenharmony_civoid hfs_btree_close(struct hfs_btree *tree)
14062306a36Sopenharmony_ci{
14162306a36Sopenharmony_ci	struct hfs_bnode *node;
14262306a36Sopenharmony_ci	int i;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	if (!tree)
14562306a36Sopenharmony_ci		return;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	for (i = 0; i < NODE_HASH_SIZE; i++) {
14862306a36Sopenharmony_ci		while ((node = tree->node_hash[i])) {
14962306a36Sopenharmony_ci			tree->node_hash[i] = node->next_hash;
15062306a36Sopenharmony_ci			if (atomic_read(&node->refcnt))
15162306a36Sopenharmony_ci				pr_err("node %d:%d still has %d user(s)!\n",
15262306a36Sopenharmony_ci				       node->tree->cnid, node->this,
15362306a36Sopenharmony_ci				       atomic_read(&node->refcnt));
15462306a36Sopenharmony_ci			hfs_bnode_free(node);
15562306a36Sopenharmony_ci			tree->node_hash_cnt--;
15662306a36Sopenharmony_ci		}
15762306a36Sopenharmony_ci	}
15862306a36Sopenharmony_ci	iput(tree->inode);
15962306a36Sopenharmony_ci	kfree(tree);
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_civoid hfs_btree_write(struct hfs_btree *tree)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	struct hfs_btree_header_rec *head;
16562306a36Sopenharmony_ci	struct hfs_bnode *node;
16662306a36Sopenharmony_ci	struct page *page;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	node = hfs_bnode_find(tree, 0);
16962306a36Sopenharmony_ci	if (IS_ERR(node))
17062306a36Sopenharmony_ci		/* panic? */
17162306a36Sopenharmony_ci		return;
17262306a36Sopenharmony_ci	/* Load the header */
17362306a36Sopenharmony_ci	page = node->page[0];
17462306a36Sopenharmony_ci	head = (struct hfs_btree_header_rec *)(kmap_local_page(page) +
17562306a36Sopenharmony_ci					       sizeof(struct hfs_bnode_desc));
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	head->root = cpu_to_be32(tree->root);
17862306a36Sopenharmony_ci	head->leaf_count = cpu_to_be32(tree->leaf_count);
17962306a36Sopenharmony_ci	head->leaf_head = cpu_to_be32(tree->leaf_head);
18062306a36Sopenharmony_ci	head->leaf_tail = cpu_to_be32(tree->leaf_tail);
18162306a36Sopenharmony_ci	head->node_count = cpu_to_be32(tree->node_count);
18262306a36Sopenharmony_ci	head->free_nodes = cpu_to_be32(tree->free_nodes);
18362306a36Sopenharmony_ci	head->attributes = cpu_to_be32(tree->attributes);
18462306a36Sopenharmony_ci	head->depth = cpu_to_be16(tree->depth);
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	kunmap_local(head);
18762306a36Sopenharmony_ci	set_page_dirty(page);
18862306a36Sopenharmony_ci	hfs_bnode_put(node);
18962306a36Sopenharmony_ci}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_cistatic struct hfs_bnode *hfs_bmap_new_bmap(struct hfs_bnode *prev, u32 idx)
19262306a36Sopenharmony_ci{
19362306a36Sopenharmony_ci	struct hfs_btree *tree = prev->tree;
19462306a36Sopenharmony_ci	struct hfs_bnode *node;
19562306a36Sopenharmony_ci	struct hfs_bnode_desc desc;
19662306a36Sopenharmony_ci	__be32 cnid;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	node = hfs_bnode_create(tree, idx);
19962306a36Sopenharmony_ci	if (IS_ERR(node))
20062306a36Sopenharmony_ci		return node;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	if (!tree->free_nodes)
20362306a36Sopenharmony_ci		panic("FIXME!!!");
20462306a36Sopenharmony_ci	tree->free_nodes--;
20562306a36Sopenharmony_ci	prev->next = idx;
20662306a36Sopenharmony_ci	cnid = cpu_to_be32(idx);
20762306a36Sopenharmony_ci	hfs_bnode_write(prev, &cnid, offsetof(struct hfs_bnode_desc, next), 4);
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	node->type = HFS_NODE_MAP;
21062306a36Sopenharmony_ci	node->num_recs = 1;
21162306a36Sopenharmony_ci	hfs_bnode_clear(node, 0, tree->node_size);
21262306a36Sopenharmony_ci	desc.next = 0;
21362306a36Sopenharmony_ci	desc.prev = 0;
21462306a36Sopenharmony_ci	desc.type = HFS_NODE_MAP;
21562306a36Sopenharmony_ci	desc.height = 0;
21662306a36Sopenharmony_ci	desc.num_recs = cpu_to_be16(1);
21762306a36Sopenharmony_ci	desc.reserved = 0;
21862306a36Sopenharmony_ci	hfs_bnode_write(node, &desc, 0, sizeof(desc));
21962306a36Sopenharmony_ci	hfs_bnode_write_u16(node, 14, 0x8000);
22062306a36Sopenharmony_ci	hfs_bnode_write_u16(node, tree->node_size - 2, 14);
22162306a36Sopenharmony_ci	hfs_bnode_write_u16(node, tree->node_size - 4, tree->node_size - 6);
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	return node;
22462306a36Sopenharmony_ci}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci/* Make sure @tree has enough space for the @rsvd_nodes */
22762306a36Sopenharmony_ciint hfs_bmap_reserve(struct hfs_btree *tree, int rsvd_nodes)
22862306a36Sopenharmony_ci{
22962306a36Sopenharmony_ci	struct inode *inode = tree->inode;
23062306a36Sopenharmony_ci	u32 count;
23162306a36Sopenharmony_ci	int res;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	while (tree->free_nodes < rsvd_nodes) {
23462306a36Sopenharmony_ci		res = hfs_extend_file(inode);
23562306a36Sopenharmony_ci		if (res)
23662306a36Sopenharmony_ci			return res;
23762306a36Sopenharmony_ci		HFS_I(inode)->phys_size = inode->i_size =
23862306a36Sopenharmony_ci				(loff_t)HFS_I(inode)->alloc_blocks *
23962306a36Sopenharmony_ci				HFS_SB(tree->sb)->alloc_blksz;
24062306a36Sopenharmony_ci		HFS_I(inode)->fs_blocks = inode->i_size >>
24162306a36Sopenharmony_ci					  tree->sb->s_blocksize_bits;
24262306a36Sopenharmony_ci		inode_set_bytes(inode, inode->i_size);
24362306a36Sopenharmony_ci		count = inode->i_size >> tree->node_size_shift;
24462306a36Sopenharmony_ci		tree->free_nodes += count - tree->node_count;
24562306a36Sopenharmony_ci		tree->node_count = count;
24662306a36Sopenharmony_ci	}
24762306a36Sopenharmony_ci	return 0;
24862306a36Sopenharmony_ci}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_cistruct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree)
25162306a36Sopenharmony_ci{
25262306a36Sopenharmony_ci	struct hfs_bnode *node, *next_node;
25362306a36Sopenharmony_ci	struct page **pagep;
25462306a36Sopenharmony_ci	u32 nidx, idx;
25562306a36Sopenharmony_ci	unsigned off;
25662306a36Sopenharmony_ci	u16 off16;
25762306a36Sopenharmony_ci	u16 len;
25862306a36Sopenharmony_ci	u8 *data, byte, m;
25962306a36Sopenharmony_ci	int i, res;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	res = hfs_bmap_reserve(tree, 1);
26262306a36Sopenharmony_ci	if (res)
26362306a36Sopenharmony_ci		return ERR_PTR(res);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	nidx = 0;
26662306a36Sopenharmony_ci	node = hfs_bnode_find(tree, nidx);
26762306a36Sopenharmony_ci	if (IS_ERR(node))
26862306a36Sopenharmony_ci		return node;
26962306a36Sopenharmony_ci	len = hfs_brec_lenoff(node, 2, &off16);
27062306a36Sopenharmony_ci	off = off16;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	off += node->page_offset;
27362306a36Sopenharmony_ci	pagep = node->page + (off >> PAGE_SHIFT);
27462306a36Sopenharmony_ci	data = kmap_local_page(*pagep);
27562306a36Sopenharmony_ci	off &= ~PAGE_MASK;
27662306a36Sopenharmony_ci	idx = 0;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	for (;;) {
27962306a36Sopenharmony_ci		while (len) {
28062306a36Sopenharmony_ci			byte = data[off];
28162306a36Sopenharmony_ci			if (byte != 0xff) {
28262306a36Sopenharmony_ci				for (m = 0x80, i = 0; i < 8; m >>= 1, i++) {
28362306a36Sopenharmony_ci					if (!(byte & m)) {
28462306a36Sopenharmony_ci						idx += i;
28562306a36Sopenharmony_ci						data[off] |= m;
28662306a36Sopenharmony_ci						set_page_dirty(*pagep);
28762306a36Sopenharmony_ci						kunmap_local(data);
28862306a36Sopenharmony_ci						tree->free_nodes--;
28962306a36Sopenharmony_ci						mark_inode_dirty(tree->inode);
29062306a36Sopenharmony_ci						hfs_bnode_put(node);
29162306a36Sopenharmony_ci						return hfs_bnode_create(tree, idx);
29262306a36Sopenharmony_ci					}
29362306a36Sopenharmony_ci				}
29462306a36Sopenharmony_ci			}
29562306a36Sopenharmony_ci			if (++off >= PAGE_SIZE) {
29662306a36Sopenharmony_ci				kunmap_local(data);
29762306a36Sopenharmony_ci				data = kmap_local_page(*++pagep);
29862306a36Sopenharmony_ci				off = 0;
29962306a36Sopenharmony_ci			}
30062306a36Sopenharmony_ci			idx += 8;
30162306a36Sopenharmony_ci			len--;
30262306a36Sopenharmony_ci		}
30362306a36Sopenharmony_ci		kunmap_local(data);
30462306a36Sopenharmony_ci		nidx = node->next;
30562306a36Sopenharmony_ci		if (!nidx) {
30662306a36Sopenharmony_ci			printk(KERN_DEBUG "create new bmap node...\n");
30762306a36Sopenharmony_ci			next_node = hfs_bmap_new_bmap(node, idx);
30862306a36Sopenharmony_ci		} else
30962306a36Sopenharmony_ci			next_node = hfs_bnode_find(tree, nidx);
31062306a36Sopenharmony_ci		hfs_bnode_put(node);
31162306a36Sopenharmony_ci		if (IS_ERR(next_node))
31262306a36Sopenharmony_ci			return next_node;
31362306a36Sopenharmony_ci		node = next_node;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci		len = hfs_brec_lenoff(node, 0, &off16);
31662306a36Sopenharmony_ci		off = off16;
31762306a36Sopenharmony_ci		off += node->page_offset;
31862306a36Sopenharmony_ci		pagep = node->page + (off >> PAGE_SHIFT);
31962306a36Sopenharmony_ci		data = kmap_local_page(*pagep);
32062306a36Sopenharmony_ci		off &= ~PAGE_MASK;
32162306a36Sopenharmony_ci	}
32262306a36Sopenharmony_ci}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_civoid hfs_bmap_free(struct hfs_bnode *node)
32562306a36Sopenharmony_ci{
32662306a36Sopenharmony_ci	struct hfs_btree *tree;
32762306a36Sopenharmony_ci	struct page *page;
32862306a36Sopenharmony_ci	u16 off, len;
32962306a36Sopenharmony_ci	u32 nidx;
33062306a36Sopenharmony_ci	u8 *data, byte, m;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	hfs_dbg(BNODE_MOD, "btree_free_node: %u\n", node->this);
33362306a36Sopenharmony_ci	tree = node->tree;
33462306a36Sopenharmony_ci	nidx = node->this;
33562306a36Sopenharmony_ci	node = hfs_bnode_find(tree, 0);
33662306a36Sopenharmony_ci	if (IS_ERR(node))
33762306a36Sopenharmony_ci		return;
33862306a36Sopenharmony_ci	len = hfs_brec_lenoff(node, 2, &off);
33962306a36Sopenharmony_ci	while (nidx >= len * 8) {
34062306a36Sopenharmony_ci		u32 i;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci		nidx -= len * 8;
34362306a36Sopenharmony_ci		i = node->next;
34462306a36Sopenharmony_ci		if (!i) {
34562306a36Sopenharmony_ci			/* panic */;
34662306a36Sopenharmony_ci			pr_crit("unable to free bnode %u. bmap not found!\n",
34762306a36Sopenharmony_ci				node->this);
34862306a36Sopenharmony_ci			hfs_bnode_put(node);
34962306a36Sopenharmony_ci			return;
35062306a36Sopenharmony_ci		}
35162306a36Sopenharmony_ci		hfs_bnode_put(node);
35262306a36Sopenharmony_ci		node = hfs_bnode_find(tree, i);
35362306a36Sopenharmony_ci		if (IS_ERR(node))
35462306a36Sopenharmony_ci			return;
35562306a36Sopenharmony_ci		if (node->type != HFS_NODE_MAP) {
35662306a36Sopenharmony_ci			/* panic */;
35762306a36Sopenharmony_ci			pr_crit("invalid bmap found! (%u,%d)\n",
35862306a36Sopenharmony_ci				node->this, node->type);
35962306a36Sopenharmony_ci			hfs_bnode_put(node);
36062306a36Sopenharmony_ci			return;
36162306a36Sopenharmony_ci		}
36262306a36Sopenharmony_ci		len = hfs_brec_lenoff(node, 0, &off);
36362306a36Sopenharmony_ci	}
36462306a36Sopenharmony_ci	off += node->page_offset + nidx / 8;
36562306a36Sopenharmony_ci	page = node->page[off >> PAGE_SHIFT];
36662306a36Sopenharmony_ci	data = kmap_local_page(page);
36762306a36Sopenharmony_ci	off &= ~PAGE_MASK;
36862306a36Sopenharmony_ci	m = 1 << (~nidx & 7);
36962306a36Sopenharmony_ci	byte = data[off];
37062306a36Sopenharmony_ci	if (!(byte & m)) {
37162306a36Sopenharmony_ci		pr_crit("trying to free free bnode %u(%d)\n",
37262306a36Sopenharmony_ci			node->this, node->type);
37362306a36Sopenharmony_ci		kunmap_local(data);
37462306a36Sopenharmony_ci		hfs_bnode_put(node);
37562306a36Sopenharmony_ci		return;
37662306a36Sopenharmony_ci	}
37762306a36Sopenharmony_ci	data[off] = byte & ~m;
37862306a36Sopenharmony_ci	set_page_dirty(page);
37962306a36Sopenharmony_ci	kunmap_local(data);
38062306a36Sopenharmony_ci	hfs_bnode_put(node);
38162306a36Sopenharmony_ci	tree->free_nodes++;
38262306a36Sopenharmony_ci	mark_inode_dirty(tree->inode);
38362306a36Sopenharmony_ci}
384