xref: /dflybsd-src/sys/vfs/hammer/hammer_reblock.c (revision 4e17f4657577ceed5625f8c8ef5e1d0885645ead)
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*4e17f465SMatthew Dillon  * $DragonFly: src/sys/vfs/hammer/hammer_reblock.c,v 1.9 2008/05/03 05:28:55 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:
72*4e17f465SMatthew Dillon 	error = hammer_init_cursor(trans, &cursor, NULL, 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;
929480ff55SMatthew Dillon 	cursor.flags |= HAMMER_CURSOR_BACKEND;
93bf686dbeSMatthew Dillon 
94bf686dbeSMatthew Dillon 	error = hammer_btree_first(&cursor);
95bf686dbeSMatthew Dillon 	while (error == 0) {
96bf686dbeSMatthew Dillon 		elm = &cursor.node->ondisk->elms[cursor.index];
97bf686dbeSMatthew Dillon 		reblock->cur_obj_id = elm->base.obj_id;
98bf686dbeSMatthew Dillon 
999480ff55SMatthew Dillon 		/*
1009480ff55SMatthew Dillon 		 * Acquiring the sync_lock prevents the operation from
1019480ff55SMatthew Dillon 		 * crossing a synchronization boundary.
1029480ff55SMatthew Dillon 		 */
1039480ff55SMatthew Dillon 		hammer_lock_ex(&trans->hmp->sync_lock);
10436f82b23SMatthew Dillon 		error = hammer_reblock_helper(reblock, &cursor, elm);
1059480ff55SMatthew Dillon 		hammer_unlock(&trans->hmp->sync_lock);
106bf686dbeSMatthew Dillon 		if (error == 0) {
107bf686dbeSMatthew Dillon 			cursor.flags |= HAMMER_CURSOR_ATEDISK;
108bf686dbeSMatthew Dillon 			error = hammer_btree_iterate(&cursor);
109bf686dbeSMatthew Dillon 		}
1109480ff55SMatthew Dillon 
1119480ff55SMatthew Dillon 		/*
1129480ff55SMatthew Dillon 		 * Bad hack for now, don't blow out the kernel's buffer
1139480ff55SMatthew Dillon 		 * cache.
1149480ff55SMatthew Dillon 		 */
1159480ff55SMatthew Dillon 		if (trans->hmp->locked_dirty_count > hammer_limit_dirtybufs)
1169480ff55SMatthew Dillon 			hammer_flusher_sync(trans->hmp);
117855942b6SMatthew Dillon 		if (error == 0)
118855942b6SMatthew Dillon 			error = hammer_signal_check(trans->hmp);
119bf686dbeSMatthew Dillon 	}
120bf686dbeSMatthew Dillon 	if (error == ENOENT)
121bf686dbeSMatthew Dillon 		error = 0;
122bf686dbeSMatthew Dillon 	hammer_done_cursor(&cursor);
123bf686dbeSMatthew Dillon 	if (error == EDEADLK)
124bf686dbeSMatthew Dillon 		goto retry;
125bf686dbeSMatthew Dillon 	return(error);
126bf686dbeSMatthew Dillon }
127bf686dbeSMatthew Dillon 
128bf686dbeSMatthew Dillon /*
129bf686dbeSMatthew Dillon  * Reblock the B-Tree (leaf) node, record, and/or data if necessary.
130bf686dbeSMatthew Dillon  *
1319480ff55SMatthew Dillon  * XXX We have no visibility into internal B-Tree nodes at the moment,
1329480ff55SMatthew Dillon  * only leaf nodes.
133bf686dbeSMatthew Dillon  */
134bf686dbeSMatthew Dillon static int
13536f82b23SMatthew Dillon hammer_reblock_helper(struct hammer_ioc_reblock *reblock,
136bf686dbeSMatthew Dillon 		      hammer_cursor_t cursor, hammer_btree_elm_t elm)
137bf686dbeSMatthew Dillon {
138bf686dbeSMatthew Dillon 	hammer_off_t tmp_offset;
139bf686dbeSMatthew Dillon 	int error;
140bf686dbeSMatthew Dillon 	int zone;
141bf686dbeSMatthew Dillon 	int bytes;
142bf686dbeSMatthew Dillon 	int cur;
143bf686dbeSMatthew Dillon 
144bf686dbeSMatthew Dillon 	if (elm->leaf.base.btype != HAMMER_BTREE_TYPE_RECORD)
145bf686dbeSMatthew Dillon 		return(0);
146bf686dbeSMatthew Dillon 	error = 0;
147bf686dbeSMatthew Dillon 
148bf686dbeSMatthew Dillon 	/*
149bf686dbeSMatthew Dillon 	 * Reblock data.  Note that data embedded in a record is reblocked
150bf686dbeSMatthew Dillon 	 * by the record reblock code.
151bf686dbeSMatthew Dillon 	 */
152bf686dbeSMatthew Dillon 	tmp_offset = elm->leaf.data_offset;
153bf686dbeSMatthew Dillon 	zone = HAMMER_ZONE_DECODE(tmp_offset);		/* can be 0 */
154bf686dbeSMatthew Dillon 	if ((zone == HAMMER_ZONE_SMALL_DATA_INDEX ||
155bf686dbeSMatthew Dillon 	     zone == HAMMER_ZONE_LARGE_DATA_INDEX) && error == 0) {
156bf686dbeSMatthew Dillon 		++reblock->data_count;
157bf686dbeSMatthew Dillon 		reblock->data_byte_count += elm->leaf.data_len;
15836f82b23SMatthew Dillon 		bytes = hammer_blockmap_getfree(cursor->trans->hmp, tmp_offset,
15936f82b23SMatthew Dillon 						&cur, &error);
160bf686dbeSMatthew Dillon 		if (error == 0 && cur == 0 && bytes > reblock->free_level) {
1616e1e8b6dSMatthew Dillon 			if (hammer_debug_general & 0x4000)
162bf686dbeSMatthew Dillon 				kprintf("%6d ", bytes);
163bf686dbeSMatthew Dillon 			error = hammer_cursor_upgrade(cursor);
164bf686dbeSMatthew Dillon 			if (error == 0) {
16536f82b23SMatthew Dillon 				error = hammer_reblock_data(reblock,
166bf686dbeSMatthew Dillon 							    cursor, elm);
167bf686dbeSMatthew Dillon 			}
168bf686dbeSMatthew Dillon 			if (error == 0) {
169bf686dbeSMatthew Dillon 				++reblock->data_moves;
170bf686dbeSMatthew Dillon 				reblock->data_byte_moves += elm->leaf.data_len;
171bf686dbeSMatthew Dillon 			}
172bf686dbeSMatthew Dillon 		}
173bf686dbeSMatthew Dillon 	}
174bf686dbeSMatthew Dillon 
175bf686dbeSMatthew Dillon 	/*
176bf686dbeSMatthew Dillon 	 * Reblock a record
177bf686dbeSMatthew Dillon 	 */
178bf686dbeSMatthew Dillon 	tmp_offset = elm->leaf.rec_offset;
179bf686dbeSMatthew Dillon 	zone = HAMMER_ZONE_DECODE(tmp_offset);
180bf686dbeSMatthew Dillon 	if (zone == HAMMER_ZONE_RECORD_INDEX && error == 0) {
181bf686dbeSMatthew Dillon 		++reblock->record_count;
18236f82b23SMatthew Dillon 		bytes = hammer_blockmap_getfree(cursor->trans->hmp, tmp_offset,
18336f82b23SMatthew Dillon 						&cur, &error);
184bf686dbeSMatthew Dillon 		if (error == 0 && cur == 0 && bytes > reblock->free_level) {
1856e1e8b6dSMatthew Dillon 			if (hammer_debug_general & 0x4000)
186bf686dbeSMatthew Dillon 				kprintf("%6d ", bytes);
187bf686dbeSMatthew Dillon 			error = hammer_cursor_upgrade(cursor);
188bf686dbeSMatthew Dillon 			if (error == 0) {
18936f82b23SMatthew Dillon 				error = hammer_reblock_record(reblock,
190bf686dbeSMatthew Dillon 							      cursor, elm);
191bf686dbeSMatthew Dillon 			}
192bf686dbeSMatthew Dillon 			if (error == 0) {
193bf686dbeSMatthew Dillon 				++reblock->record_moves;
194bf686dbeSMatthew Dillon 			}
195bf686dbeSMatthew Dillon 		}
196bf686dbeSMatthew Dillon 	}
197bf686dbeSMatthew Dillon 
198bf686dbeSMatthew Dillon 	/*
199bf686dbeSMatthew Dillon 	 * Reblock a B-Tree node.  Adjust elm to point at the parent's
200bf686dbeSMatthew Dillon 	 * leaf entry.
201bf686dbeSMatthew Dillon 	 */
202bf686dbeSMatthew Dillon 	tmp_offset = cursor->node->node_offset;
203bf686dbeSMatthew Dillon 	zone = HAMMER_ZONE_DECODE(tmp_offset);
204bf686dbeSMatthew Dillon 	if (zone == HAMMER_ZONE_BTREE_INDEX && error == 0 &&
205bf686dbeSMatthew Dillon 	    cursor->index == 0) {
206bf686dbeSMatthew Dillon 		++reblock->btree_count;
20736f82b23SMatthew Dillon 		bytes = hammer_blockmap_getfree(cursor->trans->hmp, tmp_offset,
20836f82b23SMatthew Dillon 						&cur, &error);
209bf686dbeSMatthew Dillon 		if (error == 0 && cur == 0 && bytes > reblock->free_level) {
2106e1e8b6dSMatthew Dillon 			if (hammer_debug_general & 0x4000)
211bf686dbeSMatthew Dillon 				kprintf("%6d ", bytes);
212bf686dbeSMatthew Dillon 			error = hammer_cursor_upgrade(cursor);
213bf686dbeSMatthew Dillon 			if (error == 0) {
214bf686dbeSMatthew Dillon 				if (cursor->parent)
215bf686dbeSMatthew Dillon 					elm = &cursor->parent->ondisk->elms[cursor->parent_index];
216bf686dbeSMatthew Dillon 				else
217bf686dbeSMatthew Dillon 					elm = NULL;
21836f82b23SMatthew Dillon 				error = hammer_reblock_node(reblock,
219bf686dbeSMatthew Dillon 							    cursor, elm);
220bf686dbeSMatthew Dillon 			}
221bf686dbeSMatthew Dillon 			if (error == 0) {
222bf686dbeSMatthew Dillon 				++reblock->btree_moves;
223bf686dbeSMatthew Dillon 			}
224bf686dbeSMatthew Dillon 		}
225bf686dbeSMatthew Dillon 	}
226bf686dbeSMatthew Dillon 
227bf686dbeSMatthew Dillon 	hammer_cursor_downgrade(cursor);
228bf686dbeSMatthew Dillon 	return(error);
229bf686dbeSMatthew Dillon }
230bf686dbeSMatthew Dillon 
231bf686dbeSMatthew Dillon /*
232bf686dbeSMatthew Dillon  * Reblock a record's data.  Both the B-Tree element and record pointers
233bf686dbeSMatthew Dillon  * to the data must be adjusted.
234bf686dbeSMatthew Dillon  */
235bf686dbeSMatthew Dillon static int
23636f82b23SMatthew Dillon hammer_reblock_data(struct hammer_ioc_reblock *reblock,
237bf686dbeSMatthew Dillon 		    hammer_cursor_t cursor, hammer_btree_elm_t elm)
238bf686dbeSMatthew Dillon {
239bf686dbeSMatthew Dillon 	struct hammer_buffer *data_buffer = NULL;
240bf686dbeSMatthew Dillon 	hammer_off_t ndata_offset;
241bf686dbeSMatthew Dillon 	int error;
242bf686dbeSMatthew Dillon 	void *ndata;
243bf686dbeSMatthew Dillon 
244bf686dbeSMatthew Dillon 	error = hammer_btree_extract(cursor, HAMMER_CURSOR_GET_DATA |
245bf686dbeSMatthew Dillon 					     HAMMER_CURSOR_GET_RECORD);
246bf686dbeSMatthew Dillon 	if (error)
247bf686dbeSMatthew Dillon 		return (error);
24836f82b23SMatthew Dillon 	ndata = hammer_alloc_data(cursor->trans, elm->leaf.data_len,
24936f82b23SMatthew Dillon 				  &ndata_offset, &data_buffer, &error);
250bf686dbeSMatthew Dillon 	if (error)
251bf686dbeSMatthew Dillon 		goto done;
252bf686dbeSMatthew Dillon 
253bf686dbeSMatthew Dillon 	/*
254bf686dbeSMatthew Dillon 	 * Move the data
255bf686dbeSMatthew Dillon 	 */
25610a5d1baSMatthew Dillon 	hammer_modify_buffer(cursor->trans, data_buffer, NULL, 0);
257bf686dbeSMatthew Dillon 	bcopy(cursor->data, ndata, elm->leaf.data_len);
25810a5d1baSMatthew Dillon 	hammer_modify_buffer_done(data_buffer);
259bf686dbeSMatthew Dillon 
26036f82b23SMatthew Dillon 	hammer_blockmap_free(cursor->trans,
26136f82b23SMatthew Dillon 			     elm->leaf.data_offset, elm->leaf.data_len);
262bf686dbeSMatthew Dillon 
26310a5d1baSMatthew Dillon 	hammer_modify_record(cursor->trans, cursor->record_buffer,
26410a5d1baSMatthew Dillon 			     &cursor->record->base.data_off,
26510a5d1baSMatthew Dillon 			     sizeof(hammer_off_t));
266bf686dbeSMatthew Dillon 	cursor->record->base.data_off = ndata_offset;
26710a5d1baSMatthew Dillon 	hammer_modify_record_done(cursor->record_buffer);
26810a5d1baSMatthew Dillon 
26910a5d1baSMatthew Dillon 	hammer_modify_node(cursor->trans, cursor->node,
27010a5d1baSMatthew Dillon 			   &elm->leaf.data_offset, sizeof(hammer_off_t));
271bf686dbeSMatthew Dillon 	elm->leaf.data_offset = ndata_offset;
27210a5d1baSMatthew Dillon 	hammer_modify_node_done(cursor->node);
273bf686dbeSMatthew Dillon 
274bf686dbeSMatthew Dillon done:
275bf686dbeSMatthew Dillon 	if (data_buffer)
276bf686dbeSMatthew Dillon 		hammer_rel_buffer(data_buffer, 0);
277bf686dbeSMatthew Dillon 	return (error);
278bf686dbeSMatthew Dillon }
279bf686dbeSMatthew Dillon 
280bf686dbeSMatthew Dillon /*
281bf686dbeSMatthew Dillon  * Reblock a record.  The B-Tree must be adjusted to point to the new record
282bf686dbeSMatthew Dillon  * and the existing record must be physically destroyed so a FS rebuild
283bf686dbeSMatthew Dillon  * does not see two versions of the same record.
284bf686dbeSMatthew Dillon  */
285bf686dbeSMatthew Dillon static int
28636f82b23SMatthew Dillon hammer_reblock_record(struct hammer_ioc_reblock *reblock,
287bf686dbeSMatthew Dillon 		      hammer_cursor_t cursor, hammer_btree_elm_t elm)
288bf686dbeSMatthew Dillon {
289bf686dbeSMatthew Dillon 	struct hammer_buffer *rec_buffer = NULL;
290bf686dbeSMatthew Dillon 	hammer_off_t nrec_offset;
2918fe2cd5dSMatthew Dillon 	hammer_off_t ndata_offset;
2928fe2cd5dSMatthew Dillon 	hammer_record_ondisk_t orec;
293bf686dbeSMatthew Dillon 	hammer_record_ondisk_t nrec;
294bf686dbeSMatthew Dillon 	int error;
2958fe2cd5dSMatthew Dillon 	int inline_data;
296bf686dbeSMatthew Dillon 
297bf686dbeSMatthew Dillon 	error = hammer_btree_extract(cursor, HAMMER_CURSOR_GET_RECORD);
298bf686dbeSMatthew Dillon 	if (error)
299bf686dbeSMatthew Dillon 		return (error);
300bf686dbeSMatthew Dillon 
30136f82b23SMatthew Dillon 	nrec = hammer_alloc_record(cursor->trans, &nrec_offset,
30236f82b23SMatthew Dillon 				   elm->leaf.base.rec_type, &rec_buffer,
30336f82b23SMatthew Dillon 				   0, NULL, NULL, &error);
304bf686dbeSMatthew Dillon 	if (error)
305bf686dbeSMatthew Dillon 		goto done;
306bf686dbeSMatthew Dillon 
307bf686dbeSMatthew Dillon 	/*
3088fe2cd5dSMatthew Dillon 	 * Move the record.  Check for an inline data reference and move that
3098fe2cd5dSMatthew Dillon 	 * too if necessary.
310bf686dbeSMatthew Dillon 	 */
3118fe2cd5dSMatthew Dillon 	orec = cursor->record;
31210a5d1baSMatthew Dillon 	hammer_modify_buffer(cursor->trans, rec_buffer, NULL, 0);
3138fe2cd5dSMatthew Dillon 	bcopy(orec, nrec, sizeof(*nrec));
314bf686dbeSMatthew Dillon 
3158fe2cd5dSMatthew Dillon 	if ((orec->base.data_off & HAMMER_OFF_ZONE_MASK) == HAMMER_ZONE_RECORD) {
3168fe2cd5dSMatthew Dillon 		ndata_offset = orec->base.data_off - elm->leaf.rec_offset;
3178fe2cd5dSMatthew Dillon 		KKASSERT(ndata_offset < sizeof(*nrec));
3188fe2cd5dSMatthew Dillon 		ndata_offset += nrec_offset;
3198fe2cd5dSMatthew Dillon 		inline_data = 1;
3208fe2cd5dSMatthew Dillon 	} else {
3218fe2cd5dSMatthew Dillon 		ndata_offset = 0;
3228fe2cd5dSMatthew Dillon 		inline_data = 0;
3238fe2cd5dSMatthew Dillon 	}
3248fe2cd5dSMatthew Dillon 
32536f82b23SMatthew Dillon 	hammer_modify_record(cursor->trans, cursor->record_buffer,
32636f82b23SMatthew Dillon 			     &orec->base.base.rec_type,
32736f82b23SMatthew Dillon 			     sizeof(orec->base.base.rec_type));
3288fe2cd5dSMatthew Dillon 	orec->base.base.rec_type |= HAMMER_RECTYPE_MOVED;
32910a5d1baSMatthew Dillon 	hammer_modify_record_done(cursor->record_buffer);
330bf686dbeSMatthew Dillon 
33136f82b23SMatthew Dillon 	hammer_blockmap_free(cursor->trans,
33236f82b23SMatthew Dillon 			     elm->leaf.rec_offset, sizeof(*nrec));
333bf686dbeSMatthew Dillon 
334b58c6388SMatthew Dillon 	if (hammer_debug_general & 0x4000) {
335bf686dbeSMatthew Dillon 		kprintf("REBLOCK RECD %016llx -> %016llx\n",
336bf686dbeSMatthew Dillon 			elm->leaf.rec_offset, nrec_offset);
337b58c6388SMatthew Dillon 	}
3388fe2cd5dSMatthew Dillon 
33936f82b23SMatthew Dillon 	hammer_modify_node(cursor->trans, cursor->node,
3408fe2cd5dSMatthew Dillon 			   &elm->leaf.rec_offset, sizeof(hammer_off_t));
341bf686dbeSMatthew Dillon 	elm->leaf.rec_offset = nrec_offset;
34210a5d1baSMatthew Dillon 	hammer_modify_node_done(cursor->node);
3438fe2cd5dSMatthew Dillon 	if (inline_data) {
34436f82b23SMatthew Dillon 		hammer_modify_node(cursor->trans, cursor->node,
3458fe2cd5dSMatthew Dillon 				 &elm->leaf.data_offset, sizeof(hammer_off_t));
3468fe2cd5dSMatthew Dillon 		elm->leaf.data_offset = ndata_offset;
34710a5d1baSMatthew Dillon 		hammer_modify_node_done(cursor->node);
3486e1e8b6dSMatthew Dillon 		nrec->base.data_off = ndata_offset;
3498fe2cd5dSMatthew Dillon 	}
35010a5d1baSMatthew Dillon 	hammer_modify_buffer_done(rec_buffer);
351bf686dbeSMatthew Dillon 
352bf686dbeSMatthew Dillon done:
353bf686dbeSMatthew Dillon 	if (rec_buffer)
354bf686dbeSMatthew Dillon 		hammer_rel_buffer(rec_buffer, 0);
355bf686dbeSMatthew Dillon 	return (error);
356bf686dbeSMatthew Dillon }
357bf686dbeSMatthew Dillon 
358bf686dbeSMatthew Dillon /*
359bf686dbeSMatthew Dillon  * Reblock a B-Tree (leaf) node.  The parent must be adjusted to point to
360bf686dbeSMatthew Dillon  * the new copy of the leaf node.  elm is a pointer to the parent element
361bf686dbeSMatthew Dillon  * pointing at cursor.node.
362bf686dbeSMatthew Dillon  *
363bf686dbeSMatthew Dillon  * XXX reblock internal nodes too.
364bf686dbeSMatthew Dillon  */
365bf686dbeSMatthew Dillon static int
36636f82b23SMatthew Dillon hammer_reblock_node(struct hammer_ioc_reblock *reblock,
367bf686dbeSMatthew Dillon 		    hammer_cursor_t cursor, hammer_btree_elm_t elm)
368bf686dbeSMatthew Dillon {
369bf686dbeSMatthew Dillon 	hammer_node_t onode;
370bf686dbeSMatthew Dillon 	hammer_node_t nnode;
371bf686dbeSMatthew Dillon 	int error;
372bf686dbeSMatthew Dillon 
373bf686dbeSMatthew Dillon 	onode = cursor->node;
37436f82b23SMatthew Dillon 	nnode = hammer_alloc_btree(cursor->trans, &error);
375bf686dbeSMatthew Dillon 	hammer_lock_ex(&nnode->lock);
376bf686dbeSMatthew Dillon 
377bf686dbeSMatthew Dillon 	if (nnode == NULL)
378bf686dbeSMatthew Dillon 		return (error);
379bf686dbeSMatthew Dillon 
380bf686dbeSMatthew Dillon 	/*
381bf686dbeSMatthew Dillon 	 * Move the node
382bf686dbeSMatthew Dillon 	 */
383bf686dbeSMatthew Dillon 	bcopy(onode->ondisk, nnode->ondisk, sizeof(*nnode->ondisk));
384bf686dbeSMatthew Dillon 
385bf686dbeSMatthew Dillon 	if (elm) {
386bf686dbeSMatthew Dillon 		/*
387bf686dbeSMatthew Dillon 		 * We are not the root of the B-Tree
388bf686dbeSMatthew Dillon 		 */
38936f82b23SMatthew Dillon 		hammer_modify_node(cursor->trans, cursor->parent,
390bf686dbeSMatthew Dillon 				   &elm->internal.subtree_offset,
391bf686dbeSMatthew Dillon 				   sizeof(elm->internal.subtree_offset));
392bf686dbeSMatthew Dillon 		elm->internal.subtree_offset = nnode->node_offset;
39310a5d1baSMatthew Dillon 		hammer_modify_node_done(cursor->parent);
394bf686dbeSMatthew Dillon 	} else {
395bf686dbeSMatthew Dillon 		/*
396bf686dbeSMatthew Dillon 		 * We are the root of the B-Tree
397bf686dbeSMatthew Dillon 		 */
398bf686dbeSMatthew Dillon                 hammer_volume_t volume;
399bf686dbeSMatthew Dillon 
40036f82b23SMatthew Dillon                 volume = hammer_get_root_volume(cursor->trans->hmp, &error);
401bf686dbeSMatthew Dillon                 KKASSERT(error == 0);
402bf686dbeSMatthew Dillon 
40336f82b23SMatthew Dillon                 hammer_modify_volume(cursor->trans, volume,
40436f82b23SMatthew Dillon 				     &volume->ondisk->vol0_btree_root,
405bf686dbeSMatthew Dillon                                      sizeof(hammer_off_t));
406bf686dbeSMatthew Dillon                 volume->ondisk->vol0_btree_root = nnode->node_offset;
40710a5d1baSMatthew Dillon                 hammer_modify_volume_done(volume);
408bf686dbeSMatthew Dillon                 hammer_rel_volume(volume, 0);
409bf686dbeSMatthew Dillon         }
410bf686dbeSMatthew Dillon 
41136f82b23SMatthew Dillon 	hammer_delete_node(cursor->trans, onode);
412bf686dbeSMatthew Dillon 
413b58c6388SMatthew Dillon 	if (hammer_debug_general & 0x4000) {
414bf686dbeSMatthew Dillon 		kprintf("REBLOCK NODE %016llx -> %016llx\n",
415bf686dbeSMatthew Dillon 			onode->node_offset, nnode->node_offset);
416b58c6388SMatthew Dillon 	}
417bf686dbeSMatthew Dillon 
418bf686dbeSMatthew Dillon 	cursor->node = nnode;
419bf686dbeSMatthew Dillon 	hammer_rel_node(onode);
420bf686dbeSMatthew Dillon 
421bf686dbeSMatthew Dillon 	return (error);
422bf686dbeSMatthew Dillon }
423bf686dbeSMatthew Dillon 
424