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" 12e089f05cSChris Mason #include "transaction.h" 13eb60ceacSChris Mason 14eb60ceacSChris Mason static int allocated_blocks = 0; 15ed2ff2cbSChris Mason int cache_max = 10000; 16eb60ceacSChris Mason 17234b63a0SChris Mason static int check_tree_block(struct btrfs_root *root, struct btrfs_buffer *buf) 18eb60ceacSChris Mason { 197518a238SChris Mason if (buf->blocknr != btrfs_header_blocknr(&buf->node.header)) 209a8dd150SChris Mason BUG(); 217518a238SChris Mason if (root->node && btrfs_header_parentid(&buf->node.header) != 227518a238SChris Mason btrfs_header_parentid(&root->node->node.header)) 239a8dd150SChris Mason BUG(); 249a8dd150SChris Mason return 0; 25eb60ceacSChris Mason } 26eb60ceacSChris Mason 27234b63a0SChris Mason static int free_some_buffers(struct btrfs_root *root) 28ed2ff2cbSChris Mason { 29ed2ff2cbSChris Mason struct list_head *node, *next; 30234b63a0SChris Mason struct btrfs_buffer *b; 31ed2ff2cbSChris Mason if (root->cache_size < cache_max) 32ed2ff2cbSChris Mason return 0; 33ed2ff2cbSChris Mason list_for_each_safe(node, next, &root->cache) { 34234b63a0SChris Mason b = list_entry(node, struct btrfs_buffer, cache); 35ed2ff2cbSChris Mason if (b->count == 1) { 36ed2ff2cbSChris Mason BUG_ON(!list_empty(&b->dirty)); 37ed2ff2cbSChris Mason list_del_init(&b->cache); 38234b63a0SChris Mason btrfs_block_release(root, b); 39ed2ff2cbSChris Mason if (root->cache_size < cache_max) 4077ce6846SChris Mason break; 41ed2ff2cbSChris Mason } 42ed2ff2cbSChris Mason } 43ed2ff2cbSChris Mason return 0; 44ed2ff2cbSChris Mason } 45ed2ff2cbSChris Mason 46234b63a0SChris Mason struct btrfs_buffer *alloc_tree_block(struct btrfs_root *root, u64 blocknr) 47eb60ceacSChris Mason { 48234b63a0SChris Mason struct btrfs_buffer *buf; 49eb60ceacSChris Mason int ret; 50123abc88SChris Mason 51123abc88SChris Mason buf = malloc(sizeof(struct btrfs_buffer) + root->blocksize); 52eb60ceacSChris Mason if (!buf) 53eb60ceacSChris Mason return buf; 54eb60ceacSChris Mason allocated_blocks++; 55eb60ceacSChris Mason buf->blocknr = blocknr; 56ed2ff2cbSChris Mason buf->count = 2; 57ed2ff2cbSChris Mason INIT_LIST_HEAD(&buf->dirty); 58ed2ff2cbSChris Mason free_some_buffers(root); 59eb60ceacSChris Mason radix_tree_preload(GFP_KERNEL); 60eb60ceacSChris Mason ret = radix_tree_insert(&root->cache_radix, blocknr, buf); 61eb60ceacSChris Mason radix_tree_preload_end(); 62ed2ff2cbSChris Mason list_add_tail(&buf->cache, &root->cache); 63ed2ff2cbSChris Mason root->cache_size++; 64eb60ceacSChris Mason if (ret) { 65eb60ceacSChris Mason free(buf); 66eb60ceacSChris Mason return NULL; 67eb60ceacSChris Mason } 68eb60ceacSChris Mason return buf; 69eb60ceacSChris Mason } 70eb60ceacSChris Mason 71234b63a0SChris Mason struct btrfs_buffer *find_tree_block(struct btrfs_root *root, u64 blocknr) 72eb60ceacSChris Mason { 73234b63a0SChris Mason struct btrfs_buffer *buf; 749a8dd150SChris Mason buf = radix_tree_lookup(&root->cache_radix, blocknr); 759a8dd150SChris Mason if (buf) { 769a8dd150SChris Mason buf->count++; 779a8dd150SChris Mason } else { 789a8dd150SChris Mason buf = alloc_tree_block(root, blocknr); 799a8dd150SChris Mason if (!buf) { 80eb60ceacSChris Mason BUG(); 81eb60ceacSChris Mason return NULL; 82eb60ceacSChris Mason } 839a8dd150SChris Mason } 84eb60ceacSChris Mason return buf; 85eb60ceacSChris Mason } 86eb60ceacSChris Mason 87234b63a0SChris Mason struct btrfs_buffer *read_tree_block(struct btrfs_root *root, u64 blocknr) 88eb60ceacSChris Mason { 89123abc88SChris Mason loff_t offset = blocknr * root->blocksize; 90234b63a0SChris Mason struct btrfs_buffer *buf; 91eb60ceacSChris Mason int ret; 92eb60ceacSChris Mason 93eb60ceacSChris Mason buf = radix_tree_lookup(&root->cache_radix, blocknr); 94eb60ceacSChris Mason if (buf) { 95eb60ceacSChris Mason buf->count++; 969a8dd150SChris Mason } else { 97eb60ceacSChris Mason buf = alloc_tree_block(root, blocknr); 98eb60ceacSChris Mason if (!buf) 99eb60ceacSChris Mason return NULL; 100123abc88SChris Mason ret = pread(root->fp, &buf->node, root->blocksize, offset); 101123abc88SChris Mason if (ret != root->blocksize) { 102eb60ceacSChris Mason free(buf); 103eb60ceacSChris Mason return NULL; 104eb60ceacSChris Mason } 1059a8dd150SChris Mason } 1069a8dd150SChris Mason if (check_tree_block(root, buf)) 107cfaa7295SChris Mason BUG(); 108eb60ceacSChris Mason return buf; 109eb60ceacSChris Mason } 110eb60ceacSChris Mason 111e089f05cSChris Mason int dirty_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, 112e089f05cSChris Mason struct btrfs_buffer *buf) 113ed2ff2cbSChris Mason { 114ed2ff2cbSChris Mason if (!list_empty(&buf->dirty)) 115ed2ff2cbSChris Mason return 0; 116ed2ff2cbSChris Mason list_add_tail(&buf->dirty, &root->trans); 117ed2ff2cbSChris Mason buf->count++; 118ed2ff2cbSChris Mason return 0; 119ed2ff2cbSChris Mason } 120ed2ff2cbSChris Mason 121e089f05cSChris Mason int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, 122e089f05cSChris Mason struct btrfs_buffer *buf) 123ed2ff2cbSChris Mason { 124ed2ff2cbSChris Mason if (!list_empty(&buf->dirty)) { 125ed2ff2cbSChris Mason list_del_init(&buf->dirty); 126234b63a0SChris Mason btrfs_block_release(root, buf); 127ed2ff2cbSChris Mason } 128ed2ff2cbSChris Mason return 0; 129ed2ff2cbSChris Mason } 130ed2ff2cbSChris Mason 131e089f05cSChris Mason int write_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, 132e089f05cSChris Mason struct btrfs_buffer *buf) 133eb60ceacSChris Mason { 134eb60ceacSChris Mason u64 blocknr = buf->blocknr; 135123abc88SChris Mason loff_t offset = blocknr * root->blocksize; 136eb60ceacSChris Mason int ret; 137eb60ceacSChris Mason 1387518a238SChris Mason if (buf->blocknr != btrfs_header_blocknr(&buf->node.header)) 139eb60ceacSChris Mason BUG(); 140123abc88SChris Mason ret = pwrite(root->fp, &buf->node, root->blocksize, offset); 141123abc88SChris Mason if (ret != root->blocksize) 142eb60ceacSChris Mason return ret; 143eb60ceacSChris Mason return 0; 144eb60ceacSChris Mason } 145eb60ceacSChris Mason 146e089f05cSChris Mason static int __commit_transaction(struct btrfs_trans_handle *trans, struct 147e089f05cSChris Mason btrfs_root *root) 148ed2ff2cbSChris Mason { 149234b63a0SChris Mason struct btrfs_buffer *b; 150ed2ff2cbSChris Mason int ret = 0; 151ed2ff2cbSChris Mason int wret; 152ed2ff2cbSChris Mason while(!list_empty(&root->trans)) { 153234b63a0SChris Mason b = list_entry(root->trans.next, struct btrfs_buffer, dirty); 154ed2ff2cbSChris Mason list_del_init(&b->dirty); 155e089f05cSChris Mason wret = write_tree_block(trans, root, b); 156ed2ff2cbSChris Mason if (wret) 157ed2ff2cbSChris Mason ret = wret; 158234b63a0SChris Mason btrfs_block_release(root, b); 159ed2ff2cbSChris Mason } 160ed2ff2cbSChris Mason return ret; 161ed2ff2cbSChris Mason } 162ed2ff2cbSChris Mason 163e089f05cSChris Mason static int commit_extent_and_tree_roots(struct btrfs_trans_handle *trans, 164e089f05cSChris Mason struct btrfs_root *tree_root, struct 165e089f05cSChris Mason btrfs_root *extent_root) 1663768f368SChris Mason { 1673768f368SChris Mason int ret; 1683768f368SChris Mason u64 old_extent_block; 1693768f368SChris Mason 1703768f368SChris Mason while(1) { 1713768f368SChris Mason old_extent_block = btrfs_root_blocknr(&extent_root->root_item); 1723768f368SChris Mason if (old_extent_block == extent_root->node->blocknr) 1733768f368SChris Mason break; 1743768f368SChris Mason btrfs_set_root_blocknr(&extent_root->root_item, 1753768f368SChris Mason extent_root->node->blocknr); 176e089f05cSChris Mason ret = btrfs_update_root(trans, tree_root, 1773768f368SChris Mason &extent_root->root_key, 1783768f368SChris Mason &extent_root->root_item); 1793768f368SChris Mason BUG_ON(ret); 1803768f368SChris Mason } 181e089f05cSChris Mason __commit_transaction(trans, extent_root); 182e089f05cSChris Mason __commit_transaction(trans, tree_root); 1833768f368SChris Mason return 0; 1843768f368SChris Mason } 1853768f368SChris Mason 186e089f05cSChris Mason int btrfs_commit_transaction(struct btrfs_trans_handle *trans, struct 187e089f05cSChris Mason btrfs_root *root, struct btrfs_super_block *s) 188ed2ff2cbSChris Mason { 189a28ec197SChris Mason int ret = 0; 1903768f368SChris Mason struct btrfs_buffer *snap = root->commit_root; 1913768f368SChris Mason struct btrfs_key snap_key; 192a28ec197SChris Mason 193e089f05cSChris Mason ret = __commit_transaction(trans, root); 194ed2ff2cbSChris Mason BUG_ON(ret); 1953768f368SChris Mason 1963768f368SChris Mason if (root->commit_root == root->node) 1973768f368SChris Mason return 0; 1983768f368SChris Mason 1993768f368SChris Mason memcpy(&snap_key, &root->root_key, sizeof(snap_key)); 2003768f368SChris Mason root->root_key.offset++; 2013768f368SChris Mason 2023768f368SChris Mason btrfs_set_root_blocknr(&root->root_item, root->node->blocknr); 203e089f05cSChris Mason ret = btrfs_insert_root(trans, root->tree_root, &root->root_key, 2043768f368SChris Mason &root->root_item); 2053768f368SChris Mason BUG_ON(ret); 2063768f368SChris Mason 207e089f05cSChris Mason ret = commit_extent_and_tree_roots(trans, root->tree_root, 208e089f05cSChris Mason root->extent_root); 2093768f368SChris Mason BUG_ON(ret); 2103768f368SChris Mason 211e089f05cSChris Mason write_ctree_super(trans, root, s); 212e089f05cSChris Mason btrfs_finish_extent_commit(trans, root->extent_root); 213e089f05cSChris Mason btrfs_finish_extent_commit(trans, root->tree_root); 2143768f368SChris Mason 215a28ec197SChris Mason root->commit_root = root->node; 216a28ec197SChris Mason root->node->count++; 217e089f05cSChris Mason ret = btrfs_drop_snapshot(trans, root, snap); 218a28ec197SChris Mason BUG_ON(ret); 2193768f368SChris Mason 220e089f05cSChris Mason ret = btrfs_del_root(trans, root->tree_root, &snap_key); 2213768f368SChris Mason BUG_ON(ret); 2223768f368SChris Mason 223ed2ff2cbSChris Mason return ret; 224ed2ff2cbSChris Mason } 225ed2ff2cbSChris Mason 226123abc88SChris Mason static int __setup_root(struct btrfs_super_block *super, 227123abc88SChris Mason struct btrfs_root *root, u64 objectid, int fp) 228d97e63b6SChris Mason { 229ed2ff2cbSChris Mason INIT_LIST_HEAD(&root->trans); 230ed2ff2cbSChris Mason INIT_LIST_HEAD(&root->cache); 231a28ec197SChris Mason root->cache_size = 0; 232d97e63b6SChris Mason root->fp = fp; 233cfaa7295SChris Mason root->node = NULL; 234a28ec197SChris Mason root->commit_root = NULL; 235123abc88SChris Mason root->blocksize = btrfs_super_blocksize(super); 236123abc88SChris Mason root->ref_cows = 0; 237a28ec197SChris Mason memset(&root->current_insert, 0, sizeof(root->current_insert)); 2380579da42SChris Mason memset(&root->last_insert, 0, sizeof(root->last_insert)); 2393768f368SChris Mason memset(&root->root_key, 0, sizeof(root->root_key)); 2403768f368SChris Mason memset(&root->root_item, 0, sizeof(root->root_item)); 2413768f368SChris Mason return 0; 2423768f368SChris Mason } 2433768f368SChris Mason 244123abc88SChris Mason static int find_and_setup_root(struct btrfs_super_block *super, 245123abc88SChris Mason struct btrfs_root *tree_root, u64 objectid, 2463768f368SChris Mason struct btrfs_root *root, int fp) 2473768f368SChris Mason { 2483768f368SChris Mason int ret; 2493768f368SChris Mason 250123abc88SChris Mason __setup_root(super, root, objectid, fp); 2513768f368SChris Mason ret = btrfs_find_last_root(tree_root, objectid, 2523768f368SChris Mason &root->root_item, &root->root_key); 2533768f368SChris Mason BUG_ON(ret); 2543768f368SChris Mason 2553768f368SChris Mason root->node = read_tree_block(root, 2563768f368SChris Mason btrfs_root_blocknr(&root->root_item)); 2573768f368SChris Mason BUG_ON(!root->node); 258d97e63b6SChris Mason return 0; 259d97e63b6SChris Mason } 260d97e63b6SChris Mason 261234b63a0SChris Mason struct btrfs_root *open_ctree(char *filename, struct btrfs_super_block *super) 262eb60ceacSChris Mason { 263234b63a0SChris Mason struct btrfs_root *root = malloc(sizeof(struct btrfs_root)); 264234b63a0SChris Mason struct btrfs_root *extent_root = malloc(sizeof(struct btrfs_root)); 2653768f368SChris Mason struct btrfs_root *tree_root = malloc(sizeof(struct btrfs_root)); 266eb60ceacSChris Mason int fp; 267eb60ceacSChris Mason int ret; 268eb60ceacSChris Mason 2693768f368SChris Mason root->extent_root = extent_root; 2703768f368SChris Mason root->tree_root = tree_root; 2713768f368SChris Mason 2723768f368SChris Mason extent_root->extent_root = extent_root; 2733768f368SChris Mason extent_root->tree_root = tree_root; 2743768f368SChris Mason 2753768f368SChris Mason tree_root->extent_root = extent_root; 2763768f368SChris Mason tree_root->tree_root = tree_root; 2773768f368SChris Mason 278c673024aSChris Mason fp = open(filename, O_CREAT | O_RDWR, 0600); 279eb60ceacSChris Mason if (fp < 0) { 280eb60ceacSChris Mason free(root); 281eb60ceacSChris Mason return NULL; 282eb60ceacSChris Mason } 2839a8dd150SChris Mason INIT_RADIX_TREE(&root->cache_radix, GFP_KERNEL); 284a28ec197SChris Mason INIT_RADIX_TREE(&root->pinned_radix, GFP_KERNEL); 285a28ec197SChris Mason INIT_RADIX_TREE(&extent_root->pinned_radix, GFP_KERNEL); 2869a8dd150SChris Mason INIT_RADIX_TREE(&extent_root->cache_radix, GFP_KERNEL); 2873768f368SChris Mason INIT_RADIX_TREE(&tree_root->pinned_radix, GFP_KERNEL); 2883768f368SChris Mason INIT_RADIX_TREE(&tree_root->cache_radix, GFP_KERNEL); 2893768f368SChris Mason 290234b63a0SChris Mason ret = pread(fp, super, sizeof(struct btrfs_super_block), 291123abc88SChris Mason BTRFS_SUPER_INFO_OFFSET); 2923768f368SChris Mason if (ret == 0 || btrfs_super_root(super) == 0) { 2935c680ed6SChris Mason printf("making new FS!\n"); 294123abc88SChris Mason ret = mkfs(fp, 0, 1024); 295d97e63b6SChris Mason if (ret) 296d97e63b6SChris Mason return NULL; 297234b63a0SChris Mason ret = pread(fp, super, sizeof(struct btrfs_super_block), 298123abc88SChris Mason BTRFS_SUPER_INFO_OFFSET); 299234b63a0SChris Mason if (ret != sizeof(struct btrfs_super_block)) 300d97e63b6SChris Mason return NULL; 301d97e63b6SChris Mason } 302d97e63b6SChris Mason BUG_ON(ret < 0); 3033768f368SChris Mason 304123abc88SChris Mason __setup_root(super, tree_root, BTRFS_ROOT_TREE_OBJECTID, fp); 3053768f368SChris Mason tree_root->node = read_tree_block(tree_root, btrfs_super_root(super)); 3063768f368SChris Mason BUG_ON(!tree_root->node); 3073768f368SChris Mason 308123abc88SChris Mason ret = find_and_setup_root(super, tree_root, BTRFS_EXTENT_TREE_OBJECTID, 3093768f368SChris Mason extent_root, fp); 3103768f368SChris Mason BUG_ON(ret); 3113768f368SChris Mason 312123abc88SChris Mason ret = find_and_setup_root(super, tree_root, BTRFS_FS_TREE_OBJECTID, 3133768f368SChris Mason root, fp); 3143768f368SChris Mason BUG_ON(ret); 3153768f368SChris Mason 316a28ec197SChris Mason root->commit_root = root->node; 317a28ec197SChris Mason root->node->count++; 3183768f368SChris Mason root->ref_cows = 1; 319eb60ceacSChris Mason return root; 320eb60ceacSChris Mason } 321eb60ceacSChris Mason 322e089f05cSChris Mason int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root 323e089f05cSChris Mason *root, struct btrfs_super_block *s) 324cfaa7295SChris Mason { 325cfaa7295SChris Mason int ret; 3263768f368SChris Mason btrfs_set_super_root(s, root->tree_root->node->blocknr); 327234b63a0SChris Mason ret = pwrite(root->fp, s, sizeof(*s), 328123abc88SChris Mason BTRFS_SUPER_INFO_OFFSET); 329cfaa7295SChris Mason if (ret != sizeof(*s)) { 330cfaa7295SChris Mason fprintf(stderr, "failed to write new super block err %d\n", ret); 331cfaa7295SChris Mason return ret; 332cfaa7295SChris Mason } 333cfaa7295SChris Mason return 0; 334cfaa7295SChris Mason } 335cfaa7295SChris Mason 336234b63a0SChris Mason static int drop_cache(struct btrfs_root *root) 337ed2ff2cbSChris Mason { 338ed2ff2cbSChris Mason while(!list_empty(&root->cache)) { 339234b63a0SChris Mason struct btrfs_buffer *b = list_entry(root->cache.next, 340234b63a0SChris Mason struct btrfs_buffer, cache); 341ed2ff2cbSChris Mason list_del_init(&b->cache); 342234b63a0SChris Mason btrfs_block_release(root, b); 343ed2ff2cbSChris Mason } 344ed2ff2cbSChris Mason return 0; 345ed2ff2cbSChris Mason } 346234b63a0SChris Mason int close_ctree(struct btrfs_root *root, struct btrfs_super_block *s) 347eb60ceacSChris Mason { 3483768f368SChris Mason int ret; 349e089f05cSChris Mason struct btrfs_trans_handle *trans; 350e089f05cSChris Mason 351e089f05cSChris Mason trans = root->running_transaction; 352e089f05cSChris Mason btrfs_commit_transaction(trans, root, s); 353e089f05cSChris Mason ret = commit_extent_and_tree_roots(trans, root->tree_root, 354e089f05cSChris Mason root->extent_root); 3553768f368SChris Mason BUG_ON(ret); 356e089f05cSChris Mason write_ctree_super(trans, root, s); 357ed2ff2cbSChris Mason drop_cache(root->extent_root); 3583768f368SChris Mason drop_cache(root->tree_root); 359ed2ff2cbSChris Mason drop_cache(root); 360ed2ff2cbSChris Mason BUG_ON(!list_empty(&root->trans)); 361ed2ff2cbSChris Mason BUG_ON(!list_empty(&root->extent_root->trans)); 3623768f368SChris Mason BUG_ON(!list_empty(&root->tree_root->trans)); 363ed2ff2cbSChris Mason 364eb60ceacSChris Mason close(root->fp); 365eb60ceacSChris Mason if (root->node) 366234b63a0SChris Mason btrfs_block_release(root, root->node); 367cfaa7295SChris Mason if (root->extent_root->node) 368234b63a0SChris Mason btrfs_block_release(root->extent_root, root->extent_root->node); 3693768f368SChris Mason if (root->tree_root->node) 3703768f368SChris Mason btrfs_block_release(root->tree_root, root->tree_root->node); 371234b63a0SChris Mason btrfs_block_release(root, root->commit_root); 372eb60ceacSChris Mason free(root); 373eb60ceacSChris Mason printf("on close %d blocks are allocated\n", allocated_blocks); 374eb60ceacSChris Mason return 0; 375eb60ceacSChris Mason } 376eb60ceacSChris Mason 377234b63a0SChris Mason void btrfs_block_release(struct btrfs_root *root, struct btrfs_buffer *buf) 378eb60ceacSChris Mason { 379eb60ceacSChris Mason buf->count--; 380cfaa7295SChris Mason if (buf->count < 0) 381cfaa7295SChris Mason BUG(); 382eb60ceacSChris Mason if (buf->count == 0) { 38302217ed2SChris Mason BUG_ON(!list_empty(&buf->cache)); 38402217ed2SChris Mason BUG_ON(!list_empty(&buf->dirty)); 385eb60ceacSChris Mason if (!radix_tree_lookup(&root->cache_radix, buf->blocknr)) 386eb60ceacSChris Mason BUG(); 387eb60ceacSChris Mason radix_tree_delete(&root->cache_radix, buf->blocknr); 388eb60ceacSChris Mason memset(buf, 0, sizeof(*buf)); 389eb60ceacSChris Mason free(buf); 390eb60ceacSChris Mason BUG_ON(allocated_blocks == 0); 391eb60ceacSChris Mason allocated_blocks--; 392ed2ff2cbSChris Mason BUG_ON(root->cache_size == 0); 393ed2ff2cbSChris Mason root->cache_size--; 394eb60ceacSChris Mason } 395eb60ceacSChris Mason } 396eb60ceacSChris Mason 397