xref: /dflybsd-src/sys/vfs/hammer/hammer_cursor.c (revision d26d0ae9b763bc95e7517d9825f5488bd3e53e67)
18cd0a023SMatthew Dillon /*
28cd0a023SMatthew Dillon  * Copyright (c) 2007 The DragonFly Project.  All rights reserved.
38cd0a023SMatthew Dillon  *
48cd0a023SMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
58cd0a023SMatthew Dillon  * by Matthew Dillon <dillon@backplane.com>
68cd0a023SMatthew Dillon  *
78cd0a023SMatthew Dillon  * Redistribution and use in source and binary forms, with or without
88cd0a023SMatthew Dillon  * modification, are permitted provided that the following conditions
98cd0a023SMatthew Dillon  * are met:
108cd0a023SMatthew Dillon  *
118cd0a023SMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
128cd0a023SMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
138cd0a023SMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
148cd0a023SMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
158cd0a023SMatthew Dillon  *    the documentation and/or other materials provided with the
168cd0a023SMatthew Dillon  *    distribution.
178cd0a023SMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
188cd0a023SMatthew Dillon  *    contributors may be used to endorse or promote products derived
198cd0a023SMatthew Dillon  *    from this software without specific, prior written permission.
208cd0a023SMatthew Dillon  *
218cd0a023SMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
228cd0a023SMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
238cd0a023SMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
248cd0a023SMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
258cd0a023SMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
268cd0a023SMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
278cd0a023SMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
288cd0a023SMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
298cd0a023SMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
308cd0a023SMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
318cd0a023SMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
328cd0a023SMatthew Dillon  * SUCH DAMAGE.
338cd0a023SMatthew Dillon  *
34*d26d0ae9SMatthew Dillon  * $DragonFly: src/sys/vfs/hammer/hammer_cursor.c,v 1.6 2007/12/29 09:01:27 dillon Exp $
358cd0a023SMatthew Dillon  */
368cd0a023SMatthew Dillon 
378cd0a023SMatthew Dillon /*
388cd0a023SMatthew Dillon  * HAMMER B-Tree index - cursor support routines
398cd0a023SMatthew Dillon  */
408cd0a023SMatthew Dillon #include "hammer.h"
418cd0a023SMatthew Dillon 
428cd0a023SMatthew Dillon static int hammer_load_cursor_parent(hammer_cursor_t cursor);
438cd0a023SMatthew Dillon static int hammer_load_cursor_parent_local(hammer_cursor_t cursor);
448cd0a023SMatthew Dillon static int hammer_load_cursor_parent_cluster(hammer_cursor_t cursor);
458cd0a023SMatthew Dillon 
468cd0a023SMatthew Dillon /*
478cd0a023SMatthew Dillon  * Initialize a fresh cursor at the root of the filesystem hierarchy.
488cd0a023SMatthew Dillon  *
498cd0a023SMatthew Dillon  * cursor->parent will be NULL on return since we are loading the root
508cd0a023SMatthew Dillon  * node of the root cluster.
518cd0a023SMatthew Dillon  */
528cd0a023SMatthew Dillon int
538cd0a023SMatthew Dillon hammer_init_cursor_hmp(hammer_cursor_t cursor, hammer_mount_t hmp)
548cd0a023SMatthew Dillon {
558cd0a023SMatthew Dillon 	hammer_cluster_t cluster;
568cd0a023SMatthew Dillon 	int error;
578cd0a023SMatthew Dillon 
588cd0a023SMatthew Dillon 	bzero(cursor, sizeof(*cursor));
598cd0a023SMatthew Dillon 	cluster = hammer_get_root_cluster(hmp, &error);
608cd0a023SMatthew Dillon 	if (error == 0) {
618cd0a023SMatthew Dillon 		cursor->node = hammer_get_node(cluster,
628cd0a023SMatthew Dillon 					       cluster->ondisk->clu_btree_root,
638cd0a023SMatthew Dillon 					       &error);
648cd0a023SMatthew Dillon 		hammer_rel_cluster(cluster, 0);
658cd0a023SMatthew Dillon 		if (error == 0)
668cd0a023SMatthew Dillon 			hammer_lock_ex(&cursor->node->lock);
678cd0a023SMatthew Dillon 	}
688cd0a023SMatthew Dillon 	if (error == 0)
698cd0a023SMatthew Dillon 		error = hammer_load_cursor_parent(cursor);
708cd0a023SMatthew Dillon 	return(error);
718cd0a023SMatthew Dillon }
728cd0a023SMatthew Dillon 
738cd0a023SMatthew Dillon /*
74*d26d0ae9SMatthew Dillon  * Initialize a fresh cursor at the root of the specified cluster and
75*d26d0ae9SMatthew Dillon  * limit operations to within the cluster.
76*d26d0ae9SMatthew Dillon  */
77*d26d0ae9SMatthew Dillon int
78*d26d0ae9SMatthew Dillon hammer_init_cursor_cluster(hammer_cursor_t cursor, hammer_cluster_t cluster)
79*d26d0ae9SMatthew Dillon {
80*d26d0ae9SMatthew Dillon 	int error;
81*d26d0ae9SMatthew Dillon 
82*d26d0ae9SMatthew Dillon 	bzero(cursor, sizeof(*cursor));
83*d26d0ae9SMatthew Dillon 	cursor->flags |= HAMMER_CURSOR_INCLUSTER;
84*d26d0ae9SMatthew Dillon 	cursor->node = hammer_get_node(cluster,
85*d26d0ae9SMatthew Dillon 				       cluster->ondisk->clu_btree_root,
86*d26d0ae9SMatthew Dillon 				       &error);
87*d26d0ae9SMatthew Dillon 	if (error == 0) {
88*d26d0ae9SMatthew Dillon 		hammer_lock_ex(&cursor->node->lock);
89*d26d0ae9SMatthew Dillon 		error = hammer_load_cursor_parent(cursor);
90*d26d0ae9SMatthew Dillon 	}
91*d26d0ae9SMatthew Dillon 	return(error);
92*d26d0ae9SMatthew Dillon }
93*d26d0ae9SMatthew Dillon 
94*d26d0ae9SMatthew Dillon /*
958cd0a023SMatthew Dillon  * Initialize a fresh cursor using the B-Tree node cached by the
968cd0a023SMatthew Dillon  * in-memory inode.
978cd0a023SMatthew Dillon  */
988cd0a023SMatthew Dillon int
998cd0a023SMatthew Dillon hammer_init_cursor_ip(hammer_cursor_t cursor, hammer_inode_t ip)
1008cd0a023SMatthew Dillon {
101a89aec1bSMatthew Dillon 	hammer_node_t node;
1028cd0a023SMatthew Dillon 	int error;
1038cd0a023SMatthew Dillon 
1048cd0a023SMatthew Dillon 	if (ip->cache) {
1058cd0a023SMatthew Dillon 		bzero(cursor, sizeof(*cursor));
106a89aec1bSMatthew Dillon 		node = ip->cache;
107a89aec1bSMatthew Dillon 		error = hammer_ref_node(node);
1088cd0a023SMatthew Dillon 		if (error == 0) {
109a89aec1bSMatthew Dillon 			hammer_lock_ex(&node->lock);
110a89aec1bSMatthew Dillon 			cursor->node = node;
1118cd0a023SMatthew Dillon 			error = hammer_load_cursor_parent(cursor);
1128cd0a023SMatthew Dillon 		} else {
113a89aec1bSMatthew Dillon 			node = NULL;
114a89aec1bSMatthew Dillon 			cursor->node = node;
1158cd0a023SMatthew Dillon 		}
1168cd0a023SMatthew Dillon 	} else {
1178cd0a023SMatthew Dillon 		error = hammer_init_cursor_hmp(cursor, ip->hmp);
1188cd0a023SMatthew Dillon 	}
1198cd0a023SMatthew Dillon 	return(error);
1208cd0a023SMatthew Dillon }
1218cd0a023SMatthew Dillon 
1228cd0a023SMatthew Dillon /*
1238cd0a023SMatthew Dillon  * We are finished with a cursor.  We NULL out various fields as sanity
1248cd0a023SMatthew Dillon  * check, in case the structure is inappropriately used afterwords.
1258cd0a023SMatthew Dillon  */
1268cd0a023SMatthew Dillon void
1278cd0a023SMatthew Dillon hammer_done_cursor(hammer_cursor_t cursor)
1288cd0a023SMatthew Dillon {
1298cd0a023SMatthew Dillon 	if (cursor->parent) {
1308cd0a023SMatthew Dillon 		hammer_unlock(&cursor->parent->lock);
1318cd0a023SMatthew Dillon 		hammer_rel_node(cursor->parent);
1328cd0a023SMatthew Dillon 		cursor->parent = NULL;
1338cd0a023SMatthew Dillon 	}
1348cd0a023SMatthew Dillon 	if (cursor->node) {
1358cd0a023SMatthew Dillon 		hammer_unlock(&cursor->node->lock);
1368cd0a023SMatthew Dillon 		hammer_rel_node(cursor->node);
1378cd0a023SMatthew Dillon 		cursor->node = NULL;
1388cd0a023SMatthew Dillon 	}
1398cd0a023SMatthew Dillon         if (cursor->data_buffer) {
1408cd0a023SMatthew Dillon                 hammer_rel_buffer(cursor->data_buffer, 0);
1418cd0a023SMatthew Dillon                 cursor->data_buffer = NULL;
1428cd0a023SMatthew Dillon         }
1438cd0a023SMatthew Dillon         if (cursor->record_buffer) {
1448cd0a023SMatthew Dillon                 hammer_rel_buffer(cursor->record_buffer, 0);
1458cd0a023SMatthew Dillon                 cursor->record_buffer = NULL;
1468cd0a023SMatthew Dillon         }
1476b4f890bSMatthew Dillon 	if (cursor->ip)
1486b4f890bSMatthew Dillon 		hammer_mem_done(cursor);
149a89aec1bSMatthew Dillon 
1508cd0a023SMatthew Dillon 	cursor->data = NULL;
1518cd0a023SMatthew Dillon 	cursor->record = NULL;
1528cd0a023SMatthew Dillon 	cursor->left_bound = NULL;
1538cd0a023SMatthew Dillon 	cursor->right_bound = NULL;
1548cd0a023SMatthew Dillon }
1558cd0a023SMatthew Dillon 
1568cd0a023SMatthew Dillon /*
157195c19a1SMatthew Dillon  * Acquire the parent B-Tree node of the specified node, returning a
158195c19a1SMatthew Dillon  * referenced but unlocked node.  NULL can be returned with *errorp == 0
159195c19a1SMatthew Dillon  * if node is the root node of the root cluster.
160195c19a1SMatthew Dillon  */
161195c19a1SMatthew Dillon static
162195c19a1SMatthew Dillon hammer_node_t
163195c19a1SMatthew Dillon hammer_get_parent_node(hammer_node_t node, int *errorp)
164195c19a1SMatthew Dillon {
165195c19a1SMatthew Dillon 	hammer_cluster_t cluster;
166195c19a1SMatthew Dillon 	hammer_node_t parent;
167195c19a1SMatthew Dillon 
168195c19a1SMatthew Dillon 	cluster = node->cluster;
169195c19a1SMatthew Dillon 	if (node->ondisk->parent) {
170195c19a1SMatthew Dillon 		/*
171195c19a1SMatthew Dillon 		 * Local parent
172195c19a1SMatthew Dillon 		 */
173195c19a1SMatthew Dillon 		parent = hammer_get_node(cluster, node->ondisk->parent, errorp);
174195c19a1SMatthew Dillon 	} else if (cluster->ondisk->clu_btree_parent_vol_no >= 0) {
175195c19a1SMatthew Dillon 		/*
176195c19a1SMatthew Dillon 		 * At cluster root, locate node in parent cluster
177195c19a1SMatthew Dillon 		 */
178195c19a1SMatthew Dillon 		hammer_cluster_ondisk_t ondisk;
179195c19a1SMatthew Dillon 		hammer_cluster_t pcluster;
180195c19a1SMatthew Dillon 		hammer_volume_t pvolume;
181195c19a1SMatthew Dillon 		int32_t clu_no;
182195c19a1SMatthew Dillon 		int32_t vol_no;
183195c19a1SMatthew Dillon 
184195c19a1SMatthew Dillon 		ondisk = cluster->ondisk;
185195c19a1SMatthew Dillon 		vol_no = ondisk->clu_btree_parent_vol_no;
186195c19a1SMatthew Dillon 		clu_no = ondisk->clu_btree_parent_clu_no;
187195c19a1SMatthew Dillon 
188195c19a1SMatthew Dillon 		/*
189195c19a1SMatthew Dillon 		 * Acquire the node from (volume, cluster, offset)
190195c19a1SMatthew Dillon 		 */
191195c19a1SMatthew Dillon 		pvolume = hammer_get_volume(cluster->volume->hmp, vol_no,
192195c19a1SMatthew Dillon 					    errorp);
193195c19a1SMatthew Dillon 		if (*errorp)
194195c19a1SMatthew Dillon 			return (NULL);
195195c19a1SMatthew Dillon 		pcluster = hammer_get_cluster(pvolume, clu_no, errorp, 0);
196195c19a1SMatthew Dillon 		hammer_rel_volume(pvolume, 0);
197195c19a1SMatthew Dillon 		if (*errorp)
198195c19a1SMatthew Dillon 			return (NULL);
199195c19a1SMatthew Dillon 		parent = hammer_get_node(pcluster,
200195c19a1SMatthew Dillon 					 ondisk->clu_btree_parent_offset,
201195c19a1SMatthew Dillon 					 errorp);
202195c19a1SMatthew Dillon 		hammer_rel_cluster(pcluster, 0);
203195c19a1SMatthew Dillon 	} else {
204195c19a1SMatthew Dillon 		/*
205195c19a1SMatthew Dillon 		 * At root of root cluster, there is no parent.
206195c19a1SMatthew Dillon 		 */
207*d26d0ae9SMatthew Dillon 		KKASSERT(cluster->ondisk->clu_btree_parent_vol_no == -1);
208195c19a1SMatthew Dillon 		parent = NULL;
209195c19a1SMatthew Dillon 		*errorp = 0;
210195c19a1SMatthew Dillon 	}
211195c19a1SMatthew Dillon 	return(parent);
212195c19a1SMatthew Dillon }
213195c19a1SMatthew Dillon 
214195c19a1SMatthew Dillon /*
2158cd0a023SMatthew Dillon  * Load the parent of cursor->node into cursor->parent.  There are several
2168cd0a023SMatthew Dillon  * cases.  (1) The parent is in the current cluster.  (2) We are at the
2178cd0a023SMatthew Dillon  * root of the cluster and the parent is in another cluster.  (3) We are at
2188cd0a023SMatthew Dillon  * the root of the root cluster.
219*d26d0ae9SMatthew Dillon  *
220*d26d0ae9SMatthew Dillon  * If HAMMER_CURSOR_INCLUSTER is set and we are at the root of the cluster,
221*d26d0ae9SMatthew Dillon  * we do not access the parent cluster at all and make the cursor look like
222*d26d0ae9SMatthew Dillon  * its at the root.
2238cd0a023SMatthew Dillon  */
2248cd0a023SMatthew Dillon static
2258cd0a023SMatthew Dillon int
2268cd0a023SMatthew Dillon hammer_load_cursor_parent(hammer_cursor_t cursor)
2278cd0a023SMatthew Dillon {
2288cd0a023SMatthew Dillon 	hammer_cluster_t cluster;
2298cd0a023SMatthew Dillon 	int error;
2308cd0a023SMatthew Dillon 
2318cd0a023SMatthew Dillon 	cluster = cursor->node->cluster;
2328cd0a023SMatthew Dillon 
2338cd0a023SMatthew Dillon 	if (cursor->node->ondisk->parent) {
2348cd0a023SMatthew Dillon 		error = hammer_load_cursor_parent_local(cursor);
235*d26d0ae9SMatthew Dillon 	} else if (cluster->ondisk->clu_btree_parent_vol_no >= 0 &&
236*d26d0ae9SMatthew Dillon 		   ((cursor->flags & HAMMER_CURSOR_INCLUSTER) == 0)
237*d26d0ae9SMatthew Dillon 	) {
2388cd0a023SMatthew Dillon 		error = hammer_load_cursor_parent_cluster(cursor);
2398cd0a023SMatthew Dillon 	} else {
2408cd0a023SMatthew Dillon 		cursor->parent = NULL;
2418cd0a023SMatthew Dillon 		cursor->parent_index = 0;
2428cd0a023SMatthew Dillon 		cursor->left_bound = &cluster->ondisk->clu_btree_beg;
2438cd0a023SMatthew Dillon 		cursor->right_bound = &cluster->ondisk->clu_btree_end;
2448cd0a023SMatthew Dillon 		error = 0;
2458cd0a023SMatthew Dillon 	}
2468cd0a023SMatthew Dillon 	return(error);
2478cd0a023SMatthew Dillon }
2488cd0a023SMatthew Dillon 
2498cd0a023SMatthew Dillon static
2508cd0a023SMatthew Dillon int
2518cd0a023SMatthew Dillon hammer_load_cursor_parent_local(hammer_cursor_t cursor)
2528cd0a023SMatthew Dillon {
2538cd0a023SMatthew Dillon 	hammer_node_t node;
2548cd0a023SMatthew Dillon 	hammer_node_t parent;
2558cd0a023SMatthew Dillon 	hammer_btree_elm_t elm;
2568cd0a023SMatthew Dillon 	int error;
2578cd0a023SMatthew Dillon 	int i;
2588cd0a023SMatthew Dillon 
2598cd0a023SMatthew Dillon 	node = cursor->node;
2608cd0a023SMatthew Dillon 	parent = hammer_get_node(node->cluster, node->ondisk->parent, &error);
2618cd0a023SMatthew Dillon 	if (error)
2628cd0a023SMatthew Dillon 		return(error);
2638cd0a023SMatthew Dillon 	elm = NULL;
2648cd0a023SMatthew Dillon 	for (i = 0; i < parent->ondisk->count; ++i) {
2658cd0a023SMatthew Dillon 		elm = &parent->ondisk->elms[i];
2668cd0a023SMatthew Dillon 		if (parent->ondisk->elms[i].internal.subtree_offset ==
2678cd0a023SMatthew Dillon 		    node->node_offset) {
2688cd0a023SMatthew Dillon 			break;
2698cd0a023SMatthew Dillon 		}
2708cd0a023SMatthew Dillon 	}
2718cd0a023SMatthew Dillon 	KKASSERT(i != parent->ondisk->count);
2728cd0a023SMatthew Dillon 	KKASSERT(parent->ondisk->elms[i].internal.rec_offset == 0);
2738cd0a023SMatthew Dillon 	cursor->parent = parent;
2748cd0a023SMatthew Dillon 	cursor->parent_index = i;
2758cd0a023SMatthew Dillon 	cursor->left_bound = &elm[0].internal.base;
2768cd0a023SMatthew Dillon 	cursor->right_bound = &elm[1].internal.base;
2778cd0a023SMatthew Dillon 
2788cd0a023SMatthew Dillon 	if (hammer_lock_ex_try(&parent->lock) != 0) {
2798cd0a023SMatthew Dillon 		hammer_unlock(&cursor->node->lock);
2808cd0a023SMatthew Dillon 		hammer_lock_ex(&parent->lock);
2818cd0a023SMatthew Dillon 		hammer_lock_ex(&cursor->node->lock);
2828cd0a023SMatthew Dillon 		/* XXX check node generation count */
2838cd0a023SMatthew Dillon 	}
2848cd0a023SMatthew Dillon 	return(error);
2858cd0a023SMatthew Dillon }
2868cd0a023SMatthew Dillon 
2878cd0a023SMatthew Dillon static
2888cd0a023SMatthew Dillon int
2898cd0a023SMatthew Dillon hammer_load_cursor_parent_cluster(hammer_cursor_t cursor)
2908cd0a023SMatthew Dillon {
2918cd0a023SMatthew Dillon 	hammer_cluster_ondisk_t ondisk;
292*d26d0ae9SMatthew Dillon 	hammer_cluster_t pcluster;
293*d26d0ae9SMatthew Dillon 	hammer_cluster_t ccluster;
2948cd0a023SMatthew Dillon 	hammer_volume_t volume;
2958cd0a023SMatthew Dillon 	hammer_node_t node;
2968cd0a023SMatthew Dillon 	hammer_node_t parent;
2978cd0a023SMatthew Dillon 	hammer_btree_elm_t elm;
2988cd0a023SMatthew Dillon 	int32_t clu_no;
2998cd0a023SMatthew Dillon 	int32_t vol_no;
3008cd0a023SMatthew Dillon 	int error;
3018cd0a023SMatthew Dillon 	int i;
3028cd0a023SMatthew Dillon 
3038cd0a023SMatthew Dillon 	node = cursor->node;
304*d26d0ae9SMatthew Dillon 	ccluster = node->cluster;
305*d26d0ae9SMatthew Dillon 	ondisk = ccluster->ondisk;
3068cd0a023SMatthew Dillon 	vol_no = ondisk->clu_btree_parent_vol_no;
3078cd0a023SMatthew Dillon 	clu_no = ondisk->clu_btree_parent_clu_no;
3088cd0a023SMatthew Dillon 
3098cd0a023SMatthew Dillon 	/*
3108cd0a023SMatthew Dillon 	 * Acquire the node from (volume, cluster, offset)
3118cd0a023SMatthew Dillon 	 */
312*d26d0ae9SMatthew Dillon 	volume = hammer_get_volume(ccluster->volume->hmp, vol_no, &error);
3138cd0a023SMatthew Dillon 	if (error)
3148cd0a023SMatthew Dillon 		return (error);
315*d26d0ae9SMatthew Dillon 	pcluster = hammer_get_cluster(volume, clu_no, &error, 0);
3168cd0a023SMatthew Dillon 	hammer_rel_volume(volume, 0);
3178cd0a023SMatthew Dillon 	if (error)
3188cd0a023SMatthew Dillon 		return (error);
319*d26d0ae9SMatthew Dillon 	parent = hammer_get_node(pcluster, ondisk->clu_btree_parent_offset,
3208cd0a023SMatthew Dillon 				 &error);
321*d26d0ae9SMatthew Dillon 	hammer_rel_cluster(pcluster, 0);
322*d26d0ae9SMatthew Dillon 	kprintf("parent %p clu_no %d\n", parent, clu_no);
3238cd0a023SMatthew Dillon 	if (error)
3248cd0a023SMatthew Dillon 		return (error);
3258cd0a023SMatthew Dillon 
3268cd0a023SMatthew Dillon 	/*
3278cd0a023SMatthew Dillon 	 * Ok, we have the node.  Locate the inter-cluster element
3288cd0a023SMatthew Dillon 	 */
3298cd0a023SMatthew Dillon 	elm = NULL;
3308cd0a023SMatthew Dillon 	for (i = 0; i < parent->ondisk->count; ++i) {
3318cd0a023SMatthew Dillon 		elm = &parent->ondisk->elms[i];
332*d26d0ae9SMatthew Dillon 		if (elm->internal.subtree_type == HAMMER_BTREE_TYPE_CLUSTER)
333*d26d0ae9SMatthew Dillon 			kprintf("SUBTEST CLU %d\n", elm->internal.subtree_clu_no);
3348cd0a023SMatthew Dillon 		if (elm->internal.rec_offset != 0 &&
335*d26d0ae9SMatthew Dillon 		    elm->internal.subtree_type == HAMMER_BTREE_TYPE_CLUSTER &&
336*d26d0ae9SMatthew Dillon 		    elm->internal.subtree_clu_no == cursor->node->cluster->clu_no) {
3378cd0a023SMatthew Dillon 			break;
3388cd0a023SMatthew Dillon 		}
3398cd0a023SMatthew Dillon 	}
3408cd0a023SMatthew Dillon 	KKASSERT(i != parent->ondisk->count);
3418cd0a023SMatthew Dillon 	cursor->parent = parent;
3428cd0a023SMatthew Dillon 	cursor->parent_index = i;
3438cd0a023SMatthew Dillon 	cursor->left_bound = &elm[0].internal.base;
3448cd0a023SMatthew Dillon 	cursor->right_bound = &elm[1].internal.base;
3458cd0a023SMatthew Dillon 
3468cd0a023SMatthew Dillon 	KKASSERT(hammer_btree_cmp(cursor->left_bound,
347*d26d0ae9SMatthew Dillon 		 &ccluster->ondisk->clu_btree_beg) == 0);
3488cd0a023SMatthew Dillon 	KKASSERT(hammer_btree_cmp(cursor->right_bound,
349*d26d0ae9SMatthew Dillon 		 &ccluster->ondisk->clu_btree_end) == 0);
3508cd0a023SMatthew Dillon 
3518cd0a023SMatthew Dillon 	if (hammer_lock_ex_try(&parent->lock) != 0) {
3528cd0a023SMatthew Dillon 		hammer_unlock(&cursor->node->lock);
3538cd0a023SMatthew Dillon 		hammer_lock_ex(&parent->lock);
3548cd0a023SMatthew Dillon 		hammer_lock_ex(&cursor->node->lock);
3558cd0a023SMatthew Dillon 		/* XXX check node generation count */
3568cd0a023SMatthew Dillon 	}
3578cd0a023SMatthew Dillon 	return(0);
3588cd0a023SMatthew Dillon }
3598cd0a023SMatthew Dillon 
3608cd0a023SMatthew Dillon /*
3618cd0a023SMatthew Dillon  * Cursor up to our parent node.  Return ENOENT if we are at the root of
3628cd0a023SMatthew Dillon  * the root cluster.
363195c19a1SMatthew Dillon  *
364195c19a1SMatthew Dillon  * If doing a nonblocking cursor-up and we are unable to acquire the lock,
365195c19a1SMatthew Dillon  * the cursor remains unchanged.
3668cd0a023SMatthew Dillon  */
3678cd0a023SMatthew Dillon int
368195c19a1SMatthew Dillon hammer_cursor_up(hammer_cursor_t cursor, int nonblock)
3698cd0a023SMatthew Dillon {
370195c19a1SMatthew Dillon 	hammer_node_t save;
3718cd0a023SMatthew Dillon 	int error;
3728cd0a023SMatthew Dillon 
3738cd0a023SMatthew Dillon 	/*
374195c19a1SMatthew Dillon 	 * If asked to do this non-blocking acquire a lock on the parent
375195c19a1SMatthew Dillon 	 * now, before we mess with the cursor.
376195c19a1SMatthew Dillon 	 */
377195c19a1SMatthew Dillon 	if (nonblock) {
378195c19a1SMatthew Dillon 		save = hammer_get_parent_node(cursor->parent, &error);
379195c19a1SMatthew Dillon 		if (error)
380195c19a1SMatthew Dillon 			return(error);
381195c19a1SMatthew Dillon 		if (save) {
382195c19a1SMatthew Dillon 			if (hammer_lock_ex_try(&save->lock) != 0) {
383195c19a1SMatthew Dillon 				hammer_rel_node(save);
384195c19a1SMatthew Dillon 				return(EAGAIN);
385195c19a1SMatthew Dillon 			}
386195c19a1SMatthew Dillon 		}
387195c19a1SMatthew Dillon 	} else {
388195c19a1SMatthew Dillon 		save = NULL;
389195c19a1SMatthew Dillon 	}
390195c19a1SMatthew Dillon 
391195c19a1SMatthew Dillon 	/*
3928cd0a023SMatthew Dillon 	 * Set the node to its parent.  If the parent is NULL we are at
3938cd0a023SMatthew Dillon 	 * the root of the root cluster and return ENOENT.
3948cd0a023SMatthew Dillon 	 */
3958cd0a023SMatthew Dillon 	hammer_unlock(&cursor->node->lock);
3968cd0a023SMatthew Dillon 	hammer_rel_node(cursor->node);
3978cd0a023SMatthew Dillon 	cursor->node = cursor->parent;
3988cd0a023SMatthew Dillon 	cursor->index = cursor->parent_index;
3998cd0a023SMatthew Dillon 	cursor->parent = NULL;
4008cd0a023SMatthew Dillon 	cursor->parent_index = 0;
4018cd0a023SMatthew Dillon 
4028cd0a023SMatthew Dillon 	if (cursor->node == NULL) {
4038cd0a023SMatthew Dillon 		error = ENOENT;
404*d26d0ae9SMatthew Dillon 	} else if ((cursor->flags & HAMMER_CURSOR_INCLUSTER) &&
405*d26d0ae9SMatthew Dillon 		   cursor->node->ondisk->parent == 0
406*d26d0ae9SMatthew Dillon 	) {
407*d26d0ae9SMatthew Dillon 		error = ENOENT;
4088cd0a023SMatthew Dillon 	} else {
4098cd0a023SMatthew Dillon 		error = hammer_load_cursor_parent(cursor);
4108cd0a023SMatthew Dillon 	}
411195c19a1SMatthew Dillon 	if (save) {
412195c19a1SMatthew Dillon 		hammer_unlock(&save->lock);
413195c19a1SMatthew Dillon 		hammer_rel_node(save);
414195c19a1SMatthew Dillon 	}
4158cd0a023SMatthew Dillon 	return(error);
4168cd0a023SMatthew Dillon }
4178cd0a023SMatthew Dillon 
4188cd0a023SMatthew Dillon /*
4198cd0a023SMatthew Dillon  * Set the cursor to the root of the current cursor's cluster.
4208cd0a023SMatthew Dillon  */
4218cd0a023SMatthew Dillon int
4228cd0a023SMatthew Dillon hammer_cursor_toroot(hammer_cursor_t cursor)
4238cd0a023SMatthew Dillon {
4248cd0a023SMatthew Dillon 	hammer_cluster_t cluster;
4258cd0a023SMatthew Dillon 	int error;
4268cd0a023SMatthew Dillon 
4278cd0a023SMatthew Dillon 	/*
4288cd0a023SMatthew Dillon 	 * Already at root of cluster?
4298cd0a023SMatthew Dillon 	 */
4308cd0a023SMatthew Dillon 	if (cursor->node->ondisk->parent == 0)
4318cd0a023SMatthew Dillon 		return (0);
4328cd0a023SMatthew Dillon 
4338cd0a023SMatthew Dillon 	/*
4348cd0a023SMatthew Dillon 	 * Parent is root of cluster?
4358cd0a023SMatthew Dillon 	 */
4368cd0a023SMatthew Dillon 	if (cursor->parent->ondisk->parent == 0)
437195c19a1SMatthew Dillon 		return (hammer_cursor_up(cursor, 0));
4388cd0a023SMatthew Dillon 
4398cd0a023SMatthew Dillon 	/*
4408cd0a023SMatthew Dillon 	 * Ok, reload the cursor with the root of the cluster, then
4418cd0a023SMatthew Dillon 	 * locate its parent.
4428cd0a023SMatthew Dillon 	 */
4438cd0a023SMatthew Dillon 	cluster = cursor->node->cluster;
4448cd0a023SMatthew Dillon 	error = hammer_ref_cluster(cluster);
4458cd0a023SMatthew Dillon 	if (error)
4468cd0a023SMatthew Dillon 		return (error);
4478cd0a023SMatthew Dillon 
4488cd0a023SMatthew Dillon 	hammer_unlock(&cursor->parent->lock);
4498cd0a023SMatthew Dillon 	hammer_rel_node(cursor->parent);
4508cd0a023SMatthew Dillon 	hammer_unlock(&cursor->node->lock);
4518cd0a023SMatthew Dillon 	hammer_rel_node(cursor->node);
4528cd0a023SMatthew Dillon 	cursor->parent = NULL;
4538cd0a023SMatthew Dillon 	cursor->parent_index = 0;
4548cd0a023SMatthew Dillon 
4558cd0a023SMatthew Dillon 	cursor->node = hammer_get_node(cluster, cluster->ondisk->clu_btree_root,
4568cd0a023SMatthew Dillon 				       &error);
4578cd0a023SMatthew Dillon 	cursor->index = 0;
4588cd0a023SMatthew Dillon 	hammer_rel_cluster(cluster, 0);
4598cd0a023SMatthew Dillon 	if (error == 0)
4608cd0a023SMatthew Dillon 		error = hammer_load_cursor_parent(cursor);
4618cd0a023SMatthew Dillon 	return(error);
4628cd0a023SMatthew Dillon }
4638cd0a023SMatthew Dillon 
4648cd0a023SMatthew Dillon /*
4658cd0a023SMatthew Dillon  * Cursor down through the current node, which must be an internal node.
4668cd0a023SMatthew Dillon  *
4678cd0a023SMatthew Dillon  * This routine adjusts the cursor and sets index to 0.
4688cd0a023SMatthew Dillon  */
4698cd0a023SMatthew Dillon int
4708cd0a023SMatthew Dillon hammer_cursor_down(hammer_cursor_t cursor)
4718cd0a023SMatthew Dillon {
4728cd0a023SMatthew Dillon 	hammer_node_t node;
4738cd0a023SMatthew Dillon 	hammer_btree_elm_t elm;
4748cd0a023SMatthew Dillon 	hammer_volume_t volume;
4758cd0a023SMatthew Dillon 	hammer_cluster_t cluster;
4768cd0a023SMatthew Dillon 	int32_t vol_no;
4778cd0a023SMatthew Dillon 	int32_t clu_no;
4788cd0a023SMatthew Dillon 	int error;
4798cd0a023SMatthew Dillon 
4808cd0a023SMatthew Dillon 	/*
4818cd0a023SMatthew Dillon 	 * The current node becomes the current parent
4828cd0a023SMatthew Dillon 	 */
4838cd0a023SMatthew Dillon 	node = cursor->node;
4848cd0a023SMatthew Dillon 	KKASSERT(node->ondisk->type == HAMMER_BTREE_TYPE_INTERNAL);
4858cd0a023SMatthew Dillon 	KKASSERT(cursor->index >= 0 && cursor->index < node->ondisk->count);
4868cd0a023SMatthew Dillon 	if (cursor->parent) {
4878cd0a023SMatthew Dillon 		hammer_unlock(&cursor->parent->lock);
4888cd0a023SMatthew Dillon 		hammer_rel_node(cursor->parent);
4898cd0a023SMatthew Dillon 	}
4908cd0a023SMatthew Dillon 	cursor->parent = node;
4918cd0a023SMatthew Dillon 	cursor->parent_index = cursor->index;
4928cd0a023SMatthew Dillon 	cursor->node = NULL;
4938cd0a023SMatthew Dillon 	cursor->index = 0;
4948cd0a023SMatthew Dillon 
4958cd0a023SMatthew Dillon 	/*
49676376933SMatthew Dillon 	 * Extract element to push into at (node,index), set bounds.
4978cd0a023SMatthew Dillon 	 */
4988cd0a023SMatthew Dillon 	elm = &node->ondisk->elms[cursor->parent_index];
49976376933SMatthew Dillon 	cursor->left_bound = &elm[0].internal.base;
50076376933SMatthew Dillon 	cursor->right_bound = &elm[1].internal.base;
5018cd0a023SMatthew Dillon 
5028cd0a023SMatthew Dillon 	/*
5038cd0a023SMatthew Dillon 	 * Ok, push down into elm.  If rec_offset is non-zero this is
5048cd0a023SMatthew Dillon 	 * an inter-cluster push, otherwise it is a intra-cluster push.
505*d26d0ae9SMatthew Dillon 	 *
506*d26d0ae9SMatthew Dillon 	 * Cursoring down through a cluster transition when the INCLUSTER
507*d26d0ae9SMatthew Dillon 	 * flag is set is not legal.
5088cd0a023SMatthew Dillon 	 */
5098cd0a023SMatthew Dillon 	if (elm->internal.rec_offset) {
510*d26d0ae9SMatthew Dillon 		KKASSERT((cursor->flags & HAMMER_CURSOR_INCLUSTER) == 0);
511*d26d0ae9SMatthew Dillon 		vol_no = elm->internal.subtree_vol_no;
512*d26d0ae9SMatthew Dillon 		clu_no = elm->internal.subtree_clu_no;
5138cd0a023SMatthew Dillon 		volume = hammer_get_volume(node->cluster->volume->hmp,
5148cd0a023SMatthew Dillon 					   vol_no, &error);
5158cd0a023SMatthew Dillon 		if (error)
5168cd0a023SMatthew Dillon 			return(error);
5178cd0a023SMatthew Dillon 		cluster = hammer_get_cluster(volume, clu_no, &error, 0);
5188cd0a023SMatthew Dillon 		hammer_rel_volume(volume, 0);
5198cd0a023SMatthew Dillon 		if (error)
5208cd0a023SMatthew Dillon 			return(error);
5218cd0a023SMatthew Dillon 		node = hammer_get_node(cluster,
5228cd0a023SMatthew Dillon 				       cluster->ondisk->clu_btree_root,
5238cd0a023SMatthew Dillon 				       &error);
5248cd0a023SMatthew Dillon 		hammer_rel_cluster(cluster, 0);
5258cd0a023SMatthew Dillon 	} else {
526*d26d0ae9SMatthew Dillon 		KKASSERT(elm->internal.subtree_offset != 0);
5278cd0a023SMatthew Dillon 		node = hammer_get_node(node->cluster,
5288cd0a023SMatthew Dillon 				       elm->internal.subtree_offset,
5298cd0a023SMatthew Dillon 				       &error);
530*d26d0ae9SMatthew Dillon 		if (error == 0) {
531*d26d0ae9SMatthew Dillon 			KKASSERT(elm->internal.subtree_type == node->ondisk->type);
532*d26d0ae9SMatthew Dillon 			KKASSERT(node->ondisk->parent == cursor->parent->node_offset);
533*d26d0ae9SMatthew Dillon 		}
5348cd0a023SMatthew Dillon 	}
5358cd0a023SMatthew Dillon 	if (error == 0) {
5368cd0a023SMatthew Dillon 		hammer_lock_ex(&node->lock);
5378cd0a023SMatthew Dillon 		cursor->node = node;
5388cd0a023SMatthew Dillon 		cursor->index = 0;
5398cd0a023SMatthew Dillon 	}
5408cd0a023SMatthew Dillon 	return(error);
5418cd0a023SMatthew Dillon }
5428cd0a023SMatthew Dillon 
543