xref: /openbmc/linux/fs/hfs/btree.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *  linux/fs/hfs/btree.c
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Copyright (C) 2001
61da177e4SLinus Torvalds  * Brad Boyer (flar@allandria.com)
71da177e4SLinus Torvalds  * (C) 2003 Ardis Technologies <roman@ardistech.com>
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  * Handle opening/closing btree
101da177e4SLinus Torvalds  */
111da177e4SLinus Torvalds 
121da177e4SLinus Torvalds #include <linux/pagemap.h>
135a0e3ad6STejun Heo #include <linux/slab.h>
14e1b5c1d3SVignesh Babu BM #include <linux/log2.h>
151da177e4SLinus Torvalds 
161da177e4SLinus Torvalds #include "btree.h"
171da177e4SLinus Torvalds 
181da177e4SLinus Torvalds /* Get a reference to a B*Tree and do some initial checks */
hfs_btree_open(struct super_block * sb,u32 id,btree_keycmp keycmp)191da177e4SLinus Torvalds struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id, btree_keycmp keycmp)
201da177e4SLinus Torvalds {
211da177e4SLinus Torvalds 	struct hfs_btree *tree;
221da177e4SLinus Torvalds 	struct hfs_btree_header_rec *head;
231da177e4SLinus Torvalds 	struct address_space *mapping;
241da177e4SLinus Torvalds 	struct page *page;
251da177e4SLinus Torvalds 	unsigned int size;
261da177e4SLinus Torvalds 
27f8314dc6SPanagiotis Issaris 	tree = kzalloc(sizeof(*tree), GFP_KERNEL);
281da177e4SLinus Torvalds 	if (!tree)
291da177e4SLinus Torvalds 		return NULL;
301da177e4SLinus Torvalds 
314a941035SThomas Gleixner 	mutex_init(&tree->tree_lock);
321da177e4SLinus Torvalds 	spin_lock_init(&tree->hash_lock);
331da177e4SLinus Torvalds 	/* Set the correct compare function */
341da177e4SLinus Torvalds 	tree->sb = sb;
351da177e4SLinus Torvalds 	tree->cnid = id;
361da177e4SLinus Torvalds 	tree->keycmp = keycmp;
371da177e4SLinus Torvalds 
381da177e4SLinus Torvalds 	tree->inode = iget_locked(sb, id);
391da177e4SLinus Torvalds 	if (!tree->inode)
401da177e4SLinus Torvalds 		goto free_tree;
414d4ef9abSEric Sesterhenn 	BUG_ON(!(tree->inode->i_state & I_NEW));
421da177e4SLinus Torvalds 	{
431da177e4SLinus Torvalds 	struct hfs_mdb *mdb = HFS_SB(sb)->mdb;
441da177e4SLinus Torvalds 	HFS_I(tree->inode)->flags = 0;
4539f8d472SMatthias Kaehlcke 	mutex_init(&HFS_I(tree->inode)->extents_lock);
461da177e4SLinus Torvalds 	switch (id) {
471da177e4SLinus Torvalds 	case HFS_EXT_CNID:
481da177e4SLinus Torvalds 		hfs_inode_read_fork(tree->inode, mdb->drXTExtRec, mdb->drXTFlSize,
491da177e4SLinus Torvalds 				    mdb->drXTFlSize, be32_to_cpu(mdb->drXTClpSiz));
50434a964dSPhillip Lougher 		if (HFS_I(tree->inode)->alloc_blocks >
51434a964dSPhillip Lougher 					HFS_I(tree->inode)->first_blocks) {
52d6142673SJoe Perches 			pr_err("invalid btree extent records\n");
53434a964dSPhillip Lougher 			unlock_new_inode(tree->inode);
54434a964dSPhillip Lougher 			goto free_inode;
55434a964dSPhillip Lougher 		}
56434a964dSPhillip Lougher 
571da177e4SLinus Torvalds 		tree->inode->i_mapping->a_ops = &hfs_btree_aops;
581da177e4SLinus Torvalds 		break;
591da177e4SLinus Torvalds 	case HFS_CAT_CNID:
601da177e4SLinus Torvalds 		hfs_inode_read_fork(tree->inode, mdb->drCTExtRec, mdb->drCTFlSize,
611da177e4SLinus Torvalds 				    mdb->drCTFlSize, be32_to_cpu(mdb->drCTClpSiz));
62434a964dSPhillip Lougher 
63434a964dSPhillip Lougher 		if (!HFS_I(tree->inode)->first_blocks) {
64d6142673SJoe Perches 			pr_err("invalid btree extent records (0 size)\n");
65434a964dSPhillip Lougher 			unlock_new_inode(tree->inode);
66434a964dSPhillip Lougher 			goto free_inode;
67434a964dSPhillip Lougher 		}
68434a964dSPhillip Lougher 
691da177e4SLinus Torvalds 		tree->inode->i_mapping->a_ops = &hfs_btree_aops;
701da177e4SLinus Torvalds 		break;
711da177e4SLinus Torvalds 	default:
721da177e4SLinus Torvalds 		BUG();
731da177e4SLinus Torvalds 	}
741da177e4SLinus Torvalds 	}
751da177e4SLinus Torvalds 	unlock_new_inode(tree->inode);
761da177e4SLinus Torvalds 
771da177e4SLinus Torvalds 	mapping = tree->inode->i_mapping;
78090d2b18SPekka Enberg 	page = read_mapping_page(mapping, 0, NULL);
791da177e4SLinus Torvalds 	if (IS_ERR(page))
8046a39c1cSEric Sandeen 		goto free_inode;
811da177e4SLinus Torvalds 
821da177e4SLinus Torvalds 	/* Load the header */
83*21490effSFabio M. De Francesco 	head = (struct hfs_btree_header_rec *)(kmap_local_page(page) +
84*21490effSFabio M. De Francesco 					       sizeof(struct hfs_bnode_desc));
851da177e4SLinus Torvalds 	tree->root = be32_to_cpu(head->root);
861da177e4SLinus Torvalds 	tree->leaf_count = be32_to_cpu(head->leaf_count);
871da177e4SLinus Torvalds 	tree->leaf_head = be32_to_cpu(head->leaf_head);
881da177e4SLinus Torvalds 	tree->leaf_tail = be32_to_cpu(head->leaf_tail);
891da177e4SLinus Torvalds 	tree->node_count = be32_to_cpu(head->node_count);
901da177e4SLinus Torvalds 	tree->free_nodes = be32_to_cpu(head->free_nodes);
911da177e4SLinus Torvalds 	tree->attributes = be32_to_cpu(head->attributes);
921da177e4SLinus Torvalds 	tree->node_size = be16_to_cpu(head->node_size);
931da177e4SLinus Torvalds 	tree->max_key_len = be16_to_cpu(head->max_key_len);
941da177e4SLinus Torvalds 	tree->depth = be16_to_cpu(head->depth);
951da177e4SLinus Torvalds 
961da177e4SLinus Torvalds 	size = tree->node_size;
97e1b5c1d3SVignesh Babu BM 	if (!is_power_of_2(size))
981da177e4SLinus Torvalds 		goto fail_page;
991da177e4SLinus Torvalds 	if (!tree->node_count)
1001da177e4SLinus Torvalds 		goto fail_page;
10155581d01SEric Sandeen 	switch (id) {
10255581d01SEric Sandeen 	case HFS_EXT_CNID:
10355581d01SEric Sandeen 		if (tree->max_key_len != HFS_MAX_EXT_KEYLEN) {
104d6142673SJoe Perches 			pr_err("invalid extent max_key_len %d\n",
105cf059462SEric Sandeen 			       tree->max_key_len);
106cf059462SEric Sandeen 			goto fail_page;
107cf059462SEric Sandeen 		}
10855581d01SEric Sandeen 		break;
10955581d01SEric Sandeen 	case HFS_CAT_CNID:
11055581d01SEric Sandeen 		if (tree->max_key_len != HFS_MAX_CAT_KEYLEN) {
111d6142673SJoe Perches 			pr_err("invalid catalog max_key_len %d\n",
112cf059462SEric Sandeen 			       tree->max_key_len);
113cf059462SEric Sandeen 			goto fail_page;
114cf059462SEric Sandeen 		}
11555581d01SEric Sandeen 		break;
11655581d01SEric Sandeen 	default:
11755581d01SEric Sandeen 		BUG();
11855581d01SEric Sandeen 	}
119cf059462SEric Sandeen 
1201da177e4SLinus Torvalds 	tree->node_size_shift = ffs(size) - 1;
12109cbfeafSKirill A. Shutemov 	tree->pages_per_bnode = (tree->node_size + PAGE_SIZE - 1) >> PAGE_SHIFT;
1221da177e4SLinus Torvalds 
123*21490effSFabio M. De Francesco 	kunmap_local(head);
12409cbfeafSKirill A. Shutemov 	put_page(page);
1251da177e4SLinus Torvalds 	return tree;
1261da177e4SLinus Torvalds 
1271da177e4SLinus Torvalds fail_page:
128*21490effSFabio M. De Francesco 	kunmap_local(head);
12909cbfeafSKirill A. Shutemov 	put_page(page);
13046a39c1cSEric Sandeen free_inode:
131cf059462SEric Sandeen 	tree->inode->i_mapping->a_ops = &hfs_aops;
1321da177e4SLinus Torvalds 	iput(tree->inode);
13346a39c1cSEric Sandeen free_tree:
1341da177e4SLinus Torvalds 	kfree(tree);
1351da177e4SLinus Torvalds 	return NULL;
1361da177e4SLinus Torvalds }
1371da177e4SLinus Torvalds 
1381da177e4SLinus Torvalds /* Release resources used by a btree */
hfs_btree_close(struct hfs_btree * tree)1391da177e4SLinus Torvalds void hfs_btree_close(struct hfs_btree *tree)
1401da177e4SLinus Torvalds {
1411da177e4SLinus Torvalds 	struct hfs_bnode *node;
1421da177e4SLinus Torvalds 	int i;
1431da177e4SLinus Torvalds 
1441da177e4SLinus Torvalds 	if (!tree)
1451da177e4SLinus Torvalds 		return;
1461da177e4SLinus Torvalds 
1471da177e4SLinus Torvalds 	for (i = 0; i < NODE_HASH_SIZE; i++) {
1481da177e4SLinus Torvalds 		while ((node = tree->node_hash[i])) {
1491da177e4SLinus Torvalds 			tree->node_hash[i] = node->next_hash;
1501da177e4SLinus Torvalds 			if (atomic_read(&node->refcnt))
151d6142673SJoe Perches 				pr_err("node %d:%d still has %d user(s)!\n",
152d6142673SJoe Perches 				       node->tree->cnid, node->this,
153d6142673SJoe Perches 				       atomic_read(&node->refcnt));
1541da177e4SLinus Torvalds 			hfs_bnode_free(node);
1551da177e4SLinus Torvalds 			tree->node_hash_cnt--;
1561da177e4SLinus Torvalds 		}
1571da177e4SLinus Torvalds 	}
1581da177e4SLinus Torvalds 	iput(tree->inode);
1591da177e4SLinus Torvalds 	kfree(tree);
1601da177e4SLinus Torvalds }
1611da177e4SLinus Torvalds 
hfs_btree_write(struct hfs_btree * tree)1621da177e4SLinus Torvalds void hfs_btree_write(struct hfs_btree *tree)
1631da177e4SLinus Torvalds {
1641da177e4SLinus Torvalds 	struct hfs_btree_header_rec *head;
1651da177e4SLinus Torvalds 	struct hfs_bnode *node;
1661da177e4SLinus Torvalds 	struct page *page;
1671da177e4SLinus Torvalds 
1681da177e4SLinus Torvalds 	node = hfs_bnode_find(tree, 0);
1691da177e4SLinus Torvalds 	if (IS_ERR(node))
1701da177e4SLinus Torvalds 		/* panic? */
1711da177e4SLinus Torvalds 		return;
1721da177e4SLinus Torvalds 	/* Load the header */
1731da177e4SLinus Torvalds 	page = node->page[0];
174*21490effSFabio M. De Francesco 	head = (struct hfs_btree_header_rec *)(kmap_local_page(page) +
175*21490effSFabio M. De Francesco 					       sizeof(struct hfs_bnode_desc));
1761da177e4SLinus Torvalds 
1771da177e4SLinus Torvalds 	head->root = cpu_to_be32(tree->root);
1781da177e4SLinus Torvalds 	head->leaf_count = cpu_to_be32(tree->leaf_count);
1791da177e4SLinus Torvalds 	head->leaf_head = cpu_to_be32(tree->leaf_head);
1801da177e4SLinus Torvalds 	head->leaf_tail = cpu_to_be32(tree->leaf_tail);
1811da177e4SLinus Torvalds 	head->node_count = cpu_to_be32(tree->node_count);
1821da177e4SLinus Torvalds 	head->free_nodes = cpu_to_be32(tree->free_nodes);
1831da177e4SLinus Torvalds 	head->attributes = cpu_to_be32(tree->attributes);
1841da177e4SLinus Torvalds 	head->depth = cpu_to_be16(tree->depth);
1851da177e4SLinus Torvalds 
186*21490effSFabio M. De Francesco 	kunmap_local(head);
1871da177e4SLinus Torvalds 	set_page_dirty(page);
1881da177e4SLinus Torvalds 	hfs_bnode_put(node);
1891da177e4SLinus Torvalds }
1901da177e4SLinus Torvalds 
hfs_bmap_new_bmap(struct hfs_bnode * prev,u32 idx)1911da177e4SLinus Torvalds static struct hfs_bnode *hfs_bmap_new_bmap(struct hfs_bnode *prev, u32 idx)
1921da177e4SLinus Torvalds {
1931da177e4SLinus Torvalds 	struct hfs_btree *tree = prev->tree;
1941da177e4SLinus Torvalds 	struct hfs_bnode *node;
1951da177e4SLinus Torvalds 	struct hfs_bnode_desc desc;
1961da177e4SLinus Torvalds 	__be32 cnid;
1971da177e4SLinus Torvalds 
1981da177e4SLinus Torvalds 	node = hfs_bnode_create(tree, idx);
1991da177e4SLinus Torvalds 	if (IS_ERR(node))
2001da177e4SLinus Torvalds 		return node;
2011da177e4SLinus Torvalds 
2021da177e4SLinus Torvalds 	if (!tree->free_nodes)
2031da177e4SLinus Torvalds 		panic("FIXME!!!");
2041da177e4SLinus Torvalds 	tree->free_nodes--;
2051da177e4SLinus Torvalds 	prev->next = idx;
2061da177e4SLinus Torvalds 	cnid = cpu_to_be32(idx);
2071da177e4SLinus Torvalds 	hfs_bnode_write(prev, &cnid, offsetof(struct hfs_bnode_desc, next), 4);
2081da177e4SLinus Torvalds 
2091da177e4SLinus Torvalds 	node->type = HFS_NODE_MAP;
2101da177e4SLinus Torvalds 	node->num_recs = 1;
2111da177e4SLinus Torvalds 	hfs_bnode_clear(node, 0, tree->node_size);
2121da177e4SLinus Torvalds 	desc.next = 0;
2131da177e4SLinus Torvalds 	desc.prev = 0;
2141da177e4SLinus Torvalds 	desc.type = HFS_NODE_MAP;
2151da177e4SLinus Torvalds 	desc.height = 0;
2161da177e4SLinus Torvalds 	desc.num_recs = cpu_to_be16(1);
2171da177e4SLinus Torvalds 	desc.reserved = 0;
2181da177e4SLinus Torvalds 	hfs_bnode_write(node, &desc, 0, sizeof(desc));
2191da177e4SLinus Torvalds 	hfs_bnode_write_u16(node, 14, 0x8000);
2201da177e4SLinus Torvalds 	hfs_bnode_write_u16(node, tree->node_size - 2, 14);
2211da177e4SLinus Torvalds 	hfs_bnode_write_u16(node, tree->node_size - 4, tree->node_size - 6);
2221da177e4SLinus Torvalds 
2231da177e4SLinus Torvalds 	return node;
2241da177e4SLinus Torvalds }
2251da177e4SLinus Torvalds 
22654640c75SErnesto A. Fernández /* Make sure @tree has enough space for the @rsvd_nodes */
hfs_bmap_reserve(struct hfs_btree * tree,int rsvd_nodes)22754640c75SErnesto A. Fernández int hfs_bmap_reserve(struct hfs_btree *tree, int rsvd_nodes)
22854640c75SErnesto A. Fernández {
22954640c75SErnesto A. Fernández 	struct inode *inode = tree->inode;
23054640c75SErnesto A. Fernández 	u32 count;
23154640c75SErnesto A. Fernández 	int res;
23254640c75SErnesto A. Fernández 
23354640c75SErnesto A. Fernández 	while (tree->free_nodes < rsvd_nodes) {
23454640c75SErnesto A. Fernández 		res = hfs_extend_file(inode);
23554640c75SErnesto A. Fernández 		if (res)
23654640c75SErnesto A. Fernández 			return res;
23754640c75SErnesto A. Fernández 		HFS_I(inode)->phys_size = inode->i_size =
23854640c75SErnesto A. Fernández 				(loff_t)HFS_I(inode)->alloc_blocks *
23954640c75SErnesto A. Fernández 				HFS_SB(tree->sb)->alloc_blksz;
24054640c75SErnesto A. Fernández 		HFS_I(inode)->fs_blocks = inode->i_size >>
24154640c75SErnesto A. Fernández 					  tree->sb->s_blocksize_bits;
24254640c75SErnesto A. Fernández 		inode_set_bytes(inode, inode->i_size);
24354640c75SErnesto A. Fernández 		count = inode->i_size >> tree->node_size_shift;
24454640c75SErnesto A. Fernández 		tree->free_nodes += count - tree->node_count;
24554640c75SErnesto A. Fernández 		tree->node_count = count;
24654640c75SErnesto A. Fernández 	}
24754640c75SErnesto A. Fernández 	return 0;
24854640c75SErnesto A. Fernández }
24954640c75SErnesto A. Fernández 
hfs_bmap_alloc(struct hfs_btree * tree)2501da177e4SLinus Torvalds struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree)
2511da177e4SLinus Torvalds {
2521da177e4SLinus Torvalds 	struct hfs_bnode *node, *next_node;
2531da177e4SLinus Torvalds 	struct page **pagep;
2541da177e4SLinus Torvalds 	u32 nidx, idx;
2553e5a5097SAndrew Morton 	unsigned off;
2563e5a5097SAndrew Morton 	u16 off16;
2573e5a5097SAndrew Morton 	u16 len;
2581da177e4SLinus Torvalds 	u8 *data, byte, m;
25954640c75SErnesto A. Fernández 	int i, res;
2601da177e4SLinus Torvalds 
26154640c75SErnesto A. Fernández 	res = hfs_bmap_reserve(tree, 1);
2621da177e4SLinus Torvalds 	if (res)
2631da177e4SLinus Torvalds 		return ERR_PTR(res);
2641da177e4SLinus Torvalds 
2651da177e4SLinus Torvalds 	nidx = 0;
2661da177e4SLinus Torvalds 	node = hfs_bnode_find(tree, nidx);
2671da177e4SLinus Torvalds 	if (IS_ERR(node))
2681da177e4SLinus Torvalds 		return node;
2693e5a5097SAndrew Morton 	len = hfs_brec_lenoff(node, 2, &off16);
2703e5a5097SAndrew Morton 	off = off16;
2711da177e4SLinus Torvalds 
2721da177e4SLinus Torvalds 	off += node->page_offset;
27309cbfeafSKirill A. Shutemov 	pagep = node->page + (off >> PAGE_SHIFT);
274*21490effSFabio M. De Francesco 	data = kmap_local_page(*pagep);
27509cbfeafSKirill A. Shutemov 	off &= ~PAGE_MASK;
2761da177e4SLinus Torvalds 	idx = 0;
2771da177e4SLinus Torvalds 
2781da177e4SLinus Torvalds 	for (;;) {
2791da177e4SLinus Torvalds 		while (len) {
2801da177e4SLinus Torvalds 			byte = data[off];
2811da177e4SLinus Torvalds 			if (byte != 0xff) {
2821da177e4SLinus Torvalds 				for (m = 0x80, i = 0; i < 8; m >>= 1, i++) {
2831da177e4SLinus Torvalds 					if (!(byte & m)) {
2841da177e4SLinus Torvalds 						idx += i;
2851da177e4SLinus Torvalds 						data[off] |= m;
2861da177e4SLinus Torvalds 						set_page_dirty(*pagep);
287*21490effSFabio M. De Francesco 						kunmap_local(data);
2881da177e4SLinus Torvalds 						tree->free_nodes--;
2891da177e4SLinus Torvalds 						mark_inode_dirty(tree->inode);
2901da177e4SLinus Torvalds 						hfs_bnode_put(node);
2911da177e4SLinus Torvalds 						return hfs_bnode_create(tree, idx);
2921da177e4SLinus Torvalds 					}
2931da177e4SLinus Torvalds 				}
2941da177e4SLinus Torvalds 			}
29509cbfeafSKirill A. Shutemov 			if (++off >= PAGE_SIZE) {
296*21490effSFabio M. De Francesco 				kunmap_local(data);
297*21490effSFabio M. De Francesco 				data = kmap_local_page(*++pagep);
2981da177e4SLinus Torvalds 				off = 0;
2991da177e4SLinus Torvalds 			}
3001da177e4SLinus Torvalds 			idx += 8;
3011da177e4SLinus Torvalds 			len--;
3021da177e4SLinus Torvalds 		}
303*21490effSFabio M. De Francesco 		kunmap_local(data);
3041da177e4SLinus Torvalds 		nidx = node->next;
3051da177e4SLinus Torvalds 		if (!nidx) {
306d6142673SJoe Perches 			printk(KERN_DEBUG "create new bmap node...\n");
3071da177e4SLinus Torvalds 			next_node = hfs_bmap_new_bmap(node, idx);
3081da177e4SLinus Torvalds 		} else
3091da177e4SLinus Torvalds 			next_node = hfs_bnode_find(tree, nidx);
3101da177e4SLinus Torvalds 		hfs_bnode_put(node);
3111da177e4SLinus Torvalds 		if (IS_ERR(next_node))
3121da177e4SLinus Torvalds 			return next_node;
3131da177e4SLinus Torvalds 		node = next_node;
3141da177e4SLinus Torvalds 
3153e5a5097SAndrew Morton 		len = hfs_brec_lenoff(node, 0, &off16);
3163e5a5097SAndrew Morton 		off = off16;
3171da177e4SLinus Torvalds 		off += node->page_offset;
31809cbfeafSKirill A. Shutemov 		pagep = node->page + (off >> PAGE_SHIFT);
319*21490effSFabio M. De Francesco 		data = kmap_local_page(*pagep);
32009cbfeafSKirill A. Shutemov 		off &= ~PAGE_MASK;
3211da177e4SLinus Torvalds 	}
3221da177e4SLinus Torvalds }
3231da177e4SLinus Torvalds 
hfs_bmap_free(struct hfs_bnode * node)3241da177e4SLinus Torvalds void hfs_bmap_free(struct hfs_bnode *node)
3251da177e4SLinus Torvalds {
3261da177e4SLinus Torvalds 	struct hfs_btree *tree;
3271da177e4SLinus Torvalds 	struct page *page;
3281da177e4SLinus Torvalds 	u16 off, len;
3291da177e4SLinus Torvalds 	u32 nidx;
3301da177e4SLinus Torvalds 	u8 *data, byte, m;
3311da177e4SLinus Torvalds 
332c2b3e1f7SJoe Perches 	hfs_dbg(BNODE_MOD, "btree_free_node: %u\n", node->this);
3331da177e4SLinus Torvalds 	tree = node->tree;
3341da177e4SLinus Torvalds 	nidx = node->this;
3351da177e4SLinus Torvalds 	node = hfs_bnode_find(tree, 0);
3361da177e4SLinus Torvalds 	if (IS_ERR(node))
3371da177e4SLinus Torvalds 		return;
3381da177e4SLinus Torvalds 	len = hfs_brec_lenoff(node, 2, &off);
3391da177e4SLinus Torvalds 	while (nidx >= len * 8) {
3401da177e4SLinus Torvalds 		u32 i;
3411da177e4SLinus Torvalds 
3421da177e4SLinus Torvalds 		nidx -= len * 8;
3431da177e4SLinus Torvalds 		i = node->next;
3441da177e4SLinus Torvalds 		if (!i) {
3451da177e4SLinus Torvalds 			/* panic */;
346d6142673SJoe Perches 			pr_crit("unable to free bnode %u. bmap not found!\n",
347d6142673SJoe Perches 				node->this);
348ce96a407SPan Bian 			hfs_bnode_put(node);
3491da177e4SLinus Torvalds 			return;
3501da177e4SLinus Torvalds 		}
351ce96a407SPan Bian 		hfs_bnode_put(node);
3521da177e4SLinus Torvalds 		node = hfs_bnode_find(tree, i);
3531da177e4SLinus Torvalds 		if (IS_ERR(node))
3541da177e4SLinus Torvalds 			return;
3551da177e4SLinus Torvalds 		if (node->type != HFS_NODE_MAP) {
3561da177e4SLinus Torvalds 			/* panic */;
357d6142673SJoe Perches 			pr_crit("invalid bmap found! (%u,%d)\n",
358d6142673SJoe Perches 				node->this, node->type);
3591da177e4SLinus Torvalds 			hfs_bnode_put(node);
3601da177e4SLinus Torvalds 			return;
3611da177e4SLinus Torvalds 		}
3621da177e4SLinus Torvalds 		len = hfs_brec_lenoff(node, 0, &off);
3631da177e4SLinus Torvalds 	}
3641da177e4SLinus Torvalds 	off += node->page_offset + nidx / 8;
36509cbfeafSKirill A. Shutemov 	page = node->page[off >> PAGE_SHIFT];
366*21490effSFabio M. De Francesco 	data = kmap_local_page(page);
36709cbfeafSKirill A. Shutemov 	off &= ~PAGE_MASK;
3681da177e4SLinus Torvalds 	m = 1 << (~nidx & 7);
3691da177e4SLinus Torvalds 	byte = data[off];
3701da177e4SLinus Torvalds 	if (!(byte & m)) {
371d6142673SJoe Perches 		pr_crit("trying to free free bnode %u(%d)\n",
372d6142673SJoe Perches 			node->this, node->type);
373*21490effSFabio M. De Francesco 		kunmap_local(data);
3741da177e4SLinus Torvalds 		hfs_bnode_put(node);
3751da177e4SLinus Torvalds 		return;
3761da177e4SLinus Torvalds 	}
3771da177e4SLinus Torvalds 	data[off] = byte & ~m;
3781da177e4SLinus Torvalds 	set_page_dirty(page);
379*21490effSFabio M. De Francesco 	kunmap_local(data);
3801da177e4SLinus Torvalds 	hfs_bnode_put(node);
3811da177e4SLinus Torvalds 	tree->free_nodes++;
3821da177e4SLinus Torvalds 	mark_inode_dirty(tree->inode);
3831da177e4SLinus Torvalds }
384