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