The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/hfs/btree.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * linux/fs/hfs/btree.c
    3  *
    4  * Copyright (C) 1995-1997  Paul H. Hargrove
    5  * This file may be distributed under the terms of the GNU General Public License.
    6  *
    7  * This file contains the code to manipulate the B-tree structure.
    8  * The catalog and extents files are both B-trees.
    9  *
   10  * "XXX" in a comment is a note to myself to consider changing something.
   11  *
   12  * In function preconditions the term "valid" applied to a pointer to
   13  * a structure means that the pointer is non-NULL and the structure it
   14  * points to has all fields initialized to consistent values.
   15  *
   16  * The code in this file initializes some structures which contain
   17  * pointers by calling memset(&foo, 0, sizeof(foo)).
   18  * This produces the desired behavior only due to the non-ANSI
   19  * assumption that the machine representation of NULL is all zeros.
   20  */
   21 
   22 #include "hfs_btree.h"
   23 
   24 /*================ File-local functions ================*/
   25 
   26 /*
   27  * hfs_bnode_ditch() 
   28  *
   29  * Description:
   30  *   This function deletes an entire linked list of bnodes, so it
   31  *   does not need to keep the linked list consistent as
   32  *   hfs_bnode_delete() does.
   33  *   Called by hfs_btree_init() for error cleanup and by hfs_btree_free().
   34  * Input Variable(s):
   35  *   struct hfs_bnode *bn: pointer to the first (struct hfs_bnode) in
   36  *    the linked list to be deleted.
   37  * Output Variable(s):
   38  *   NONE
   39  * Returns:
   40  *   void
   41  * Preconditions:
   42  *   'bn' is NULL or points to a "valid" (struct hfs_bnode) with a 'prev'
   43  *    field of NULL.
   44  * Postconditions:
   45  *   'bn' and all (struct hfs_bnode)s in the chain of 'next' pointers
   46  *   are deleted, freeing the associated memory and hfs_buffer_put()ing
   47  *   the associated buffer.
   48  */
   49 static void hfs_bnode_ditch(struct hfs_bnode *bn) {
   50         struct hfs_bnode *tmp;
   51 #if defined(DEBUG_BNODES) || defined(DEBUG_ALL)
   52         extern int bnode_count;
   53 #endif
   54 
   55         while (bn != NULL) {
   56                 tmp = bn->next;
   57 #if defined(DEBUG_BNODES) || defined(DEBUG_ALL)
   58                 hfs_warn("deleting node %d from tree %d with count %d\n",
   59                          bn->node, (int)ntohl(bn->tree->entry.cnid), bn->count);
   60                 --bnode_count;
   61 #endif
   62                 hfs_buffer_put(bn->buf); /* safe: checks for NULL argument */
   63 
   64                 /* free all but the header */
   65                 if (bn->node) {
   66                         HFS_DELETE(bn);
   67                 }
   68                 bn = tmp;
   69         }
   70 }
   71 
   72 /*================ Global functions ================*/
   73 
   74 /*
   75  * hfs_btree_free()
   76  *
   77  * Description:
   78  *   This function frees a (struct hfs_btree) obtained from hfs_btree_init().
   79  *   Called by hfs_put_super().
   80  * Input Variable(s):
   81  *   struct hfs_btree *bt: pointer to the (struct hfs_btree) to free
   82  * Output Variable(s):
   83  *   NONE
   84  * Returns:
   85  *   void
   86  * Preconditions:
   87  *   'bt' is NULL or points to a "valid" (struct hfs_btree)
   88  * Postconditions:
   89  *   If 'bt' points to a "valid" (struct hfs_btree) then all (struct
   90  *    hfs_bnode)s associated with 'bt' are freed by calling
   91  *    hfs_bnode_ditch() and the memory associated with the (struct
   92  *    hfs_btree) is freed.
   93  *   If 'bt' is NULL or not "valid" an error is printed and nothing
   94  *    is changed.
   95  */
   96 void hfs_btree_free(struct hfs_btree *bt)
   97 {
   98         int lcv;
   99 
  100         if (bt && (bt->magic == HFS_BTREE_MAGIC)) {
  101                 hfs_extent_free(&bt->entry.u.file.data_fork);
  102 
  103                 for (lcv=0; lcv<HFS_CACHELEN; ++lcv) {
  104 #if defined(DEBUG_BNODES) || defined(DEBUG_ALL)
  105                         hfs_warn("deleting nodes from bucket %d:\n", lcv);
  106 #endif
  107                         hfs_bnode_ditch(bt->cache[lcv]);
  108                 }
  109 
  110 #if defined(DEBUG_BNODES) || defined(DEBUG_ALL)
  111                 hfs_warn("deleting header and bitmap nodes\n");
  112 #endif
  113                 hfs_bnode_ditch(&bt->head);
  114 
  115 #if defined(DEBUG_BNODES) || defined(DEBUG_ALL)
  116                 hfs_warn("deleting root node\n");
  117 #endif
  118                 hfs_bnode_ditch(bt->root);
  119 
  120                 HFS_DELETE(bt);
  121         } else if (bt) {
  122                 hfs_warn("hfs_btree_free: corrupted hfs_btree.\n");
  123         }
  124 }
  125 
  126 /*
  127  * hfs_btree_init()
  128  *
  129  * Description:
  130  *   Given some vital information from the MDB (HFS superblock),
  131  *   initializes the fields of a (struct hfs_btree).
  132  * Input Variable(s):
  133  *   struct hfs_mdb *mdb: pointer to the MDB
  134  *   ino_t cnid: the CNID (HFS_CAT_CNID or HFS_EXT_CNID) of the B-tree
  135  *   hfs_u32 tsize: the size, in bytes, of the B-tree
  136  *   hfs_u32 csize: the size, in bytes, of the clump size for the B-tree
  137  * Output Variable(s):
  138  *   NONE
  139  * Returns:
  140  *   (struct hfs_btree *): pointer to the initialized hfs_btree on success,
  141  *    or NULL on failure
  142  * Preconditions:
  143  *   'mdb' points to a "valid" (struct hfs_mdb)
  144  * Postconditions:
  145  *   Assuming the inputs are what they claim to be, no errors occur
  146  *   reading from disk, and no inconsistencies are noticed in the data
  147  *   read from disk, the return value is a pointer to a "valid"
  148  *   (struct hfs_btree).  If there are errors reading from disk or
  149  *   inconsistencies are noticed in the data read from disk, then and
  150  *   all resources that were allocated are released and NULL is
  151  *   returned.  If the inputs are not what they claim to be or if they
  152  *   are unnoticed inconsistencies in the data read from disk then the
  153  *   returned hfs_btree is probably going to lead to errors when it is
  154  *   used in a non-trivial way.
  155  */
  156 struct hfs_btree * hfs_btree_init(struct hfs_mdb *mdb, ino_t cnid,
  157                                   hfs_byte_t ext[12],
  158                                   hfs_u32 tsize, hfs_u32 csize)
  159 {
  160         struct hfs_btree * bt;
  161         struct BTHdrRec * th;
  162         struct hfs_bnode * tmp;
  163         unsigned int next;
  164 #if defined(DEBUG_HEADER) || defined(DEBUG_ALL)
  165         unsigned char *p, *q;
  166 #endif
  167 
  168         if (!mdb || !ext || !HFS_NEW(bt)) {
  169                 goto bail3;
  170         }
  171 
  172         bt->magic = HFS_BTREE_MAGIC;
  173         bt->sys_mdb = mdb->sys_mdb;
  174         bt->reserved = 0;
  175         bt->lock = 0;
  176         hfs_init_waitqueue(&bt->wait);
  177         bt->dirt = 0;
  178         memset(bt->cache, 0, sizeof(bt->cache));
  179 
  180 #if 0   /* this is a fake entry. so we don't need to initialize it. */
  181         memset(&bt->entry, 0, sizeof(bt->entry));
  182         hfs_init_waitqueue(&bt->entry.wait);
  183         INIT_LIST_HEAD(&bt->entry.hash);
  184         INIT_LIST_HEAD(&bt->entry.list);
  185 #endif
  186 
  187         bt->entry.mdb = mdb;
  188         bt->entry.cnid = cnid;
  189         bt->entry.type = HFS_CDR_FIL;
  190         bt->entry.u.file.magic = HFS_FILE_MAGIC;
  191         bt->entry.u.file.clumpablks = (csize / mdb->alloc_blksz)
  192                                                 >> HFS_SECTOR_SIZE_BITS;
  193         bt->entry.u.file.data_fork.entry = &bt->entry;
  194         bt->entry.u.file.data_fork.lsize = tsize;
  195         bt->entry.u.file.data_fork.psize = tsize >> HFS_SECTOR_SIZE_BITS;
  196         bt->entry.u.file.data_fork.fork = HFS_FK_DATA;
  197         hfs_extent_in(&bt->entry.u.file.data_fork, ext);
  198 
  199         hfs_bnode_read(&bt->head, bt, 0, HFS_STICKY);
  200         if (!hfs_buffer_ok(bt->head.buf)) {
  201                 goto bail2;
  202         }
  203         th = (struct BTHdrRec *)((char *)hfs_buffer_data(bt->head.buf) +
  204                                                 sizeof(struct NodeDescriptor));
  205 
  206         /* read in the bitmap nodes (if any) */
  207         tmp = &bt->head;
  208         while ((next = tmp->ndFLink)) {
  209                 if (!HFS_NEW(tmp->next)) {
  210                         goto bail2;
  211                 }
  212                 hfs_bnode_read(tmp->next, bt, next, HFS_STICKY);
  213                 if (!hfs_buffer_ok(tmp->next->buf)) {
  214                         goto bail2;
  215                 }
  216                 tmp->next->prev = tmp;
  217                 tmp = tmp->next;
  218         }
  219 
  220         if (hfs_get_ns(th->bthNodeSize) != htons(HFS_SECTOR_SIZE)) {
  221                 hfs_warn("hfs_btree_init: bthNodeSize!=512 not supported\n");
  222                 goto bail2;
  223         }
  224 
  225         if (cnid == htonl(HFS_CAT_CNID)) {
  226                 bt->compare = (hfs_cmpfn)hfs_cat_compare;
  227         } else if (cnid == htonl(HFS_EXT_CNID)) {
  228                 bt->compare = (hfs_cmpfn)hfs_ext_compare;
  229         } else {
  230                 goto bail2;
  231         }
  232         bt->bthDepth  = hfs_get_hs(th->bthDepth);
  233         bt->bthRoot   = hfs_get_hl(th->bthRoot);
  234         bt->bthNRecs  = hfs_get_hl(th->bthNRecs);
  235         bt->bthFNode  = hfs_get_hl(th->bthFNode);
  236         bt->bthLNode  = hfs_get_hl(th->bthLNode);
  237         bt->bthNNodes = hfs_get_hl(th->bthNNodes);
  238         bt->bthFree   = hfs_get_hl(th->bthFree);
  239         bt->bthKeyLen = hfs_get_hs(th->bthKeyLen);
  240 
  241 #if defined(DEBUG_HEADER) || defined(DEBUG_ALL)
  242         hfs_warn("bthDepth %d\n", bt->bthDepth);
  243         hfs_warn("bthRoot %d\n", bt->bthRoot);
  244         hfs_warn("bthNRecs %d\n", bt->bthNRecs);
  245         hfs_warn("bthFNode %d\n", bt->bthFNode);
  246         hfs_warn("bthLNode %d\n", bt->bthLNode);
  247         hfs_warn("bthKeyLen %d\n", bt->bthKeyLen);
  248         hfs_warn("bthNNodes %d\n", bt->bthNNodes);
  249         hfs_warn("bthFree %d\n", bt->bthFree);
  250         p = (unsigned char *)hfs_buffer_data(bt->head.buf);
  251         q = p + HFS_SECTOR_SIZE;
  252         while (p < q) {
  253                 hfs_warn("%02x %02x %02x %02x %02x %02x %02x %02x "
  254                          "%02x %02x %02x %02x %02x %02x %02x %02x\n",
  255                          *p++, *p++, *p++, *p++, *p++, *p++, *p++, *p++,
  256                          *p++, *p++, *p++, *p++, *p++, *p++, *p++, *p++);
  257         }
  258 #endif
  259 
  260         /* Read in the root if it exists.
  261            The header always exists, but the root exists only if the
  262            tree is non-empty */
  263         if (bt->bthDepth && bt->bthRoot) {
  264                 if (!HFS_NEW(bt->root)) {
  265                         goto bail2;
  266                 }
  267                 hfs_bnode_read(bt->root, bt, bt->bthRoot, HFS_STICKY);
  268                 if (!hfs_buffer_ok(bt->root->buf)) {
  269                         goto bail1;
  270                 }
  271         } else {
  272                 bt->root = NULL;
  273         }
  274 
  275         return bt;
  276 
  277  bail1:
  278         hfs_bnode_ditch(bt->root);
  279  bail2:
  280         hfs_bnode_ditch(&bt->head);
  281         HFS_DELETE(bt);
  282  bail3:
  283         return NULL;
  284 }
  285 
  286 /*
  287  * hfs_btree_commit()
  288  *
  289  * Called to write a possibly dirty btree back to disk.
  290  */
  291 void hfs_btree_commit(struct hfs_btree *bt, hfs_byte_t ext[12], hfs_lword_t size)
  292 {
  293         if (bt->dirt) {
  294                 struct BTHdrRec *th;
  295                 th = (struct BTHdrRec *)((char *)hfs_buffer_data(bt->head.buf) +
  296                                                  sizeof(struct NodeDescriptor));
  297 
  298                 hfs_put_hs(bt->bthDepth,  th->bthDepth);
  299                 hfs_put_hl(bt->bthRoot,   th->bthRoot);
  300                 hfs_put_hl(bt->bthNRecs,  th->bthNRecs);
  301                 hfs_put_hl(bt->bthFNode,  th->bthFNode);
  302                 hfs_put_hl(bt->bthLNode,  th->bthLNode);
  303                 hfs_put_hl(bt->bthNNodes, th->bthNNodes);
  304                 hfs_put_hl(bt->bthFree,   th->bthFree);
  305                 hfs_buffer_dirty(bt->head.buf);
  306 
  307                 /*
  308                  * Commit the bnodes which are not cached.
  309                  * The map nodes don't need to be committed here because
  310                  * they are committed every time they are changed.
  311                  */
  312                 hfs_bnode_commit(&bt->head);
  313                 if (bt->root) {
  314                         hfs_bnode_commit(bt->root);
  315                 }
  316 
  317         
  318                 hfs_put_hl(bt->bthNNodes << HFS_SECTOR_SIZE_BITS, size);
  319                 hfs_extent_out(&bt->entry.u.file.data_fork, ext);
  320                 /* hfs_buffer_dirty(mdb->buf); (Done by caller) */
  321 
  322                 bt->dirt = 0;
  323         }
  324 }

Cache object: b0aa55f0c7cb922ea74caedee1865336


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.