1bf686dbeSMatthew Dillon /*
255b50bd5SMatthew Dillon * Copyright (c) 2008-2012 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 */
34bf686dbeSMatthew Dillon /*
35bf686dbeSMatthew Dillon * HAMMER reblocker - This code frees up fragmented physical space
36bf686dbeSMatthew Dillon *
37bf686dbeSMatthew Dillon * HAMMER only keeps track of free space on a big-block basis. A big-block
38bf686dbeSMatthew Dillon * containing holes can only be freed by migrating the remaining data in
39bf686dbeSMatthew Dillon * that big-block into a new big-block, then freeing the big-block.
40bf686dbeSMatthew Dillon *
41bf686dbeSMatthew Dillon * This function is called from an ioctl or via the hammer support thread.
42bf686dbeSMatthew Dillon */
43bf686dbeSMatthew Dillon
44bf686dbeSMatthew Dillon #include "hammer.h"
45bf686dbeSMatthew Dillon
4636f82b23SMatthew Dillon static int hammer_reblock_helper(struct hammer_ioc_reblock *reblock,
47bf686dbeSMatthew Dillon hammer_cursor_t cursor,
48bf686dbeSMatthew Dillon hammer_btree_elm_t elm);
4936f82b23SMatthew Dillon static int hammer_reblock_data(struct hammer_ioc_reblock *reblock,
50bf686dbeSMatthew Dillon hammer_cursor_t cursor, hammer_btree_elm_t elm);
512f85fa4dSMatthew Dillon static int hammer_reblock_leaf_node(struct hammer_ioc_reblock *reblock,
522f85fa4dSMatthew Dillon hammer_cursor_t cursor, hammer_btree_elm_t elm);
532f85fa4dSMatthew Dillon static int hammer_reblock_int_node(struct hammer_ioc_reblock *reblock,
54bf686dbeSMatthew Dillon hammer_cursor_t cursor, hammer_btree_elm_t elm);
5526748b87STomohiro Kusumi static void hammer_move_node(hammer_cursor_t cursor, hammer_btree_elm_t elm,
5626748b87STomohiro Kusumi hammer_node_t onode, hammer_node_t nnode);
57bf686dbeSMatthew Dillon
58bf686dbeSMatthew Dillon int
hammer_ioc_reblock(hammer_transaction_t trans,hammer_inode_t ip,struct hammer_ioc_reblock * reblock)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;
64a7e9bef1SMatthew Dillon int checkspace_count;
6593291532SMatthew Dillon int error;
6693291532SMatthew Dillon int seq;
677b6ccb11SMatthew Dillon int slop;
6846137e17STomohiro Kusumi uint32_t key_end_localization;
697b6ccb11SMatthew Dillon
704fa5fb92STomohiro Kusumi if ((reblock->key_beg.localization | reblock->key_end.localization) &
714fa5fb92STomohiro Kusumi HAMMER_LOCALIZE_PSEUDOFS_MASK) {
724fa5fb92STomohiro Kusumi return(EINVAL);
734fa5fb92STomohiro Kusumi }
744fa5fb92STomohiro Kusumi if (reblock->key_beg.obj_id >= reblock->key_end.obj_id)
754fa5fb92STomohiro Kusumi return(EINVAL);
764fa5fb92STomohiro Kusumi if (reblock->free_level < 0 ||
774fa5fb92STomohiro Kusumi reblock->free_level > HAMMER_BIGBLOCK_SIZE)
784fa5fb92STomohiro Kusumi return(EINVAL);
794fa5fb92STomohiro Kusumi
807b6ccb11SMatthew Dillon /*
81558a44e2STomohiro Kusumi * A fill_percentage <= 20% is considered an emergency. free_level is
82558a44e2STomohiro Kusumi * inverted from fill_percentage.
837b6ccb11SMatthew Dillon */
84e04ee2deSTomohiro Kusumi if (reblock->free_level >= HAMMER_BIGBLOCK_SIZE * 8 / 10)
857b6ccb11SMatthew Dillon slop = HAMMER_CHKSPC_EMERGENCY;
867b6ccb11SMatthew Dillon else
877b6ccb11SMatthew Dillon slop = HAMMER_CHKSPC_REBLOCK;
88bf686dbeSMatthew Dillon
896540d157STomohiro Kusumi /*
906540d157STomohiro Kusumi * Ioctl caller has only set localization type to reblock.
916540d157STomohiro Kusumi * Initialize cursor key localization with ip localization.
926540d157STomohiro Kusumi */
93dd94f1b1SMatthew Dillon reblock->key_cur = reblock->key_beg;
94842e7a70SMatthew Dillon reblock->key_cur.localization &= HAMMER_LOCALIZE_MASK;
955e1e1454STomohiro Kusumi if (reblock->allpfs == 0)
967e52af60STomohiro Kusumi reblock->key_cur.localization |= ip->obj_localization;
97814387f6SMatthew Dillon
986540d157STomohiro Kusumi key_end_localization = reblock->key_end.localization;
996540d157STomohiro Kusumi key_end_localization &= HAMMER_LOCALIZE_MASK;
1005e1e1454STomohiro Kusumi if (reblock->allpfs == 0)
1017e52af60STomohiro Kusumi key_end_localization |= ip->obj_localization;
1025e1e1454STomohiro Kusumi else
10320cf2291STomohiro Kusumi key_end_localization |= pfs_to_lo(HAMMER_MAX_PFSID);
1046540d157STomohiro Kusumi
105a7e9bef1SMatthew Dillon checkspace_count = 0;
106e86903d8SMatthew Dillon seq = trans->hmp->flusher.done;
107bf686dbeSMatthew Dillon retry:
1084e17f465SMatthew Dillon error = hammer_init_cursor(trans, &cursor, NULL, NULL);
109bf686dbeSMatthew Dillon if (error) {
110bf686dbeSMatthew Dillon hammer_done_cursor(&cursor);
111dd94f1b1SMatthew Dillon goto failed;
112bf686dbeSMatthew Dillon }
113dd94f1b1SMatthew Dillon cursor.key_beg.localization = reblock->key_cur.localization;
114dd94f1b1SMatthew Dillon cursor.key_beg.obj_id = reblock->key_cur.obj_id;
115bf686dbeSMatthew Dillon cursor.key_beg.key = HAMMER_MIN_KEY;
116bf686dbeSMatthew Dillon cursor.key_beg.create_tid = 1;
117bf686dbeSMatthew Dillon cursor.key_beg.delete_tid = 0;
118bf686dbeSMatthew Dillon cursor.key_beg.rec_type = HAMMER_MIN_RECTYPE;
119bf686dbeSMatthew Dillon cursor.key_beg.obj_type = 0;
120bf686dbeSMatthew Dillon
1216540d157STomohiro Kusumi cursor.key_end.localization = key_end_localization;
122dd94f1b1SMatthew Dillon cursor.key_end.obj_id = reblock->key_end.obj_id;
123bf686dbeSMatthew Dillon cursor.key_end.key = HAMMER_MAX_KEY;
124bf686dbeSMatthew Dillon cursor.key_end.create_tid = HAMMER_MAX_TID - 1;
125bf686dbeSMatthew Dillon cursor.key_end.delete_tid = 0;
126bf686dbeSMatthew Dillon cursor.key_end.rec_type = HAMMER_MAX_RECTYPE;
127bf686dbeSMatthew Dillon cursor.key_end.obj_type = 0;
128bf686dbeSMatthew Dillon
129bf686dbeSMatthew Dillon cursor.flags |= HAMMER_CURSOR_END_INCLUSIVE;
1309480ff55SMatthew Dillon cursor.flags |= HAMMER_CURSOR_BACKEND;
13118bee4a2SMatthew Dillon cursor.flags |= HAMMER_CURSOR_NOSWAPCACHE;
132bf686dbeSMatthew Dillon
1332f85fa4dSMatthew Dillon /*
1342f85fa4dSMatthew Dillon * This flag allows the btree scan code to return internal nodes,
1352f85fa4dSMatthew Dillon * so we can reblock them in addition to the leafs. Only specify it
1362f85fa4dSMatthew Dillon * if we intend to reblock B-Tree nodes.
1372f85fa4dSMatthew Dillon */
1382f85fa4dSMatthew Dillon if (reblock->head.flags & HAMMER_IOC_DO_BTREE)
1392f85fa4dSMatthew Dillon cursor.flags |= HAMMER_CURSOR_REBLOCKING;
1402f85fa4dSMatthew Dillon
141bf686dbeSMatthew Dillon error = hammer_btree_first(&cursor);
142bf686dbeSMatthew Dillon while (error == 0) {
1432f85fa4dSMatthew Dillon /*
1442f85fa4dSMatthew Dillon * Internal or Leaf node
1452f85fa4dSMatthew Dillon */
14607ed04b5SMatthew Dillon KKASSERT(cursor.index < cursor.node->ondisk->count);
147bf686dbeSMatthew Dillon elm = &cursor.node->ondisk->elms[cursor.index];
148dd94f1b1SMatthew Dillon reblock->key_cur.obj_id = elm->base.obj_id;
149dd94f1b1SMatthew Dillon reblock->key_cur.localization = elm->base.localization;
150bf686dbeSMatthew Dillon
1519480ff55SMatthew Dillon /*
15284c5a984SMatthew Dillon * Filesystem went read-only during rebalancing
15384c5a984SMatthew Dillon */
15484c5a984SMatthew Dillon if (trans->hmp->ronly) {
15584c5a984SMatthew Dillon error = EROFS;
15684c5a984SMatthew Dillon break;
15784c5a984SMatthew Dillon }
15884c5a984SMatthew Dillon
15984c5a984SMatthew Dillon /*
1609f5097dcSMatthew Dillon * Yield to more important tasks
1619f5097dcSMatthew Dillon */
1629f5097dcSMatthew Dillon if ((error = hammer_signal_check(trans->hmp)) != 0)
1639f5097dcSMatthew Dillon break;
164a7e9bef1SMatthew Dillon
165a7e9bef1SMatthew Dillon /*
166a7e9bef1SMatthew Dillon * If there is insufficient free space it may be due to
167a981af19STomohiro Kusumi * reserved big-blocks, which flushing might fix.
168c9ce54d6SMatthew Dillon *
16907ed04b5SMatthew Dillon * We must force a retest in case the unlocked cursor is
17007ed04b5SMatthew Dillon * moved to the end of the leaf, or moved to an internal
17107ed04b5SMatthew Dillon * node.
17207ed04b5SMatthew Dillon *
173c9ce54d6SMatthew Dillon * WARNING: See warnings in hammer_unlock_cursor() function.
174a7e9bef1SMatthew Dillon */
1757b6ccb11SMatthew Dillon if (hammer_checkspace(trans->hmp, slop)) {
176a7e9bef1SMatthew Dillon if (++checkspace_count == 10) {
177a7e9bef1SMatthew Dillon error = ENOSPC;
178a7e9bef1SMatthew Dillon break;
179a7e9bef1SMatthew Dillon }
180982be4bfSMatthew Dillon hammer_unlock_cursor(&cursor);
18107ed04b5SMatthew Dillon cursor.flags |= HAMMER_CURSOR_RETEST;
18293291532SMatthew Dillon hammer_flusher_wait(trans->hmp, seq);
183982be4bfSMatthew Dillon hammer_lock_cursor(&cursor);
1847a61b85dSMatthew Dillon seq = hammer_flusher_async(trans->hmp, NULL);
18507ed04b5SMatthew Dillon goto skip;
18693291532SMatthew Dillon }
187a7e9bef1SMatthew Dillon
188a7e9bef1SMatthew Dillon /*
1899480ff55SMatthew Dillon * Acquiring the sync_lock prevents the operation from
1909480ff55SMatthew Dillon * crossing a synchronization boundary.
19109ac686bSMatthew Dillon *
19209ac686bSMatthew Dillon * NOTE: cursor.node may have changed on return.
193c9ce54d6SMatthew Dillon *
194c9ce54d6SMatthew Dillon * WARNING: See warnings in hammer_unlock_cursor() function.
1959480ff55SMatthew Dillon */
1962f85fa4dSMatthew Dillon hammer_sync_lock_sh(trans);
19736f82b23SMatthew Dillon error = hammer_reblock_helper(reblock, &cursor, elm);
1982f85fa4dSMatthew Dillon hammer_sync_unlock(trans);
19993291532SMatthew Dillon
20015e75dabSMatthew Dillon while (hammer_flusher_meta_halflimit(trans->hmp) ||
2017a61b85dSMatthew Dillon hammer_flusher_undo_exhausted(trans, 2)) {
202982be4bfSMatthew Dillon hammer_unlock_cursor(&cursor);
20393291532SMatthew Dillon hammer_flusher_wait(trans->hmp, seq);
204982be4bfSMatthew Dillon hammer_lock_cursor(&cursor);
20515e75dabSMatthew Dillon seq = hammer_flusher_async_one(trans->hmp);
20693291532SMatthew Dillon }
2071b0ab2c3SMatthew Dillon
2081b0ab2c3SMatthew Dillon /*
2091b0ab2c3SMatthew Dillon * Setup for iteration, our cursor flags may be modified by
2101b0ab2c3SMatthew Dillon * other threads while we are unlocked.
2111b0ab2c3SMatthew Dillon */
212bf686dbeSMatthew Dillon cursor.flags |= HAMMER_CURSOR_ATEDISK;
2131b0ab2c3SMatthew Dillon
2141b0ab2c3SMatthew Dillon /*
2151b0ab2c3SMatthew Dillon * We allocate data buffers, which atm we don't track
2161b0ab2c3SMatthew Dillon * dirty levels for because we allow the kernel to write
2171b0ab2c3SMatthew Dillon * them. But if we allocate too many we can still deadlock
2181b0ab2c3SMatthew Dillon * the buffer cache.
2191b0ab2c3SMatthew Dillon *
220c9ce54d6SMatthew Dillon * WARNING: See warnings in hammer_unlock_cursor() function.
2211b0ab2c3SMatthew Dillon * (The cursor's node and element may change!)
2221b0ab2c3SMatthew Dillon */
2231b0ab2c3SMatthew Dillon if (bd_heatup()) {
224982be4bfSMatthew Dillon hammer_unlock_cursor(&cursor);
2251b0ab2c3SMatthew Dillon bwillwrite(HAMMER_XBUFSIZE);
226982be4bfSMatthew Dillon hammer_lock_cursor(&cursor);
2271b0ab2c3SMatthew Dillon }
22855b50bd5SMatthew Dillon vm_wait_nominal();
22907ed04b5SMatthew Dillon skip:
2301b0ab2c3SMatthew Dillon if (error == 0) {
231bf686dbeSMatthew Dillon error = hammer_btree_iterate(&cursor);
232bf686dbeSMatthew Dillon }
233bf686dbeSMatthew Dillon }
234bf686dbeSMatthew Dillon if (error == ENOENT)
235bf686dbeSMatthew Dillon error = 0;
236bf686dbeSMatthew Dillon hammer_done_cursor(&cursor);
23706ad81ffSMatthew Dillon if (error == EWOULDBLOCK) {
23806ad81ffSMatthew Dillon hammer_flusher_sync(trans->hmp);
23906ad81ffSMatthew Dillon goto retry;
24006ad81ffSMatthew Dillon }
241bf686dbeSMatthew Dillon if (error == EDEADLK)
242bf686dbeSMatthew Dillon goto retry;
24319619882SMatthew Dillon if (error == EINTR) {
24419619882SMatthew Dillon reblock->head.flags |= HAMMER_IOC_HEAD_INTR;
24519619882SMatthew Dillon error = 0;
24619619882SMatthew Dillon }
247dd94f1b1SMatthew Dillon failed:
248dd94f1b1SMatthew Dillon reblock->key_cur.localization &= HAMMER_LOCALIZE_MASK;
249bf686dbeSMatthew Dillon return(error);
250bf686dbeSMatthew Dillon }
251bf686dbeSMatthew Dillon
252bf686dbeSMatthew Dillon /*
253bf686dbeSMatthew Dillon * Reblock the B-Tree (leaf) node, record, and/or data if necessary.
254bf686dbeSMatthew Dillon *
2559480ff55SMatthew Dillon * XXX We have no visibility into internal B-Tree nodes at the moment,
2569480ff55SMatthew Dillon * only leaf nodes.
257bf686dbeSMatthew Dillon */
258bf686dbeSMatthew Dillon static int
hammer_reblock_helper(struct hammer_ioc_reblock * reblock,hammer_cursor_t cursor,hammer_btree_elm_t elm)25936f82b23SMatthew Dillon hammer_reblock_helper(struct hammer_ioc_reblock *reblock,
260bf686dbeSMatthew Dillon hammer_cursor_t cursor, hammer_btree_elm_t elm)
261bf686dbeSMatthew Dillon {
26243c665aeSMatthew Dillon hammer_mount_t hmp;
263bf686dbeSMatthew Dillon hammer_off_t tmp_offset;
264ebbcfba9SMatthew Dillon hammer_node_ondisk_t ondisk;
26544a83111SMatthew Dillon struct hammer_btree_leaf_elm leaf;
266bf686dbeSMatthew Dillon int error;
267bf686dbeSMatthew Dillon int bytes;
268bf686dbeSMatthew Dillon int cur;
269bf3b416bSMatthew Dillon int iocflags;
270bf686dbeSMatthew Dillon
271bf686dbeSMatthew Dillon error = 0;
27243c665aeSMatthew Dillon hmp = cursor->trans->hmp;
273bf686dbeSMatthew Dillon
274bf686dbeSMatthew Dillon /*
275bf686dbeSMatthew Dillon * Reblock data. Note that data embedded in a record is reblocked
2762f85fa4dSMatthew Dillon * by the record reblock code. Data processing only occurs at leaf
2772f85fa4dSMatthew Dillon * nodes and for RECORD element types.
278bf686dbeSMatthew Dillon */
2792f85fa4dSMatthew Dillon if (cursor->node->ondisk->type != HAMMER_BTREE_TYPE_LEAF)
2802f85fa4dSMatthew Dillon goto skip;
2812f85fa4dSMatthew Dillon if (elm->leaf.base.btype != HAMMER_BTREE_TYPE_RECORD)
282c9d1310cSTomohiro Kusumi return(EINVAL);
283bf686dbeSMatthew Dillon tmp_offset = elm->leaf.data_offset;
284bf3b416bSMatthew Dillon if (tmp_offset == 0)
285bf3b416bSMatthew Dillon goto skip;
286bf3b416bSMatthew Dillon
287bf3b416bSMatthew Dillon /*
2887ef2d7b3STomohiro Kusumi * If reblock->vol_no is specified we only want to reblock data
2897ef2d7b3STomohiro Kusumi * in that volume, but ignore everything else.
2907ef2d7b3STomohiro Kusumi */
2917ef2d7b3STomohiro Kusumi if (reblock->vol_no != -1 &&
2927ef2d7b3STomohiro Kusumi reblock->vol_no != HAMMER_VOL_DECODE(tmp_offset))
2937ef2d7b3STomohiro Kusumi goto skip;
2947ef2d7b3STomohiro Kusumi
2957ef2d7b3STomohiro Kusumi /*
296bf3b416bSMatthew Dillon * NOTE: Localization restrictions may also have been set-up, we can't
297bf3b416bSMatthew Dillon * just set the match flags willy-nilly here.
298bf3b416bSMatthew Dillon */
299bf3b416bSMatthew Dillon switch(elm->leaf.base.rec_type) {
300bf3b416bSMatthew Dillon case HAMMER_RECTYPE_INODE:
30183f2a3aaSMatthew Dillon case HAMMER_RECTYPE_SNAPSHOT:
30283f2a3aaSMatthew Dillon case HAMMER_RECTYPE_CONFIG:
303bf3b416bSMatthew Dillon iocflags = HAMMER_IOC_DO_INODES;
304bf3b416bSMatthew Dillon break;
305bf3b416bSMatthew Dillon case HAMMER_RECTYPE_EXT:
306bf3b416bSMatthew Dillon case HAMMER_RECTYPE_FIX:
307ea434b6fSMatthew Dillon case HAMMER_RECTYPE_PFS:
308bf3b416bSMatthew Dillon case HAMMER_RECTYPE_DIRENTRY:
309bf3b416bSMatthew Dillon iocflags = HAMMER_IOC_DO_DIRS;
310bf3b416bSMatthew Dillon break;
311bf3b416bSMatthew Dillon case HAMMER_RECTYPE_DATA:
312bf3b416bSMatthew Dillon case HAMMER_RECTYPE_DB:
313bf3b416bSMatthew Dillon iocflags = HAMMER_IOC_DO_DATA;
314bf3b416bSMatthew Dillon break;
315bf3b416bSMatthew Dillon default:
316bf3b416bSMatthew Dillon iocflags = 0;
317bf3b416bSMatthew Dillon break;
318bf3b416bSMatthew Dillon }
319bf3b416bSMatthew Dillon if (reblock->head.flags & iocflags) {
320bf686dbeSMatthew Dillon ++reblock->data_count;
321bf686dbeSMatthew Dillon reblock->data_byte_count += elm->leaf.data_len;
32243c665aeSMatthew Dillon bytes = hammer_blockmap_getfree(hmp, tmp_offset, &cur, &error);
3236e1e8b6dSMatthew Dillon if (hammer_debug_general & 0x4000)
32433234d14STomohiro Kusumi hdkprintf("D %6d/%d\n", bytes, reblock->free_level);
3254af7f537STomohiro Kusumi /*
3264af7f537STomohiro Kusumi * Start data reblock if
3274af7f537STomohiro Kusumi * 1. there is no error
3284af7f537STomohiro Kusumi * 2. the data and allocator offset are not in the same
3294af7f537STomohiro Kusumi * big-block, or free level threshold is 0
3304af7f537STomohiro Kusumi * 3. free bytes in the data's big-block is larger than
3314af7f537STomohiro Kusumi * free level threshold (means if threshold is 0 then
3324af7f537STomohiro Kusumi * do reblock no matter what).
3334af7f537STomohiro Kusumi */
334bf3b416bSMatthew Dillon if (error == 0 && (cur == 0 || reblock->free_level == 0) &&
335bf3b416bSMatthew Dillon bytes >= reblock->free_level) {
33644a83111SMatthew Dillon /*
33744a83111SMatthew Dillon * This is nasty, the uncache code may have to get
33844a83111SMatthew Dillon * vnode locks and because of that we can't hold
33944a83111SMatthew Dillon * the cursor locked.
340c9ce54d6SMatthew Dillon *
341c9ce54d6SMatthew Dillon * WARNING: See warnings in hammer_unlock_cursor()
342c9ce54d6SMatthew Dillon * function.
34344a83111SMatthew Dillon */
34444a83111SMatthew Dillon leaf = elm->leaf;
345982be4bfSMatthew Dillon hammer_unlock_cursor(cursor);
34644a83111SMatthew Dillon hammer_io_direct_uncache(hmp, &leaf);
347982be4bfSMatthew Dillon hammer_lock_cursor(cursor);
348ebbcfba9SMatthew Dillon
349ebbcfba9SMatthew Dillon /*
350ebbcfba9SMatthew Dillon * elm may have become stale or invalid, reload it.
351ebbcfba9SMatthew Dillon * ondisk variable is temporary only. Note that
352ebbcfba9SMatthew Dillon * cursor->node and thus cursor->node->ondisk may
353ebbcfba9SMatthew Dillon * also changed.
354ebbcfba9SMatthew Dillon */
355ebbcfba9SMatthew Dillon ondisk = cursor->node->ondisk;
356ebbcfba9SMatthew Dillon elm = &ondisk->elms[cursor->index];
35744a83111SMatthew Dillon if (cursor->flags & HAMMER_CURSOR_RETEST) {
358d053aa8aSTomohiro Kusumi hkprintf("debug: retest on reblocker uncache\n");
35944a83111SMatthew Dillon error = EDEADLK;
360ebbcfba9SMatthew Dillon } else if (ondisk->type != HAMMER_BTREE_TYPE_LEAF ||
361ebbcfba9SMatthew Dillon cursor->index >= ondisk->count) {
362d053aa8aSTomohiro Kusumi hkprintf("debug: shifted on reblocker uncache\n");
363ebbcfba9SMatthew Dillon error = EDEADLK;
364ebbcfba9SMatthew Dillon } else if (bcmp(&elm->leaf, &leaf, sizeof(leaf))) {
365d053aa8aSTomohiro Kusumi hkprintf("debug: changed on reblocker uncache\n");
366ebbcfba9SMatthew Dillon error = EDEADLK;
36744a83111SMatthew Dillon }
36844a83111SMatthew Dillon if (error == 0)
369bf686dbeSMatthew Dillon error = hammer_cursor_upgrade(cursor);
370bf686dbeSMatthew Dillon if (error == 0) {
37107ed04b5SMatthew Dillon KKASSERT(cursor->index < ondisk->count);
37236f82b23SMatthew Dillon error = hammer_reblock_data(reblock,
373bf686dbeSMatthew Dillon cursor, elm);
374bf686dbeSMatthew Dillon }
375bf686dbeSMatthew Dillon if (error == 0) {
376bf686dbeSMatthew Dillon ++reblock->data_moves;
377bf686dbeSMatthew Dillon reblock->data_byte_moves += elm->leaf.data_len;
378bf686dbeSMatthew Dillon }
379bf686dbeSMatthew Dillon }
380bf686dbeSMatthew Dillon }
381bf686dbeSMatthew Dillon
3822f85fa4dSMatthew Dillon skip:
383bf686dbeSMatthew Dillon /*
3841775b6a0SMatthew Dillon * Reblock a B-Tree internal or leaf node. A leaf node is reblocked
3851775b6a0SMatthew Dillon * on initial entry only (element 0). An internal node is reblocked
386525fa6bbSTomohiro Kusumi * when entered upward from its first leaf node only (also element 0,
387525fa6bbSTomohiro Kusumi * see hammer_btree_iterate() where cursor moves up and may return).
3881775b6a0SMatthew Dillon * Further revisits of the internal node (index > 0) are ignored.
389bf686dbeSMatthew Dillon */
390bf686dbeSMatthew Dillon tmp_offset = cursor->node->node_offset;
3917ef2d7b3STomohiro Kusumi
3927ef2d7b3STomohiro Kusumi /*
3937ef2d7b3STomohiro Kusumi * If reblock->vol_no is specified we only want to reblock data
3947ef2d7b3STomohiro Kusumi * in that volume, but ignore everything else.
3957ef2d7b3STomohiro Kusumi */
3967ef2d7b3STomohiro Kusumi if (reblock->vol_no != -1 &&
3977ef2d7b3STomohiro Kusumi reblock->vol_no != HAMMER_VOL_DECODE(tmp_offset))
3987ef2d7b3STomohiro Kusumi goto end;
3997ef2d7b3STomohiro Kusumi
400bf3b416bSMatthew Dillon if (cursor->index == 0 &&
401814387f6SMatthew Dillon error == 0 && (reblock->head.flags & HAMMER_IOC_DO_BTREE)) {
402bf686dbeSMatthew Dillon ++reblock->btree_count;
40343c665aeSMatthew Dillon bytes = hammer_blockmap_getfree(hmp, tmp_offset, &cur, &error);
4046e1e8b6dSMatthew Dillon if (hammer_debug_general & 0x4000)
40533234d14STomohiro Kusumi hdkprintf("B %6d/%d\n", bytes, reblock->free_level);
4064af7f537STomohiro Kusumi /*
4074af7f537STomohiro Kusumi * Start node reblock if
4084af7f537STomohiro Kusumi * 1. there is no error
4094af7f537STomohiro Kusumi * 2. the node and allocator offset are not in the same
4104af7f537STomohiro Kusumi * big-block, or free level threshold is 0
4114af7f537STomohiro Kusumi * 3. free bytes in the node's big-block is larger than
4124af7f537STomohiro Kusumi * free level threshold (means if threshold is 0 then
4134af7f537STomohiro Kusumi * do reblock no matter what).
4144af7f537STomohiro Kusumi */
415bf3b416bSMatthew Dillon if (error == 0 && (cur == 0 || reblock->free_level == 0) &&
416bf3b416bSMatthew Dillon bytes >= reblock->free_level) {
417bf686dbeSMatthew Dillon error = hammer_cursor_upgrade(cursor);
418bf686dbeSMatthew Dillon if (error == 0) {
41907ed04b5SMatthew Dillon if (cursor->parent) {
42007ed04b5SMatthew Dillon KKASSERT(cursor->parent_index <
42107ed04b5SMatthew Dillon cursor->parent->ondisk->count);
422bf686dbeSMatthew Dillon elm = &cursor->parent->ondisk->elms[cursor->parent_index];
42307ed04b5SMatthew Dillon } else {
424bf686dbeSMatthew Dillon elm = NULL;
42507ed04b5SMatthew Dillon }
4262f85fa4dSMatthew Dillon switch(cursor->node->ondisk->type) {
4272f85fa4dSMatthew Dillon case HAMMER_BTREE_TYPE_LEAF:
4282f85fa4dSMatthew Dillon error = hammer_reblock_leaf_node(
4292f85fa4dSMatthew Dillon reblock, cursor, elm);
4302f85fa4dSMatthew Dillon break;
4312f85fa4dSMatthew Dillon case HAMMER_BTREE_TYPE_INTERNAL:
4322f85fa4dSMatthew Dillon error = hammer_reblock_int_node(
4332f85fa4dSMatthew Dillon reblock, cursor, elm);
4342f85fa4dSMatthew Dillon break;
4352f85fa4dSMatthew Dillon default:
4365134aacdSTomohiro Kusumi hpanic("Illegal B-Tree node type");
4372f85fa4dSMatthew Dillon }
438bf686dbeSMatthew Dillon }
439bf686dbeSMatthew Dillon if (error == 0) {
440bf686dbeSMatthew Dillon ++reblock->btree_moves;
441bf686dbeSMatthew Dillon }
442bf686dbeSMatthew Dillon }
443bf686dbeSMatthew Dillon }
4447ef2d7b3STomohiro Kusumi end:
445ebc5d79eSTomohiro Kusumi hammer_cursor_downgrade(cursor);
446bf686dbeSMatthew Dillon return(error);
447bf686dbeSMatthew Dillon }
448bf686dbeSMatthew Dillon
449bf686dbeSMatthew Dillon /*
450bf686dbeSMatthew Dillon * Reblock a record's data. Both the B-Tree element and record pointers
451bf686dbeSMatthew Dillon * to the data must be adjusted.
452bf686dbeSMatthew Dillon */
453bf686dbeSMatthew Dillon static int
hammer_reblock_data(struct hammer_ioc_reblock * reblock,hammer_cursor_t cursor,hammer_btree_elm_t elm)45436f82b23SMatthew Dillon hammer_reblock_data(struct hammer_ioc_reblock *reblock,
455bf686dbeSMatthew Dillon hammer_cursor_t cursor, hammer_btree_elm_t elm)
456bf686dbeSMatthew Dillon {
457562d34c2STomohiro Kusumi hammer_buffer_t data_buffer = NULL;
458bc996e65STomohiro Kusumi hammer_off_t odata_offset;
459bf686dbeSMatthew Dillon hammer_off_t ndata_offset;
460*17b150c6STomohiro Kusumi hammer_crc_t ncrc;
461bf686dbeSMatthew Dillon int error;
462bf686dbeSMatthew Dillon void *ndata;
463bf686dbeSMatthew Dillon
4640a6fabdbSTomohiro Kusumi error = hammer_btree_extract_data(cursor);
465bf686dbeSMatthew Dillon if (error)
466bf686dbeSMatthew Dillon return (error);
46736f82b23SMatthew Dillon ndata = hammer_alloc_data(cursor->trans, elm->leaf.data_len,
468bf3b416bSMatthew Dillon elm->leaf.base.rec_type,
469df2ccbacSMatthew Dillon &ndata_offset, &data_buffer,
470df2ccbacSMatthew Dillon 0, &error);
471bf686dbeSMatthew Dillon if (error)
472bf686dbeSMatthew Dillon goto done;
473b8a41159SMatthew Dillon hammer_io_notmeta(data_buffer);
474bf686dbeSMatthew Dillon
475bf686dbeSMatthew Dillon /*
476b9107f58SMatthew Dillon * Move the data. Note that we must invalidate any cached
477b9107f58SMatthew Dillon * data buffer in the cursor before calling blockmap_free.
478e04ee2deSTomohiro Kusumi * The blockmap_free may free up the entire big-block and
479b9107f58SMatthew Dillon * will not be able to invalidate it if the cursor is holding
480d165c90aSTomohiro Kusumi * a data buffer cached in that big-block.
4814c09d9c4SMatthew Dillon *
4824c09d9c4SMatthew Dillon * Unconditionally regenerate the CRC. This is a slightly hack
4834c09d9c4SMatthew Dillon * to ensure that the crc method is the latest for the filesystem
4844c09d9c4SMatthew Dillon * version (e.g. upgrade from v6 to v7).
485bf686dbeSMatthew Dillon */
486f1c0ae53STomohiro Kusumi hammer_modify_buffer_noundo(cursor->trans, data_buffer);
487bf686dbeSMatthew Dillon bcopy(cursor->data, ndata, elm->leaf.data_len);
4884c09d9c4SMatthew Dillon ncrc = hammer_crc_get_leaf(cursor->trans->hmp->version, ndata,
4894c09d9c4SMatthew Dillon &elm->leaf);
49010a5d1baSMatthew Dillon hammer_modify_buffer_done(data_buffer);
491b9107f58SMatthew Dillon hammer_cursor_invalidate_cache(cursor);
492bf686dbeSMatthew Dillon
49336f82b23SMatthew Dillon hammer_blockmap_free(cursor->trans,
49436f82b23SMatthew Dillon elm->leaf.data_offset, elm->leaf.data_len);
495bf686dbeSMatthew Dillon
49610a5d1baSMatthew Dillon hammer_modify_node(cursor->trans, cursor->node,
49710a5d1baSMatthew Dillon &elm->leaf.data_offset, sizeof(hammer_off_t));
498bc996e65STomohiro Kusumi odata_offset = elm->leaf.data_offset;
499bf686dbeSMatthew Dillon elm->leaf.data_offset = ndata_offset;
5004c09d9c4SMatthew Dillon elm->leaf.data_crc = ncrc;
50110a5d1baSMatthew Dillon hammer_modify_node_done(cursor->node);
502bf686dbeSMatthew Dillon
503bc996e65STomohiro Kusumi if (hammer_debug_general & 0x4000) {
50435a5249bSTomohiro Kusumi hdkprintf("%08x %016jx -> %016jx\n",
505a6af8eaeSTomohiro Kusumi (elm ? elm->base.localization : -1),
50635a5249bSTomohiro Kusumi (intmax_t)odata_offset,
50735a5249bSTomohiro Kusumi (intmax_t)ndata_offset);
508bc996e65STomohiro Kusumi }
509bf686dbeSMatthew Dillon done:
510bf686dbeSMatthew Dillon if (data_buffer)
511bf686dbeSMatthew Dillon hammer_rel_buffer(data_buffer, 0);
512bf686dbeSMatthew Dillon return (error);
513bf686dbeSMatthew Dillon }
514bf686dbeSMatthew Dillon
515bf686dbeSMatthew Dillon /*
5162f85fa4dSMatthew Dillon * Reblock a B-Tree leaf node. The parent must be adjusted to point to
5172f85fa4dSMatthew Dillon * the new copy of the leaf node.
518bf686dbeSMatthew Dillon *
5192f85fa4dSMatthew Dillon * elm is a pointer to the parent element pointing at cursor.node.
520bf686dbeSMatthew Dillon */
521bf686dbeSMatthew Dillon static int
hammer_reblock_leaf_node(struct hammer_ioc_reblock * reblock,hammer_cursor_t cursor,hammer_btree_elm_t elm)5222f85fa4dSMatthew Dillon hammer_reblock_leaf_node(struct hammer_ioc_reblock *reblock,
523bf686dbeSMatthew Dillon hammer_cursor_t cursor, hammer_btree_elm_t elm)
524bf686dbeSMatthew Dillon {
525bf686dbeSMatthew Dillon hammer_node_t onode;
526bf686dbeSMatthew Dillon hammer_node_t nnode;
527bf686dbeSMatthew Dillon int error;
528bf686dbeSMatthew Dillon
529df2ccbacSMatthew Dillon /*
530df2ccbacSMatthew Dillon * Don't supply a hint when allocating the leaf. Fills are done
531df2ccbacSMatthew Dillon * from the leaf upwards.
532df2ccbacSMatthew Dillon */
533bf686dbeSMatthew Dillon onode = cursor->node;
534df2ccbacSMatthew Dillon nnode = hammer_alloc_btree(cursor->trans, 0, &error);
5358d0efe43SMatthew Dillon
536bf686dbeSMatthew Dillon if (nnode == NULL)
537bf686dbeSMatthew Dillon return (error);
538bf686dbeSMatthew Dillon
53909ac686bSMatthew Dillon hammer_lock_ex(&nnode->lock);
54009ac686bSMatthew Dillon hammer_modify_node_noundo(cursor->trans, nnode);
541bf686dbeSMatthew Dillon
54226748b87STomohiro Kusumi hammer_move_node(cursor, elm, onode, nnode);
54326748b87STomohiro Kusumi
544bf686dbeSMatthew Dillon /*
54526748b87STomohiro Kusumi * Clean up.
54626748b87STomohiro Kusumi *
54726748b87STomohiro Kusumi * The new node replaces the current node in the cursor. The cursor
54826748b87STomohiro Kusumi * expects it to be locked so leave it locked. Discard onode.
549bf686dbeSMatthew Dillon */
550b3bad96fSMatthew Dillon hammer_cursor_replaced_node(onode, nnode);
55136f82b23SMatthew Dillon hammer_delete_node(cursor->trans, onode);
552bf686dbeSMatthew Dillon
553b58c6388SMatthew Dillon if (hammer_debug_general & 0x4000) {
55435a5249bSTomohiro Kusumi hdkprintf("%08x %016jx -> %016jx\n",
555a6af8eaeSTomohiro Kusumi (elm ? elm->base.localization : -1),
55635a5249bSTomohiro Kusumi (intmax_t)onode->node_offset,
55735a5249bSTomohiro Kusumi (intmax_t)nnode->node_offset);
558b58c6388SMatthew Dillon }
5598d0efe43SMatthew Dillon hammer_modify_node_done(nnode);
560bf686dbeSMatthew Dillon cursor->node = nnode;
56109ac686bSMatthew Dillon
56209ac686bSMatthew Dillon hammer_unlock(&onode->lock);
563bf686dbeSMatthew Dillon hammer_rel_node(onode);
564bf686dbeSMatthew Dillon
565bf686dbeSMatthew Dillon return (error);
566bf686dbeSMatthew Dillon }
567bf686dbeSMatthew Dillon
5682f85fa4dSMatthew Dillon /*
5692f85fa4dSMatthew Dillon * Reblock a B-Tree internal node. The parent must be adjusted to point to
5702f85fa4dSMatthew Dillon * the new copy of the internal node, and the node's children's parent
5712f85fa4dSMatthew Dillon * pointers must also be adjusted to point to the new copy.
5722f85fa4dSMatthew Dillon *
5732f85fa4dSMatthew Dillon * elm is a pointer to the parent element pointing at cursor.node.
5742f85fa4dSMatthew Dillon */
5752f85fa4dSMatthew Dillon static int
hammer_reblock_int_node(struct hammer_ioc_reblock * reblock,hammer_cursor_t cursor,hammer_btree_elm_t elm)5762f85fa4dSMatthew Dillon hammer_reblock_int_node(struct hammer_ioc_reblock *reblock,
5772f85fa4dSMatthew Dillon hammer_cursor_t cursor, hammer_btree_elm_t elm)
5782f85fa4dSMatthew Dillon {
5791775b6a0SMatthew Dillon struct hammer_node_lock lockroot;
5802f85fa4dSMatthew Dillon hammer_node_t onode;
5812f85fa4dSMatthew Dillon hammer_node_t nnode;
5822f85fa4dSMatthew Dillon int error;
5832f85fa4dSMatthew Dillon
5841775b6a0SMatthew Dillon hammer_node_lock_init(&lockroot, cursor->node);
58524cf83d2SMatthew Dillon error = hammer_btree_lock_children(cursor, 1, &lockroot, NULL);
5862f85fa4dSMatthew Dillon if (error)
5872f85fa4dSMatthew Dillon goto done;
5882f85fa4dSMatthew Dillon
589525fa6bbSTomohiro Kusumi /*
590525fa6bbSTomohiro Kusumi * Don't supply a hint when allocating the leaf. Fills are done
591525fa6bbSTomohiro Kusumi * from the leaf upwards.
592525fa6bbSTomohiro Kusumi */
5932f85fa4dSMatthew Dillon onode = cursor->node;
594b4f86ea3SMatthew Dillon nnode = hammer_alloc_btree(cursor->trans, 0, &error);
5952f85fa4dSMatthew Dillon
5962f85fa4dSMatthew Dillon if (nnode == NULL)
5972f85fa4dSMatthew Dillon goto done;
5982f85fa4dSMatthew Dillon
5992f85fa4dSMatthew Dillon hammer_lock_ex(&nnode->lock);
6002f85fa4dSMatthew Dillon hammer_modify_node_noundo(cursor->trans, nnode);
6012f85fa4dSMatthew Dillon
60226748b87STomohiro Kusumi hammer_move_node(cursor, elm, onode, nnode);
6032f85fa4dSMatthew Dillon
6042f85fa4dSMatthew Dillon /*
6052f85fa4dSMatthew Dillon * Clean up.
6062f85fa4dSMatthew Dillon *
6072f85fa4dSMatthew Dillon * The new node replaces the current node in the cursor. The cursor
6082f85fa4dSMatthew Dillon * expects it to be locked so leave it locked. Discard onode.
6092f85fa4dSMatthew Dillon */
610b3bad96fSMatthew Dillon hammer_cursor_replaced_node(onode, nnode);
6112f85fa4dSMatthew Dillon hammer_delete_node(cursor->trans, onode);
6122f85fa4dSMatthew Dillon
6132f85fa4dSMatthew Dillon if (hammer_debug_general & 0x4000) {
61435a5249bSTomohiro Kusumi hdkprintf("%08x %016jx -> %016jx\n",
615a6af8eaeSTomohiro Kusumi (elm ? elm->base.localization : -1),
61635a5249bSTomohiro Kusumi (intmax_t)onode->node_offset,
61735a5249bSTomohiro Kusumi (intmax_t)nnode->node_offset);
6182f85fa4dSMatthew Dillon }
6192f85fa4dSMatthew Dillon hammer_modify_node_done(nnode);
6202f85fa4dSMatthew Dillon cursor->node = nnode;
6212f85fa4dSMatthew Dillon
6222f85fa4dSMatthew Dillon hammer_unlock(&onode->lock);
6232f85fa4dSMatthew Dillon hammer_rel_node(onode);
6242f85fa4dSMatthew Dillon
6252f85fa4dSMatthew Dillon done:
62624cf83d2SMatthew Dillon hammer_btree_unlock_children(cursor->trans->hmp, &lockroot, NULL);
6272f85fa4dSMatthew Dillon return (error);
6282f85fa4dSMatthew Dillon }
6292f85fa4dSMatthew Dillon
63026748b87STomohiro Kusumi /*
63126748b87STomohiro Kusumi * nnode is a newly allocated node, and now elm becomes the node
63226748b87STomohiro Kusumi * element within nnode's parent that represents a pointer to nnode,
63326748b87STomohiro Kusumi * or nnode becomes the root node if elm does not exist.
63426748b87STomohiro Kusumi */
63526748b87STomohiro Kusumi static void
hammer_move_node(hammer_cursor_t cursor,hammer_btree_elm_t elm,hammer_node_t onode,hammer_node_t nnode)63626748b87STomohiro Kusumi hammer_move_node(hammer_cursor_t cursor, hammer_btree_elm_t elm,
63726748b87STomohiro Kusumi hammer_node_t onode, hammer_node_t nnode)
63826748b87STomohiro Kusumi {
63926748b87STomohiro Kusumi int error, i;
64026748b87STomohiro Kusumi
64126748b87STomohiro Kusumi bcopy(onode->ondisk, nnode->ondisk, sizeof(*nnode->ondisk));
64226748b87STomohiro Kusumi
64326748b87STomohiro Kusumi /*
64426748b87STomohiro Kusumi * Adjust the parent's pointer to us first.
64526748b87STomohiro Kusumi */
64626748b87STomohiro Kusumi if (elm) {
64726748b87STomohiro Kusumi /*
64826748b87STomohiro Kusumi * We are not the root of the B-Tree
64926748b87STomohiro Kusumi */
6501424c922STomohiro Kusumi KKASSERT(hammer_is_internal_node_elm(elm));
65126748b87STomohiro Kusumi hammer_modify_node(cursor->trans, cursor->parent,
65226748b87STomohiro Kusumi &elm->internal.subtree_offset,
65326748b87STomohiro Kusumi sizeof(elm->internal.subtree_offset));
65426748b87STomohiro Kusumi elm->internal.subtree_offset = nnode->node_offset;
65526748b87STomohiro Kusumi hammer_modify_node_done(cursor->parent);
65626748b87STomohiro Kusumi } else {
65726748b87STomohiro Kusumi /*
65826748b87STomohiro Kusumi * We are the root of the B-Tree
65926748b87STomohiro Kusumi */
66026748b87STomohiro Kusumi hammer_volume_t volume;
66126748b87STomohiro Kusumi volume = hammer_get_root_volume(cursor->trans->hmp, &error);
66226748b87STomohiro Kusumi KKASSERT(error == 0);
66326748b87STomohiro Kusumi
66426748b87STomohiro Kusumi hammer_modify_volume_field(cursor->trans, volume,
66526748b87STomohiro Kusumi vol0_btree_root);
66626748b87STomohiro Kusumi volume->ondisk->vol0_btree_root = nnode->node_offset;
66726748b87STomohiro Kusumi hammer_modify_volume_done(volume);
66826748b87STomohiro Kusumi hammer_rel_volume(volume, 0);
66926748b87STomohiro Kusumi }
67026748b87STomohiro Kusumi
67126748b87STomohiro Kusumi /*
67226748b87STomohiro Kusumi * Now adjust our children's pointers to us
67326748b87STomohiro Kusumi * if we are an internal node.
67426748b87STomohiro Kusumi */
67526748b87STomohiro Kusumi if (nnode->ondisk->type == HAMMER_BTREE_TYPE_INTERNAL) {
67626748b87STomohiro Kusumi for (i = 0; i < nnode->ondisk->count; ++i) {
67790f96c37STomohiro Kusumi error = btree_set_parent_of_child(cursor->trans, nnode,
67826748b87STomohiro Kusumi &nnode->ondisk->elms[i]);
67926748b87STomohiro Kusumi if (error)
6805134aacdSTomohiro Kusumi hpanic("reblock internal node: fixup problem");
68126748b87STomohiro Kusumi }
68226748b87STomohiro Kusumi }
68326748b87STomohiro Kusumi }
684