xref: /dflybsd-src/sys/vfs/hammer/hammer_reblock.c (revision 8fe2cd5d365daa6ad185c70c82376bc7635e1427)
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*8fe2cd5dSMatthew Dillon  * $DragonFly: src/sys/vfs/hammer/hammer_reblock.c,v 1.2 2008/03/18 20:20:26 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 
48bf686dbeSMatthew Dillon static int hammer_reblock_helper(hammer_mount_t hmp,
49bf686dbeSMatthew Dillon 				 struct hammer_ioc_reblock *reblock,
50bf686dbeSMatthew Dillon 				 hammer_cursor_t cursor,
51bf686dbeSMatthew Dillon 				 hammer_btree_elm_t elm);
52bf686dbeSMatthew Dillon static int hammer_reblock_data(hammer_mount_t hmp,
53bf686dbeSMatthew Dillon 				struct hammer_ioc_reblock *reblock,
54bf686dbeSMatthew Dillon 				hammer_cursor_t cursor, hammer_btree_elm_t elm);
55bf686dbeSMatthew Dillon static int hammer_reblock_record(hammer_mount_t hmp,
56bf686dbeSMatthew Dillon 				struct hammer_ioc_reblock *reblock,
57bf686dbeSMatthew Dillon 				hammer_cursor_t cursor, hammer_btree_elm_t elm);
58bf686dbeSMatthew Dillon static int hammer_reblock_node(hammer_mount_t hmp,
59bf686dbeSMatthew Dillon 				struct hammer_ioc_reblock *reblock,
60bf686dbeSMatthew Dillon 				hammer_cursor_t cursor, hammer_btree_elm_t elm);
61bf686dbeSMatthew Dillon 
62bf686dbeSMatthew Dillon int
63bf686dbeSMatthew Dillon hammer_reblock(hammer_inode_t ip, struct hammer_ioc_reblock *reblock)
64bf686dbeSMatthew Dillon {
65bf686dbeSMatthew Dillon 	struct hammer_cursor cursor;
66bf686dbeSMatthew Dillon 	hammer_btree_elm_t elm;
67bf686dbeSMatthew Dillon 	int error;
68bf686dbeSMatthew Dillon 
69bf686dbeSMatthew Dillon 	if (reblock->beg_obj_id >= reblock->end_obj_id)
70bf686dbeSMatthew Dillon 		return(EINVAL);
71bf686dbeSMatthew Dillon 	if (reblock->free_level < 0)
72bf686dbeSMatthew Dillon 		return(EINVAL);
73bf686dbeSMatthew Dillon 
74bf686dbeSMatthew Dillon retry:
75bf686dbeSMatthew Dillon 	error = hammer_init_cursor_hmp(&cursor, NULL, ip->hmp);
76bf686dbeSMatthew Dillon 	if (error) {
77bf686dbeSMatthew Dillon 		hammer_done_cursor(&cursor);
78bf686dbeSMatthew Dillon 		return(error);
79bf686dbeSMatthew Dillon 	}
80bf686dbeSMatthew Dillon 	cursor.key_beg.obj_id = reblock->cur_obj_id;
81bf686dbeSMatthew Dillon 	cursor.key_beg.key = HAMMER_MIN_KEY;
82bf686dbeSMatthew Dillon 	cursor.key_beg.create_tid = 1;
83bf686dbeSMatthew Dillon 	cursor.key_beg.delete_tid = 0;
84bf686dbeSMatthew Dillon 	cursor.key_beg.rec_type = HAMMER_MIN_RECTYPE;
85bf686dbeSMatthew Dillon 	cursor.key_beg.obj_type = 0;
86bf686dbeSMatthew Dillon 
87bf686dbeSMatthew Dillon 	cursor.key_end.obj_id = reblock->end_obj_id;
88bf686dbeSMatthew Dillon 	cursor.key_end.key = HAMMER_MAX_KEY;
89bf686dbeSMatthew Dillon 	cursor.key_end.create_tid = HAMMER_MAX_TID - 1;
90bf686dbeSMatthew Dillon 	cursor.key_end.delete_tid = 0;
91bf686dbeSMatthew Dillon 	cursor.key_end.rec_type = HAMMER_MAX_RECTYPE;
92bf686dbeSMatthew Dillon 	cursor.key_end.obj_type = 0;
93bf686dbeSMatthew Dillon 
94bf686dbeSMatthew Dillon 	cursor.flags |= HAMMER_CURSOR_END_INCLUSIVE;
95bf686dbeSMatthew Dillon 
96bf686dbeSMatthew Dillon 	error = hammer_btree_first(&cursor);
97bf686dbeSMatthew Dillon 	while (error == 0) {
98bf686dbeSMatthew Dillon 		elm = &cursor.node->ondisk->elms[cursor.index];
99bf686dbeSMatthew Dillon 		reblock->cur_obj_id = elm->base.obj_id;
100bf686dbeSMatthew Dillon 
101bf686dbeSMatthew Dillon 		error = hammer_reblock_helper(ip->hmp, reblock, &cursor, elm);
102bf686dbeSMatthew Dillon 		if (error == 0) {
103bf686dbeSMatthew Dillon 			cursor.flags |= HAMMER_CURSOR_ATEDISK;
104bf686dbeSMatthew Dillon 			error = hammer_btree_iterate(&cursor);
105bf686dbeSMatthew Dillon 		}
106bf686dbeSMatthew Dillon 	}
107bf686dbeSMatthew Dillon 	if (error == ENOENT)
108bf686dbeSMatthew Dillon 		error = 0;
109bf686dbeSMatthew Dillon 	hammer_done_cursor(&cursor);
110bf686dbeSMatthew Dillon 	if (error == EDEADLK)
111bf686dbeSMatthew Dillon 		goto retry;
112bf686dbeSMatthew Dillon 	return(error);
113bf686dbeSMatthew Dillon }
114bf686dbeSMatthew Dillon 
115bf686dbeSMatthew Dillon /*
116bf686dbeSMatthew Dillon  * Reblock the B-Tree (leaf) node, record, and/or data if necessary.
117bf686dbeSMatthew Dillon  *
118bf686dbeSMatthew Dillon  * XXX We have no visibility into internal B-Tree nodes at the moment.
119bf686dbeSMatthew Dillon  */
120bf686dbeSMatthew Dillon static int
121bf686dbeSMatthew Dillon hammer_reblock_helper(hammer_mount_t hmp, struct hammer_ioc_reblock *reblock,
122bf686dbeSMatthew Dillon 		      hammer_cursor_t cursor, hammer_btree_elm_t elm)
123bf686dbeSMatthew Dillon {
124bf686dbeSMatthew Dillon 	hammer_off_t tmp_offset;
125bf686dbeSMatthew Dillon 	int error;
126bf686dbeSMatthew Dillon 	int zone;
127bf686dbeSMatthew Dillon 	int bytes;
128bf686dbeSMatthew Dillon 	int cur;
129bf686dbeSMatthew Dillon 
130bf686dbeSMatthew Dillon 	if (elm->leaf.base.btype != HAMMER_BTREE_TYPE_RECORD)
131bf686dbeSMatthew Dillon 		return(0);
132bf686dbeSMatthew Dillon 	error = 0;
133bf686dbeSMatthew Dillon 
134bf686dbeSMatthew Dillon 	/*
135bf686dbeSMatthew Dillon 	 * Reblock data.  Note that data embedded in a record is reblocked
136bf686dbeSMatthew Dillon 	 * by the record reblock code.
137bf686dbeSMatthew Dillon 	 */
138bf686dbeSMatthew Dillon 	tmp_offset = elm->leaf.data_offset;
139bf686dbeSMatthew Dillon 	zone = HAMMER_ZONE_DECODE(tmp_offset);		/* can be 0 */
140bf686dbeSMatthew Dillon 	if ((zone == HAMMER_ZONE_SMALL_DATA_INDEX ||
141bf686dbeSMatthew Dillon 	     zone == HAMMER_ZONE_LARGE_DATA_INDEX) && error == 0) {
142bf686dbeSMatthew Dillon 		++reblock->data_count;
143bf686dbeSMatthew Dillon 		reblock->data_byte_count += elm->leaf.data_len;
144bf686dbeSMatthew Dillon 		bytes = hammer_blockmap_getfree(hmp, tmp_offset, &cur, &error);
145bf686dbeSMatthew Dillon 		if (error == 0 && cur == 0 && bytes > reblock->free_level) {
146bf686dbeSMatthew Dillon 			kprintf("%6d ", bytes);
147bf686dbeSMatthew Dillon 			error = hammer_cursor_upgrade(cursor);
148bf686dbeSMatthew Dillon 			if (error == 0) {
149bf686dbeSMatthew Dillon 				error = hammer_reblock_data(hmp, reblock,
150bf686dbeSMatthew Dillon 							    cursor, elm);
151bf686dbeSMatthew Dillon 			}
152bf686dbeSMatthew Dillon 			if (error == 0) {
153bf686dbeSMatthew Dillon 				++reblock->data_moves;
154bf686dbeSMatthew Dillon 				reblock->data_byte_moves += elm->leaf.data_len;
155bf686dbeSMatthew Dillon 			}
156bf686dbeSMatthew Dillon 		}
157bf686dbeSMatthew Dillon 	}
158bf686dbeSMatthew Dillon 
159bf686dbeSMatthew Dillon 	/*
160bf686dbeSMatthew Dillon 	 * Reblock a record
161bf686dbeSMatthew Dillon 	 */
162bf686dbeSMatthew Dillon 	tmp_offset = elm->leaf.rec_offset;
163bf686dbeSMatthew Dillon 	zone = HAMMER_ZONE_DECODE(tmp_offset);
164bf686dbeSMatthew Dillon 	if (zone == HAMMER_ZONE_RECORD_INDEX && error == 0) {
165bf686dbeSMatthew Dillon 		++reblock->record_count;
166bf686dbeSMatthew Dillon 		bytes = hammer_blockmap_getfree(hmp, tmp_offset, &cur, &error);
167bf686dbeSMatthew Dillon 		if (error == 0 && cur == 0 && bytes > reblock->free_level) {
168bf686dbeSMatthew Dillon 			kprintf("%6d ", bytes);
169bf686dbeSMatthew Dillon 			error = hammer_cursor_upgrade(cursor);
170bf686dbeSMatthew Dillon 			if (error == 0) {
171bf686dbeSMatthew Dillon 				error = hammer_reblock_record(hmp, reblock,
172bf686dbeSMatthew Dillon 							      cursor, elm);
173bf686dbeSMatthew Dillon 			}
174bf686dbeSMatthew Dillon 			if (error == 0) {
175bf686dbeSMatthew Dillon 				++reblock->record_moves;
176bf686dbeSMatthew Dillon 			}
177bf686dbeSMatthew Dillon 		}
178bf686dbeSMatthew Dillon 	}
179bf686dbeSMatthew Dillon 
180bf686dbeSMatthew Dillon 	/*
181bf686dbeSMatthew Dillon 	 * Reblock a B-Tree node.  Adjust elm to point at the parent's
182bf686dbeSMatthew Dillon 	 * leaf entry.
183bf686dbeSMatthew Dillon 	 */
184bf686dbeSMatthew Dillon 	tmp_offset = cursor->node->node_offset;
185bf686dbeSMatthew Dillon 	zone = HAMMER_ZONE_DECODE(tmp_offset);
186bf686dbeSMatthew Dillon 	if (zone == HAMMER_ZONE_BTREE_INDEX && error == 0 &&
187bf686dbeSMatthew Dillon 	    cursor->index == 0) {
188bf686dbeSMatthew Dillon 		++reblock->btree_count;
189bf686dbeSMatthew Dillon 		bytes = hammer_blockmap_getfree(hmp, tmp_offset, &cur, &error);
190bf686dbeSMatthew Dillon 		if (error == 0 && cur == 0 && bytes > reblock->free_level) {
191bf686dbeSMatthew Dillon 			kprintf("%6d ", bytes);
192bf686dbeSMatthew Dillon 			error = hammer_cursor_upgrade(cursor);
193bf686dbeSMatthew Dillon 			if (error == 0) {
194bf686dbeSMatthew Dillon 				if (cursor->parent)
195bf686dbeSMatthew Dillon 					elm = &cursor->parent->ondisk->elms[cursor->parent_index];
196bf686dbeSMatthew Dillon 				else
197bf686dbeSMatthew Dillon 					elm = NULL;
198bf686dbeSMatthew Dillon 				error = hammer_reblock_node(hmp, reblock,
199bf686dbeSMatthew Dillon 							    cursor, elm);
200bf686dbeSMatthew Dillon 			}
201bf686dbeSMatthew Dillon 			if (error == 0) {
202bf686dbeSMatthew Dillon 				++reblock->btree_moves;
203bf686dbeSMatthew Dillon 			}
204bf686dbeSMatthew Dillon 		}
205bf686dbeSMatthew Dillon 	}
206bf686dbeSMatthew Dillon 
207bf686dbeSMatthew Dillon 	hammer_cursor_downgrade(cursor);
208bf686dbeSMatthew Dillon 	return(error);
209bf686dbeSMatthew Dillon }
210bf686dbeSMatthew Dillon 
211bf686dbeSMatthew Dillon /*
212bf686dbeSMatthew Dillon  * Reblock a record's data.  Both the B-Tree element and record pointers
213bf686dbeSMatthew Dillon  * to the data must be adjusted.
214bf686dbeSMatthew Dillon  */
215bf686dbeSMatthew Dillon static int
216bf686dbeSMatthew Dillon hammer_reblock_data(hammer_mount_t hmp, struct hammer_ioc_reblock *reblock,
217bf686dbeSMatthew Dillon 		    hammer_cursor_t cursor, hammer_btree_elm_t elm)
218bf686dbeSMatthew Dillon {
219bf686dbeSMatthew Dillon 	struct hammer_buffer *data_buffer = NULL;
220bf686dbeSMatthew Dillon 	hammer_off_t ndata_offset;
221bf686dbeSMatthew Dillon 	int error;
222bf686dbeSMatthew Dillon 	void *ndata;
223bf686dbeSMatthew Dillon 
224bf686dbeSMatthew Dillon 	error = hammer_btree_extract(cursor, HAMMER_CURSOR_GET_DATA |
225bf686dbeSMatthew Dillon 					     HAMMER_CURSOR_GET_RECORD);
226bf686dbeSMatthew Dillon 	if (error)
227bf686dbeSMatthew Dillon 		return (error);
228bf686dbeSMatthew Dillon 	ndata = hammer_alloc_data(hmp, elm->leaf.data_len, &ndata_offset,
229bf686dbeSMatthew Dillon 				  &data_buffer, &error);
230bf686dbeSMatthew Dillon 	if (error)
231bf686dbeSMatthew Dillon 		goto done;
232bf686dbeSMatthew Dillon 
233bf686dbeSMatthew Dillon 	/*
234bf686dbeSMatthew Dillon 	 * Move the data
235bf686dbeSMatthew Dillon 	 */
236bf686dbeSMatthew Dillon 	bcopy(cursor->data, ndata, elm->leaf.data_len);
237bf686dbeSMatthew Dillon 	hammer_modify_node(cursor->node,
238bf686dbeSMatthew Dillon 		&elm->leaf.data_offset, sizeof(hammer_off_t));
239bf686dbeSMatthew Dillon 	hammer_modify_record(cursor->record_buffer,
240bf686dbeSMatthew Dillon 		&cursor->record->base.data_off, sizeof(hammer_off_t));
241bf686dbeSMatthew Dillon 
242bf686dbeSMatthew Dillon 	hammer_blockmap_free(hmp, elm->leaf.data_offset, elm->leaf.data_len);
243bf686dbeSMatthew Dillon 
244bf686dbeSMatthew Dillon 	cursor->record->base.data_off = ndata_offset;
245bf686dbeSMatthew Dillon 	elm->leaf.data_offset = ndata_offset;
246bf686dbeSMatthew Dillon 
247bf686dbeSMatthew Dillon done:
248bf686dbeSMatthew Dillon 	if (data_buffer)
249bf686dbeSMatthew Dillon 		hammer_rel_buffer(data_buffer, 0);
250bf686dbeSMatthew Dillon 	return (error);
251bf686dbeSMatthew Dillon }
252bf686dbeSMatthew Dillon 
253bf686dbeSMatthew Dillon /*
254bf686dbeSMatthew Dillon  * Reblock a record.  The B-Tree must be adjusted to point to the new record
255bf686dbeSMatthew Dillon  * and the existing record must be physically destroyed so a FS rebuild
256bf686dbeSMatthew Dillon  * does not see two versions of the same record.
257bf686dbeSMatthew Dillon  */
258bf686dbeSMatthew Dillon static int
259bf686dbeSMatthew Dillon hammer_reblock_record(hammer_mount_t hmp, struct hammer_ioc_reblock *reblock,
260bf686dbeSMatthew Dillon 		      hammer_cursor_t cursor, hammer_btree_elm_t elm)
261bf686dbeSMatthew Dillon {
262bf686dbeSMatthew Dillon 	struct hammer_buffer *rec_buffer = NULL;
263bf686dbeSMatthew Dillon 	hammer_off_t nrec_offset;
264*8fe2cd5dSMatthew Dillon 	hammer_off_t ndata_offset;
265*8fe2cd5dSMatthew Dillon 	hammer_record_ondisk_t orec;
266bf686dbeSMatthew Dillon 	hammer_record_ondisk_t nrec;
267bf686dbeSMatthew Dillon 	int error;
268*8fe2cd5dSMatthew Dillon 	int inline_data;
269bf686dbeSMatthew Dillon 
270bf686dbeSMatthew Dillon 	error = hammer_btree_extract(cursor, HAMMER_CURSOR_GET_RECORD);
271bf686dbeSMatthew Dillon 	if (error)
272bf686dbeSMatthew Dillon 		return (error);
273bf686dbeSMatthew Dillon 
274bf686dbeSMatthew Dillon 	nrec = hammer_alloc_record(hmp, &nrec_offset, elm->leaf.base.rec_type,
275bf686dbeSMatthew Dillon 				  &rec_buffer, 0, NULL, NULL, &error);
276bf686dbeSMatthew Dillon 	if (error)
277bf686dbeSMatthew Dillon 		goto done;
278bf686dbeSMatthew Dillon 
279bf686dbeSMatthew Dillon 	/*
280*8fe2cd5dSMatthew Dillon 	 * Move the record.  Check for an inline data reference and move that
281*8fe2cd5dSMatthew Dillon 	 * too if necessary.
282bf686dbeSMatthew Dillon 	 */
283*8fe2cd5dSMatthew Dillon 	orec = cursor->record;
284*8fe2cd5dSMatthew Dillon 	bcopy(orec, nrec, sizeof(*nrec));
285bf686dbeSMatthew Dillon 
286*8fe2cd5dSMatthew Dillon 	if ((orec->base.data_off & HAMMER_OFF_ZONE_MASK) == HAMMER_ZONE_RECORD) {
287*8fe2cd5dSMatthew Dillon 		ndata_offset = orec->base.data_off - elm->leaf.rec_offset;
288*8fe2cd5dSMatthew Dillon 		KKASSERT(ndata_offset < sizeof(*nrec));
289*8fe2cd5dSMatthew Dillon 		ndata_offset += nrec_offset;
290*8fe2cd5dSMatthew Dillon 		inline_data = 1;
291*8fe2cd5dSMatthew Dillon 	} else {
292*8fe2cd5dSMatthew Dillon 		ndata_offset = 0;
293*8fe2cd5dSMatthew Dillon 		inline_data = 0;
294*8fe2cd5dSMatthew Dillon 	}
295*8fe2cd5dSMatthew Dillon 
296bf686dbeSMatthew Dillon 	hammer_modify_record(cursor->record_buffer,
297*8fe2cd5dSMatthew Dillon 		&orec->base.base.rec_type, sizeof(orec->base.base.rec_type));
298*8fe2cd5dSMatthew Dillon 	orec->base.base.rec_type |= HAMMER_RECTYPE_MOVED;
299bf686dbeSMatthew Dillon 
300bf686dbeSMatthew Dillon 	hammer_blockmap_free(hmp, elm->leaf.rec_offset, sizeof(*nrec));
301bf686dbeSMatthew Dillon 
302bf686dbeSMatthew Dillon 	kprintf("REBLOCK RECD %016llx -> %016llx\n",
303bf686dbeSMatthew Dillon 		elm->leaf.rec_offset, nrec_offset);
304*8fe2cd5dSMatthew Dillon 
305*8fe2cd5dSMatthew Dillon 	hammer_modify_node(cursor->node,
306*8fe2cd5dSMatthew Dillon 		&elm->leaf.rec_offset, sizeof(hammer_off_t));
307bf686dbeSMatthew Dillon 	elm->leaf.rec_offset = nrec_offset;
308*8fe2cd5dSMatthew Dillon 	if (inline_data) {
309*8fe2cd5dSMatthew Dillon 		hammer_modify_node(cursor->node,
310*8fe2cd5dSMatthew Dillon 			&elm->leaf.data_offset, sizeof(hammer_off_t));
311*8fe2cd5dSMatthew Dillon 		elm->leaf.data_offset = ndata_offset;
312*8fe2cd5dSMatthew Dillon 	}
313bf686dbeSMatthew Dillon 
314bf686dbeSMatthew Dillon done:
315bf686dbeSMatthew Dillon 	if (rec_buffer)
316bf686dbeSMatthew Dillon 		hammer_rel_buffer(rec_buffer, 0);
317bf686dbeSMatthew Dillon 	return (error);
318bf686dbeSMatthew Dillon }
319bf686dbeSMatthew Dillon 
320bf686dbeSMatthew Dillon /*
321bf686dbeSMatthew Dillon  * Reblock a B-Tree (leaf) node.  The parent must be adjusted to point to
322bf686dbeSMatthew Dillon  * the new copy of the leaf node.  elm is a pointer to the parent element
323bf686dbeSMatthew Dillon  * pointing at cursor.node.
324bf686dbeSMatthew Dillon  *
325bf686dbeSMatthew Dillon  * XXX reblock internal nodes too.
326bf686dbeSMatthew Dillon  */
327bf686dbeSMatthew Dillon static int
328bf686dbeSMatthew Dillon hammer_reblock_node(hammer_mount_t hmp, struct hammer_ioc_reblock *reblock,
329bf686dbeSMatthew Dillon 		    hammer_cursor_t cursor, hammer_btree_elm_t elm)
330bf686dbeSMatthew Dillon {
331bf686dbeSMatthew Dillon 	hammer_node_t onode;
332bf686dbeSMatthew Dillon 	hammer_node_t nnode;
333bf686dbeSMatthew Dillon 	int error;
334bf686dbeSMatthew Dillon 
335bf686dbeSMatthew Dillon 	onode = cursor->node;
336bf686dbeSMatthew Dillon 	nnode = hammer_alloc_btree(hmp, &error);
337bf686dbeSMatthew Dillon 	hammer_lock_ex(&nnode->lock);
338bf686dbeSMatthew Dillon 
339bf686dbeSMatthew Dillon 	if (nnode == NULL)
340bf686dbeSMatthew Dillon 		return (error);
341bf686dbeSMatthew Dillon 
342bf686dbeSMatthew Dillon 	/*
343bf686dbeSMatthew Dillon 	 * Move the node
344bf686dbeSMatthew Dillon 	 */
345bf686dbeSMatthew Dillon 	bcopy(onode->ondisk, nnode->ondisk, sizeof(*nnode->ondisk));
346bf686dbeSMatthew Dillon 
347bf686dbeSMatthew Dillon 	if (elm) {
348bf686dbeSMatthew Dillon 		/*
349bf686dbeSMatthew Dillon 		 * We are not the root of the B-Tree
350bf686dbeSMatthew Dillon 		 */
351bf686dbeSMatthew Dillon 		hammer_modify_node(cursor->parent,
352bf686dbeSMatthew Dillon 				   &elm->internal.subtree_offset,
353bf686dbeSMatthew Dillon 				   sizeof(elm->internal.subtree_offset));
354bf686dbeSMatthew Dillon 		elm->internal.subtree_offset = nnode->node_offset;
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 
361bf686dbeSMatthew Dillon                 volume = hammer_get_root_volume(hmp, &error);
362bf686dbeSMatthew Dillon                 KKASSERT(error == 0);
363bf686dbeSMatthew Dillon 
364bf686dbeSMatthew Dillon                 hammer_modify_volume(volume, &volume->ondisk->vol0_btree_root,
365bf686dbeSMatthew Dillon                                      sizeof(hammer_off_t));
366bf686dbeSMatthew Dillon                 volume->ondisk->vol0_btree_root = nnode->node_offset;
367bf686dbeSMatthew Dillon                 hammer_rel_volume(volume, 0);
368bf686dbeSMatthew Dillon         }
369bf686dbeSMatthew Dillon 
370bf686dbeSMatthew Dillon 	onode->flags |= HAMMER_NODE_DELETED;
371bf686dbeSMatthew Dillon 
372bf686dbeSMatthew Dillon 	kprintf("REBLOCK NODE %016llx -> %016llx\n",
373bf686dbeSMatthew Dillon 		onode->node_offset, nnode->node_offset);
374bf686dbeSMatthew Dillon 
375bf686dbeSMatthew Dillon 	cursor->node = nnode;
376bf686dbeSMatthew Dillon 	hammer_rel_node(onode);
377bf686dbeSMatthew Dillon 
378bf686dbeSMatthew Dillon 	return (error);
379bf686dbeSMatthew Dillon }
380bf686dbeSMatthew Dillon 
381