OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [fs/] [hfsplus/] [btree.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
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 <asm/div64.h>
14
 
15
#include "hfsplus_fs.h"
16
#include "hfsplus_raw.h"
17
 
18
/* Release resources used by a btree */
19
void hfsplus_close_btree(struct hfsplus_btree *tree)
20
{
21
        hfsplus_bnode *node;
22
        int i;
23
 
24
        if (!tree)
25
                return;
26
 
27
        for (i = 0; i < NODE_HASH_SIZE; i++) {
28
                while ((node = tree->node_hash[i])) {
29
                        tree->node_hash[i] = node->next_hash;
30
                        if (atomic_read(&node->refcnt))
31
                                printk("HFS+: node %d:%d still has %d user(s)!\n",
32
                                        node->tree->cnid, node->this, atomic_read(&node->refcnt));
33
                        hfsplus_bnode_free(node);
34
                        tree->node_hash_cnt--;
35
                }
36
        }
37
        iput(tree->inode);
38
        kfree(tree);
39
}
40
 
41
/* Fill in extra data in tree structure from header node */
42
static void hfsplus_read_treeinfo(hfsplus_btree *tree, hfsplus_btree_head *hdr)
43
{
44
        unsigned int shift, size;
45
 
46
        if (!tree || !hdr)
47
                return;
48
 
49
        tree->root = be32_to_cpu(hdr->root);
50
        tree->leaf_count = be32_to_cpu(hdr->leaf_count);
51
        tree->leaf_head = be32_to_cpu(hdr->leaf_head);
52
        tree->leaf_tail = be32_to_cpu(hdr->leaf_tail);
53
        tree->node_count = be32_to_cpu(hdr->node_count);
54
        tree->free_nodes = be32_to_cpu(hdr->free_nodes);
55
        tree->attributes = be32_to_cpu(hdr->attributes);
56
        tree->node_size = be16_to_cpu(hdr->node_size);
57
        tree->max_key_len = be16_to_cpu(hdr->max_key_len);
58
        tree->depth = be16_to_cpu(hdr->depth);
59
 
60
        size = tree->node_size;
61
        if (size & (size - 1))
62
                /* panic */;
63
        for (shift = 0; size >>= 1; shift += 1)
64
                ;
65
        tree->node_size_shift = shift;
66
 
67
        tree->pages_per_bnode = (tree->node_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
68
}
69
 
70
static void hfsplus_write_treeinfo(hfsplus_btree *tree, hfsplus_btree_head *hdr)
71
{
72
        hdr->root = cpu_to_be32(tree->root);
73
        hdr->leaf_count = cpu_to_be32(tree->leaf_count);
74
        hdr->leaf_head = cpu_to_be32(tree->leaf_head);
75
        hdr->leaf_tail = cpu_to_be32(tree->leaf_tail);
76
        hdr->node_count = cpu_to_be32(tree->node_count);
77
        hdr->free_nodes = cpu_to_be32(tree->free_nodes);
78
        hdr->attributes = cpu_to_be32(tree->attributes);
79
        hdr->depth = cpu_to_be16(tree->depth);
80
}
81
 
82
/* Get a reference to a B*Tree and do some initial checks */
83
hfsplus_btree *hfsplus_open_btree(struct super_block *sb, u32 id)
84
{
85
        hfsplus_btree *tree;
86
        hfsplus_btree_head *head;
87
        struct address_space *mapping;
88
        struct page *page;
89
 
90
        tree = kmalloc(sizeof(struct hfsplus_btree), GFP_KERNEL);
91
        if (!tree)
92
                return NULL;
93
        memset(tree, 0, sizeof(struct hfsplus_btree));
94
 
95
        init_MUTEX(&tree->tree_lock);
96
        spin_lock_init(&tree->hash_lock);
97
        /* Set the correct compare function */
98
        tree->sb = sb;
99
        tree->cnid = id;
100
        if (id == HFSPLUS_EXT_CNID) {
101
                tree->keycmp = hfsplus_cmp_ext_key;
102
        } else if (id == HFSPLUS_CAT_CNID) {
103
                tree->keycmp = hfsplus_cmp_cat_key;
104
        } else {
105
                printk("HFS+-fs: unknown B*Tree requested\n");
106
                goto free_tree;
107
        }
108
        tree->inode = iget(sb, id);
109
        if (!tree->inode)
110
                goto free_tree;
111
 
112
        mapping = tree->inode->i_mapping;
113
        page = grab_cache_page(mapping, 0);
114
        if (!page)
115
                goto free_tree;
116
        if (!PageUptodate(page)) {
117
                if (mapping->a_ops->readpage(NULL, page))
118
                        goto fail_page;
119
                wait_on_page_locked(page);
120
                if (!PageUptodate(page))
121
                        goto fail_page;
122
        } else
123
                unlock_page(page);
124
 
125
        /* Load the header */
126
        head = (hfsplus_btree_head *)(kmap(page) + sizeof(hfsplus_btree_node_desc));
127
        hfsplus_read_treeinfo(tree, head);
128
        kunmap(page);
129
        page_cache_release(page);
130
        return tree;
131
 
132
 fail_page:
133
        page_cache_release(page);
134
 free_tree:
135
        iput(tree->inode);
136
        kfree(tree);
137
        return NULL;
138
}
139
 
140
void hfsplus_write_btree(struct hfsplus_btree *tree)
141
{
142
        hfsplus_btree_head *head;
143
        hfsplus_bnode *node;
144
        struct page *page;
145
 
146
        node = hfsplus_find_bnode(tree, 0);
147
        if (!node)
148
                /* panic? */
149
                return;
150
        /* Load the header */
151
        page = node->page[0];
152
        head = (hfsplus_btree_head *)(kmap(page) + sizeof(hfsplus_btree_node_desc));
153
        hfsplus_write_treeinfo(tree, head);
154
        kunmap(page);
155
        set_page_dirty(page);
156
        hfsplus_put_bnode(node);
157
}
158
 
159
hfsplus_bnode *hfsplus_btree_alloc_node(hfsplus_btree *tree)
160
{
161
        hfsplus_bnode *node;
162
        struct page **pagep;
163
        u32 nidx;
164
        u16 idx, off, len;
165
        u8 *data, byte, m;
166
        int i;
167
 
168
        while (!tree->free_nodes) {
169
                loff_t size;
170
                int res;
171
 
172
                res = hfsplus_extend_file(tree->inode);
173
                if (res)
174
                        return ERR_PTR(res);
175
                HFSPLUS_I(tree->inode).total_blocks = HFSPLUS_I(tree->inode).alloc_blocks;
176
                size = HFSPLUS_I(tree->inode).total_blocks;
177
                size <<= tree->sb->s_blocksize_bits;
178
                tree->inode->i_size = size;
179
                do_div(size, (u32)tree->node_size);
180
                tree->free_nodes = (u32)size - tree->node_count;
181
                tree->node_count = size;
182
        }
183
 
184
        nidx = 0;
185
        node = hfsplus_find_bnode(tree, nidx);
186
        len = hfsplus_brec_lenoff(node, 2, &off);
187
 
188
        off += node->page_offset;
189
        pagep = node->page + (off >> PAGE_CACHE_SHIFT);
190
        data = hfsplus_kmap(*pagep);
191
        off &= ~PAGE_CACHE_MASK;
192
        idx = 0;
193
 
194
        for (;;) {
195
                while (len) {
196
                        byte = data[off];
197
                        if (byte != 0xff) {
198
                                for (m = 0x80, i = 0; i < 8; m >>= 1, i++) {
199
                                        if (!(byte & m)) {
200
                                                idx += i;
201
                                                data[off] |= m;
202
                                                set_page_dirty(*pagep);
203
                                                hfsplus_kunmap(*pagep);
204
                                                tree->free_nodes--;
205
                                                mark_inode_dirty(tree->inode);
206
                                                hfsplus_put_bnode(node);
207
                                                return hfsplus_create_bnode(tree, idx);
208
                                        }
209
                                }
210
                        }
211
                        if (++off >= PAGE_CACHE_SIZE) {
212
                                hfsplus_kunmap(*pagep++);
213
                                data = hfsplus_kmap(*pagep);
214
                                off = 0;
215
                        }
216
                        idx += 8;
217
                        len--;
218
                }
219
                nidx = node->next;
220
                hfsplus_put_bnode(node);
221
                if (!nidx) {
222
                        printk("need new bmap node...\n");
223
                        hfsplus_kunmap(*pagep);
224
                        return ERR_PTR(-ENOSPC);
225
                }
226
                node = hfsplus_find_bnode(tree, nidx);
227
                len = hfsplus_brec_lenoff(node, 0, &off);
228
 
229
                off += node->page_offset;
230
                pagep = node->page + (off >> PAGE_CACHE_SHIFT);
231
                data = hfsplus_kmap(*pagep);
232
                off &= ~PAGE_CACHE_MASK;
233
        }
234
}
235
 
236
void hfsplus_btree_remove_node(hfsplus_bnode *node)
237
{
238
        hfsplus_btree *tree;
239
        hfsplus_bnode *tmp;
240
        u32 cnid;
241
 
242
        tree = node->tree;
243
        if (node->prev) {
244
                tmp = hfsplus_find_bnode(tree, node->prev);
245
                tmp->next = node->next;
246
                cnid = cpu_to_be32(tmp->next);
247
                hfsplus_bnode_writebytes(tmp, &cnid, offsetof(hfsplus_btree_node_desc, next), 4);
248
                hfsplus_put_bnode(tmp);
249
        } else if (node->kind == HFSPLUS_NODE_LEAF)
250
                tree->leaf_head = node->next;
251
 
252
        if (node->next) {
253
                tmp = hfsplus_find_bnode(tree, node->next);
254
                tmp->prev = node->prev;
255
                cnid = cpu_to_be32(tmp->prev);
256
                hfsplus_bnode_writebytes(tmp, &cnid, offsetof(hfsplus_btree_node_desc, prev), 4);
257
                hfsplus_put_bnode(tmp);
258
        } else if (node->kind == HFSPLUS_NODE_LEAF)
259
                tree->leaf_tail = node->prev;
260
 
261
        // move down?
262
        if (!node->prev && !node->next) {
263
                printk("hfsplus_btree_del_level\n");
264
        }
265
        if (!node->parent) {
266
                tree->root = 0;
267
                tree->depth = 0;
268
        }
269
        set_bit(HFSPLUS_BNODE_DELETED, &node->flags);
270
}
271
 
272
void hfsplus_btree_free_node(hfsplus_bnode *node)
273
{
274
        hfsplus_btree *tree;
275
        struct page *page;
276
        u16 off, len;
277
        u32 nidx;
278
        u8 *data, byte, m;
279
 
280
        dprint(DBG_BNODE_MOD, "btree_free_node: %u\n", node->this);
281
        tree = node->tree;
282
        nidx = node->this;
283
        node = hfsplus_find_bnode(tree, 0);
284
        len = hfsplus_brec_lenoff(node, 2, &off);
285
        while (nidx >= len * 8) {
286
                u32 i;
287
 
288
                nidx -= len * 8;
289
                i = node->next;
290
                hfsplus_put_bnode(node);
291
                if (!nidx)
292
                        /* panic */;
293
                node = hfsplus_find_bnode(tree, nidx);
294
                if (node->kind != HFSPLUS_NODE_MAP)
295
                        /* panic */;
296
                len = hfsplus_brec_lenoff(node, 0, &off);
297
        }
298
        off += node->page_offset + nidx / 8;
299
        page = node->page[off >> PAGE_CACHE_SHIFT];
300
        data = hfsplus_kmap(page);
301
        off &= ~PAGE_CACHE_MASK;
302
        m = 1 << (~nidx & 7);
303
        byte = data[off];
304
        if (!(byte & m)) {
305
                BUG();
306
                /* panic */
307
                hfsplus_kunmap(page);
308
                hfsplus_put_bnode(node);
309
                return;
310
        }
311
        data[off] = byte & ~m;
312
        set_page_dirty(page);
313
        hfsplus_kunmap(page);
314
        hfsplus_put_bnode(node);
315
        tree->free_nodes++;
316
        mark_inode_dirty(tree->inode);
317
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.