xref: /dflybsd-src/sys/vfs/hammer/hammer_reblock.c (revision dd94f1b1ad357fec1cb4404c99bb7ed9ba6460d1)
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