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*dd94f1b1SMatthew Dillon * $DragonFly: src/sys/vfs/hammer/hammer_reblock.c,v 1.21 2008/06/24 17:38:17 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; 65bf686dbeSMatthew Dillon 66*dd94f1b1SMatthew Dillon if ((reblock->key_beg.localization | reblock->key_end.localization) & 67*dd94f1b1SMatthew Dillon HAMMER_LOCALIZE_PSEUDOFS_MASK) { 68*dd94f1b1SMatthew Dillon return(EINVAL); 69*dd94f1b1SMatthew Dillon } 70*dd94f1b1SMatthew Dillon if (reblock->key_beg.obj_id >= reblock->key_end.obj_id) 71bf686dbeSMatthew Dillon return(EINVAL); 72bf686dbeSMatthew Dillon if (reblock->free_level < 0) 73bf686dbeSMatthew Dillon return(EINVAL); 74bf686dbeSMatthew Dillon 75*dd94f1b1SMatthew Dillon reblock->key_cur = reblock->key_beg; 76*dd94f1b1SMatthew Dillon reblock->key_cur.localization += ip->obj_localization; 77814387f6SMatthew Dillon 78bf686dbeSMatthew Dillon retry: 794e17f465SMatthew Dillon error = hammer_init_cursor(trans, &cursor, NULL, NULL); 80bf686dbeSMatthew Dillon if (error) { 81bf686dbeSMatthew Dillon hammer_done_cursor(&cursor); 82*dd94f1b1SMatthew Dillon goto failed; 83bf686dbeSMatthew Dillon } 84*dd94f1b1SMatthew Dillon cursor.key_beg.localization = reblock->key_cur.localization; 85*dd94f1b1SMatthew Dillon cursor.key_beg.obj_id = reblock->key_cur.obj_id; 86bf686dbeSMatthew Dillon cursor.key_beg.key = HAMMER_MIN_KEY; 87bf686dbeSMatthew Dillon cursor.key_beg.create_tid = 1; 88bf686dbeSMatthew Dillon cursor.key_beg.delete_tid = 0; 89bf686dbeSMatthew Dillon cursor.key_beg.rec_type = HAMMER_MIN_RECTYPE; 90bf686dbeSMatthew Dillon cursor.key_beg.obj_type = 0; 91bf686dbeSMatthew Dillon 92*dd94f1b1SMatthew Dillon cursor.key_end.localization = reblock->key_end.localization + 93*dd94f1b1SMatthew Dillon ip->obj_localization; 94*dd94f1b1SMatthew Dillon cursor.key_end.obj_id = reblock->key_end.obj_id; 95bf686dbeSMatthew Dillon cursor.key_end.key = HAMMER_MAX_KEY; 96bf686dbeSMatthew Dillon cursor.key_end.create_tid = HAMMER_MAX_TID - 1; 97bf686dbeSMatthew Dillon cursor.key_end.delete_tid = 0; 98bf686dbeSMatthew Dillon cursor.key_end.rec_type = HAMMER_MAX_RECTYPE; 99bf686dbeSMatthew Dillon cursor.key_end.obj_type = 0; 100bf686dbeSMatthew Dillon 101bf686dbeSMatthew Dillon cursor.flags |= HAMMER_CURSOR_END_INCLUSIVE; 1029480ff55SMatthew Dillon cursor.flags |= HAMMER_CURSOR_BACKEND; 103bf686dbeSMatthew Dillon 1042f85fa4dSMatthew Dillon /* 1052f85fa4dSMatthew Dillon * This flag allows the btree scan code to return internal nodes, 1062f85fa4dSMatthew Dillon * so we can reblock them in addition to the leafs. Only specify it 1072f85fa4dSMatthew Dillon * if we intend to reblock B-Tree nodes. 1082f85fa4dSMatthew Dillon */ 1092f85fa4dSMatthew Dillon if (reblock->head.flags & HAMMER_IOC_DO_BTREE) 1102f85fa4dSMatthew Dillon cursor.flags |= HAMMER_CURSOR_REBLOCKING; 1112f85fa4dSMatthew Dillon 112bf686dbeSMatthew Dillon error = hammer_btree_first(&cursor); 113bf686dbeSMatthew Dillon while (error == 0) { 1142f85fa4dSMatthew Dillon /* 1152f85fa4dSMatthew Dillon * Internal or Leaf node 1162f85fa4dSMatthew Dillon */ 117bf686dbeSMatthew Dillon elm = &cursor.node->ondisk->elms[cursor.index]; 118*dd94f1b1SMatthew Dillon reblock->key_cur.obj_id = elm->base.obj_id; 119*dd94f1b1SMatthew Dillon reblock->key_cur.localization = elm->base.localization; 120bf686dbeSMatthew Dillon 1219480ff55SMatthew Dillon /* 1229f5097dcSMatthew Dillon * Yield to more important tasks 1239f5097dcSMatthew Dillon */ 1249f5097dcSMatthew Dillon if ((error = hammer_signal_check(trans->hmp)) != 0) 1259f5097dcSMatthew Dillon break; 1269f5097dcSMatthew Dillon if (trans->hmp->sync_lock.wanted) { 1279f5097dcSMatthew Dillon tsleep(trans, 0, "hmrslo", hz / 10); 1289f5097dcSMatthew Dillon } 1299f5097dcSMatthew Dillon if (trans->hmp->locked_dirty_count + 1309f5097dcSMatthew Dillon trans->hmp->io_running_count > hammer_limit_dirtybufs) { 1319f5097dcSMatthew Dillon hammer_flusher_async(trans->hmp); 1329f5097dcSMatthew Dillon tsleep(trans, 0, "hmrslo", hz / 10); 1339f5097dcSMatthew Dillon } 1349f5097dcSMatthew Dillon 1359f5097dcSMatthew Dillon /* 1369480ff55SMatthew Dillon * Acquiring the sync_lock prevents the operation from 1379480ff55SMatthew Dillon * crossing a synchronization boundary. 13809ac686bSMatthew Dillon * 13909ac686bSMatthew Dillon * NOTE: cursor.node may have changed on return. 1409480ff55SMatthew Dillon */ 1412f85fa4dSMatthew Dillon hammer_sync_lock_sh(trans); 14236f82b23SMatthew Dillon error = hammer_reblock_helper(reblock, &cursor, elm); 1432f85fa4dSMatthew Dillon hammer_sync_unlock(trans); 144bf686dbeSMatthew Dillon if (error == 0) { 145bf686dbeSMatthew Dillon cursor.flags |= HAMMER_CURSOR_ATEDISK; 146bf686dbeSMatthew Dillon error = hammer_btree_iterate(&cursor); 147bf686dbeSMatthew Dillon } 148bf686dbeSMatthew Dillon } 149bf686dbeSMatthew Dillon if (error == ENOENT) 150bf686dbeSMatthew Dillon error = 0; 151bf686dbeSMatthew Dillon hammer_done_cursor(&cursor); 152bf686dbeSMatthew Dillon if (error == EDEADLK) 153bf686dbeSMatthew Dillon goto retry; 15419619882SMatthew Dillon if (error == EINTR) { 15519619882SMatthew Dillon reblock->head.flags |= HAMMER_IOC_HEAD_INTR; 15619619882SMatthew Dillon error = 0; 15719619882SMatthew Dillon } 158*dd94f1b1SMatthew Dillon failed: 159*dd94f1b1SMatthew Dillon reblock->key_cur.localization &= HAMMER_LOCALIZE_MASK; 160bf686dbeSMatthew Dillon return(error); 161bf686dbeSMatthew Dillon } 162bf686dbeSMatthew Dillon 163bf686dbeSMatthew Dillon /* 164bf686dbeSMatthew Dillon * Reblock the B-Tree (leaf) node, record, and/or data if necessary. 165bf686dbeSMatthew Dillon * 1669480ff55SMatthew Dillon * XXX We have no visibility into internal B-Tree nodes at the moment, 1679480ff55SMatthew Dillon * only leaf nodes. 168bf686dbeSMatthew Dillon */ 169bf686dbeSMatthew Dillon static int 17036f82b23SMatthew Dillon hammer_reblock_helper(struct hammer_ioc_reblock *reblock, 171bf686dbeSMatthew Dillon hammer_cursor_t cursor, hammer_btree_elm_t elm) 172bf686dbeSMatthew Dillon { 17343c665aeSMatthew Dillon hammer_mount_t hmp; 174bf686dbeSMatthew Dillon hammer_off_t tmp_offset; 175bf686dbeSMatthew Dillon int error; 176bf686dbeSMatthew Dillon int bytes; 177bf686dbeSMatthew Dillon int cur; 178bf3b416bSMatthew Dillon int iocflags; 179bf686dbeSMatthew Dillon 180bf686dbeSMatthew Dillon error = 0; 18143c665aeSMatthew Dillon hmp = cursor->trans->hmp; 182bf686dbeSMatthew Dillon 183bf686dbeSMatthew Dillon /* 184bf686dbeSMatthew Dillon * Reblock data. Note that data embedded in a record is reblocked 1852f85fa4dSMatthew Dillon * by the record reblock code. Data processing only occurs at leaf 1862f85fa4dSMatthew Dillon * nodes and for RECORD element types. 187bf686dbeSMatthew Dillon */ 1882f85fa4dSMatthew Dillon if (cursor->node->ondisk->type != HAMMER_BTREE_TYPE_LEAF) 1892f85fa4dSMatthew Dillon goto skip; 1902f85fa4dSMatthew Dillon if (elm->leaf.base.btype != HAMMER_BTREE_TYPE_RECORD) 1912f85fa4dSMatthew Dillon return(0); 192bf686dbeSMatthew Dillon tmp_offset = elm->leaf.data_offset; 193bf3b416bSMatthew Dillon if (tmp_offset == 0) 194bf3b416bSMatthew Dillon goto skip; 195bf3b416bSMatthew Dillon if (error) 196bf3b416bSMatthew Dillon goto skip; 197bf3b416bSMatthew Dillon 198bf3b416bSMatthew Dillon /* 199bf3b416bSMatthew Dillon * NOTE: Localization restrictions may also have been set-up, we can't 200bf3b416bSMatthew Dillon * just set the match flags willy-nilly here. 201bf3b416bSMatthew Dillon */ 202bf3b416bSMatthew Dillon switch(elm->leaf.base.rec_type) { 203bf3b416bSMatthew Dillon case HAMMER_RECTYPE_INODE: 204bf3b416bSMatthew Dillon iocflags = HAMMER_IOC_DO_INODES; 205bf3b416bSMatthew Dillon break; 206bf3b416bSMatthew Dillon case HAMMER_RECTYPE_EXT: 207bf3b416bSMatthew Dillon case HAMMER_RECTYPE_FIX: 208bf3b416bSMatthew Dillon case HAMMER_RECTYPE_DIRENTRY: 209bf3b416bSMatthew Dillon iocflags = HAMMER_IOC_DO_DIRS; 210bf3b416bSMatthew Dillon break; 211bf3b416bSMatthew Dillon case HAMMER_RECTYPE_DATA: 212bf3b416bSMatthew Dillon case HAMMER_RECTYPE_DB: 213bf3b416bSMatthew Dillon iocflags = HAMMER_IOC_DO_DATA; 214bf3b416bSMatthew Dillon break; 215bf3b416bSMatthew Dillon default: 216bf3b416bSMatthew Dillon iocflags = 0; 217bf3b416bSMatthew Dillon break; 218bf3b416bSMatthew Dillon } 219bf3b416bSMatthew Dillon if (reblock->head.flags & iocflags) { 220bf686dbeSMatthew Dillon ++reblock->data_count; 221bf686dbeSMatthew Dillon reblock->data_byte_count += elm->leaf.data_len; 22243c665aeSMatthew Dillon bytes = hammer_blockmap_getfree(hmp, tmp_offset, &cur, &error); 2236e1e8b6dSMatthew Dillon if (hammer_debug_general & 0x4000) 2242f85fa4dSMatthew Dillon kprintf("D %6d/%d\n", bytes, reblock->free_level); 225bf3b416bSMatthew Dillon if (error == 0 && (cur == 0 || reblock->free_level == 0) && 226bf3b416bSMatthew Dillon bytes >= reblock->free_level) { 22743c665aeSMatthew Dillon hammer_io_direct_uncache(hmp, &elm->leaf); 228bf686dbeSMatthew Dillon error = hammer_cursor_upgrade(cursor); 229bf686dbeSMatthew Dillon if (error == 0) { 23036f82b23SMatthew Dillon error = hammer_reblock_data(reblock, 231bf686dbeSMatthew Dillon cursor, elm); 232bf686dbeSMatthew Dillon } 233bf686dbeSMatthew Dillon if (error == 0) { 234bf686dbeSMatthew Dillon ++reblock->data_moves; 235bf686dbeSMatthew Dillon reblock->data_byte_moves += elm->leaf.data_len; 236bf686dbeSMatthew Dillon } 237bf686dbeSMatthew Dillon } 238bf686dbeSMatthew Dillon } 239bf686dbeSMatthew Dillon 2402f85fa4dSMatthew Dillon skip: 241bf686dbeSMatthew Dillon /* 2422f85fa4dSMatthew Dillon * Reblock a B-Tree internal or leaf node. 243bf686dbeSMatthew Dillon */ 244bf686dbeSMatthew Dillon tmp_offset = cursor->node->node_offset; 245bf3b416bSMatthew Dillon if (cursor->index == 0 && 246814387f6SMatthew Dillon error == 0 && (reblock->head.flags & HAMMER_IOC_DO_BTREE)) { 247bf686dbeSMatthew Dillon ++reblock->btree_count; 24843c665aeSMatthew Dillon bytes = hammer_blockmap_getfree(hmp, tmp_offset, &cur, &error); 2496e1e8b6dSMatthew Dillon if (hammer_debug_general & 0x4000) 2502f85fa4dSMatthew Dillon kprintf("B %6d/%d\n", bytes, reblock->free_level); 251bf3b416bSMatthew Dillon if (error == 0 && (cur == 0 || reblock->free_level == 0) && 252bf3b416bSMatthew Dillon bytes >= reblock->free_level) { 253bf686dbeSMatthew Dillon error = hammer_cursor_upgrade(cursor); 254bf686dbeSMatthew Dillon if (error == 0) { 255bf686dbeSMatthew Dillon if (cursor->parent) 256bf686dbeSMatthew Dillon elm = &cursor->parent->ondisk->elms[cursor->parent_index]; 257bf686dbeSMatthew Dillon else 258bf686dbeSMatthew Dillon elm = NULL; 2592f85fa4dSMatthew Dillon switch(cursor->node->ondisk->type) { 2602f85fa4dSMatthew Dillon case HAMMER_BTREE_TYPE_LEAF: 2612f85fa4dSMatthew Dillon error = hammer_reblock_leaf_node( 2622f85fa4dSMatthew Dillon reblock, cursor, elm); 2632f85fa4dSMatthew Dillon break; 2642f85fa4dSMatthew Dillon case HAMMER_BTREE_TYPE_INTERNAL: 2652f85fa4dSMatthew Dillon error = hammer_reblock_int_node( 2662f85fa4dSMatthew Dillon reblock, cursor, elm); 2672f85fa4dSMatthew Dillon break; 2682f85fa4dSMatthew Dillon default: 2692f85fa4dSMatthew Dillon panic("Illegal B-Tree node type"); 2702f85fa4dSMatthew Dillon } 271bf686dbeSMatthew Dillon } 272bf686dbeSMatthew Dillon if (error == 0) { 273bf686dbeSMatthew Dillon ++reblock->btree_moves; 274bf686dbeSMatthew Dillon } 275bf686dbeSMatthew Dillon } 276bf686dbeSMatthew Dillon } 277bf686dbeSMatthew Dillon 278bf686dbeSMatthew Dillon hammer_cursor_downgrade(cursor); 279bf686dbeSMatthew Dillon return(error); 280bf686dbeSMatthew Dillon } 281bf686dbeSMatthew Dillon 282bf686dbeSMatthew Dillon /* 283bf686dbeSMatthew Dillon * Reblock a record's data. Both the B-Tree element and record pointers 284bf686dbeSMatthew Dillon * to the data must be adjusted. 285bf686dbeSMatthew Dillon */ 286bf686dbeSMatthew Dillon static int 28736f82b23SMatthew Dillon hammer_reblock_data(struct hammer_ioc_reblock *reblock, 288bf686dbeSMatthew Dillon hammer_cursor_t cursor, hammer_btree_elm_t elm) 289bf686dbeSMatthew Dillon { 290bf686dbeSMatthew Dillon struct hammer_buffer *data_buffer = NULL; 291bf686dbeSMatthew Dillon hammer_off_t ndata_offset; 292bf686dbeSMatthew Dillon int error; 293bf686dbeSMatthew Dillon void *ndata; 294bf686dbeSMatthew Dillon 295bf686dbeSMatthew Dillon error = hammer_btree_extract(cursor, HAMMER_CURSOR_GET_DATA | 29611ad5adeSMatthew Dillon HAMMER_CURSOR_GET_LEAF); 297bf686dbeSMatthew Dillon if (error) 298bf686dbeSMatthew Dillon return (error); 29936f82b23SMatthew Dillon ndata = hammer_alloc_data(cursor->trans, elm->leaf.data_len, 300bf3b416bSMatthew Dillon elm->leaf.base.rec_type, 30136f82b23SMatthew Dillon &ndata_offset, &data_buffer, &error); 302bf686dbeSMatthew Dillon if (error) 303bf686dbeSMatthew Dillon goto done; 304bf686dbeSMatthew Dillon 305bf686dbeSMatthew Dillon /* 306bf686dbeSMatthew Dillon * Move the data 307bf686dbeSMatthew Dillon */ 30810a5d1baSMatthew Dillon hammer_modify_buffer(cursor->trans, data_buffer, NULL, 0); 309bf686dbeSMatthew Dillon bcopy(cursor->data, ndata, elm->leaf.data_len); 31010a5d1baSMatthew Dillon hammer_modify_buffer_done(data_buffer); 311bf686dbeSMatthew Dillon 31236f82b23SMatthew Dillon hammer_blockmap_free(cursor->trans, 31336f82b23SMatthew Dillon elm->leaf.data_offset, elm->leaf.data_len); 314bf686dbeSMatthew Dillon 31510a5d1baSMatthew Dillon hammer_modify_node(cursor->trans, cursor->node, 31610a5d1baSMatthew Dillon &elm->leaf.data_offset, sizeof(hammer_off_t)); 317bf686dbeSMatthew Dillon elm->leaf.data_offset = ndata_offset; 31810a5d1baSMatthew Dillon hammer_modify_node_done(cursor->node); 319bf686dbeSMatthew Dillon 320bf686dbeSMatthew Dillon done: 321bf686dbeSMatthew Dillon if (data_buffer) 322bf686dbeSMatthew Dillon hammer_rel_buffer(data_buffer, 0); 323bf686dbeSMatthew Dillon return (error); 324bf686dbeSMatthew Dillon } 325bf686dbeSMatthew Dillon 326bf686dbeSMatthew Dillon /* 3272f85fa4dSMatthew Dillon * Reblock a B-Tree leaf node. The parent must be adjusted to point to 3282f85fa4dSMatthew Dillon * the new copy of the leaf node. 329bf686dbeSMatthew Dillon * 3302f85fa4dSMatthew Dillon * elm is a pointer to the parent element pointing at cursor.node. 331bf686dbeSMatthew Dillon */ 332bf686dbeSMatthew Dillon static int 3332f85fa4dSMatthew Dillon hammer_reblock_leaf_node(struct hammer_ioc_reblock *reblock, 334bf686dbeSMatthew Dillon hammer_cursor_t cursor, hammer_btree_elm_t elm) 335bf686dbeSMatthew Dillon { 336bf686dbeSMatthew Dillon hammer_node_t onode; 337bf686dbeSMatthew Dillon hammer_node_t nnode; 338bf686dbeSMatthew Dillon int error; 339bf686dbeSMatthew Dillon 340bf686dbeSMatthew Dillon onode = cursor->node; 34136f82b23SMatthew Dillon nnode = hammer_alloc_btree(cursor->trans, &error); 3428d0efe43SMatthew Dillon 343bf686dbeSMatthew Dillon if (nnode == NULL) 344bf686dbeSMatthew Dillon return (error); 345bf686dbeSMatthew Dillon 346bf686dbeSMatthew Dillon /* 347bf686dbeSMatthew Dillon * Move the node 348bf686dbeSMatthew Dillon */ 34909ac686bSMatthew Dillon hammer_lock_ex(&nnode->lock); 35009ac686bSMatthew Dillon hammer_modify_node_noundo(cursor->trans, nnode); 351bf686dbeSMatthew Dillon bcopy(onode->ondisk, nnode->ondisk, sizeof(*nnode->ondisk)); 352bf686dbeSMatthew Dillon 353bf686dbeSMatthew Dillon if (elm) { 354bf686dbeSMatthew Dillon /* 355bf686dbeSMatthew Dillon * We are not the root of the B-Tree 356bf686dbeSMatthew Dillon */ 35736f82b23SMatthew Dillon hammer_modify_node(cursor->trans, cursor->parent, 358bf686dbeSMatthew Dillon &elm->internal.subtree_offset, 359bf686dbeSMatthew Dillon sizeof(elm->internal.subtree_offset)); 360bf686dbeSMatthew Dillon elm->internal.subtree_offset = nnode->node_offset; 36110a5d1baSMatthew Dillon hammer_modify_node_done(cursor->parent); 362bf686dbeSMatthew Dillon } else { 363bf686dbeSMatthew Dillon /* 364bf686dbeSMatthew Dillon * We are the root of the B-Tree 365bf686dbeSMatthew Dillon */ 366bf686dbeSMatthew Dillon hammer_volume_t volume; 367bf686dbeSMatthew Dillon 36836f82b23SMatthew Dillon volume = hammer_get_root_volume(cursor->trans->hmp, &error); 369bf686dbeSMatthew Dillon KKASSERT(error == 0); 370bf686dbeSMatthew Dillon 371e8599db1SMatthew Dillon hammer_modify_volume_field(cursor->trans, volume, 372e8599db1SMatthew Dillon vol0_btree_root); 373bf686dbeSMatthew Dillon volume->ondisk->vol0_btree_root = nnode->node_offset; 37410a5d1baSMatthew Dillon hammer_modify_volume_done(volume); 375bf686dbeSMatthew Dillon hammer_rel_volume(volume, 0); 376bf686dbeSMatthew Dillon } 377bf686dbeSMatthew Dillon 37836f82b23SMatthew Dillon hammer_delete_node(cursor->trans, onode); 379bf686dbeSMatthew Dillon 380b58c6388SMatthew Dillon if (hammer_debug_general & 0x4000) { 3812f85fa4dSMatthew Dillon kprintf("REBLOCK LNODE %016llx -> %016llx\n", 382bf686dbeSMatthew Dillon onode->node_offset, nnode->node_offset); 383b58c6388SMatthew Dillon } 3848d0efe43SMatthew Dillon hammer_modify_node_done(nnode); 385bf686dbeSMatthew Dillon cursor->node = nnode; 38609ac686bSMatthew Dillon 38709ac686bSMatthew Dillon hammer_unlock(&onode->lock); 388bf686dbeSMatthew Dillon hammer_rel_node(onode); 389bf686dbeSMatthew Dillon 390bf686dbeSMatthew Dillon return (error); 391bf686dbeSMatthew Dillon } 392bf686dbeSMatthew Dillon 3932f85fa4dSMatthew Dillon /* 3942f85fa4dSMatthew Dillon * Reblock a B-Tree internal node. The parent must be adjusted to point to 3952f85fa4dSMatthew Dillon * the new copy of the internal node, and the node's children's parent 3962f85fa4dSMatthew Dillon * pointers must also be adjusted to point to the new copy. 3972f85fa4dSMatthew Dillon * 3982f85fa4dSMatthew Dillon * elm is a pointer to the parent element pointing at cursor.node. 3992f85fa4dSMatthew Dillon */ 4002f85fa4dSMatthew Dillon static int 4012f85fa4dSMatthew Dillon hammer_reblock_int_node(struct hammer_ioc_reblock *reblock, 4022f85fa4dSMatthew Dillon hammer_cursor_t cursor, hammer_btree_elm_t elm) 4032f85fa4dSMatthew Dillon { 4042f85fa4dSMatthew Dillon hammer_node_locklist_t locklist = NULL; 4052f85fa4dSMatthew Dillon hammer_node_t onode; 4062f85fa4dSMatthew Dillon hammer_node_t nnode; 4072f85fa4dSMatthew Dillon int error; 4082f85fa4dSMatthew Dillon int i; 4092f85fa4dSMatthew Dillon 4102f85fa4dSMatthew Dillon error = hammer_btree_lock_children(cursor, &locklist); 4112f85fa4dSMatthew Dillon if (error) 4122f85fa4dSMatthew Dillon goto done; 4132f85fa4dSMatthew Dillon 4142f85fa4dSMatthew Dillon onode = cursor->node; 4152f85fa4dSMatthew Dillon nnode = hammer_alloc_btree(cursor->trans, &error); 4162f85fa4dSMatthew Dillon 4172f85fa4dSMatthew Dillon if (nnode == NULL) 4182f85fa4dSMatthew Dillon goto done; 4192f85fa4dSMatthew Dillon 4202f85fa4dSMatthew Dillon /* 4212f85fa4dSMatthew Dillon * Move the node. Adjust the parent's pointer to us first. 4222f85fa4dSMatthew Dillon */ 4232f85fa4dSMatthew Dillon hammer_lock_ex(&nnode->lock); 4242f85fa4dSMatthew Dillon hammer_modify_node_noundo(cursor->trans, nnode); 4252f85fa4dSMatthew Dillon bcopy(onode->ondisk, nnode->ondisk, sizeof(*nnode->ondisk)); 4262f85fa4dSMatthew Dillon 4272f85fa4dSMatthew Dillon if (elm) { 4282f85fa4dSMatthew Dillon /* 4292f85fa4dSMatthew Dillon * We are not the root of the B-Tree 4302f85fa4dSMatthew Dillon */ 4312f85fa4dSMatthew Dillon hammer_modify_node(cursor->trans, cursor->parent, 4322f85fa4dSMatthew Dillon &elm->internal.subtree_offset, 4332f85fa4dSMatthew Dillon sizeof(elm->internal.subtree_offset)); 4342f85fa4dSMatthew Dillon elm->internal.subtree_offset = nnode->node_offset; 4352f85fa4dSMatthew Dillon hammer_modify_node_done(cursor->parent); 4362f85fa4dSMatthew Dillon } else { 4372f85fa4dSMatthew Dillon /* 4382f85fa4dSMatthew Dillon * We are the root of the B-Tree 4392f85fa4dSMatthew Dillon */ 4402f85fa4dSMatthew Dillon hammer_volume_t volume; 4412f85fa4dSMatthew Dillon 4422f85fa4dSMatthew Dillon volume = hammer_get_root_volume(cursor->trans->hmp, &error); 4432f85fa4dSMatthew Dillon KKASSERT(error == 0); 4442f85fa4dSMatthew Dillon 4452f85fa4dSMatthew Dillon hammer_modify_volume_field(cursor->trans, volume, 4462f85fa4dSMatthew Dillon vol0_btree_root); 4472f85fa4dSMatthew Dillon volume->ondisk->vol0_btree_root = nnode->node_offset; 4482f85fa4dSMatthew Dillon hammer_modify_volume_done(volume); 4492f85fa4dSMatthew Dillon hammer_rel_volume(volume, 0); 4502f85fa4dSMatthew Dillon } 4512f85fa4dSMatthew Dillon 4522f85fa4dSMatthew Dillon /* 4532f85fa4dSMatthew Dillon * Now adjust our children's pointers to us. 4542f85fa4dSMatthew Dillon */ 4552f85fa4dSMatthew Dillon for (i = 0; i < nnode->ondisk->count; ++i) { 4562f85fa4dSMatthew Dillon elm = &nnode->ondisk->elms[i]; 4572f85fa4dSMatthew Dillon error = btree_set_parent(cursor->trans, nnode, elm); 4582f85fa4dSMatthew Dillon if (error) 4592f85fa4dSMatthew Dillon panic("reblock internal node: fixup problem"); 4602f85fa4dSMatthew Dillon } 4612f85fa4dSMatthew Dillon 4622f85fa4dSMatthew Dillon /* 4632f85fa4dSMatthew Dillon * Clean up. 4642f85fa4dSMatthew Dillon * 4652f85fa4dSMatthew Dillon * The new node replaces the current node in the cursor. The cursor 4662f85fa4dSMatthew Dillon * expects it to be locked so leave it locked. Discard onode. 4672f85fa4dSMatthew Dillon */ 4682f85fa4dSMatthew Dillon hammer_delete_node(cursor->trans, onode); 4692f85fa4dSMatthew Dillon 4702f85fa4dSMatthew Dillon if (hammer_debug_general & 0x4000) { 4712f85fa4dSMatthew Dillon kprintf("REBLOCK INODE %016llx -> %016llx\n", 4722f85fa4dSMatthew Dillon onode->node_offset, nnode->node_offset); 4732f85fa4dSMatthew Dillon } 4742f85fa4dSMatthew Dillon hammer_modify_node_done(nnode); 4752f85fa4dSMatthew Dillon cursor->node = nnode; 4762f85fa4dSMatthew Dillon 4772f85fa4dSMatthew Dillon hammer_unlock(&onode->lock); 4782f85fa4dSMatthew Dillon hammer_rel_node(onode); 4792f85fa4dSMatthew Dillon 4802f85fa4dSMatthew Dillon done: 4812f85fa4dSMatthew Dillon hammer_btree_unlock_children(&locklist); 4822f85fa4dSMatthew Dillon return (error); 4832f85fa4dSMatthew Dillon } 4842f85fa4dSMatthew Dillon 485