linux/fs/hfsplus/btree.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 *  linux/fs/hfsplus/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/slab.h>
  13#include <linux/pagemap.h>
  14#include <linux/log2.h>
  15
  16#include "hfsplus_fs.h"
  17#include "hfsplus_raw.h"
  18
  19/*
  20 * Initial source code of clump size calculation is gotten
  21 * from http://opensource.apple.com/tarballs/diskdev_cmds/
  22 */
  23#define CLUMP_ENTRIES   15
  24
  25static short clumptbl[CLUMP_ENTRIES * 3] = {
  26/*
  27 *          Volume      Attributes       Catalog         Extents
  28 *           Size       Clump (MB)      Clump (MB)      Clump (MB)
  29 */
  30        /*   1GB */       4,              4,             4,
  31        /*   2GB */       6,              6,             4,
  32        /*   4GB */       8,              8,             4,
  33        /*   8GB */      11,             11,             5,
  34        /*
  35         * For volumes 16GB and larger, we want to make sure that a full OS
  36         * install won't require fragmentation of the Catalog or Attributes
  37         * B-trees.  We do this by making the clump sizes sufficiently large,
  38         * and by leaving a gap after the B-trees for them to grow into.
  39         *
  40         * For SnowLeopard 10A298, a FullNetInstall with all packages selected
  41         * results in:
  42         * Catalog B-tree Header
  43         *      nodeSize:          8192
  44         *      totalNodes:       31616
  45         *      freeNodes:         1978
  46         * (used = 231.55 MB)
  47         * Attributes B-tree Header
  48         *      nodeSize:          8192
  49         *      totalNodes:       63232
  50         *      freeNodes:          958
  51         * (used = 486.52 MB)
  52         *
  53         * We also want Time Machine backup volumes to have a sufficiently
  54         * large clump size to reduce fragmentation.
  55         *
  56         * The series of numbers for Catalog and Attribute form a geometric
  57         * series. For Catalog (16GB to 512GB), each term is 8**(1/5) times
  58         * the previous term.  For Attributes (16GB to 512GB), each term is
  59         * 4**(1/5) times the previous term.  For 1TB to 16TB, each term is
  60         * 2**(1/5) times the previous term.
  61         */
  62        /*  16GB */      64,             32,             5,
  63        /*  32GB */      84,             49,             6,
  64        /*  64GB */     111,             74,             7,
  65        /* 128GB */     147,            111,             8,
  66        /* 256GB */     194,            169,             9,
  67        /* 512GB */     256,            256,            11,
  68        /*   1TB */     294,            294,            14,
  69        /*   2TB */     338,            338,            16,
  70        /*   4TB */     388,            388,            20,
  71        /*   8TB */     446,            446,            25,
  72        /*  16TB */     512,            512,            32
  73};
  74
  75u32 hfsplus_calc_btree_clump_size(u32 block_size, u32 node_size,
  76                                        u64 sectors, int file_id)
  77{
  78        u32 mod = max(node_size, block_size);
  79        u32 clump_size;
  80        int column;
  81        int i;
  82
  83        /* Figure out which column of the above table to use for this file. */
  84        switch (file_id) {
  85        case HFSPLUS_ATTR_CNID:
  86                column = 0;
  87                break;
  88        case HFSPLUS_CAT_CNID:
  89                column = 1;
  90                break;
  91        default:
  92                column = 2;
  93                break;
  94        }
  95
  96        /*
  97         * The default clump size is 0.8% of the volume size. And
  98         * it must also be a multiple of the node and block size.
  99         */
 100        if (sectors < 0x200000) {
 101                clump_size = sectors << 2;      /*  0.8 %  */
 102                if (clump_size < (8 * node_size))
 103                        clump_size = 8 * node_size;
 104        } else {
 105                /* turn exponent into table index... */
 106                for (i = 0, sectors = sectors >> 22;
 107                     sectors && (i < CLUMP_ENTRIES - 1);
 108                     ++i, sectors = sectors >> 1) {
 109                        /* empty body */
 110                }
 111
 112                clump_size = clumptbl[column + (i) * 3] * 1024 * 1024;
 113        }
 114
 115        /*
 116         * Round the clump size to a multiple of node and block size.
 117         * NOTE: This rounds down.
 118         */
 119        clump_size /= mod;
 120        clump_size *= mod;
 121
 122        /*
 123         * Rounding down could have rounded down to 0 if the block size was
 124         * greater than the clump size.  If so, just use one block or node.
 125         */
 126        if (clump_size == 0)
 127                clump_size = mod;
 128
 129        return clump_size;
 130}
 131
 132/* Get a reference to a B*Tree and do some initial checks */
 133struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
 134{
 135        struct hfs_btree *tree;
 136        struct hfs_btree_header_rec *head;
 137        struct address_space *mapping;
 138        struct inode *inode;
 139        struct page *page;
 140        unsigned int size;
 141
 142        tree = kzalloc(sizeof(*tree), GFP_KERNEL);
 143        if (!tree)
 144                return NULL;
 145
 146        mutex_init(&tree->tree_lock);
 147        spin_lock_init(&tree->hash_lock);
 148        tree->sb = sb;
 149        tree->cnid = id;
 150        inode = hfsplus_iget(sb, id);
 151        if (IS_ERR(inode))
 152                goto free_tree;
 153        tree->inode = inode;
 154
 155        if (!HFSPLUS_I(tree->inode)->first_blocks) {
 156                pr_err("invalid btree extent records (0 size)\n");
 157                goto free_inode;
 158        }
 159
 160        mapping = tree->inode->i_mapping;
 161        page = read_mapping_page(mapping, 0, NULL);
 162        if (IS_ERR(page))
 163                goto free_inode;
 164
 165        /* Load the header */
 166        head = (struct hfs_btree_header_rec *)(kmap(page) +
 167                sizeof(struct hfs_bnode_desc));
 168        tree->root = be32_to_cpu(head->root);
 169        tree->leaf_count = be32_to_cpu(head->leaf_count);
 170        tree->leaf_head = be32_to_cpu(head->leaf_head);
 171        tree->leaf_tail = be32_to_cpu(head->leaf_tail);
 172        tree->node_count = be32_to_cpu(head->node_count);
 173        tree->free_nodes = be32_to_cpu(head->free_nodes);
 174        tree->attributes = be32_to_cpu(head->attributes);
 175        tree->node_size = be16_to_cpu(head->node_size);
 176        tree->max_key_len = be16_to_cpu(head->max_key_len);
 177        tree->depth = be16_to_cpu(head->depth);
 178
 179        /* Verify the tree and set the correct compare function */
 180        switch (id) {
 181        case HFSPLUS_EXT_CNID:
 182                if (tree->max_key_len != HFSPLUS_EXT_KEYLEN - sizeof(u16)) {
 183                        pr_err("invalid extent max_key_len %d\n",
 184                                tree->max_key_len);
 185                        goto fail_page;
 186                }
 187                if (tree->attributes & HFS_TREE_VARIDXKEYS) {
 188                        pr_err("invalid extent btree flag\n");
 189                        goto fail_page;
 190                }
 191
 192                tree->keycmp = hfsplus_ext_cmp_key;
 193                break;
 194        case HFSPLUS_CAT_CNID:
 195                if (tree->max_key_len != HFSPLUS_CAT_KEYLEN - sizeof(u16)) {
 196                        pr_err("invalid catalog max_key_len %d\n",
 197                                tree->max_key_len);
 198                        goto fail_page;
 199                }
 200                if (!(tree->attributes & HFS_TREE_VARIDXKEYS)) {
 201                        pr_err("invalid catalog btree flag\n");
 202                        goto fail_page;
 203                }
 204
 205                if (test_bit(HFSPLUS_SB_HFSX, &HFSPLUS_SB(sb)->flags) &&
 206                    (head->key_type == HFSPLUS_KEY_BINARY))
 207                        tree->keycmp = hfsplus_cat_bin_cmp_key;
 208                else {
 209                        tree->keycmp = hfsplus_cat_case_cmp_key;
 210                        set_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags);
 211                }
 212                break;
 213        case HFSPLUS_ATTR_CNID:
 214                if (tree->max_key_len != HFSPLUS_ATTR_KEYLEN - sizeof(u16)) {
 215                        pr_err("invalid attributes max_key_len %d\n",
 216                                tree->max_key_len);
 217                        goto fail_page;
 218                }
 219                tree->keycmp = hfsplus_attr_bin_cmp_key;
 220                break;
 221        default:
 222                pr_err("unknown B*Tree requested\n");
 223                goto fail_page;
 224        }
 225
 226        if (!(tree->attributes & HFS_TREE_BIGKEYS)) {
 227                pr_err("invalid btree flag\n");
 228                goto fail_page;
 229        }
 230
 231        size = tree->node_size;
 232        if (!is_power_of_2(size))
 233                goto fail_page;
 234        if (!tree->node_count)
 235                goto fail_page;
 236
 237        tree->node_size_shift = ffs(size) - 1;
 238
 239        tree->pages_per_bnode =
 240                (tree->node_size + PAGE_SIZE - 1) >>
 241                PAGE_SHIFT;
 242
 243        kunmap(page);
 244        put_page(page);
 245        return tree;
 246
 247 fail_page:
 248        put_page(page);
 249 free_inode:
 250        tree->inode->i_mapping->a_ops = &hfsplus_aops;
 251        iput(tree->inode);
 252 free_tree:
 253        kfree(tree);
 254        return NULL;
 255}
 256
 257/* Release resources used by a btree */
 258void hfs_btree_close(struct hfs_btree *tree)
 259{
 260        struct hfs_bnode *node;
 261        int i;
 262
 263        if (!tree)
 264                return;
 265
 266        for (i = 0; i < NODE_HASH_SIZE; i++) {
 267                while ((node = tree->node_hash[i])) {
 268                        tree->node_hash[i] = node->next_hash;
 269                        if (atomic_read(&node->refcnt))
 270                                pr_crit("node %d:%d "
 271                                                "still has %d user(s)!\n",
 272                                        node->tree->cnid, node->this,
 273                                        atomic_read(&node->refcnt));
 274                        hfs_bnode_free(node);
 275                        tree->node_hash_cnt--;
 276                }
 277        }
 278        iput(tree->inode);
 279        kfree(tree);
 280}
 281
 282int hfs_btree_write(struct hfs_btree *tree)
 283{
 284        struct hfs_btree_header_rec *head;
 285        struct hfs_bnode *node;
 286        struct page *page;
 287
 288        node = hfs_bnode_find(tree, 0);
 289        if (IS_ERR(node))
 290                /* panic? */
 291                return -EIO;
 292        /* Load the header */
 293        page = node->page[0];
 294        head = (struct hfs_btree_header_rec *)(kmap(page) +
 295                sizeof(struct hfs_bnode_desc));
 296
 297        head->root = cpu_to_be32(tree->root);
 298        head->leaf_count = cpu_to_be32(tree->leaf_count);
 299        head->leaf_head = cpu_to_be32(tree->leaf_head);
 300        head->leaf_tail = cpu_to_be32(tree->leaf_tail);
 301        head->node_count = cpu_to_be32(tree->node_count);
 302        head->free_nodes = cpu_to_be32(tree->free_nodes);
 303        head->attributes = cpu_to_be32(tree->attributes);
 304        head->depth = cpu_to_be16(tree->depth);
 305
 306        kunmap(page);
 307        set_page_dirty(page);
 308        hfs_bnode_put(node);
 309        return 0;
 310}
 311
 312static struct hfs_bnode *hfs_bmap_new_bmap(struct hfs_bnode *prev, u32 idx)
 313{
 314        struct hfs_btree *tree = prev->tree;
 315        struct hfs_bnode *node;
 316        struct hfs_bnode_desc desc;
 317        __be32 cnid;
 318
 319        node = hfs_bnode_create(tree, idx);
 320        if (IS_ERR(node))
 321                return node;
 322
 323        tree->free_nodes--;
 324        prev->next = idx;
 325        cnid = cpu_to_be32(idx);
 326        hfs_bnode_write(prev, &cnid, offsetof(struct hfs_bnode_desc, next), 4);
 327
 328        node->type = HFS_NODE_MAP;
 329        node->num_recs = 1;
 330        hfs_bnode_clear(node, 0, tree->node_size);
 331        desc.next = 0;
 332        desc.prev = 0;
 333        desc.type = HFS_NODE_MAP;
 334        desc.height = 0;
 335        desc.num_recs = cpu_to_be16(1);
 336        desc.reserved = 0;
 337        hfs_bnode_write(node, &desc, 0, sizeof(desc));
 338        hfs_bnode_write_u16(node, 14, 0x8000);
 339        hfs_bnode_write_u16(node, tree->node_size - 2, 14);
 340        hfs_bnode_write_u16(node, tree->node_size - 4, tree->node_size - 6);
 341
 342        return node;
 343}
 344
 345/* Make sure @tree has enough space for the @rsvd_nodes */
 346int hfs_bmap_reserve(struct hfs_btree *tree, int rsvd_nodes)
 347{
 348        struct inode *inode = tree->inode;
 349        struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
 350        u32 count;
 351        int res;
 352
 353        if (rsvd_nodes <= 0)
 354                return 0;
 355
 356        while (tree->free_nodes < rsvd_nodes) {
 357                res = hfsplus_file_extend(inode, hfs_bnode_need_zeroout(tree));
 358                if (res)
 359                        return res;
 360                hip->phys_size = inode->i_size =
 361                        (loff_t)hip->alloc_blocks <<
 362                                HFSPLUS_SB(tree->sb)->alloc_blksz_shift;
 363                hip->fs_blocks =
 364                        hip->alloc_blocks << HFSPLUS_SB(tree->sb)->fs_shift;
 365                inode_set_bytes(inode, inode->i_size);
 366                count = inode->i_size >> tree->node_size_shift;
 367                tree->free_nodes += count - tree->node_count;
 368                tree->node_count = count;
 369        }
 370        return 0;
 371}
 372
 373struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree)
 374{
 375        struct hfs_bnode *node, *next_node;
 376        struct page **pagep;
 377        u32 nidx, idx;
 378        unsigned off;
 379        u16 off16;
 380        u16 len;
 381        u8 *data, byte, m;
 382        int i, res;
 383
 384        res = hfs_bmap_reserve(tree, 1);
 385        if (res)
 386                return ERR_PTR(res);
 387
 388        nidx = 0;
 389        node = hfs_bnode_find(tree, nidx);
 390        if (IS_ERR(node))
 391                return node;
 392        len = hfs_brec_lenoff(node, 2, &off16);
 393        off = off16;
 394
 395        off += node->page_offset;
 396        pagep = node->page + (off >> PAGE_SHIFT);
 397        data = kmap(*pagep);
 398        off &= ~PAGE_MASK;
 399        idx = 0;
 400
 401        for (;;) {
 402                while (len) {
 403                        byte = data[off];
 404                        if (byte != 0xff) {
 405                                for (m = 0x80, i = 0; i < 8; m >>= 1, i++) {
 406                                        if (!(byte & m)) {
 407                                                idx += i;
 408                                                data[off] |= m;
 409                                                set_page_dirty(*pagep);
 410                                                kunmap(*pagep);
 411                                                tree->free_nodes--;
 412                                                mark_inode_dirty(tree->inode);
 413                                                hfs_bnode_put(node);
 414                                                return hfs_bnode_create(tree,
 415                                                        idx);
 416                                        }
 417                                }
 418                        }
 419                        if (++off >= PAGE_SIZE) {
 420                                kunmap(*pagep);
 421                                data = kmap(*++pagep);
 422                                off = 0;
 423                        }
 424                        idx += 8;
 425                        len--;
 426                }
 427                kunmap(*pagep);
 428                nidx = node->next;
 429                if (!nidx) {
 430                        hfs_dbg(BNODE_MOD, "create new bmap node\n");
 431                        next_node = hfs_bmap_new_bmap(node, idx);
 432                } else
 433                        next_node = hfs_bnode_find(tree, nidx);
 434                hfs_bnode_put(node);
 435                if (IS_ERR(next_node))
 436                        return next_node;
 437                node = next_node;
 438
 439                len = hfs_brec_lenoff(node, 0, &off16);
 440                off = off16;
 441                off += node->page_offset;
 442                pagep = node->page + (off >> PAGE_SHIFT);
 443                data = kmap(*pagep);
 444                off &= ~PAGE_MASK;
 445        }
 446}
 447
 448void hfs_bmap_free(struct hfs_bnode *node)
 449{
 450        struct hfs_btree *tree;
 451        struct page *page;
 452        u16 off, len;
 453        u32 nidx;
 454        u8 *data, byte, m;
 455
 456        hfs_dbg(BNODE_MOD, "btree_free_node: %u\n", node->this);
 457        BUG_ON(!node->this);
 458        tree = node->tree;
 459        nidx = node->this;
 460        node = hfs_bnode_find(tree, 0);
 461        if (IS_ERR(node))
 462                return;
 463        len = hfs_brec_lenoff(node, 2, &off);
 464        while (nidx >= len * 8) {
 465                u32 i;
 466
 467                nidx -= len * 8;
 468                i = node->next;
 469                if (!i) {
 470                        /* panic */;
 471                        pr_crit("unable to free bnode %u. "
 472                                        "bmap not found!\n",
 473                                node->this);
 474                        hfs_bnode_put(node);
 475                        return;
 476                }
 477                hfs_bnode_put(node);
 478                node = hfs_bnode_find(tree, i);
 479                if (IS_ERR(node))
 480                        return;
 481                if (node->type != HFS_NODE_MAP) {
 482                        /* panic */;
 483                        pr_crit("invalid bmap found! "
 484                                        "(%u,%d)\n",
 485                                node->this, node->type);
 486                        hfs_bnode_put(node);
 487                        return;
 488                }
 489                len = hfs_brec_lenoff(node, 0, &off);
 490        }
 491        off += node->page_offset + nidx / 8;
 492        page = node->page[off >> PAGE_SHIFT];
 493        data = kmap(page);
 494        off &= ~PAGE_MASK;
 495        m = 1 << (~nidx & 7);
 496        byte = data[off];
 497        if (!(byte & m)) {
 498                pr_crit("trying to free free bnode "
 499                                "%u(%d)\n",
 500                        node->this, node->type);
 501                kunmap(page);
 502                hfs_bnode_put(node);
 503                return;
 504        }
 505        data[off] = byte & ~m;
 506        set_page_dirty(page);
 507        kunmap(page);
 508        hfs_bnode_put(node);
 509        tree->free_nodes++;
 510        mark_inode_dirty(tree->inode);
 511}
 512