xref: /dflybsd-src/sys/vfs/hammer/hammer_reblock.c (revision ea434b6fa505f0bbc28650a41494dea1ee26dd28)
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*ea434b6fSMatthew Dillon  * $DragonFly: src/sys/vfs/hammer/hammer_reblock.c,v 1.25 2008/07/09 10:29:20 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;
65a7e9bef1SMatthew Dillon 	int checkspace_count;
66bf686dbeSMatthew Dillon 
67dd94f1b1SMatthew Dillon 	if ((reblock->key_beg.localization | reblock->key_end.localization) &
68dd94f1b1SMatthew Dillon 	    HAMMER_LOCALIZE_PSEUDOFS_MASK) {
69dd94f1b1SMatthew Dillon 		return(EINVAL);
70dd94f1b1SMatthew Dillon 	}
71dd94f1b1SMatthew Dillon 	if (reblock->key_beg.obj_id >= reblock->key_end.obj_id)
72bf686dbeSMatthew Dillon 		return(EINVAL);
73bf686dbeSMatthew Dillon 	if (reblock->free_level < 0)
74bf686dbeSMatthew Dillon 		return(EINVAL);
75bf686dbeSMatthew Dillon 
76dd94f1b1SMatthew Dillon 	reblock->key_cur = reblock->key_beg;
77dd94f1b1SMatthew Dillon 	reblock->key_cur.localization += ip->obj_localization;
78814387f6SMatthew Dillon 
79a7e9bef1SMatthew Dillon 	checkspace_count = 0;
80bf686dbeSMatthew Dillon retry:
814e17f465SMatthew Dillon 	error = hammer_init_cursor(trans, &cursor, NULL, NULL);
82bf686dbeSMatthew Dillon 	if (error) {
83bf686dbeSMatthew Dillon 		hammer_done_cursor(&cursor);
84dd94f1b1SMatthew Dillon 		goto failed;
85bf686dbeSMatthew Dillon 	}
86dd94f1b1SMatthew Dillon 	cursor.key_beg.localization = reblock->key_cur.localization;
87dd94f1b1SMatthew Dillon 	cursor.key_beg.obj_id = reblock->key_cur.obj_id;
88bf686dbeSMatthew Dillon 	cursor.key_beg.key = HAMMER_MIN_KEY;
89bf686dbeSMatthew Dillon 	cursor.key_beg.create_tid = 1;
90bf686dbeSMatthew Dillon 	cursor.key_beg.delete_tid = 0;
91bf686dbeSMatthew Dillon 	cursor.key_beg.rec_type = HAMMER_MIN_RECTYPE;
92bf686dbeSMatthew Dillon 	cursor.key_beg.obj_type = 0;
93bf686dbeSMatthew Dillon 
94dd94f1b1SMatthew Dillon 	cursor.key_end.localization = reblock->key_end.localization +
95dd94f1b1SMatthew Dillon 				      ip->obj_localization;
96dd94f1b1SMatthew Dillon 	cursor.key_end.obj_id = reblock->key_end.obj_id;
97bf686dbeSMatthew Dillon 	cursor.key_end.key = HAMMER_MAX_KEY;
98bf686dbeSMatthew Dillon 	cursor.key_end.create_tid = HAMMER_MAX_TID - 1;
99bf686dbeSMatthew Dillon 	cursor.key_end.delete_tid = 0;
100bf686dbeSMatthew Dillon 	cursor.key_end.rec_type = HAMMER_MAX_RECTYPE;
101bf686dbeSMatthew Dillon 	cursor.key_end.obj_type = 0;
102bf686dbeSMatthew Dillon 
103bf686dbeSMatthew Dillon 	cursor.flags |= HAMMER_CURSOR_END_INCLUSIVE;
1049480ff55SMatthew Dillon 	cursor.flags |= HAMMER_CURSOR_BACKEND;
105bf686dbeSMatthew Dillon 
1062f85fa4dSMatthew Dillon 	/*
1072f85fa4dSMatthew Dillon 	 * This flag allows the btree scan code to return internal nodes,
1082f85fa4dSMatthew Dillon 	 * so we can reblock them in addition to the leafs.  Only specify it
1092f85fa4dSMatthew Dillon 	 * if we intend to reblock B-Tree nodes.
1102f85fa4dSMatthew Dillon 	 */
1112f85fa4dSMatthew Dillon 	if (reblock->head.flags & HAMMER_IOC_DO_BTREE)
1122f85fa4dSMatthew Dillon 		cursor.flags |= HAMMER_CURSOR_REBLOCKING;
1132f85fa4dSMatthew Dillon 
114bf686dbeSMatthew Dillon 	error = hammer_btree_first(&cursor);
115bf686dbeSMatthew Dillon 	while (error == 0) {
1162f85fa4dSMatthew Dillon 		/*
1172f85fa4dSMatthew Dillon 		 * Internal or Leaf node
1182f85fa4dSMatthew Dillon 		 */
119bf686dbeSMatthew Dillon 		elm = &cursor.node->ondisk->elms[cursor.index];
120dd94f1b1SMatthew Dillon 		reblock->key_cur.obj_id = elm->base.obj_id;
121dd94f1b1SMatthew Dillon 		reblock->key_cur.localization = elm->base.localization;
122bf686dbeSMatthew Dillon 
1239480ff55SMatthew Dillon 		/*
1249f5097dcSMatthew Dillon 		 * Yield to more important tasks
1259f5097dcSMatthew Dillon 		 */
1269f5097dcSMatthew Dillon 		if ((error = hammer_signal_check(trans->hmp)) != 0)
1279f5097dcSMatthew Dillon 			break;
1289f5097dcSMatthew Dillon 		if (trans->hmp->sync_lock.wanted) {
1299f5097dcSMatthew Dillon 			tsleep(trans, 0, "hmrslo", hz / 10);
1309f5097dcSMatthew Dillon 		}
131a7e9bef1SMatthew Dillon 
132a7e9bef1SMatthew Dillon 		/*
133a7e9bef1SMatthew Dillon 		 * If we build up too much meta-data we have to wait for
134a7e9bef1SMatthew Dillon 		 * a flush cycle.
135a7e9bef1SMatthew Dillon 		 */
13606ad81ffSMatthew Dillon 		if (hammer_flusher_meta_limit(trans->hmp) ||
13706ad81ffSMatthew Dillon 		    hammer_flusher_undo_exhausted(trans, 2)) {
13806ad81ffSMatthew Dillon 			error = EWOULDBLOCK;
13906ad81ffSMatthew Dillon 			break;
1409f5097dcSMatthew Dillon 		}
1419f5097dcSMatthew Dillon 
1429f5097dcSMatthew Dillon 		/*
143a7e9bef1SMatthew Dillon 		 * If there is insufficient free space it may be due to
144a7e9bef1SMatthew Dillon 		 * reserved bigblocks, which flushing might fix.
145a7e9bef1SMatthew Dillon 		 */
146a7e9bef1SMatthew Dillon 		if (hammer_checkspace(trans->hmp, HAMMER_CHECKSPACE_SLOP_REBLOCK)) {
147a7e9bef1SMatthew Dillon 			if (++checkspace_count == 10) {
148a7e9bef1SMatthew Dillon 				error = ENOSPC;
149a7e9bef1SMatthew Dillon 			} else {
150a7e9bef1SMatthew Dillon 				error = EWOULDBLOCK;
151a7e9bef1SMatthew Dillon 			}
152a7e9bef1SMatthew Dillon 			break;
153a7e9bef1SMatthew Dillon 		}
154a7e9bef1SMatthew Dillon 
155a7e9bef1SMatthew Dillon 		/*
1569480ff55SMatthew Dillon 		 * Acquiring the sync_lock prevents the operation from
1579480ff55SMatthew Dillon 		 * crossing a synchronization boundary.
15809ac686bSMatthew Dillon 		 *
15909ac686bSMatthew Dillon 		 * NOTE: cursor.node may have changed on return.
1609480ff55SMatthew Dillon 		 */
1612f85fa4dSMatthew Dillon 		hammer_sync_lock_sh(trans);
16236f82b23SMatthew Dillon 		error = hammer_reblock_helper(reblock, &cursor, elm);
1632f85fa4dSMatthew Dillon 		hammer_sync_unlock(trans);
164bf686dbeSMatthew Dillon 		if (error == 0) {
165bf686dbeSMatthew Dillon 			cursor.flags |= HAMMER_CURSOR_ATEDISK;
166bf686dbeSMatthew Dillon 			error = hammer_btree_iterate(&cursor);
167bf686dbeSMatthew Dillon 		}
168a7e9bef1SMatthew Dillon 
169bf686dbeSMatthew Dillon 	}
170bf686dbeSMatthew Dillon 	if (error == ENOENT)
171bf686dbeSMatthew Dillon 		error = 0;
172bf686dbeSMatthew Dillon 	hammer_done_cursor(&cursor);
17306ad81ffSMatthew Dillon 	if (error == EWOULDBLOCK) {
17406ad81ffSMatthew Dillon 		hammer_flusher_sync(trans->hmp);
17506ad81ffSMatthew Dillon 		goto retry;
17606ad81ffSMatthew Dillon 	}
177bf686dbeSMatthew Dillon 	if (error == EDEADLK)
178bf686dbeSMatthew Dillon 		goto retry;
17919619882SMatthew Dillon 	if (error == EINTR) {
18019619882SMatthew Dillon 		reblock->head.flags |= HAMMER_IOC_HEAD_INTR;
18119619882SMatthew Dillon 		error = 0;
18219619882SMatthew Dillon 	}
183dd94f1b1SMatthew Dillon failed:
184dd94f1b1SMatthew Dillon 	reblock->key_cur.localization &= HAMMER_LOCALIZE_MASK;
185bf686dbeSMatthew Dillon 	return(error);
186bf686dbeSMatthew Dillon }
187bf686dbeSMatthew Dillon 
188bf686dbeSMatthew Dillon /*
189bf686dbeSMatthew Dillon  * Reblock the B-Tree (leaf) node, record, and/or data if necessary.
190bf686dbeSMatthew Dillon  *
1919480ff55SMatthew Dillon  * XXX We have no visibility into internal B-Tree nodes at the moment,
1929480ff55SMatthew Dillon  * only leaf nodes.
193bf686dbeSMatthew Dillon  */
194bf686dbeSMatthew Dillon static int
19536f82b23SMatthew Dillon hammer_reblock_helper(struct hammer_ioc_reblock *reblock,
196bf686dbeSMatthew Dillon 		      hammer_cursor_t cursor, hammer_btree_elm_t elm)
197bf686dbeSMatthew Dillon {
19843c665aeSMatthew Dillon 	hammer_mount_t hmp;
199bf686dbeSMatthew Dillon 	hammer_off_t tmp_offset;
200bf686dbeSMatthew Dillon 	int error;
201bf686dbeSMatthew Dillon 	int bytes;
202bf686dbeSMatthew Dillon 	int cur;
203bf3b416bSMatthew Dillon 	int iocflags;
204bf686dbeSMatthew Dillon 
205bf686dbeSMatthew Dillon 	error = 0;
20643c665aeSMatthew Dillon 	hmp = cursor->trans->hmp;
207bf686dbeSMatthew Dillon 
208bf686dbeSMatthew Dillon 	/*
209bf686dbeSMatthew Dillon 	 * Reblock data.  Note that data embedded in a record is reblocked
2102f85fa4dSMatthew Dillon 	 * by the record reblock code.  Data processing only occurs at leaf
2112f85fa4dSMatthew Dillon 	 * nodes and for RECORD element types.
212bf686dbeSMatthew Dillon 	 */
2132f85fa4dSMatthew Dillon 	if (cursor->node->ondisk->type != HAMMER_BTREE_TYPE_LEAF)
2142f85fa4dSMatthew Dillon 		goto skip;
2152f85fa4dSMatthew Dillon 	if (elm->leaf.base.btype != HAMMER_BTREE_TYPE_RECORD)
2162f85fa4dSMatthew Dillon 		return(0);
217bf686dbeSMatthew Dillon 	tmp_offset = elm->leaf.data_offset;
218bf3b416bSMatthew Dillon 	if (tmp_offset == 0)
219bf3b416bSMatthew Dillon 		goto skip;
220bf3b416bSMatthew Dillon 	if (error)
221bf3b416bSMatthew Dillon 		goto skip;
222bf3b416bSMatthew Dillon 
223bf3b416bSMatthew Dillon 	/*
224bf3b416bSMatthew Dillon 	 * NOTE: Localization restrictions may also have been set-up, we can't
225bf3b416bSMatthew Dillon 	 * just set the match flags willy-nilly here.
226bf3b416bSMatthew Dillon 	 */
227bf3b416bSMatthew Dillon 	switch(elm->leaf.base.rec_type) {
228bf3b416bSMatthew Dillon 	case HAMMER_RECTYPE_INODE:
229bf3b416bSMatthew Dillon 		iocflags = HAMMER_IOC_DO_INODES;
230bf3b416bSMatthew Dillon 		break;
231bf3b416bSMatthew Dillon 	case HAMMER_RECTYPE_EXT:
232bf3b416bSMatthew Dillon 	case HAMMER_RECTYPE_FIX:
233*ea434b6fSMatthew Dillon 	case HAMMER_RECTYPE_PFS:
234bf3b416bSMatthew Dillon 	case HAMMER_RECTYPE_DIRENTRY:
235bf3b416bSMatthew Dillon 		iocflags = HAMMER_IOC_DO_DIRS;
236bf3b416bSMatthew Dillon 		break;
237bf3b416bSMatthew Dillon 	case HAMMER_RECTYPE_DATA:
238bf3b416bSMatthew Dillon 	case HAMMER_RECTYPE_DB:
239bf3b416bSMatthew Dillon 		iocflags = HAMMER_IOC_DO_DATA;
240bf3b416bSMatthew Dillon 		break;
241bf3b416bSMatthew Dillon 	default:
242bf3b416bSMatthew Dillon 		iocflags = 0;
243bf3b416bSMatthew Dillon 		break;
244bf3b416bSMatthew Dillon 	}
245bf3b416bSMatthew Dillon 	if (reblock->head.flags & iocflags) {
246bf686dbeSMatthew Dillon 		++reblock->data_count;
247bf686dbeSMatthew Dillon 		reblock->data_byte_count += elm->leaf.data_len;
24843c665aeSMatthew Dillon 		bytes = hammer_blockmap_getfree(hmp, tmp_offset, &cur, &error);
2496e1e8b6dSMatthew Dillon 		if (hammer_debug_general & 0x4000)
2502f85fa4dSMatthew Dillon 			kprintf("D %6d/%d\n", bytes, reblock->free_level);
251bf3b416bSMatthew Dillon 		if (error == 0 && (cur == 0 || reblock->free_level == 0) &&
252bf3b416bSMatthew Dillon 		    bytes >= reblock->free_level) {
25343c665aeSMatthew Dillon 			hammer_io_direct_uncache(hmp, &elm->leaf);
254bf686dbeSMatthew Dillon 			error = hammer_cursor_upgrade(cursor);
255bf686dbeSMatthew Dillon 			if (error == 0) {
25636f82b23SMatthew Dillon 				error = hammer_reblock_data(reblock,
257bf686dbeSMatthew Dillon 							    cursor, elm);
258bf686dbeSMatthew Dillon 			}
259bf686dbeSMatthew Dillon 			if (error == 0) {
260bf686dbeSMatthew Dillon 				++reblock->data_moves;
261bf686dbeSMatthew Dillon 				reblock->data_byte_moves += elm->leaf.data_len;
262bf686dbeSMatthew Dillon 			}
263bf686dbeSMatthew Dillon 		}
264bf686dbeSMatthew Dillon 	}
265bf686dbeSMatthew Dillon 
2662f85fa4dSMatthew Dillon skip:
267bf686dbeSMatthew Dillon 	/*
2682f85fa4dSMatthew Dillon 	 * Reblock a B-Tree internal or leaf node.
269bf686dbeSMatthew Dillon 	 */
270bf686dbeSMatthew Dillon 	tmp_offset = cursor->node->node_offset;
271bf3b416bSMatthew Dillon 	if (cursor->index == 0 &&
272814387f6SMatthew Dillon 	    error == 0 && (reblock->head.flags & HAMMER_IOC_DO_BTREE)) {
273bf686dbeSMatthew Dillon 		++reblock->btree_count;
27443c665aeSMatthew Dillon 		bytes = hammer_blockmap_getfree(hmp, tmp_offset, &cur, &error);
2756e1e8b6dSMatthew Dillon 		if (hammer_debug_general & 0x4000)
2762f85fa4dSMatthew Dillon 			kprintf("B %6d/%d\n", bytes, reblock->free_level);
277bf3b416bSMatthew Dillon 		if (error == 0 && (cur == 0 || reblock->free_level == 0) &&
278bf3b416bSMatthew Dillon 		    bytes >= reblock->free_level) {
279bf686dbeSMatthew Dillon 			error = hammer_cursor_upgrade(cursor);
280bf686dbeSMatthew Dillon 			if (error == 0) {
281bf686dbeSMatthew Dillon 				if (cursor->parent)
282bf686dbeSMatthew Dillon 					elm = &cursor->parent->ondisk->elms[cursor->parent_index];
283bf686dbeSMatthew Dillon 				else
284bf686dbeSMatthew Dillon 					elm = NULL;
2852f85fa4dSMatthew Dillon 				switch(cursor->node->ondisk->type) {
2862f85fa4dSMatthew Dillon 				case HAMMER_BTREE_TYPE_LEAF:
2872f85fa4dSMatthew Dillon 					error = hammer_reblock_leaf_node(
2882f85fa4dSMatthew Dillon 							reblock, cursor, elm);
2892f85fa4dSMatthew Dillon 					break;
2902f85fa4dSMatthew Dillon 				case HAMMER_BTREE_TYPE_INTERNAL:
2912f85fa4dSMatthew Dillon 					error = hammer_reblock_int_node(
2922f85fa4dSMatthew Dillon 							reblock, cursor, elm);
2932f85fa4dSMatthew Dillon 					break;
2942f85fa4dSMatthew Dillon 				default:
2952f85fa4dSMatthew Dillon 					panic("Illegal B-Tree node type");
2962f85fa4dSMatthew Dillon 				}
297bf686dbeSMatthew Dillon 			}
298bf686dbeSMatthew Dillon 			if (error == 0) {
299bf686dbeSMatthew Dillon 				++reblock->btree_moves;
300bf686dbeSMatthew Dillon 			}
301bf686dbeSMatthew Dillon 		}
302bf686dbeSMatthew Dillon 	}
303bf686dbeSMatthew Dillon 
304bf686dbeSMatthew Dillon 	hammer_cursor_downgrade(cursor);
305bf686dbeSMatthew Dillon 	return(error);
306bf686dbeSMatthew Dillon }
307bf686dbeSMatthew Dillon 
308bf686dbeSMatthew Dillon /*
309bf686dbeSMatthew Dillon  * Reblock a record's data.  Both the B-Tree element and record pointers
310bf686dbeSMatthew Dillon  * to the data must be adjusted.
311bf686dbeSMatthew Dillon  */
312bf686dbeSMatthew Dillon static int
31336f82b23SMatthew Dillon hammer_reblock_data(struct hammer_ioc_reblock *reblock,
314bf686dbeSMatthew Dillon 		    hammer_cursor_t cursor, hammer_btree_elm_t elm)
315bf686dbeSMatthew Dillon {
316bf686dbeSMatthew Dillon 	struct hammer_buffer *data_buffer = NULL;
317bf686dbeSMatthew Dillon 	hammer_off_t ndata_offset;
318bf686dbeSMatthew Dillon 	int error;
319bf686dbeSMatthew Dillon 	void *ndata;
320bf686dbeSMatthew Dillon 
321bf686dbeSMatthew Dillon 	error = hammer_btree_extract(cursor, HAMMER_CURSOR_GET_DATA |
32211ad5adeSMatthew Dillon 					     HAMMER_CURSOR_GET_LEAF);
323bf686dbeSMatthew Dillon 	if (error)
324bf686dbeSMatthew Dillon 		return (error);
32536f82b23SMatthew Dillon 	ndata = hammer_alloc_data(cursor->trans, elm->leaf.data_len,
326bf3b416bSMatthew Dillon 				  elm->leaf.base.rec_type,
32736f82b23SMatthew Dillon 				  &ndata_offset, &data_buffer, &error);
328bf686dbeSMatthew Dillon 	if (error)
329bf686dbeSMatthew Dillon 		goto done;
330bf686dbeSMatthew Dillon 
331bf686dbeSMatthew Dillon 	/*
332bf686dbeSMatthew Dillon 	 * Move the data
333bf686dbeSMatthew Dillon 	 */
33410a5d1baSMatthew Dillon 	hammer_modify_buffer(cursor->trans, data_buffer, NULL, 0);
335bf686dbeSMatthew Dillon 	bcopy(cursor->data, ndata, elm->leaf.data_len);
33610a5d1baSMatthew Dillon 	hammer_modify_buffer_done(data_buffer);
337bf686dbeSMatthew Dillon 
33836f82b23SMatthew Dillon 	hammer_blockmap_free(cursor->trans,
33936f82b23SMatthew Dillon 			     elm->leaf.data_offset, elm->leaf.data_len);
340bf686dbeSMatthew Dillon 
34110a5d1baSMatthew Dillon 	hammer_modify_node(cursor->trans, cursor->node,
34210a5d1baSMatthew Dillon 			   &elm->leaf.data_offset, sizeof(hammer_off_t));
343bf686dbeSMatthew Dillon 	elm->leaf.data_offset = ndata_offset;
34410a5d1baSMatthew Dillon 	hammer_modify_node_done(cursor->node);
345bf686dbeSMatthew Dillon 
346bf686dbeSMatthew Dillon done:
347bf686dbeSMatthew Dillon 	if (data_buffer)
348bf686dbeSMatthew Dillon 		hammer_rel_buffer(data_buffer, 0);
349bf686dbeSMatthew Dillon 	return (error);
350bf686dbeSMatthew Dillon }
351bf686dbeSMatthew Dillon 
352bf686dbeSMatthew Dillon /*
3532f85fa4dSMatthew Dillon  * Reblock a B-Tree leaf node.  The parent must be adjusted to point to
3542f85fa4dSMatthew Dillon  * the new copy of the leaf node.
355bf686dbeSMatthew Dillon  *
3562f85fa4dSMatthew Dillon  * elm is a pointer to the parent element pointing at cursor.node.
357bf686dbeSMatthew Dillon  */
358bf686dbeSMatthew Dillon static int
3592f85fa4dSMatthew Dillon hammer_reblock_leaf_node(struct hammer_ioc_reblock *reblock,
360bf686dbeSMatthew Dillon 			 hammer_cursor_t cursor, hammer_btree_elm_t elm)
361bf686dbeSMatthew Dillon {
362bf686dbeSMatthew Dillon 	hammer_node_t onode;
363bf686dbeSMatthew Dillon 	hammer_node_t nnode;
364bf686dbeSMatthew Dillon 	int error;
365bf686dbeSMatthew Dillon 
366bf686dbeSMatthew Dillon 	onode = cursor->node;
36736f82b23SMatthew Dillon 	nnode = hammer_alloc_btree(cursor->trans, &error);
3688d0efe43SMatthew Dillon 
369bf686dbeSMatthew Dillon 	if (nnode == NULL)
370bf686dbeSMatthew Dillon 		return (error);
371bf686dbeSMatthew Dillon 
372bf686dbeSMatthew Dillon 	/*
373bf686dbeSMatthew Dillon 	 * Move the node
374bf686dbeSMatthew Dillon 	 */
37509ac686bSMatthew Dillon 	hammer_lock_ex(&nnode->lock);
37609ac686bSMatthew Dillon 	hammer_modify_node_noundo(cursor->trans, nnode);
377bf686dbeSMatthew Dillon 	bcopy(onode->ondisk, nnode->ondisk, sizeof(*nnode->ondisk));
378bf686dbeSMatthew Dillon 
379bf686dbeSMatthew Dillon 	if (elm) {
380bf686dbeSMatthew Dillon 		/*
381bf686dbeSMatthew Dillon 		 * We are not the root of the B-Tree
382bf686dbeSMatthew Dillon 		 */
38336f82b23SMatthew Dillon 		hammer_modify_node(cursor->trans, cursor->parent,
384bf686dbeSMatthew Dillon 				   &elm->internal.subtree_offset,
385bf686dbeSMatthew Dillon 				   sizeof(elm->internal.subtree_offset));
386bf686dbeSMatthew Dillon 		elm->internal.subtree_offset = nnode->node_offset;
38710a5d1baSMatthew Dillon 		hammer_modify_node_done(cursor->parent);
388bf686dbeSMatthew Dillon 	} else {
389bf686dbeSMatthew Dillon 		/*
390bf686dbeSMatthew Dillon 		 * We are the root of the B-Tree
391bf686dbeSMatthew Dillon 		 */
392bf686dbeSMatthew Dillon                 hammer_volume_t volume;
393bf686dbeSMatthew Dillon 
39436f82b23SMatthew Dillon                 volume = hammer_get_root_volume(cursor->trans->hmp, &error);
395bf686dbeSMatthew Dillon                 KKASSERT(error == 0);
396bf686dbeSMatthew Dillon 
397e8599db1SMatthew Dillon                 hammer_modify_volume_field(cursor->trans, volume,
398e8599db1SMatthew Dillon 					   vol0_btree_root);
399bf686dbeSMatthew Dillon                 volume->ondisk->vol0_btree_root = nnode->node_offset;
40010a5d1baSMatthew Dillon                 hammer_modify_volume_done(volume);
401bf686dbeSMatthew Dillon                 hammer_rel_volume(volume, 0);
402bf686dbeSMatthew Dillon         }
403bf686dbeSMatthew Dillon 
404b3bad96fSMatthew Dillon 	hammer_cursor_replaced_node(onode, nnode);
40536f82b23SMatthew Dillon 	hammer_delete_node(cursor->trans, onode);
406bf686dbeSMatthew Dillon 
407b58c6388SMatthew Dillon 	if (hammer_debug_general & 0x4000) {
4082f85fa4dSMatthew Dillon 		kprintf("REBLOCK LNODE %016llx -> %016llx\n",
409bf686dbeSMatthew Dillon 			onode->node_offset, nnode->node_offset);
410b58c6388SMatthew Dillon 	}
4118d0efe43SMatthew Dillon 	hammer_modify_node_done(nnode);
412bf686dbeSMatthew Dillon 	cursor->node = nnode;
41309ac686bSMatthew Dillon 
41409ac686bSMatthew Dillon 	hammer_unlock(&onode->lock);
415bf686dbeSMatthew Dillon 	hammer_rel_node(onode);
416bf686dbeSMatthew Dillon 
417bf686dbeSMatthew Dillon 	return (error);
418bf686dbeSMatthew Dillon }
419bf686dbeSMatthew Dillon 
4202f85fa4dSMatthew Dillon /*
4212f85fa4dSMatthew Dillon  * Reblock a B-Tree internal node.  The parent must be adjusted to point to
4222f85fa4dSMatthew Dillon  * the new copy of the internal node, and the node's children's parent
4232f85fa4dSMatthew Dillon  * pointers must also be adjusted to point to the new copy.
4242f85fa4dSMatthew Dillon  *
4252f85fa4dSMatthew Dillon  * elm is a pointer to the parent element pointing at cursor.node.
4262f85fa4dSMatthew Dillon  */
4272f85fa4dSMatthew Dillon static int
4282f85fa4dSMatthew Dillon hammer_reblock_int_node(struct hammer_ioc_reblock *reblock,
4292f85fa4dSMatthew Dillon 			 hammer_cursor_t cursor, hammer_btree_elm_t elm)
4302f85fa4dSMatthew Dillon {
4312f85fa4dSMatthew Dillon 	hammer_node_locklist_t locklist = NULL;
4322f85fa4dSMatthew Dillon 	hammer_node_t onode;
4332f85fa4dSMatthew Dillon 	hammer_node_t nnode;
4342f85fa4dSMatthew Dillon 	int error;
4352f85fa4dSMatthew Dillon 	int i;
4362f85fa4dSMatthew Dillon 
4372f85fa4dSMatthew Dillon 	error = hammer_btree_lock_children(cursor, &locklist);
4382f85fa4dSMatthew Dillon 	if (error)
4392f85fa4dSMatthew Dillon 		goto done;
4402f85fa4dSMatthew Dillon 
4412f85fa4dSMatthew Dillon 	onode = cursor->node;
4422f85fa4dSMatthew Dillon 	nnode = hammer_alloc_btree(cursor->trans, &error);
4432f85fa4dSMatthew Dillon 
4442f85fa4dSMatthew Dillon 	if (nnode == NULL)
4452f85fa4dSMatthew Dillon 		goto done;
4462f85fa4dSMatthew Dillon 
4472f85fa4dSMatthew Dillon 	/*
4482f85fa4dSMatthew Dillon 	 * Move the node.  Adjust the parent's pointer to us first.
4492f85fa4dSMatthew Dillon 	 */
4502f85fa4dSMatthew Dillon 	hammer_lock_ex(&nnode->lock);
4512f85fa4dSMatthew Dillon 	hammer_modify_node_noundo(cursor->trans, nnode);
4522f85fa4dSMatthew Dillon 	bcopy(onode->ondisk, nnode->ondisk, sizeof(*nnode->ondisk));
4532f85fa4dSMatthew Dillon 
4542f85fa4dSMatthew Dillon 	if (elm) {
4552f85fa4dSMatthew Dillon 		/*
4562f85fa4dSMatthew Dillon 		 * We are not the root of the B-Tree
4572f85fa4dSMatthew Dillon 		 */
4582f85fa4dSMatthew Dillon 		hammer_modify_node(cursor->trans, cursor->parent,
4592f85fa4dSMatthew Dillon 				   &elm->internal.subtree_offset,
4602f85fa4dSMatthew Dillon 				   sizeof(elm->internal.subtree_offset));
4612f85fa4dSMatthew Dillon 		elm->internal.subtree_offset = nnode->node_offset;
4622f85fa4dSMatthew Dillon 		hammer_modify_node_done(cursor->parent);
4632f85fa4dSMatthew Dillon 	} else {
4642f85fa4dSMatthew Dillon 		/*
4652f85fa4dSMatthew Dillon 		 * We are the root of the B-Tree
4662f85fa4dSMatthew Dillon 		 */
4672f85fa4dSMatthew Dillon                 hammer_volume_t volume;
4682f85fa4dSMatthew Dillon 
4692f85fa4dSMatthew Dillon                 volume = hammer_get_root_volume(cursor->trans->hmp, &error);
4702f85fa4dSMatthew Dillon                 KKASSERT(error == 0);
4712f85fa4dSMatthew Dillon 
4722f85fa4dSMatthew Dillon                 hammer_modify_volume_field(cursor->trans, volume,
4732f85fa4dSMatthew Dillon 					   vol0_btree_root);
4742f85fa4dSMatthew Dillon                 volume->ondisk->vol0_btree_root = nnode->node_offset;
4752f85fa4dSMatthew Dillon                 hammer_modify_volume_done(volume);
4762f85fa4dSMatthew Dillon                 hammer_rel_volume(volume, 0);
4772f85fa4dSMatthew Dillon         }
4782f85fa4dSMatthew Dillon 
4792f85fa4dSMatthew Dillon 	/*
4802f85fa4dSMatthew Dillon 	 * Now adjust our children's pointers to us.
4812f85fa4dSMatthew Dillon 	 */
4822f85fa4dSMatthew Dillon 	for (i = 0; i < nnode->ondisk->count; ++i) {
4832f85fa4dSMatthew Dillon 		elm = &nnode->ondisk->elms[i];
4842f85fa4dSMatthew Dillon 		error = btree_set_parent(cursor->trans, nnode, elm);
4852f85fa4dSMatthew Dillon 		if (error)
4862f85fa4dSMatthew Dillon 			panic("reblock internal node: fixup problem");
4872f85fa4dSMatthew Dillon 	}
4882f85fa4dSMatthew Dillon 
4892f85fa4dSMatthew Dillon 	/*
4902f85fa4dSMatthew Dillon 	 * Clean up.
4912f85fa4dSMatthew Dillon 	 *
4922f85fa4dSMatthew Dillon 	 * The new node replaces the current node in the cursor.  The cursor
4932f85fa4dSMatthew Dillon 	 * expects it to be locked so leave it locked.  Discard onode.
4942f85fa4dSMatthew Dillon 	 */
495b3bad96fSMatthew Dillon 	hammer_cursor_replaced_node(onode, nnode);
4962f85fa4dSMatthew Dillon 	hammer_delete_node(cursor->trans, onode);
4972f85fa4dSMatthew Dillon 
4982f85fa4dSMatthew Dillon 	if (hammer_debug_general & 0x4000) {
4992f85fa4dSMatthew Dillon 		kprintf("REBLOCK INODE %016llx -> %016llx\n",
5002f85fa4dSMatthew Dillon 			onode->node_offset, nnode->node_offset);
5012f85fa4dSMatthew Dillon 	}
5022f85fa4dSMatthew Dillon 	hammer_modify_node_done(nnode);
5032f85fa4dSMatthew Dillon 	cursor->node = nnode;
5042f85fa4dSMatthew Dillon 
5052f85fa4dSMatthew Dillon 	hammer_unlock(&onode->lock);
5062f85fa4dSMatthew Dillon 	hammer_rel_node(onode);
5072f85fa4dSMatthew Dillon 
5082f85fa4dSMatthew Dillon done:
5092f85fa4dSMatthew Dillon 	hammer_btree_unlock_children(&locklist);
5102f85fa4dSMatthew Dillon 	return (error);
5112f85fa4dSMatthew Dillon }
5122f85fa4dSMatthew Dillon 
513