balloc.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:12k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * linux/fs/hfs/balloc.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.  * hfs_bnode_alloc() and hfs_bnode_bitop() are based on GPLed code
  8.  * Copyright (C) 1995  Michael Dreher
  9.  *
  10.  * This file contains the code to create and destroy nodes
  11.  * in the B-tree structure.
  12.  *
  13.  * "XXX" in a comment is a note to myself to consider changing something.
  14.  *
  15.  * In function preconditions the term "valid" applied to a pointer to
  16.  * a structure means that the pointer is non-NULL and the structure it
  17.  * points to has all fields initialized to consistent values.
  18.  *
  19.  * The code in this file initializes some structures which contain
  20.  * pointers by calling memset(&foo, 0, sizeof(foo)).
  21.  * This produces the desired behavior only due to the non-ANSI
  22.  * assumption that the machine representation of NULL is all zeros.
  23.  */
  24. #include "hfs_btree.h"
  25. /*================ File-local functions ================*/
  26. /*
  27.  * get_new_node()
  28.  *
  29.  * Get a buffer for a new node with out reading it from disk.
  30.  */
  31. static hfs_buffer get_new_node(struct hfs_btree *tree, hfs_u32 node)
  32. {
  33. int tmp;
  34. hfs_buffer retval = HFS_BAD_BUFFER;
  35.    tmp = hfs_extent_map(&tree->entry.u.file.data_fork, node, 0);
  36. if (tmp) {
  37. retval = hfs_buffer_get(tree->sys_mdb, tmp, 0);
  38. }
  39. return retval;
  40. }
  41. /*
  42.  * hfs_bnode_init()
  43.  *
  44.  * Description:
  45.  *   Initialize a newly allocated bnode.
  46.  * Input Variable(s):
  47.  *   struct hfs_btree *tree: Pointer to a B-tree
  48.  *   hfs_u32 node: the node number to allocate
  49.  * Output Variable(s):
  50.  *   NONE
  51.  * Returns:
  52.  *   struct hfs_bnode_ref for the new node
  53.  * Preconditions:
  54.  *   'tree' points to a "valid" (struct hfs_btree)
  55.  *   'node' exists and has been allocated in the bitmap of bnodes.
  56.  * Postconditions:
  57.  *   On success:
  58.  *    The node is not read from disk, nor added to the bnode cache.
  59.  *    The 'sticky' and locking-related fields are all zero/NULL.
  60.  *    The bnode's nd{[FB]Link, Type, NHeight} fields are uninitialized.
  61.  *    The bnode's ndNRecs field and offsets table indicate an empty bnode.
  62.  *   On failure:
  63.  *    The node is deallocated.
  64.  */
  65. static struct hfs_bnode_ref hfs_bnode_init(struct hfs_btree * tree,
  66.    hfs_u32 node)
  67. {
  68. #if defined(DEBUG_BNODES) || defined(DEBUG_ALL)
  69. extern int bnode_count;
  70. #endif
  71. struct hfs_bnode_ref retval;
  72. retval.lock_type = HFS_LOCK_NONE;
  73. if (!HFS_NEW(retval.bn)) {
  74. hfs_warn("hfs_bnode_init: out of memory.n");
  75. goto bail2;
  76. }
  77. /* Partially initialize the in-core structure */
  78. memset(retval.bn, 0, sizeof(*retval.bn));
  79. retval.bn->magic = HFS_BNODE_MAGIC;
  80. retval.bn->tree = tree;
  81. retval.bn->node = node;
  82. hfs_init_waitqueue(&retval.bn->wqueue);
  83. hfs_init_waitqueue(&retval.bn->rqueue);
  84. hfs_bnode_lock(&retval, HFS_LOCK_WRITE);
  85. retval.bn->buf = get_new_node(tree, node);
  86. if (!hfs_buffer_ok(retval.bn->buf)) {
  87. goto bail1;
  88. }
  89. #if defined(DEBUG_BNODES) || defined(DEBUG_ALL)
  90. ++bnode_count;
  91. #endif
  92. /* Partially initialize the on-disk structure */
  93. memset(hfs_buffer_data(retval.bn->buf), 0, HFS_SECTOR_SIZE);
  94. hfs_put_hs(sizeof(struct NodeDescriptor), RECTBL(retval.bn, 1));
  95. return retval;
  96. bail1:
  97. HFS_DELETE(retval.bn);
  98. bail2:
  99. /* clear the bit in the bitmap */
  100. hfs_bnode_bitop(tree, node, 0);
  101. return retval;
  102. }
  103. /*
  104.  * init_mapnode()
  105.  *
  106.  * Description:
  107.  *   Initializes a given node as a mapnode in the given tree.
  108.  * Input Variable(s):
  109.  *   struct hfs_bnode *bn: the node to add the mapnode after.
  110.  *   hfs_u32: the node to use as a mapnode.
  111.  * Output Variable(s):
  112.  *   NONE
  113.  * Returns:
  114.  *   struct hfs_bnode *: the new mapnode or NULL
  115.  * Preconditions:
  116.  *   'tree' is a valid (struct hfs_btree).
  117.  *   'node' is the number of the first node in 'tree' that is not
  118.  *    represented by a bit in the existing mapnodes.
  119.  * Postconditions:
  120.  *   On failure 'tree' is unchanged and NULL is returned.
  121.  *   On success the node given by 'node' has been added to the linked
  122.  *    list of mapnodes attached to 'tree', and has been initialized as
  123.  *    a valid mapnode with its first bit set to indicate itself as
  124.  *    allocated.
  125.  */
  126. static struct hfs_bnode *init_mapnode(struct hfs_bnode *bn, hfs_u32 node)
  127. {
  128. #if defined(DEBUG_BNODES) || defined(DEBUG_ALL)
  129. extern int bnode_count;
  130. #endif
  131. struct hfs_bnode *retval;
  132. if (!HFS_NEW(retval)) {
  133. hfs_warn("hfs_bnode_add: out of memory.n");
  134. return NULL;
  135. }
  136. memset(retval, 0, sizeof(*retval));
  137. retval->magic = HFS_BNODE_MAGIC;
  138. retval->tree = bn->tree;
  139. retval->node = node;
  140. retval->sticky = HFS_STICKY;
  141. retval->buf = get_new_node(bn->tree, node);
  142. if (!hfs_buffer_ok(retval->buf)) {
  143. HFS_DELETE(retval);
  144. return NULL;
  145. }
  146. #if defined(DEBUG_BNODES) || defined(DEBUG_ALL)
  147. ++bnode_count;
  148. #endif
  149. /* Initialize the bnode data structure */
  150. memset(hfs_buffer_data(retval->buf), 0, HFS_SECTOR_SIZE);
  151. retval->ndFLink = 0;
  152. retval->ndBLink = bn->node;
  153. retval->ndType = ndMapNode;
  154. retval->ndNHeight = 0;
  155. retval->ndNRecs = 1;
  156. hfs_put_hs(sizeof(struct NodeDescriptor), RECTBL(retval, 1));
  157. hfs_put_hs(0x1fa,                         RECTBL(retval, 2));
  158. *((hfs_u8 *)bnode_key(retval, 1)) = 0x80; /* set first bit of bitmap */
  159. retval->prev = bn;
  160. hfs_bnode_commit(retval);
  161. bn->ndFLink = node;
  162. bn->next = retval;
  163. hfs_bnode_commit(bn);
  164. return retval;
  165. }
  166. /*================ Global functions ================*/
  167. /*
  168.  * hfs_bnode_bitop()
  169.  *
  170.  * Description:
  171.  *   Allocate/free the requested node of a B-tree of the hfs filesystem
  172.  *   by setting/clearing the corresponding bit in the B-tree bitmap.
  173.  *   The size of the B-tree will not be changed.
  174.  * Input Variable(s):
  175.  *   struct hfs_btree *tree: Pointer to a B-tree
  176.  *   hfs_u32 bitnr: The node number to free
  177.  *   int set: 0 to clear the bit, non-zero to set it.
  178.  * Output Variable(s):
  179.  *   None
  180.  * Returns:
  181.  *    0: no error
  182.  *   -1: The node was already allocated/free, nothing has been done.
  183.  *   -2: The node is out of range of the B-tree.
  184.  *   -4: not enough map nodes to hold all the bits
  185.  * Preconditions:
  186.  *   'tree' points to a "valid" (struct hfs_btree)
  187.  *   'bitnr' is a node number within the range of the btree, which is
  188.  *   currently free/allocated.
  189.  * Postconditions:
  190.  *   The bit number 'bitnr' of the node bitmap is set/cleared and the
  191.  *   number of free nodes in the btree is decremented/incremented by one.
  192.  */
  193. int hfs_bnode_bitop(struct hfs_btree *tree, hfs_u32 bitnr, int set)
  194. {
  195. struct hfs_bnode *bn;   /* the current bnode */
  196. hfs_u16 start; /* the start (in bits) of the bitmap in node */
  197. hfs_u16 len; /* the len (in bits) of the bitmap in node */
  198. hfs_u32 *u32; /* address of the u32 containing the bit */
  199. if (bitnr >= tree->bthNNodes) {
  200. hfs_warn("hfs_bnode_bitop: node number out of range.n");
  201. return -2;
  202. }
  203. bn = &tree->head;
  204. for (;;) {
  205. start = bnode_offset(bn, bn->ndNRecs) << 3;
  206. len = (bnode_offset(bn, bn->ndNRecs + 1) << 3) - start;
  207. if (bitnr < len) {
  208. break;
  209. }
  210. /* continue on to next map node if available */
  211. if (!(bn = bn->next)) {
  212. hfs_warn("hfs_bnode_bitop: too few map nodes.n");
  213. return -4;
  214. }
  215. bitnr -= len;
  216. }
  217. /* Change the correct bit */
  218. bitnr += start;
  219. u32 = (hfs_u32 *)hfs_buffer_data(bn->buf) + (bitnr >> 5);
  220. bitnr %= 32;
  221. if ((set && hfs_set_bit(bitnr, u32)) ||
  222.     (!set && !hfs_clear_bit(bitnr, u32))) {
  223. hfs_warn("hfs_bnode_bitop: bitmap corruption.n");
  224. return -1;
  225. }
  226. hfs_buffer_dirty(bn->buf);
  227. /* adjust the free count */
  228. tree->bthFree += (set ? -1 : 1);
  229. tree->dirt = 1;
  230. return 0;
  231. }
  232. /*
  233.  * hfs_bnode_alloc()
  234.  *
  235.  * Description:
  236.  *   Find a cleared bit in the B-tree node bitmap of the hfs filesystem,
  237.  *   set it and return the corresponding bnode, with its contents zeroed.
  238.  *   When there is no free bnode in the tree, an error is returned, no
  239.  *   new nodes will be added by this function!
  240.  * Input Variable(s):
  241.  *   struct hfs_btree *tree: Pointer to a B-tree
  242.  * Output Variable(s):
  243.  *   NONE
  244.  * Returns:
  245.  *   struct hfs_bnode_ref for the new bnode
  246.  * Preconditions:
  247.  *   'tree' points to a "valid" (struct hfs_btree)
  248.  *   There is at least one free bnode.
  249.  * Postconditions:
  250.  *   On success:
  251.  *     The corresponding bit in the btree bitmap is set.
  252.  *     The number of free nodes in the btree is decremented by one.
  253.  *   The node is not read from disk, nor added to the bnode cache.
  254.  *   The 'sticky' field is uninitialized.
  255.  */
  256. struct hfs_bnode_ref hfs_bnode_alloc(struct hfs_btree *tree)
  257. {
  258. struct hfs_bnode *bn;   /* the current bnode */
  259. hfs_u32 bitnr = 0; /* which bit are we examining */
  260. hfs_u16 first; /* the first clear bit in this bnode */
  261. hfs_u16 start; /* the start (in bits) of the bitmap in node */
  262. hfs_u16 end; /* the end (in bits) of the bitmap in node */
  263. hfs_u32 *data; /* address of the data in this bnode */
  264. bn = &tree->head;
  265. for (;;) {
  266. start = bnode_offset(bn, bn->ndNRecs) << 3;
  267. end = bnode_offset(bn, bn->ndNRecs + 1) << 3;
  268. data =  (hfs_u32 *)hfs_buffer_data(bn->buf);
  269. /* search the current node */
  270. first = hfs_find_zero_bit(data, end, start);
  271. if (first < end) {
  272. break;
  273. }
  274. /* continue search in next map node */
  275. bn = bn->next;
  276. if (!bn) {
  277. hfs_warn("hfs_bnode_alloc: too few map nodes.n");
  278. goto bail;
  279. }
  280. bitnr += (end - start);
  281. }
  282. if ((bitnr += (first - start)) >= tree->bthNNodes) {
  283. hfs_warn("hfs_bnode_alloc: no free nodes found, "
  284.  "count wrong?n");
  285. goto bail;
  286. }
  287. if (hfs_set_bit(first % 32, data + (first>>5))) {
  288. hfs_warn("hfs_bnode_alloc: bitmap corruption.n");
  289. goto bail;
  290. }
  291. hfs_buffer_dirty(bn->buf);
  292. /* decrement the free count */
  293. --tree->bthFree;
  294. tree->dirt = 1;
  295. return hfs_bnode_init(tree, bitnr);
  296. bail:
  297. return (struct hfs_bnode_ref){NULL, HFS_LOCK_NONE};
  298. }
  299. /*
  300.  * hfs_btree_extend()
  301.  *
  302.  * Description:
  303.  *   Adds nodes to a B*-tree if possible.
  304.  * Input Variable(s):
  305.  *   struct hfs_btree *tree: the btree to add nodes to.
  306.  * Output Variable(s):
  307.  *   NONE
  308.  * Returns:
  309.  *   void
  310.  * Preconditions:
  311.  *   'tree' is a valid (struct hfs_btree *).
  312.  * Postconditions:
  313.  *   If possible the number of nodes indicated by the tree's clumpsize
  314.  *    have been added to the tree, updating all in-core and on-disk
  315.  *    allocation information.
  316.  *   If insufficient disk-space was available then fewer nodes may have
  317.  *    been added than would be expected based on the clumpsize.
  318.  *   In the case of the extents B*-tree this function will add fewer
  319.  *    nodes than expected if adding more would result in an extent
  320.  *    record for the extents tree being added to the extents tree.
  321.  *    The situation could be dealt with, but doing so confuses Macs.
  322.  */
  323. void hfs_btree_extend(struct hfs_btree *tree)
  324. {
  325. struct hfs_bnode_ref head;
  326. struct hfs_bnode *bn, *tmp;
  327. struct hfs_cat_entry *entry = &tree->entry;
  328. struct hfs_mdb *mdb = entry->mdb;
  329. hfs_u32 old_nodes, new_nodes, total_nodes, new_mapnodes, seen;
  330. old_nodes = entry->u.file.data_fork.psize;
  331. entry->u.file.data_fork.lsize += 1; /* rounded up to clumpsize */
  332. hfs_extent_adj(&entry->u.file.data_fork);
  333. total_nodes = entry->u.file.data_fork.psize;
  334. entry->u.file.data_fork.lsize = total_nodes << HFS_SECTOR_SIZE_BITS;
  335. new_nodes = total_nodes - old_nodes;
  336. if (!new_nodes) {
  337. return;
  338. }
  339. head = hfs_bnode_find(tree, 0, HFS_LOCK_WRITE);
  340. if (!(bn = head.bn)) {
  341. hfs_warn("hfs_btree_extend: header node not found.n");
  342. return;
  343. }
  344. seen = 0;
  345. new_mapnodes = 0;
  346. for (;;) {
  347. seen += bnode_rsize(bn, bn->ndNRecs) << 3;
  348. if (seen >= total_nodes) {
  349. break;
  350. }
  351. if (!bn->next) {
  352. tmp = init_mapnode(bn, seen);
  353. if (!tmp) {
  354. hfs_warn("hfs_btree_extend: "
  355.  "can't build mapnode.n");
  356. hfs_bnode_relse(&head);
  357. return;
  358. }
  359. ++new_mapnodes;
  360. }
  361. bn = bn->next;
  362. }
  363. hfs_bnode_relse(&head);
  364. tree->bthNNodes = total_nodes;
  365. tree->bthFree += (new_nodes - new_mapnodes);
  366. tree->dirt = 1;
  367. /* write the backup MDB, not returning until it is written */
  368. hfs_mdb_commit(mdb, 1);
  369. return;
  370. }
  371. /*
  372.  * hfs_bnode_free()
  373.  *
  374.  * Remove a node from the cache and mark it free in the bitmap.
  375.  */
  376. int hfs_bnode_free(struct hfs_bnode_ref *bnr)
  377. {
  378. hfs_u32 node = bnr->bn->node;
  379. struct hfs_btree *tree = bnr->bn->tree;
  380. if (bnr->bn->count != 1) {
  381. hfs_warn("hfs_bnode_free: count != 1.n");
  382. return -EIO;
  383. }
  384. hfs_bnode_relse(bnr);
  385. hfs_bnode_bitop(tree, node, 0);
  386. return 0;
  387. }