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