2 * Copyright (c) 2015 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@dragonflybsd.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * This module implements various PFS-based helper threads.
39 #define HAMMER2_SYNCTHR_DEBUG 1
41 static int hammer2_sync_slaves(hammer2_syncthr_t
*thr
,
42 hammer2_cluster_t
*cparent
, int *errors
);
43 static void hammer2_update_pfs_status(hammer2_syncthr_t
*thr
,
44 hammer2_cluster_t
*cparent
);
45 static int hammer2_sync_insert(hammer2_syncthr_t
*thr
,
46 hammer2_cluster_t
*cparent
, hammer2_cluster_t
*cluster
,
47 hammer2_tid_t modify_tid
,
49 static int hammer2_sync_destroy(hammer2_syncthr_t
*thr
,
50 hammer2_cluster_t
*cparent
, hammer2_cluster_t
*cluster
,
52 static int hammer2_sync_replace(hammer2_syncthr_t
*thr
,
53 hammer2_cluster_t
*cparent
, hammer2_cluster_t
*cluster
,
54 hammer2_tid_t modify_tid
,
58 * Initialize the suspplied syncthr structure, starting the specified
62 hammer2_syncthr_create(hammer2_syncthr_t
*thr
, hammer2_pfs_t
*pmp
,
63 int clindex
, void (*func
)(void *arg
))
65 lockinit(&thr
->lk
, "h2syncthr", 0, 0);
67 thr
->clindex
= clindex
;
68 lwkt_create(func
, thr
, &thr
->td
, NULL
, 0, -1,
69 "h2nod-%s", pmp
->pfs_names
[clindex
]);
73 * Terminate a syncthr. This function will silently return if the syncthr
74 * was never initialized or has already been deleted.
76 * This is accomplished by setting the STOP flag and waiting for the td
77 * structure to become NULL.
80 hammer2_syncthr_delete(hammer2_syncthr_t
*thr
)
84 lockmgr(&thr
->lk
, LK_EXCLUSIVE
);
85 atomic_set_int(&thr
->flags
, HAMMER2_SYNCTHR_STOP
);
88 lksleep(thr
, &thr
->lk
, 0, "h2thr", hz
);
90 lockmgr(&thr
->lk
, LK_RELEASE
);
96 * Asynchronous remaster request. Ask the synchronization thread to
97 * start over soon (as if it were frozen and unfrozen, but without waiting).
98 * The thread always recalculates mastership relationships when restarting.
101 hammer2_syncthr_remaster(hammer2_syncthr_t
*thr
)
105 lockmgr(&thr
->lk
, LK_EXCLUSIVE
);
106 atomic_set_int(&thr
->flags
, HAMMER2_SYNCTHR_REMASTER
);
108 lockmgr(&thr
->lk
, LK_RELEASE
);
112 hammer2_syncthr_freeze(hammer2_syncthr_t
*thr
)
116 lockmgr(&thr
->lk
, LK_EXCLUSIVE
);
117 atomic_set_int(&thr
->flags
, HAMMER2_SYNCTHR_FREEZE
);
119 while ((thr
->flags
& HAMMER2_SYNCTHR_FROZEN
) == 0) {
120 lksleep(thr
, &thr
->lk
, 0, "h2frz", hz
);
122 lockmgr(&thr
->lk
, LK_RELEASE
);
126 hammer2_syncthr_unfreeze(hammer2_syncthr_t
*thr
)
130 lockmgr(&thr
->lk
, LK_EXCLUSIVE
);
131 atomic_clear_int(&thr
->flags
, HAMMER2_SYNCTHR_FROZEN
);
133 lockmgr(&thr
->lk
, LK_RELEASE
);
137 * Primary management thread for an element of a node. A thread will exist
138 * for each element requiring management.
140 * No management threads are needed for the SPMP or for any PMP with only
143 * On the SPMP - handles bulkfree and dedup operations
144 * On a PFS - handles remastering and synchronization
147 hammer2_syncthr_primary(void *arg
)
149 hammer2_syncthr_t
*thr
= arg
;
150 hammer2_cluster_t
*cparent
;
151 hammer2_chain_t
*chain
;
153 int errors
[HAMMER2_MAXCLUSTER
];
158 lockmgr(&thr
->lk
, LK_EXCLUSIVE
);
159 while ((thr
->flags
& HAMMER2_SYNCTHR_STOP
) == 0) {
161 * Handle freeze request
163 if (thr
->flags
& HAMMER2_SYNCTHR_FREEZE
) {
164 atomic_set_int(&thr
->flags
, HAMMER2_SYNCTHR_FROZEN
);
165 atomic_clear_int(&thr
->flags
, HAMMER2_SYNCTHR_FREEZE
);
169 * Force idle if frozen until unfrozen or stopped.
171 if (thr
->flags
& HAMMER2_SYNCTHR_FROZEN
) {
172 lksleep(&thr
->flags
, &thr
->lk
, 0, "frozen", 0);
177 * Reset state on REMASTER request
179 if (thr
->flags
& HAMMER2_SYNCTHR_REMASTER
) {
180 atomic_clear_int(&thr
->flags
, HAMMER2_SYNCTHR_REMASTER
);
185 * Synchronization scan.
187 hammer2_trans_init(&thr
->trans
, pmp
, HAMMER2_TRANS_KEEPMODIFY
);
188 cparent
= hammer2_inode_lock(pmp
->iroot
,
189 HAMMER2_RESOLVE_ALWAYS
);
190 hammer2_update_pfs_status(thr
, cparent
);
191 hammer2_inode_unlock(pmp
->iroot
, NULL
);
192 bzero(errors
, sizeof(errors
));
193 kprintf("sync_slaves clindex %d\n", thr
->clindex
);
196 * We are the syncer, not a normal frontend operator,
197 * so force cparent good to prime the scan.
199 hammer2_cluster_forcegood(cparent
);
200 error
= hammer2_sync_slaves(thr
, cparent
, errors
);
202 kprintf("hammer2_sync_slaves: error %d\n", error
);
203 chain
= cparent
->array
[thr
->clindex
].chain
;
206 * Retain chain for our node and release the cluster.
208 hammer2_chain_ref(chain
);
209 hammer2_chain_lock(chain
, HAMMER2_RESOLVE_ALWAYS
);
210 hammer2_cluster_unlock(cparent
);
211 hammer2_cluster_drop(cparent
);
216 hammer2_flush(&thr
->trans
, chain
, 1);
217 hammer2_chain_unlock(chain
);
218 hammer2_chain_drop(chain
);
220 hammer2_trans_done(&thr
->trans
);
223 * Wait for event, or 5-second poll.
225 lksleep(&thr
->flags
, &thr
->lk
, 0, "h2idle", hz
* 5);
229 lockmgr(&thr
->lk
, LK_RELEASE
);
230 /* thr structure can go invalid after this point */
234 * Given a locked cluster created from pmp->iroot, update the PFS's
239 hammer2_update_pfs_status(hammer2_syncthr_t
*thr
, hammer2_cluster_t
*cparent
)
241 hammer2_pfs_t
*pmp
= thr
->pmp
;
244 flags
= cparent
->flags
& HAMMER2_CLUSTER_ZFLAGS
;
245 if (pmp
->flags
== flags
)
249 kprintf("pfs %p", pmp
);
250 if (flags
& HAMMER2_CLUSTER_MSYNCED
)
251 kprintf(" masters-all-good");
252 if (flags
& HAMMER2_CLUSTER_SSYNCED
)
253 kprintf(" slaves-all-good");
255 if (flags
& HAMMER2_CLUSTER_WRHARD
)
256 kprintf(" quorum/rw");
257 else if (flags
& HAMMER2_CLUSTER_RDHARD
)
258 kprintf(" quorum/ro");
260 if (flags
& HAMMER2_CLUSTER_UNHARD
)
261 kprintf(" out-of-sync-masters");
262 else if (flags
& HAMMER2_CLUSTER_NOHARD
)
263 kprintf(" no-masters-visible");
265 if (flags
& HAMMER2_CLUSTER_WRSOFT
)
267 else if (flags
& HAMMER2_CLUSTER_RDSOFT
)
270 if (flags
& HAMMER2_CLUSTER_UNSOFT
)
271 kprintf(" out-of-sync-slaves");
272 else if (flags
& HAMMER2_CLUSTER_NOSOFT
)
273 kprintf(" no-slaves-visible");
279 dumpcluster(const char *label
,
280 hammer2_cluster_t
*cparent
, hammer2_cluster_t
*cluster
)
282 hammer2_chain_t
*chain
;
285 if ((hammer2_debug
& 1) == 0)
288 kprintf("%s\t", label
);
289 KKASSERT(cparent
->nchains
== cluster
->nchains
);
290 for (i
= 0; i
< cparent
->nchains
; ++i
) {
294 if ((chain
= cparent
->array
[i
].chain
) != NULL
) {
297 ((cparent
->array
[i
].flags
&
298 HAMMER2_CITEM_INVALID
) ? "(I)" : " ")
301 kprintf(" NULL %s ", " ");
303 if ((chain
= cluster
->array
[i
].chain
) != NULL
) {
306 ((cluster
->array
[i
].flags
&
307 HAMMER2_CITEM_INVALID
) ? "(I)" : " ")
310 kprintf(" NULL %s ", " ");
317 * TODO - have cparent use a shared lock normally instead of exclusive,
318 * (needs to be upgraded for slave adjustments).
322 hammer2_sync_slaves(hammer2_syncthr_t
*thr
, hammer2_cluster_t
*cparent
,
326 hammer2_cluster_t
*cluster
;
327 hammer2_cluster_t
*scluster
;
328 hammer2_chain_t
*focus
;
329 hammer2_chain_t
*chain
;
330 hammer2_key_t key_next
;
339 idx
= thr
->clindex
; /* cluster node we are responsible for */
342 * Nothing to do if all slaves are synchronized.
343 * Nothing to do if cluster not authoritatively readable.
345 if (pmp
->flags
& HAMMER2_CLUSTER_SSYNCED
)
347 if ((pmp
->flags
& HAMMER2_CLUSTER_RDHARD
) == 0)
348 return(HAMMER2_ERROR_INCOMPLETE
);
353 * XXX snapshot the source to provide a stable source to copy.
357 * Update all local slaves (remote slaves are handled by the sync
358 * threads on their respective hosts).
360 * Do a full topology scan, insert/delete elements on slaves as
361 * needed. cparent must be ref'd so we can unlock and relock it
364 * ALLNODES - Allows clusters with a NULL focus to be returned if
365 * elements remain on other nodes.
367 hammer2_cluster_ref(cparent
);
368 cluster
= hammer2_cluster_lookup(cparent
, &key_next
,
369 HAMMER2_KEY_MIN
, HAMMER2_KEY_MAX
,
370 HAMMER2_LOOKUP_NODATA
|
371 HAMMER2_LOOKUP_NOLOCK
|
372 HAMMER2_LOOKUP_NODIRECT
|
373 HAMMER2_LOOKUP_ALLNODES
);
374 dumpcluster("lookup", cparent
, cluster
);
381 * nowork is adjusted during the loop,
382 * dorecursion is calculated here.
385 focus
= cluster
->focus
;
386 if (focus
&& focus
->bref
.type
== HAMMER2_BREF_TYPE_INODE
)
391 if (idx
== 3 && (hammer2_debug
& 1) && focus
)
392 kprintf("scan3 focus %d.%016jx %d.%016jx\n",
393 (cparent
? cparent
->focus
->bref
.type
: 0xFF),
394 (cparent
? cparent
->focus
->bref
.key
: (uintmax_t)-1LLU),
395 focus
->bref
.type
, focus
->bref
.key
);
398 * Synchronize chains to focus
400 if (idx
>= cluster
->nchains
)
402 chain
= cluster
->array
[idx
].chain
;
403 if (idx
== 3 && (hammer2_debug
& 1) && chain
)
404 kprintf("scan3 slave %d.%016jx %d.%016jx\n",
405 ((cparent
&& cparent
->array
[idx
].chain
) ? cparent
->array
[idx
].chain
->bref
.type
: 0xFF),
406 ((cparent
&& cparent
->array
[idx
].chain
) ? cparent
->array
[idx
].chain
->bref
.key
: (uintmax_t)-1LLU),
407 cluster
->array
[idx
].chain
->bref
.type
,
408 cluster
->array
[idx
].chain
->bref
.key
);
409 if (idx
== 3 && (hammer2_debug
& 1) && chain
== NULL
)
410 kprintf("scan3 slave %d.%16jx NULL\n",
411 ((cparent
&& cparent
->array
[idx
].chain
) ? cparent
->array
[idx
].chain
->bref
.type
: 0xFF),
412 ((cparent
&& cparent
->array
[idx
].chain
) ? cparent
->array
[idx
].chain
->bref
.key
: (uintmax_t)-1LLU)
416 * Disable recursion for this index and loop up
417 * if a chain error is detected.
419 * A NULL chain is ok, it simply indicates that
420 * the slave reached the end of its scan, but we
421 * might have stuff from the master that still
422 * needs to be copied in.
424 if (chain
&& chain
->error
) {
425 kprintf("chain error index %d: %d\n",
427 errors
[idx
] = chain
->error
;
428 error
= chain
->error
;
429 cluster
->array
[idx
].flags
|= HAMMER2_CITEM_INVALID
;
434 * Skip if the slave already has the record (everything
435 * matches including the modify_tid). Note that the
436 * mirror_tid does not have to match, mirror_tid is
437 * a per-block-device entity.
440 (cluster
->array
[idx
].flags
& HAMMER2_CITEM_INVALID
) == 0) {
445 * Invalid element needs to be updated.
450 * Otherwise adjust the slave. Compare the focus to
451 * the chain. Note that focus and chain can
452 * independently be NULL.
454 KKASSERT(cluster
->focus
== focus
);
457 n
= hammer2_chain_cmp(focus
, chain
);
459 n
= -1; /* end-of-scan on slave */
462 n
= 1; /* end-of-scan on focus */
464 n
= 0; /* end-of-scan on both */
469 * slave chain missing, create missing chain.
471 * If we are going to recurse we have to set
472 * the initial modify_tid to 0 until the
473 * sub-tree is completely synchronized.
474 * Setting (n = 0) in this situation forces
475 * the replacement call to run on the way
476 * back up after the sub-tree has
480 nerror
= hammer2_sync_insert(
481 thr
, cparent
, cluster
,
487 nerror
= hammer2_sync_insert(
488 thr
, cparent
, cluster
,
489 focus
->bref
.modify_tid
,
494 * excess slave chain, destroy
496 nerror
= hammer2_sync_destroy(thr
,
499 hammer2_cluster_next_single_chain(
505 HAMMER2_LOOKUP_NODATA
|
506 HAMMER2_LOOKUP_NOLOCK
|
507 HAMMER2_LOOKUP_NODIRECT
|
508 HAMMER2_LOOKUP_ALLNODES
);
510 * Re-execute same index, there might be more
511 * items to delete before this slave catches
517 * Key matched but INVALID was set which likely
518 * means that modify_tid is out of sync.
520 * If we are going to recurse we have to do
521 * a partial replacement of the parent to
522 * ensure that the block array is compatible.
523 * For example, the current slave inode might
524 * be flagged DIRECTDATA when the focus is not.
525 * We must set modify_tid to 0 for now and
526 * will fix it when recursion is complete.
528 * If we are not going to recurse we can do
529 * a normal replacement.
531 * focus && chain can both be NULL on a match.
534 nerror
= hammer2_sync_replace(
535 thr
, cparent
, cluster
,
539 nerror
= hammer2_sync_replace(
540 thr
, cparent
, cluster
,
541 focus
->bref
.modify_tid
,
549 /* finished primary synchronization of chains */
554 * Operation may have modified cparent, we must replace
555 * iroot->cluster if we are at the top level.
558 hammer2_inode_repoint_one(pmp
->iroot
, cparent
, idx
);
560 KKASSERT(cluster
->focus
== focus
);
563 * If no work to do this iteration, skip any recursion.
569 * EXECUTE RECURSION (skip if no recursion)
571 * Indirect blocks are absorbed by the iteration so we only
572 * have to recurse on inodes.
574 * Do not resolve scluster, it represents the iteration
575 * parent and while it is logically in-sync the physical
576 * elements might not match due to the presence of indirect
579 if (dorecursion
== 0)
581 if (thr
->depth
> 20) {
582 kprintf("depth limit reached\n");
583 nerror
= HAMMER2_ERROR_DEPTH
;
585 hammer2_cluster_unlock(cparent
);
586 scluster
= hammer2_cluster_copy(cluster
);
587 hammer2_cluster_lock(scluster
, HAMMER2_RESOLVE_ALWAYS
);
589 nerror
= hammer2_sync_slaves(thr
, scluster
, errors
);
591 hammer2_cluster_unlock(scluster
);
592 hammer2_cluster_drop(scluster
);
593 /* XXX modify_tid on scluster */
594 /* flush needs to not update modify_tid */
595 hammer2_cluster_lock(cparent
, HAMMER2_RESOLVE_ALWAYS
);
601 * Fixup parent nodes on the way back up from the recursion
602 * if no error occurred. The modify_tid for these nodes
603 * would have been set to 0 and must be set to their final
606 chain
= cluster
->array
[idx
].chain
;
607 if (chain
== NULL
|| chain
->error
)
610 * should not be set but must fixup parents.
611 if ((cluster->array[idx].flags & HAMMER2_CITEM_INVALID) == 0)
616 * At this point we have to have key-matched non-NULL
619 n
= hammer2_chain_cmp(focus
, chain
);
621 kprintf("hammer2_sync_slaves: illegal "
622 "post-recursion state %d\n", n
);
627 * Update modify_tid on the way back up.
629 nerror
= hammer2_sync_replace(
630 thr
, cparent
, cluster
,
631 focus
->bref
.modify_tid
,
638 * Operation may modify cparent, must replace
639 * iroot->cluster if we are at the top level.
642 hammer2_inode_repoint_one(pmp
->iroot
, cparent
, idx
);
649 dumpcluster("adjust", cparent
, cluster
);
650 cluster
= hammer2_cluster_next(cparent
, cluster
,
654 HAMMER2_LOOKUP_NODATA
|
655 HAMMER2_LOOKUP_NOLOCK
|
656 HAMMER2_LOOKUP_NODIRECT
|
657 HAMMER2_LOOKUP_ALLNODES
);
658 dumpcluster("nextcl", cparent
, cluster
);
660 hammer2_cluster_drop(cparent
);
662 hammer2_cluster_drop(cluster
);
668 * cparent is locked exclusively, with an extra ref, cluster is not locked.
672 hammer2_sync_insert(hammer2_syncthr_t
*thr
,
673 hammer2_cluster_t
*cparent
, hammer2_cluster_t
*cluster
,
674 hammer2_tid_t modify_tid
, int i
, int *errors
)
676 hammer2_chain_t
*focus
;
677 hammer2_chain_t
*chain
;
680 focus
= cluster
->focus
;
681 #if HAMMER2_SYNCTHR_DEBUG
682 if (hammer2_debug
& 1)
683 kprintf("insert rec par=%p/%d.%016jx slave %d %d.%016jx mod=%016jx\n",
684 cparent
->array
[i
].chain
,
685 cparent
->array
[i
].chain
->bref
.type
,
686 cparent
->array
[i
].chain
->bref
.key
,
687 i
, focus
->bref
.type
, focus
->bref
.key
, modify_tid
);
691 * We have to do a lookup to position ourselves at the correct
692 * parent when inserting a record into a new slave because the
693 * cluster iteration for this slave might not be pointing to the
694 * right place. Our expectation is that the record will not be
697 hammer2_cluster_unlock_except(cparent
, i
);
698 chain
= hammer2_chain_lookup(&cparent
->array
[i
].chain
, &dummy
,
699 focus
->bref
.key
, focus
->bref
.key
,
700 &cparent
->array
[i
].cache_index
,
701 HAMMER2_LOOKUP_NODIRECT
);
702 if (cparent
->focus_index
== i
)
703 cparent
->focus
= cparent
->array
[i
].chain
;
704 KKASSERT(chain
== NULL
);
707 * Create the missing chain.
709 * Have to be careful to avoid deadlocks.
712 if (cluster
->focus_index
< i
)
713 hammer2_chain_lock(focus
, HAMMER2_RESOLVE_ALWAYS
);
714 hammer2_chain_create(&thr
->trans
, &cparent
->array
[i
].chain
,
716 focus
->bref
.key
, focus
->bref
.keybits
,
717 focus
->bref
.type
, focus
->bytes
,
719 if (cluster
->focus_index
> i
)
720 hammer2_chain_lock(focus
, HAMMER2_RESOLVE_ALWAYS
);
721 if (cparent
->focus_index
== i
)
722 cparent
->focus
= cparent
->array
[i
].chain
;
723 hammer2_chain_modify(&thr
->trans
, chain
, 0);
726 * Copy focus to new chain
729 /* type already set */
730 chain
->bref
.methods
= focus
->bref
.methods
;
731 /* keybits already set */
732 chain
->bref
.vradix
= focus
->bref
.vradix
;
733 /* mirror_tid set by flush */
734 chain
->bref
.modify_tid
= modify_tid
;
735 chain
->bref
.flags
= focus
->bref
.flags
;
736 /* key already present */
737 /* check code will be recalculated */
742 switch(chain
->bref
.type
) {
743 case HAMMER2_BREF_TYPE_INODE
:
744 if ((focus
->data
->ipdata
.op_flags
&
745 HAMMER2_OPFLAG_DIRECTDATA
) == 0) {
746 bcopy(focus
->data
, chain
->data
,
747 offsetof(hammer2_inode_data_t
, u
));
751 case HAMMER2_BREF_TYPE_DATA
:
752 bcopy(focus
->data
, chain
->data
, chain
->bytes
);
753 hammer2_chain_setcheck(chain
, chain
->data
);
760 hammer2_chain_unlock(focus
);
761 hammer2_chain_unlock(chain
); /* unlock, leave ref */
764 * Avoid ordering deadlock when relocking cparent.
767 hammer2_cluster_lock_except(cparent
, i
, HAMMER2_RESOLVE_ALWAYS
);
769 hammer2_chain_unlock(cparent
->array
[i
].chain
);
770 hammer2_cluster_lock(cparent
, HAMMER2_RESOLVE_ALWAYS
);
774 * Enter item into (unlocked) cluster.
776 * Must clear invalid for iteration to work properly.
778 if (cluster
->array
[i
].chain
)
779 hammer2_chain_drop(cluster
->array
[i
].chain
);
780 cluster
->array
[i
].chain
= chain
;
781 cluster
->array
[i
].flags
&= ~HAMMER2_CITEM_INVALID
;
787 * cparent is locked exclusively, with an extra ref, cluster is not locked.
791 hammer2_sync_destroy(hammer2_syncthr_t
*thr
,
792 hammer2_cluster_t
*cparent
, hammer2_cluster_t
*cluster
,
795 hammer2_chain_t
*chain
;
797 chain
= cluster
->array
[i
].chain
;
798 #if HAMMER2_SYNCTHR_DEBUG
799 if (hammer2_debug
& 1)
800 kprintf("destroy rec %p/%p slave %d %d.%016jx\n",
802 i
, chain
->bref
.type
, chain
->bref
.key
);
805 * Try to avoid unnecessary I/O.
807 * XXX accounting not propagated up properly. We might have to do
808 * a RESOLVE_MAYBE here and pass 0 for the flags.
810 hammer2_chain_lock(chain
, HAMMER2_RESOLVE_NEVER
);
811 hammer2_chain_delete(&thr
->trans
, cparent
->array
[i
].chain
, chain
,
812 HAMMER2_DELETE_NOSTATS
|
813 HAMMER2_DELETE_PERMANENT
);
814 hammer2_chain_unlock(chain
);
817 * The element is not valid in that it doesn't match the other
818 * elements, but we have to mark it valid here to allow the
819 * cluster_next() call to advance this index to the next element.
821 cluster
->array
[i
].flags
&= ~HAMMER2_CITEM_INVALID
;
827 * cparent is locked exclusively, with an extra ref, cluster is not locked.
828 * Replace element [i] in the cluster.
832 hammer2_sync_replace(hammer2_syncthr_t
*thr
,
833 hammer2_cluster_t
*cparent
, hammer2_cluster_t
*cluster
,
834 hammer2_tid_t modify_tid
, int i
, int *errors
)
836 hammer2_chain_t
*focus
;
837 hammer2_chain_t
*chain
;
841 focus
= cluster
->focus
;
842 chain
= cluster
->array
[i
].chain
;
843 #if HAMMER2_SYNCTHR_DEBUG
844 if (hammer2_debug
& 1)
845 kprintf("replace rec %p/%p slave %d %d.%016jx mod=%016jx\n",
847 i
, focus
->bref
.type
, focus
->bref
.key
, modify_tid
);
849 if (cluster
->focus_index
< i
)
850 hammer2_chain_lock(focus
, HAMMER2_RESOLVE_ALWAYS
);
851 hammer2_chain_lock(chain
, HAMMER2_RESOLVE_ALWAYS
);
852 if (cluster
->focus_index
>= i
)
853 hammer2_chain_lock(focus
, HAMMER2_RESOLVE_ALWAYS
);
854 if (chain
->bytes
!= focus
->bytes
) {
855 /* XXX what if compressed? */
856 nradix
= hammer2_getradix(chain
->bytes
);
857 hammer2_chain_resize(&thr
->trans
, NULL
,
858 cparent
->array
[i
].chain
, chain
,
861 hammer2_chain_modify(&thr
->trans
, chain
, 0);
862 otype
= chain
->bref
.type
;
863 chain
->bref
.type
= focus
->bref
.type
;
864 chain
->bref
.methods
= focus
->bref
.methods
;
865 chain
->bref
.keybits
= focus
->bref
.keybits
;
866 chain
->bref
.vradix
= focus
->bref
.vradix
;
867 /* mirror_tid updated by flush */
868 chain
->bref
.modify_tid
= modify_tid
;
869 chain
->bref
.flags
= focus
->bref
.flags
;
870 /* key already present */
871 /* check code will be recalculated */
877 switch(chain
->bref
.type
) {
878 case HAMMER2_BREF_TYPE_INODE
:
879 if ((focus
->data
->ipdata
.op_flags
&
880 HAMMER2_OPFLAG_DIRECTDATA
) == 0) {
882 * If DIRECTDATA is transitioning to 0 or the old
883 * chain is not an inode we have to initialize
886 if (otype
!= HAMMER2_BREF_TYPE_INODE
||
887 (chain
->data
->ipdata
.op_flags
&
888 HAMMER2_OPFLAG_DIRECTDATA
)) {
889 kprintf("chain inode transiiton away from dd\n");
890 bzero(&chain
->data
->ipdata
.u
,
891 sizeof(chain
->data
->ipdata
.u
));
893 bcopy(focus
->data
, chain
->data
,
894 offsetof(hammer2_inode_data_t
, u
));
895 /* XXX setcheck on inode should not be needed */
896 hammer2_chain_setcheck(chain
, chain
->data
);
900 case HAMMER2_BREF_TYPE_DATA
:
901 bcopy(focus
->data
, chain
->data
, chain
->bytes
);
902 hammer2_chain_setcheck(chain
, chain
->data
);
909 hammer2_chain_unlock(focus
);
910 hammer2_chain_unlock(chain
);
913 * Must clear invalid for iteration to work properly.
915 cluster
->array
[i
].flags
&= ~HAMMER2_CITEM_INVALID
;