disk-io.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. #define _XOPEN_SOURCE 500
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <sys/types.h>
  5. #include <sys/stat.h>
  6. #include <fcntl.h>
  7. #include <unistd.h>
  8. #include "kerncompat.h"
  9. #include "radix-tree.h"
  10. #include "ctree.h"
  11. #include "disk-io.h"
  12. static int allocated_blocks = 0;
  13. struct ctree_header {
  14. u64 root_block;
  15. } __attribute__ ((__packed__));
  16. static int get_free_block(struct ctree_root *root, u64 *block)
  17. {
  18. struct stat st;
  19. int ret;
  20. st.st_size = 0;
  21. ret = fstat(root->fp, &st);
  22. if (st.st_size > sizeof(struct ctree_header)) {
  23. *block = (st.st_size -
  24. sizeof(struct ctree_header)) / CTREE_BLOCKSIZE;
  25. } else {
  26. *block = 0;
  27. }
  28. ret = ftruncate(root->fp, sizeof(struct ctree_header) + (*block + 1) *
  29. CTREE_BLOCKSIZE);
  30. return ret;
  31. }
  32. struct tree_buffer *alloc_tree_block(struct ctree_root *root, u64 blocknr)
  33. {
  34. struct tree_buffer *buf;
  35. int ret;
  36. buf = malloc(sizeof(struct tree_buffer));
  37. if (!buf)
  38. return buf;
  39. allocated_blocks++;
  40. buf->blocknr = blocknr;
  41. buf->count = 1;
  42. radix_tree_preload(GFP_KERNEL);
  43. ret = radix_tree_insert(&root->cache_radix, blocknr, buf);
  44. radix_tree_preload_end();
  45. if (ret) {
  46. free(buf);
  47. return NULL;
  48. }
  49. return buf;
  50. }
  51. struct tree_buffer *alloc_free_block(struct ctree_root *root)
  52. {
  53. u64 free_block;
  54. int ret;
  55. struct tree_buffer * buf;
  56. ret = get_free_block(root, &free_block);
  57. if (ret) {
  58. BUG();
  59. return NULL;
  60. }
  61. buf = alloc_tree_block(root, free_block);
  62. if (!buf)
  63. BUG();
  64. return buf;
  65. }
  66. struct tree_buffer *read_tree_block(struct ctree_root *root, u64 blocknr)
  67. {
  68. loff_t offset = blocknr * CTREE_BLOCKSIZE + sizeof(struct ctree_header);
  69. struct tree_buffer *buf;
  70. int ret;
  71. buf = radix_tree_lookup(&root->cache_radix, blocknr);
  72. if (buf) {
  73. buf->count++;
  74. if (buf->blocknr != blocknr)
  75. BUG();
  76. if (buf->blocknr != buf->node.header.blocknr)
  77. BUG();
  78. return buf;
  79. }
  80. buf = alloc_tree_block(root, blocknr);
  81. if (!buf)
  82. return NULL;
  83. ret = pread(root->fp, &buf->node, CTREE_BLOCKSIZE, offset);
  84. if (ret != CTREE_BLOCKSIZE) {
  85. free(buf);
  86. return NULL;
  87. }
  88. if (buf->blocknr != buf->node.header.blocknr)
  89. BUG();
  90. return buf;
  91. }
  92. int write_tree_block(struct ctree_root *root, struct tree_buffer *buf)
  93. {
  94. u64 blocknr = buf->blocknr;
  95. loff_t offset = blocknr * CTREE_BLOCKSIZE + sizeof(struct ctree_header);
  96. int ret;
  97. if (buf->blocknr != buf->node.header.blocknr)
  98. BUG();
  99. ret = pwrite(root->fp, &buf->node, CTREE_BLOCKSIZE, offset);
  100. if (ret != CTREE_BLOCKSIZE)
  101. return ret;
  102. if (buf == root->node)
  103. return update_root_block(root);
  104. return 0;
  105. }
  106. struct ctree_root *open_ctree(char *filename)
  107. {
  108. struct ctree_root *root = malloc(sizeof(struct ctree_root));
  109. int fp;
  110. u64 root_block;
  111. int ret;
  112. fp = open(filename, O_CREAT | O_RDWR);
  113. if (fp < 0) {
  114. free(root);
  115. return NULL;
  116. }
  117. root->fp = fp;
  118. INIT_RADIX_TREE(&root->cache_radix, GFP_KERNEL);
  119. ret = pread(fp, &root_block, sizeof(u64), 0);
  120. if (ret == sizeof(u64)) {
  121. printf("reading root node at block %lu\n", root_block);
  122. root->node = read_tree_block(root, root_block);
  123. } else
  124. root->node = NULL;
  125. return root;
  126. }
  127. int close_ctree(struct ctree_root *root)
  128. {
  129. close(root->fp);
  130. if (root->node)
  131. tree_block_release(root, root->node);
  132. free(root);
  133. printf("on close %d blocks are allocated\n", allocated_blocks);
  134. return 0;
  135. }
  136. int update_root_block(struct ctree_root *root)
  137. {
  138. int ret;
  139. u64 root_block = root->node->blocknr;
  140. ret = pwrite(root->fp, &root_block, sizeof(u64), 0);
  141. if (ret != sizeof(u64))
  142. return ret;
  143. return 0;
  144. }
  145. void tree_block_release(struct ctree_root *root, struct tree_buffer *buf)
  146. {
  147. buf->count--;
  148. if (buf->count == 0) {
  149. if (!radix_tree_lookup(&root->cache_radix, buf->blocknr))
  150. BUG();
  151. radix_tree_delete(&root->cache_radix, buf->blocknr);
  152. memset(buf, 0, sizeof(*buf));
  153. free(buf);
  154. BUG_ON(allocated_blocks == 0);
  155. allocated_blocks--;
  156. }
  157. }