xref: /dflybsd-src/sys/vfs/hammer/hammer_reblock.c (revision 6e1e8b6d5af6ed43d660602a410a5edd29533db1)
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*6e1e8b6dSMatthew Dillon  * $DragonFly: src/sys/vfs/hammer/hammer_reblock.c,v 1.6 2008/03/26 04:32:54 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);
5336f82b23SMatthew Dillon static int hammer_reblock_record(struct hammer_ioc_reblock *reblock,
54bf686dbeSMatthew Dillon 				hammer_cursor_t cursor, hammer_btree_elm_t elm);
5536f82b23SMatthew Dillon static int hammer_reblock_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 
71bf686dbeSMatthew Dillon retry:
7236f82b23SMatthew Dillon 	error = hammer_init_cursor(trans, &cursor, NULL);
73bf686dbeSMatthew Dillon 	if (error) {
74bf686dbeSMatthew Dillon 		hammer_done_cursor(&cursor);
75bf686dbeSMatthew Dillon 		return(error);
76bf686dbeSMatthew Dillon 	}
77bf686dbeSMatthew Dillon 	cursor.key_beg.obj_id = reblock->cur_obj_id;
78bf686dbeSMatthew Dillon 	cursor.key_beg.key = HAMMER_MIN_KEY;
79bf686dbeSMatthew Dillon 	cursor.key_beg.create_tid = 1;
80bf686dbeSMatthew Dillon 	cursor.key_beg.delete_tid = 0;
81bf686dbeSMatthew Dillon 	cursor.key_beg.rec_type = HAMMER_MIN_RECTYPE;
82bf686dbeSMatthew Dillon 	cursor.key_beg.obj_type = 0;
83bf686dbeSMatthew Dillon 
84bf686dbeSMatthew Dillon 	cursor.key_end.obj_id = reblock->end_obj_id;
85bf686dbeSMatthew Dillon 	cursor.key_end.key = HAMMER_MAX_KEY;
86bf686dbeSMatthew Dillon 	cursor.key_end.create_tid = HAMMER_MAX_TID - 1;
87bf686dbeSMatthew Dillon 	cursor.key_end.delete_tid = 0;
88bf686dbeSMatthew Dillon 	cursor.key_end.rec_type = HAMMER_MAX_RECTYPE;
89bf686dbeSMatthew Dillon 	cursor.key_end.obj_type = 0;
90bf686dbeSMatthew Dillon 
91bf686dbeSMatthew Dillon 	cursor.flags |= HAMMER_CURSOR_END_INCLUSIVE;
92bf686dbeSMatthew Dillon 
93bf686dbeSMatthew Dillon 	error = hammer_btree_first(&cursor);
94bf686dbeSMatthew Dillon 	while (error == 0) {
95bf686dbeSMatthew Dillon 		elm = &cursor.node->ondisk->elms[cursor.index];
96bf686dbeSMatthew Dillon 		reblock->cur_obj_id = elm->base.obj_id;
97bf686dbeSMatthew Dillon 
9836f82b23SMatthew Dillon 		error = hammer_reblock_helper(reblock, &cursor, elm);
99bf686dbeSMatthew Dillon 		if (error == 0) {
100bf686dbeSMatthew Dillon 			cursor.flags |= HAMMER_CURSOR_ATEDISK;
101bf686dbeSMatthew Dillon 			error = hammer_btree_iterate(&cursor);
102bf686dbeSMatthew Dillon 		}
103855942b6SMatthew Dillon 		if (error == 0)
104855942b6SMatthew Dillon 			error = hammer_signal_check(trans->hmp);
105bf686dbeSMatthew Dillon 	}
106bf686dbeSMatthew Dillon 	if (error == ENOENT)
107bf686dbeSMatthew Dillon 		error = 0;
108bf686dbeSMatthew Dillon 	hammer_done_cursor(&cursor);
109bf686dbeSMatthew Dillon 	if (error == EDEADLK)
110bf686dbeSMatthew Dillon 		goto retry;
111bf686dbeSMatthew Dillon 	return(error);
112bf686dbeSMatthew Dillon }
113bf686dbeSMatthew Dillon 
114bf686dbeSMatthew Dillon /*
115bf686dbeSMatthew Dillon  * Reblock the B-Tree (leaf) node, record, and/or data if necessary.
116bf686dbeSMatthew Dillon  *
117bf686dbeSMatthew Dillon  * XXX We have no visibility into internal B-Tree nodes at the moment.
118bf686dbeSMatthew Dillon  */
119bf686dbeSMatthew Dillon static int
12036f82b23SMatthew Dillon hammer_reblock_helper(struct hammer_ioc_reblock *reblock,
121bf686dbeSMatthew Dillon 		      hammer_cursor_t cursor, hammer_btree_elm_t elm)
122bf686dbeSMatthew Dillon {
123bf686dbeSMatthew Dillon 	hammer_off_t tmp_offset;
124bf686dbeSMatthew Dillon 	int error;
125bf686dbeSMatthew Dillon 	int zone;
126bf686dbeSMatthew Dillon 	int bytes;
127bf686dbeSMatthew Dillon 	int cur;
128bf686dbeSMatthew Dillon 
129bf686dbeSMatthew Dillon 	if (elm->leaf.base.btype != HAMMER_BTREE_TYPE_RECORD)
130bf686dbeSMatthew Dillon 		return(0);
131bf686dbeSMatthew Dillon 	error = 0;
132bf686dbeSMatthew Dillon 
133bf686dbeSMatthew Dillon 	/*
134bf686dbeSMatthew Dillon 	 * Reblock data.  Note that data embedded in a record is reblocked
135bf686dbeSMatthew Dillon 	 * by the record reblock code.
136bf686dbeSMatthew Dillon 	 */
137bf686dbeSMatthew Dillon 	tmp_offset = elm->leaf.data_offset;
138bf686dbeSMatthew Dillon 	zone = HAMMER_ZONE_DECODE(tmp_offset);		/* can be 0 */
139bf686dbeSMatthew Dillon 	if ((zone == HAMMER_ZONE_SMALL_DATA_INDEX ||
140bf686dbeSMatthew Dillon 	     zone == HAMMER_ZONE_LARGE_DATA_INDEX) && error == 0) {
141bf686dbeSMatthew Dillon 		++reblock->data_count;
142bf686dbeSMatthew Dillon 		reblock->data_byte_count += elm->leaf.data_len;
14336f82b23SMatthew Dillon 		bytes = hammer_blockmap_getfree(cursor->trans->hmp, tmp_offset,
14436f82b23SMatthew Dillon 						&cur, &error);
145bf686dbeSMatthew Dillon 		if (error == 0 && cur == 0 && bytes > reblock->free_level) {
146*6e1e8b6dSMatthew Dillon 			if (hammer_debug_general & 0x4000)
147bf686dbeSMatthew Dillon 				kprintf("%6d ", bytes);
148bf686dbeSMatthew Dillon 			error = hammer_cursor_upgrade(cursor);
149bf686dbeSMatthew Dillon 			if (error == 0) {
15036f82b23SMatthew Dillon 				error = hammer_reblock_data(reblock,
151bf686dbeSMatthew Dillon 							    cursor, elm);
152bf686dbeSMatthew Dillon 			}
153bf686dbeSMatthew Dillon 			if (error == 0) {
154bf686dbeSMatthew Dillon 				++reblock->data_moves;
155bf686dbeSMatthew Dillon 				reblock->data_byte_moves += elm->leaf.data_len;
156bf686dbeSMatthew Dillon 			}
157bf686dbeSMatthew Dillon 		}
158bf686dbeSMatthew Dillon 	}
159bf686dbeSMatthew Dillon 
160bf686dbeSMatthew Dillon 	/*
161bf686dbeSMatthew Dillon 	 * Reblock a record
162bf686dbeSMatthew Dillon 	 */
163bf686dbeSMatthew Dillon 	tmp_offset = elm->leaf.rec_offset;
164bf686dbeSMatthew Dillon 	zone = HAMMER_ZONE_DECODE(tmp_offset);
165bf686dbeSMatthew Dillon 	if (zone == HAMMER_ZONE_RECORD_INDEX && error == 0) {
166bf686dbeSMatthew Dillon 		++reblock->record_count;
16736f82b23SMatthew Dillon 		bytes = hammer_blockmap_getfree(cursor->trans->hmp, tmp_offset,
16836f82b23SMatthew Dillon 						&cur, &error);
169bf686dbeSMatthew Dillon 		if (error == 0 && cur == 0 && bytes > reblock->free_level) {
170*6e1e8b6dSMatthew Dillon 			if (hammer_debug_general & 0x4000)
171bf686dbeSMatthew Dillon 				kprintf("%6d ", bytes);
172bf686dbeSMatthew Dillon 			error = hammer_cursor_upgrade(cursor);
173bf686dbeSMatthew Dillon 			if (error == 0) {
17436f82b23SMatthew Dillon 				error = hammer_reblock_record(reblock,
175bf686dbeSMatthew Dillon 							      cursor, elm);
176bf686dbeSMatthew Dillon 			}
177bf686dbeSMatthew Dillon 			if (error == 0) {
178bf686dbeSMatthew Dillon 				++reblock->record_moves;
179bf686dbeSMatthew Dillon 			}
180bf686dbeSMatthew Dillon 		}
181bf686dbeSMatthew Dillon 	}
182bf686dbeSMatthew Dillon 
183bf686dbeSMatthew Dillon 	/*
184bf686dbeSMatthew Dillon 	 * Reblock a B-Tree node.  Adjust elm to point at the parent's
185bf686dbeSMatthew Dillon 	 * leaf entry.
186bf686dbeSMatthew Dillon 	 */
187bf686dbeSMatthew Dillon 	tmp_offset = cursor->node->node_offset;
188bf686dbeSMatthew Dillon 	zone = HAMMER_ZONE_DECODE(tmp_offset);
189bf686dbeSMatthew Dillon 	if (zone == HAMMER_ZONE_BTREE_INDEX && error == 0 &&
190bf686dbeSMatthew Dillon 	    cursor->index == 0) {
191bf686dbeSMatthew Dillon 		++reblock->btree_count;
19236f82b23SMatthew Dillon 		bytes = hammer_blockmap_getfree(cursor->trans->hmp, tmp_offset,
19336f82b23SMatthew Dillon 						&cur, &error);
194bf686dbeSMatthew Dillon 		if (error == 0 && cur == 0 && bytes > reblock->free_level) {
195*6e1e8b6dSMatthew Dillon 			if (hammer_debug_general & 0x4000)
196bf686dbeSMatthew Dillon 				kprintf("%6d ", bytes);
197bf686dbeSMatthew Dillon 			error = hammer_cursor_upgrade(cursor);
198bf686dbeSMatthew Dillon 			if (error == 0) {
199bf686dbeSMatthew Dillon 				if (cursor->parent)
200bf686dbeSMatthew Dillon 					elm = &cursor->parent->ondisk->elms[cursor->parent_index];
201bf686dbeSMatthew Dillon 				else
202bf686dbeSMatthew Dillon 					elm = NULL;
20336f82b23SMatthew Dillon 				error = hammer_reblock_node(reblock,
204bf686dbeSMatthew Dillon 							    cursor, elm);
205bf686dbeSMatthew Dillon 			}
206bf686dbeSMatthew Dillon 			if (error == 0) {
207bf686dbeSMatthew Dillon 				++reblock->btree_moves;
208bf686dbeSMatthew Dillon 			}
209bf686dbeSMatthew Dillon 		}
210bf686dbeSMatthew Dillon 	}
211bf686dbeSMatthew Dillon 
212bf686dbeSMatthew Dillon 	hammer_cursor_downgrade(cursor);
213bf686dbeSMatthew Dillon 	return(error);
214bf686dbeSMatthew Dillon }
215bf686dbeSMatthew Dillon 
216bf686dbeSMatthew Dillon /*
217bf686dbeSMatthew Dillon  * Reblock a record's data.  Both the B-Tree element and record pointers
218bf686dbeSMatthew Dillon  * to the data must be adjusted.
219bf686dbeSMatthew Dillon  */
220bf686dbeSMatthew Dillon static int
22136f82b23SMatthew Dillon hammer_reblock_data(struct hammer_ioc_reblock *reblock,
222bf686dbeSMatthew Dillon 		    hammer_cursor_t cursor, hammer_btree_elm_t elm)
223bf686dbeSMatthew Dillon {
224bf686dbeSMatthew Dillon 	struct hammer_buffer *data_buffer = NULL;
225bf686dbeSMatthew Dillon 	hammer_off_t ndata_offset;
226bf686dbeSMatthew Dillon 	int error;
227bf686dbeSMatthew Dillon 	void *ndata;
228bf686dbeSMatthew Dillon 
229bf686dbeSMatthew Dillon 	error = hammer_btree_extract(cursor, HAMMER_CURSOR_GET_DATA |
230bf686dbeSMatthew Dillon 					     HAMMER_CURSOR_GET_RECORD);
231bf686dbeSMatthew Dillon 	if (error)
232bf686dbeSMatthew Dillon 		return (error);
23336f82b23SMatthew Dillon 	ndata = hammer_alloc_data(cursor->trans, elm->leaf.data_len,
23436f82b23SMatthew Dillon 				  &ndata_offset, &data_buffer, &error);
235bf686dbeSMatthew Dillon 	if (error)
236bf686dbeSMatthew Dillon 		goto done;
237bf686dbeSMatthew Dillon 
238bf686dbeSMatthew Dillon 	/*
239bf686dbeSMatthew Dillon 	 * Move the data
240bf686dbeSMatthew Dillon 	 */
241bf686dbeSMatthew Dillon 	bcopy(cursor->data, ndata, elm->leaf.data_len);
24236f82b23SMatthew Dillon 	hammer_modify_node(cursor->trans, cursor->node,
243bf686dbeSMatthew Dillon 			   &elm->leaf.data_offset, sizeof(hammer_off_t));
24436f82b23SMatthew Dillon 	hammer_modify_record(cursor->trans, cursor->record_buffer,
24536f82b23SMatthew Dillon 			     &cursor->record->base.data_off,
24636f82b23SMatthew Dillon 			     sizeof(hammer_off_t));
247bf686dbeSMatthew Dillon 
24836f82b23SMatthew Dillon 	hammer_blockmap_free(cursor->trans,
24936f82b23SMatthew Dillon 			     elm->leaf.data_offset, elm->leaf.data_len);
250bf686dbeSMatthew Dillon 
251bf686dbeSMatthew Dillon 	cursor->record->base.data_off = ndata_offset;
252bf686dbeSMatthew Dillon 	elm->leaf.data_offset = ndata_offset;
253bf686dbeSMatthew Dillon 
254bf686dbeSMatthew Dillon done:
255bf686dbeSMatthew Dillon 	if (data_buffer)
256bf686dbeSMatthew Dillon 		hammer_rel_buffer(data_buffer, 0);
257bf686dbeSMatthew Dillon 	return (error);
258bf686dbeSMatthew Dillon }
259bf686dbeSMatthew Dillon 
260bf686dbeSMatthew Dillon /*
261bf686dbeSMatthew Dillon  * Reblock a record.  The B-Tree must be adjusted to point to the new record
262bf686dbeSMatthew Dillon  * and the existing record must be physically destroyed so a FS rebuild
263bf686dbeSMatthew Dillon  * does not see two versions of the same record.
264bf686dbeSMatthew Dillon  */
265bf686dbeSMatthew Dillon static int
26636f82b23SMatthew Dillon hammer_reblock_record(struct hammer_ioc_reblock *reblock,
267bf686dbeSMatthew Dillon 		      hammer_cursor_t cursor, hammer_btree_elm_t elm)
268bf686dbeSMatthew Dillon {
269bf686dbeSMatthew Dillon 	struct hammer_buffer *rec_buffer = NULL;
270bf686dbeSMatthew Dillon 	hammer_off_t nrec_offset;
2718fe2cd5dSMatthew Dillon 	hammer_off_t ndata_offset;
2728fe2cd5dSMatthew Dillon 	hammer_record_ondisk_t orec;
273bf686dbeSMatthew Dillon 	hammer_record_ondisk_t nrec;
274bf686dbeSMatthew Dillon 	int error;
2758fe2cd5dSMatthew Dillon 	int inline_data;
276bf686dbeSMatthew Dillon 
277bf686dbeSMatthew Dillon 	error = hammer_btree_extract(cursor, HAMMER_CURSOR_GET_RECORD);
278bf686dbeSMatthew Dillon 	if (error)
279bf686dbeSMatthew Dillon 		return (error);
280bf686dbeSMatthew Dillon 
28136f82b23SMatthew Dillon 	nrec = hammer_alloc_record(cursor->trans, &nrec_offset,
28236f82b23SMatthew Dillon 				   elm->leaf.base.rec_type, &rec_buffer,
28336f82b23SMatthew Dillon 				   0, NULL, NULL, &error);
284bf686dbeSMatthew Dillon 	if (error)
285bf686dbeSMatthew Dillon 		goto done;
286bf686dbeSMatthew Dillon 
287bf686dbeSMatthew Dillon 	/*
2888fe2cd5dSMatthew Dillon 	 * Move the record.  Check for an inline data reference and move that
2898fe2cd5dSMatthew Dillon 	 * too if necessary.
290bf686dbeSMatthew Dillon 	 */
2918fe2cd5dSMatthew Dillon 	orec = cursor->record;
2928fe2cd5dSMatthew Dillon 	bcopy(orec, nrec, sizeof(*nrec));
293bf686dbeSMatthew Dillon 
2948fe2cd5dSMatthew Dillon 	if ((orec->base.data_off & HAMMER_OFF_ZONE_MASK) == HAMMER_ZONE_RECORD) {
2958fe2cd5dSMatthew Dillon 		ndata_offset = orec->base.data_off - elm->leaf.rec_offset;
2968fe2cd5dSMatthew Dillon 		KKASSERT(ndata_offset < sizeof(*nrec));
2978fe2cd5dSMatthew Dillon 		ndata_offset += nrec_offset;
2988fe2cd5dSMatthew Dillon 		inline_data = 1;
2998fe2cd5dSMatthew Dillon 	} else {
3008fe2cd5dSMatthew Dillon 		ndata_offset = 0;
3018fe2cd5dSMatthew Dillon 		inline_data = 0;
3028fe2cd5dSMatthew Dillon 	}
3038fe2cd5dSMatthew Dillon 
30436f82b23SMatthew Dillon 	hammer_modify_record(cursor->trans, cursor->record_buffer,
30536f82b23SMatthew Dillon 			     &orec->base.base.rec_type,
30636f82b23SMatthew Dillon 			     sizeof(orec->base.base.rec_type));
3078fe2cd5dSMatthew Dillon 	orec->base.base.rec_type |= HAMMER_RECTYPE_MOVED;
308bf686dbeSMatthew Dillon 
30936f82b23SMatthew Dillon 	hammer_blockmap_free(cursor->trans,
31036f82b23SMatthew Dillon 			     elm->leaf.rec_offset, sizeof(*nrec));
311bf686dbeSMatthew Dillon 
312b58c6388SMatthew Dillon 	if (hammer_debug_general & 0x4000) {
313bf686dbeSMatthew Dillon 		kprintf("REBLOCK RECD %016llx -> %016llx\n",
314bf686dbeSMatthew Dillon 			elm->leaf.rec_offset, nrec_offset);
315b58c6388SMatthew Dillon 	}
3168fe2cd5dSMatthew Dillon 
31736f82b23SMatthew Dillon 	hammer_modify_node(cursor->trans, cursor->node,
3188fe2cd5dSMatthew Dillon 			   &elm->leaf.rec_offset, sizeof(hammer_off_t));
319bf686dbeSMatthew Dillon 	elm->leaf.rec_offset = nrec_offset;
3208fe2cd5dSMatthew Dillon 	if (inline_data) {
32136f82b23SMatthew Dillon 		hammer_modify_node(cursor->trans, cursor->node,
3228fe2cd5dSMatthew Dillon 				 &elm->leaf.data_offset, sizeof(hammer_off_t));
3238fe2cd5dSMatthew Dillon 		elm->leaf.data_offset = ndata_offset;
324*6e1e8b6dSMatthew Dillon 		nrec->base.data_off = ndata_offset;
3258fe2cd5dSMatthew Dillon 	}
326bf686dbeSMatthew Dillon 
327bf686dbeSMatthew Dillon done:
328bf686dbeSMatthew Dillon 	if (rec_buffer)
329bf686dbeSMatthew Dillon 		hammer_rel_buffer(rec_buffer, 0);
330bf686dbeSMatthew Dillon 	return (error);
331bf686dbeSMatthew Dillon }
332bf686dbeSMatthew Dillon 
333bf686dbeSMatthew Dillon /*
334bf686dbeSMatthew Dillon  * Reblock a B-Tree (leaf) node.  The parent must be adjusted to point to
335bf686dbeSMatthew Dillon  * the new copy of the leaf node.  elm is a pointer to the parent element
336bf686dbeSMatthew Dillon  * pointing at cursor.node.
337bf686dbeSMatthew Dillon  *
338bf686dbeSMatthew Dillon  * XXX reblock internal nodes too.
339bf686dbeSMatthew Dillon  */
340bf686dbeSMatthew Dillon static int
34136f82b23SMatthew Dillon hammer_reblock_node(struct hammer_ioc_reblock *reblock,
342bf686dbeSMatthew Dillon 		    hammer_cursor_t cursor, hammer_btree_elm_t elm)
343bf686dbeSMatthew Dillon {
344bf686dbeSMatthew Dillon 	hammer_node_t onode;
345bf686dbeSMatthew Dillon 	hammer_node_t nnode;
346bf686dbeSMatthew Dillon 	int error;
347bf686dbeSMatthew Dillon 
348bf686dbeSMatthew Dillon 	onode = cursor->node;
34936f82b23SMatthew Dillon 	nnode = hammer_alloc_btree(cursor->trans, &error);
350bf686dbeSMatthew Dillon 	hammer_lock_ex(&nnode->lock);
351bf686dbeSMatthew Dillon 
352bf686dbeSMatthew Dillon 	if (nnode == NULL)
353bf686dbeSMatthew Dillon 		return (error);
354bf686dbeSMatthew Dillon 
355bf686dbeSMatthew Dillon 	/*
356bf686dbeSMatthew Dillon 	 * Move the node
357bf686dbeSMatthew Dillon 	 */
358bf686dbeSMatthew Dillon 	bcopy(onode->ondisk, nnode->ondisk, sizeof(*nnode->ondisk));
359bf686dbeSMatthew Dillon 
360bf686dbeSMatthew Dillon 	if (elm) {
361bf686dbeSMatthew Dillon 		/*
362bf686dbeSMatthew Dillon 		 * We are not the root of the B-Tree
363bf686dbeSMatthew Dillon 		 */
36436f82b23SMatthew Dillon 		hammer_modify_node(cursor->trans, cursor->parent,
365bf686dbeSMatthew Dillon 				   &elm->internal.subtree_offset,
366bf686dbeSMatthew Dillon 				   sizeof(elm->internal.subtree_offset));
367bf686dbeSMatthew Dillon 		elm->internal.subtree_offset = nnode->node_offset;
368bf686dbeSMatthew Dillon 	} else {
369bf686dbeSMatthew Dillon 		/*
370bf686dbeSMatthew Dillon 		 * We are the root of the B-Tree
371bf686dbeSMatthew Dillon 		 */
372bf686dbeSMatthew Dillon                 hammer_volume_t volume;
373bf686dbeSMatthew Dillon 
37436f82b23SMatthew Dillon                 volume = hammer_get_root_volume(cursor->trans->hmp, &error);
375bf686dbeSMatthew Dillon                 KKASSERT(error == 0);
376bf686dbeSMatthew Dillon 
37736f82b23SMatthew Dillon                 hammer_modify_volume(cursor->trans, volume,
37836f82b23SMatthew Dillon 				     &volume->ondisk->vol0_btree_root,
379bf686dbeSMatthew Dillon                                      sizeof(hammer_off_t));
380bf686dbeSMatthew Dillon                 volume->ondisk->vol0_btree_root = nnode->node_offset;
381bf686dbeSMatthew Dillon                 hammer_rel_volume(volume, 0);
382bf686dbeSMatthew Dillon         }
383bf686dbeSMatthew Dillon 
38436f82b23SMatthew Dillon 	hammer_delete_node(cursor->trans, onode);
385bf686dbeSMatthew Dillon 
386b58c6388SMatthew Dillon 	if (hammer_debug_general & 0x4000) {
387bf686dbeSMatthew Dillon 		kprintf("REBLOCK NODE %016llx -> %016llx\n",
388bf686dbeSMatthew Dillon 			onode->node_offset, nnode->node_offset);
389b58c6388SMatthew Dillon 	}
390bf686dbeSMatthew Dillon 
391bf686dbeSMatthew Dillon 	cursor->node = nnode;
392bf686dbeSMatthew Dillon 	hammer_rel_node(onode);
393bf686dbeSMatthew Dillon 
394bf686dbeSMatthew Dillon 	return (error);
395bf686dbeSMatthew Dillon }
396bf686dbeSMatthew Dillon 
397