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,
77fda30e02SMatthew 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,
84fda30e02SMatthew Dillon hammer2_xop_head_t *xop, hammer2_chain_t *focus,
85fda30e02SMatthew 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
hammer2_primary_sync_thread(void * arg)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
hammer2_sync_slaves(hammer2_thread_t * thr,hammer2_inode_t * ip,hammer2_deferred_list_t * list,int isroot)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);
411c4421f07SMatthew Dillon hammer2_xop_start_except(&xop2->head, &hammer2_ipcluster_desc,
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;
454c4421f07SMatthew Dillon hammer2_xop_start_except(&xop->head, &hammer2_scanall_desc, 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,
538fda30e02SMatthew 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,
544fda30e02SMatthew 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,
568fda30e02SMatthew 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,
574fda30e02SMatthew 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;
6045afbe9d8SMatthew Dillon nip = hammer2_inode_get(pmp, &xop->head, -1, 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);
672c4421f07SMatthew Dillon hammer2_xop_start_except(&xop2->head, &hammer2_ipcluster_desc,
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;
678fda30e02SMatthew Dillon if ((hammer2_debug & 0x8000) && focus) {
679fda30e02SMatthew Dillon const char *filename;
680fda30e02SMatthew Dillon
681fda30e02SMatthew Dillon filename = hammer2_xop_gdata(&xop2->head)->
682fda30e02SMatthew Dillon ipdata.filename;
6833f01ebaaSMatthew Dillon kprintf("syncthr: update inode %p (%s)\n",
684fda30e02SMatthew Dillon focus, filename);
685fda30e02SMatthew 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,
696fda30e02SMatthew 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
hammer2_sync_insert(hammer2_thread_t * thr,hammer2_chain_t ** parentp,hammer2_chain_t ** chainp,hammer2_tid_t mtid,int idx,hammer2_xop_head_t * xop,hammer2_chain_t * focus)7173f01ebaaSMatthew Dillon hammer2_sync_insert(hammer2_thread_t *thr,
7183f01ebaaSMatthew Dillon hammer2_chain_t **parentp, hammer2_chain_t **chainp,
719fda30e02SMatthew Dillon hammer2_tid_t mtid, int idx, hammer2_xop_head_t *xop,
720fda30e02SMatthew 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;
761*ecfe89b8SMatthew Dillon error = hammer2_chain_create(parentp, &chain, NULL, thr->pmp,
762*ecfe89b8SMatthew Dillon 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) {
767fda30e02SMatthew Dillon const hammer2_media_data_t *data;
768fda30e02SMatthew 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:
792fda30e02SMatthew Dillon data = hammer2_xop_gdata(xop);
793fda30e02SMatthew Dillon
794fda30e02SMatthew Dillon if ((data->ipdata.meta.op_flags &
7953f01ebaaSMatthew Dillon HAMMER2_OPFLAG_DIRECTDATA) == 0) {
796b02c0ae6SMatthew Dillon /* do not copy block table */
797fda30e02SMatthew Dillon bcopy(data, chain->data,
7983f01ebaaSMatthew Dillon offsetof(hammer2_inode_data_t, u));
799fda30e02SMatthew Dillon hammer2_xop_pdata(xop);
8003f01ebaaSMatthew Dillon break;
8013f01ebaaSMatthew Dillon }
802fda30e02SMatthew Dillon hammer2_xop_pdata(xop);
803b02c0ae6SMatthew Dillon /* fall through copy whole thing */
8043f01ebaaSMatthew Dillon case HAMMER2_BREF_TYPE_DATA:
805fda30e02SMatthew Dillon data = hammer2_xop_gdata(xop);
806fda30e02SMatthew Dillon bcopy(data, chain->data, chain->bytes);
8073f01ebaaSMatthew Dillon hammer2_chain_setcheck(chain, chain->data);
808fda30e02SMatthew 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) {
815fda30e02SMatthew Dillon data = hammer2_xop_gdata(xop);
816fda30e02SMatthew Dillon bcopy(data, chain->data, chain->bytes);
817da0cdd33SMatthew Dillon hammer2_chain_setcheck(chain, chain->data);
818fda30e02SMatthew 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
hammer2_sync_destroy(hammer2_thread_t * thr,hammer2_chain_t ** parentp,hammer2_chain_t ** chainp,hammer2_tid_t mtid,int idx)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
hammer2_sync_replace(hammer2_thread_t * thr,hammer2_chain_t * parent,hammer2_chain_t * chain,hammer2_tid_t mtid,int idx,hammer2_xop_head_t * xop,hammer2_chain_t * focus,int isroot)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,
919fda30e02SMatthew Dillon hammer2_xop_head_t *xop, hammer2_chain_t *focus,
920fda30e02SMatthew 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) {
937fda30e02SMatthew Dillon const hammer2_media_data_t *data;
938fda30e02SMatthew 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;
950fda30e02SMatthew 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 =
973fda30e02SMatthew Dillon data->ipdata.meta.uflags;
974b02c0ae6SMatthew Dillon chain->data->ipdata.meta.rmajor =
975fda30e02SMatthew Dillon data->ipdata.meta.rmajor;
976b02c0ae6SMatthew Dillon chain->data->ipdata.meta.rminor =
977fda30e02SMatthew Dillon data->ipdata.meta.rminor;
978b02c0ae6SMatthew Dillon chain->data->ipdata.meta.ctime =
979fda30e02SMatthew Dillon data->ipdata.meta.ctime;
980b02c0ae6SMatthew Dillon chain->data->ipdata.meta.mtime =
981fda30e02SMatthew Dillon data->ipdata.meta.mtime;
982b02c0ae6SMatthew Dillon chain->data->ipdata.meta.atime =
983fda30e02SMatthew Dillon data->ipdata.meta.atime;
984b02c0ae6SMatthew Dillon /* not btime */
985b02c0ae6SMatthew Dillon chain->data->ipdata.meta.uid =
986fda30e02SMatthew Dillon data->ipdata.meta.uid;
987b02c0ae6SMatthew Dillon chain->data->ipdata.meta.gid =
988fda30e02SMatthew Dillon data->ipdata.meta.gid;
989b02c0ae6SMatthew Dillon chain->data->ipdata.meta.mode =
990fda30e02SMatthew Dillon data->ipdata.meta.mode;
991b02c0ae6SMatthew Dillon chain->data->ipdata.meta.ncopies =
992fda30e02SMatthew Dillon data->ipdata.meta.ncopies;
993b02c0ae6SMatthew Dillon chain->data->ipdata.meta.comp_algo =
994fda30e02SMatthew Dillon data->ipdata.meta.comp_algo;
995b02c0ae6SMatthew Dillon chain->data->ipdata.meta.check_algo =
996fda30e02SMatthew Dillon data->ipdata.meta.check_algo;
997b02c0ae6SMatthew Dillon chain->data->ipdata.meta.data_quota =
998fda30e02SMatthew Dillon data->ipdata.meta.data_quota;
999b02c0ae6SMatthew Dillon chain->data->ipdata.meta.inode_quota =
1000fda30e02SMatthew 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 <
1006fda30e02SMatthew Dillon data->ipdata.meta.pfs_lsnap_tid) {
10077fece146SMatthew Dillon chain->data->ipdata.meta.pfs_lsnap_tid =
1008fda30e02SMatthew 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 */
1018fda30e02SMatthew 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 }
1033fda30e02SMatthew 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:
1041fda30e02SMatthew 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) {
1049fda30e02SMatthew 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 }
1060fda30e02SMatthew 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