xref: /dflybsd-src/sys/vfs/hammer/hammer_reblock.c (revision 43c665ae988b8aad9ffde49db18622101a33d25c)
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*43c665aeSMatthew Dillon  * $DragonFly: src/sys/vfs/hammer/hammer_reblock.c,v 1.20 2008/06/21 20:21:58 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 
66bf686dbeSMatthew Dillon 	if (reblock->beg_obj_id >= reblock->end_obj_id)
67bf686dbeSMatthew Dillon 		return(EINVAL);
68bf686dbeSMatthew Dillon 	if (reblock->free_level < 0)
69bf686dbeSMatthew Dillon 		return(EINVAL);
70bf686dbeSMatthew Dillon 
71814387f6SMatthew Dillon 	reblock->cur_obj_id = reblock->beg_obj_id;
722f85fa4dSMatthew Dillon 	reblock->cur_localization = reblock->beg_localization;
73814387f6SMatthew Dillon 
74bf686dbeSMatthew Dillon retry:
754e17f465SMatthew Dillon 	error = hammer_init_cursor(trans, &cursor, NULL, NULL);
76bf686dbeSMatthew Dillon 	if (error) {
77bf686dbeSMatthew Dillon 		hammer_done_cursor(&cursor);
78bf686dbeSMatthew Dillon 		return(error);
79bf686dbeSMatthew Dillon 	}
802f85fa4dSMatthew Dillon 	cursor.key_beg.localization = reblock->cur_localization;
81bf686dbeSMatthew Dillon 	cursor.key_beg.obj_id = reblock->cur_obj_id;
82bf686dbeSMatthew Dillon 	cursor.key_beg.key = HAMMER_MIN_KEY;
83bf686dbeSMatthew Dillon 	cursor.key_beg.create_tid = 1;
84bf686dbeSMatthew Dillon 	cursor.key_beg.delete_tid = 0;
85bf686dbeSMatthew Dillon 	cursor.key_beg.rec_type = HAMMER_MIN_RECTYPE;
86bf686dbeSMatthew Dillon 	cursor.key_beg.obj_type = 0;
87bf686dbeSMatthew Dillon 
882f85fa4dSMatthew Dillon 	cursor.key_end.localization = reblock->end_localization;
89bf686dbeSMatthew Dillon 	cursor.key_end.obj_id = reblock->end_obj_id;
90bf686dbeSMatthew Dillon 	cursor.key_end.key = HAMMER_MAX_KEY;
91bf686dbeSMatthew Dillon 	cursor.key_end.create_tid = HAMMER_MAX_TID - 1;
92bf686dbeSMatthew Dillon 	cursor.key_end.delete_tid = 0;
93bf686dbeSMatthew Dillon 	cursor.key_end.rec_type = HAMMER_MAX_RECTYPE;
94bf686dbeSMatthew Dillon 	cursor.key_end.obj_type = 0;
95bf686dbeSMatthew Dillon 
96bf686dbeSMatthew Dillon 	cursor.flags |= HAMMER_CURSOR_END_INCLUSIVE;
979480ff55SMatthew Dillon 	cursor.flags |= HAMMER_CURSOR_BACKEND;
98bf686dbeSMatthew Dillon 
992f85fa4dSMatthew Dillon 	/*
1002f85fa4dSMatthew Dillon 	 * This flag allows the btree scan code to return internal nodes,
1012f85fa4dSMatthew Dillon 	 * so we can reblock them in addition to the leafs.  Only specify it
1022f85fa4dSMatthew Dillon 	 * if we intend to reblock B-Tree nodes.
1032f85fa4dSMatthew Dillon 	 */
1042f85fa4dSMatthew Dillon 	if (reblock->head.flags & HAMMER_IOC_DO_BTREE)
1052f85fa4dSMatthew Dillon 		cursor.flags |= HAMMER_CURSOR_REBLOCKING;
1062f85fa4dSMatthew Dillon 
107bf686dbeSMatthew Dillon 	error = hammer_btree_first(&cursor);
108bf686dbeSMatthew Dillon 	while (error == 0) {
1092f85fa4dSMatthew Dillon 		/*
1102f85fa4dSMatthew Dillon 		 * Internal or Leaf node
1112f85fa4dSMatthew Dillon 		 */
112bf686dbeSMatthew Dillon 		elm = &cursor.node->ondisk->elms[cursor.index];
113bf686dbeSMatthew Dillon 		reblock->cur_obj_id = elm->base.obj_id;
1142f85fa4dSMatthew Dillon 		reblock->cur_localization = elm->base.localization;
115bf686dbeSMatthew Dillon 
1169480ff55SMatthew Dillon 		/*
1179f5097dcSMatthew Dillon 		 * Yield to more important tasks
1189f5097dcSMatthew Dillon 		 */
1199f5097dcSMatthew Dillon 		if ((error = hammer_signal_check(trans->hmp)) != 0)
1209f5097dcSMatthew Dillon 			break;
1219f5097dcSMatthew Dillon 		if (trans->hmp->sync_lock.wanted) {
1229f5097dcSMatthew Dillon 			tsleep(trans, 0, "hmrslo", hz / 10);
1239f5097dcSMatthew Dillon 		}
1249f5097dcSMatthew Dillon 		if (trans->hmp->locked_dirty_count +
1259f5097dcSMatthew Dillon 		    trans->hmp->io_running_count > hammer_limit_dirtybufs) {
1269f5097dcSMatthew Dillon 			hammer_flusher_async(trans->hmp);
1279f5097dcSMatthew Dillon 			tsleep(trans, 0, "hmrslo", hz / 10);
1289f5097dcSMatthew Dillon 		}
1299f5097dcSMatthew Dillon 
1309f5097dcSMatthew Dillon 		/*
1319480ff55SMatthew Dillon 		 * Acquiring the sync_lock prevents the operation from
1329480ff55SMatthew Dillon 		 * crossing a synchronization boundary.
13309ac686bSMatthew Dillon 		 *
13409ac686bSMatthew Dillon 		 * NOTE: cursor.node may have changed on return.
1359480ff55SMatthew Dillon 		 */
1362f85fa4dSMatthew Dillon 		hammer_sync_lock_sh(trans);
13736f82b23SMatthew Dillon 		error = hammer_reblock_helper(reblock, &cursor, elm);
1382f85fa4dSMatthew Dillon 		hammer_sync_unlock(trans);
139bf686dbeSMatthew Dillon 		if (error == 0) {
140bf686dbeSMatthew Dillon 			cursor.flags |= HAMMER_CURSOR_ATEDISK;
141bf686dbeSMatthew Dillon 			error = hammer_btree_iterate(&cursor);
142bf686dbeSMatthew Dillon 		}
143bf686dbeSMatthew Dillon 	}
144bf686dbeSMatthew Dillon 	if (error == ENOENT)
145bf686dbeSMatthew Dillon 		error = 0;
146bf686dbeSMatthew Dillon 	hammer_done_cursor(&cursor);
147bf686dbeSMatthew Dillon 	if (error == EDEADLK)
148bf686dbeSMatthew Dillon 		goto retry;
14919619882SMatthew Dillon 	if (error == EINTR) {
15019619882SMatthew Dillon 		reblock->head.flags |= HAMMER_IOC_HEAD_INTR;
15119619882SMatthew Dillon 		error = 0;
15219619882SMatthew Dillon 	}
153bf686dbeSMatthew Dillon 	return(error);
154bf686dbeSMatthew Dillon }
155bf686dbeSMatthew Dillon 
156bf686dbeSMatthew Dillon /*
157bf686dbeSMatthew Dillon  * Reblock the B-Tree (leaf) node, record, and/or data if necessary.
158bf686dbeSMatthew Dillon  *
1599480ff55SMatthew Dillon  * XXX We have no visibility into internal B-Tree nodes at the moment,
1609480ff55SMatthew Dillon  * only leaf nodes.
161bf686dbeSMatthew Dillon  */
162bf686dbeSMatthew Dillon static int
16336f82b23SMatthew Dillon hammer_reblock_helper(struct hammer_ioc_reblock *reblock,
164bf686dbeSMatthew Dillon 		      hammer_cursor_t cursor, hammer_btree_elm_t elm)
165bf686dbeSMatthew Dillon {
166*43c665aeSMatthew Dillon 	hammer_mount_t hmp;
167bf686dbeSMatthew Dillon 	hammer_off_t tmp_offset;
168bf686dbeSMatthew Dillon 	int error;
169bf686dbeSMatthew Dillon 	int bytes;
170bf686dbeSMatthew Dillon 	int cur;
171bf3b416bSMatthew Dillon 	int iocflags;
172bf686dbeSMatthew Dillon 
173bf686dbeSMatthew Dillon 	error = 0;
174*43c665aeSMatthew Dillon 	hmp = cursor->trans->hmp;
175bf686dbeSMatthew Dillon 
176bf686dbeSMatthew Dillon 	/*
177bf686dbeSMatthew Dillon 	 * Reblock data.  Note that data embedded in a record is reblocked
1782f85fa4dSMatthew Dillon 	 * by the record reblock code.  Data processing only occurs at leaf
1792f85fa4dSMatthew Dillon 	 * nodes and for RECORD element types.
180bf686dbeSMatthew Dillon 	 */
1812f85fa4dSMatthew Dillon 	if (cursor->node->ondisk->type != HAMMER_BTREE_TYPE_LEAF)
1822f85fa4dSMatthew Dillon 		goto skip;
1832f85fa4dSMatthew Dillon 	if (elm->leaf.base.btype != HAMMER_BTREE_TYPE_RECORD)
1842f85fa4dSMatthew Dillon 		return(0);
185bf686dbeSMatthew Dillon 	tmp_offset = elm->leaf.data_offset;
186bf3b416bSMatthew Dillon 	if (tmp_offset == 0)
187bf3b416bSMatthew Dillon 		goto skip;
188bf3b416bSMatthew Dillon 	if (error)
189bf3b416bSMatthew Dillon 		goto skip;
190bf3b416bSMatthew Dillon 
191bf3b416bSMatthew Dillon 	/*
192bf3b416bSMatthew Dillon 	 * NOTE: Localization restrictions may also have been set-up, we can't
193bf3b416bSMatthew Dillon 	 * just set the match flags willy-nilly here.
194bf3b416bSMatthew Dillon 	 */
195bf3b416bSMatthew Dillon 	switch(elm->leaf.base.rec_type) {
196bf3b416bSMatthew Dillon 	case HAMMER_RECTYPE_INODE:
197bf3b416bSMatthew Dillon 		iocflags = HAMMER_IOC_DO_INODES;
198bf3b416bSMatthew Dillon 		break;
199bf3b416bSMatthew Dillon 	case HAMMER_RECTYPE_EXT:
200bf3b416bSMatthew Dillon 	case HAMMER_RECTYPE_FIX:
201bf3b416bSMatthew Dillon 	case HAMMER_RECTYPE_DIRENTRY:
202bf3b416bSMatthew Dillon 		iocflags = HAMMER_IOC_DO_DIRS;
203bf3b416bSMatthew Dillon 		break;
204bf3b416bSMatthew Dillon 	case HAMMER_RECTYPE_DATA:
205bf3b416bSMatthew Dillon 	case HAMMER_RECTYPE_DB:
206bf3b416bSMatthew Dillon 		iocflags = HAMMER_IOC_DO_DATA;
207bf3b416bSMatthew Dillon 		break;
208bf3b416bSMatthew Dillon 	default:
209bf3b416bSMatthew Dillon 		iocflags = 0;
210bf3b416bSMatthew Dillon 		break;
211bf3b416bSMatthew Dillon 	}
212bf3b416bSMatthew Dillon 	if (reblock->head.flags & iocflags) {
213bf686dbeSMatthew Dillon 		++reblock->data_count;
214bf686dbeSMatthew Dillon 		reblock->data_byte_count += elm->leaf.data_len;
215*43c665aeSMatthew Dillon 		bytes = hammer_blockmap_getfree(hmp, tmp_offset, &cur, &error);
2166e1e8b6dSMatthew Dillon 		if (hammer_debug_general & 0x4000)
2172f85fa4dSMatthew Dillon 			kprintf("D %6d/%d\n", bytes, reblock->free_level);
218bf3b416bSMatthew Dillon 		if (error == 0 && (cur == 0 || reblock->free_level == 0) &&
219bf3b416bSMatthew Dillon 		    bytes >= reblock->free_level) {
220*43c665aeSMatthew Dillon 			hammer_io_direct_uncache(hmp, &elm->leaf);
221bf686dbeSMatthew Dillon 			error = hammer_cursor_upgrade(cursor);
222bf686dbeSMatthew Dillon 			if (error == 0) {
22336f82b23SMatthew Dillon 				error = hammer_reblock_data(reblock,
224bf686dbeSMatthew Dillon 							    cursor, elm);
225bf686dbeSMatthew Dillon 			}
226bf686dbeSMatthew Dillon 			if (error == 0) {
227bf686dbeSMatthew Dillon 				++reblock->data_moves;
228bf686dbeSMatthew Dillon 				reblock->data_byte_moves += elm->leaf.data_len;
229bf686dbeSMatthew Dillon 			}
230bf686dbeSMatthew Dillon 		}
231bf686dbeSMatthew Dillon 	}
232bf686dbeSMatthew Dillon 
2332f85fa4dSMatthew Dillon skip:
234bf686dbeSMatthew Dillon 	/*
2352f85fa4dSMatthew Dillon 	 * Reblock a B-Tree internal or leaf node.
236bf686dbeSMatthew Dillon 	 */
237bf686dbeSMatthew Dillon 	tmp_offset = cursor->node->node_offset;
238bf3b416bSMatthew Dillon 	if (cursor->index == 0 &&
239814387f6SMatthew Dillon 	    error == 0 && (reblock->head.flags & HAMMER_IOC_DO_BTREE)) {
240bf686dbeSMatthew Dillon 		++reblock->btree_count;
241*43c665aeSMatthew Dillon 		bytes = hammer_blockmap_getfree(hmp, tmp_offset, &cur, &error);
2426e1e8b6dSMatthew Dillon 		if (hammer_debug_general & 0x4000)
2432f85fa4dSMatthew Dillon 			kprintf("B %6d/%d\n", bytes, reblock->free_level);
244bf3b416bSMatthew Dillon 		if (error == 0 && (cur == 0 || reblock->free_level == 0) &&
245bf3b416bSMatthew Dillon 		    bytes >= reblock->free_level) {
246bf686dbeSMatthew Dillon 			error = hammer_cursor_upgrade(cursor);
247bf686dbeSMatthew Dillon 			if (error == 0) {
248bf686dbeSMatthew Dillon 				if (cursor->parent)
249bf686dbeSMatthew Dillon 					elm = &cursor->parent->ondisk->elms[cursor->parent_index];
250bf686dbeSMatthew Dillon 				else
251bf686dbeSMatthew Dillon 					elm = NULL;
2522f85fa4dSMatthew Dillon 				switch(cursor->node->ondisk->type) {
2532f85fa4dSMatthew Dillon 				case HAMMER_BTREE_TYPE_LEAF:
2542f85fa4dSMatthew Dillon 					error = hammer_reblock_leaf_node(
2552f85fa4dSMatthew Dillon 							reblock, cursor, elm);
2562f85fa4dSMatthew Dillon 					break;
2572f85fa4dSMatthew Dillon 				case HAMMER_BTREE_TYPE_INTERNAL:
2582f85fa4dSMatthew Dillon 					error = hammer_reblock_int_node(
2592f85fa4dSMatthew Dillon 							reblock, cursor, elm);
2602f85fa4dSMatthew Dillon 					break;
2612f85fa4dSMatthew Dillon 				default:
2622f85fa4dSMatthew Dillon 					panic("Illegal B-Tree node type");
2632f85fa4dSMatthew Dillon 				}
264bf686dbeSMatthew Dillon 			}
265bf686dbeSMatthew Dillon 			if (error == 0) {
266bf686dbeSMatthew Dillon 				++reblock->btree_moves;
267bf686dbeSMatthew Dillon 			}
268bf686dbeSMatthew Dillon 		}
269bf686dbeSMatthew Dillon 	}
270bf686dbeSMatthew Dillon 
271bf686dbeSMatthew Dillon 	hammer_cursor_downgrade(cursor);
272bf686dbeSMatthew Dillon 	return(error);
273bf686dbeSMatthew Dillon }
274bf686dbeSMatthew Dillon 
275bf686dbeSMatthew Dillon /*
276bf686dbeSMatthew Dillon  * Reblock a record's data.  Both the B-Tree element and record pointers
277bf686dbeSMatthew Dillon  * to the data must be adjusted.
278bf686dbeSMatthew Dillon  */
279bf686dbeSMatthew Dillon static int
28036f82b23SMatthew Dillon hammer_reblock_data(struct hammer_ioc_reblock *reblock,
281bf686dbeSMatthew Dillon 		    hammer_cursor_t cursor, hammer_btree_elm_t elm)
282bf686dbeSMatthew Dillon {
283bf686dbeSMatthew Dillon 	struct hammer_buffer *data_buffer = NULL;
284bf686dbeSMatthew Dillon 	hammer_off_t ndata_offset;
285bf686dbeSMatthew Dillon 	int error;
286bf686dbeSMatthew Dillon 	void *ndata;
287bf686dbeSMatthew Dillon 
288bf686dbeSMatthew Dillon 	error = hammer_btree_extract(cursor, HAMMER_CURSOR_GET_DATA |
28911ad5adeSMatthew Dillon 					     HAMMER_CURSOR_GET_LEAF);
290bf686dbeSMatthew Dillon 	if (error)
291bf686dbeSMatthew Dillon 		return (error);
29236f82b23SMatthew Dillon 	ndata = hammer_alloc_data(cursor->trans, elm->leaf.data_len,
293bf3b416bSMatthew Dillon 				  elm->leaf.base.rec_type,
29436f82b23SMatthew Dillon 				  &ndata_offset, &data_buffer, &error);
295bf686dbeSMatthew Dillon 	if (error)
296bf686dbeSMatthew Dillon 		goto done;
297bf686dbeSMatthew Dillon 
298bf686dbeSMatthew Dillon 	/*
299bf686dbeSMatthew Dillon 	 * Move the data
300bf686dbeSMatthew Dillon 	 */
30110a5d1baSMatthew Dillon 	hammer_modify_buffer(cursor->trans, data_buffer, NULL, 0);
302bf686dbeSMatthew Dillon 	bcopy(cursor->data, ndata, elm->leaf.data_len);
30310a5d1baSMatthew Dillon 	hammer_modify_buffer_done(data_buffer);
304bf686dbeSMatthew Dillon 
30536f82b23SMatthew Dillon 	hammer_blockmap_free(cursor->trans,
30636f82b23SMatthew Dillon 			     elm->leaf.data_offset, elm->leaf.data_len);
307bf686dbeSMatthew Dillon 
30810a5d1baSMatthew Dillon 	hammer_modify_node(cursor->trans, cursor->node,
30910a5d1baSMatthew Dillon 			   &elm->leaf.data_offset, sizeof(hammer_off_t));
310bf686dbeSMatthew Dillon 	elm->leaf.data_offset = ndata_offset;
31110a5d1baSMatthew Dillon 	hammer_modify_node_done(cursor->node);
312bf686dbeSMatthew Dillon 
313bf686dbeSMatthew Dillon done:
314bf686dbeSMatthew Dillon 	if (data_buffer)
315bf686dbeSMatthew Dillon 		hammer_rel_buffer(data_buffer, 0);
316bf686dbeSMatthew Dillon 	return (error);
317bf686dbeSMatthew Dillon }
318bf686dbeSMatthew Dillon 
319bf686dbeSMatthew Dillon /*
3202f85fa4dSMatthew Dillon  * Reblock a B-Tree leaf node.  The parent must be adjusted to point to
3212f85fa4dSMatthew Dillon  * the new copy of the leaf node.
322bf686dbeSMatthew Dillon  *
3232f85fa4dSMatthew Dillon  * elm is a pointer to the parent element pointing at cursor.node.
324bf686dbeSMatthew Dillon  */
325bf686dbeSMatthew Dillon static int
3262f85fa4dSMatthew Dillon hammer_reblock_leaf_node(struct hammer_ioc_reblock *reblock,
327bf686dbeSMatthew Dillon 			 hammer_cursor_t cursor, hammer_btree_elm_t elm)
328bf686dbeSMatthew Dillon {
329bf686dbeSMatthew Dillon 	hammer_node_t onode;
330bf686dbeSMatthew Dillon 	hammer_node_t nnode;
331bf686dbeSMatthew Dillon 	int error;
332bf686dbeSMatthew Dillon 
333bf686dbeSMatthew Dillon 	onode = cursor->node;
33436f82b23SMatthew Dillon 	nnode = hammer_alloc_btree(cursor->trans, &error);
3358d0efe43SMatthew Dillon 
336bf686dbeSMatthew Dillon 	if (nnode == NULL)
337bf686dbeSMatthew Dillon 		return (error);
338bf686dbeSMatthew Dillon 
339bf686dbeSMatthew Dillon 	/*
340bf686dbeSMatthew Dillon 	 * Move the node
341bf686dbeSMatthew Dillon 	 */
34209ac686bSMatthew Dillon 	hammer_lock_ex(&nnode->lock);
34309ac686bSMatthew Dillon 	hammer_modify_node_noundo(cursor->trans, nnode);
344bf686dbeSMatthew Dillon 	bcopy(onode->ondisk, nnode->ondisk, sizeof(*nnode->ondisk));
345bf686dbeSMatthew Dillon 
346bf686dbeSMatthew Dillon 	if (elm) {
347bf686dbeSMatthew Dillon 		/*
348bf686dbeSMatthew Dillon 		 * We are not the root of the B-Tree
349bf686dbeSMatthew Dillon 		 */
35036f82b23SMatthew Dillon 		hammer_modify_node(cursor->trans, cursor->parent,
351bf686dbeSMatthew Dillon 				   &elm->internal.subtree_offset,
352bf686dbeSMatthew Dillon 				   sizeof(elm->internal.subtree_offset));
353bf686dbeSMatthew Dillon 		elm->internal.subtree_offset = nnode->node_offset;
35410a5d1baSMatthew Dillon 		hammer_modify_node_done(cursor->parent);
355bf686dbeSMatthew Dillon 	} else {
356bf686dbeSMatthew Dillon 		/*
357bf686dbeSMatthew Dillon 		 * We are the root of the B-Tree
358bf686dbeSMatthew Dillon 		 */
359bf686dbeSMatthew Dillon                 hammer_volume_t volume;
360bf686dbeSMatthew Dillon 
36136f82b23SMatthew Dillon                 volume = hammer_get_root_volume(cursor->trans->hmp, &error);
362bf686dbeSMatthew Dillon                 KKASSERT(error == 0);
363bf686dbeSMatthew Dillon 
364e8599db1SMatthew Dillon                 hammer_modify_volume_field(cursor->trans, volume,
365e8599db1SMatthew Dillon 					   vol0_btree_root);
366bf686dbeSMatthew Dillon                 volume->ondisk->vol0_btree_root = nnode->node_offset;
36710a5d1baSMatthew Dillon                 hammer_modify_volume_done(volume);
368bf686dbeSMatthew Dillon                 hammer_rel_volume(volume, 0);
369bf686dbeSMatthew Dillon         }
370bf686dbeSMatthew Dillon 
37136f82b23SMatthew Dillon 	hammer_delete_node(cursor->trans, onode);
372bf686dbeSMatthew Dillon 
373b58c6388SMatthew Dillon 	if (hammer_debug_general & 0x4000) {
3742f85fa4dSMatthew Dillon 		kprintf("REBLOCK LNODE %016llx -> %016llx\n",
375bf686dbeSMatthew Dillon 			onode->node_offset, nnode->node_offset);
376b58c6388SMatthew Dillon 	}
3778d0efe43SMatthew Dillon 	hammer_modify_node_done(nnode);
378bf686dbeSMatthew Dillon 	cursor->node = nnode;
37909ac686bSMatthew Dillon 
38009ac686bSMatthew Dillon 	hammer_unlock(&onode->lock);
381bf686dbeSMatthew Dillon 	hammer_rel_node(onode);
382bf686dbeSMatthew Dillon 
383bf686dbeSMatthew Dillon 	return (error);
384bf686dbeSMatthew Dillon }
385bf686dbeSMatthew Dillon 
3862f85fa4dSMatthew Dillon /*
3872f85fa4dSMatthew Dillon  * Reblock a B-Tree internal node.  The parent must be adjusted to point to
3882f85fa4dSMatthew Dillon  * the new copy of the internal node, and the node's children's parent
3892f85fa4dSMatthew Dillon  * pointers must also be adjusted to point to the new copy.
3902f85fa4dSMatthew Dillon  *
3912f85fa4dSMatthew Dillon  * elm is a pointer to the parent element pointing at cursor.node.
3922f85fa4dSMatthew Dillon  */
3932f85fa4dSMatthew Dillon static int
3942f85fa4dSMatthew Dillon hammer_reblock_int_node(struct hammer_ioc_reblock *reblock,
3952f85fa4dSMatthew Dillon 			 hammer_cursor_t cursor, hammer_btree_elm_t elm)
3962f85fa4dSMatthew Dillon {
3972f85fa4dSMatthew Dillon 	hammer_node_locklist_t locklist = NULL;
3982f85fa4dSMatthew Dillon 	hammer_node_t onode;
3992f85fa4dSMatthew Dillon 	hammer_node_t nnode;
4002f85fa4dSMatthew Dillon 	int error;
4012f85fa4dSMatthew Dillon 	int i;
4022f85fa4dSMatthew Dillon 
4032f85fa4dSMatthew Dillon 	error = hammer_btree_lock_children(cursor, &locklist);
4042f85fa4dSMatthew Dillon 	if (error)
4052f85fa4dSMatthew Dillon 		goto done;
4062f85fa4dSMatthew Dillon 
4072f85fa4dSMatthew Dillon 	onode = cursor->node;
4082f85fa4dSMatthew Dillon 	nnode = hammer_alloc_btree(cursor->trans, &error);
4092f85fa4dSMatthew Dillon 
4102f85fa4dSMatthew Dillon 	if (nnode == NULL)
4112f85fa4dSMatthew Dillon 		goto done;
4122f85fa4dSMatthew Dillon 
4132f85fa4dSMatthew Dillon 	/*
4142f85fa4dSMatthew Dillon 	 * Move the node.  Adjust the parent's pointer to us first.
4152f85fa4dSMatthew Dillon 	 */
4162f85fa4dSMatthew Dillon 	hammer_lock_ex(&nnode->lock);
4172f85fa4dSMatthew Dillon 	hammer_modify_node_noundo(cursor->trans, nnode);
4182f85fa4dSMatthew Dillon 	bcopy(onode->ondisk, nnode->ondisk, sizeof(*nnode->ondisk));
4192f85fa4dSMatthew Dillon 
4202f85fa4dSMatthew Dillon 	if (elm) {
4212f85fa4dSMatthew Dillon 		/*
4222f85fa4dSMatthew Dillon 		 * We are not the root of the B-Tree
4232f85fa4dSMatthew Dillon 		 */
4242f85fa4dSMatthew Dillon 		hammer_modify_node(cursor->trans, cursor->parent,
4252f85fa4dSMatthew Dillon 				   &elm->internal.subtree_offset,
4262f85fa4dSMatthew Dillon 				   sizeof(elm->internal.subtree_offset));
4272f85fa4dSMatthew Dillon 		elm->internal.subtree_offset = nnode->node_offset;
4282f85fa4dSMatthew Dillon 		hammer_modify_node_done(cursor->parent);
4292f85fa4dSMatthew Dillon 	} else {
4302f85fa4dSMatthew Dillon 		/*
4312f85fa4dSMatthew Dillon 		 * We are the root of the B-Tree
4322f85fa4dSMatthew Dillon 		 */
4332f85fa4dSMatthew Dillon                 hammer_volume_t volume;
4342f85fa4dSMatthew Dillon 
4352f85fa4dSMatthew Dillon                 volume = hammer_get_root_volume(cursor->trans->hmp, &error);
4362f85fa4dSMatthew Dillon                 KKASSERT(error == 0);
4372f85fa4dSMatthew Dillon 
4382f85fa4dSMatthew Dillon                 hammer_modify_volume_field(cursor->trans, volume,
4392f85fa4dSMatthew Dillon 					   vol0_btree_root);
4402f85fa4dSMatthew Dillon                 volume->ondisk->vol0_btree_root = nnode->node_offset;
4412f85fa4dSMatthew Dillon                 hammer_modify_volume_done(volume);
4422f85fa4dSMatthew Dillon                 hammer_rel_volume(volume, 0);
4432f85fa4dSMatthew Dillon         }
4442f85fa4dSMatthew Dillon 
4452f85fa4dSMatthew Dillon 	/*
4462f85fa4dSMatthew Dillon 	 * Now adjust our children's pointers to us.
4472f85fa4dSMatthew Dillon 	 */
4482f85fa4dSMatthew Dillon 	for (i = 0; i < nnode->ondisk->count; ++i) {
4492f85fa4dSMatthew Dillon 		elm = &nnode->ondisk->elms[i];
4502f85fa4dSMatthew Dillon 		error = btree_set_parent(cursor->trans, nnode, elm);
4512f85fa4dSMatthew Dillon 		if (error)
4522f85fa4dSMatthew Dillon 			panic("reblock internal node: fixup problem");
4532f85fa4dSMatthew Dillon 	}
4542f85fa4dSMatthew Dillon 
4552f85fa4dSMatthew Dillon 	/*
4562f85fa4dSMatthew Dillon 	 * Clean up.
4572f85fa4dSMatthew Dillon 	 *
4582f85fa4dSMatthew Dillon 	 * The new node replaces the current node in the cursor.  The cursor
4592f85fa4dSMatthew Dillon 	 * expects it to be locked so leave it locked.  Discard onode.
4602f85fa4dSMatthew Dillon 	 */
4612f85fa4dSMatthew Dillon 	hammer_delete_node(cursor->trans, onode);
4622f85fa4dSMatthew Dillon 
4632f85fa4dSMatthew Dillon 	if (hammer_debug_general & 0x4000) {
4642f85fa4dSMatthew Dillon 		kprintf("REBLOCK INODE %016llx -> %016llx\n",
4652f85fa4dSMatthew Dillon 			onode->node_offset, nnode->node_offset);
4662f85fa4dSMatthew Dillon 	}
4672f85fa4dSMatthew Dillon 	hammer_modify_node_done(nnode);
4682f85fa4dSMatthew Dillon 	cursor->node = nnode;
4692f85fa4dSMatthew Dillon 
4702f85fa4dSMatthew Dillon 	hammer_unlock(&onode->lock);
4712f85fa4dSMatthew Dillon 	hammer_rel_node(onode);
4722f85fa4dSMatthew Dillon 
4732f85fa4dSMatthew Dillon done:
4742f85fa4dSMatthew Dillon 	hammer_btree_unlock_children(&locklist);
4752f85fa4dSMatthew Dillon 	return (error);
4762f85fa4dSMatthew Dillon }
4772f85fa4dSMatthew Dillon 
478