13f01ebaaSMatthew Dillon /* 20d66a712SMatthew Dillon * Copyright (c) 2015-2017 The DragonFly Project. All rights reserved. 33f01ebaaSMatthew Dillon * 43f01ebaaSMatthew Dillon * This code is derived from software contributed to The DragonFly Project 53f01ebaaSMatthew Dillon * by Matthew Dillon <dillon@dragonflybsd.org> 63f01ebaaSMatthew Dillon * 73f01ebaaSMatthew Dillon * Redistribution and use in source and binary forms, with or without 83f01ebaaSMatthew Dillon * modification, are permitted provided that the following conditions 93f01ebaaSMatthew Dillon * are met: 103f01ebaaSMatthew Dillon * 113f01ebaaSMatthew Dillon * 1. Redistributions of source code must retain the above copyright 123f01ebaaSMatthew Dillon * notice, this list of conditions and the following disclaimer. 133f01ebaaSMatthew Dillon * 2. Redistributions in binary form must reproduce the above copyright 143f01ebaaSMatthew Dillon * notice, this list of conditions and the following disclaimer in 153f01ebaaSMatthew Dillon * the documentation and/or other materials provided with the 163f01ebaaSMatthew Dillon * distribution. 173f01ebaaSMatthew Dillon * 3. Neither the name of The DragonFly Project nor the names of its 183f01ebaaSMatthew Dillon * contributors may be used to endorse or promote products derived 193f01ebaaSMatthew Dillon * from this software without specific, prior written permission. 203f01ebaaSMatthew Dillon * 213f01ebaaSMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 223f01ebaaSMatthew Dillon * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 233f01ebaaSMatthew Dillon * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 243f01ebaaSMatthew Dillon * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 253f01ebaaSMatthew Dillon * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 263f01ebaaSMatthew Dillon * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 273f01ebaaSMatthew Dillon * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 283f01ebaaSMatthew Dillon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 293f01ebaaSMatthew Dillon * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 303f01ebaaSMatthew Dillon * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 313f01ebaaSMatthew Dillon * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 323f01ebaaSMatthew Dillon * SUCH DAMAGE. 333f01ebaaSMatthew Dillon */ 343f01ebaaSMatthew Dillon /* 353f01ebaaSMatthew Dillon * This module implements the cluster synchronizer. Basically the way 363f01ebaaSMatthew Dillon * it works is that a thread is created for each cluster node in a PFS. 373f01ebaaSMatthew Dillon * This thread is responsible for synchronizing the current node using 383f01ebaaSMatthew Dillon * data from other nodes. 393f01ebaaSMatthew Dillon * 403f01ebaaSMatthew Dillon * Any out of sync master or slave can get back into synchronization as 413f01ebaaSMatthew Dillon * long as a quorum of masters agree on the update_tid. If a quorum is 423f01ebaaSMatthew Dillon * not available it may still be possible to synchronize to the highest 433f01ebaaSMatthew Dillon * available update_tid as a way of trying to catch up as much as possible 443f01ebaaSMatthew Dillon * until a quorum is available. 453f01ebaaSMatthew Dillon * 463f01ebaaSMatthew Dillon * If no quorum is possible (which can happen even if all masters are 473f01ebaaSMatthew Dillon * available, if the update_tid does not match), then manual intervention 483f01ebaaSMatthew Dillon * may be required to resolve discrepancies. 493f01ebaaSMatthew Dillon */ 503f01ebaaSMatthew Dillon #include "hammer2.h" 513f01ebaaSMatthew Dillon 523f01ebaaSMatthew Dillon typedef struct hammer2_deferred_ip { 533f01ebaaSMatthew Dillon struct hammer2_deferred_ip *next; 543f01ebaaSMatthew Dillon hammer2_inode_t *ip; 553f01ebaaSMatthew Dillon } hammer2_deferred_ip_t; 563f01ebaaSMatthew Dillon 573f01ebaaSMatthew Dillon typedef struct hammer2_deferred_list { 583f01ebaaSMatthew Dillon hammer2_deferred_ip_t *base; 593f01ebaaSMatthew Dillon int count; 603f01ebaaSMatthew Dillon } hammer2_deferred_list_t; 613f01ebaaSMatthew Dillon 623f01ebaaSMatthew Dillon 633f01ebaaSMatthew Dillon #define HAMMER2_SYNCHRO_DEBUG 1 643f01ebaaSMatthew Dillon 653f01ebaaSMatthew Dillon static int hammer2_sync_slaves(hammer2_thread_t *thr, hammer2_inode_t *ip, 66b02c0ae6SMatthew Dillon hammer2_deferred_list_t *list, int isroot); 673f01ebaaSMatthew Dillon #if 0 683f01ebaaSMatthew Dillon static void hammer2_update_pfs_status(hammer2_thread_t *thr, uint32_t flags); 693f01ebaaSMatthew Dillon nerror = hammer2_sync_insert( 703f01ebaaSMatthew Dillon thr, &parent, &chain, 713f01ebaaSMatthew Dillon focus->bref.modify_tid, 723f01ebaaSMatthew Dillon idx, focus); 733f01ebaaSMatthew Dillon #endif 743f01ebaaSMatthew Dillon static int hammer2_sync_insert(hammer2_thread_t *thr, 753f01ebaaSMatthew Dillon hammer2_chain_t **parentp, hammer2_chain_t **chainp, 763f01ebaaSMatthew Dillon hammer2_tid_t modify_tid, int idx, 773f01ebaaSMatthew Dillon hammer2_chain_t *focus); 783f01ebaaSMatthew Dillon static int hammer2_sync_destroy(hammer2_thread_t *thr, 793f01ebaaSMatthew Dillon hammer2_chain_t **parentp, hammer2_chain_t **chainp, 803f01ebaaSMatthew Dillon hammer2_tid_t mtid, int idx); 813f01ebaaSMatthew Dillon static int hammer2_sync_replace(hammer2_thread_t *thr, 823f01ebaaSMatthew Dillon hammer2_chain_t *parent, hammer2_chain_t *chain, 833f01ebaaSMatthew Dillon hammer2_tid_t mtid, int idx, 84b02c0ae6SMatthew Dillon hammer2_chain_t *focus, int isroot); 853f01ebaaSMatthew Dillon 863f01ebaaSMatthew Dillon /**************************************************************************** 873f01ebaaSMatthew Dillon * HAMMER2 SYNC THREADS * 883f01ebaaSMatthew Dillon ****************************************************************************/ 893f01ebaaSMatthew Dillon /* 903f01ebaaSMatthew Dillon * Primary management thread for an element of a node. A thread will exist 913f01ebaaSMatthew Dillon * for each element requiring management. 923f01ebaaSMatthew Dillon * 933f01ebaaSMatthew Dillon * No management threads are needed for the SPMP or for any PMP with only 943f01ebaaSMatthew Dillon * a single MASTER. 953f01ebaaSMatthew Dillon * 963f01ebaaSMatthew Dillon * On the SPMP - handles bulkfree and dedup operations 973f01ebaaSMatthew Dillon * On a PFS - handles remastering and synchronization 983f01ebaaSMatthew Dillon */ 993f01ebaaSMatthew Dillon void 1003f01ebaaSMatthew Dillon hammer2_primary_sync_thread(void *arg) 1013f01ebaaSMatthew Dillon { 1023f01ebaaSMatthew Dillon hammer2_thread_t *thr = arg; 1033f01ebaaSMatthew Dillon hammer2_pfs_t *pmp; 1043f01ebaaSMatthew Dillon hammer2_deferred_list_t list; 1053f01ebaaSMatthew Dillon hammer2_deferred_ip_t *defer; 1063f01ebaaSMatthew Dillon int error; 107660d007eSMatthew Dillon uint32_t flags; 108660d007eSMatthew Dillon uint32_t nflags; 1093f01ebaaSMatthew Dillon 1103f01ebaaSMatthew Dillon pmp = thr->pmp; 1113f01ebaaSMatthew Dillon bzero(&list, sizeof(list)); 1123f01ebaaSMatthew Dillon 113660d007eSMatthew Dillon for (;;) { 114660d007eSMatthew Dillon flags = thr->flags; 115660d007eSMatthew Dillon cpu_ccfence(); 116660d007eSMatthew Dillon 117660d007eSMatthew Dillon /* 118660d007eSMatthew Dillon * Handle stop request 119660d007eSMatthew Dillon */ 120660d007eSMatthew Dillon if (flags & HAMMER2_THREAD_STOP) 121660d007eSMatthew Dillon break; 122660d007eSMatthew Dillon 1233f01ebaaSMatthew Dillon /* 1243f01ebaaSMatthew Dillon * Handle freeze request 1253f01ebaaSMatthew Dillon */ 126660d007eSMatthew Dillon if (flags & HAMMER2_THREAD_FREEZE) { 127660d007eSMatthew Dillon nflags = (flags & ~(HAMMER2_THREAD_FREEZE | 1289dca9515SMatthew Dillon HAMMER2_THREAD_WAITING)) | 129660d007eSMatthew Dillon HAMMER2_THREAD_FROZEN; 130660d007eSMatthew Dillon if (!atomic_cmpset_int(&thr->flags, flags, nflags)) 131660d007eSMatthew Dillon continue; 1329dca9515SMatthew Dillon if (flags & HAMMER2_THREAD_WAITING) 133660d007eSMatthew Dillon wakeup(&thr->flags); 13459eb0066SMatthew Dillon continue; 135660d007eSMatthew Dillon } 136660d007eSMatthew Dillon 137660d007eSMatthew Dillon if (flags & HAMMER2_THREAD_UNFREEZE) { 138660d007eSMatthew Dillon nflags = flags & ~(HAMMER2_THREAD_UNFREEZE | 139660d007eSMatthew Dillon HAMMER2_THREAD_FROZEN | 1409dca9515SMatthew Dillon HAMMER2_THREAD_WAITING); 141660d007eSMatthew Dillon if (!atomic_cmpset_int(&thr->flags, flags, nflags)) 142660d007eSMatthew Dillon continue; 1439dca9515SMatthew Dillon if (flags & HAMMER2_THREAD_WAITING) 144660d007eSMatthew Dillon wakeup(&thr->flags); 14559eb0066SMatthew Dillon continue; 1463f01ebaaSMatthew Dillon } 1473f01ebaaSMatthew Dillon 1483f01ebaaSMatthew Dillon /* 1493f01ebaaSMatthew Dillon * Force idle if frozen until unfrozen or stopped. 1503f01ebaaSMatthew Dillon */ 151660d007eSMatthew Dillon if (flags & HAMMER2_THREAD_FROZEN) { 152660d007eSMatthew Dillon nflags = flags | HAMMER2_THREAD_WAITING; 15359eb0066SMatthew Dillon 154660d007eSMatthew Dillon tsleep_interlock(&thr->flags, 0); 15559eb0066SMatthew Dillon if (atomic_cmpset_int(&thr->flags, flags, nflags)) 156660d007eSMatthew Dillon tsleep(&thr->flags, PINTERLOCKED, "frozen", 0); 1573f01ebaaSMatthew Dillon continue; 1583f01ebaaSMatthew Dillon } 1593f01ebaaSMatthew Dillon 1603f01ebaaSMatthew Dillon /* 1613f01ebaaSMatthew Dillon * Reset state on REMASTER request 1623f01ebaaSMatthew Dillon */ 1633f01ebaaSMatthew Dillon if (thr->flags & HAMMER2_THREAD_REMASTER) { 164660d007eSMatthew Dillon nflags = flags & ~HAMMER2_THREAD_REMASTER; 165660d007eSMatthew Dillon if (atomic_cmpset_int(&thr->flags, flags, nflags)) { 166660d007eSMatthew Dillon /* reset state here */ 167660d007eSMatthew Dillon } 168660d007eSMatthew Dillon continue; 1693f01ebaaSMatthew Dillon } 1703f01ebaaSMatthew Dillon 1713f01ebaaSMatthew Dillon /* 1723f01ebaaSMatthew Dillon * Synchronization scan. 1733f01ebaaSMatthew Dillon */ 1743cbe226bSMatthew Dillon if (hammer2_debug & 0x8000) 1753f01ebaaSMatthew Dillon kprintf("sync_slaves pfs %s clindex %d\n", 1763f01ebaaSMatthew Dillon pmp->pfs_names[thr->clindex], thr->clindex); 1773f01ebaaSMatthew Dillon hammer2_trans_init(pmp, 0); 1783f01ebaaSMatthew Dillon 1793f01ebaaSMatthew Dillon hammer2_inode_ref(pmp->iroot); 1803f01ebaaSMatthew Dillon 1813f01ebaaSMatthew Dillon for (;;) { 1823f01ebaaSMatthew Dillon int didbreak = 0; 1833f01ebaaSMatthew Dillon /* XXX lock synchronize pmp->modify_tid */ 184b02c0ae6SMatthew Dillon error = hammer2_sync_slaves(thr, pmp->iroot, &list, 1); 185b02c0ae6SMatthew Dillon if (hammer2_debug & 0x8000) { 186b02c0ae6SMatthew Dillon kprintf("sync_slaves error %d defer %p\n", 187b02c0ae6SMatthew Dillon error, list.base); 188b02c0ae6SMatthew Dillon } 1893f01ebaaSMatthew Dillon if (error != EAGAIN) 1903f01ebaaSMatthew Dillon break; 1913f01ebaaSMatthew Dillon while ((defer = list.base) != NULL) { 1923f01ebaaSMatthew Dillon hammer2_inode_t *nip; 1933f01ebaaSMatthew Dillon 1943f01ebaaSMatthew Dillon nip = defer->ip; 1950d66a712SMatthew Dillon error = hammer2_sync_slaves(thr, nip, &list, 1960d66a712SMatthew Dillon (nip == pmp->iroot)); 197b02c0ae6SMatthew Dillon if (error && error != EAGAIN && error != ENOENT) 1983f01ebaaSMatthew Dillon break; 1993f01ebaaSMatthew Dillon if (hammer2_thr_break(thr)) { 2003f01ebaaSMatthew Dillon didbreak = 1; 2013f01ebaaSMatthew Dillon break; 2023f01ebaaSMatthew Dillon } 2033f01ebaaSMatthew Dillon 2043f01ebaaSMatthew Dillon /* 2053f01ebaaSMatthew Dillon * If no additional defers occurred we can 206b02c0ae6SMatthew Dillon * remove this one, otherwise keep it on 2073f01ebaaSMatthew Dillon * the list and retry once the additional 2083f01ebaaSMatthew Dillon * defers have completed. 2093f01ebaaSMatthew Dillon */ 2103f01ebaaSMatthew Dillon if (defer == list.base) { 2113f01ebaaSMatthew Dillon --list.count; 2123f01ebaaSMatthew Dillon list.base = defer->next; 2133f01ebaaSMatthew Dillon kfree(defer, M_HAMMER2); 2143f01ebaaSMatthew Dillon defer = NULL; /* safety */ 2153f01ebaaSMatthew Dillon hammer2_inode_drop(nip); 2163f01ebaaSMatthew Dillon } 2173f01ebaaSMatthew Dillon } 2183f01ebaaSMatthew Dillon 2193f01ebaaSMatthew Dillon /* 2203f01ebaaSMatthew Dillon * If the thread is being remastered, frozen, or 2213f01ebaaSMatthew Dillon * stopped, clean up any left-over deferals. 2223f01ebaaSMatthew Dillon */ 2233f01ebaaSMatthew Dillon if (didbreak || (error && error != EAGAIN)) { 2243f01ebaaSMatthew Dillon kprintf("didbreak\n"); 2253f01ebaaSMatthew Dillon while ((defer = list.base) != NULL) { 2263f01ebaaSMatthew Dillon --list.count; 2273f01ebaaSMatthew Dillon hammer2_inode_drop(defer->ip); 2283f01ebaaSMatthew Dillon list.base = defer->next; 2293f01ebaaSMatthew Dillon kfree(defer, M_HAMMER2); 2303f01ebaaSMatthew Dillon } 2313f01ebaaSMatthew Dillon if (error == 0 || error == EAGAIN) 2323f01ebaaSMatthew Dillon error = EINPROGRESS; 2333f01ebaaSMatthew Dillon break; 2343f01ebaaSMatthew Dillon } 2353f01ebaaSMatthew Dillon } 2363f01ebaaSMatthew Dillon 2373f01ebaaSMatthew Dillon hammer2_inode_drop(pmp->iroot); 2383f01ebaaSMatthew Dillon hammer2_trans_done(pmp); 2393f01ebaaSMatthew Dillon 2403cbe226bSMatthew Dillon if (error && error != EINPROGRESS) 2413f01ebaaSMatthew Dillon kprintf("hammer2_sync_slaves: error %d\n", error); 2423f01ebaaSMatthew Dillon 2433f01ebaaSMatthew Dillon /* 2443f01ebaaSMatthew Dillon * Wait for event, or 5-second poll. 2453f01ebaaSMatthew Dillon */ 246660d007eSMatthew Dillon nflags = flags | HAMMER2_THREAD_WAITING; 247660d007eSMatthew Dillon tsleep_interlock(&thr->flags, 0); 248660d007eSMatthew Dillon if (atomic_cmpset_int(&thr->flags, flags, nflags)) { 249660d007eSMatthew Dillon tsleep(&thr->flags, 0, "h2idle", hz * 5); 250660d007eSMatthew Dillon } 2513f01ebaaSMatthew Dillon } 2523f01ebaaSMatthew Dillon thr->td = NULL; 2539dca9515SMatthew Dillon hammer2_thr_signal(thr, HAMMER2_THREAD_STOPPED); 2543f01ebaaSMatthew Dillon /* thr structure can go invalid after this point */ 2553f01ebaaSMatthew Dillon } 2563f01ebaaSMatthew Dillon 2573f01ebaaSMatthew Dillon #if 0 2583f01ebaaSMatthew Dillon /* 2593f01ebaaSMatthew Dillon * Given a locked cluster created from pmp->iroot, update the PFS's 2603f01ebaaSMatthew Dillon * reporting status. 2613f01ebaaSMatthew Dillon */ 2623f01ebaaSMatthew Dillon static 2633f01ebaaSMatthew Dillon void 2643f01ebaaSMatthew Dillon hammer2_update_pfs_status(hammer2_thread_t *thr, uint32_t flags) 2653f01ebaaSMatthew Dillon { 2663f01ebaaSMatthew Dillon hammer2_pfs_t *pmp = thr->pmp; 2673f01ebaaSMatthew Dillon 2683f01ebaaSMatthew Dillon flags &= HAMMER2_CLUSTER_ZFLAGS; 2693f01ebaaSMatthew Dillon if (pmp->cluster_flags == flags) 2703f01ebaaSMatthew Dillon return; 2713f01ebaaSMatthew Dillon pmp->cluster_flags = flags; 2723f01ebaaSMatthew Dillon 2733f01ebaaSMatthew Dillon kprintf("pfs %p", pmp); 2743f01ebaaSMatthew Dillon if (flags & HAMMER2_CLUSTER_MSYNCED) 2753f01ebaaSMatthew Dillon kprintf(" masters-all-good"); 2763f01ebaaSMatthew Dillon if (flags & HAMMER2_CLUSTER_SSYNCED) 2773f01ebaaSMatthew Dillon kprintf(" slaves-all-good"); 2783f01ebaaSMatthew Dillon 2793f01ebaaSMatthew Dillon if (flags & HAMMER2_CLUSTER_WRHARD) 2803f01ebaaSMatthew Dillon kprintf(" quorum/rw"); 2813f01ebaaSMatthew Dillon else if (flags & HAMMER2_CLUSTER_RDHARD) 2823f01ebaaSMatthew Dillon kprintf(" quorum/ro"); 2833f01ebaaSMatthew Dillon 2843f01ebaaSMatthew Dillon if (flags & HAMMER2_CLUSTER_UNHARD) 2853f01ebaaSMatthew Dillon kprintf(" out-of-sync-masters"); 2863f01ebaaSMatthew Dillon else if (flags & HAMMER2_CLUSTER_NOHARD) 2873f01ebaaSMatthew Dillon kprintf(" no-masters-visible"); 2883f01ebaaSMatthew Dillon 2893f01ebaaSMatthew Dillon if (flags & HAMMER2_CLUSTER_WRSOFT) 2903f01ebaaSMatthew Dillon kprintf(" soft/rw"); 2913f01ebaaSMatthew Dillon else if (flags & HAMMER2_CLUSTER_RDSOFT) 2923f01ebaaSMatthew Dillon kprintf(" soft/ro"); 2933f01ebaaSMatthew Dillon 2943f01ebaaSMatthew Dillon if (flags & HAMMER2_CLUSTER_UNSOFT) 2953f01ebaaSMatthew Dillon kprintf(" out-of-sync-slaves"); 2963f01ebaaSMatthew Dillon else if (flags & HAMMER2_CLUSTER_NOSOFT) 2973f01ebaaSMatthew Dillon kprintf(" no-slaves-visible"); 2983f01ebaaSMatthew Dillon kprintf("\n"); 2993f01ebaaSMatthew Dillon } 3003f01ebaaSMatthew Dillon #endif 3013f01ebaaSMatthew Dillon 3023f01ebaaSMatthew Dillon #if 0 3033f01ebaaSMatthew Dillon static 3043f01ebaaSMatthew Dillon void 3053f01ebaaSMatthew Dillon dumpcluster(const char *label, 3063f01ebaaSMatthew Dillon hammer2_cluster_t *cparent, hammer2_cluster_t *cluster) 3073f01ebaaSMatthew Dillon { 3083f01ebaaSMatthew Dillon hammer2_chain_t *chain; 3093f01ebaaSMatthew Dillon int i; 3103f01ebaaSMatthew Dillon 3113f01ebaaSMatthew Dillon if ((hammer2_debug & 1) == 0) 3123f01ebaaSMatthew Dillon return; 3133f01ebaaSMatthew Dillon 3143f01ebaaSMatthew Dillon kprintf("%s\t", label); 3153f01ebaaSMatthew Dillon KKASSERT(cparent->nchains == cluster->nchains); 3163f01ebaaSMatthew Dillon for (i = 0; i < cparent->nchains; ++i) { 3173f01ebaaSMatthew Dillon if (i) 3183f01ebaaSMatthew Dillon kprintf("\t"); 3193f01ebaaSMatthew Dillon kprintf("%d ", i); 3203f01ebaaSMatthew Dillon if ((chain = cparent->array[i].chain) != NULL) { 3213f01ebaaSMatthew Dillon kprintf("%016jx%s ", 3223f01ebaaSMatthew Dillon chain->bref.key, 3233f01ebaaSMatthew Dillon ((cparent->array[i].flags & 3243f01ebaaSMatthew Dillon HAMMER2_CITEM_INVALID) ? "(I)" : " ") 3253f01ebaaSMatthew Dillon ); 3263f01ebaaSMatthew Dillon } else { 3273f01ebaaSMatthew Dillon kprintf(" NULL %s ", " "); 3283f01ebaaSMatthew Dillon } 3293f01ebaaSMatthew Dillon if ((chain = cluster->array[i].chain) != NULL) { 3303f01ebaaSMatthew Dillon kprintf("%016jx%s ", 3313f01ebaaSMatthew Dillon chain->bref.key, 3323f01ebaaSMatthew Dillon ((cluster->array[i].flags & 3333f01ebaaSMatthew Dillon HAMMER2_CITEM_INVALID) ? "(I)" : " ") 3343f01ebaaSMatthew Dillon ); 3353f01ebaaSMatthew Dillon } else { 3363f01ebaaSMatthew Dillon kprintf(" NULL %s ", " "); 3373f01ebaaSMatthew Dillon } 3383f01ebaaSMatthew Dillon kprintf("\n"); 3393f01ebaaSMatthew Dillon } 3403f01ebaaSMatthew Dillon } 3413f01ebaaSMatthew Dillon #endif 3423f01ebaaSMatthew Dillon 3433f01ebaaSMatthew Dillon /* 3443f01ebaaSMatthew Dillon * Each out of sync node sync-thread must issue an all-nodes XOP scan of 3453f01ebaaSMatthew Dillon * the inode. This creates a multiplication effect since the XOP scan itself 3463f01ebaaSMatthew Dillon * issues to all nodes. However, this is the only way we can safely 3473f01ebaaSMatthew Dillon * synchronize nodes which might have disparate I/O bandwidths and the only 3483f01ebaaSMatthew Dillon * way we can safely deal with stalled nodes. 349*c8c0a18aSMatthew Dillon * 350*c8c0a18aSMatthew Dillon * XXX serror / merror rollup and handling. 3513f01ebaaSMatthew Dillon */ 3523f01ebaaSMatthew Dillon static 3533f01ebaaSMatthew Dillon int 3543f01ebaaSMatthew Dillon hammer2_sync_slaves(hammer2_thread_t *thr, hammer2_inode_t *ip, 355b02c0ae6SMatthew Dillon hammer2_deferred_list_t *list, int isroot) 3563f01ebaaSMatthew Dillon { 3573f01ebaaSMatthew Dillon hammer2_xop_scanall_t *xop; 3583f01ebaaSMatthew Dillon hammer2_chain_t *parent; 3593f01ebaaSMatthew Dillon hammer2_chain_t *chain; 3603f01ebaaSMatthew Dillon hammer2_pfs_t *pmp; 3613f01ebaaSMatthew Dillon hammer2_key_t key_next; 3623f01ebaaSMatthew Dillon hammer2_tid_t sync_tid; 3633f01ebaaSMatthew Dillon int needrescan; 364b02c0ae6SMatthew Dillon int want_update; 365*c8c0a18aSMatthew Dillon int serror; /* slave error */ 366*c8c0a18aSMatthew Dillon int merror; /* master error (from xop_collect) */ 367*c8c0a18aSMatthew Dillon int nerror; /* temporary error */ 3683f01ebaaSMatthew Dillon int idx; 3693f01ebaaSMatthew Dillon int n; 3703f01ebaaSMatthew Dillon 3713f01ebaaSMatthew Dillon pmp = ip->pmp; 3723f01ebaaSMatthew Dillon idx = thr->clindex; /* cluster node we are responsible for */ 3733f01ebaaSMatthew Dillon needrescan = 0; 374b02c0ae6SMatthew Dillon want_update = 0; 375b02c0ae6SMatthew Dillon sync_tid = 0; 376b02c0ae6SMatthew Dillon chain = NULL; 377b02c0ae6SMatthew Dillon parent = NULL; 3783f01ebaaSMatthew Dillon 3793f01ebaaSMatthew Dillon #if 0 3803f01ebaaSMatthew Dillon /* 3813f01ebaaSMatthew Dillon * Nothing to do if all slaves are synchronized. 3823f01ebaaSMatthew Dillon * Nothing to do if cluster not authoritatively readable. 3833f01ebaaSMatthew Dillon */ 3843f01ebaaSMatthew Dillon if (pmp->cluster_flags & HAMMER2_CLUSTER_SSYNCED) 3853f01ebaaSMatthew Dillon return(0); 3863f01ebaaSMatthew Dillon if ((pmp->cluster_flags & HAMMER2_CLUSTER_RDHARD) == 0) 3873f01ebaaSMatthew Dillon return(HAMMER2_ERROR_INCOMPLETE); 3883f01ebaaSMatthew Dillon #endif 3893f01ebaaSMatthew Dillon 390*c8c0a18aSMatthew Dillon merror = 0; 3913f01ebaaSMatthew Dillon 3923f01ebaaSMatthew Dillon /* 393b02c0ae6SMatthew Dillon * Resolve the root inode of the PFS and determine if synchronization 394b02c0ae6SMatthew Dillon * is needed by checking modify_tid. 3950d66a712SMatthew Dillon * 3960d66a712SMatthew Dillon * Retain the synchronization TID from the focus inode and use it 3970d66a712SMatthew Dillon * later to synchronize the focus inode if/when the recursion 3980d66a712SMatthew Dillon * succeeds. 399b02c0ae6SMatthew Dillon */ 400b02c0ae6SMatthew Dillon { 401b02c0ae6SMatthew Dillon hammer2_xop_ipcluster_t *xop2; 402b02c0ae6SMatthew Dillon hammer2_chain_t *focus; 403b02c0ae6SMatthew Dillon 404b02c0ae6SMatthew Dillon hammer2_inode_lock(ip, HAMMER2_RESOLVE_SHARED); 405b02c0ae6SMatthew Dillon xop2 = hammer2_xop_alloc(ip, HAMMER2_XOP_MODIFYING); 406b02c0ae6SMatthew Dillon hammer2_xop_start_except(&xop2->head, hammer2_xop_ipcluster, 407b02c0ae6SMatthew Dillon idx); 408b02c0ae6SMatthew Dillon hammer2_inode_unlock(ip); 409*c8c0a18aSMatthew Dillon merror = hammer2_xop_collect(&xop2->head, 0); 410*c8c0a18aSMatthew Dillon if (merror == 0 && (focus = xop2->head.cluster.focus) != NULL) { 4110d66a712SMatthew Dillon sync_tid = focus->bref.modify_tid; 412b02c0ae6SMatthew Dillon chain = hammer2_inode_chain_and_parent(ip, idx, 413b02c0ae6SMatthew Dillon &parent, 414b02c0ae6SMatthew Dillon HAMMER2_RESOLVE_ALWAYS | 415b02c0ae6SMatthew Dillon HAMMER2_RESOLVE_SHARED); 416b02c0ae6SMatthew Dillon want_update = (chain->bref.modify_tid != sync_tid); 417b02c0ae6SMatthew Dillon if (chain) { 418b02c0ae6SMatthew Dillon hammer2_chain_unlock(chain); 419b02c0ae6SMatthew Dillon hammer2_chain_drop(chain); 420b02c0ae6SMatthew Dillon chain = NULL; 421b02c0ae6SMatthew Dillon } 422b02c0ae6SMatthew Dillon if (parent) { 423b02c0ae6SMatthew Dillon hammer2_chain_unlock(parent); 424b02c0ae6SMatthew Dillon hammer2_chain_drop(parent); 425b02c0ae6SMatthew Dillon parent = NULL; 426b02c0ae6SMatthew Dillon } 427b02c0ae6SMatthew Dillon } 428b02c0ae6SMatthew Dillon hammer2_xop_retire(&xop2->head, HAMMER2_XOPMASK_VOP); 429b02c0ae6SMatthew Dillon } 430b02c0ae6SMatthew Dillon 431b02c0ae6SMatthew Dillon if (want_update == 0) 432b02c0ae6SMatthew Dillon return(0); 433b02c0ae6SMatthew Dillon 434b02c0ae6SMatthew Dillon /* 4353f01ebaaSMatthew Dillon * The inode is left unlocked during the scan. Issue a XOP 4363f01ebaaSMatthew Dillon * that does *not* include our cluster index to iterate 4373f01ebaaSMatthew Dillon * properly synchronized elements and resolve our cluster index 4383f01ebaaSMatthew Dillon * against it. 4393f01ebaaSMatthew Dillon */ 4403f01ebaaSMatthew Dillon hammer2_inode_lock(ip, HAMMER2_RESOLVE_SHARED); 4413f01ebaaSMatthew Dillon xop = hammer2_xop_alloc(ip, HAMMER2_XOP_MODIFYING); 4423f01ebaaSMatthew Dillon xop->key_beg = HAMMER2_KEY_MIN; 4433f01ebaaSMatthew Dillon xop->key_end = HAMMER2_KEY_MAX; 444b02c0ae6SMatthew Dillon xop->resolve_flags = HAMMER2_RESOLVE_SHARED | 445b02c0ae6SMatthew Dillon HAMMER2_RESOLVE_ALWAYS; 446b02c0ae6SMatthew Dillon xop->lookup_flags = HAMMER2_LOOKUP_SHARED | 447b02c0ae6SMatthew Dillon HAMMER2_LOOKUP_NODIRECT | 448b02c0ae6SMatthew Dillon HAMMER2_LOOKUP_ALWAYS; 4493f01ebaaSMatthew Dillon hammer2_xop_start_except(&xop->head, hammer2_xop_scanall, idx); 4503f01ebaaSMatthew Dillon parent = hammer2_inode_chain(ip, idx, 4513f01ebaaSMatthew Dillon HAMMER2_RESOLVE_ALWAYS | 4523f01ebaaSMatthew Dillon HAMMER2_RESOLVE_SHARED); 4533f01ebaaSMatthew Dillon hammer2_inode_unlock(ip); 4543f01ebaaSMatthew Dillon 4553f01ebaaSMatthew Dillon chain = hammer2_chain_lookup(&parent, &key_next, 4563f01ebaaSMatthew Dillon HAMMER2_KEY_MIN, HAMMER2_KEY_MAX, 457*c8c0a18aSMatthew Dillon &serror, 4583f01ebaaSMatthew Dillon HAMMER2_LOOKUP_SHARED | 4593f01ebaaSMatthew Dillon HAMMER2_LOOKUP_NODIRECT | 4603f01ebaaSMatthew Dillon HAMMER2_LOOKUP_NODATA); 461*c8c0a18aSMatthew Dillon serror = hammer2_error_to_errno(serror); 462*c8c0a18aSMatthew Dillon merror = hammer2_xop_collect(&xop->head, 0); 4630d66a712SMatthew Dillon if (hammer2_debug & 0x8000) { 464b02c0ae6SMatthew Dillon kprintf("START_SCAN IP=%016jx chain=%p (%016jx)\n", 465b02c0ae6SMatthew Dillon ip->meta.name_key, chain, 466b02c0ae6SMatthew Dillon (chain ? chain->bref.key : -1)); 4670d66a712SMatthew Dillon } 4683f01ebaaSMatthew Dillon 4693f01ebaaSMatthew Dillon for (;;) { 4703f01ebaaSMatthew Dillon /* 4713f01ebaaSMatthew Dillon * We are done if our scan is done and the XOP scan is done. 4723f01ebaaSMatthew Dillon * We are done if the XOP scan failed (that is, we don't 4733f01ebaaSMatthew Dillon * have authoritative data to synchronize with). 4743f01ebaaSMatthew Dillon */ 4753f01ebaaSMatthew Dillon int advance_local = 0; 4763f01ebaaSMatthew Dillon int advance_xop = 0; 4773f01ebaaSMatthew Dillon int dodefer = 0; 4783f01ebaaSMatthew Dillon hammer2_chain_t *focus; 4793f01ebaaSMatthew Dillon 480*c8c0a18aSMatthew Dillon if (chain == NULL && merror == ENOENT) 4813f01ebaaSMatthew Dillon break; 482*c8c0a18aSMatthew Dillon if (merror && merror != ENOENT) 4833f01ebaaSMatthew Dillon break; 4843f01ebaaSMatthew Dillon 4853f01ebaaSMatthew Dillon /* 4863f01ebaaSMatthew Dillon * Compare 4873f01ebaaSMatthew Dillon */ 488*c8c0a18aSMatthew Dillon if (chain && merror == ENOENT) { 4893f01ebaaSMatthew Dillon /* 4903f01ebaaSMatthew Dillon * If we have local chains but the XOP scan is done, 4913f01ebaaSMatthew Dillon * the chains need to be deleted. 4923f01ebaaSMatthew Dillon */ 4933f01ebaaSMatthew Dillon n = -1; 4943f01ebaaSMatthew Dillon focus = NULL; 4953f01ebaaSMatthew Dillon } else if (chain == NULL) { 4963f01ebaaSMatthew Dillon /* 4973f01ebaaSMatthew Dillon * If our local scan is done but the XOP scan is not, 4983f01ebaaSMatthew Dillon * we need to create the missing chain(s). 4993f01ebaaSMatthew Dillon */ 5003f01ebaaSMatthew Dillon n = 1; 5013f01ebaaSMatthew Dillon focus = xop->head.cluster.focus; 5023f01ebaaSMatthew Dillon } else { 5033f01ebaaSMatthew Dillon /* 5043f01ebaaSMatthew Dillon * Otherwise compare to determine the action 5053f01ebaaSMatthew Dillon * needed. 5063f01ebaaSMatthew Dillon */ 5073f01ebaaSMatthew Dillon focus = xop->head.cluster.focus; 5083f01ebaaSMatthew Dillon n = hammer2_chain_cmp(chain, focus); 5093f01ebaaSMatthew Dillon } 5103f01ebaaSMatthew Dillon 5113f01ebaaSMatthew Dillon /* 5123f01ebaaSMatthew Dillon * Take action based on comparison results. 5133f01ebaaSMatthew Dillon */ 5143f01ebaaSMatthew Dillon if (n < 0) { 5153f01ebaaSMatthew Dillon /* 5163f01ebaaSMatthew Dillon * Delete extranious local data. This will 5173f01ebaaSMatthew Dillon * automatically advance the chain. 5183f01ebaaSMatthew Dillon */ 5193f01ebaaSMatthew Dillon nerror = hammer2_sync_destroy(thr, &parent, &chain, 5203f01ebaaSMatthew Dillon 0, idx); 5213f01ebaaSMatthew Dillon } else if (n == 0 && chain->bref.modify_tid != 5223f01ebaaSMatthew Dillon focus->bref.modify_tid) { 5233f01ebaaSMatthew Dillon /* 5243f01ebaaSMatthew Dillon * Matching key but local data or meta-data requires 5253f01ebaaSMatthew Dillon * updating. If we will recurse, we still need to 5263f01ebaaSMatthew Dillon * update to compatible content first but we do not 5273f01ebaaSMatthew Dillon * synchronize modify_tid until the entire recursion 5283f01ebaaSMatthew Dillon * has completed successfully. 5293f01ebaaSMatthew Dillon */ 530da0cdd33SMatthew Dillon if (focus->bref.type == HAMMER2_BREF_TYPE_INODE) { 5313f01ebaaSMatthew Dillon nerror = hammer2_sync_replace( 5323f01ebaaSMatthew Dillon thr, parent, chain, 5333f01ebaaSMatthew Dillon 0, 534b02c0ae6SMatthew Dillon idx, focus, 0); 5353f01ebaaSMatthew Dillon dodefer = 1; 5363f01ebaaSMatthew Dillon } else { 5373f01ebaaSMatthew Dillon nerror = hammer2_sync_replace( 5383f01ebaaSMatthew Dillon thr, parent, chain, 5393f01ebaaSMatthew Dillon focus->bref.modify_tid, 540b02c0ae6SMatthew Dillon idx, focus, 0); 5413f01ebaaSMatthew Dillon } 542b02c0ae6SMatthew Dillon advance_local = 1; 543b02c0ae6SMatthew Dillon advance_xop = 1; 5443f01ebaaSMatthew Dillon } else if (n == 0) { 5453f01ebaaSMatthew Dillon /* 5463f01ebaaSMatthew Dillon * 100% match, advance both 5473f01ebaaSMatthew Dillon */ 5483f01ebaaSMatthew Dillon advance_local = 1; 5493f01ebaaSMatthew Dillon advance_xop = 1; 5503f01ebaaSMatthew Dillon nerror = 0; 5513f01ebaaSMatthew Dillon } else if (n > 0) { 5523f01ebaaSMatthew Dillon /* 5533f01ebaaSMatthew Dillon * Insert missing local data. 5543f01ebaaSMatthew Dillon * 5553f01ebaaSMatthew Dillon * If we will recurse, we still need to update to 5563f01ebaaSMatthew Dillon * compatible content first but we do not synchronize 5573f01ebaaSMatthew Dillon * modify_tid until the entire recursion has 5583f01ebaaSMatthew Dillon * completed successfully. 5593f01ebaaSMatthew Dillon */ 560da0cdd33SMatthew Dillon if (focus->bref.type == HAMMER2_BREF_TYPE_INODE) { 5613f01ebaaSMatthew Dillon nerror = hammer2_sync_insert( 5623f01ebaaSMatthew Dillon thr, &parent, &chain, 5633f01ebaaSMatthew Dillon 0, 5643f01ebaaSMatthew Dillon idx, focus); 5653f01ebaaSMatthew Dillon dodefer = 2; 5663f01ebaaSMatthew Dillon } else { 5673f01ebaaSMatthew Dillon nerror = hammer2_sync_insert( 5683f01ebaaSMatthew Dillon thr, &parent, &chain, 5693f01ebaaSMatthew Dillon focus->bref.modify_tid, 5703f01ebaaSMatthew Dillon idx, focus); 5713f01ebaaSMatthew Dillon } 5723f01ebaaSMatthew Dillon advance_local = 1; 5733f01ebaaSMatthew Dillon advance_xop = 1; 5743f01ebaaSMatthew Dillon } 5753f01ebaaSMatthew Dillon 5763f01ebaaSMatthew Dillon /* 5773f01ebaaSMatthew Dillon * We cannot recurse depth-first because the XOP is still 5783f01ebaaSMatthew Dillon * running in node threads for this scan. Create a placemarker 5793f01ebaaSMatthew Dillon * by obtaining and record the hammer2_inode. 5803f01ebaaSMatthew Dillon * 5813f01ebaaSMatthew Dillon * We excluded our node from the XOP so we must temporarily 5823f01ebaaSMatthew Dillon * add it to xop->head.cluster so it is properly incorporated 5833f01ebaaSMatthew Dillon * into the inode. 5843f01ebaaSMatthew Dillon * 5853f01ebaaSMatthew Dillon * The deferral is pushed onto a LIFO list for bottom-up 5863f01ebaaSMatthew Dillon * synchronization. 5873f01ebaaSMatthew Dillon */ 588*c8c0a18aSMatthew Dillon if (merror == 0 && dodefer) { 5893f01ebaaSMatthew Dillon hammer2_inode_t *nip; 5903f01ebaaSMatthew Dillon hammer2_deferred_ip_t *defer; 5913f01ebaaSMatthew Dillon 5923f01ebaaSMatthew Dillon KKASSERT(focus->bref.type == HAMMER2_BREF_TYPE_INODE); 5933f01ebaaSMatthew Dillon 5943f01ebaaSMatthew Dillon defer = kmalloc(sizeof(*defer), M_HAMMER2, 5953f01ebaaSMatthew Dillon M_WAITOK | M_ZERO); 5963f01ebaaSMatthew Dillon KKASSERT(xop->head.cluster.array[idx].chain == NULL); 5973f01ebaaSMatthew Dillon xop->head.cluster.array[idx].flags = 5983f01ebaaSMatthew Dillon HAMMER2_CITEM_INVALID; 5993f01ebaaSMatthew Dillon xop->head.cluster.array[idx].chain = chain; 6003f01ebaaSMatthew Dillon nip = hammer2_inode_get(pmp, ip, 6013f01ebaaSMatthew Dillon &xop->head.cluster, idx); 6023f01ebaaSMatthew Dillon xop->head.cluster.array[idx].chain = NULL; 6033f01ebaaSMatthew Dillon 6043f01ebaaSMatthew Dillon hammer2_inode_ref(nip); 6053f01ebaaSMatthew Dillon hammer2_inode_unlock(nip); 6063f01ebaaSMatthew Dillon 6073f01ebaaSMatthew Dillon defer->next = list->base; 6083f01ebaaSMatthew Dillon defer->ip = nip; 6093f01ebaaSMatthew Dillon list->base = defer; 6103f01ebaaSMatthew Dillon ++list->count; 6113f01ebaaSMatthew Dillon needrescan = 1; 6123f01ebaaSMatthew Dillon } 6133f01ebaaSMatthew Dillon 6143f01ebaaSMatthew Dillon /* 6153f01ebaaSMatthew Dillon * If at least one deferral was added and the deferral 6163f01ebaaSMatthew Dillon * list has grown too large, stop adding more. This 6173f01ebaaSMatthew Dillon * will trigger an EAGAIN return. 6183f01ebaaSMatthew Dillon */ 6193f01ebaaSMatthew Dillon if (needrescan && list->count > 1000) 6203f01ebaaSMatthew Dillon break; 6213f01ebaaSMatthew Dillon 6223f01ebaaSMatthew Dillon /* 6233f01ebaaSMatthew Dillon * Advancements for iteration. 6243f01ebaaSMatthew Dillon */ 6253f01ebaaSMatthew Dillon if (advance_xop) { 626*c8c0a18aSMatthew Dillon merror = hammer2_xop_collect(&xop->head, 0); 6273f01ebaaSMatthew Dillon } 6283f01ebaaSMatthew Dillon if (advance_local) { 6293f01ebaaSMatthew Dillon chain = hammer2_chain_next(&parent, chain, &key_next, 6303f01ebaaSMatthew Dillon key_next, HAMMER2_KEY_MAX, 631*c8c0a18aSMatthew Dillon &serror, 6323f01ebaaSMatthew Dillon HAMMER2_LOOKUP_SHARED | 6333f01ebaaSMatthew Dillon HAMMER2_LOOKUP_NODIRECT | 6343f01ebaaSMatthew Dillon HAMMER2_LOOKUP_NODATA); 635*c8c0a18aSMatthew Dillon serror = hammer2_error_to_errno(serror); 6363f01ebaaSMatthew Dillon } 6373f01ebaaSMatthew Dillon } 6383f01ebaaSMatthew Dillon hammer2_xop_retire(&xop->head, HAMMER2_XOPMASK_VOP); 6393f01ebaaSMatthew Dillon if (chain) { 6403f01ebaaSMatthew Dillon hammer2_chain_unlock(chain); 6413f01ebaaSMatthew Dillon hammer2_chain_drop(chain); 6423f01ebaaSMatthew Dillon } 6433f01ebaaSMatthew Dillon if (parent) { 6443f01ebaaSMatthew Dillon hammer2_chain_unlock(parent); 6453f01ebaaSMatthew Dillon hammer2_chain_drop(parent); 6463f01ebaaSMatthew Dillon } 6473f01ebaaSMatthew Dillon 6483f01ebaaSMatthew Dillon /* 6493f01ebaaSMatthew Dillon * If we added deferrals we want the caller to synchronize them 6503f01ebaaSMatthew Dillon * and then call us again. 6513f01ebaaSMatthew Dillon * 6523f01ebaaSMatthew Dillon * NOTE: In this situation we do not yet want to synchronize our 6533f01ebaaSMatthew Dillon * inode, setting the error code also has that effect. 6543f01ebaaSMatthew Dillon */ 655*c8c0a18aSMatthew Dillon if ((merror == 0 || merror == ENOENT) && needrescan) 656*c8c0a18aSMatthew Dillon merror = EAGAIN; 6573f01ebaaSMatthew Dillon 6583f01ebaaSMatthew Dillon /* 659b02c0ae6SMatthew Dillon * If no error occurred we can synchronize the inode meta-data 660b02c0ae6SMatthew Dillon * and modify_tid. Only limited changes are made to PFSROOTs. 6613f01ebaaSMatthew Dillon * 6623f01ebaaSMatthew Dillon * XXX inode lock was lost 6633f01ebaaSMatthew Dillon */ 664*c8c0a18aSMatthew Dillon if (merror == 0 || merror == ENOENT) { 6653f01ebaaSMatthew Dillon hammer2_xop_ipcluster_t *xop2; 6663f01ebaaSMatthew Dillon hammer2_chain_t *focus; 6673f01ebaaSMatthew Dillon 668b02c0ae6SMatthew Dillon hammer2_inode_lock(ip, HAMMER2_RESOLVE_SHARED); 6693f01ebaaSMatthew Dillon xop2 = hammer2_xop_alloc(ip, HAMMER2_XOP_MODIFYING); 6703f01ebaaSMatthew Dillon hammer2_xop_start_except(&xop2->head, hammer2_xop_ipcluster, 6713f01ebaaSMatthew Dillon idx); 672b02c0ae6SMatthew Dillon hammer2_inode_unlock(ip); 673*c8c0a18aSMatthew Dillon merror = hammer2_xop_collect(&xop2->head, 0); 674*c8c0a18aSMatthew Dillon if (merror == 0) { 6753f01ebaaSMatthew Dillon focus = xop2->head.cluster.focus; 6760d66a712SMatthew Dillon if (hammer2_debug & 0x8000) { 6773f01ebaaSMatthew Dillon kprintf("syncthr: update inode %p (%s)\n", 6783f01ebaaSMatthew Dillon focus, 6790d66a712SMatthew Dillon (focus ? (char *)focus->data-> 6800d66a712SMatthew Dillon ipdata.filename : 6810d66a712SMatthew Dillon "?")); 6820d66a712SMatthew Dillon } 6833f01ebaaSMatthew Dillon chain = hammer2_inode_chain_and_parent(ip, idx, 6843f01ebaaSMatthew Dillon &parent, 6853f01ebaaSMatthew Dillon HAMMER2_RESOLVE_ALWAYS | 6863f01ebaaSMatthew Dillon HAMMER2_RESOLVE_SHARED); 6873f01ebaaSMatthew Dillon 6883f01ebaaSMatthew Dillon KKASSERT(parent != NULL); 6893f01ebaaSMatthew Dillon nerror = hammer2_sync_replace( 6903f01ebaaSMatthew Dillon thr, parent, chain, 6913f01ebaaSMatthew Dillon sync_tid, 692b02c0ae6SMatthew Dillon idx, focus, isroot); 6933f01ebaaSMatthew Dillon hammer2_chain_unlock(chain); 6943f01ebaaSMatthew Dillon hammer2_chain_drop(chain); 6953f01ebaaSMatthew Dillon hammer2_chain_unlock(parent); 6963f01ebaaSMatthew Dillon hammer2_chain_drop(parent); 6973f01ebaaSMatthew Dillon /* XXX */ 6983f01ebaaSMatthew Dillon } 6993f01ebaaSMatthew Dillon hammer2_xop_retire(&xop2->head, HAMMER2_XOPMASK_VOP); 7003f01ebaaSMatthew Dillon } 7013f01ebaaSMatthew Dillon 702*c8c0a18aSMatthew Dillon return merror; 7033f01ebaaSMatthew Dillon } 7043f01ebaaSMatthew Dillon 7053f01ebaaSMatthew Dillon /* 7063f01ebaaSMatthew Dillon * Create a missing chain by copying the focus from another device. 7073f01ebaaSMatthew Dillon * 7083f01ebaaSMatthew Dillon * On entry *parentp and focus are both locked shared. The chain will be 7093f01ebaaSMatthew Dillon * created and returned in *chainp also locked shared. 7103f01ebaaSMatthew Dillon */ 7113f01ebaaSMatthew Dillon static 7123f01ebaaSMatthew Dillon int 7133f01ebaaSMatthew Dillon hammer2_sync_insert(hammer2_thread_t *thr, 7143f01ebaaSMatthew Dillon hammer2_chain_t **parentp, hammer2_chain_t **chainp, 7153f01ebaaSMatthew Dillon hammer2_tid_t mtid, int idx, hammer2_chain_t *focus) 7163f01ebaaSMatthew Dillon { 7173f01ebaaSMatthew Dillon hammer2_chain_t *chain; 718b02c0ae6SMatthew Dillon hammer2_key_t dummy; 719*c8c0a18aSMatthew Dillon int error; 7203f01ebaaSMatthew Dillon 7213f01ebaaSMatthew Dillon #if HAMMER2_SYNCHRO_DEBUG 7223f01ebaaSMatthew Dillon if (hammer2_debug & 1) 7233f01ebaaSMatthew Dillon kprintf("insert rec par=%p/%d.%016jx slave %d %d.%016jx mod=%016jx\n", 7243f01ebaaSMatthew Dillon *parentp, 7253f01ebaaSMatthew Dillon (*parentp)->bref.type, 7263f01ebaaSMatthew Dillon (*parentp)->bref.key, 7273f01ebaaSMatthew Dillon idx, 7283f01ebaaSMatthew Dillon focus->bref.type, focus->bref.key, mtid); 7293f01ebaaSMatthew Dillon #endif 7303f01ebaaSMatthew Dillon 7313f01ebaaSMatthew Dillon /* 732b02c0ae6SMatthew Dillon * Parent requires an exclusive lock for the insertion. 733b02c0ae6SMatthew Dillon * We must unlock the child to avoid deadlocks while 734b02c0ae6SMatthew Dillon * relocking the parent. 7353f01ebaaSMatthew Dillon */ 736b02c0ae6SMatthew Dillon if (*chainp) { 7373f01ebaaSMatthew Dillon hammer2_chain_unlock(*chainp); 738b02c0ae6SMatthew Dillon hammer2_chain_drop(*chainp); 739b02c0ae6SMatthew Dillon *chainp = NULL; 740b02c0ae6SMatthew Dillon } 7413f01ebaaSMatthew Dillon hammer2_chain_unlock(*parentp); 7423f01ebaaSMatthew Dillon hammer2_chain_lock(*parentp, HAMMER2_RESOLVE_ALWAYS); 743b02c0ae6SMatthew Dillon 744b02c0ae6SMatthew Dillon /* 745b02c0ae6SMatthew Dillon * We must reissue the lookup to properly position (*parentp) 746b02c0ae6SMatthew Dillon * for the insertion. 747b02c0ae6SMatthew Dillon */ 748b02c0ae6SMatthew Dillon chain = hammer2_chain_lookup(parentp, &dummy, 749b02c0ae6SMatthew Dillon focus->bref.key, focus->bref.key, 750*c8c0a18aSMatthew Dillon &error, 751b02c0ae6SMatthew Dillon HAMMER2_LOOKUP_NODIRECT | 752b02c0ae6SMatthew Dillon HAMMER2_LOOKUP_ALWAYS); 753b02c0ae6SMatthew Dillon KKASSERT(chain == NULL); 7543f01ebaaSMatthew Dillon 7553f01ebaaSMatthew Dillon chain = NULL; 756*c8c0a18aSMatthew Dillon error = hammer2_chain_create(parentp, &chain, 7577fece146SMatthew Dillon thr->pmp, focus->bref.methods, 7583f01ebaaSMatthew Dillon focus->bref.key, focus->bref.keybits, 7593f01ebaaSMatthew Dillon focus->bref.type, focus->bytes, 7603f01ebaaSMatthew Dillon mtid, 0, 0); 761*c8c0a18aSMatthew Dillon if (error == 0) { 7623f01ebaaSMatthew Dillon hammer2_chain_modify(chain, mtid, 0, 0); 7633f01ebaaSMatthew Dillon 7643f01ebaaSMatthew Dillon /* 7653f01ebaaSMatthew Dillon * Copy focus to new chain 7663f01ebaaSMatthew Dillon */ 7673f01ebaaSMatthew Dillon 7683f01ebaaSMatthew Dillon /* type already set */ 7693f01ebaaSMatthew Dillon chain->bref.methods = focus->bref.methods; 7703f01ebaaSMatthew Dillon /* keybits already set */ 7713f01ebaaSMatthew Dillon chain->bref.vradix = focus->bref.vradix; 7723f01ebaaSMatthew Dillon /* mirror_tid set by flush */ 7733f01ebaaSMatthew Dillon KKASSERT(chain->bref.modify_tid == mtid); 7743f01ebaaSMatthew Dillon chain->bref.flags = focus->bref.flags; 7753f01ebaaSMatthew Dillon /* key already present */ 7763f01ebaaSMatthew Dillon /* check code will be recalculated */ 7773f01ebaaSMatthew Dillon 7783f01ebaaSMatthew Dillon /* 7793f01ebaaSMatthew Dillon * Copy data body. 7803f01ebaaSMatthew Dillon */ 7813f01ebaaSMatthew Dillon switch(chain->bref.type) { 7823f01ebaaSMatthew Dillon case HAMMER2_BREF_TYPE_INODE: 7833f01ebaaSMatthew Dillon if ((focus->data->ipdata.meta.op_flags & 7843f01ebaaSMatthew Dillon HAMMER2_OPFLAG_DIRECTDATA) == 0) { 785b02c0ae6SMatthew Dillon /* do not copy block table */ 7863f01ebaaSMatthew Dillon bcopy(focus->data, chain->data, 7873f01ebaaSMatthew Dillon offsetof(hammer2_inode_data_t, u)); 7883f01ebaaSMatthew Dillon break; 7893f01ebaaSMatthew Dillon } 790b02c0ae6SMatthew Dillon /* fall through copy whole thing */ 7913f01ebaaSMatthew Dillon case HAMMER2_BREF_TYPE_DATA: 7923f01ebaaSMatthew Dillon bcopy(focus->data, chain->data, chain->bytes); 7933f01ebaaSMatthew Dillon hammer2_chain_setcheck(chain, chain->data); 7943f01ebaaSMatthew Dillon break; 795da0cdd33SMatthew Dillon case HAMMER2_BREF_TYPE_DIRENT: 796da0cdd33SMatthew Dillon /* 797da0cdd33SMatthew Dillon * Directory entries embed data in the blockref. 798da0cdd33SMatthew Dillon */ 799da0cdd33SMatthew Dillon if (chain->bytes) { 800da0cdd33SMatthew Dillon bcopy(focus->data, chain->data, chain->bytes); 801da0cdd33SMatthew Dillon hammer2_chain_setcheck(chain, chain->data); 802da0cdd33SMatthew Dillon } else { 803da0cdd33SMatthew Dillon chain->bref.check = focus->bref.check; 804da0cdd33SMatthew Dillon } 805da0cdd33SMatthew Dillon chain->bref.embed = focus->bref.embed; 806da0cdd33SMatthew Dillon break; 8073f01ebaaSMatthew Dillon default: 8083f01ebaaSMatthew Dillon KKASSERT(0); 8093f01ebaaSMatthew Dillon break; 8103f01ebaaSMatthew Dillon } 811*c8c0a18aSMatthew Dillon } 8123f01ebaaSMatthew Dillon 813*c8c0a18aSMatthew Dillon if (chain) 8143f01ebaaSMatthew Dillon hammer2_chain_unlock(chain); /* unlock, leave ref */ 8153f01ebaaSMatthew Dillon *chainp = chain; /* will be returned locked */ 8163f01ebaaSMatthew Dillon 8173f01ebaaSMatthew Dillon /* 818da0cdd33SMatthew Dillon * Avoid an ordering deadlock when relocking shared. 8193f01ebaaSMatthew Dillon */ 8203f01ebaaSMatthew Dillon hammer2_chain_unlock(*parentp); 8213f01ebaaSMatthew Dillon hammer2_chain_lock(*parentp, HAMMER2_RESOLVE_SHARED | 8223f01ebaaSMatthew Dillon HAMMER2_RESOLVE_ALWAYS); 823*c8c0a18aSMatthew Dillon if (chain) { 8243f01ebaaSMatthew Dillon hammer2_chain_lock(chain, HAMMER2_RESOLVE_SHARED | 8253f01ebaaSMatthew Dillon HAMMER2_RESOLVE_ALWAYS); 826*c8c0a18aSMatthew Dillon error = chain->error; 827*c8c0a18aSMatthew Dillon } 8283f01ebaaSMatthew Dillon 829*c8c0a18aSMatthew Dillon return error; 8303f01ebaaSMatthew Dillon } 8313f01ebaaSMatthew Dillon 8323f01ebaaSMatthew Dillon /* 8333f01ebaaSMatthew Dillon * Destroy an extranious chain. 8343f01ebaaSMatthew Dillon * 8353f01ebaaSMatthew Dillon * Both *parentp and *chainp are locked shared. 8363f01ebaaSMatthew Dillon * 8373f01ebaaSMatthew Dillon * On return, *chainp will be adjusted to point to the next element in the 8383f01ebaaSMatthew Dillon * iteration and locked shared. 8393f01ebaaSMatthew Dillon */ 8403f01ebaaSMatthew Dillon static 8413f01ebaaSMatthew Dillon int 8423f01ebaaSMatthew Dillon hammer2_sync_destroy(hammer2_thread_t *thr, 8433f01ebaaSMatthew Dillon hammer2_chain_t **parentp, hammer2_chain_t **chainp, 8443f01ebaaSMatthew Dillon hammer2_tid_t mtid, int idx) 8453f01ebaaSMatthew Dillon { 8463f01ebaaSMatthew Dillon hammer2_chain_t *chain; 8473f01ebaaSMatthew Dillon hammer2_key_t key_next; 8483f01ebaaSMatthew Dillon hammer2_key_t save_key; 849*c8c0a18aSMatthew Dillon int error; 8503f01ebaaSMatthew Dillon 8513f01ebaaSMatthew Dillon chain = *chainp; 8523f01ebaaSMatthew Dillon 8533f01ebaaSMatthew Dillon #if HAMMER2_SYNCHRO_DEBUG 8543f01ebaaSMatthew Dillon if (hammer2_debug & 1) 8553f01ebaaSMatthew Dillon kprintf("destroy rec %p/%p slave %d %d.%016jx\n", 8563f01ebaaSMatthew Dillon *parentp, chain, 8573f01ebaaSMatthew Dillon idx, chain->bref.type, chain->bref.key); 8583f01ebaaSMatthew Dillon #endif 8593f01ebaaSMatthew Dillon 8603f01ebaaSMatthew Dillon save_key = chain->bref.key; 8613f01ebaaSMatthew Dillon if (save_key != HAMMER2_KEY_MAX) 8623f01ebaaSMatthew Dillon ++save_key; 8633f01ebaaSMatthew Dillon 8643f01ebaaSMatthew Dillon /* 8653f01ebaaSMatthew Dillon * Try to avoid unnecessary I/O. 8663f01ebaaSMatthew Dillon * 8673f01ebaaSMatthew Dillon * XXX accounting not propagated up properly. We might have to do 8683f01ebaaSMatthew Dillon * a RESOLVE_MAYBE here and pass 0 for the flags. 8693f01ebaaSMatthew Dillon */ 8703f01ebaaSMatthew Dillon hammer2_chain_unlock(chain); /* relock exclusive */ 8713f01ebaaSMatthew Dillon hammer2_chain_unlock(*parentp); 8723f01ebaaSMatthew Dillon hammer2_chain_lock(*parentp, HAMMER2_RESOLVE_ALWAYS); 8733f01ebaaSMatthew Dillon hammer2_chain_lock(chain, HAMMER2_RESOLVE_NEVER); 8743f01ebaaSMatthew Dillon 8753f01ebaaSMatthew Dillon hammer2_chain_delete(*parentp, chain, mtid, HAMMER2_DELETE_PERMANENT); 8763f01ebaaSMatthew Dillon hammer2_chain_unlock(chain); 8773f01ebaaSMatthew Dillon hammer2_chain_drop(chain); 8783f01ebaaSMatthew Dillon chain = NULL; /* safety */ 8793f01ebaaSMatthew Dillon 8803f01ebaaSMatthew Dillon hammer2_chain_unlock(*parentp); /* relock shared */ 8813f01ebaaSMatthew Dillon hammer2_chain_lock(*parentp, HAMMER2_RESOLVE_SHARED | 8823f01ebaaSMatthew Dillon HAMMER2_RESOLVE_ALWAYS); 8830d66a712SMatthew Dillon *chainp = hammer2_chain_lookup(parentp, &key_next, 8843f01ebaaSMatthew Dillon save_key, HAMMER2_KEY_MAX, 885*c8c0a18aSMatthew Dillon &error, 8863f01ebaaSMatthew Dillon HAMMER2_LOOKUP_SHARED | 8873f01ebaaSMatthew Dillon HAMMER2_LOOKUP_NODIRECT | 8883f01ebaaSMatthew Dillon HAMMER2_LOOKUP_NODATA); 889*c8c0a18aSMatthew Dillon return error; 8903f01ebaaSMatthew Dillon } 8913f01ebaaSMatthew Dillon 8923f01ebaaSMatthew Dillon /* 8933f01ebaaSMatthew Dillon * cparent is locked exclusively, with an extra ref, cluster is not locked. 8943f01ebaaSMatthew Dillon * Replace element [i] in the cluster. 8953f01ebaaSMatthew Dillon */ 8963f01ebaaSMatthew Dillon static 8973f01ebaaSMatthew Dillon int 8983f01ebaaSMatthew Dillon hammer2_sync_replace(hammer2_thread_t *thr, 8993f01ebaaSMatthew Dillon hammer2_chain_t *parent, hammer2_chain_t *chain, 9003f01ebaaSMatthew Dillon hammer2_tid_t mtid, int idx, 901b02c0ae6SMatthew Dillon hammer2_chain_t *focus, int isroot) 9023f01ebaaSMatthew Dillon { 9033f01ebaaSMatthew Dillon uint8_t otype; 904*c8c0a18aSMatthew Dillon int nradix; 9053f01ebaaSMatthew Dillon 9063f01ebaaSMatthew Dillon #if HAMMER2_SYNCHRO_DEBUG 9073f01ebaaSMatthew Dillon if (hammer2_debug & 1) 9083f01ebaaSMatthew Dillon kprintf("replace rec %p slave %d %d.%016jx mod=%016jx\n", 9093f01ebaaSMatthew Dillon chain, 9103f01ebaaSMatthew Dillon idx, 9113f01ebaaSMatthew Dillon focus->bref.type, focus->bref.key, mtid); 9123f01ebaaSMatthew Dillon #endif 9133f01ebaaSMatthew Dillon hammer2_chain_unlock(chain); 9143f01ebaaSMatthew Dillon hammer2_chain_lock(chain, HAMMER2_RESOLVE_ALWAYS); 915*c8c0a18aSMatthew Dillon if (chain->error == 0) { 9163f01ebaaSMatthew Dillon if (chain->bytes != focus->bytes) { 9173f01ebaaSMatthew Dillon /* XXX what if compressed? */ 9183f01ebaaSMatthew Dillon nradix = hammer2_getradix(chain->bytes); 919da0cdd33SMatthew Dillon hammer2_chain_resize(chain, mtid, 0, nradix, 0); 9203f01ebaaSMatthew Dillon } 9213f01ebaaSMatthew Dillon hammer2_chain_modify(chain, mtid, 0, 0); 9223f01ebaaSMatthew Dillon otype = chain->bref.type; 9233f01ebaaSMatthew Dillon chain->bref.type = focus->bref.type; 9243f01ebaaSMatthew Dillon chain->bref.methods = focus->bref.methods; 9253f01ebaaSMatthew Dillon chain->bref.keybits = focus->bref.keybits; 9263f01ebaaSMatthew Dillon chain->bref.vradix = focus->bref.vradix; 9273f01ebaaSMatthew Dillon /* mirror_tid updated by flush */ 928b02c0ae6SMatthew Dillon KKASSERT(mtid == 0 || chain->bref.modify_tid == mtid); 9293f01ebaaSMatthew Dillon chain->bref.flags = focus->bref.flags; 9303f01ebaaSMatthew Dillon /* key already present */ 9313f01ebaaSMatthew Dillon /* check code will be recalculated */ 9323f01ebaaSMatthew Dillon 9333f01ebaaSMatthew Dillon /* 9343f01ebaaSMatthew Dillon * Copy data body. 9353f01ebaaSMatthew Dillon */ 9363f01ebaaSMatthew Dillon switch(chain->bref.type) { 9373f01ebaaSMatthew Dillon case HAMMER2_BREF_TYPE_INODE: 938b02c0ae6SMatthew Dillon /* 939*c8c0a18aSMatthew Dillon * Special case PFSROOTs, only limited changes can 940*c8c0a18aSMatthew Dillon * be made since the meta-data contains miscellanious 941*c8c0a18aSMatthew Dillon * distinguishing fields. 942b02c0ae6SMatthew Dillon */ 943b02c0ae6SMatthew Dillon if (isroot) { 944b02c0ae6SMatthew Dillon chain->data->ipdata.meta.uflags = 945b02c0ae6SMatthew Dillon focus->data->ipdata.meta.uflags; 946b02c0ae6SMatthew Dillon chain->data->ipdata.meta.rmajor = 947b02c0ae6SMatthew Dillon focus->data->ipdata.meta.rmajor; 948b02c0ae6SMatthew Dillon chain->data->ipdata.meta.rminor = 949b02c0ae6SMatthew Dillon focus->data->ipdata.meta.rminor; 950b02c0ae6SMatthew Dillon chain->data->ipdata.meta.ctime = 951b02c0ae6SMatthew Dillon focus->data->ipdata.meta.ctime; 952b02c0ae6SMatthew Dillon chain->data->ipdata.meta.mtime = 953b02c0ae6SMatthew Dillon focus->data->ipdata.meta.mtime; 954b02c0ae6SMatthew Dillon chain->data->ipdata.meta.atime = 955b02c0ae6SMatthew Dillon focus->data->ipdata.meta.atime; 956b02c0ae6SMatthew Dillon /* not btime */ 957b02c0ae6SMatthew Dillon chain->data->ipdata.meta.uid = 958b02c0ae6SMatthew Dillon focus->data->ipdata.meta.uid; 959b02c0ae6SMatthew Dillon chain->data->ipdata.meta.gid = 960b02c0ae6SMatthew Dillon focus->data->ipdata.meta.gid; 961b02c0ae6SMatthew Dillon chain->data->ipdata.meta.mode = 962b02c0ae6SMatthew Dillon focus->data->ipdata.meta.mode; 963b02c0ae6SMatthew Dillon chain->data->ipdata.meta.ncopies = 964b02c0ae6SMatthew Dillon focus->data->ipdata.meta.ncopies; 965b02c0ae6SMatthew Dillon chain->data->ipdata.meta.comp_algo = 966b02c0ae6SMatthew Dillon focus->data->ipdata.meta.comp_algo; 967b02c0ae6SMatthew Dillon chain->data->ipdata.meta.check_algo = 968b02c0ae6SMatthew Dillon focus->data->ipdata.meta.check_algo; 969b02c0ae6SMatthew Dillon chain->data->ipdata.meta.data_quota = 970b02c0ae6SMatthew Dillon focus->data->ipdata.meta.data_quota; 971b02c0ae6SMatthew Dillon chain->data->ipdata.meta.inode_quota = 972b02c0ae6SMatthew Dillon focus->data->ipdata.meta.inode_quota; 9737fece146SMatthew Dillon 9747fece146SMatthew Dillon /* 9757fece146SMatthew Dillon * last snapshot tid controls overwrite 9767fece146SMatthew Dillon */ 9777fece146SMatthew Dillon if (chain->data->ipdata.meta.pfs_lsnap_tid < 9787fece146SMatthew Dillon focus->data->ipdata.meta.pfs_lsnap_tid) { 9797fece146SMatthew Dillon chain->data->ipdata.meta.pfs_lsnap_tid = 9807fece146SMatthew Dillon focus->data->ipdata.meta.pfs_lsnap_tid; 9817fece146SMatthew Dillon } 9827fece146SMatthew Dillon 983b02c0ae6SMatthew Dillon hammer2_chain_setcheck(chain, chain->data); 984b02c0ae6SMatthew Dillon break; 985b02c0ae6SMatthew Dillon } 986b02c0ae6SMatthew Dillon 987b02c0ae6SMatthew Dillon /* 988b02c0ae6SMatthew Dillon * Normal replacement. 989b02c0ae6SMatthew Dillon */ 9903f01ebaaSMatthew Dillon if ((focus->data->ipdata.meta.op_flags & 9913f01ebaaSMatthew Dillon HAMMER2_OPFLAG_DIRECTDATA) == 0) { 9923f01ebaaSMatthew Dillon /* 993*c8c0a18aSMatthew Dillon * If DIRECTDATA is transitioning to 0 or the 994*c8c0a18aSMatthew Dillon * old chain is not an inode we have to 995*c8c0a18aSMatthew Dillon * initialize the block table. 9963f01ebaaSMatthew Dillon */ 9973f01ebaaSMatthew Dillon if (otype != HAMMER2_BREF_TYPE_INODE || 9983f01ebaaSMatthew Dillon (chain->data->ipdata.meta.op_flags & 9993f01ebaaSMatthew Dillon HAMMER2_OPFLAG_DIRECTDATA)) { 1000*c8c0a18aSMatthew Dillon kprintf("chain inode trans " 1001*c8c0a18aSMatthew Dillon "away from dd\n"); 10023f01ebaaSMatthew Dillon bzero(&chain->data->ipdata.u, 10033f01ebaaSMatthew Dillon sizeof(chain->data->ipdata.u)); 10043f01ebaaSMatthew Dillon } 10053f01ebaaSMatthew Dillon bcopy(focus->data, chain->data, 10063f01ebaaSMatthew Dillon offsetof(hammer2_inode_data_t, u)); 10073f01ebaaSMatthew Dillon /* XXX setcheck on inode should not be needed */ 10083f01ebaaSMatthew Dillon hammer2_chain_setcheck(chain, chain->data); 10093f01ebaaSMatthew Dillon break; 10103f01ebaaSMatthew Dillon } 10113f01ebaaSMatthew Dillon /* fall through */ 10123f01ebaaSMatthew Dillon case HAMMER2_BREF_TYPE_DATA: 10133f01ebaaSMatthew Dillon bcopy(focus->data, chain->data, chain->bytes); 10143f01ebaaSMatthew Dillon hammer2_chain_setcheck(chain, chain->data); 10153f01ebaaSMatthew Dillon break; 1016da0cdd33SMatthew Dillon case HAMMER2_BREF_TYPE_DIRENT: 1017da0cdd33SMatthew Dillon /* 1018da0cdd33SMatthew Dillon * Directory entries embed data in the blockref. 1019da0cdd33SMatthew Dillon */ 1020da0cdd33SMatthew Dillon if (chain->bytes) { 1021da0cdd33SMatthew Dillon bcopy(focus->data, chain->data, chain->bytes); 1022da0cdd33SMatthew Dillon hammer2_chain_setcheck(chain, chain->data); 1023da0cdd33SMatthew Dillon } else { 1024da0cdd33SMatthew Dillon chain->bref.check = focus->bref.check; 1025da0cdd33SMatthew Dillon } 1026da0cdd33SMatthew Dillon chain->bref.embed = focus->bref.embed; 1027da0cdd33SMatthew Dillon break; 10283f01ebaaSMatthew Dillon default: 10293f01ebaaSMatthew Dillon KKASSERT(0); 10303f01ebaaSMatthew Dillon break; 10313f01ebaaSMatthew Dillon } 1032*c8c0a18aSMatthew Dillon } 10333f01ebaaSMatthew Dillon 10343f01ebaaSMatthew Dillon hammer2_chain_unlock(chain); 10353f01ebaaSMatthew Dillon hammer2_chain_lock(chain, HAMMER2_RESOLVE_SHARED | 10363f01ebaaSMatthew Dillon HAMMER2_RESOLVE_MAYBE); 10373f01ebaaSMatthew Dillon 10383f01ebaaSMatthew Dillon return 0; 10393f01ebaaSMatthew Dillon } 1040