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