• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/fs/hfsplus_journal/
1/*
2 *  linux/fs/hfsplus/btree.c
3 *
4 * Copyright (C) 2001
5 * Brad Boyer (flar@allandria.com)
6 * (C) 2003 Ardis Technologies <roman@ardistech.com>
7 *
8 * Handle opening/closing btree
9 */
10
11#include <linux/slab.h>
12#include <linux/pagemap.h>
13#include <linux/log2.h>
14
15#include "hfsplus_fs.h"
16#include "hfsplus_raw.h"
17
18unsigned hfsplus_pages_per_bnode;
19/* Get a reference to a B*Tree and do some initial checks */
20struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
21{
22	struct hfs_btree *tree;
23	struct hfs_btree_header_rec *head;
24	struct address_space *mapping;
25	struct inode *inode;
26	struct page *page;
27	unsigned int size;
28
29	tree = kzalloc(sizeof(*tree), GFP_KERNEL);
30	if (!tree)
31		return NULL;
32
33	mutex_init(&tree->tree_lock);
34	spin_lock_init(&tree->hash_lock);
35	tree->sb = sb;
36	tree->cnid = id;
37	inode = hfsplus_iget(sb, id);
38	if (IS_ERR(inode))
39		goto free_tree;
40	tree->inode = inode;
41
42	if (!HFSPLUS_I(tree->inode).first_blocks) {
43		printk(KERN_ERR
44		       "hfs: invalid btree extent records (0 size).\n");
45		goto free_inode;
46	}
47
48	mapping = tree->inode->i_mapping;
49	page = read_mapping_page(mapping, 0, NULL);
50	if (IS_ERR(page))
51		goto free_inode;
52
53	/* Load the header */
54	head = (struct hfs_btree_header_rec *)(kmap(page) + sizeof(struct hfs_bnode_desc));
55	tree->root = be32_to_cpu(head->root);
56	tree->leaf_count = be32_to_cpu(head->leaf_count);
57	tree->leaf_head = be32_to_cpu(head->leaf_head);
58	tree->leaf_tail = be32_to_cpu(head->leaf_tail);
59	tree->node_count = be32_to_cpu(head->node_count);
60	tree->free_nodes = be32_to_cpu(head->free_nodes);
61	tree->attributes = be32_to_cpu(head->attributes);
62	tree->node_size = be16_to_cpu(head->node_size);
63	tree->max_key_len = be16_to_cpu(head->max_key_len);
64	tree->depth = be16_to_cpu(head->depth);
65
66	/* Verify the tree and set the correct compare function */
67	switch (id) {
68	case HFSPLUS_EXT_CNID:
69		if (tree->max_key_len != HFSPLUS_EXT_KEYLEN - sizeof(u16)) {
70			printk(KERN_ERR "hfs: invalid extent max_key_len %d\n",
71				tree->max_key_len);
72			goto fail_page;
73		}
74		if (tree->attributes & HFS_TREE_VARIDXKEYS) {
75			printk(KERN_ERR "hfs: invalid extent btree flag\n");
76			goto fail_page;
77		}
78
79		tree->keycmp = hfsplus_ext_cmp_key;
80		break;
81	case HFSPLUS_CAT_CNID:
82		if (tree->max_key_len != HFSPLUS_CAT_KEYLEN - sizeof(u16)) {
83			printk(KERN_ERR "hfs: invalid catalog max_key_len %d\n",
84				tree->max_key_len);
85			goto fail_page;
86		}
87		if (!(tree->attributes & HFS_TREE_VARIDXKEYS)) {
88			printk(KERN_ERR "hfs: invalid catalog btree flag\n");
89			goto fail_page;
90		}
91
92		if (test_bit(HFSPLUS_SB_HFSX, &HFSPLUS_SB(sb).flags) &&
93		    (head->key_type == HFSPLUS_KEY_BINARY))
94			tree->keycmp = hfsplus_cat_bin_cmp_key;
95		else {
96			tree->keycmp = hfsplus_cat_case_cmp_key;
97			set_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb).flags);
98		}
99		break;
100	default:
101		printk(KERN_ERR "hfs: unknown B*Tree requested\n");
102		goto fail_page;
103	}
104
105	if (!(tree->attributes & HFS_TREE_BIGKEYS)) {
106		printk(KERN_ERR "hfs: invalid btree flag\n");
107		goto fail_page;
108	}
109
110	size = tree->node_size;
111	if (!is_power_of_2(size))
112		goto fail_page;
113	if (!tree->node_count)
114		goto fail_page;
115	tree->node_size_shift = ffs(size) - 1;
116
117	tree->pages_per_bnode = (tree->node_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
118hfsplus_pages_per_bnode=tree->pages_per_bnode;
119	kunmap(page);
120	page_cache_release(page);
121	return tree;
122
123 fail_page:
124	tree->inode->i_mapping->a_ops = &hfsplus_aops;
125	page_cache_release(page);
126 free_inode:
127	iput(tree->inode);
128 free_tree:
129	kfree(tree);
130	return NULL;
131}
132
133/* Release resources used by a btree */
134void hfs_btree_close(struct hfs_btree *tree)
135{
136	struct hfs_bnode *node;
137	int i;
138
139	if (!tree)
140		return;
141
142	for (i = 0; i < NODE_HASH_SIZE; i++) {
143		while ((node = tree->node_hash[i])) {
144			tree->node_hash[i] = node->next_hash;
145			if (atomic_read(&node->refcnt))
146				printk(KERN_CRIT "hfs: node %d:%d still has %d user(s)!\n",
147					node->tree->cnid, node->this, atomic_read(&node->refcnt));
148			hfs_bnode_free(node);
149			tree->node_hash_cnt--;
150		}
151	}
152	iput(tree->inode);
153	kfree(tree);
154}
155
156int hfs_btree_write(hfsplus_handle_t *hfsplus_handle,struct hfs_btree *tree)
157{
158	struct hfs_btree_header_rec *head;
159	struct hfs_bnode *node;
160	struct page *page;
161
162	node = hfs_bnode_find(hfsplus_handle, tree, 0);
163	if (IS_ERR(node))
164		/* panic? */
165		return -EIO;
166	/* Load the header */
167	page = node->page[0];
168	head = (struct hfs_btree_header_rec *)(kmap(page) + sizeof(struct hfs_bnode_desc));
169
170	head->root = cpu_to_be32(tree->root);
171	head->leaf_count = cpu_to_be32(tree->leaf_count);
172	head->leaf_head = cpu_to_be32(tree->leaf_head);
173	head->leaf_tail = cpu_to_be32(tree->leaf_tail);
174	head->node_count = cpu_to_be32(tree->node_count);
175	head->free_nodes = cpu_to_be32(tree->free_nodes);
176	head->attributes = cpu_to_be32(tree->attributes);
177	head->depth = cpu_to_be16(tree->depth);
178
179	kunmap(page);
180	hfsplus_journalled_set_page_dirty(hfsplus_handle, page);
181	hfs_bnode_put(hfsplus_handle, node);
182	return 0;
183}
184
185static struct hfs_bnode *hfs_bmap_new_bmap(hfsplus_handle_t *hfsplus_handle, struct hfs_bnode *prev, u32 idx)
186{
187	struct hfs_btree *tree = prev->tree;
188	struct hfs_bnode *node;
189	struct hfs_bnode_desc desc;
190	__be32 cnid;
191
192	node = hfs_bnode_create(hfsplus_handle, tree, idx);
193	if (IS_ERR(node))
194		return node;
195
196	tree->free_nodes--;
197	prev->next = idx;
198	cnid = cpu_to_be32(idx);
199	hfs_bnode_write(hfsplus_handle, prev, &cnid, offsetof(struct hfs_bnode_desc, next), 4);
200
201	node->type = HFS_NODE_MAP;
202	node->num_recs = 1;
203	hfs_bnode_clear(hfsplus_handle, node, 0, tree->node_size);
204	desc.next = 0;
205	desc.prev = 0;
206	desc.type = HFS_NODE_MAP;
207	desc.height = 0;
208	desc.num_recs = cpu_to_be16(1);
209	desc.reserved = 0;
210	hfs_bnode_write(hfsplus_handle, node, &desc, 0, sizeof(desc));
211	hfs_bnode_write_u16(hfsplus_handle, node, 14, 0x8000);
212	hfs_bnode_write_u16(hfsplus_handle, node, tree->node_size - 2, 14);
213	hfs_bnode_write_u16(hfsplus_handle, node, tree->node_size - 4, tree->node_size - 6);
214
215	return node;
216}
217
218struct hfs_bnode *hfs_bmap_alloc(hfsplus_handle_t *hfsplus_handle, struct hfs_btree *tree)
219{
220	struct hfs_bnode *node, *next_node;
221	struct page **pagep;
222	u32 nidx, idx;
223	unsigned off;
224	u16 off16;
225	u16 len;
226	u8 *data, byte, m;
227	int i;
228
229	while (!tree->free_nodes) {
230		struct inode *inode = tree->inode;
231		u32 count;
232		int res;
233
234		res = hfsplus_file_extend(hfsplus_handle, inode);
235		if (res)
236			return ERR_PTR(res);
237		HFSPLUS_I(inode).phys_size = inode->i_size =
238				(loff_t)HFSPLUS_I(inode).alloc_blocks <<
239				HFSPLUS_SB(tree->sb).alloc_blksz_shift;
240		HFSPLUS_I(inode).fs_blocks = HFSPLUS_I(inode).alloc_blocks <<
241					     HFSPLUS_SB(tree->sb).fs_shift;
242		inode_set_bytes(inode, inode->i_size);
243        /* Foxconn added start pling 05/31/2010 */
244        /* Set the i_blocks field properly */
245        inode->i_blocks = inode->i_size/512;
246        if (inode->i_size % 512)
247            inode->i_blocks++;
248        /* Foxconn added end pling 05/31/2010 */
249		count = inode->i_size >> tree->node_size_shift;
250		tree->free_nodes = count - tree->node_count;
251		tree->node_count = count;
252	}
253
254	nidx = 0;
255	node = hfs_bnode_find(hfsplus_handle, tree, nidx);
256	if (IS_ERR(node))
257		return node;
258	len = hfs_brec_lenoff(node, 2, &off16);
259	off = off16;
260
261	off += node->page_offset;
262	pagep = node->page + (off >> PAGE_CACHE_SHIFT);
263	data = kmap(*pagep);
264	off &= ~PAGE_CACHE_MASK;
265	idx = 0;
266
267	for (;;) {
268		while (len) {
269			byte = data[off];
270			if (byte != 0xff) {
271				for (m = 0x80, i = 0; i < 8; m >>= 1, i++) {
272					if (!(byte & m)) {
273						idx += i;
274						data[off] |= m;
275						hfsplus_journalled_set_page_dirty(hfsplus_handle, *pagep);
276						kunmap(*pagep);
277						tree->free_nodes--;
278						if (hfsplus_journalled_mark_inode_dirty(__FUNCTION__, hfsplus_handle, tree->inode))
279							return NULL;
280						hfs_bnode_put(hfsplus_handle, node);
281						return hfs_bnode_create(hfsplus_handle, tree, idx);
282					}
283				}
284			}
285			if (++off >= PAGE_CACHE_SIZE) {
286				kunmap(*pagep);
287				data = kmap(*++pagep);
288				off = 0;
289			}
290			idx += 8;
291			len--;
292		}
293		kunmap(*pagep);
294		nidx = node->next;
295		if (!nidx) {
296			printk(KERN_DEBUG "hfs: create new bmap node...\n");
297			next_node = hfs_bmap_new_bmap(hfsplus_handle, node, idx);
298		} else
299			next_node = hfs_bnode_find(hfsplus_handle, tree, nidx);
300		hfs_bnode_put(hfsplus_handle, node);
301		if (IS_ERR(next_node))
302			return next_node;
303		node = next_node;
304
305		len = hfs_brec_lenoff(node, 0, &off16);
306		off = off16;
307		off += node->page_offset;
308		pagep = node->page + (off >> PAGE_CACHE_SHIFT);
309		data = kmap(*pagep);
310		off &= ~PAGE_CACHE_MASK;
311	}
312}
313
314void hfs_bmap_free(hfsplus_handle_t *hfsplus_handle, struct hfs_bnode *node)
315{
316	struct hfs_btree *tree;
317	struct page *page;
318	u16 off, len;
319	u32 nidx;
320	u8 *data, byte, m;
321
322	dprint(DBG_BNODE_MOD, "btree_free_node: %u\n", node->this);
323	BUG_ON(!node->this);
324	tree = node->tree;
325	nidx = node->this;
326	node = hfs_bnode_find(hfsplus_handle, tree, 0);
327	if (IS_ERR(node))
328		return;
329	len = hfs_brec_lenoff(node, 2, &off);
330	while (nidx >= len * 8) {
331		u32 i;
332
333		nidx -= len * 8;
334		i = node->next;
335		hfs_bnode_put(hfsplus_handle, node);
336		if (!i) {
337			/* panic */;
338			printk(KERN_CRIT "hfs: unable to free bnode %u. bmap not found!\n", node->this);
339			return;
340		}
341		node = hfs_bnode_find(hfsplus_handle, tree, i);
342		if (IS_ERR(node))
343			return;
344		if (node->type != HFS_NODE_MAP) {
345			/* panic */;
346			printk(KERN_CRIT "hfs: invalid bmap found! (%u,%d)\n", node->this, node->type);
347			hfs_bnode_put(hfsplus_handle, node);
348			return;
349		}
350		len = hfs_brec_lenoff(node, 0, &off);
351	}
352	off += node->page_offset + nidx / 8;
353	page = node->page[off >> PAGE_CACHE_SHIFT];
354	data = kmap(page);
355	off &= ~PAGE_CACHE_MASK;
356	m = 1 << (~nidx & 7);
357	byte = data[off];
358	if (!(byte & m)) {
359		printk(KERN_CRIT "hfs: trying to free free bnode %u(%d)\n", node->this, node->type);
360		kunmap(page);
361		hfs_bnode_put(hfsplus_handle, node);
362		return;
363	}
364	data[off] = byte & ~m;
365	hfsplus_journalled_set_page_dirty(hfsplus_handle, page);
366	kunmap(page);
367	hfs_bnode_put(hfsplus_handle, node);
368	tree->free_nodes++;
369	if (hfsplus_journalled_mark_inode_dirty(__FUNCTION__, hfsplus_handle, tree->inode))
370		return;
371}
372