xref: /dflybsd-src/sys/vfs/hammer/hammer_reblock.c (revision bf686dbe109e04d50f3c63426cba46e299dbc0a5)
1*bf686dbeSMatthew Dillon /*
2*bf686dbeSMatthew Dillon  * Copyright (c) 2008 The DragonFly Project.  All rights reserved.
3*bf686dbeSMatthew Dillon  *
4*bf686dbeSMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
5*bf686dbeSMatthew Dillon  * by Matthew Dillon <dillon@backplane.com>
6*bf686dbeSMatthew Dillon  *
7*bf686dbeSMatthew Dillon  * Redistribution and use in source and binary forms, with or without
8*bf686dbeSMatthew Dillon  * modification, are permitted provided that the following conditions
9*bf686dbeSMatthew Dillon  * are met:
10*bf686dbeSMatthew Dillon  *
11*bf686dbeSMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
12*bf686dbeSMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
13*bf686dbeSMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
14*bf686dbeSMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
15*bf686dbeSMatthew Dillon  *    the documentation and/or other materials provided with the
16*bf686dbeSMatthew Dillon  *    distribution.
17*bf686dbeSMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
18*bf686dbeSMatthew Dillon  *    contributors may be used to endorse or promote products derived
19*bf686dbeSMatthew Dillon  *    from this software without specific, prior written permission.
20*bf686dbeSMatthew Dillon  *
21*bf686dbeSMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22*bf686dbeSMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23*bf686dbeSMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24*bf686dbeSMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25*bf686dbeSMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26*bf686dbeSMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27*bf686dbeSMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28*bf686dbeSMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29*bf686dbeSMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30*bf686dbeSMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31*bf686dbeSMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32*bf686dbeSMatthew Dillon  * SUCH DAMAGE.
33*bf686dbeSMatthew Dillon  *
34*bf686dbeSMatthew Dillon  * $DragonFly: src/sys/vfs/hammer/hammer_reblock.c,v 1.1 2008/03/18 05:19:16 dillon Exp $
35*bf686dbeSMatthew Dillon  */
36*bf686dbeSMatthew Dillon /*
37*bf686dbeSMatthew Dillon  * HAMMER reblocker - This code frees up fragmented physical space
38*bf686dbeSMatthew Dillon  *
39*bf686dbeSMatthew Dillon  * HAMMER only keeps track of free space on a big-block basis.  A big-block
40*bf686dbeSMatthew Dillon  * containing holes can only be freed by migrating the remaining data in
41*bf686dbeSMatthew Dillon  * that big-block into a new big-block, then freeing the big-block.
42*bf686dbeSMatthew Dillon  *
43*bf686dbeSMatthew Dillon  * This function is called from an ioctl or via the hammer support thread.
44*bf686dbeSMatthew Dillon  */
45*bf686dbeSMatthew Dillon 
46*bf686dbeSMatthew Dillon #include "hammer.h"
47*bf686dbeSMatthew Dillon 
48*bf686dbeSMatthew Dillon static int hammer_reblock_helper(hammer_mount_t hmp,
49*bf686dbeSMatthew Dillon 				 struct hammer_ioc_reblock *reblock,
50*bf686dbeSMatthew Dillon 				 hammer_cursor_t cursor,
51*bf686dbeSMatthew Dillon 				 hammer_btree_elm_t elm);
52*bf686dbeSMatthew Dillon static int hammer_reblock_data(hammer_mount_t hmp,
53*bf686dbeSMatthew Dillon 				struct hammer_ioc_reblock *reblock,
54*bf686dbeSMatthew Dillon 				hammer_cursor_t cursor, hammer_btree_elm_t elm);
55*bf686dbeSMatthew Dillon static int hammer_reblock_record(hammer_mount_t hmp,
56*bf686dbeSMatthew Dillon 				struct hammer_ioc_reblock *reblock,
57*bf686dbeSMatthew Dillon 				hammer_cursor_t cursor, hammer_btree_elm_t elm);
58*bf686dbeSMatthew Dillon static int hammer_reblock_node(hammer_mount_t hmp,
59*bf686dbeSMatthew Dillon 				struct hammer_ioc_reblock *reblock,
60*bf686dbeSMatthew Dillon 				hammer_cursor_t cursor, hammer_btree_elm_t elm);
61*bf686dbeSMatthew Dillon 
62*bf686dbeSMatthew Dillon int
63*bf686dbeSMatthew Dillon hammer_reblock(hammer_inode_t ip, struct hammer_ioc_reblock *reblock)
64*bf686dbeSMatthew Dillon {
65*bf686dbeSMatthew Dillon 	struct hammer_cursor cursor;
66*bf686dbeSMatthew Dillon 	hammer_btree_elm_t elm;
67*bf686dbeSMatthew Dillon 	int error;
68*bf686dbeSMatthew Dillon 
69*bf686dbeSMatthew Dillon 	if (reblock->beg_obj_id >= reblock->end_obj_id)
70*bf686dbeSMatthew Dillon 		return(EINVAL);
71*bf686dbeSMatthew Dillon 	if (reblock->free_level < 0)
72*bf686dbeSMatthew Dillon 		return(EINVAL);
73*bf686dbeSMatthew Dillon 
74*bf686dbeSMatthew Dillon retry:
75*bf686dbeSMatthew Dillon 	error = hammer_init_cursor_hmp(&cursor, NULL, ip->hmp);
76*bf686dbeSMatthew Dillon 	if (error) {
77*bf686dbeSMatthew Dillon 		hammer_done_cursor(&cursor);
78*bf686dbeSMatthew Dillon 		return(error);
79*bf686dbeSMatthew Dillon 	}
80*bf686dbeSMatthew Dillon 	cursor.key_beg.obj_id = reblock->cur_obj_id;
81*bf686dbeSMatthew Dillon 	cursor.key_beg.key = HAMMER_MIN_KEY;
82*bf686dbeSMatthew Dillon 	cursor.key_beg.create_tid = 1;
83*bf686dbeSMatthew Dillon 	cursor.key_beg.delete_tid = 0;
84*bf686dbeSMatthew Dillon 	cursor.key_beg.rec_type = HAMMER_MIN_RECTYPE;
85*bf686dbeSMatthew Dillon 	cursor.key_beg.obj_type = 0;
86*bf686dbeSMatthew Dillon 
87*bf686dbeSMatthew Dillon 	cursor.key_end.obj_id = reblock->end_obj_id;
88*bf686dbeSMatthew Dillon 	cursor.key_end.key = HAMMER_MAX_KEY;
89*bf686dbeSMatthew Dillon 	cursor.key_end.create_tid = HAMMER_MAX_TID - 1;
90*bf686dbeSMatthew Dillon 	cursor.key_end.delete_tid = 0;
91*bf686dbeSMatthew Dillon 	cursor.key_end.rec_type = HAMMER_MAX_RECTYPE;
92*bf686dbeSMatthew Dillon 	cursor.key_end.obj_type = 0;
93*bf686dbeSMatthew Dillon 
94*bf686dbeSMatthew Dillon 	cursor.flags |= HAMMER_CURSOR_END_INCLUSIVE;
95*bf686dbeSMatthew Dillon 
96*bf686dbeSMatthew Dillon 	error = hammer_btree_first(&cursor);
97*bf686dbeSMatthew Dillon 	while (error == 0) {
98*bf686dbeSMatthew Dillon 		elm = &cursor.node->ondisk->elms[cursor.index];
99*bf686dbeSMatthew Dillon 		reblock->cur_obj_id = elm->base.obj_id;
100*bf686dbeSMatthew Dillon 
101*bf686dbeSMatthew Dillon 		error = hammer_reblock_helper(ip->hmp, reblock, &cursor, elm);
102*bf686dbeSMatthew Dillon 		if (error == 0) {
103*bf686dbeSMatthew Dillon 			cursor.flags |= HAMMER_CURSOR_ATEDISK;
104*bf686dbeSMatthew Dillon 			error = hammer_btree_iterate(&cursor);
105*bf686dbeSMatthew Dillon 		}
106*bf686dbeSMatthew Dillon 	}
107*bf686dbeSMatthew Dillon 	if (error == ENOENT)
108*bf686dbeSMatthew Dillon 		error = 0;
109*bf686dbeSMatthew Dillon 	hammer_done_cursor(&cursor);
110*bf686dbeSMatthew Dillon 	if (error == EDEADLK)
111*bf686dbeSMatthew Dillon 		goto retry;
112*bf686dbeSMatthew Dillon 	return(error);
113*bf686dbeSMatthew Dillon }
114*bf686dbeSMatthew Dillon 
115*bf686dbeSMatthew Dillon /*
116*bf686dbeSMatthew Dillon  * Reblock the B-Tree (leaf) node, record, and/or data if necessary.
117*bf686dbeSMatthew Dillon  *
118*bf686dbeSMatthew Dillon  * XXX We have no visibility into internal B-Tree nodes at the moment.
119*bf686dbeSMatthew Dillon  */
120*bf686dbeSMatthew Dillon static int
121*bf686dbeSMatthew Dillon hammer_reblock_helper(hammer_mount_t hmp, struct hammer_ioc_reblock *reblock,
122*bf686dbeSMatthew Dillon 		      hammer_cursor_t cursor, hammer_btree_elm_t elm)
123*bf686dbeSMatthew Dillon {
124*bf686dbeSMatthew Dillon 	hammer_off_t tmp_offset;
125*bf686dbeSMatthew Dillon 	int error;
126*bf686dbeSMatthew Dillon 	int zone;
127*bf686dbeSMatthew Dillon 	int bytes;
128*bf686dbeSMatthew Dillon 	int cur;
129*bf686dbeSMatthew Dillon 
130*bf686dbeSMatthew Dillon 	if (elm->leaf.base.btype != HAMMER_BTREE_TYPE_RECORD)
131*bf686dbeSMatthew Dillon 		return(0);
132*bf686dbeSMatthew Dillon 	error = 0;
133*bf686dbeSMatthew Dillon 
134*bf686dbeSMatthew Dillon 	/*
135*bf686dbeSMatthew Dillon 	 * Reblock data.  Note that data embedded in a record is reblocked
136*bf686dbeSMatthew Dillon 	 * by the record reblock code.
137*bf686dbeSMatthew Dillon 	 */
138*bf686dbeSMatthew Dillon 	tmp_offset = elm->leaf.data_offset;
139*bf686dbeSMatthew Dillon 	zone = HAMMER_ZONE_DECODE(tmp_offset);		/* can be 0 */
140*bf686dbeSMatthew Dillon 	if ((zone == HAMMER_ZONE_SMALL_DATA_INDEX ||
141*bf686dbeSMatthew Dillon 	     zone == HAMMER_ZONE_LARGE_DATA_INDEX) && error == 0) {
142*bf686dbeSMatthew Dillon 		++reblock->data_count;
143*bf686dbeSMatthew Dillon 		reblock->data_byte_count += elm->leaf.data_len;
144*bf686dbeSMatthew Dillon 		bytes = hammer_blockmap_getfree(hmp, tmp_offset, &cur, &error);
145*bf686dbeSMatthew Dillon 		if (error == 0 && cur == 0 && bytes > reblock->free_level) {
146*bf686dbeSMatthew Dillon 			kprintf("%6d ", bytes);
147*bf686dbeSMatthew Dillon 			error = hammer_cursor_upgrade(cursor);
148*bf686dbeSMatthew Dillon 			if (error == 0) {
149*bf686dbeSMatthew Dillon 				error = hammer_reblock_data(hmp, reblock,
150*bf686dbeSMatthew Dillon 							    cursor, elm);
151*bf686dbeSMatthew Dillon 			}
152*bf686dbeSMatthew Dillon 			if (error == 0) {
153*bf686dbeSMatthew Dillon 				++reblock->data_moves;
154*bf686dbeSMatthew Dillon 				reblock->data_byte_moves += elm->leaf.data_len;
155*bf686dbeSMatthew Dillon 			}
156*bf686dbeSMatthew Dillon 		}
157*bf686dbeSMatthew Dillon 	}
158*bf686dbeSMatthew Dillon 
159*bf686dbeSMatthew Dillon 	/*
160*bf686dbeSMatthew Dillon 	 * Reblock a record
161*bf686dbeSMatthew Dillon 	 */
162*bf686dbeSMatthew Dillon 	tmp_offset = elm->leaf.rec_offset;
163*bf686dbeSMatthew Dillon 	zone = HAMMER_ZONE_DECODE(tmp_offset);
164*bf686dbeSMatthew Dillon 	if (zone == HAMMER_ZONE_RECORD_INDEX && error == 0) {
165*bf686dbeSMatthew Dillon 		++reblock->record_count;
166*bf686dbeSMatthew Dillon 		bytes = hammer_blockmap_getfree(hmp, tmp_offset, &cur, &error);
167*bf686dbeSMatthew Dillon 		if (error == 0 && cur == 0 && bytes > reblock->free_level) {
168*bf686dbeSMatthew Dillon 			kprintf("%6d ", bytes);
169*bf686dbeSMatthew Dillon 			error = hammer_cursor_upgrade(cursor);
170*bf686dbeSMatthew Dillon 			if (error == 0) {
171*bf686dbeSMatthew Dillon 				error = hammer_reblock_record(hmp, reblock,
172*bf686dbeSMatthew Dillon 							      cursor, elm);
173*bf686dbeSMatthew Dillon 			}
174*bf686dbeSMatthew Dillon 			if (error == 0) {
175*bf686dbeSMatthew Dillon 				++reblock->record_moves;
176*bf686dbeSMatthew Dillon 			}
177*bf686dbeSMatthew Dillon 		}
178*bf686dbeSMatthew Dillon 	}
179*bf686dbeSMatthew Dillon 
180*bf686dbeSMatthew Dillon 	/*
181*bf686dbeSMatthew Dillon 	 * Reblock a B-Tree node.  Adjust elm to point at the parent's
182*bf686dbeSMatthew Dillon 	 * leaf entry.
183*bf686dbeSMatthew Dillon 	 */
184*bf686dbeSMatthew Dillon 	tmp_offset = cursor->node->node_offset;
185*bf686dbeSMatthew Dillon 	zone = HAMMER_ZONE_DECODE(tmp_offset);
186*bf686dbeSMatthew Dillon 	if (zone == HAMMER_ZONE_BTREE_INDEX && error == 0 &&
187*bf686dbeSMatthew Dillon 	    cursor->index == 0) {
188*bf686dbeSMatthew Dillon 		++reblock->btree_count;
189*bf686dbeSMatthew Dillon 		bytes = hammer_blockmap_getfree(hmp, tmp_offset, &cur, &error);
190*bf686dbeSMatthew Dillon 		if (error == 0 && cur == 0 && bytes > reblock->free_level) {
191*bf686dbeSMatthew Dillon 			kprintf("%6d ", bytes);
192*bf686dbeSMatthew Dillon 			error = hammer_cursor_upgrade(cursor);
193*bf686dbeSMatthew Dillon 			if (error == 0) {
194*bf686dbeSMatthew Dillon 				if (cursor->parent)
195*bf686dbeSMatthew Dillon 					elm = &cursor->parent->ondisk->elms[cursor->parent_index];
196*bf686dbeSMatthew Dillon 				else
197*bf686dbeSMatthew Dillon 					elm = NULL;
198*bf686dbeSMatthew Dillon 				error = hammer_reblock_node(hmp, reblock,
199*bf686dbeSMatthew Dillon 							    cursor, elm);
200*bf686dbeSMatthew Dillon 			}
201*bf686dbeSMatthew Dillon 			if (error == 0) {
202*bf686dbeSMatthew Dillon 				++reblock->btree_moves;
203*bf686dbeSMatthew Dillon 			}
204*bf686dbeSMatthew Dillon 		}
205*bf686dbeSMatthew Dillon 	}
206*bf686dbeSMatthew Dillon 
207*bf686dbeSMatthew Dillon 	hammer_cursor_downgrade(cursor);
208*bf686dbeSMatthew Dillon 	return(error);
209*bf686dbeSMatthew Dillon }
210*bf686dbeSMatthew Dillon 
211*bf686dbeSMatthew Dillon /*
212*bf686dbeSMatthew Dillon  * Reblock a record's data.  Both the B-Tree element and record pointers
213*bf686dbeSMatthew Dillon  * to the data must be adjusted.
214*bf686dbeSMatthew Dillon  */
215*bf686dbeSMatthew Dillon static int
216*bf686dbeSMatthew Dillon hammer_reblock_data(hammer_mount_t hmp, struct hammer_ioc_reblock *reblock,
217*bf686dbeSMatthew Dillon 		    hammer_cursor_t cursor, hammer_btree_elm_t elm)
218*bf686dbeSMatthew Dillon {
219*bf686dbeSMatthew Dillon 	struct hammer_buffer *data_buffer = NULL;
220*bf686dbeSMatthew Dillon 	hammer_off_t ndata_offset;
221*bf686dbeSMatthew Dillon 	int error;
222*bf686dbeSMatthew Dillon 	void *ndata;
223*bf686dbeSMatthew Dillon 
224*bf686dbeSMatthew Dillon 	error = hammer_btree_extract(cursor, HAMMER_CURSOR_GET_DATA |
225*bf686dbeSMatthew Dillon 					     HAMMER_CURSOR_GET_RECORD);
226*bf686dbeSMatthew Dillon 	if (error)
227*bf686dbeSMatthew Dillon 		return (error);
228*bf686dbeSMatthew Dillon 	ndata = hammer_alloc_data(hmp, elm->leaf.data_len, &ndata_offset,
229*bf686dbeSMatthew Dillon 				  &data_buffer, &error);
230*bf686dbeSMatthew Dillon 	if (error)
231*bf686dbeSMatthew Dillon 		goto done;
232*bf686dbeSMatthew Dillon 
233*bf686dbeSMatthew Dillon 	/*
234*bf686dbeSMatthew Dillon 	 * Move the data
235*bf686dbeSMatthew Dillon 	 */
236*bf686dbeSMatthew Dillon 	bcopy(cursor->data, ndata, elm->leaf.data_len);
237*bf686dbeSMatthew Dillon 	hammer_modify_node(cursor->node,
238*bf686dbeSMatthew Dillon 		&elm->leaf.data_offset, sizeof(hammer_off_t));
239*bf686dbeSMatthew Dillon 	hammer_modify_record(cursor->record_buffer,
240*bf686dbeSMatthew Dillon 		&cursor->record->base.data_off, sizeof(hammer_off_t));
241*bf686dbeSMatthew Dillon 
242*bf686dbeSMatthew Dillon 	hammer_blockmap_free(hmp, elm->leaf.data_offset, elm->leaf.data_len);
243*bf686dbeSMatthew Dillon 
244*bf686dbeSMatthew Dillon 	kprintf("REBLOCK DATA %016llx -> %016llx\n",
245*bf686dbeSMatthew Dillon 		elm->leaf.data_offset, ndata_offset);
246*bf686dbeSMatthew Dillon 	cursor->record->base.data_off = ndata_offset;
247*bf686dbeSMatthew Dillon 	elm->leaf.data_offset = ndata_offset;
248*bf686dbeSMatthew Dillon 
249*bf686dbeSMatthew Dillon done:
250*bf686dbeSMatthew Dillon 	if (data_buffer)
251*bf686dbeSMatthew Dillon 		hammer_rel_buffer(data_buffer, 0);
252*bf686dbeSMatthew Dillon 	return (error);
253*bf686dbeSMatthew Dillon }
254*bf686dbeSMatthew Dillon 
255*bf686dbeSMatthew Dillon /*
256*bf686dbeSMatthew Dillon  * Reblock a record.  The B-Tree must be adjusted to point to the new record
257*bf686dbeSMatthew Dillon  * and the existing record must be physically destroyed so a FS rebuild
258*bf686dbeSMatthew Dillon  * does not see two versions of the same record.
259*bf686dbeSMatthew Dillon  */
260*bf686dbeSMatthew Dillon static int
261*bf686dbeSMatthew Dillon hammer_reblock_record(hammer_mount_t hmp, struct hammer_ioc_reblock *reblock,
262*bf686dbeSMatthew Dillon 		      hammer_cursor_t cursor, hammer_btree_elm_t elm)
263*bf686dbeSMatthew Dillon {
264*bf686dbeSMatthew Dillon 	struct hammer_buffer *rec_buffer = NULL;
265*bf686dbeSMatthew Dillon 	hammer_off_t nrec_offset;
266*bf686dbeSMatthew Dillon 	hammer_record_ondisk_t nrec;
267*bf686dbeSMatthew Dillon 	int error;
268*bf686dbeSMatthew Dillon 
269*bf686dbeSMatthew Dillon 	error = hammer_btree_extract(cursor, HAMMER_CURSOR_GET_RECORD);
270*bf686dbeSMatthew Dillon 	if (error)
271*bf686dbeSMatthew Dillon 		return (error);
272*bf686dbeSMatthew Dillon 
273*bf686dbeSMatthew Dillon 	nrec = hammer_alloc_record(hmp, &nrec_offset, elm->leaf.base.rec_type,
274*bf686dbeSMatthew Dillon 				  &rec_buffer, 0, NULL, NULL, &error);
275*bf686dbeSMatthew Dillon 	if (error)
276*bf686dbeSMatthew Dillon 		goto done;
277*bf686dbeSMatthew Dillon 
278*bf686dbeSMatthew Dillon 	/*
279*bf686dbeSMatthew Dillon 	 * Move the record
280*bf686dbeSMatthew Dillon 	 */
281*bf686dbeSMatthew Dillon 	bcopy(cursor->record, nrec, sizeof(*nrec));
282*bf686dbeSMatthew Dillon 
283*bf686dbeSMatthew Dillon 	hammer_modify_node(cursor->node,
284*bf686dbeSMatthew Dillon 		&elm->leaf.rec_offset, sizeof(hammer_off_t));
285*bf686dbeSMatthew Dillon 	hammer_modify_record(cursor->record_buffer,
286*bf686dbeSMatthew Dillon 		&cursor->record->base.base.rec_type,
287*bf686dbeSMatthew Dillon 		sizeof(cursor->record->base.base.rec_type));
288*bf686dbeSMatthew Dillon 
289*bf686dbeSMatthew Dillon 	hammer_blockmap_free(hmp, elm->leaf.rec_offset, sizeof(*nrec));
290*bf686dbeSMatthew Dillon 
291*bf686dbeSMatthew Dillon 	kprintf("REBLOCK RECD %016llx -> %016llx\n",
292*bf686dbeSMatthew Dillon 		elm->leaf.rec_offset, nrec_offset);
293*bf686dbeSMatthew Dillon 	elm->leaf.rec_offset = nrec_offset;
294*bf686dbeSMatthew Dillon 
295*bf686dbeSMatthew Dillon done:
296*bf686dbeSMatthew Dillon 	if (rec_buffer)
297*bf686dbeSMatthew Dillon 		hammer_rel_buffer(rec_buffer, 0);
298*bf686dbeSMatthew Dillon 	return (error);
299*bf686dbeSMatthew Dillon }
300*bf686dbeSMatthew Dillon 
301*bf686dbeSMatthew Dillon /*
302*bf686dbeSMatthew Dillon  * Reblock a B-Tree (leaf) node.  The parent must be adjusted to point to
303*bf686dbeSMatthew Dillon  * the new copy of the leaf node.  elm is a pointer to the parent element
304*bf686dbeSMatthew Dillon  * pointing at cursor.node.
305*bf686dbeSMatthew Dillon  *
306*bf686dbeSMatthew Dillon  * XXX reblock internal nodes too.
307*bf686dbeSMatthew Dillon  */
308*bf686dbeSMatthew Dillon static int
309*bf686dbeSMatthew Dillon hammer_reblock_node(hammer_mount_t hmp, struct hammer_ioc_reblock *reblock,
310*bf686dbeSMatthew Dillon 		    hammer_cursor_t cursor, hammer_btree_elm_t elm)
311*bf686dbeSMatthew Dillon {
312*bf686dbeSMatthew Dillon 	hammer_node_t onode;
313*bf686dbeSMatthew Dillon 	hammer_node_t nnode;
314*bf686dbeSMatthew Dillon 	int error;
315*bf686dbeSMatthew Dillon 
316*bf686dbeSMatthew Dillon 	onode = cursor->node;
317*bf686dbeSMatthew Dillon 	nnode = hammer_alloc_btree(hmp, &error);
318*bf686dbeSMatthew Dillon 	hammer_lock_ex(&nnode->lock);
319*bf686dbeSMatthew Dillon 
320*bf686dbeSMatthew Dillon 	if (nnode == NULL)
321*bf686dbeSMatthew Dillon 		return (error);
322*bf686dbeSMatthew Dillon 
323*bf686dbeSMatthew Dillon 	/*
324*bf686dbeSMatthew Dillon 	 * Move the node
325*bf686dbeSMatthew Dillon 	 */
326*bf686dbeSMatthew Dillon 	bcopy(onode->ondisk, nnode->ondisk, sizeof(*nnode->ondisk));
327*bf686dbeSMatthew Dillon 
328*bf686dbeSMatthew Dillon 	if (elm) {
329*bf686dbeSMatthew Dillon 		/*
330*bf686dbeSMatthew Dillon 		 * We are not the root of the B-Tree
331*bf686dbeSMatthew Dillon 		 */
332*bf686dbeSMatthew Dillon 		hammer_modify_node(cursor->parent,
333*bf686dbeSMatthew Dillon 				   &elm->internal.subtree_offset,
334*bf686dbeSMatthew Dillon 				   sizeof(elm->internal.subtree_offset));
335*bf686dbeSMatthew Dillon 		elm->internal.subtree_offset = nnode->node_offset;
336*bf686dbeSMatthew Dillon 	} else {
337*bf686dbeSMatthew Dillon 		/*
338*bf686dbeSMatthew Dillon 		 * We are the root of the B-Tree
339*bf686dbeSMatthew Dillon 		 */
340*bf686dbeSMatthew Dillon                 hammer_volume_t volume;
341*bf686dbeSMatthew Dillon 
342*bf686dbeSMatthew Dillon                 volume = hammer_get_root_volume(hmp, &error);
343*bf686dbeSMatthew Dillon                 KKASSERT(error == 0);
344*bf686dbeSMatthew Dillon 
345*bf686dbeSMatthew Dillon                 hammer_modify_volume(volume, &volume->ondisk->vol0_btree_root,
346*bf686dbeSMatthew Dillon                                      sizeof(hammer_off_t));
347*bf686dbeSMatthew Dillon                 volume->ondisk->vol0_btree_root = nnode->node_offset;
348*bf686dbeSMatthew Dillon                 hammer_rel_volume(volume, 0);
349*bf686dbeSMatthew Dillon         }
350*bf686dbeSMatthew Dillon 
351*bf686dbeSMatthew Dillon 	onode->flags |= HAMMER_NODE_DELETED;
352*bf686dbeSMatthew Dillon 
353*bf686dbeSMatthew Dillon 	kprintf("REBLOCK NODE %016llx -> %016llx\n",
354*bf686dbeSMatthew Dillon 		onode->node_offset, nnode->node_offset);
355*bf686dbeSMatthew Dillon 
356*bf686dbeSMatthew Dillon 	cursor->node = nnode;
357*bf686dbeSMatthew Dillon 	hammer_rel_node(onode);
358*bf686dbeSMatthew Dillon 
359*bf686dbeSMatthew Dillon 	return (error);
360*bf686dbeSMatthew Dillon }
361*bf686dbeSMatthew Dillon 
362