1bf686dbeSMatthew Dillon /* 2bf686dbeSMatthew Dillon * Copyright (c) 2008 The DragonFly Project. All rights reserved. 3bf686dbeSMatthew Dillon * 4bf686dbeSMatthew Dillon * This code is derived from software contributed to The DragonFly Project 5bf686dbeSMatthew Dillon * by Matthew Dillon <dillon@backplane.com> 6bf686dbeSMatthew Dillon * 7bf686dbeSMatthew Dillon * Redistribution and use in source and binary forms, with or without 8bf686dbeSMatthew Dillon * modification, are permitted provided that the following conditions 9bf686dbeSMatthew Dillon * are met: 10bf686dbeSMatthew Dillon * 11bf686dbeSMatthew Dillon * 1. Redistributions of source code must retain the above copyright 12bf686dbeSMatthew Dillon * notice, this list of conditions and the following disclaimer. 13bf686dbeSMatthew Dillon * 2. Redistributions in binary form must reproduce the above copyright 14bf686dbeSMatthew Dillon * notice, this list of conditions and the following disclaimer in 15bf686dbeSMatthew Dillon * the documentation and/or other materials provided with the 16bf686dbeSMatthew Dillon * distribution. 17bf686dbeSMatthew Dillon * 3. Neither the name of The DragonFly Project nor the names of its 18bf686dbeSMatthew Dillon * contributors may be used to endorse or promote products derived 19bf686dbeSMatthew Dillon * from this software without specific, prior written permission. 20bf686dbeSMatthew Dillon * 21bf686dbeSMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22bf686dbeSMatthew Dillon * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23bf686dbeSMatthew Dillon * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24bf686dbeSMatthew Dillon * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25bf686dbeSMatthew Dillon * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26bf686dbeSMatthew Dillon * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27bf686dbeSMatthew Dillon * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28bf686dbeSMatthew Dillon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29bf686dbeSMatthew Dillon * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30bf686dbeSMatthew Dillon * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31bf686dbeSMatthew Dillon * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32bf686dbeSMatthew Dillon * SUCH DAMAGE. 33bf686dbeSMatthew Dillon * 34*ea434b6fSMatthew Dillon * $DragonFly: src/sys/vfs/hammer/hammer_reblock.c,v 1.25 2008/07/09 10:29:20 dillon Exp $ 35bf686dbeSMatthew Dillon */ 36bf686dbeSMatthew Dillon /* 37bf686dbeSMatthew Dillon * HAMMER reblocker - This code frees up fragmented physical space 38bf686dbeSMatthew Dillon * 39bf686dbeSMatthew Dillon * HAMMER only keeps track of free space on a big-block basis. A big-block 40bf686dbeSMatthew Dillon * containing holes can only be freed by migrating the remaining data in 41bf686dbeSMatthew Dillon * that big-block into a new big-block, then freeing the big-block. 42bf686dbeSMatthew Dillon * 43bf686dbeSMatthew Dillon * This function is called from an ioctl or via the hammer support thread. 44bf686dbeSMatthew Dillon */ 45bf686dbeSMatthew Dillon 46bf686dbeSMatthew Dillon #include "hammer.h" 47bf686dbeSMatthew Dillon 4836f82b23SMatthew Dillon static int hammer_reblock_helper(struct hammer_ioc_reblock *reblock, 49bf686dbeSMatthew Dillon hammer_cursor_t cursor, 50bf686dbeSMatthew Dillon hammer_btree_elm_t elm); 5136f82b23SMatthew Dillon static int hammer_reblock_data(struct hammer_ioc_reblock *reblock, 52bf686dbeSMatthew Dillon hammer_cursor_t cursor, hammer_btree_elm_t elm); 532f85fa4dSMatthew Dillon static int hammer_reblock_leaf_node(struct hammer_ioc_reblock *reblock, 542f85fa4dSMatthew Dillon hammer_cursor_t cursor, hammer_btree_elm_t elm); 552f85fa4dSMatthew Dillon static int hammer_reblock_int_node(struct hammer_ioc_reblock *reblock, 56bf686dbeSMatthew Dillon hammer_cursor_t cursor, hammer_btree_elm_t elm); 57bf686dbeSMatthew Dillon 58bf686dbeSMatthew Dillon int 5936f82b23SMatthew Dillon hammer_ioc_reblock(hammer_transaction_t trans, hammer_inode_t ip, 6036f82b23SMatthew Dillon struct hammer_ioc_reblock *reblock) 61bf686dbeSMatthew Dillon { 62bf686dbeSMatthew Dillon struct hammer_cursor cursor; 63bf686dbeSMatthew Dillon hammer_btree_elm_t elm; 64bf686dbeSMatthew Dillon int error; 65a7e9bef1SMatthew Dillon int checkspace_count; 66bf686dbeSMatthew Dillon 67dd94f1b1SMatthew Dillon if ((reblock->key_beg.localization | reblock->key_end.localization) & 68dd94f1b1SMatthew Dillon HAMMER_LOCALIZE_PSEUDOFS_MASK) { 69dd94f1b1SMatthew Dillon return(EINVAL); 70dd94f1b1SMatthew Dillon } 71dd94f1b1SMatthew Dillon if (reblock->key_beg.obj_id >= reblock->key_end.obj_id) 72bf686dbeSMatthew Dillon return(EINVAL); 73bf686dbeSMatthew Dillon if (reblock->free_level < 0) 74bf686dbeSMatthew Dillon return(EINVAL); 75bf686dbeSMatthew Dillon 76dd94f1b1SMatthew Dillon reblock->key_cur = reblock->key_beg; 77dd94f1b1SMatthew Dillon reblock->key_cur.localization += ip->obj_localization; 78814387f6SMatthew Dillon 79a7e9bef1SMatthew Dillon checkspace_count = 0; 80bf686dbeSMatthew Dillon retry: 814e17f465SMatthew Dillon error = hammer_init_cursor(trans, &cursor, NULL, NULL); 82bf686dbeSMatthew Dillon if (error) { 83bf686dbeSMatthew Dillon hammer_done_cursor(&cursor); 84dd94f1b1SMatthew Dillon goto failed; 85bf686dbeSMatthew Dillon } 86dd94f1b1SMatthew Dillon cursor.key_beg.localization = reblock->key_cur.localization; 87dd94f1b1SMatthew Dillon cursor.key_beg.obj_id = reblock->key_cur.obj_id; 88bf686dbeSMatthew Dillon cursor.key_beg.key = HAMMER_MIN_KEY; 89bf686dbeSMatthew Dillon cursor.key_beg.create_tid = 1; 90bf686dbeSMatthew Dillon cursor.key_beg.delete_tid = 0; 91bf686dbeSMatthew Dillon cursor.key_beg.rec_type = HAMMER_MIN_RECTYPE; 92bf686dbeSMatthew Dillon cursor.key_beg.obj_type = 0; 93bf686dbeSMatthew Dillon 94dd94f1b1SMatthew Dillon cursor.key_end.localization = reblock->key_end.localization + 95dd94f1b1SMatthew Dillon ip->obj_localization; 96dd94f1b1SMatthew Dillon cursor.key_end.obj_id = reblock->key_end.obj_id; 97bf686dbeSMatthew Dillon cursor.key_end.key = HAMMER_MAX_KEY; 98bf686dbeSMatthew Dillon cursor.key_end.create_tid = HAMMER_MAX_TID - 1; 99bf686dbeSMatthew Dillon cursor.key_end.delete_tid = 0; 100bf686dbeSMatthew Dillon cursor.key_end.rec_type = HAMMER_MAX_RECTYPE; 101bf686dbeSMatthew Dillon cursor.key_end.obj_type = 0; 102bf686dbeSMatthew Dillon 103bf686dbeSMatthew Dillon cursor.flags |= HAMMER_CURSOR_END_INCLUSIVE; 1049480ff55SMatthew Dillon cursor.flags |= HAMMER_CURSOR_BACKEND; 105bf686dbeSMatthew Dillon 1062f85fa4dSMatthew Dillon /* 1072f85fa4dSMatthew Dillon * This flag allows the btree scan code to return internal nodes, 1082f85fa4dSMatthew Dillon * so we can reblock them in addition to the leafs. Only specify it 1092f85fa4dSMatthew Dillon * if we intend to reblock B-Tree nodes. 1102f85fa4dSMatthew Dillon */ 1112f85fa4dSMatthew Dillon if (reblock->head.flags & HAMMER_IOC_DO_BTREE) 1122f85fa4dSMatthew Dillon cursor.flags |= HAMMER_CURSOR_REBLOCKING; 1132f85fa4dSMatthew Dillon 114bf686dbeSMatthew Dillon error = hammer_btree_first(&cursor); 115bf686dbeSMatthew Dillon while (error == 0) { 1162f85fa4dSMatthew Dillon /* 1172f85fa4dSMatthew Dillon * Internal or Leaf node 1182f85fa4dSMatthew Dillon */ 119bf686dbeSMatthew Dillon elm = &cursor.node->ondisk->elms[cursor.index]; 120dd94f1b1SMatthew Dillon reblock->key_cur.obj_id = elm->base.obj_id; 121dd94f1b1SMatthew Dillon reblock->key_cur.localization = elm->base.localization; 122bf686dbeSMatthew Dillon 1239480ff55SMatthew Dillon /* 1249f5097dcSMatthew Dillon * Yield to more important tasks 1259f5097dcSMatthew Dillon */ 1269f5097dcSMatthew Dillon if ((error = hammer_signal_check(trans->hmp)) != 0) 1279f5097dcSMatthew Dillon break; 1289f5097dcSMatthew Dillon if (trans->hmp->sync_lock.wanted) { 1299f5097dcSMatthew Dillon tsleep(trans, 0, "hmrslo", hz / 10); 1309f5097dcSMatthew Dillon } 131a7e9bef1SMatthew Dillon 132a7e9bef1SMatthew Dillon /* 133a7e9bef1SMatthew Dillon * If we build up too much meta-data we have to wait for 134a7e9bef1SMatthew Dillon * a flush cycle. 135a7e9bef1SMatthew Dillon */ 13606ad81ffSMatthew Dillon if (hammer_flusher_meta_limit(trans->hmp) || 13706ad81ffSMatthew Dillon hammer_flusher_undo_exhausted(trans, 2)) { 13806ad81ffSMatthew Dillon error = EWOULDBLOCK; 13906ad81ffSMatthew Dillon break; 1409f5097dcSMatthew Dillon } 1419f5097dcSMatthew Dillon 1429f5097dcSMatthew Dillon /* 143a7e9bef1SMatthew Dillon * If there is insufficient free space it may be due to 144a7e9bef1SMatthew Dillon * reserved bigblocks, which flushing might fix. 145a7e9bef1SMatthew Dillon */ 146a7e9bef1SMatthew Dillon if (hammer_checkspace(trans->hmp, HAMMER_CHECKSPACE_SLOP_REBLOCK)) { 147a7e9bef1SMatthew Dillon if (++checkspace_count == 10) { 148a7e9bef1SMatthew Dillon error = ENOSPC; 149a7e9bef1SMatthew Dillon } else { 150a7e9bef1SMatthew Dillon error = EWOULDBLOCK; 151a7e9bef1SMatthew Dillon } 152a7e9bef1SMatthew Dillon break; 153a7e9bef1SMatthew Dillon } 154a7e9bef1SMatthew Dillon 155a7e9bef1SMatthew Dillon /* 1569480ff55SMatthew Dillon * Acquiring the sync_lock prevents the operation from 1579480ff55SMatthew Dillon * crossing a synchronization boundary. 15809ac686bSMatthew Dillon * 15909ac686bSMatthew Dillon * NOTE: cursor.node may have changed on return. 1609480ff55SMatthew Dillon */ 1612f85fa4dSMatthew Dillon hammer_sync_lock_sh(trans); 16236f82b23SMatthew Dillon error = hammer_reblock_helper(reblock, &cursor, elm); 1632f85fa4dSMatthew Dillon hammer_sync_unlock(trans); 164bf686dbeSMatthew Dillon if (error == 0) { 165bf686dbeSMatthew Dillon cursor.flags |= HAMMER_CURSOR_ATEDISK; 166bf686dbeSMatthew Dillon error = hammer_btree_iterate(&cursor); 167bf686dbeSMatthew Dillon } 168a7e9bef1SMatthew Dillon 169bf686dbeSMatthew Dillon } 170bf686dbeSMatthew Dillon if (error == ENOENT) 171bf686dbeSMatthew Dillon error = 0; 172bf686dbeSMatthew Dillon hammer_done_cursor(&cursor); 17306ad81ffSMatthew Dillon if (error == EWOULDBLOCK) { 17406ad81ffSMatthew Dillon hammer_flusher_sync(trans->hmp); 17506ad81ffSMatthew Dillon goto retry; 17606ad81ffSMatthew Dillon } 177bf686dbeSMatthew Dillon if (error == EDEADLK) 178bf686dbeSMatthew Dillon goto retry; 17919619882SMatthew Dillon if (error == EINTR) { 18019619882SMatthew Dillon reblock->head.flags |= HAMMER_IOC_HEAD_INTR; 18119619882SMatthew Dillon error = 0; 18219619882SMatthew Dillon } 183dd94f1b1SMatthew Dillon failed: 184dd94f1b1SMatthew Dillon reblock->key_cur.localization &= HAMMER_LOCALIZE_MASK; 185bf686dbeSMatthew Dillon return(error); 186bf686dbeSMatthew Dillon } 187bf686dbeSMatthew Dillon 188bf686dbeSMatthew Dillon /* 189bf686dbeSMatthew Dillon * Reblock the B-Tree (leaf) node, record, and/or data if necessary. 190bf686dbeSMatthew Dillon * 1919480ff55SMatthew Dillon * XXX We have no visibility into internal B-Tree nodes at the moment, 1929480ff55SMatthew Dillon * only leaf nodes. 193bf686dbeSMatthew Dillon */ 194bf686dbeSMatthew Dillon static int 19536f82b23SMatthew Dillon hammer_reblock_helper(struct hammer_ioc_reblock *reblock, 196bf686dbeSMatthew Dillon hammer_cursor_t cursor, hammer_btree_elm_t elm) 197bf686dbeSMatthew Dillon { 19843c665aeSMatthew Dillon hammer_mount_t hmp; 199bf686dbeSMatthew Dillon hammer_off_t tmp_offset; 200bf686dbeSMatthew Dillon int error; 201bf686dbeSMatthew Dillon int bytes; 202bf686dbeSMatthew Dillon int cur; 203bf3b416bSMatthew Dillon int iocflags; 204bf686dbeSMatthew Dillon 205bf686dbeSMatthew Dillon error = 0; 20643c665aeSMatthew Dillon hmp = cursor->trans->hmp; 207bf686dbeSMatthew Dillon 208bf686dbeSMatthew Dillon /* 209bf686dbeSMatthew Dillon * Reblock data. Note that data embedded in a record is reblocked 2102f85fa4dSMatthew Dillon * by the record reblock code. Data processing only occurs at leaf 2112f85fa4dSMatthew Dillon * nodes and for RECORD element types. 212bf686dbeSMatthew Dillon */ 2132f85fa4dSMatthew Dillon if (cursor->node->ondisk->type != HAMMER_BTREE_TYPE_LEAF) 2142f85fa4dSMatthew Dillon goto skip; 2152f85fa4dSMatthew Dillon if (elm->leaf.base.btype != HAMMER_BTREE_TYPE_RECORD) 2162f85fa4dSMatthew Dillon return(0); 217bf686dbeSMatthew Dillon tmp_offset = elm->leaf.data_offset; 218bf3b416bSMatthew Dillon if (tmp_offset == 0) 219bf3b416bSMatthew Dillon goto skip; 220bf3b416bSMatthew Dillon if (error) 221bf3b416bSMatthew Dillon goto skip; 222bf3b416bSMatthew Dillon 223bf3b416bSMatthew Dillon /* 224bf3b416bSMatthew Dillon * NOTE: Localization restrictions may also have been set-up, we can't 225bf3b416bSMatthew Dillon * just set the match flags willy-nilly here. 226bf3b416bSMatthew Dillon */ 227bf3b416bSMatthew Dillon switch(elm->leaf.base.rec_type) { 228bf3b416bSMatthew Dillon case HAMMER_RECTYPE_INODE: 229bf3b416bSMatthew Dillon iocflags = HAMMER_IOC_DO_INODES; 230bf3b416bSMatthew Dillon break; 231bf3b416bSMatthew Dillon case HAMMER_RECTYPE_EXT: 232bf3b416bSMatthew Dillon case HAMMER_RECTYPE_FIX: 233*ea434b6fSMatthew Dillon case HAMMER_RECTYPE_PFS: 234bf3b416bSMatthew Dillon case HAMMER_RECTYPE_DIRENTRY: 235bf3b416bSMatthew Dillon iocflags = HAMMER_IOC_DO_DIRS; 236bf3b416bSMatthew Dillon break; 237bf3b416bSMatthew Dillon case HAMMER_RECTYPE_DATA: 238bf3b416bSMatthew Dillon case HAMMER_RECTYPE_DB: 239bf3b416bSMatthew Dillon iocflags = HAMMER_IOC_DO_DATA; 240bf3b416bSMatthew Dillon break; 241bf3b416bSMatthew Dillon default: 242bf3b416bSMatthew Dillon iocflags = 0; 243bf3b416bSMatthew Dillon break; 244bf3b416bSMatthew Dillon } 245bf3b416bSMatthew Dillon if (reblock->head.flags & iocflags) { 246bf686dbeSMatthew Dillon ++reblock->data_count; 247bf686dbeSMatthew Dillon reblock->data_byte_count += elm->leaf.data_len; 24843c665aeSMatthew Dillon bytes = hammer_blockmap_getfree(hmp, tmp_offset, &cur, &error); 2496e1e8b6dSMatthew Dillon if (hammer_debug_general & 0x4000) 2502f85fa4dSMatthew Dillon kprintf("D %6d/%d\n", bytes, reblock->free_level); 251bf3b416bSMatthew Dillon if (error == 0 && (cur == 0 || reblock->free_level == 0) && 252bf3b416bSMatthew Dillon bytes >= reblock->free_level) { 25343c665aeSMatthew Dillon hammer_io_direct_uncache(hmp, &elm->leaf); 254bf686dbeSMatthew Dillon error = hammer_cursor_upgrade(cursor); 255bf686dbeSMatthew Dillon if (error == 0) { 25636f82b23SMatthew Dillon error = hammer_reblock_data(reblock, 257bf686dbeSMatthew Dillon cursor, elm); 258bf686dbeSMatthew Dillon } 259bf686dbeSMatthew Dillon if (error == 0) { 260bf686dbeSMatthew Dillon ++reblock->data_moves; 261bf686dbeSMatthew Dillon reblock->data_byte_moves += elm->leaf.data_len; 262bf686dbeSMatthew Dillon } 263bf686dbeSMatthew Dillon } 264bf686dbeSMatthew Dillon } 265bf686dbeSMatthew Dillon 2662f85fa4dSMatthew Dillon skip: 267bf686dbeSMatthew Dillon /* 2682f85fa4dSMatthew Dillon * Reblock a B-Tree internal or leaf node. 269bf686dbeSMatthew Dillon */ 270bf686dbeSMatthew Dillon tmp_offset = cursor->node->node_offset; 271bf3b416bSMatthew Dillon if (cursor->index == 0 && 272814387f6SMatthew Dillon error == 0 && (reblock->head.flags & HAMMER_IOC_DO_BTREE)) { 273bf686dbeSMatthew Dillon ++reblock->btree_count; 27443c665aeSMatthew Dillon bytes = hammer_blockmap_getfree(hmp, tmp_offset, &cur, &error); 2756e1e8b6dSMatthew Dillon if (hammer_debug_general & 0x4000) 2762f85fa4dSMatthew Dillon kprintf("B %6d/%d\n", bytes, reblock->free_level); 277bf3b416bSMatthew Dillon if (error == 0 && (cur == 0 || reblock->free_level == 0) && 278bf3b416bSMatthew Dillon bytes >= reblock->free_level) { 279bf686dbeSMatthew Dillon error = hammer_cursor_upgrade(cursor); 280bf686dbeSMatthew Dillon if (error == 0) { 281bf686dbeSMatthew Dillon if (cursor->parent) 282bf686dbeSMatthew Dillon elm = &cursor->parent->ondisk->elms[cursor->parent_index]; 283bf686dbeSMatthew Dillon else 284bf686dbeSMatthew Dillon elm = NULL; 2852f85fa4dSMatthew Dillon switch(cursor->node->ondisk->type) { 2862f85fa4dSMatthew Dillon case HAMMER_BTREE_TYPE_LEAF: 2872f85fa4dSMatthew Dillon error = hammer_reblock_leaf_node( 2882f85fa4dSMatthew Dillon reblock, cursor, elm); 2892f85fa4dSMatthew Dillon break; 2902f85fa4dSMatthew Dillon case HAMMER_BTREE_TYPE_INTERNAL: 2912f85fa4dSMatthew Dillon error = hammer_reblock_int_node( 2922f85fa4dSMatthew Dillon reblock, cursor, elm); 2932f85fa4dSMatthew Dillon break; 2942f85fa4dSMatthew Dillon default: 2952f85fa4dSMatthew Dillon panic("Illegal B-Tree node type"); 2962f85fa4dSMatthew Dillon } 297bf686dbeSMatthew Dillon } 298bf686dbeSMatthew Dillon if (error == 0) { 299bf686dbeSMatthew Dillon ++reblock->btree_moves; 300bf686dbeSMatthew Dillon } 301bf686dbeSMatthew Dillon } 302bf686dbeSMatthew Dillon } 303bf686dbeSMatthew Dillon 304bf686dbeSMatthew Dillon hammer_cursor_downgrade(cursor); 305bf686dbeSMatthew Dillon return(error); 306bf686dbeSMatthew Dillon } 307bf686dbeSMatthew Dillon 308bf686dbeSMatthew Dillon /* 309bf686dbeSMatthew Dillon * Reblock a record's data. Both the B-Tree element and record pointers 310bf686dbeSMatthew Dillon * to the data must be adjusted. 311bf686dbeSMatthew Dillon */ 312bf686dbeSMatthew Dillon static int 31336f82b23SMatthew Dillon hammer_reblock_data(struct hammer_ioc_reblock *reblock, 314bf686dbeSMatthew Dillon hammer_cursor_t cursor, hammer_btree_elm_t elm) 315bf686dbeSMatthew Dillon { 316bf686dbeSMatthew Dillon struct hammer_buffer *data_buffer = NULL; 317bf686dbeSMatthew Dillon hammer_off_t ndata_offset; 318bf686dbeSMatthew Dillon int error; 319bf686dbeSMatthew Dillon void *ndata; 320bf686dbeSMatthew Dillon 321bf686dbeSMatthew Dillon error = hammer_btree_extract(cursor, HAMMER_CURSOR_GET_DATA | 32211ad5adeSMatthew Dillon HAMMER_CURSOR_GET_LEAF); 323bf686dbeSMatthew Dillon if (error) 324bf686dbeSMatthew Dillon return (error); 32536f82b23SMatthew Dillon ndata = hammer_alloc_data(cursor->trans, elm->leaf.data_len, 326bf3b416bSMatthew Dillon elm->leaf.base.rec_type, 32736f82b23SMatthew Dillon &ndata_offset, &data_buffer, &error); 328bf686dbeSMatthew Dillon if (error) 329bf686dbeSMatthew Dillon goto done; 330bf686dbeSMatthew Dillon 331bf686dbeSMatthew Dillon /* 332bf686dbeSMatthew Dillon * Move the data 333bf686dbeSMatthew Dillon */ 33410a5d1baSMatthew Dillon hammer_modify_buffer(cursor->trans, data_buffer, NULL, 0); 335bf686dbeSMatthew Dillon bcopy(cursor->data, ndata, elm->leaf.data_len); 33610a5d1baSMatthew Dillon hammer_modify_buffer_done(data_buffer); 337bf686dbeSMatthew Dillon 33836f82b23SMatthew Dillon hammer_blockmap_free(cursor->trans, 33936f82b23SMatthew Dillon elm->leaf.data_offset, elm->leaf.data_len); 340bf686dbeSMatthew Dillon 34110a5d1baSMatthew Dillon hammer_modify_node(cursor->trans, cursor->node, 34210a5d1baSMatthew Dillon &elm->leaf.data_offset, sizeof(hammer_off_t)); 343bf686dbeSMatthew Dillon elm->leaf.data_offset = ndata_offset; 34410a5d1baSMatthew Dillon hammer_modify_node_done(cursor->node); 345bf686dbeSMatthew Dillon 346bf686dbeSMatthew Dillon done: 347bf686dbeSMatthew Dillon if (data_buffer) 348bf686dbeSMatthew Dillon hammer_rel_buffer(data_buffer, 0); 349bf686dbeSMatthew Dillon return (error); 350bf686dbeSMatthew Dillon } 351bf686dbeSMatthew Dillon 352bf686dbeSMatthew Dillon /* 3532f85fa4dSMatthew Dillon * Reblock a B-Tree leaf node. The parent must be adjusted to point to 3542f85fa4dSMatthew Dillon * the new copy of the leaf node. 355bf686dbeSMatthew Dillon * 3562f85fa4dSMatthew Dillon * elm is a pointer to the parent element pointing at cursor.node. 357bf686dbeSMatthew Dillon */ 358bf686dbeSMatthew Dillon static int 3592f85fa4dSMatthew Dillon hammer_reblock_leaf_node(struct hammer_ioc_reblock *reblock, 360bf686dbeSMatthew Dillon hammer_cursor_t cursor, hammer_btree_elm_t elm) 361bf686dbeSMatthew Dillon { 362bf686dbeSMatthew Dillon hammer_node_t onode; 363bf686dbeSMatthew Dillon hammer_node_t nnode; 364bf686dbeSMatthew Dillon int error; 365bf686dbeSMatthew Dillon 366bf686dbeSMatthew Dillon onode = cursor->node; 36736f82b23SMatthew Dillon nnode = hammer_alloc_btree(cursor->trans, &error); 3688d0efe43SMatthew Dillon 369bf686dbeSMatthew Dillon if (nnode == NULL) 370bf686dbeSMatthew Dillon return (error); 371bf686dbeSMatthew Dillon 372bf686dbeSMatthew Dillon /* 373bf686dbeSMatthew Dillon * Move the node 374bf686dbeSMatthew Dillon */ 37509ac686bSMatthew Dillon hammer_lock_ex(&nnode->lock); 37609ac686bSMatthew Dillon hammer_modify_node_noundo(cursor->trans, nnode); 377bf686dbeSMatthew Dillon bcopy(onode->ondisk, nnode->ondisk, sizeof(*nnode->ondisk)); 378bf686dbeSMatthew Dillon 379bf686dbeSMatthew Dillon if (elm) { 380bf686dbeSMatthew Dillon /* 381bf686dbeSMatthew Dillon * We are not the root of the B-Tree 382bf686dbeSMatthew Dillon */ 38336f82b23SMatthew Dillon hammer_modify_node(cursor->trans, cursor->parent, 384bf686dbeSMatthew Dillon &elm->internal.subtree_offset, 385bf686dbeSMatthew Dillon sizeof(elm->internal.subtree_offset)); 386bf686dbeSMatthew Dillon elm->internal.subtree_offset = nnode->node_offset; 38710a5d1baSMatthew Dillon hammer_modify_node_done(cursor->parent); 388bf686dbeSMatthew Dillon } else { 389bf686dbeSMatthew Dillon /* 390bf686dbeSMatthew Dillon * We are the root of the B-Tree 391bf686dbeSMatthew Dillon */ 392bf686dbeSMatthew Dillon hammer_volume_t volume; 393bf686dbeSMatthew Dillon 39436f82b23SMatthew Dillon volume = hammer_get_root_volume(cursor->trans->hmp, &error); 395bf686dbeSMatthew Dillon KKASSERT(error == 0); 396bf686dbeSMatthew Dillon 397e8599db1SMatthew Dillon hammer_modify_volume_field(cursor->trans, volume, 398e8599db1SMatthew Dillon vol0_btree_root); 399bf686dbeSMatthew Dillon volume->ondisk->vol0_btree_root = nnode->node_offset; 40010a5d1baSMatthew Dillon hammer_modify_volume_done(volume); 401bf686dbeSMatthew Dillon hammer_rel_volume(volume, 0); 402bf686dbeSMatthew Dillon } 403bf686dbeSMatthew Dillon 404b3bad96fSMatthew Dillon hammer_cursor_replaced_node(onode, nnode); 40536f82b23SMatthew Dillon hammer_delete_node(cursor->trans, onode); 406bf686dbeSMatthew Dillon 407b58c6388SMatthew Dillon if (hammer_debug_general & 0x4000) { 4082f85fa4dSMatthew Dillon kprintf("REBLOCK LNODE %016llx -> %016llx\n", 409bf686dbeSMatthew Dillon onode->node_offset, nnode->node_offset); 410b58c6388SMatthew Dillon } 4118d0efe43SMatthew Dillon hammer_modify_node_done(nnode); 412bf686dbeSMatthew Dillon cursor->node = nnode; 41309ac686bSMatthew Dillon 41409ac686bSMatthew Dillon hammer_unlock(&onode->lock); 415bf686dbeSMatthew Dillon hammer_rel_node(onode); 416bf686dbeSMatthew Dillon 417bf686dbeSMatthew Dillon return (error); 418bf686dbeSMatthew Dillon } 419bf686dbeSMatthew Dillon 4202f85fa4dSMatthew Dillon /* 4212f85fa4dSMatthew Dillon * Reblock a B-Tree internal node. The parent must be adjusted to point to 4222f85fa4dSMatthew Dillon * the new copy of the internal node, and the node's children's parent 4232f85fa4dSMatthew Dillon * pointers must also be adjusted to point to the new copy. 4242f85fa4dSMatthew Dillon * 4252f85fa4dSMatthew Dillon * elm is a pointer to the parent element pointing at cursor.node. 4262f85fa4dSMatthew Dillon */ 4272f85fa4dSMatthew Dillon static int 4282f85fa4dSMatthew Dillon hammer_reblock_int_node(struct hammer_ioc_reblock *reblock, 4292f85fa4dSMatthew Dillon hammer_cursor_t cursor, hammer_btree_elm_t elm) 4302f85fa4dSMatthew Dillon { 4312f85fa4dSMatthew Dillon hammer_node_locklist_t locklist = NULL; 4322f85fa4dSMatthew Dillon hammer_node_t onode; 4332f85fa4dSMatthew Dillon hammer_node_t nnode; 4342f85fa4dSMatthew Dillon int error; 4352f85fa4dSMatthew Dillon int i; 4362f85fa4dSMatthew Dillon 4372f85fa4dSMatthew Dillon error = hammer_btree_lock_children(cursor, &locklist); 4382f85fa4dSMatthew Dillon if (error) 4392f85fa4dSMatthew Dillon goto done; 4402f85fa4dSMatthew Dillon 4412f85fa4dSMatthew Dillon onode = cursor->node; 4422f85fa4dSMatthew Dillon nnode = hammer_alloc_btree(cursor->trans, &error); 4432f85fa4dSMatthew Dillon 4442f85fa4dSMatthew Dillon if (nnode == NULL) 4452f85fa4dSMatthew Dillon goto done; 4462f85fa4dSMatthew Dillon 4472f85fa4dSMatthew Dillon /* 4482f85fa4dSMatthew Dillon * Move the node. Adjust the parent's pointer to us first. 4492f85fa4dSMatthew Dillon */ 4502f85fa4dSMatthew Dillon hammer_lock_ex(&nnode->lock); 4512f85fa4dSMatthew Dillon hammer_modify_node_noundo(cursor->trans, nnode); 4522f85fa4dSMatthew Dillon bcopy(onode->ondisk, nnode->ondisk, sizeof(*nnode->ondisk)); 4532f85fa4dSMatthew Dillon 4542f85fa4dSMatthew Dillon if (elm) { 4552f85fa4dSMatthew Dillon /* 4562f85fa4dSMatthew Dillon * We are not the root of the B-Tree 4572f85fa4dSMatthew Dillon */ 4582f85fa4dSMatthew Dillon hammer_modify_node(cursor->trans, cursor->parent, 4592f85fa4dSMatthew Dillon &elm->internal.subtree_offset, 4602f85fa4dSMatthew Dillon sizeof(elm->internal.subtree_offset)); 4612f85fa4dSMatthew Dillon elm->internal.subtree_offset = nnode->node_offset; 4622f85fa4dSMatthew Dillon hammer_modify_node_done(cursor->parent); 4632f85fa4dSMatthew Dillon } else { 4642f85fa4dSMatthew Dillon /* 4652f85fa4dSMatthew Dillon * We are the root of the B-Tree 4662f85fa4dSMatthew Dillon */ 4672f85fa4dSMatthew Dillon hammer_volume_t volume; 4682f85fa4dSMatthew Dillon 4692f85fa4dSMatthew Dillon volume = hammer_get_root_volume(cursor->trans->hmp, &error); 4702f85fa4dSMatthew Dillon KKASSERT(error == 0); 4712f85fa4dSMatthew Dillon 4722f85fa4dSMatthew Dillon hammer_modify_volume_field(cursor->trans, volume, 4732f85fa4dSMatthew Dillon vol0_btree_root); 4742f85fa4dSMatthew Dillon volume->ondisk->vol0_btree_root = nnode->node_offset; 4752f85fa4dSMatthew Dillon hammer_modify_volume_done(volume); 4762f85fa4dSMatthew Dillon hammer_rel_volume(volume, 0); 4772f85fa4dSMatthew Dillon } 4782f85fa4dSMatthew Dillon 4792f85fa4dSMatthew Dillon /* 4802f85fa4dSMatthew Dillon * Now adjust our children's pointers to us. 4812f85fa4dSMatthew Dillon */ 4822f85fa4dSMatthew Dillon for (i = 0; i < nnode->ondisk->count; ++i) { 4832f85fa4dSMatthew Dillon elm = &nnode->ondisk->elms[i]; 4842f85fa4dSMatthew Dillon error = btree_set_parent(cursor->trans, nnode, elm); 4852f85fa4dSMatthew Dillon if (error) 4862f85fa4dSMatthew Dillon panic("reblock internal node: fixup problem"); 4872f85fa4dSMatthew Dillon } 4882f85fa4dSMatthew Dillon 4892f85fa4dSMatthew Dillon /* 4902f85fa4dSMatthew Dillon * Clean up. 4912f85fa4dSMatthew Dillon * 4922f85fa4dSMatthew Dillon * The new node replaces the current node in the cursor. The cursor 4932f85fa4dSMatthew Dillon * expects it to be locked so leave it locked. Discard onode. 4942f85fa4dSMatthew Dillon */ 495b3bad96fSMatthew Dillon hammer_cursor_replaced_node(onode, nnode); 4962f85fa4dSMatthew Dillon hammer_delete_node(cursor->trans, onode); 4972f85fa4dSMatthew Dillon 4982f85fa4dSMatthew Dillon if (hammer_debug_general & 0x4000) { 4992f85fa4dSMatthew Dillon kprintf("REBLOCK INODE %016llx -> %016llx\n", 5002f85fa4dSMatthew Dillon onode->node_offset, nnode->node_offset); 5012f85fa4dSMatthew Dillon } 5022f85fa4dSMatthew Dillon hammer_modify_node_done(nnode); 5032f85fa4dSMatthew Dillon cursor->node = nnode; 5042f85fa4dSMatthew Dillon 5052f85fa4dSMatthew Dillon hammer_unlock(&onode->lock); 5062f85fa4dSMatthew Dillon hammer_rel_node(onode); 5072f85fa4dSMatthew Dillon 5082f85fa4dSMatthew Dillon done: 5092f85fa4dSMatthew Dillon hammer_btree_unlock_children(&locklist); 5102f85fa4dSMatthew Dillon return (error); 5112f85fa4dSMatthew Dillon } 5122f85fa4dSMatthew Dillon 513