13f01ebaaSMatthew Dillon /* 268b321c1SMatthew Dillon * Copyright (c) 2015-2018 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, 77*fda30e02SMatthew Dillon hammer2_xop_head_t *xop, 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, 84*fda30e02SMatthew Dillon hammer2_xop_head_t *xop, hammer2_chain_t *focus, 85*fda30e02SMatthew Dillon int isroot); 863f01ebaaSMatthew Dillon 873f01ebaaSMatthew Dillon /**************************************************************************** 883f01ebaaSMatthew Dillon * HAMMER2 SYNC THREADS * 893f01ebaaSMatthew Dillon ****************************************************************************/ 903f01ebaaSMatthew Dillon /* 913f01ebaaSMatthew Dillon * Primary management thread for an element of a node. A thread will exist 923f01ebaaSMatthew Dillon * for each element requiring management. 933f01ebaaSMatthew Dillon * 943f01ebaaSMatthew Dillon * No management threads are needed for the SPMP or for any PMP with only 953f01ebaaSMatthew Dillon * a single MASTER. 963f01ebaaSMatthew Dillon * 973f01ebaaSMatthew Dillon * On the SPMP - handles bulkfree and dedup operations 983f01ebaaSMatthew Dillon * On a PFS - handles remastering and synchronization 993f01ebaaSMatthew Dillon */ 1003f01ebaaSMatthew Dillon void 1013f01ebaaSMatthew Dillon hammer2_primary_sync_thread(void *arg) 1023f01ebaaSMatthew Dillon { 1033f01ebaaSMatthew Dillon hammer2_thread_t *thr = arg; 1043f01ebaaSMatthew Dillon hammer2_pfs_t *pmp; 1053f01ebaaSMatthew Dillon hammer2_deferred_list_t list; 1063f01ebaaSMatthew Dillon hammer2_deferred_ip_t *defer; 1073f01ebaaSMatthew Dillon int error; 108660d007eSMatthew Dillon uint32_t flags; 109660d007eSMatthew Dillon uint32_t nflags; 1103f01ebaaSMatthew Dillon 1113f01ebaaSMatthew Dillon pmp = thr->pmp; 1123f01ebaaSMatthew Dillon bzero(&list, sizeof(list)); 1133f01ebaaSMatthew Dillon 114660d007eSMatthew Dillon for (;;) { 115660d007eSMatthew Dillon flags = thr->flags; 116660d007eSMatthew Dillon cpu_ccfence(); 117660d007eSMatthew Dillon 118660d007eSMatthew Dillon /* 119660d007eSMatthew Dillon * Handle stop request 120660d007eSMatthew Dillon */ 121660d007eSMatthew Dillon if (flags & HAMMER2_THREAD_STOP) 122660d007eSMatthew Dillon break; 123660d007eSMatthew Dillon 1243f01ebaaSMatthew Dillon /* 1253f01ebaaSMatthew Dillon * Handle freeze request 1263f01ebaaSMatthew Dillon */ 127660d007eSMatthew Dillon if (flags & HAMMER2_THREAD_FREEZE) { 128660d007eSMatthew Dillon nflags = (flags & ~(HAMMER2_THREAD_FREEZE | 1299dca9515SMatthew Dillon HAMMER2_THREAD_WAITING)) | 130660d007eSMatthew Dillon HAMMER2_THREAD_FROZEN; 131660d007eSMatthew Dillon if (!atomic_cmpset_int(&thr->flags, flags, nflags)) 132660d007eSMatthew Dillon continue; 1339dca9515SMatthew Dillon if (flags & HAMMER2_THREAD_WAITING) 134660d007eSMatthew Dillon wakeup(&thr->flags); 13559eb0066SMatthew Dillon continue; 136660d007eSMatthew Dillon } 137660d007eSMatthew Dillon 138660d007eSMatthew Dillon if (flags & HAMMER2_THREAD_UNFREEZE) { 139660d007eSMatthew Dillon nflags = flags & ~(HAMMER2_THREAD_UNFREEZE | 140660d007eSMatthew Dillon HAMMER2_THREAD_FROZEN | 1419dca9515SMatthew Dillon HAMMER2_THREAD_WAITING); 142660d007eSMatthew Dillon if (!atomic_cmpset_int(&thr->flags, flags, nflags)) 143660d007eSMatthew Dillon continue; 1449dca9515SMatthew Dillon if (flags & HAMMER2_THREAD_WAITING) 145660d007eSMatthew Dillon wakeup(&thr->flags); 14659eb0066SMatthew Dillon continue; 1473f01ebaaSMatthew Dillon } 1483f01ebaaSMatthew Dillon 1493f01ebaaSMatthew Dillon /* 1503f01ebaaSMatthew Dillon * Force idle if frozen until unfrozen or stopped. 1513f01ebaaSMatthew Dillon */ 152660d007eSMatthew Dillon if (flags & HAMMER2_THREAD_FROZEN) { 153660d007eSMatthew Dillon nflags = flags | HAMMER2_THREAD_WAITING; 15459eb0066SMatthew Dillon 155660d007eSMatthew Dillon tsleep_interlock(&thr->flags, 0); 15659eb0066SMatthew Dillon if (atomic_cmpset_int(&thr->flags, flags, nflags)) 157660d007eSMatthew Dillon tsleep(&thr->flags, PINTERLOCKED, "frozen", 0); 1583f01ebaaSMatthew Dillon continue; 1593f01ebaaSMatthew Dillon } 1603f01ebaaSMatthew Dillon 1613f01ebaaSMatthew Dillon /* 1623f01ebaaSMatthew Dillon * Reset state on REMASTER request 1633f01ebaaSMatthew Dillon */ 1643f01ebaaSMatthew Dillon if (thr->flags & HAMMER2_THREAD_REMASTER) { 165660d007eSMatthew Dillon nflags = flags & ~HAMMER2_THREAD_REMASTER; 166660d007eSMatthew Dillon if (atomic_cmpset_int(&thr->flags, flags, nflags)) { 167660d007eSMatthew Dillon /* reset state here */ 168660d007eSMatthew Dillon } 169660d007eSMatthew Dillon continue; 1703f01ebaaSMatthew Dillon } 1713f01ebaaSMatthew Dillon 1723f01ebaaSMatthew Dillon /* 1733f01ebaaSMatthew Dillon * Synchronization scan. 1743f01ebaaSMatthew Dillon */ 1753cbe226bSMatthew Dillon if (hammer2_debug & 0x8000) 1763f01ebaaSMatthew Dillon kprintf("sync_slaves pfs %s clindex %d\n", 1773f01ebaaSMatthew Dillon pmp->pfs_names[thr->clindex], thr->clindex); 1783f01ebaaSMatthew Dillon hammer2_trans_init(pmp, 0); 1793f01ebaaSMatthew Dillon 1803f01ebaaSMatthew Dillon hammer2_inode_ref(pmp->iroot); 1813f01ebaaSMatthew Dillon 1823f01ebaaSMatthew Dillon for (;;) { 1833f01ebaaSMatthew Dillon int didbreak = 0; 1843f01ebaaSMatthew Dillon /* XXX lock synchronize pmp->modify_tid */ 185b02c0ae6SMatthew Dillon error = hammer2_sync_slaves(thr, pmp->iroot, &list, 1); 186b02c0ae6SMatthew Dillon if (hammer2_debug & 0x8000) { 187b02c0ae6SMatthew Dillon kprintf("sync_slaves error %d defer %p\n", 188b02c0ae6SMatthew Dillon error, list.base); 189b02c0ae6SMatthew Dillon } 19065cacacfSMatthew Dillon if (error != HAMMER2_ERROR_EAGAIN) 1913f01ebaaSMatthew Dillon break; 1923f01ebaaSMatthew Dillon while ((defer = list.base) != NULL) { 1933f01ebaaSMatthew Dillon hammer2_inode_t *nip; 1943f01ebaaSMatthew Dillon 1953f01ebaaSMatthew Dillon nip = defer->ip; 1960d66a712SMatthew Dillon error = hammer2_sync_slaves(thr, nip, &list, 1970d66a712SMatthew Dillon (nip == pmp->iroot)); 19865cacacfSMatthew Dillon if (error && 19965cacacfSMatthew Dillon error != HAMMER2_ERROR_EAGAIN && 20065cacacfSMatthew Dillon error != HAMMER2_ERROR_ENOENT) { 2013f01ebaaSMatthew Dillon break; 20265cacacfSMatthew Dillon } 2033f01ebaaSMatthew Dillon if (hammer2_thr_break(thr)) { 2043f01ebaaSMatthew Dillon didbreak = 1; 2053f01ebaaSMatthew Dillon break; 2063f01ebaaSMatthew Dillon } 2073f01ebaaSMatthew Dillon 2083f01ebaaSMatthew Dillon /* 2093f01ebaaSMatthew Dillon * If no additional defers occurred we can 210b02c0ae6SMatthew Dillon * remove this one, otherwise keep it on 2113f01ebaaSMatthew Dillon * the list and retry once the additional 2123f01ebaaSMatthew Dillon * defers have completed. 2133f01ebaaSMatthew Dillon */ 2143f01ebaaSMatthew Dillon if (defer == list.base) { 2153f01ebaaSMatthew Dillon --list.count; 2163f01ebaaSMatthew Dillon list.base = defer->next; 2173f01ebaaSMatthew Dillon kfree(defer, M_HAMMER2); 2183f01ebaaSMatthew Dillon defer = NULL; /* safety */ 2193f01ebaaSMatthew Dillon hammer2_inode_drop(nip); 2203f01ebaaSMatthew Dillon } 2213f01ebaaSMatthew Dillon } 2223f01ebaaSMatthew Dillon 2233f01ebaaSMatthew Dillon /* 2243f01ebaaSMatthew Dillon * If the thread is being remastered, frozen, or 2253f01ebaaSMatthew Dillon * stopped, clean up any left-over deferals. 2263f01ebaaSMatthew Dillon */ 22765cacacfSMatthew Dillon if (didbreak || 22865cacacfSMatthew Dillon (error && error != HAMMER2_ERROR_EAGAIN)) { 2293f01ebaaSMatthew Dillon kprintf("didbreak\n"); 2303f01ebaaSMatthew Dillon while ((defer = list.base) != NULL) { 2313f01ebaaSMatthew Dillon --list.count; 2323f01ebaaSMatthew Dillon hammer2_inode_drop(defer->ip); 2333f01ebaaSMatthew Dillon list.base = defer->next; 2343f01ebaaSMatthew Dillon kfree(defer, M_HAMMER2); 2353f01ebaaSMatthew Dillon } 23665cacacfSMatthew Dillon if (error == 0 || error == HAMMER2_ERROR_EAGAIN) 23765cacacfSMatthew Dillon error = HAMMER2_ERROR_EINPROGRESS; 2383f01ebaaSMatthew Dillon break; 2393f01ebaaSMatthew Dillon } 2403f01ebaaSMatthew Dillon } 2413f01ebaaSMatthew Dillon 2423f01ebaaSMatthew Dillon hammer2_inode_drop(pmp->iroot); 243257c2728SMatthew Dillon hammer2_trans_done(pmp, 0); 2443f01ebaaSMatthew Dillon 24565cacacfSMatthew Dillon if (error && error != HAMMER2_ERROR_EINPROGRESS) 2463f01ebaaSMatthew Dillon kprintf("hammer2_sync_slaves: error %d\n", error); 2473f01ebaaSMatthew Dillon 2483f01ebaaSMatthew Dillon /* 2493f01ebaaSMatthew Dillon * Wait for event, or 5-second poll. 2503f01ebaaSMatthew Dillon */ 251660d007eSMatthew Dillon nflags = flags | HAMMER2_THREAD_WAITING; 252660d007eSMatthew Dillon tsleep_interlock(&thr->flags, 0); 253660d007eSMatthew Dillon if (atomic_cmpset_int(&thr->flags, flags, nflags)) { 254660d007eSMatthew Dillon tsleep(&thr->flags, 0, "h2idle", hz * 5); 255660d007eSMatthew Dillon } 2563f01ebaaSMatthew Dillon } 2573f01ebaaSMatthew Dillon thr->td = NULL; 2589dca9515SMatthew Dillon hammer2_thr_signal(thr, HAMMER2_THREAD_STOPPED); 2593f01ebaaSMatthew Dillon /* thr structure can go invalid after this point */ 2603f01ebaaSMatthew Dillon } 2613f01ebaaSMatthew Dillon 2623f01ebaaSMatthew Dillon #if 0 2633f01ebaaSMatthew Dillon /* 2643f01ebaaSMatthew Dillon * Given a locked cluster created from pmp->iroot, update the PFS's 2653f01ebaaSMatthew Dillon * reporting status. 2663f01ebaaSMatthew Dillon */ 2673f01ebaaSMatthew Dillon static 2683f01ebaaSMatthew Dillon void 2693f01ebaaSMatthew Dillon hammer2_update_pfs_status(hammer2_thread_t *thr, uint32_t flags) 2703f01ebaaSMatthew Dillon { 2713f01ebaaSMatthew Dillon hammer2_pfs_t *pmp = thr->pmp; 2723f01ebaaSMatthew Dillon 2733f01ebaaSMatthew Dillon flags &= HAMMER2_CLUSTER_ZFLAGS; 2743f01ebaaSMatthew Dillon if (pmp->cluster_flags == flags) 2753f01ebaaSMatthew Dillon return; 2763f01ebaaSMatthew Dillon pmp->cluster_flags = flags; 2773f01ebaaSMatthew Dillon 2783f01ebaaSMatthew Dillon kprintf("pfs %p", pmp); 2793f01ebaaSMatthew Dillon if (flags & HAMMER2_CLUSTER_MSYNCED) 2803f01ebaaSMatthew Dillon kprintf(" masters-all-good"); 2813f01ebaaSMatthew Dillon if (flags & HAMMER2_CLUSTER_SSYNCED) 2823f01ebaaSMatthew Dillon kprintf(" slaves-all-good"); 2833f01ebaaSMatthew Dillon 2843f01ebaaSMatthew Dillon if (flags & HAMMER2_CLUSTER_WRHARD) 2853f01ebaaSMatthew Dillon kprintf(" quorum/rw"); 2863f01ebaaSMatthew Dillon else if (flags & HAMMER2_CLUSTER_RDHARD) 2873f01ebaaSMatthew Dillon kprintf(" quorum/ro"); 2883f01ebaaSMatthew Dillon 2893f01ebaaSMatthew Dillon if (flags & HAMMER2_CLUSTER_UNHARD) 2903f01ebaaSMatthew Dillon kprintf(" out-of-sync-masters"); 2913f01ebaaSMatthew Dillon else if (flags & HAMMER2_CLUSTER_NOHARD) 2923f01ebaaSMatthew Dillon kprintf(" no-masters-visible"); 2933f01ebaaSMatthew Dillon 2943f01ebaaSMatthew Dillon if (flags & HAMMER2_CLUSTER_WRSOFT) 2953f01ebaaSMatthew Dillon kprintf(" soft/rw"); 2963f01ebaaSMatthew Dillon else if (flags & HAMMER2_CLUSTER_RDSOFT) 2973f01ebaaSMatthew Dillon kprintf(" soft/ro"); 2983f01ebaaSMatthew Dillon 2993f01ebaaSMatthew Dillon if (flags & HAMMER2_CLUSTER_UNSOFT) 3003f01ebaaSMatthew Dillon kprintf(" out-of-sync-slaves"); 3013f01ebaaSMatthew Dillon else if (flags & HAMMER2_CLUSTER_NOSOFT) 3023f01ebaaSMatthew Dillon kprintf(" no-slaves-visible"); 3033f01ebaaSMatthew Dillon kprintf("\n"); 3043f01ebaaSMatthew Dillon } 3053f01ebaaSMatthew Dillon #endif 3063f01ebaaSMatthew Dillon 3073f01ebaaSMatthew Dillon #if 0 3083f01ebaaSMatthew Dillon static 3093f01ebaaSMatthew Dillon void 3103f01ebaaSMatthew Dillon dumpcluster(const char *label, 3113f01ebaaSMatthew Dillon hammer2_cluster_t *cparent, hammer2_cluster_t *cluster) 3123f01ebaaSMatthew Dillon { 3133f01ebaaSMatthew Dillon hammer2_chain_t *chain; 3143f01ebaaSMatthew Dillon int i; 3153f01ebaaSMatthew Dillon 3163f01ebaaSMatthew Dillon if ((hammer2_debug & 1) == 0) 3173f01ebaaSMatthew Dillon return; 3183f01ebaaSMatthew Dillon 3193f01ebaaSMatthew Dillon kprintf("%s\t", label); 3203f01ebaaSMatthew Dillon KKASSERT(cparent->nchains == cluster->nchains); 3213f01ebaaSMatthew Dillon for (i = 0; i < cparent->nchains; ++i) { 3223f01ebaaSMatthew Dillon if (i) 3233f01ebaaSMatthew Dillon kprintf("\t"); 3243f01ebaaSMatthew Dillon kprintf("%d ", i); 3253f01ebaaSMatthew Dillon if ((chain = cparent->array[i].chain) != NULL) { 3263f01ebaaSMatthew Dillon kprintf("%016jx%s ", 3273f01ebaaSMatthew Dillon chain->bref.key, 3283f01ebaaSMatthew Dillon ((cparent->array[i].flags & 3293f01ebaaSMatthew Dillon HAMMER2_CITEM_INVALID) ? "(I)" : " ") 3303f01ebaaSMatthew Dillon ); 3313f01ebaaSMatthew Dillon } else { 3323f01ebaaSMatthew Dillon kprintf(" NULL %s ", " "); 3333f01ebaaSMatthew Dillon } 3343f01ebaaSMatthew Dillon if ((chain = cluster->array[i].chain) != NULL) { 3353f01ebaaSMatthew Dillon kprintf("%016jx%s ", 3363f01ebaaSMatthew Dillon chain->bref.key, 3373f01ebaaSMatthew Dillon ((cluster->array[i].flags & 3383f01ebaaSMatthew Dillon HAMMER2_CITEM_INVALID) ? "(I)" : " ") 3393f01ebaaSMatthew Dillon ); 3403f01ebaaSMatthew Dillon } else { 3413f01ebaaSMatthew Dillon kprintf(" NULL %s ", " "); 3423f01ebaaSMatthew Dillon } 3433f01ebaaSMatthew Dillon kprintf("\n"); 3443f01ebaaSMatthew Dillon } 3453f01ebaaSMatthew Dillon } 3463f01ebaaSMatthew Dillon #endif 3473f01ebaaSMatthew Dillon 3483f01ebaaSMatthew Dillon /* 3493f01ebaaSMatthew Dillon * Each out of sync node sync-thread must issue an all-nodes XOP scan of 3503f01ebaaSMatthew Dillon * the inode. This creates a multiplication effect since the XOP scan itself 3513f01ebaaSMatthew Dillon * issues to all nodes. However, this is the only way we can safely 3523f01ebaaSMatthew Dillon * synchronize nodes which might have disparate I/O bandwidths and the only 3533f01ebaaSMatthew Dillon * way we can safely deal with stalled nodes. 354c8c0a18aSMatthew Dillon * 355c8c0a18aSMatthew Dillon * XXX serror / merror rollup and handling. 3563f01ebaaSMatthew Dillon */ 3573f01ebaaSMatthew Dillon static 3583f01ebaaSMatthew Dillon int 3593f01ebaaSMatthew Dillon hammer2_sync_slaves(hammer2_thread_t *thr, hammer2_inode_t *ip, 360b02c0ae6SMatthew Dillon hammer2_deferred_list_t *list, int isroot) 3613f01ebaaSMatthew Dillon { 3623f01ebaaSMatthew Dillon hammer2_xop_scanall_t *xop; 3633f01ebaaSMatthew Dillon hammer2_chain_t *parent; 3643f01ebaaSMatthew Dillon hammer2_chain_t *chain; 3653f01ebaaSMatthew Dillon hammer2_pfs_t *pmp; 3663f01ebaaSMatthew Dillon hammer2_key_t key_next; 3673f01ebaaSMatthew Dillon hammer2_tid_t sync_tid; 3683f01ebaaSMatthew Dillon int needrescan; 369b02c0ae6SMatthew Dillon int want_update; 370c8c0a18aSMatthew Dillon int serror; /* slave error */ 371c8c0a18aSMatthew Dillon int merror; /* master error (from xop_collect) */ 372c8c0a18aSMatthew Dillon int nerror; /* temporary error */ 3733f01ebaaSMatthew Dillon int idx; 3743f01ebaaSMatthew Dillon int n; 3753f01ebaaSMatthew Dillon 3763f01ebaaSMatthew Dillon pmp = ip->pmp; 3773f01ebaaSMatthew Dillon idx = thr->clindex; /* cluster node we are responsible for */ 3783f01ebaaSMatthew Dillon needrescan = 0; 379b02c0ae6SMatthew Dillon want_update = 0; 380b02c0ae6SMatthew Dillon sync_tid = 0; 381b02c0ae6SMatthew Dillon chain = NULL; 382b02c0ae6SMatthew Dillon parent = NULL; 3833f01ebaaSMatthew Dillon 3843f01ebaaSMatthew Dillon #if 0 3853f01ebaaSMatthew Dillon /* 3863f01ebaaSMatthew Dillon * Nothing to do if all slaves are synchronized. 3873f01ebaaSMatthew Dillon * Nothing to do if cluster not authoritatively readable. 3883f01ebaaSMatthew Dillon */ 3893f01ebaaSMatthew Dillon if (pmp->cluster_flags & HAMMER2_CLUSTER_SSYNCED) 3903f01ebaaSMatthew Dillon return(0); 3913f01ebaaSMatthew Dillon if ((pmp->cluster_flags & HAMMER2_CLUSTER_RDHARD) == 0) 3923f01ebaaSMatthew Dillon return(HAMMER2_ERROR_INCOMPLETE); 3933f01ebaaSMatthew Dillon #endif 3943f01ebaaSMatthew Dillon 395c8c0a18aSMatthew Dillon merror = 0; 3963f01ebaaSMatthew Dillon 3973f01ebaaSMatthew Dillon /* 398b02c0ae6SMatthew Dillon * Resolve the root inode of the PFS and determine if synchronization 399b02c0ae6SMatthew Dillon * is needed by checking modify_tid. 4000d66a712SMatthew Dillon * 4010d66a712SMatthew Dillon * Retain the synchronization TID from the focus inode and use it 4020d66a712SMatthew Dillon * later to synchronize the focus inode if/when the recursion 4030d66a712SMatthew Dillon * succeeds. 404b02c0ae6SMatthew Dillon */ 405b02c0ae6SMatthew Dillon { 406b02c0ae6SMatthew Dillon hammer2_xop_ipcluster_t *xop2; 407b02c0ae6SMatthew Dillon hammer2_chain_t *focus; 408b02c0ae6SMatthew Dillon 409b02c0ae6SMatthew Dillon hammer2_inode_lock(ip, HAMMER2_RESOLVE_SHARED); 410b02c0ae6SMatthew Dillon xop2 = hammer2_xop_alloc(ip, HAMMER2_XOP_MODIFYING); 411b02c0ae6SMatthew Dillon hammer2_xop_start_except(&xop2->head, hammer2_xop_ipcluster, 412b02c0ae6SMatthew Dillon idx); 413b02c0ae6SMatthew Dillon hammer2_inode_unlock(ip); 414c8c0a18aSMatthew Dillon merror = hammer2_xop_collect(&xop2->head, 0); 415c8c0a18aSMatthew Dillon if (merror == 0 && (focus = xop2->head.cluster.focus) != NULL) { 4160d66a712SMatthew Dillon sync_tid = focus->bref.modify_tid; 417b02c0ae6SMatthew Dillon chain = hammer2_inode_chain_and_parent(ip, idx, 418b02c0ae6SMatthew Dillon &parent, 419b02c0ae6SMatthew Dillon HAMMER2_RESOLVE_ALWAYS | 420b02c0ae6SMatthew Dillon HAMMER2_RESOLVE_SHARED); 421b02c0ae6SMatthew Dillon want_update = (chain->bref.modify_tid != sync_tid); 422b02c0ae6SMatthew Dillon if (chain) { 423b02c0ae6SMatthew Dillon hammer2_chain_unlock(chain); 424b02c0ae6SMatthew Dillon hammer2_chain_drop(chain); 425b02c0ae6SMatthew Dillon chain = NULL; 426b02c0ae6SMatthew Dillon } 427b02c0ae6SMatthew Dillon if (parent) { 428b02c0ae6SMatthew Dillon hammer2_chain_unlock(parent); 429b02c0ae6SMatthew Dillon hammer2_chain_drop(parent); 430b02c0ae6SMatthew Dillon parent = NULL; 431b02c0ae6SMatthew Dillon } 432b02c0ae6SMatthew Dillon } 433b02c0ae6SMatthew Dillon hammer2_xop_retire(&xop2->head, HAMMER2_XOPMASK_VOP); 434b02c0ae6SMatthew Dillon } 435b02c0ae6SMatthew Dillon 436b02c0ae6SMatthew Dillon if (want_update == 0) 437b02c0ae6SMatthew Dillon return(0); 438b02c0ae6SMatthew Dillon 439b02c0ae6SMatthew Dillon /* 4403f01ebaaSMatthew Dillon * The inode is left unlocked during the scan. Issue a XOP 4413f01ebaaSMatthew Dillon * that does *not* include our cluster index to iterate 4423f01ebaaSMatthew Dillon * properly synchronized elements and resolve our cluster index 4433f01ebaaSMatthew Dillon * against it. 4443f01ebaaSMatthew Dillon */ 4453f01ebaaSMatthew Dillon hammer2_inode_lock(ip, HAMMER2_RESOLVE_SHARED); 4463f01ebaaSMatthew Dillon xop = hammer2_xop_alloc(ip, HAMMER2_XOP_MODIFYING); 4473f01ebaaSMatthew Dillon xop->key_beg = HAMMER2_KEY_MIN; 4483f01ebaaSMatthew Dillon xop->key_end = HAMMER2_KEY_MAX; 449b02c0ae6SMatthew Dillon xop->resolve_flags = HAMMER2_RESOLVE_SHARED | 450b02c0ae6SMatthew Dillon HAMMER2_RESOLVE_ALWAYS; 451b02c0ae6SMatthew Dillon xop->lookup_flags = HAMMER2_LOOKUP_SHARED | 452b02c0ae6SMatthew Dillon HAMMER2_LOOKUP_NODIRECT | 453b02c0ae6SMatthew Dillon HAMMER2_LOOKUP_ALWAYS; 4543f01ebaaSMatthew Dillon hammer2_xop_start_except(&xop->head, hammer2_xop_scanall, idx); 4553f01ebaaSMatthew Dillon parent = hammer2_inode_chain(ip, idx, 4563f01ebaaSMatthew Dillon HAMMER2_RESOLVE_ALWAYS | 4573f01ebaaSMatthew Dillon HAMMER2_RESOLVE_SHARED); 4583f01ebaaSMatthew Dillon hammer2_inode_unlock(ip); 4593f01ebaaSMatthew Dillon 4603f01ebaaSMatthew Dillon chain = hammer2_chain_lookup(&parent, &key_next, 4613f01ebaaSMatthew Dillon HAMMER2_KEY_MIN, HAMMER2_KEY_MAX, 462c8c0a18aSMatthew Dillon &serror, 4633f01ebaaSMatthew Dillon HAMMER2_LOOKUP_SHARED | 4643f01ebaaSMatthew Dillon HAMMER2_LOOKUP_NODIRECT | 4653f01ebaaSMatthew Dillon HAMMER2_LOOKUP_NODATA); 466c8c0a18aSMatthew Dillon merror = hammer2_xop_collect(&xop->head, 0); 4670d66a712SMatthew Dillon if (hammer2_debug & 0x8000) { 468b02c0ae6SMatthew Dillon kprintf("START_SCAN IP=%016jx chain=%p (%016jx)\n", 469b02c0ae6SMatthew Dillon ip->meta.name_key, chain, 470b02c0ae6SMatthew Dillon (chain ? chain->bref.key : -1)); 4710d66a712SMatthew Dillon } 4723f01ebaaSMatthew Dillon 4733f01ebaaSMatthew Dillon for (;;) { 4743f01ebaaSMatthew Dillon /* 4753f01ebaaSMatthew Dillon * We are done if our scan is done and the XOP scan is done. 4763f01ebaaSMatthew Dillon * We are done if the XOP scan failed (that is, we don't 4773f01ebaaSMatthew Dillon * have authoritative data to synchronize with). 4783f01ebaaSMatthew Dillon */ 4793f01ebaaSMatthew Dillon int advance_local = 0; 4803f01ebaaSMatthew Dillon int advance_xop = 0; 4813f01ebaaSMatthew Dillon int dodefer = 0; 4823f01ebaaSMatthew Dillon hammer2_chain_t *focus; 4833f01ebaaSMatthew Dillon 48465cacacfSMatthew Dillon if (chain == NULL && merror == HAMMER2_ERROR_ENOENT) 4853f01ebaaSMatthew Dillon break; 48665cacacfSMatthew Dillon if (merror && merror != HAMMER2_ERROR_ENOENT) 4873f01ebaaSMatthew Dillon break; 4883f01ebaaSMatthew Dillon 4893f01ebaaSMatthew Dillon /* 4903f01ebaaSMatthew Dillon * Compare 4913f01ebaaSMatthew Dillon */ 49265cacacfSMatthew Dillon if (chain && merror == HAMMER2_ERROR_ENOENT) { 4933f01ebaaSMatthew Dillon /* 4943f01ebaaSMatthew Dillon * If we have local chains but the XOP scan is done, 4953f01ebaaSMatthew Dillon * the chains need to be deleted. 4963f01ebaaSMatthew Dillon */ 4973f01ebaaSMatthew Dillon n = -1; 4983f01ebaaSMatthew Dillon focus = NULL; 4993f01ebaaSMatthew Dillon } else if (chain == NULL) { 5003f01ebaaSMatthew Dillon /* 5013f01ebaaSMatthew Dillon * If our local scan is done but the XOP scan is not, 5023f01ebaaSMatthew Dillon * we need to create the missing chain(s). 5033f01ebaaSMatthew Dillon */ 5043f01ebaaSMatthew Dillon n = 1; 5053f01ebaaSMatthew Dillon focus = xop->head.cluster.focus; 5063f01ebaaSMatthew Dillon } else { 5073f01ebaaSMatthew Dillon /* 5083f01ebaaSMatthew Dillon * Otherwise compare to determine the action 5093f01ebaaSMatthew Dillon * needed. 5103f01ebaaSMatthew Dillon */ 5113f01ebaaSMatthew Dillon focus = xop->head.cluster.focus; 5123f01ebaaSMatthew Dillon n = hammer2_chain_cmp(chain, focus); 5133f01ebaaSMatthew Dillon } 5143f01ebaaSMatthew Dillon 5153f01ebaaSMatthew Dillon /* 5163f01ebaaSMatthew Dillon * Take action based on comparison results. 5173f01ebaaSMatthew Dillon */ 5183f01ebaaSMatthew Dillon if (n < 0) { 5193f01ebaaSMatthew Dillon /* 5203f01ebaaSMatthew Dillon * Delete extranious local data. This will 5213f01ebaaSMatthew Dillon * automatically advance the chain. 5223f01ebaaSMatthew Dillon */ 5233f01ebaaSMatthew Dillon nerror = hammer2_sync_destroy(thr, &parent, &chain, 5243f01ebaaSMatthew Dillon 0, idx); 5253f01ebaaSMatthew Dillon } else if (n == 0 && chain->bref.modify_tid != 5263f01ebaaSMatthew Dillon focus->bref.modify_tid) { 5273f01ebaaSMatthew Dillon /* 5283f01ebaaSMatthew Dillon * Matching key but local data or meta-data requires 5293f01ebaaSMatthew Dillon * updating. If we will recurse, we still need to 5303f01ebaaSMatthew Dillon * update to compatible content first but we do not 5313f01ebaaSMatthew Dillon * synchronize modify_tid until the entire recursion 5323f01ebaaSMatthew Dillon * has completed successfully. 5333f01ebaaSMatthew Dillon */ 534da0cdd33SMatthew Dillon if (focus->bref.type == HAMMER2_BREF_TYPE_INODE) { 5353f01ebaaSMatthew Dillon nerror = hammer2_sync_replace( 5363f01ebaaSMatthew Dillon thr, parent, chain, 5373f01ebaaSMatthew Dillon 0, 538*fda30e02SMatthew Dillon idx, &xop->head, focus, 0); 5393f01ebaaSMatthew Dillon dodefer = 1; 5403f01ebaaSMatthew Dillon } else { 5413f01ebaaSMatthew Dillon nerror = hammer2_sync_replace( 5423f01ebaaSMatthew Dillon thr, parent, chain, 5433f01ebaaSMatthew Dillon focus->bref.modify_tid, 544*fda30e02SMatthew Dillon idx, &xop->head, focus, 0); 5453f01ebaaSMatthew Dillon } 546b02c0ae6SMatthew Dillon advance_local = 1; 547b02c0ae6SMatthew Dillon advance_xop = 1; 5483f01ebaaSMatthew Dillon } else if (n == 0) { 5493f01ebaaSMatthew Dillon /* 5503f01ebaaSMatthew Dillon * 100% match, advance both 5513f01ebaaSMatthew Dillon */ 5523f01ebaaSMatthew Dillon advance_local = 1; 5533f01ebaaSMatthew Dillon advance_xop = 1; 5543f01ebaaSMatthew Dillon nerror = 0; 5553f01ebaaSMatthew Dillon } else if (n > 0) { 5563f01ebaaSMatthew Dillon /* 5573f01ebaaSMatthew Dillon * Insert missing local data. 5583f01ebaaSMatthew Dillon * 5593f01ebaaSMatthew Dillon * If we will recurse, we still need to update to 5603f01ebaaSMatthew Dillon * compatible content first but we do not synchronize 5613f01ebaaSMatthew Dillon * modify_tid until the entire recursion has 5623f01ebaaSMatthew Dillon * completed successfully. 5633f01ebaaSMatthew Dillon */ 564da0cdd33SMatthew Dillon if (focus->bref.type == HAMMER2_BREF_TYPE_INODE) { 5653f01ebaaSMatthew Dillon nerror = hammer2_sync_insert( 5663f01ebaaSMatthew Dillon thr, &parent, &chain, 5673f01ebaaSMatthew Dillon 0, 568*fda30e02SMatthew Dillon idx, &xop->head, focus); 5693f01ebaaSMatthew Dillon dodefer = 2; 5703f01ebaaSMatthew Dillon } else { 5713f01ebaaSMatthew Dillon nerror = hammer2_sync_insert( 5723f01ebaaSMatthew Dillon thr, &parent, &chain, 5733f01ebaaSMatthew Dillon focus->bref.modify_tid, 574*fda30e02SMatthew Dillon idx, &xop->head, focus); 5753f01ebaaSMatthew Dillon } 5763f01ebaaSMatthew Dillon advance_local = 1; 5773f01ebaaSMatthew Dillon advance_xop = 1; 5783f01ebaaSMatthew Dillon } 5793f01ebaaSMatthew Dillon 5803f01ebaaSMatthew Dillon /* 5813f01ebaaSMatthew Dillon * We cannot recurse depth-first because the XOP is still 5823f01ebaaSMatthew Dillon * running in node threads for this scan. Create a placemarker 5833f01ebaaSMatthew Dillon * by obtaining and record the hammer2_inode. 5843f01ebaaSMatthew Dillon * 5853f01ebaaSMatthew Dillon * We excluded our node from the XOP so we must temporarily 5863f01ebaaSMatthew Dillon * add it to xop->head.cluster so it is properly incorporated 5873f01ebaaSMatthew Dillon * into the inode. 5883f01ebaaSMatthew Dillon * 5893f01ebaaSMatthew Dillon * The deferral is pushed onto a LIFO list for bottom-up 5903f01ebaaSMatthew Dillon * synchronization. 5913f01ebaaSMatthew Dillon */ 592c8c0a18aSMatthew Dillon if (merror == 0 && dodefer) { 5933f01ebaaSMatthew Dillon hammer2_inode_t *nip; 5943f01ebaaSMatthew Dillon hammer2_deferred_ip_t *defer; 5953f01ebaaSMatthew Dillon 5963f01ebaaSMatthew Dillon KKASSERT(focus->bref.type == HAMMER2_BREF_TYPE_INODE); 5973f01ebaaSMatthew Dillon 5983f01ebaaSMatthew Dillon defer = kmalloc(sizeof(*defer), M_HAMMER2, 5993f01ebaaSMatthew Dillon M_WAITOK | M_ZERO); 6003f01ebaaSMatthew Dillon KKASSERT(xop->head.cluster.array[idx].chain == NULL); 6013f01ebaaSMatthew Dillon xop->head.cluster.array[idx].flags = 6023f01ebaaSMatthew Dillon HAMMER2_CITEM_INVALID; 6033f01ebaaSMatthew Dillon xop->head.cluster.array[idx].chain = chain; 604*fda30e02SMatthew Dillon nip = hammer2_inode_get(pmp, ip, &xop->head, idx); 6053f01ebaaSMatthew Dillon xop->head.cluster.array[idx].chain = NULL; 6063f01ebaaSMatthew Dillon 6073f01ebaaSMatthew Dillon hammer2_inode_ref(nip); 6083f01ebaaSMatthew Dillon hammer2_inode_unlock(nip); 6093f01ebaaSMatthew Dillon 6103f01ebaaSMatthew Dillon defer->next = list->base; 6113f01ebaaSMatthew Dillon defer->ip = nip; 6123f01ebaaSMatthew Dillon list->base = defer; 6133f01ebaaSMatthew Dillon ++list->count; 6143f01ebaaSMatthew Dillon needrescan = 1; 6153f01ebaaSMatthew Dillon } 6163f01ebaaSMatthew Dillon 6173f01ebaaSMatthew Dillon /* 6183f01ebaaSMatthew Dillon * If at least one deferral was added and the deferral 6193f01ebaaSMatthew Dillon * list has grown too large, stop adding more. This 62065cacacfSMatthew Dillon * will trigger an HAMMER2_ERROR_EAGAIN return. 6213f01ebaaSMatthew Dillon */ 6223f01ebaaSMatthew Dillon if (needrescan && list->count > 1000) 6233f01ebaaSMatthew Dillon break; 6243f01ebaaSMatthew Dillon 6253f01ebaaSMatthew Dillon /* 6263f01ebaaSMatthew Dillon * Advancements for iteration. 6273f01ebaaSMatthew Dillon */ 6283f01ebaaSMatthew Dillon if (advance_xop) { 629c8c0a18aSMatthew Dillon merror = hammer2_xop_collect(&xop->head, 0); 6303f01ebaaSMatthew Dillon } 6313f01ebaaSMatthew Dillon if (advance_local) { 6323f01ebaaSMatthew Dillon chain = hammer2_chain_next(&parent, chain, &key_next, 6333f01ebaaSMatthew Dillon key_next, HAMMER2_KEY_MAX, 634c8c0a18aSMatthew Dillon &serror, 6353f01ebaaSMatthew Dillon HAMMER2_LOOKUP_SHARED | 6363f01ebaaSMatthew Dillon HAMMER2_LOOKUP_NODIRECT | 6373f01ebaaSMatthew Dillon HAMMER2_LOOKUP_NODATA); 6383f01ebaaSMatthew Dillon } 6393f01ebaaSMatthew Dillon } 6403f01ebaaSMatthew Dillon hammer2_xop_retire(&xop->head, HAMMER2_XOPMASK_VOP); 6413f01ebaaSMatthew Dillon if (chain) { 6423f01ebaaSMatthew Dillon hammer2_chain_unlock(chain); 6433f01ebaaSMatthew Dillon hammer2_chain_drop(chain); 6443f01ebaaSMatthew Dillon } 6453f01ebaaSMatthew Dillon if (parent) { 6463f01ebaaSMatthew Dillon hammer2_chain_unlock(parent); 6473f01ebaaSMatthew Dillon hammer2_chain_drop(parent); 6483f01ebaaSMatthew Dillon } 6493f01ebaaSMatthew Dillon 6503f01ebaaSMatthew Dillon /* 6513f01ebaaSMatthew Dillon * If we added deferrals we want the caller to synchronize them 6523f01ebaaSMatthew Dillon * and then call us again. 6533f01ebaaSMatthew Dillon * 6543f01ebaaSMatthew Dillon * NOTE: In this situation we do not yet want to synchronize our 6553f01ebaaSMatthew Dillon * inode, setting the error code also has that effect. 6563f01ebaaSMatthew Dillon */ 65765cacacfSMatthew Dillon if ((merror == 0 || merror == HAMMER2_ERROR_ENOENT) && needrescan) 65865cacacfSMatthew Dillon merror = HAMMER2_ERROR_EAGAIN; 6593f01ebaaSMatthew Dillon 6603f01ebaaSMatthew Dillon /* 661b02c0ae6SMatthew Dillon * If no error occurred we can synchronize the inode meta-data 662b02c0ae6SMatthew Dillon * and modify_tid. Only limited changes are made to PFSROOTs. 6633f01ebaaSMatthew Dillon * 6643f01ebaaSMatthew Dillon * XXX inode lock was lost 6653f01ebaaSMatthew Dillon */ 66665cacacfSMatthew Dillon if (merror == 0 || merror == HAMMER2_ERROR_ENOENT) { 6673f01ebaaSMatthew Dillon hammer2_xop_ipcluster_t *xop2; 6683f01ebaaSMatthew Dillon hammer2_chain_t *focus; 6693f01ebaaSMatthew Dillon 670b02c0ae6SMatthew Dillon hammer2_inode_lock(ip, HAMMER2_RESOLVE_SHARED); 6713f01ebaaSMatthew Dillon xop2 = hammer2_xop_alloc(ip, HAMMER2_XOP_MODIFYING); 6723f01ebaaSMatthew Dillon hammer2_xop_start_except(&xop2->head, hammer2_xop_ipcluster, 6733f01ebaaSMatthew Dillon idx); 674b02c0ae6SMatthew Dillon hammer2_inode_unlock(ip); 675c8c0a18aSMatthew Dillon merror = hammer2_xop_collect(&xop2->head, 0); 676c8c0a18aSMatthew Dillon if (merror == 0) { 6773f01ebaaSMatthew Dillon focus = xop2->head.cluster.focus; 678*fda30e02SMatthew Dillon if ((hammer2_debug & 0x8000) && focus) { 679*fda30e02SMatthew Dillon const char *filename; 680*fda30e02SMatthew Dillon 681*fda30e02SMatthew Dillon filename = hammer2_xop_gdata(&xop2->head)-> 682*fda30e02SMatthew Dillon ipdata.filename; 6833f01ebaaSMatthew Dillon kprintf("syncthr: update inode %p (%s)\n", 684*fda30e02SMatthew Dillon focus, filename); 685*fda30e02SMatthew Dillon hammer2_xop_pdata(&xop2->head); 6860d66a712SMatthew Dillon } 6873f01ebaaSMatthew Dillon chain = hammer2_inode_chain_and_parent(ip, idx, 6883f01ebaaSMatthew Dillon &parent, 6893f01ebaaSMatthew Dillon HAMMER2_RESOLVE_ALWAYS | 6903f01ebaaSMatthew Dillon HAMMER2_RESOLVE_SHARED); 6913f01ebaaSMatthew Dillon 6923f01ebaaSMatthew Dillon KKASSERT(parent != NULL); 6933f01ebaaSMatthew Dillon nerror = hammer2_sync_replace( 6943f01ebaaSMatthew Dillon thr, parent, chain, 6953f01ebaaSMatthew Dillon sync_tid, 696*fda30e02SMatthew Dillon idx, &xop2->head, focus, isroot); 6973f01ebaaSMatthew Dillon hammer2_chain_unlock(chain); 6983f01ebaaSMatthew Dillon hammer2_chain_drop(chain); 6993f01ebaaSMatthew Dillon hammer2_chain_unlock(parent); 7003f01ebaaSMatthew Dillon hammer2_chain_drop(parent); 7013f01ebaaSMatthew Dillon /* XXX */ 7023f01ebaaSMatthew Dillon } 7033f01ebaaSMatthew Dillon hammer2_xop_retire(&xop2->head, HAMMER2_XOPMASK_VOP); 7043f01ebaaSMatthew Dillon } 7053f01ebaaSMatthew Dillon 706c8c0a18aSMatthew Dillon return merror; 7073f01ebaaSMatthew Dillon } 7083f01ebaaSMatthew Dillon 7093f01ebaaSMatthew Dillon /* 7103f01ebaaSMatthew Dillon * Create a missing chain by copying the focus from another device. 7113f01ebaaSMatthew Dillon * 7123f01ebaaSMatthew Dillon * On entry *parentp and focus are both locked shared. The chain will be 7133f01ebaaSMatthew Dillon * created and returned in *chainp also locked shared. 7143f01ebaaSMatthew Dillon */ 7153f01ebaaSMatthew Dillon static 7163f01ebaaSMatthew Dillon int 7173f01ebaaSMatthew Dillon hammer2_sync_insert(hammer2_thread_t *thr, 7183f01ebaaSMatthew Dillon hammer2_chain_t **parentp, hammer2_chain_t **chainp, 719*fda30e02SMatthew Dillon hammer2_tid_t mtid, int idx, hammer2_xop_head_t *xop, 720*fda30e02SMatthew Dillon hammer2_chain_t *focus) 7213f01ebaaSMatthew Dillon { 7223f01ebaaSMatthew Dillon hammer2_chain_t *chain; 723b02c0ae6SMatthew Dillon hammer2_key_t dummy; 724c8c0a18aSMatthew Dillon int error; 7253f01ebaaSMatthew Dillon 7263f01ebaaSMatthew Dillon #if HAMMER2_SYNCHRO_DEBUG 7273f01ebaaSMatthew Dillon if (hammer2_debug & 1) 7283f01ebaaSMatthew Dillon kprintf("insert rec par=%p/%d.%016jx slave %d %d.%016jx mod=%016jx\n", 7293f01ebaaSMatthew Dillon *parentp, 7303f01ebaaSMatthew Dillon (*parentp)->bref.type, 7313f01ebaaSMatthew Dillon (*parentp)->bref.key, 7323f01ebaaSMatthew Dillon idx, 7333f01ebaaSMatthew Dillon focus->bref.type, focus->bref.key, mtid); 7343f01ebaaSMatthew Dillon #endif 7353f01ebaaSMatthew Dillon 7363f01ebaaSMatthew Dillon /* 737b02c0ae6SMatthew Dillon * Parent requires an exclusive lock for the insertion. 738b02c0ae6SMatthew Dillon * We must unlock the child to avoid deadlocks while 739b02c0ae6SMatthew Dillon * relocking the parent. 7403f01ebaaSMatthew Dillon */ 741b02c0ae6SMatthew Dillon if (*chainp) { 7423f01ebaaSMatthew Dillon hammer2_chain_unlock(*chainp); 743b02c0ae6SMatthew Dillon hammer2_chain_drop(*chainp); 744b02c0ae6SMatthew Dillon *chainp = NULL; 745b02c0ae6SMatthew Dillon } 7463f01ebaaSMatthew Dillon hammer2_chain_unlock(*parentp); 7473f01ebaaSMatthew Dillon hammer2_chain_lock(*parentp, HAMMER2_RESOLVE_ALWAYS); 748b02c0ae6SMatthew Dillon 749b02c0ae6SMatthew Dillon /* 750b02c0ae6SMatthew Dillon * We must reissue the lookup to properly position (*parentp) 751b02c0ae6SMatthew Dillon * for the insertion. 752b02c0ae6SMatthew Dillon */ 753b02c0ae6SMatthew Dillon chain = hammer2_chain_lookup(parentp, &dummy, 754b02c0ae6SMatthew Dillon focus->bref.key, focus->bref.key, 755c8c0a18aSMatthew Dillon &error, 756b02c0ae6SMatthew Dillon HAMMER2_LOOKUP_NODIRECT | 757b02c0ae6SMatthew Dillon HAMMER2_LOOKUP_ALWAYS); 758b02c0ae6SMatthew Dillon KKASSERT(chain == NULL); 7593f01ebaaSMatthew Dillon 7603f01ebaaSMatthew Dillon chain = NULL; 761c8c0a18aSMatthew Dillon error = hammer2_chain_create(parentp, &chain, 7627fece146SMatthew Dillon thr->pmp, focus->bref.methods, 7633f01ebaaSMatthew Dillon focus->bref.key, focus->bref.keybits, 7643f01ebaaSMatthew Dillon focus->bref.type, focus->bytes, 7653f01ebaaSMatthew Dillon mtid, 0, 0); 766c8c0a18aSMatthew Dillon if (error == 0) { 767*fda30e02SMatthew Dillon const hammer2_media_data_t *data; 768*fda30e02SMatthew Dillon 76965cacacfSMatthew Dillon error = hammer2_chain_modify(chain, mtid, 0, 0); 77065cacacfSMatthew Dillon if (error) 77165cacacfSMatthew Dillon goto failed; 7723f01ebaaSMatthew Dillon 7733f01ebaaSMatthew Dillon /* 7743f01ebaaSMatthew Dillon * Copy focus to new chain 7753f01ebaaSMatthew Dillon */ 7763f01ebaaSMatthew Dillon 7773f01ebaaSMatthew Dillon /* type already set */ 7783f01ebaaSMatthew Dillon chain->bref.methods = focus->bref.methods; 7793f01ebaaSMatthew Dillon /* keybits already set */ 7803f01ebaaSMatthew Dillon chain->bref.vradix = focus->bref.vradix; 7813f01ebaaSMatthew Dillon /* mirror_tid set by flush */ 7823f01ebaaSMatthew Dillon KKASSERT(chain->bref.modify_tid == mtid); 7833f01ebaaSMatthew Dillon chain->bref.flags = focus->bref.flags; 7843f01ebaaSMatthew Dillon /* key already present */ 7853f01ebaaSMatthew Dillon /* check code will be recalculated */ 7863f01ebaaSMatthew Dillon 7873f01ebaaSMatthew Dillon /* 7883f01ebaaSMatthew Dillon * Copy data body. 7893f01ebaaSMatthew Dillon */ 7903f01ebaaSMatthew Dillon switch(chain->bref.type) { 7913f01ebaaSMatthew Dillon case HAMMER2_BREF_TYPE_INODE: 792*fda30e02SMatthew Dillon data = hammer2_xop_gdata(xop); 793*fda30e02SMatthew Dillon 794*fda30e02SMatthew Dillon if ((data->ipdata.meta.op_flags & 7953f01ebaaSMatthew Dillon HAMMER2_OPFLAG_DIRECTDATA) == 0) { 796b02c0ae6SMatthew Dillon /* do not copy block table */ 797*fda30e02SMatthew Dillon bcopy(data, chain->data, 7983f01ebaaSMatthew Dillon offsetof(hammer2_inode_data_t, u)); 799*fda30e02SMatthew Dillon hammer2_xop_pdata(xop); 8003f01ebaaSMatthew Dillon break; 8013f01ebaaSMatthew Dillon } 802*fda30e02SMatthew Dillon hammer2_xop_pdata(xop); 803b02c0ae6SMatthew Dillon /* fall through copy whole thing */ 8043f01ebaaSMatthew Dillon case HAMMER2_BREF_TYPE_DATA: 805*fda30e02SMatthew Dillon data = hammer2_xop_gdata(xop); 806*fda30e02SMatthew Dillon bcopy(data, chain->data, chain->bytes); 8073f01ebaaSMatthew Dillon hammer2_chain_setcheck(chain, chain->data); 808*fda30e02SMatthew Dillon hammer2_xop_pdata(xop); 8093f01ebaaSMatthew Dillon break; 810da0cdd33SMatthew Dillon case HAMMER2_BREF_TYPE_DIRENT: 811da0cdd33SMatthew Dillon /* 812da0cdd33SMatthew Dillon * Directory entries embed data in the blockref. 813da0cdd33SMatthew Dillon */ 814da0cdd33SMatthew Dillon if (chain->bytes) { 815*fda30e02SMatthew Dillon data = hammer2_xop_gdata(xop); 816*fda30e02SMatthew Dillon bcopy(data, chain->data, chain->bytes); 817da0cdd33SMatthew Dillon hammer2_chain_setcheck(chain, chain->data); 818*fda30e02SMatthew Dillon hammer2_xop_pdata(xop); 819da0cdd33SMatthew Dillon } else { 820da0cdd33SMatthew Dillon chain->bref.check = focus->bref.check; 821da0cdd33SMatthew Dillon } 822da0cdd33SMatthew Dillon chain->bref.embed = focus->bref.embed; 823da0cdd33SMatthew Dillon break; 8243f01ebaaSMatthew Dillon default: 8253f01ebaaSMatthew Dillon KKASSERT(0); 8263f01ebaaSMatthew Dillon break; 8273f01ebaaSMatthew Dillon } 828c8c0a18aSMatthew Dillon } 8293f01ebaaSMatthew Dillon 83065cacacfSMatthew Dillon failed: 831c8c0a18aSMatthew Dillon if (chain) 8323f01ebaaSMatthew Dillon hammer2_chain_unlock(chain); /* unlock, leave ref */ 8333f01ebaaSMatthew Dillon *chainp = chain; /* will be returned locked */ 8343f01ebaaSMatthew Dillon 8353f01ebaaSMatthew Dillon /* 836da0cdd33SMatthew Dillon * Avoid an ordering deadlock when relocking shared. 8373f01ebaaSMatthew Dillon */ 8383f01ebaaSMatthew Dillon hammer2_chain_unlock(*parentp); 8393f01ebaaSMatthew Dillon hammer2_chain_lock(*parentp, HAMMER2_RESOLVE_SHARED | 8403f01ebaaSMatthew Dillon HAMMER2_RESOLVE_ALWAYS); 841c8c0a18aSMatthew Dillon if (chain) { 8423f01ebaaSMatthew Dillon hammer2_chain_lock(chain, HAMMER2_RESOLVE_SHARED | 8433f01ebaaSMatthew Dillon HAMMER2_RESOLVE_ALWAYS); 844c8c0a18aSMatthew Dillon error = chain->error; 845c8c0a18aSMatthew Dillon } 8463f01ebaaSMatthew Dillon 847c8c0a18aSMatthew Dillon return error; 8483f01ebaaSMatthew Dillon } 8493f01ebaaSMatthew Dillon 8503f01ebaaSMatthew Dillon /* 8513f01ebaaSMatthew Dillon * Destroy an extranious chain. 8523f01ebaaSMatthew Dillon * 8533f01ebaaSMatthew Dillon * Both *parentp and *chainp are locked shared. 8543f01ebaaSMatthew Dillon * 8553f01ebaaSMatthew Dillon * On return, *chainp will be adjusted to point to the next element in the 8563f01ebaaSMatthew Dillon * iteration and locked shared. 8573f01ebaaSMatthew Dillon */ 8583f01ebaaSMatthew Dillon static 8593f01ebaaSMatthew Dillon int 8603f01ebaaSMatthew Dillon hammer2_sync_destroy(hammer2_thread_t *thr, 8613f01ebaaSMatthew Dillon hammer2_chain_t **parentp, hammer2_chain_t **chainp, 8623f01ebaaSMatthew Dillon hammer2_tid_t mtid, int idx) 8633f01ebaaSMatthew Dillon { 8643f01ebaaSMatthew Dillon hammer2_chain_t *chain; 8653f01ebaaSMatthew Dillon hammer2_key_t key_next; 8663f01ebaaSMatthew Dillon hammer2_key_t save_key; 867c8c0a18aSMatthew Dillon int error; 8683f01ebaaSMatthew Dillon 8693f01ebaaSMatthew Dillon chain = *chainp; 8703f01ebaaSMatthew Dillon 8713f01ebaaSMatthew Dillon #if HAMMER2_SYNCHRO_DEBUG 8723f01ebaaSMatthew Dillon if (hammer2_debug & 1) 8733f01ebaaSMatthew Dillon kprintf("destroy rec %p/%p slave %d %d.%016jx\n", 8743f01ebaaSMatthew Dillon *parentp, chain, 8753f01ebaaSMatthew Dillon idx, chain->bref.type, chain->bref.key); 8763f01ebaaSMatthew Dillon #endif 8773f01ebaaSMatthew Dillon 8783f01ebaaSMatthew Dillon save_key = chain->bref.key; 8793f01ebaaSMatthew Dillon if (save_key != HAMMER2_KEY_MAX) 8803f01ebaaSMatthew Dillon ++save_key; 8813f01ebaaSMatthew Dillon 8823f01ebaaSMatthew Dillon /* 8833f01ebaaSMatthew Dillon * Try to avoid unnecessary I/O. 8843f01ebaaSMatthew Dillon * 8853f01ebaaSMatthew Dillon * XXX accounting not propagated up properly. We might have to do 8863f01ebaaSMatthew Dillon * a RESOLVE_MAYBE here and pass 0 for the flags. 8873f01ebaaSMatthew Dillon */ 8883f01ebaaSMatthew Dillon hammer2_chain_unlock(chain); /* relock exclusive */ 8893f01ebaaSMatthew Dillon hammer2_chain_unlock(*parentp); 8903f01ebaaSMatthew Dillon hammer2_chain_lock(*parentp, HAMMER2_RESOLVE_ALWAYS); 8913f01ebaaSMatthew Dillon hammer2_chain_lock(chain, HAMMER2_RESOLVE_NEVER); 8923f01ebaaSMatthew Dillon 8933f01ebaaSMatthew Dillon hammer2_chain_delete(*parentp, chain, mtid, HAMMER2_DELETE_PERMANENT); 8943f01ebaaSMatthew Dillon hammer2_chain_unlock(chain); 8953f01ebaaSMatthew Dillon hammer2_chain_drop(chain); 8963f01ebaaSMatthew Dillon chain = NULL; /* safety */ 8973f01ebaaSMatthew Dillon 8983f01ebaaSMatthew Dillon hammer2_chain_unlock(*parentp); /* relock shared */ 8993f01ebaaSMatthew Dillon hammer2_chain_lock(*parentp, HAMMER2_RESOLVE_SHARED | 9003f01ebaaSMatthew Dillon HAMMER2_RESOLVE_ALWAYS); 9010d66a712SMatthew Dillon *chainp = hammer2_chain_lookup(parentp, &key_next, 9023f01ebaaSMatthew Dillon save_key, HAMMER2_KEY_MAX, 903c8c0a18aSMatthew Dillon &error, 9043f01ebaaSMatthew Dillon HAMMER2_LOOKUP_SHARED | 9053f01ebaaSMatthew Dillon HAMMER2_LOOKUP_NODIRECT | 9063f01ebaaSMatthew Dillon HAMMER2_LOOKUP_NODATA); 907c8c0a18aSMatthew Dillon return error; 9083f01ebaaSMatthew Dillon } 9093f01ebaaSMatthew Dillon 9103f01ebaaSMatthew Dillon /* 9113f01ebaaSMatthew Dillon * cparent is locked exclusively, with an extra ref, cluster is not locked. 9123f01ebaaSMatthew Dillon * Replace element [i] in the cluster. 9133f01ebaaSMatthew Dillon */ 9143f01ebaaSMatthew Dillon static 9153f01ebaaSMatthew Dillon int 9163f01ebaaSMatthew Dillon hammer2_sync_replace(hammer2_thread_t *thr, 9173f01ebaaSMatthew Dillon hammer2_chain_t *parent, hammer2_chain_t *chain, 9183f01ebaaSMatthew Dillon hammer2_tid_t mtid, int idx, 919*fda30e02SMatthew Dillon hammer2_xop_head_t *xop, hammer2_chain_t *focus, 920*fda30e02SMatthew Dillon int isroot) 9213f01ebaaSMatthew Dillon { 9223f01ebaaSMatthew Dillon uint8_t otype; 923c8c0a18aSMatthew Dillon int nradix; 92465cacacfSMatthew Dillon int error; 9253f01ebaaSMatthew Dillon 9263f01ebaaSMatthew Dillon #if HAMMER2_SYNCHRO_DEBUG 9273f01ebaaSMatthew Dillon if (hammer2_debug & 1) 9283f01ebaaSMatthew Dillon kprintf("replace rec %p slave %d %d.%016jx mod=%016jx\n", 9293f01ebaaSMatthew Dillon chain, 9303f01ebaaSMatthew Dillon idx, 9313f01ebaaSMatthew Dillon focus->bref.type, focus->bref.key, mtid); 9323f01ebaaSMatthew Dillon #endif 9333f01ebaaSMatthew Dillon hammer2_chain_unlock(chain); 9343f01ebaaSMatthew Dillon hammer2_chain_lock(chain, HAMMER2_RESOLVE_ALWAYS); 93565cacacfSMatthew Dillon error = chain->error; 93665cacacfSMatthew Dillon if (error == 0) { 937*fda30e02SMatthew Dillon const hammer2_media_data_t *data; 938*fda30e02SMatthew Dillon 9393f01ebaaSMatthew Dillon if (chain->bytes != focus->bytes) { 9403f01ebaaSMatthew Dillon /* XXX what if compressed? */ 9413f01ebaaSMatthew Dillon nradix = hammer2_getradix(chain->bytes); 94265cacacfSMatthew Dillon error = hammer2_chain_resize(chain, mtid, 0, nradix, 0); 94365cacacfSMatthew Dillon if (error) 94465cacacfSMatthew Dillon goto failed; 9453f01ebaaSMatthew Dillon } 94665cacacfSMatthew Dillon error = hammer2_chain_modify(chain, mtid, 0, 0); 94765cacacfSMatthew Dillon if (error) 94865cacacfSMatthew Dillon goto failed; 9493f01ebaaSMatthew Dillon otype = chain->bref.type; 950*fda30e02SMatthew Dillon data = hammer2_xop_gdata(xop); 9513f01ebaaSMatthew Dillon chain->bref.type = focus->bref.type; 9523f01ebaaSMatthew Dillon chain->bref.methods = focus->bref.methods; 9533f01ebaaSMatthew Dillon chain->bref.keybits = focus->bref.keybits; 9543f01ebaaSMatthew Dillon chain->bref.vradix = focus->bref.vradix; 9553f01ebaaSMatthew Dillon /* mirror_tid updated by flush */ 956b02c0ae6SMatthew Dillon KKASSERT(mtid == 0 || chain->bref.modify_tid == mtid); 9573f01ebaaSMatthew Dillon chain->bref.flags = focus->bref.flags; 9583f01ebaaSMatthew Dillon /* key already present */ 9593f01ebaaSMatthew Dillon /* check code will be recalculated */ 9603f01ebaaSMatthew Dillon 9613f01ebaaSMatthew Dillon /* 9623f01ebaaSMatthew Dillon * Copy data body. 9633f01ebaaSMatthew Dillon */ 9643f01ebaaSMatthew Dillon switch(chain->bref.type) { 9653f01ebaaSMatthew Dillon case HAMMER2_BREF_TYPE_INODE: 966b02c0ae6SMatthew Dillon /* 967c8c0a18aSMatthew Dillon * Special case PFSROOTs, only limited changes can 968c8c0a18aSMatthew Dillon * be made since the meta-data contains miscellanious 969c8c0a18aSMatthew Dillon * distinguishing fields. 970b02c0ae6SMatthew Dillon */ 971b02c0ae6SMatthew Dillon if (isroot) { 972b02c0ae6SMatthew Dillon chain->data->ipdata.meta.uflags = 973*fda30e02SMatthew Dillon data->ipdata.meta.uflags; 974b02c0ae6SMatthew Dillon chain->data->ipdata.meta.rmajor = 975*fda30e02SMatthew Dillon data->ipdata.meta.rmajor; 976b02c0ae6SMatthew Dillon chain->data->ipdata.meta.rminor = 977*fda30e02SMatthew Dillon data->ipdata.meta.rminor; 978b02c0ae6SMatthew Dillon chain->data->ipdata.meta.ctime = 979*fda30e02SMatthew Dillon data->ipdata.meta.ctime; 980b02c0ae6SMatthew Dillon chain->data->ipdata.meta.mtime = 981*fda30e02SMatthew Dillon data->ipdata.meta.mtime; 982b02c0ae6SMatthew Dillon chain->data->ipdata.meta.atime = 983*fda30e02SMatthew Dillon data->ipdata.meta.atime; 984b02c0ae6SMatthew Dillon /* not btime */ 985b02c0ae6SMatthew Dillon chain->data->ipdata.meta.uid = 986*fda30e02SMatthew Dillon data->ipdata.meta.uid; 987b02c0ae6SMatthew Dillon chain->data->ipdata.meta.gid = 988*fda30e02SMatthew Dillon data->ipdata.meta.gid; 989b02c0ae6SMatthew Dillon chain->data->ipdata.meta.mode = 990*fda30e02SMatthew Dillon data->ipdata.meta.mode; 991b02c0ae6SMatthew Dillon chain->data->ipdata.meta.ncopies = 992*fda30e02SMatthew Dillon data->ipdata.meta.ncopies; 993b02c0ae6SMatthew Dillon chain->data->ipdata.meta.comp_algo = 994*fda30e02SMatthew Dillon data->ipdata.meta.comp_algo; 995b02c0ae6SMatthew Dillon chain->data->ipdata.meta.check_algo = 996*fda30e02SMatthew Dillon data->ipdata.meta.check_algo; 997b02c0ae6SMatthew Dillon chain->data->ipdata.meta.data_quota = 998*fda30e02SMatthew Dillon data->ipdata.meta.data_quota; 999b02c0ae6SMatthew Dillon chain->data->ipdata.meta.inode_quota = 1000*fda30e02SMatthew Dillon data->ipdata.meta.inode_quota; 10017fece146SMatthew Dillon 10027fece146SMatthew Dillon /* 10037fece146SMatthew Dillon * last snapshot tid controls overwrite 10047fece146SMatthew Dillon */ 10057fece146SMatthew Dillon if (chain->data->ipdata.meta.pfs_lsnap_tid < 1006*fda30e02SMatthew Dillon data->ipdata.meta.pfs_lsnap_tid) { 10077fece146SMatthew Dillon chain->data->ipdata.meta.pfs_lsnap_tid = 1008*fda30e02SMatthew Dillon data->ipdata.meta.pfs_lsnap_tid; 10097fece146SMatthew Dillon } 10107fece146SMatthew Dillon 1011b02c0ae6SMatthew Dillon hammer2_chain_setcheck(chain, chain->data); 1012b02c0ae6SMatthew Dillon break; 1013b02c0ae6SMatthew Dillon } 1014b02c0ae6SMatthew Dillon 1015b02c0ae6SMatthew Dillon /* 1016b02c0ae6SMatthew Dillon * Normal replacement. 1017b02c0ae6SMatthew Dillon */ 1018*fda30e02SMatthew Dillon if ((data->ipdata.meta.op_flags & 10193f01ebaaSMatthew Dillon HAMMER2_OPFLAG_DIRECTDATA) == 0) { 10203f01ebaaSMatthew Dillon /* 1021c8c0a18aSMatthew Dillon * If DIRECTDATA is transitioning to 0 or the 1022c8c0a18aSMatthew Dillon * old chain is not an inode we have to 1023c8c0a18aSMatthew Dillon * initialize the block table. 10243f01ebaaSMatthew Dillon */ 10253f01ebaaSMatthew Dillon if (otype != HAMMER2_BREF_TYPE_INODE || 10263f01ebaaSMatthew Dillon (chain->data->ipdata.meta.op_flags & 10273f01ebaaSMatthew Dillon HAMMER2_OPFLAG_DIRECTDATA)) { 1028c8c0a18aSMatthew Dillon kprintf("chain inode trans " 1029c8c0a18aSMatthew Dillon "away from dd\n"); 10303f01ebaaSMatthew Dillon bzero(&chain->data->ipdata.u, 10313f01ebaaSMatthew Dillon sizeof(chain->data->ipdata.u)); 10323f01ebaaSMatthew Dillon } 1033*fda30e02SMatthew Dillon bcopy(data, chain->data, 10343f01ebaaSMatthew Dillon offsetof(hammer2_inode_data_t, u)); 10353f01ebaaSMatthew Dillon /* XXX setcheck on inode should not be needed */ 10363f01ebaaSMatthew Dillon hammer2_chain_setcheck(chain, chain->data); 10373f01ebaaSMatthew Dillon break; 10383f01ebaaSMatthew Dillon } 10393f01ebaaSMatthew Dillon /* fall through */ 10403f01ebaaSMatthew Dillon case HAMMER2_BREF_TYPE_DATA: 1041*fda30e02SMatthew Dillon bcopy(data, chain->data, chain->bytes); 10423f01ebaaSMatthew Dillon hammer2_chain_setcheck(chain, chain->data); 10433f01ebaaSMatthew Dillon break; 1044da0cdd33SMatthew Dillon case HAMMER2_BREF_TYPE_DIRENT: 1045da0cdd33SMatthew Dillon /* 1046da0cdd33SMatthew Dillon * Directory entries embed data in the blockref. 1047da0cdd33SMatthew Dillon */ 1048da0cdd33SMatthew Dillon if (chain->bytes) { 1049*fda30e02SMatthew Dillon bcopy(data, chain->data, chain->bytes); 1050da0cdd33SMatthew Dillon hammer2_chain_setcheck(chain, chain->data); 1051da0cdd33SMatthew Dillon } else { 1052da0cdd33SMatthew Dillon chain->bref.check = focus->bref.check; 1053da0cdd33SMatthew Dillon } 1054da0cdd33SMatthew Dillon chain->bref.embed = focus->bref.embed; 1055da0cdd33SMatthew Dillon break; 10563f01ebaaSMatthew Dillon default: 10573f01ebaaSMatthew Dillon KKASSERT(0); 10583f01ebaaSMatthew Dillon break; 10593f01ebaaSMatthew Dillon } 1060*fda30e02SMatthew Dillon hammer2_xop_pdata(xop); 1061c8c0a18aSMatthew Dillon } 10623f01ebaaSMatthew Dillon 106365cacacfSMatthew Dillon failed: 10643f01ebaaSMatthew Dillon hammer2_chain_unlock(chain); 10653f01ebaaSMatthew Dillon hammer2_chain_lock(chain, HAMMER2_RESOLVE_SHARED | 10663f01ebaaSMatthew Dillon HAMMER2_RESOLVE_MAYBE); 10673f01ebaaSMatthew Dillon 106865cacacfSMatthew Dillon return error; 10693f01ebaaSMatthew Dillon } 1070