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