xref: /dragonfly/sys/vfs/hammer2/hammer2_flush.c (revision 837bd39b)
132b800e6SMatthew Dillon /*
28138a154SMatthew Dillon  * Copyright (c) 2011-2014 The DragonFly Project.  All rights reserved.
332b800e6SMatthew Dillon  *
432b800e6SMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
532b800e6SMatthew Dillon  * by Matthew Dillon <dillon@dragonflybsd.org>
632b800e6SMatthew Dillon  * by Venkatesh Srinivas <vsrinivas@dragonflybsd.org>
732b800e6SMatthew Dillon  *
832b800e6SMatthew Dillon  * Redistribution and use in source and binary forms, with or without
932b800e6SMatthew Dillon  * modification, are permitted provided that the following conditions
1032b800e6SMatthew Dillon  * are met:
1132b800e6SMatthew Dillon  *
1232b800e6SMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
1332b800e6SMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
1432b800e6SMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
1532b800e6SMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
1632b800e6SMatthew Dillon  *    the documentation and/or other materials provided with the
1732b800e6SMatthew Dillon  *    distribution.
1832b800e6SMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
1932b800e6SMatthew Dillon  *    contributors may be used to endorse or promote products derived
2032b800e6SMatthew Dillon  *    from this software without specific, prior written permission.
2132b800e6SMatthew Dillon  *
2232b800e6SMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2332b800e6SMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2432b800e6SMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2532b800e6SMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
2632b800e6SMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2732b800e6SMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
2832b800e6SMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2932b800e6SMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
3032b800e6SMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
3132b800e6SMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
3232b800e6SMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3332b800e6SMatthew Dillon  * SUCH DAMAGE.
3432b800e6SMatthew Dillon  */
3532b800e6SMatthew Dillon 
3650456506SMatthew Dillon /*
3750456506SMatthew Dillon  *			TRANSACTION AND FLUSH HANDLING
3850456506SMatthew Dillon  *
3950456506SMatthew Dillon  * Deceptively simple but actually fairly difficult to implement properly is
4050456506SMatthew Dillon  * how I would describe it.
4150456506SMatthew Dillon  *
4250456506SMatthew Dillon  * The biggest problem is that each PFS may belong to a cluster so its
4350456506SMatthew Dillon  * media modify_tid and mirror_tid fields are in a completely different
4450456506SMatthew Dillon  * domain than the topology related to the super-root.  Most of the code
4550456506SMatthew Dillon  * operates using modify_xid and delete_xid which are local identifiers.
4650456506SMatthew Dillon  *
4750456506SMatthew Dillon  * The second biggest problem is that we really want to allow flushes to run
4850456506SMatthew Dillon  * concurrently with new front-end operations, which means that the in-memory
4950456506SMatthew Dillon  * topology of hammer2_chain structures can represent both current state and
5050456506SMatthew Dillon  * snapshot-for-flush state.
5150456506SMatthew Dillon  */
5250456506SMatthew Dillon 
5332b800e6SMatthew Dillon #include <sys/cdefs.h>
5432b800e6SMatthew Dillon #include <sys/param.h>
5532b800e6SMatthew Dillon #include <sys/systm.h>
5632b800e6SMatthew Dillon #include <sys/types.h>
5732b800e6SMatthew Dillon #include <sys/lock.h>
5832b800e6SMatthew Dillon #include <sys/uuid.h>
5932b800e6SMatthew Dillon 
6032b800e6SMatthew Dillon #include "hammer2.h"
6132b800e6SMatthew Dillon 
62925e4ad1SMatthew Dillon #define FLUSH_DEBUG 0
63925e4ad1SMatthew Dillon 
6432b800e6SMatthew Dillon /*
6532b800e6SMatthew Dillon  * Recursively flush the specified chain.  The chain is locked and
6632b800e6SMatthew Dillon  * referenced by the caller and will remain so on return.  The chain
6732b800e6SMatthew Dillon  * will remain referenced throughout but can temporarily lose its
6832b800e6SMatthew Dillon  * lock during the recursion to avoid unnecessarily stalling user
6932b800e6SMatthew Dillon  * processes.
7032b800e6SMatthew Dillon  */
7132b800e6SMatthew Dillon struct hammer2_flush_info {
720dea3156SMatthew Dillon 	hammer2_chain_t *parent;
730dea3156SMatthew Dillon 	hammer2_trans_t	*trans;
7432b800e6SMatthew Dillon 	int		depth;
750dea3156SMatthew Dillon 	int		diddeferral;
761897c66eSMatthew Dillon 	int		cache_index;
77a4dc31e0SMatthew Dillon 	int		domodify;
781897c66eSMatthew Dillon 	struct h2_flush_deferral_list flush_list;
7950456506SMatthew Dillon 	hammer2_xid_t	sync_xid;	/* memory synchronization point */
8032b800e6SMatthew Dillon };
8132b800e6SMatthew Dillon 
8232b800e6SMatthew Dillon typedef struct hammer2_flush_info hammer2_flush_info_t;
8332b800e6SMatthew Dillon 
848138a154SMatthew Dillon static void hammer2_flush_core(hammer2_flush_info_t *info,
858138a154SMatthew Dillon 				hammer2_chain_t **chainp, int deleting);
868138a154SMatthew Dillon static int hammer2_flush_pass1(hammer2_chain_t *child, void *data);
878138a154SMatthew Dillon static int hammer2_flush_pass2(hammer2_chain_t *child, void *data);
888138a154SMatthew Dillon static int hammer2_flush_pass3(hammer2_chain_t *child, void *data);
898138a154SMatthew Dillon static int hammer2_flush_pass4(hammer2_chain_t *child, void *data);
90052e0aa0SMatthew Dillon static int hammer2_flush_pass5(hammer2_chain_t *child, void *data);
9191abd410SMatthew Dillon static void hammer2_rollup_stats(hammer2_chain_t *parent,
9291abd410SMatthew Dillon 				hammer2_chain_t *child, int how);
9332b800e6SMatthew Dillon 
948138a154SMatthew Dillon 
95623d43d4SMatthew Dillon /*
96623d43d4SMatthew Dillon  * Can we ignore a chain for the purposes of flushing modifications
97623d43d4SMatthew Dillon  * to the media?
980924b3f8SMatthew Dillon  *
9959c5121aSMatthew Dillon  * This code is now degenerate.  We used to have to distinguish between
100044541cdSMatthew Dillon  * deleted chains and deleted chains associated with inodes that were
101044541cdSMatthew Dillon  * still open.  This mechanic has been fixed so the function is now
102044541cdSMatthew Dillon  * a simple test.
103623d43d4SMatthew Dillon  */
104623d43d4SMatthew Dillon static __inline
105623d43d4SMatthew Dillon int
106623d43d4SMatthew Dillon h2ignore_deleted(hammer2_flush_info_t *info, hammer2_chain_t *chain)
107623d43d4SMatthew Dillon {
10850456506SMatthew Dillon 	return (chain->delete_xid <= info->sync_xid);
109623d43d4SMatthew Dillon }
110623d43d4SMatthew Dillon 
11193f3933aSMatthew Dillon #if 0
11293f3933aSMatthew Dillon static __inline
11393f3933aSMatthew Dillon void
11493f3933aSMatthew Dillon hammer2_updatestats(hammer2_flush_info_t *info, hammer2_blockref_t *bref,
11593f3933aSMatthew Dillon 		    int how)
11693f3933aSMatthew Dillon {
11793f3933aSMatthew Dillon 	hammer2_key_t bytes;
11893f3933aSMatthew Dillon 
11993f3933aSMatthew Dillon 	if (bref->type != 0) {
12093f3933aSMatthew Dillon 		bytes = 1 << (bref->data_off & HAMMER2_OFF_MASK_RADIX);
12193f3933aSMatthew Dillon 		if (bref->type == HAMMER2_BREF_TYPE_INODE)
12293f3933aSMatthew Dillon 			info->inode_count += how;
12393f3933aSMatthew Dillon 		if (how < 0)
12493f3933aSMatthew Dillon 			info->data_count -= bytes;
12593f3933aSMatthew Dillon 		else
12693f3933aSMatthew Dillon 			info->data_count += bytes;
12793f3933aSMatthew Dillon 	}
12893f3933aSMatthew Dillon }
12993f3933aSMatthew Dillon #endif
13093f3933aSMatthew Dillon 
13132b800e6SMatthew Dillon /*
13250456506SMatthew Dillon  * For now use a global transaction manager.  What we ultimately want to do
13350456506SMatthew Dillon  * is give each non-overlapping hmp/pmp group its own transaction manager.
13450456506SMatthew Dillon  *
13550456506SMatthew Dillon  * Transactions govern XID tracking on the physical media (the hmp), but they
13650456506SMatthew Dillon  * also govern TID tracking which is per-PFS and thus might cross multiple
13750456506SMatthew Dillon  * hmp's.  So we can't just stuff tmanage into hammer2_mount or
13850456506SMatthew Dillon  * hammer2_pfsmount.
13950456506SMatthew Dillon  */
14050456506SMatthew Dillon static hammer2_trans_manage_t	tmanage;
14150456506SMatthew Dillon 
14250456506SMatthew Dillon void
14350456506SMatthew Dillon hammer2_trans_manage_init(void)
14450456506SMatthew Dillon {
14550456506SMatthew Dillon 	lockinit(&tmanage.translk, "h2trans", 0, 0);
14650456506SMatthew Dillon 	TAILQ_INIT(&tmanage.transq);
14750456506SMatthew Dillon 	tmanage.flush_xid = 1;
14850456506SMatthew Dillon 	tmanage.alloc_xid = tmanage.flush_xid + 1;
14950456506SMatthew Dillon }
15050456506SMatthew Dillon 
15150456506SMatthew Dillon hammer2_xid_t
15250456506SMatthew Dillon hammer2_trans_newxid(hammer2_pfsmount_t *pmp __unused)
15350456506SMatthew Dillon {
15450456506SMatthew Dillon 	hammer2_xid_t xid;
15550456506SMatthew Dillon 
15650456506SMatthew Dillon 	for (;;) {
15750456506SMatthew Dillon 		xid = atomic_fetchadd_int(&tmanage.alloc_xid, 1);
15850456506SMatthew Dillon 		if (xid)
15950456506SMatthew Dillon 			break;
16050456506SMatthew Dillon 	}
16150456506SMatthew Dillon 	return xid;
16250456506SMatthew Dillon }
16350456506SMatthew Dillon 
16450456506SMatthew Dillon /*
1650dea3156SMatthew Dillon  * Transaction support functions for writing to the filesystem.
1660dea3156SMatthew Dillon  *
16710136ab6SMatthew Dillon  * Initializing a new transaction allocates a transaction ID.  Typically
16810136ab6SMatthew Dillon  * passed a pmp (hmp passed as NULL), indicating a cluster transaction.  Can
16910136ab6SMatthew Dillon  * be passed a NULL pmp and non-NULL hmp to indicate a transaction on a single
17010136ab6SMatthew Dillon  * media target.  The latter mode is used by the recovery code.
17110136ab6SMatthew Dillon  *
172623d43d4SMatthew Dillon  * TWO TRANSACTION IDs can run concurrently, where one is a flush and the
173623d43d4SMatthew Dillon  * other is a set of any number of concurrent filesystem operations.  We
174623d43d4SMatthew Dillon  * can either have <running_fs_ops> + <waiting_flush> + <blocked_fs_ops>
175623d43d4SMatthew Dillon  * or we can have <running_flush> + <concurrent_fs_ops>.
1760dea3156SMatthew Dillon  *
177623d43d4SMatthew Dillon  * During a flush, new fs_ops are only blocked until the fs_ops prior to
178623d43d4SMatthew Dillon  * the flush complete.  The new fs_ops can then run concurrent with the flush.
179d001f460SMatthew Dillon  *
180623d43d4SMatthew Dillon  * Buffer-cache transactions operate as fs_ops but never block.  A
181623d43d4SMatthew Dillon  * buffer-cache flush will run either before or after the current pending
182623d43d4SMatthew Dillon  * flush depending on its state.
1830dea3156SMatthew Dillon  */
1840dea3156SMatthew Dillon void
18550456506SMatthew Dillon hammer2_trans_init(hammer2_trans_t *trans, hammer2_pfsmount_t *pmp, int flags)
1860dea3156SMatthew Dillon {
18750456506SMatthew Dillon 	hammer2_trans_manage_t *tman;
188a4dc31e0SMatthew Dillon 	hammer2_trans_t *head;
189d001f460SMatthew Dillon 
19050456506SMatthew Dillon 	tman = &tmanage;
191d001f460SMatthew Dillon 
19250456506SMatthew Dillon 	bzero(trans, sizeof(*trans));
19350456506SMatthew Dillon 	trans->pmp = pmp;
194d001f460SMatthew Dillon 	trans->flags = flags;
195d001f460SMatthew Dillon 	trans->td = curthread;
19650456506SMatthew Dillon 
19750456506SMatthew Dillon 	lockmgr(&tman->translk, LK_EXCLUSIVE);
198d001f460SMatthew Dillon 
199d001f460SMatthew Dillon 	if (flags & HAMMER2_TRANS_ISFLUSH) {
200d001f460SMatthew Dillon 		/*
201355d67fcSMatthew Dillon 		 * If multiple flushes are trying to run we have to
202a4dc31e0SMatthew Dillon 		 * wait until it is our turn.  All flushes are serialized.
203355d67fcSMatthew Dillon 		 *
204a4dc31e0SMatthew Dillon 		 * We queue ourselves and then wait to become the head
205a4dc31e0SMatthew Dillon 		 * of the queue, allowing all prior flushes to complete.
206623d43d4SMatthew Dillon 		 *
2078138a154SMatthew Dillon 		 * Multiple normal transactions can share the current
2088138a154SMatthew Dillon 		 * transaction id but a flush transaction needs its own
2098138a154SMatthew Dillon 		 * unique TID for proper block table update accounting.
210355d67fcSMatthew Dillon 		 */
21150456506SMatthew Dillon 		++tman->flushcnt;
21250456506SMatthew Dillon 		++pmp->alloc_tid;
21350456506SMatthew Dillon 		pmp->flush_tid = pmp->alloc_tid;
21450456506SMatthew Dillon 		tman->flush_xid = hammer2_trans_newxid(pmp);
21550456506SMatthew Dillon 		trans->sync_xid = tman->flush_xid;
21650456506SMatthew Dillon 		++pmp->alloc_tid;
21750456506SMatthew Dillon 		TAILQ_INSERT_TAIL(&tman->transq, trans, entry);
21850456506SMatthew Dillon 		if (TAILQ_FIRST(&tman->transq) != trans) {
219d001f460SMatthew Dillon 			trans->blocked = 1;
220d001f460SMatthew Dillon 			while (trans->blocked) {
22150456506SMatthew Dillon 				lksleep(&trans->sync_xid, &tman->translk,
222a4dc31e0SMatthew Dillon 					0, "h2multf", hz);
223d001f460SMatthew Dillon 			}
224d001f460SMatthew Dillon 		}
22550456506SMatthew Dillon 	} else if (tman->flushcnt == 0) {
226a7720be7SMatthew Dillon 		/*
22750456506SMatthew Dillon 		 * No flushes are pending, we can go.  Use prior flush_xid + 1.
22850456506SMatthew Dillon 		 *
22950456506SMatthew Dillon 		 * WARNING!  Also see hammer2_chain_setsubmod()
230a7720be7SMatthew Dillon 		 */
23150456506SMatthew Dillon 		TAILQ_INSERT_TAIL(&tman->transq, trans, entry);
23250456506SMatthew Dillon 		trans->sync_xid = tman->flush_xid + 1;
233a7720be7SMatthew Dillon 
234a4dc31e0SMatthew Dillon 		/* XXX improve/optimize inode allocation */
235052e0aa0SMatthew Dillon 	} else if (trans->flags & HAMMER2_TRANS_BUFCACHE) {
236052e0aa0SMatthew Dillon 		/*
237052e0aa0SMatthew Dillon 		 * A buffer cache transaction is requested while a flush
238052e0aa0SMatthew Dillon 		 * is in progress.  The flush's PREFLUSH flag must be set
239052e0aa0SMatthew Dillon 		 * in this situation.
240052e0aa0SMatthew Dillon 		 *
241052e0aa0SMatthew Dillon 		 * The buffer cache flush takes on the main flush's
242052e0aa0SMatthew Dillon 		 * transaction id.
243052e0aa0SMatthew Dillon 		 */
24450456506SMatthew Dillon 		TAILQ_FOREACH(head, &tman->transq, entry) {
245052e0aa0SMatthew Dillon 			if (head->flags & HAMMER2_TRANS_ISFLUSH)
246052e0aa0SMatthew Dillon 				break;
247052e0aa0SMatthew Dillon 		}
248052e0aa0SMatthew Dillon 		KKASSERT(head);
249052e0aa0SMatthew Dillon 		KKASSERT(head->flags & HAMMER2_TRANS_PREFLUSH);
250052e0aa0SMatthew Dillon 		trans->flags |= HAMMER2_TRANS_PREFLUSH;
25150456506SMatthew Dillon 		TAILQ_INSERT_AFTER(&tman->transq, head, trans, entry);
25250456506SMatthew Dillon 		trans->sync_xid = head->sync_xid;
253052e0aa0SMatthew Dillon 		trans->flags |= HAMMER2_TRANS_CONCURRENT;
254052e0aa0SMatthew Dillon 		/* not allowed to block */
255a4dc31e0SMatthew Dillon 	} else {
256a4dc31e0SMatthew Dillon 		/*
257052e0aa0SMatthew Dillon 		 * A normal transaction is requested while a flush is in
258052e0aa0SMatthew Dillon 		 * progress.  We insert after the current flush and may
25950456506SMatthew Dillon 		 * block.
26050456506SMatthew Dillon 		 *
26150456506SMatthew Dillon 		 * WARNING!  Also see hammer2_chain_setsubmod()
262a4dc31e0SMatthew Dillon 		 */
26350456506SMatthew Dillon 		TAILQ_FOREACH(head, &tman->transq, entry) {
264a4dc31e0SMatthew Dillon 			if (head->flags & HAMMER2_TRANS_ISFLUSH)
265a4dc31e0SMatthew Dillon 				break;
266a7720be7SMatthew Dillon 		}
267a4dc31e0SMatthew Dillon 		KKASSERT(head);
26850456506SMatthew Dillon 		TAILQ_INSERT_AFTER(&tman->transq, head, trans, entry);
26950456506SMatthew Dillon 		trans->sync_xid = head->sync_xid + 1;
2708138a154SMatthew Dillon 		trans->flags |= HAMMER2_TRANS_CONCURRENT;
271a4dc31e0SMatthew Dillon 
2728138a154SMatthew Dillon 		/*
273052e0aa0SMatthew Dillon 		 * XXX for now we must block new transactions, synchronous
274052e0aa0SMatthew Dillon 		 * flush mode is on by default.
275052e0aa0SMatthew Dillon 		 *
2768138a154SMatthew Dillon 		 * If synchronous flush mode is enabled concurrent
2778138a154SMatthew Dillon 		 * frontend transactions during the flush are not
2788138a154SMatthew Dillon 		 * allowed (except we don't have a choice for buffer
2798138a154SMatthew Dillon 		 * cache ops).
2808138a154SMatthew Dillon 		 */
2818138a154SMatthew Dillon 		if (hammer2_synchronous_flush > 0 ||
28250456506SMatthew Dillon 		    TAILQ_FIRST(&tman->transq) != head) {
283a4dc31e0SMatthew Dillon 			trans->blocked = 1;
284a4dc31e0SMatthew Dillon 			while (trans->blocked) {
28550456506SMatthew Dillon 				lksleep(&trans->sync_xid,
28650456506SMatthew Dillon 					&tman->translk, 0,
287a4dc31e0SMatthew Dillon 					"h2multf", hz);
288a4dc31e0SMatthew Dillon 			}
289a4dc31e0SMatthew Dillon 		}
290a4dc31e0SMatthew Dillon 	}
291044541cdSMatthew Dillon 	if (flags & HAMMER2_TRANS_NEWINODE) {
29250456506SMatthew Dillon 		if (pmp->spmp_hmp) {
29350456506SMatthew Dillon 			/*
29450456506SMatthew Dillon 			 * Super-root transaction, all new inodes have an
29550456506SMatthew Dillon 			 * inode number of 1.  Normal pfs inode cache
29650456506SMatthew Dillon 			 * semantics are not used.
29750456506SMatthew Dillon 			 */
29850456506SMatthew Dillon 			trans->inode_tid = 1;
29950456506SMatthew Dillon 		} else {
30050456506SMatthew Dillon 			/*
30150456506SMatthew Dillon 			 * Normal transaction
30250456506SMatthew Dillon 			 */
30350456506SMatthew Dillon 			if (pmp->inode_tid < HAMMER2_INODE_START)
30450456506SMatthew Dillon 				pmp->inode_tid = HAMMER2_INODE_START;
30550456506SMatthew Dillon 			trans->inode_tid = pmp->inode_tid++;
306044541cdSMatthew Dillon 		}
30750456506SMatthew Dillon 	}
30850456506SMatthew Dillon 
30950456506SMatthew Dillon 	lockmgr(&tman->translk, LK_RELEASE);
310a7720be7SMatthew Dillon }
311a7720be7SMatthew Dillon 
3120dea3156SMatthew Dillon void
3130dea3156SMatthew Dillon hammer2_trans_done(hammer2_trans_t *trans)
3140dea3156SMatthew Dillon {
31550456506SMatthew Dillon 	hammer2_trans_manage_t *tman;
316a4dc31e0SMatthew Dillon 	hammer2_trans_t *head;
317d001f460SMatthew Dillon 	hammer2_trans_t *scan;
318a02dfba1SMatthew Dillon 
31950456506SMatthew Dillon 	tman = &tmanage;
320a5913bdfSMatthew Dillon 
321a4dc31e0SMatthew Dillon 	/*
3228138a154SMatthew Dillon 	 * Remove.
323a4dc31e0SMatthew Dillon 	 */
32450456506SMatthew Dillon 	lockmgr(&tman->translk, LK_EXCLUSIVE);
32550456506SMatthew Dillon 	TAILQ_REMOVE(&tman->transq, trans, entry);
32650456506SMatthew Dillon 	head = TAILQ_FIRST(&tman->transq);
3278138a154SMatthew Dillon 
3288138a154SMatthew Dillon 	/*
3298138a154SMatthew Dillon 	 * Adjust flushcnt if this was a flush, clear TRANS_CONCURRENT
3308138a154SMatthew Dillon 	 * up through the next flush.  (If the head is a flush then we
3318138a154SMatthew Dillon 	 * stop there, unlike the unblock code following this section).
3328138a154SMatthew Dillon 	 */
3338138a154SMatthew Dillon 	if (trans->flags & HAMMER2_TRANS_ISFLUSH) {
33450456506SMatthew Dillon 		--tman->flushcnt;
3358138a154SMatthew Dillon 		scan = head;
3368138a154SMatthew Dillon 		while (scan && (scan->flags & HAMMER2_TRANS_ISFLUSH) == 0) {
3378138a154SMatthew Dillon 			atomic_clear_int(&scan->flags,
3388138a154SMatthew Dillon 					 HAMMER2_TRANS_CONCURRENT);
339052e0aa0SMatthew Dillon 			scan = TAILQ_NEXT(scan, entry);
3408138a154SMatthew Dillon 		}
3418138a154SMatthew Dillon 	}
342a4dc31e0SMatthew Dillon 
343355d67fcSMatthew Dillon 	/*
344a4dc31e0SMatthew Dillon 	 * Unblock the head of the queue and any additional transactions
3458138a154SMatthew Dillon 	 * up to the next flush.  The head can be a flush and it will be
3468138a154SMatthew Dillon 	 * unblocked along with the non-flush transactions following it
3478138a154SMatthew Dillon 	 * (which are allowed to run concurrently with it).
3488138a154SMatthew Dillon 	 *
3498138a154SMatthew Dillon 	 * In synchronous flush mode we stop if the head transaction is
3508138a154SMatthew Dillon 	 * a flush.
351355d67fcSMatthew Dillon 	 */
352a4dc31e0SMatthew Dillon 	if (head && head->blocked) {
353a4dc31e0SMatthew Dillon 		head->blocked = 0;
35450456506SMatthew Dillon 		wakeup(&head->sync_xid);
355a4dc31e0SMatthew Dillon 
3568138a154SMatthew Dillon 		if (hammer2_synchronous_flush > 0)
3578138a154SMatthew Dillon 			scan = head;
3588138a154SMatthew Dillon 		else
359a4dc31e0SMatthew Dillon 			scan = TAILQ_NEXT(head, entry);
360a4dc31e0SMatthew Dillon 		while (scan && (scan->flags & HAMMER2_TRANS_ISFLUSH) == 0) {
361925e4ad1SMatthew Dillon 			if (scan->blocked) {
362a4dc31e0SMatthew Dillon 				scan->blocked = 0;
36350456506SMatthew Dillon 				wakeup(&scan->sync_xid);
364925e4ad1SMatthew Dillon 			}
365a4dc31e0SMatthew Dillon 			scan = TAILQ_NEXT(scan, entry);
366a02dfba1SMatthew Dillon 		}
367a02dfba1SMatthew Dillon 	}
36850456506SMatthew Dillon 	lockmgr(&tman->translk, LK_RELEASE);
369a02dfba1SMatthew Dillon }
370a02dfba1SMatthew Dillon 
3710dea3156SMatthew Dillon /*
3720dea3156SMatthew Dillon  * Flush the chain and all modified sub-chains through the specified
37350456506SMatthew Dillon  * synchronization point, propagating parent chain modifications and
37450456506SMatthew Dillon  * mirror_tid updates back up as needed.  Since we are recursing downward
3750dea3156SMatthew Dillon  * we do not have to deal with the complexities of multi-homed chains (chains
3760dea3156SMatthew Dillon  * with multiple parents).
3770dea3156SMatthew Dillon  *
3780dea3156SMatthew Dillon  * Caller must have interlocked against any non-flush-related modifying
37950456506SMatthew Dillon  * operations in progress whos modify_xid values are less than or equal
38050456506SMatthew Dillon  * to the passed sync_xid.
3810dea3156SMatthew Dillon  *
3820dea3156SMatthew Dillon  * Caller must have already vetted synchronization points to ensure they
3830dea3156SMatthew Dillon  * are properly flushed.  Only snapshots and cluster flushes can create
3840dea3156SMatthew Dillon  * these sorts of synchronization points.
3850dea3156SMatthew Dillon  *
38632b800e6SMatthew Dillon  * This routine can be called from several places but the most important
3878138a154SMatthew Dillon  * is from VFS_SYNC.
38832b800e6SMatthew Dillon  *
3890dea3156SMatthew Dillon  * chain is locked on call and will remain locked on return.  If a flush
3908138a154SMatthew Dillon  * occured, the chain's FLUSH_CREATE and/or FLUSH_DELETE bit will be set
3918138a154SMatthew Dillon  * indicating that its parent (which is not part of the flush) should be
3928138a154SMatthew Dillon  * updated.  The chain may be replaced by the call if it was modified.
39332b800e6SMatthew Dillon  */
39432b800e6SMatthew Dillon void
3958138a154SMatthew Dillon hammer2_flush(hammer2_trans_t *trans, hammer2_chain_t **chainp)
39632b800e6SMatthew Dillon {
397a7720be7SMatthew Dillon 	hammer2_chain_t *chain = *chainp;
39832b800e6SMatthew Dillon 	hammer2_chain_t *scan;
399731b2a84SMatthew Dillon 	hammer2_chain_core_t *core;
40032b800e6SMatthew Dillon 	hammer2_flush_info_t info;
401925e4ad1SMatthew Dillon 	int loops;
40232b800e6SMatthew Dillon 
40332b800e6SMatthew Dillon 	/*
40432b800e6SMatthew Dillon 	 * Execute the recursive flush and handle deferrals.
40532b800e6SMatthew Dillon 	 *
40632b800e6SMatthew Dillon 	 * Chains can be ridiculously long (thousands deep), so to
40732b800e6SMatthew Dillon 	 * avoid blowing out the kernel stack the recursive flush has a
40832b800e6SMatthew Dillon 	 * depth limit.  Elements at the limit are placed on a list
40932b800e6SMatthew Dillon 	 * for re-execution after the stack has been popped.
41032b800e6SMatthew Dillon 	 */
41132b800e6SMatthew Dillon 	bzero(&info, sizeof(info));
41232b800e6SMatthew Dillon 	TAILQ_INIT(&info.flush_list);
4130dea3156SMatthew Dillon 	info.trans = trans;
41450456506SMatthew Dillon 	info.sync_xid = trans->sync_xid;
4151897c66eSMatthew Dillon 	info.cache_index = -1;
41632b800e6SMatthew Dillon 
417731b2a84SMatthew Dillon 	core = chain->core;
418731b2a84SMatthew Dillon 
419a7720be7SMatthew Dillon 	/*
420a7720be7SMatthew Dillon 	 * Extra ref needed because flush_core expects it when replacing
421a7720be7SMatthew Dillon 	 * chain.
422a7720be7SMatthew Dillon 	 */
423a7720be7SMatthew Dillon 	hammer2_chain_ref(chain);
424925e4ad1SMatthew Dillon 	loops = 0;
425a7720be7SMatthew Dillon 
4260dea3156SMatthew Dillon 	for (;;) {
42732b800e6SMatthew Dillon 		/*
4280dea3156SMatthew Dillon 		 * Unwind deep recursions which had been deferred.  This
4298138a154SMatthew Dillon 		 * can leave the FLUSH_* bits set for these chains, which
4308138a154SMatthew Dillon 		 * will be handled when we [re]flush chain after the unwind.
43132b800e6SMatthew Dillon 		 */
43232b800e6SMatthew Dillon 		while ((scan = TAILQ_FIRST(&info.flush_list)) != NULL) {
43332b800e6SMatthew Dillon 			KKASSERT(scan->flags & HAMMER2_CHAIN_DEFERRED);
43432b800e6SMatthew Dillon 			TAILQ_REMOVE(&info.flush_list, scan, flush_node);
43532b800e6SMatthew Dillon 			atomic_clear_int(&scan->flags, HAMMER2_CHAIN_DEFERRED);
43632b800e6SMatthew Dillon 
43732b800e6SMatthew Dillon 			/*
43832b800e6SMatthew Dillon 			 * Now that we've popped back up we can do a secondary
43932b800e6SMatthew Dillon 			 * recursion on the deferred elements.
440053e752cSMatthew Dillon 			 *
4418138a154SMatthew Dillon 			 * NOTE: hammer2_flush() may replace scan.
44232b800e6SMatthew Dillon 			 */
44332b800e6SMatthew Dillon 			if (hammer2_debug & 0x0040)
444053e752cSMatthew Dillon 				kprintf("deferred flush %p\n", scan);
4450dea3156SMatthew Dillon 			hammer2_chain_lock(scan, HAMMER2_RESOLVE_MAYBE);
446053e752cSMatthew Dillon 			hammer2_chain_drop(scan);	/* ref from deferral */
4478138a154SMatthew Dillon 			hammer2_flush(trans, &scan);
4480dea3156SMatthew Dillon 			hammer2_chain_unlock(scan);
44932b800e6SMatthew Dillon 		}
45032b800e6SMatthew Dillon 
45132b800e6SMatthew Dillon 		/*
452925e4ad1SMatthew Dillon 		 * [re]flush chain.
45332b800e6SMatthew Dillon 		 */
4540dea3156SMatthew Dillon 		info.diddeferral = 0;
4558138a154SMatthew Dillon 		hammer2_flush_core(&info, &chain, 0);
45632b800e6SMatthew Dillon 
45732b800e6SMatthew Dillon 		/*
4580dea3156SMatthew Dillon 		 * Only loop if deep recursions have been deferred.
45932b800e6SMatthew Dillon 		 */
4600dea3156SMatthew Dillon 		if (TAILQ_EMPTY(&info.flush_list))
46132b800e6SMatthew Dillon 			break;
462925e4ad1SMatthew Dillon 
463925e4ad1SMatthew Dillon 		if (++loops % 1000 == 0) {
4648138a154SMatthew Dillon 			kprintf("hammer2_flush: excessive loops on %p\n",
465925e4ad1SMatthew Dillon 				chain);
466925e4ad1SMatthew Dillon 			if (hammer2_debug & 0x100000)
467925e4ad1SMatthew Dillon 				Debugger("hell4");
468925e4ad1SMatthew Dillon 		}
46932b800e6SMatthew Dillon 	}
470a7720be7SMatthew Dillon 	hammer2_chain_drop(chain);
471a7720be7SMatthew Dillon 	*chainp = chain;
47232b800e6SMatthew Dillon }
47332b800e6SMatthew Dillon 
474476d2aadSMatthew Dillon /*
475ea155208SMatthew Dillon  * This is the core of the chain flushing code.  The chain is locked by the
476a7720be7SMatthew Dillon  * caller and must also have an extra ref on it by the caller, and remains
4778138a154SMatthew Dillon  * locked and will have an extra ref on return.  Upon return, the caller can
4788138a154SMatthew Dillon  * test the FLUSH_CREATE and FLUSH_DELETE bits to determine what action must
4798138a154SMatthew Dillon  * be taken on the parent.
480a7720be7SMatthew Dillon  *
4818138a154SMatthew Dillon  * (1) Determine if this node is a candidate for the flush, return if it is
4828138a154SMatthew Dillon  *     not.  fchain and vchain are always candidates for the flush.
4830dea3156SMatthew Dillon  *
4848138a154SMatthew Dillon  * (2) If we recurse too deep the chain is entered onto the deferral list and
4858138a154SMatthew Dillon  *     the current flush stack is aborted until after the deferral list is
4868138a154SMatthew Dillon  *     run.
4878138a154SMatthew Dillon  *
4888138a154SMatthew Dillon  * (3) Recursively flush live children (rbtree).  This can create deferrals.
4898138a154SMatthew Dillon  *     A successful flush clears the MODIFIED bit in the children.
4908138a154SMatthew Dillon  *
4918138a154SMatthew Dillon  * (4) Recursively flush deleted children (dbtree).  Deletions may be
4928138a154SMatthew Dillon  *     considered 'live' if the delete_tid is beyond the flush_tid.  If
4938138a154SMatthew Dillon  *     considered 'dead' the recursion is still needed in order to clean
4948138a154SMatthew Dillon  *     up the chain.  This can create deferrals.
4958138a154SMatthew Dillon  *
4968138a154SMatthew Dillon  *     A successful flush clears the MODIFIED bit in the children.
4978138a154SMatthew Dillon  *
4988138a154SMatthew Dillon  * (5) Calculate block table updates on chain based on the children scans
4998138a154SMatthew Dillon  *     in (3) and (4) by testing the FLUSH_CREATE and FLUSH_DELETE bits,
5008138a154SMatthew Dillon  *     modifying chain if necessary to perform the block table updates.
5018138a154SMatthew Dillon  *     Deletions must be removed from dbtree when removed from the
5028138a154SMatthew Dillon  *     chain's block table.
5038138a154SMatthew Dillon  *
5048138a154SMatthew Dillon  *     If 'chain' itself is marked DELETED but treated as live, the block
5058138a154SMatthew Dillon  *     table update(s) must be propagated to all contemporary chains.  In
5068138a154SMatthew Dillon  *     fact, all contemporary chains must be locked and updated uninterrupted
5078138a154SMatthew Dillon  *     to avoid lookup races.  Once MODIFIED and FLUSH_CREATE is cleared,
5088138a154SMatthew Dillon  *     a chain can be unloaded from memory with the expectation that it can
5098138a154SMatthew Dillon  *     be reloaded later via the block table at any time.
5108138a154SMatthew Dillon  *
51150456506SMatthew Dillon  *			WARNING ON BREF MODIFY_TID/MIRROR_TID
512925e4ad1SMatthew Dillon  *
51350456506SMatthew Dillon  * blockref.modify_tid and blockref.mirror_tid are consistent only within a
51450456506SMatthew Dillon  * PFS.  This is why we cannot cache sync_tid in the transaction structure.
51550456506SMatthew Dillon  * Instead we access it from the pmp.
516476d2aadSMatthew Dillon  */
51732b800e6SMatthew Dillon static void
5188138a154SMatthew Dillon hammer2_flush_core(hammer2_flush_info_t *info, hammer2_chain_t **chainp,
5198138a154SMatthew Dillon 		   int deleting)
52032b800e6SMatthew Dillon {
521a7720be7SMatthew Dillon 	hammer2_chain_t *chain = *chainp;
5220924b3f8SMatthew Dillon 	hammer2_chain_t *saved_parent;
5230dea3156SMatthew Dillon 	hammer2_mount_t *hmp;
524*837bd39bSMatthew Dillon 	hammer2_pfsmount_t *pmp;
525731b2a84SMatthew Dillon 	hammer2_chain_core_t *core;
526925e4ad1SMatthew Dillon 	int diddeferral;
5278138a154SMatthew Dillon 	int saved_domodify;
52832b800e6SMatthew Dillon 
529a5913bdfSMatthew Dillon 	hmp = chain->hmp;
530*837bd39bSMatthew Dillon 	pmp = chain->pmp;
531925e4ad1SMatthew Dillon 	core = chain->core;
532925e4ad1SMatthew Dillon 	diddeferral = info->diddeferral;
53332b800e6SMatthew Dillon 
53432b800e6SMatthew Dillon 	/*
5358138a154SMatthew Dillon 	 * (1) Check if we even have any work to do.
536925e4ad1SMatthew Dillon 	 *
537925e4ad1SMatthew Dillon 	 * This bit of code is capable of short-cutting entire sub-trees
5388138a154SMatthew Dillon 	 * if they have not been touched or if they have already been
5398138a154SMatthew Dillon 	 * flushed.
540925e4ad1SMatthew Dillon 	 */
5418138a154SMatthew Dillon 	if (/*(chain->flags & HAMMER2_CHAIN_MODIFIED) == 0 &&*/
54250456506SMatthew Dillon 	    (chain->update_xlo >= info->sync_xid ||	/* already synced */
54350456506SMatthew Dillon 	     chain->update_xlo >= chain->update_xhi)) {	/* old/unchanged */
54450456506SMatthew Dillon 		/* update_xlo/_xhi already filters chain out, do not update */
5458138a154SMatthew Dillon 		/* don't update bref.mirror_tid, pass2 is not called */
546925e4ad1SMatthew Dillon 		return;
547925e4ad1SMatthew Dillon 	}
548925e4ad1SMatthew Dillon 
549925e4ad1SMatthew Dillon 	/*
5508138a154SMatthew Dillon 	 * mirror_tid should not be forward-indexed
5510924b3f8SMatthew Dillon 	 */
552*837bd39bSMatthew Dillon 	KKASSERT(chain->bref.mirror_tid <= pmp->flush_tid);
5530924b3f8SMatthew Dillon 
5540924b3f8SMatthew Dillon 	/*
555731b2a84SMatthew Dillon 	 * Ignore chains modified beyond the current flush point.  These
556a4dc31e0SMatthew Dillon 	 * will be treated as if they did not exist.  Subchains with lower
55750456506SMatthew Dillon 	 * modify_xid's will still be accessible via other parents.
558a4dc31e0SMatthew Dillon 	 *
559925e4ad1SMatthew Dillon 	 * Do not update bref.mirror_tid here, it will interfere with
560925e4ad1SMatthew Dillon 	 * synchronization.  e.g. inode flush tid 1, concurrent D-D tid 2,
561925e4ad1SMatthew Dillon 	 * then later on inode flush tid 2.  If we were to set mirror_tid
562925e4ad1SMatthew Dillon 	 * to 1 during inode flush tid 1 the blockrefs would only be partially
563925e4ad1SMatthew Dillon 	 * updated (and likely panic).
564925e4ad1SMatthew Dillon 	 *
56550456506SMatthew Dillon 	 * We must update chain->update_xlo here to prevent re-entry in this
5668138a154SMatthew Dillon 	 * flush transaction.
567925e4ad1SMatthew Dillon 	 *
568a4dc31e0SMatthew Dillon 	 * (vchain and fchain are exceptions since they cannot be duplicated)
569ea155208SMatthew Dillon 	 */
57050456506SMatthew Dillon 	if (chain->modify_xid > info->sync_xid &&
571a4dc31e0SMatthew Dillon 	    chain != &hmp->fchain && chain != &hmp->vchain) {
5728138a154SMatthew Dillon 		/* do not update bref.mirror_tid, pass2 ignores chain */
57350456506SMatthew Dillon 		/* chain->update_xlo = info->sync_xid; */
574925e4ad1SMatthew Dillon 		return;
575925e4ad1SMatthew Dillon 	}
576ea155208SMatthew Dillon 
577ea155208SMatthew Dillon 	/*
5788138a154SMatthew Dillon 	 * (2) Recurse downward and check recursion depth.
5798138a154SMatthew Dillon 	 * (3) Flush live children
5808138a154SMatthew Dillon 	 * (4) Flush deleted children
5818138a154SMatthew Dillon 	 *
58250456506SMatthew Dillon 	 * We adjust update_xlo if not deferring chain to prevent re-entry
5838138a154SMatthew Dillon 	 * in this flush cycle, but it must be set AFTER the flush in case
5848138a154SMatthew Dillon 	 * a deeper flush hits the chain.  Otherwise the deeper flush cannot
5858138a154SMatthew Dillon 	 * complete.  We re-check the condition after finishing the flushes.
58632b800e6SMatthew Dillon 	 *
58750456506SMatthew Dillon 	 * update_xhi was already checked and prevents initial recursions on
588925e4ad1SMatthew Dillon 	 * subtrees which have not been modified.
58932b800e6SMatthew Dillon 	 */
5908138a154SMatthew Dillon 	saved_parent = info->parent;
591a4dc31e0SMatthew Dillon 	saved_domodify = info->domodify;
5928138a154SMatthew Dillon 	info->parent = chain;
593a4dc31e0SMatthew Dillon 	info->domodify = 0;
59432b800e6SMatthew Dillon 
595925e4ad1SMatthew Dillon 	if (chain->flags & HAMMER2_CHAIN_DEFERRED) {
596925e4ad1SMatthew Dillon 		++info->diddeferral;
597925e4ad1SMatthew Dillon 	} else if (info->depth == HAMMER2_FLUSH_DEPTH_LIMIT) {
5980dea3156SMatthew Dillon 		if ((chain->flags & HAMMER2_CHAIN_DEFERRED) == 0) {
5990dea3156SMatthew Dillon 			hammer2_chain_ref(chain);
6000dea3156SMatthew Dillon 			TAILQ_INSERT_TAIL(&info->flush_list,
6010dea3156SMatthew Dillon 					  chain, flush_node);
6020dea3156SMatthew Dillon 			atomic_set_int(&chain->flags,
6030dea3156SMatthew Dillon 				       HAMMER2_CHAIN_DEFERRED);
6040dea3156SMatthew Dillon 		}
605925e4ad1SMatthew Dillon 		++info->diddeferral;
60632b800e6SMatthew Dillon 	} else {
6078138a154SMatthew Dillon 		hammer2_chain_t *scan;
6088138a154SMatthew Dillon 
6098138a154SMatthew Dillon 		/*
6108138a154SMatthew Dillon 		 * The flush is queue-agnostic when running pass1, but order
6118138a154SMatthew Dillon 		 * is important to catch any races where an existing
6128138a154SMatthew Dillon 		 * flush-visible child is moved from rbtree->dbtree/dbq.
6138138a154SMatthew Dillon 		 *
6148138a154SMatthew Dillon 		 * New children added by concurrent operations are not visible
6158138a154SMatthew Dillon 		 * to the flush anyway so we don't care about those races.
6168138a154SMatthew Dillon 		 * However, the flush itself can move a child from dbq to
6178138a154SMatthew Dillon 		 * dbtree (rare in pass1 but it is possible).
6188138a154SMatthew Dillon 		 *
6198138a154SMatthew Dillon 		 * pass1 can handle re-execution of a child.
6208138a154SMatthew Dillon 		 */
621731b2a84SMatthew Dillon 		spin_lock(&core->cst.spin);
62251a0d27cSMatthew Dillon 		KKASSERT(core->good == 0x1234 && core->sharecnt > 0);
6238138a154SMatthew Dillon 		RB_SCAN(hammer2_chain_tree, &core->rbtree,
6248138a154SMatthew Dillon 			NULL, hammer2_flush_pass1, info);
6258138a154SMatthew Dillon 		RB_SCAN(hammer2_chain_tree, &core->dbtree,
6268138a154SMatthew Dillon 			NULL, hammer2_flush_pass1, info);
6278138a154SMatthew Dillon 		scan = TAILQ_FIRST(&core->dbq);
6288138a154SMatthew Dillon 		while (scan) {
6298138a154SMatthew Dillon 			KKASSERT(scan->flags & HAMMER2_CHAIN_ONDBQ);
6308138a154SMatthew Dillon 			hammer2_flush_pass1(scan, info);
6318138a154SMatthew Dillon 			if (scan->flags & HAMMER2_CHAIN_ONDBQ)
6328138a154SMatthew Dillon 				scan = TAILQ_NEXT(scan, db_entry);
6338138a154SMatthew Dillon 			else
6348138a154SMatthew Dillon 				scan = TAILQ_FIRST(&core->dbq);
63532b800e6SMatthew Dillon 		}
6361897c66eSMatthew Dillon 		spin_unlock(&core->cst.spin);
6371897c66eSMatthew Dillon 	}
63832b800e6SMatthew Dillon 
6398138a154SMatthew Dillon 	/*
64050456506SMatthew Dillon 	 * Stop if deferred, do not update update_xlo.
6418138a154SMatthew Dillon 	 */
64250456506SMatthew Dillon 	if (info->diddeferral) {
6438138a154SMatthew Dillon 		goto done;
64450456506SMatthew Dillon 	}
645925e4ad1SMatthew Dillon 
646925e4ad1SMatthew Dillon 	/*
6478138a154SMatthew Dillon 	 * If a block table update is needed place the parent in a modified
6488138a154SMatthew Dillon 	 * state, which might delete-duplicate it.
649623d43d4SMatthew Dillon 	 *
65050456506SMatthew Dillon 	 * - To prevent loops and other confusion, we synchronize update_xlo
6518138a154SMatthew Dillon 	 *   for the original chain.
652623d43d4SMatthew Dillon 	 *
6538138a154SMatthew Dillon 	 * - The original parent will not be used by the flush so we can
6548138a154SMatthew Dillon 	 *   clear its MODIFIED bit.
655925e4ad1SMatthew Dillon 	 */
6568138a154SMatthew Dillon 	if (info->domodify) {
65750456506SMatthew Dillon 		hammer2_chain_modify(info->trans, &info->parent, 0);
658a4dc31e0SMatthew Dillon 		if (info->parent != chain) {
6590924b3f8SMatthew Dillon 			/*
6608138a154SMatthew Dillon 			 * chain	- old
6618138a154SMatthew Dillon 			 * info->parent - new
6628138a154SMatthew Dillon 			 *
6630924b3f8SMatthew Dillon 			 * NOTE: bref.mirror_tid cannot be updated
6640924b3f8SMatthew Dillon 			 *	 unless MODIFIED is cleared or already
6650924b3f8SMatthew Dillon 			 *	 clear.
6660924b3f8SMatthew Dillon 			 */
6678138a154SMatthew Dillon 			chain->inode_reason += 0x10000000;
6688138a154SMatthew Dillon 			info->parent->inode_reason += 0x100;
6698138a154SMatthew Dillon 			KKASSERT(info->parent->core == chain->core);
6700924b3f8SMatthew Dillon 			if (chain->flags & HAMMER2_CHAIN_MODIFIED) {
6710924b3f8SMatthew Dillon 				atomic_clear_int(&chain->flags,
6720924b3f8SMatthew Dillon 						HAMMER2_CHAIN_MODIFIED);
673*837bd39bSMatthew Dillon 				hammer2_pfs_memory_wakeup(pmp);
6740924b3f8SMatthew Dillon 				hammer2_chain_drop(chain);
6750924b3f8SMatthew Dillon 			}
6768138a154SMatthew Dillon #if 0
6778138a154SMatthew Dillon 			if (chain->flags & HAMMER2_CHAIN_FLUSH_CREATE) {
6788138a154SMatthew Dillon 				atomic_clear_int(&chain->flags,
6798138a154SMatthew Dillon 						HAMMER2_CHAIN_FLUSH_CREATE);
6808138a154SMatthew Dillon 				hammer2_chain_drop(chain);
6818138a154SMatthew Dillon 			}
6828138a154SMatthew Dillon 			if (info->parent->flags & HAMMER2_CHAIN_FLUSH_DELETE) {
6838138a154SMatthew Dillon 				atomic_clear_int(&info->parent->flags,
6848138a154SMatthew Dillon 						HAMMER2_CHAIN_FLUSH_DELETE);
6858138a154SMatthew Dillon 				hammer2_chain_drop(info->parent);
6868138a154SMatthew Dillon 			}
6878138a154SMatthew Dillon #endif
68850456506SMatthew Dillon 			if (chain->update_xlo < info->sync_xid)
68950456506SMatthew Dillon 				chain->update_xlo = info->sync_xid;
69050456506SMatthew Dillon 			KKASSERT(info->parent->update_xlo < info->sync_xid);
691a4dc31e0SMatthew Dillon 			hammer2_chain_drop(chain);
692a4dc31e0SMatthew Dillon 			hammer2_chain_ref(info->parent);
693a4dc31e0SMatthew Dillon 		}
694a4dc31e0SMatthew Dillon 		chain = info->parent;
695a4dc31e0SMatthew Dillon 	}
696a7720be7SMatthew Dillon 
69732b800e6SMatthew Dillon 	/*
6988138a154SMatthew Dillon 	 * If a blocktable update is needed determine if this is the last
6998138a154SMatthew Dillon 	 * parent requiring modification (check all parents using the core).
70032b800e6SMatthew Dillon 	 *
7018138a154SMatthew Dillon 	 * Set bit 1 (0x02) of domodify if this is the last parent,
7028138a154SMatthew Dillon 	 * which will cause scan2 to clear FLUSH_CREATE and FLUSH_DELETE.
70332b800e6SMatthew Dillon 	 */
7048138a154SMatthew Dillon 	if (1) {
7058138a154SMatthew Dillon 		hammer2_chain_t *scan;
7068138a154SMatthew Dillon 
707731b2a84SMatthew Dillon 		spin_lock(&core->cst.spin);
7088138a154SMatthew Dillon 		TAILQ_FOREACH(scan, &core->ownerq, core_entry) {
7098138a154SMatthew Dillon 			/*
7108138a154SMatthew Dillon 			 * Ignore the current parent being processed (we do
71150456506SMatthew Dillon 			 * not adjust update_xlo until after the fixup).
712a7720be7SMatthew Dillon 			 */
7138138a154SMatthew Dillon 			if (scan == chain)
7148138a154SMatthew Dillon 				continue;
715a4dc31e0SMatthew Dillon 
7168138a154SMatthew Dillon 			/*
71750456506SMatthew Dillon 			 * Ignore chains which have already been updated
71850456506SMatthew Dillon 			 * Ignore unmodified chains (lo >= hi).
71950456506SMatthew Dillon 			 */
72050456506SMatthew Dillon 			if ((scan->flags & HAMMER2_CHAIN_MODIFIED) == 0 &&
72150456506SMatthew Dillon 			    (scan->update_xlo >= info->sync_xid ||
72250456506SMatthew Dillon 			     scan->update_xlo >= scan->update_xhi)) {
72350456506SMatthew Dillon 				continue;
72450456506SMatthew Dillon 			}
72550456506SMatthew Dillon 
72650456506SMatthew Dillon 			/*
7278138a154SMatthew Dillon 			 * Cannot exhaust all parents if one is not visible
7288138a154SMatthew Dillon 			 * to the flush.  The root chains are special-cased
7298138a154SMatthew Dillon 			 * because they cannot really be delete-duplicated.
7308138a154SMatthew Dillon 			 */
7318138a154SMatthew Dillon 			if (scan != &scan->hmp->fchain &&
7328138a154SMatthew Dillon 			    scan != &scan->hmp->vchain &&
73350456506SMatthew Dillon 			    scan->modify_xid > info->sync_xid) {
7348138a154SMatthew Dillon 				break;
7358138a154SMatthew Dillon 			}
736a7720be7SMatthew Dillon 
7378138a154SMatthew Dillon 			/*
73850456506SMatthew Dillon 			 * Fail if update_xlo has not been synchronized to
73950456506SMatthew Dillon 			 * at least our sync_xid on any modified parent chain.
7408138a154SMatthew Dillon 			 */
74150456506SMatthew Dillon 			if (scan->update_xlo < info->sync_xid)
7428138a154SMatthew Dillon 				break;
7438138a154SMatthew Dillon 		}
744a7720be7SMatthew Dillon 		spin_unlock(&core->cst.spin);
7458138a154SMatthew Dillon 		if (scan == NULL)
7468138a154SMatthew Dillon 			info->domodify |= 2;
74732b800e6SMatthew Dillon 	}
74832b800e6SMatthew Dillon 
7498138a154SMatthew Dillon 	/*
7508138a154SMatthew Dillon 	 * (5) Calculate block table updates or child cleanups.
7518138a154SMatthew Dillon 	 *     (this whole operation has to be atomic)
7528138a154SMatthew Dillon 	 *
7538138a154SMatthew Dillon 	 * domodify 0x01 - block table updates
7548138a154SMatthew Dillon 	 * 	    0x02 - child cleanups
7558138a154SMatthew Dillon 	 *
7568138a154SMatthew Dillon 	 *	pass2 - Process deletions from dbtree and dbq.
7578138a154SMatthew Dillon 	 *	pass3 - Process insertions from rbtree, dbtree, and dbq.
7588138a154SMatthew Dillon 	 *	pass4 - Cleanup child flags on the last parent and
759052e0aa0SMatthew Dillon 	 *		Adjust queues on the live parent (deletions).
760052e0aa0SMatthew Dillon 	 *	pass5 - Cleanup child flags on the last parent and
761052e0aa0SMatthew Dillon 	 *		Adjust queues on the live parent (insertions).
762052e0aa0SMatthew Dillon 	 *
763052e0aa0SMatthew Dillon 	 *	Queue adjustments had to be separated into deletions and
764052e0aa0SMatthew Dillon 	 *	insertions because both can occur on dbtree.
7658138a154SMatthew Dillon 	 */
7668138a154SMatthew Dillon 	if (info->domodify) {
7678138a154SMatthew Dillon 		hammer2_chain_t *scan;
7688138a154SMatthew Dillon 
7698138a154SMatthew Dillon 		spin_lock(&core->cst.spin);
7708138a154SMatthew Dillon 
7718138a154SMatthew Dillon 		while ((info->domodify & 1) && info->parent) {
7728138a154SMatthew Dillon 			/* PASS2 - Deletions */
7738138a154SMatthew Dillon 			RB_SCAN(hammer2_chain_tree, &core->rbtree,
7748138a154SMatthew Dillon 				NULL, hammer2_flush_pass2, info);
7758138a154SMatthew Dillon 			RB_SCAN(hammer2_chain_tree, &core->dbtree,
7768138a154SMatthew Dillon 				NULL, hammer2_flush_pass2, info);
7778138a154SMatthew Dillon 			scan = TAILQ_FIRST(&core->dbq);
7788138a154SMatthew Dillon 			TAILQ_FOREACH(scan, &core->dbq, db_entry) {
7798138a154SMatthew Dillon 				KKASSERT(scan->flags & HAMMER2_CHAIN_ONDBQ);
7808138a154SMatthew Dillon 				hammer2_flush_pass2(scan, info);
7818138a154SMatthew Dillon 			}
7828138a154SMatthew Dillon 
7838138a154SMatthew Dillon 			/* PASS3 - Insertions */
7848138a154SMatthew Dillon 			RB_SCAN(hammer2_chain_tree, &core->rbtree,
7858138a154SMatthew Dillon 				NULL, hammer2_flush_pass3, info);
7868138a154SMatthew Dillon 			RB_SCAN(hammer2_chain_tree, &core->dbtree,
7878138a154SMatthew Dillon 				NULL, hammer2_flush_pass3, info);
7888138a154SMatthew Dillon 			TAILQ_FOREACH(scan, &core->dbq, db_entry) {
7898138a154SMatthew Dillon 				KKASSERT(scan->flags & HAMMER2_CHAIN_ONDBQ);
7908138a154SMatthew Dillon 				hammer2_flush_pass3(scan, info);
7918138a154SMatthew Dillon 			}
7928138a154SMatthew Dillon 			info->parent = TAILQ_NEXT(info->parent, core_entry);
7938138a154SMatthew Dillon 			if (info->parent)
7948138a154SMatthew Dillon 				kprintf("FLUSH SPECIAL UPDATE (%p) %p.%d %08x\n",
7958138a154SMatthew Dillon 					chain, info->parent,
7968138a154SMatthew Dillon 					info->parent->bref.type,
7978138a154SMatthew Dillon 					info->parent->flags);
7988138a154SMatthew Dillon 		}
7998138a154SMatthew Dillon 		info->parent = chain;
8008138a154SMatthew Dillon 
8018138a154SMatthew Dillon 		/* PASS4 - Cleanup */
8028138a154SMatthew Dillon 		RB_SCAN(hammer2_chain_tree, &core->rbtree,
8038138a154SMatthew Dillon 			NULL, hammer2_flush_pass4, info);
8048138a154SMatthew Dillon 		scan = TAILQ_FIRST(&core->dbq);
8058138a154SMatthew Dillon 		while (scan) {
8068138a154SMatthew Dillon 			KKASSERT(scan->flags & HAMMER2_CHAIN_ONDBQ);
8078138a154SMatthew Dillon 			hammer2_flush_pass4(scan, info);
8088138a154SMatthew Dillon 			if (scan->flags & HAMMER2_CHAIN_ONDBQ)
8098138a154SMatthew Dillon 				scan = TAILQ_NEXT(scan, db_entry);
8108138a154SMatthew Dillon 			else
8118138a154SMatthew Dillon 				scan = TAILQ_FIRST(&core->dbq);
8128138a154SMatthew Dillon 		}
8138138a154SMatthew Dillon 		RB_SCAN(hammer2_chain_tree, &core->dbtree,
8148138a154SMatthew Dillon 			NULL, hammer2_flush_pass4, info);
8158138a154SMatthew Dillon 
816052e0aa0SMatthew Dillon 		/* PASS5 - Cleanup */
817052e0aa0SMatthew Dillon 		RB_SCAN(hammer2_chain_tree, &core->rbtree,
818052e0aa0SMatthew Dillon 			NULL, hammer2_flush_pass5, info);
819052e0aa0SMatthew Dillon 		scan = TAILQ_FIRST(&core->dbq);
820052e0aa0SMatthew Dillon 		while (scan) {
821052e0aa0SMatthew Dillon 			KKASSERT(scan->flags & HAMMER2_CHAIN_ONDBQ);
822052e0aa0SMatthew Dillon 			hammer2_flush_pass5(scan, info);
823052e0aa0SMatthew Dillon 			if (scan->flags & HAMMER2_CHAIN_ONDBQ)
824052e0aa0SMatthew Dillon 				scan = TAILQ_NEXT(scan, db_entry);
825052e0aa0SMatthew Dillon 			else
826052e0aa0SMatthew Dillon 				scan = TAILQ_FIRST(&core->dbq);
827052e0aa0SMatthew Dillon 		}
828052e0aa0SMatthew Dillon 		RB_SCAN(hammer2_chain_tree, &core->dbtree,
829052e0aa0SMatthew Dillon 			NULL, hammer2_flush_pass5, info);
830052e0aa0SMatthew Dillon 
8318138a154SMatthew Dillon 		spin_unlock(&core->cst.spin);
8328138a154SMatthew Dillon 	}
8330924b3f8SMatthew Dillon 
83432b800e6SMatthew Dillon 	/*
83550456506SMatthew Dillon 	 * Synchronize update_xlo to prevent reentrant block updates of this
8368138a154SMatthew Dillon 	 * parent.
8378138a154SMatthew Dillon 	 */
83850456506SMatthew Dillon 	chain->update_xlo = info->sync_xid;
8398138a154SMatthew Dillon 
8408138a154SMatthew Dillon 	/*
8418138a154SMatthew Dillon 	 * Skip the flush if the chain was not placed in a modified state
8428138a154SMatthew Dillon 	 * or was not already in a modified state.
8438138a154SMatthew Dillon 	 */
8448138a154SMatthew Dillon 	if ((chain->flags & HAMMER2_CHAIN_MODIFIED) == 0)
8458138a154SMatthew Dillon 		goto done;
8468138a154SMatthew Dillon 
8478138a154SMatthew Dillon 	/*
8488138a154SMatthew Dillon 	 * FLUSH THE CHAIN (on the way back up the recursion)
8498138a154SMatthew Dillon 	 *
8508138a154SMatthew Dillon 	 * Chain is now deterministically being flushed and not being deferred.
851623d43d4SMatthew Dillon 	 * We've finished running the recursion and the blockref update.
85291abd410SMatthew Dillon 	 *
85350456506SMatthew Dillon 	 * update bref.mirror_tid.  update_xlo has already been updated.
854623d43d4SMatthew Dillon 	 */
855*837bd39bSMatthew Dillon 	chain->bref.mirror_tid = pmp->flush_tid;
856623d43d4SMatthew Dillon 
857623d43d4SMatthew Dillon 	/*
8588138a154SMatthew Dillon 	 * Dispose of the modified bit.  FLUSH_CREATE should already be
8598138a154SMatthew Dillon 	 * set.
86032b800e6SMatthew Dillon 	 */
86150456506SMatthew Dillon 	KKASSERT((chain->flags & HAMMER2_CHAIN_FLUSH_CREATE) ||
86250456506SMatthew Dillon 		 chain == &hmp->vchain);
8630dea3156SMatthew Dillon 	atomic_clear_int(&chain->flags, HAMMER2_CHAIN_MODIFIED);
864*837bd39bSMatthew Dillon 	hammer2_pfs_memory_wakeup(pmp);
8658138a154SMatthew Dillon 
8668138a154SMatthew Dillon 	if ((chain->flags & HAMMER2_CHAIN_FLUSH_CREATE) ||
8678138a154SMatthew Dillon 	    chain == &hmp->vchain ||
8688138a154SMatthew Dillon 	    chain == &hmp->fchain) {
8698138a154SMatthew Dillon 		/*
8708138a154SMatthew Dillon 		 * Drop the ref from the MODIFIED bit we cleared,
8718138a154SMatthew Dillon 		 * net -1 ref.
8728138a154SMatthew Dillon 		 */
8730dea3156SMatthew Dillon 		hammer2_chain_drop(chain);
8748138a154SMatthew Dillon 	} else {
8758138a154SMatthew Dillon 		/*
8768138a154SMatthew Dillon 		 * Drop the ref from the MODIFIED bit we cleared and
8778138a154SMatthew Dillon 		 * set a ref for the FLUSH_CREATE bit we are setting.
8788138a154SMatthew Dillon 		 * Net 0 refs.
8798138a154SMatthew Dillon 		 */
8808138a154SMatthew Dillon 		atomic_set_int(&chain->flags, HAMMER2_CHAIN_FLUSH_CREATE);
8810dea3156SMatthew Dillon 	}
8820dea3156SMatthew Dillon 
8830dea3156SMatthew Dillon 	/*
8848138a154SMatthew Dillon 	 * Skip the actual flush operation if the chain has been deleted
8858138a154SMatthew Dillon 	 * in our flus hview.  There will be no block table entry that
8868138a154SMatthew Dillon 	 * references it.
8870dea3156SMatthew Dillon 	 */
8888138a154SMatthew Dillon 	if (h2ignore_deleted(info, chain))
8898138a154SMatthew Dillon 		goto done;
89010136ab6SMatthew Dillon 
8910dea3156SMatthew Dillon 	/*
8920dea3156SMatthew Dillon 	 * Issue flush.
8930dea3156SMatthew Dillon 	 *
894044541cdSMatthew Dillon 	 * A DELETED node that reaches this point must be flushed for
8950dea3156SMatthew Dillon 	 * synchronization point consistency.
89610136ab6SMatthew Dillon 	 *
89710136ab6SMatthew Dillon 	 * Update bref.mirror_tid, clear MODIFIED, and set MOVED.
8980dea3156SMatthew Dillon 	 *
8990dea3156SMatthew Dillon 	 * The caller will update the parent's reference to this chain
9000dea3156SMatthew Dillon 	 * by testing MOVED as long as the modification was in-bounds.
9010dea3156SMatthew Dillon 	 *
9020dea3156SMatthew Dillon 	 * MOVED is never set on the volume root as there is no parent
9030dea3156SMatthew Dillon 	 * to adjust.
9040dea3156SMatthew Dillon 	 */
905a7720be7SMatthew Dillon 	if (hammer2_debug & 0x1000) {
90650456506SMatthew Dillon 		kprintf("Flush %p.%d %016jx/%d sync_xid=%08x data=%016jx\n",
907a7720be7SMatthew Dillon 			chain, chain->bref.type,
908a7720be7SMatthew Dillon 			chain->bref.key, chain->bref.keybits,
90950456506SMatthew Dillon 			info->sync_xid, chain->bref.data_off);
910a7720be7SMatthew Dillon 	}
911a7720be7SMatthew Dillon 	if (hammer2_debug & 0x2000) {
912a7720be7SMatthew Dillon 		Debugger("Flush hell");
913a7720be7SMatthew Dillon 	}
91410136ab6SMatthew Dillon 
91532b800e6SMatthew Dillon 	/*
91632b800e6SMatthew Dillon 	 * If this is part of a recursive flush we can go ahead and write
917ea155208SMatthew Dillon 	 * out the buffer cache buffer and pass a new bref back up the chain
918ea155208SMatthew Dillon 	 * via the MOVED bit.
91932b800e6SMatthew Dillon 	 *
920ea155208SMatthew Dillon 	 * Volume headers are NOT flushed here as they require special
921ea155208SMatthew Dillon 	 * processing.
92232b800e6SMatthew Dillon 	 */
92332b800e6SMatthew Dillon 	switch(chain->bref.type) {
9241a7cfe5aSMatthew Dillon 	case HAMMER2_BREF_TYPE_FREEMAP:
92550456506SMatthew Dillon 		KKASSERT(hmp->vchain.flags & HAMMER2_CHAIN_MODIFIED);
92610136ab6SMatthew Dillon 		hmp->voldata.freemap_tid = hmp->fchain.bref.mirror_tid;
9271a7cfe5aSMatthew Dillon 		break;
92832b800e6SMatthew Dillon 	case HAMMER2_BREF_TYPE_VOLUME:
92932b800e6SMatthew Dillon 		/*
93010136ab6SMatthew Dillon 		 * The free block table is flushed by hammer2_vfs_sync()
93110136ab6SMatthew Dillon 		 * before it flushes vchain.  We must still hold fchain
93210136ab6SMatthew Dillon 		 * locked while copying voldata to volsync, however.
9331a7cfe5aSMatthew Dillon 		 */
93450456506SMatthew Dillon 		hammer2_voldata_lock(hmp);
9351a7cfe5aSMatthew Dillon 		hammer2_chain_lock(&hmp->fchain, HAMMER2_RESOLVE_ALWAYS);
93610136ab6SMatthew Dillon #if 0
937a7720be7SMatthew Dillon 		if ((hmp->fchain.flags & HAMMER2_CHAIN_MODIFIED) ||
938925e4ad1SMatthew Dillon 		    hmp->voldata.freemap_tid < info->trans->sync_tid) {
9391a7cfe5aSMatthew Dillon 			/* this will modify vchain as a side effect */
940a7720be7SMatthew Dillon 			hammer2_chain_t *tmp = &hmp->fchain;
941a7720be7SMatthew Dillon 			hammer2_chain_flush(info->trans, &tmp);
942a7720be7SMatthew Dillon 			KKASSERT(tmp == &hmp->fchain);
9431a7cfe5aSMatthew Dillon 		}
94410136ab6SMatthew Dillon #endif
94510136ab6SMatthew Dillon 
94610136ab6SMatthew Dillon 		/*
94710136ab6SMatthew Dillon 		 * There is no parent to our root vchain and fchain to
94810136ab6SMatthew Dillon 		 * synchronize the bref to, their updated mirror_tid's
94910136ab6SMatthew Dillon 		 * must be synchronized to the volume header.
95010136ab6SMatthew Dillon 		 */
95110136ab6SMatthew Dillon 		hmp->voldata.mirror_tid = chain->bref.mirror_tid;
95250456506SMatthew Dillon 		hmp->voldata.freemap_tid = hmp->fchain.bref.mirror_tid;
9531a7cfe5aSMatthew Dillon 
9541a7cfe5aSMatthew Dillon 		/*
95532b800e6SMatthew Dillon 		 * The volume header is flushed manually by the syncer, not
95610136ab6SMatthew Dillon 		 * here.  All we do here is adjust the crc's.
95732b800e6SMatthew Dillon 		 */
95832b800e6SMatthew Dillon 		KKASSERT(chain->data != NULL);
959fdf62707SMatthew Dillon 		KKASSERT(chain->dio == NULL);
96032b800e6SMatthew Dillon 
96132b800e6SMatthew Dillon 		hmp->voldata.icrc_sects[HAMMER2_VOL_ICRC_SECT1]=
96232b800e6SMatthew Dillon 			hammer2_icrc32(
96332b800e6SMatthew Dillon 				(char *)&hmp->voldata +
96432b800e6SMatthew Dillon 				 HAMMER2_VOLUME_ICRC1_OFF,
96532b800e6SMatthew Dillon 				HAMMER2_VOLUME_ICRC1_SIZE);
96632b800e6SMatthew Dillon 		hmp->voldata.icrc_sects[HAMMER2_VOL_ICRC_SECT0]=
96732b800e6SMatthew Dillon 			hammer2_icrc32(
96832b800e6SMatthew Dillon 				(char *)&hmp->voldata +
96932b800e6SMatthew Dillon 				 HAMMER2_VOLUME_ICRC0_OFF,
97032b800e6SMatthew Dillon 				HAMMER2_VOLUME_ICRC0_SIZE);
97132b800e6SMatthew Dillon 		hmp->voldata.icrc_volheader =
97232b800e6SMatthew Dillon 			hammer2_icrc32(
97332b800e6SMatthew Dillon 				(char *)&hmp->voldata +
97432b800e6SMatthew Dillon 				 HAMMER2_VOLUME_ICRCVH_OFF,
97532b800e6SMatthew Dillon 				HAMMER2_VOLUME_ICRCVH_SIZE);
97632b800e6SMatthew Dillon 		hmp->volsync = hmp->voldata;
9770dea3156SMatthew Dillon 		atomic_set_int(&chain->flags, HAMMER2_CHAIN_VOLUMESYNC);
97893f3933aSMatthew Dillon 		hammer2_chain_unlock(&hmp->fchain);
97950456506SMatthew Dillon 		hammer2_voldata_unlock(hmp);
98032b800e6SMatthew Dillon 		break;
98132b800e6SMatthew Dillon 	case HAMMER2_BREF_TYPE_DATA:
98232b800e6SMatthew Dillon 		/*
98332b800e6SMatthew Dillon 		 * Data elements have already been flushed via the logical
98432b800e6SMatthew Dillon 		 * file buffer cache.  Their hash was set in the bref by
98532b800e6SMatthew Dillon 		 * the vop_write code.
98632b800e6SMatthew Dillon 		 *
987ea155208SMatthew Dillon 		 * Make sure any device buffer(s) have been flushed out here.
988ea155208SMatthew Dillon 		 * (there aren't usually any to flush).
98932b800e6SMatthew Dillon 		 */
99032b800e6SMatthew Dillon 		break;
991512beabdSMatthew Dillon #if 0
99232b800e6SMatthew Dillon 	case HAMMER2_BREF_TYPE_INDIRECT:
99332b800e6SMatthew Dillon 		/*
99432b800e6SMatthew Dillon 		 * Indirect blocks may be in an INITIAL state.  Use the
99532b800e6SMatthew Dillon 		 * chain_lock() call to ensure that the buffer has been
99632b800e6SMatthew Dillon 		 * instantiated (even though it is already locked the buffer
99732b800e6SMatthew Dillon 		 * might not have been instantiated).
99832b800e6SMatthew Dillon 		 *
99932b800e6SMatthew Dillon 		 * Only write the buffer out if it is dirty, it is possible
100032b800e6SMatthew Dillon 		 * the operating system had already written out the buffer.
100132b800e6SMatthew Dillon 		 */
10020dea3156SMatthew Dillon 		hammer2_chain_lock(chain, HAMMER2_RESOLVE_ALWAYS);
1003fdf62707SMatthew Dillon 		KKASSERT(chain->dio != NULL);
100432b800e6SMatthew Dillon 
100532b800e6SMatthew Dillon 		chain->data = NULL;
1006fdf62707SMatthew Dillon 		hammer2_io_bqrelse(&chain->dio);
10070dea3156SMatthew Dillon 		hammer2_chain_unlock(chain);
100832b800e6SMatthew Dillon 		break;
1009512beabdSMatthew Dillon #endif
1010512beabdSMatthew Dillon 	case HAMMER2_BREF_TYPE_INDIRECT:
10111a7cfe5aSMatthew Dillon 	case HAMMER2_BREF_TYPE_FREEMAP_NODE:
101291caa51cSMatthew Dillon 	case HAMMER2_BREF_TYPE_FREEMAP_LEAF:
101350456506SMatthew Dillon 		KKASSERT((chain->flags & HAMMER2_CHAIN_EMBEDDED) == 0);
101450456506SMatthew Dillon 		break;
101591caa51cSMatthew Dillon 	case HAMMER2_BREF_TYPE_INODE:
101650456506SMatthew Dillon 		if (chain->data->ipdata.op_flags & HAMMER2_OPFLAG_PFSROOT) {
1017*837bd39bSMatthew Dillon 			/*
1018*837bd39bSMatthew Dillon 			 * non-NULL pmp if mounted as a PFS.  We must sync
1019*837bd39bSMatthew Dillon 			 * fields cached in the pmp.
1020*837bd39bSMatthew Dillon 			 */
1021*837bd39bSMatthew Dillon 			hammer2_inode_data_t *ipdata;
1022*837bd39bSMatthew Dillon 
1023*837bd39bSMatthew Dillon 			ipdata = &chain->data->ipdata;
1024*837bd39bSMatthew Dillon 			ipdata->pfs_inum = pmp->inode_tid;
102550456506SMatthew Dillon 		} else {
102650456506SMatthew Dillon 			/* can't be mounted as a PFS */
102750456506SMatthew Dillon 			KKASSERT((chain->flags & HAMMER2_CHAIN_PFSROOT) == 0);
102850456506SMatthew Dillon 		}
1029512beabdSMatthew Dillon 		KKASSERT((chain->flags & HAMMER2_CHAIN_EMBEDDED) == 0);
10301a7cfe5aSMatthew Dillon 		break;
103132b800e6SMatthew Dillon 	default:
103291caa51cSMatthew Dillon 		KKASSERT(chain->flags & HAMMER2_CHAIN_EMBEDDED);
103350456506SMatthew Dillon 		panic("hammer2_flush_core: unsupported embedded bref %d",
103491caa51cSMatthew Dillon 		      chain->bref.type);
103591caa51cSMatthew Dillon 		/* NOT REACHED */
103632b800e6SMatthew Dillon 	}
103732b800e6SMatthew Dillon 
103832b800e6SMatthew Dillon 	/*
10398138a154SMatthew Dillon 	 * Final cleanup after flush
10408138a154SMatthew Dillon 	 */
10418138a154SMatthew Dillon done:
10428138a154SMatthew Dillon 	KKASSERT(chain->refs > 1);
10438138a154SMatthew Dillon 	info->domodify = saved_domodify;
10448138a154SMatthew Dillon 	info->parent = saved_parent;
10458138a154SMatthew Dillon 	*chainp = chain;
10468138a154SMatthew Dillon 
104750456506SMatthew Dillon 	KKASSERT(chain->bref.mirror_tid <= chain->pmp->flush_tid);
10488138a154SMatthew Dillon }
10498138a154SMatthew Dillon 
10508138a154SMatthew Dillon /*
10518138a154SMatthew Dillon  * Flush helper pass1 (recursive)
10520dea3156SMatthew Dillon  *
10538138a154SMatthew Dillon  * Flushes the children of the caller's chain (info->parent), restricted
10548138a154SMatthew Dillon  * by sync_tid.  Set info->domodify if the child's blockref must propagate
10558138a154SMatthew Dillon  * back up to the parent.
10560dea3156SMatthew Dillon  *
10578138a154SMatthew Dillon  * Ripouts can move child from rbtree to dbtree or dbq but the caller's
10588138a154SMatthew Dillon  * flush scan order prevents any chains from being lost.  A child can be
105950456506SMatthew Dillon  * executes more than once (update_xlo is used to prevent infinite recursions).
1060ea155208SMatthew Dillon  *
10618138a154SMatthew Dillon  * WARNING! If we do not call hammer2_flush_core() we must update
10628138a154SMatthew Dillon  *	    bref.mirror_tid ourselves to indicate that the flush has
10638138a154SMatthew Dillon  *	    processed the child.
1064925e4ad1SMatthew Dillon  *
10658138a154SMatthew Dillon  * WARNING! parent->core spinlock is held on entry and return.
106650456506SMatthew Dillon  *
106750456506SMatthew Dillon  * WARNING! Flushes do not cross PFS boundaries.  Specifically, a flush must
106850456506SMatthew Dillon  *	    not cross a pfs-root boundary.
106932b800e6SMatthew Dillon  */
10700dea3156SMatthew Dillon static int
10718138a154SMatthew Dillon hammer2_flush_pass1(hammer2_chain_t *child, void *data)
107232b800e6SMatthew Dillon {
10730dea3156SMatthew Dillon 	hammer2_flush_info_t *info = data;
1074cd189b1eSMatthew Dillon 	hammer2_trans_t *trans = info->trans;
10750dea3156SMatthew Dillon 	hammer2_chain_t *parent = info->parent;
1076925e4ad1SMatthew Dillon 
10770dea3156SMatthew Dillon 	/*
10788138a154SMatthew Dillon 	 * Child modified in a later transactions, nothing to flush in this
10798138a154SMatthew Dillon 	 * transaction.
10808138a154SMatthew Dillon 	 *
1081a4dc31e0SMatthew Dillon 	 * Remember that modifications generally delete-duplicate so if the
1082a4dc31e0SMatthew Dillon 	 * sub-tree is dirty another child will get us there.  But not this
1083a4dc31e0SMatthew Dillon 	 * one.
1084a4dc31e0SMatthew Dillon 	 *
108510136ab6SMatthew Dillon 	 * (child can never be fchain or vchain so a special check isn't
108610136ab6SMatthew Dillon 	 *  needed).
10870dea3156SMatthew Dillon 	 */
108850456506SMatthew Dillon 	if (child->modify_xid > trans->sync_xid) {
108950456506SMatthew Dillon 		KKASSERT(child->delete_xid >= child->modify_xid);
109050456506SMatthew Dillon 		/*child->update_xlo = info->sync_xid;*/
10918138a154SMatthew Dillon 		/* do not update mirror_tid, pass2 will ignore chain */
10920dea3156SMatthew Dillon 		return (0);
109332b800e6SMatthew Dillon 	}
1094cd189b1eSMatthew Dillon 
1095a4dc31e0SMatthew Dillon 	/*
1096a4dc31e0SMatthew Dillon 	 * We must ref the child before unlocking the spinlock.
1097a4dc31e0SMatthew Dillon 	 *
1098a4dc31e0SMatthew Dillon 	 * The caller has added a ref to the parent so we can temporarily
1099a4dc31e0SMatthew Dillon 	 * unlock it in order to lock the child.
1100a4dc31e0SMatthew Dillon 	 */
1101ea155208SMatthew Dillon 	hammer2_chain_ref(child);
11020dea3156SMatthew Dillon 	spin_unlock(&parent->core->cst.spin);
11030dea3156SMatthew Dillon 
11040dea3156SMatthew Dillon 	hammer2_chain_unlock(parent);
11050dea3156SMatthew Dillon 	hammer2_chain_lock(child, HAMMER2_RESOLVE_MAYBE);
11060dea3156SMatthew Dillon 
110703faa7d5SMatthew Dillon 	/*
110850456506SMatthew Dillon 	 * Never recurse across a mounted PFS boundary.
110950456506SMatthew Dillon 	 *
11108138a154SMatthew Dillon 	 * Recurse and collect deferral data.  We only recursively sync
111150456506SMatthew Dillon 	 * (basically) if update_xlo has not been updated, indicating that
11128138a154SMatthew Dillon 	 * the child has not already been processed.
111303faa7d5SMatthew Dillon 	 */
111450456506SMatthew Dillon 	if ((child->flags & HAMMER2_CHAIN_PFSBOUNDARY) == 0 ||
111550456506SMatthew Dillon 	    child->pmp == NULL) {
11168138a154SMatthew Dillon 		if ((child->flags & HAMMER2_CHAIN_MODIFIED) ||
111750456506SMatthew Dillon 		    (child->update_xlo < info->sync_xid &&
111850456506SMatthew Dillon 		     child->update_xlo < child->update_xhi)) {
11190dea3156SMatthew Dillon 			++info->depth;
11208138a154SMatthew Dillon 			hammer2_flush_core(info, &child, 0); /* XXX deleting */
11210dea3156SMatthew Dillon 			--info->depth;
11228138a154SMatthew Dillon 		}
112350456506SMatthew Dillon 	}
11240dea3156SMatthew Dillon 
1125a4dc31e0SMatthew Dillon 	/*
11268138a154SMatthew Dillon 	 * Determine if domodify should be set.  Do not otherwise adjust
11278138a154SMatthew Dillon 	 * the child or pass2 will get confused.
1128925e4ad1SMatthew Dillon 	 *
11298138a154SMatthew Dillon 	 * Insertion:
11308138a154SMatthew Dillon 	 *	- child is flagged as possibly needing block table insertion.
11318138a154SMatthew Dillon 	 *	- child not deleted or deletion is beyond transaction id
11328138a154SMatthew Dillon 	 *	- child created beyond parent synchronization point
11338138a154SMatthew Dillon 	 *	- parent not deleted as-of this transaction
1134a4dc31e0SMatthew Dillon 	 */
11358138a154SMatthew Dillon 	if ((child->flags & HAMMER2_CHAIN_FLUSH_CREATE) &&
113650456506SMatthew Dillon 	    child->delete_xid > trans->sync_xid &&
113750456506SMatthew Dillon 	    child->modify_xid > parent->update_xlo &&
113850456506SMatthew Dillon 	    parent->delete_xid > trans->sync_xid) {
113903faa7d5SMatthew Dillon 		info->domodify = 1;
11408138a154SMatthew Dillon 	}
11418138a154SMatthew Dillon 
11428138a154SMatthew Dillon 	/*
11438138a154SMatthew Dillon 	 * Removal:
11448138a154SMatthew Dillon 	 *	- child is flagged as possibly needing block table removal.
11458138a154SMatthew Dillon 	 *	- child deleted before or during this transaction
11468138a154SMatthew Dillon 	 *	- child created prior or during parent synchronization point
11478138a154SMatthew Dillon 	 *	- parent not yet synchronized to child deletion
11488138a154SMatthew Dillon 	 *	- parent not deleted as-of this transaction
11498138a154SMatthew Dillon 	 */
11508138a154SMatthew Dillon 	if ((child->flags & HAMMER2_CHAIN_FLUSH_DELETE) &&
115150456506SMatthew Dillon 	    child->delete_xid <= trans->sync_xid &&
115250456506SMatthew Dillon 	    child->modify_xid <= parent->update_xlo &&
115350456506SMatthew Dillon 	    child->delete_xid > parent->update_xlo &&
115450456506SMatthew Dillon 	    parent->delete_xid > trans->sync_xid) {
11558138a154SMatthew Dillon 		info->domodify = 1;
1156a4dc31e0SMatthew Dillon 	}
1157a4dc31e0SMatthew Dillon 
1158a4dc31e0SMatthew Dillon 	/*
1159a4dc31e0SMatthew Dillon 	 * Relock to continue the loop
1160a4dc31e0SMatthew Dillon 	 */
1161a4dc31e0SMatthew Dillon 	hammer2_chain_unlock(child);
1162ea155208SMatthew Dillon 	hammer2_chain_lock(parent, HAMMER2_RESOLVE_MAYBE);
1163a4dc31e0SMatthew Dillon 	hammer2_chain_drop(child);
1164a4dc31e0SMatthew Dillon 	KKASSERT(info->parent == parent);
11650dea3156SMatthew Dillon 
11660dea3156SMatthew Dillon 	spin_lock(&parent->core->cst.spin);
11670dea3156SMatthew Dillon 	return (0);
11680dea3156SMatthew Dillon }
11690dea3156SMatthew Dillon 
11700dea3156SMatthew Dillon /*
11718138a154SMatthew Dillon  * PASS2 - BLOCKTABLE DELETIONS
11720dea3156SMatthew Dillon  */
11730dea3156SMatthew Dillon static int
11748138a154SMatthew Dillon hammer2_flush_pass2(hammer2_chain_t *child, void *data)
11750dea3156SMatthew Dillon {
11760dea3156SMatthew Dillon 	hammer2_flush_info_t *info = data;
11770dea3156SMatthew Dillon 	hammer2_chain_t *parent = info->parent;
1178a5913bdfSMatthew Dillon 	hammer2_mount_t *hmp = child->hmp;
1179a864c5d9SMatthew Dillon 	hammer2_trans_t *trans = info->trans;
11800dea3156SMatthew Dillon 	hammer2_blockref_t *base;
11810dea3156SMatthew Dillon 	int count;
1182ea155208SMatthew Dillon 
1183ea155208SMatthew Dillon 	/*
11848138a154SMatthew Dillon 	 * Prefilter - Ignore children not flagged as needing a parent
11858138a154SMatthew Dillon 	 *	       blocktable update.
11868138a154SMatthew Dillon 	 */
11878138a154SMatthew Dillon 	if ((child->flags & HAMMER2_CHAIN_FLUSH_DELETE) == 0)
11888138a154SMatthew Dillon 		return (0);
11898138a154SMatthew Dillon 
11908138a154SMatthew Dillon 	/*
11918138a154SMatthew Dillon 	 * Prefilter - Ignore children created after our flush_tid (not
11928138a154SMatthew Dillon 	 *	       visible to our flush).
1193731b2a84SMatthew Dillon 	 */
119450456506SMatthew Dillon 	if (child->modify_xid > trans->sync_xid) {
119550456506SMatthew Dillon 		KKASSERT(child->delete_xid >= child->modify_xid);
11968138a154SMatthew Dillon 		return 0;
1197731b2a84SMatthew Dillon 	}
1198731b2a84SMatthew Dillon 
1199731b2a84SMatthew Dillon 	/*
12008138a154SMatthew Dillon 	 * Prefilter - Don't bother updating the blockrefs for a deleted
12018138a154SMatthew Dillon 	 *	       parent (from the flush's perspective).  Otherwise,
12028138a154SMatthew Dillon 	 *	       we need to be COUNTEDBREFS synchronized for the
12038138a154SMatthew Dillon 	 *	       hammer2_base_*() functions.
12041897c66eSMatthew Dillon 	 *
12058138a154SMatthew Dillon 	 * NOTE: This test must match the similar one in flush_core.
1206ea155208SMatthew Dillon 	 */
12078138a154SMatthew Dillon 	if (h2ignore_deleted(info, parent))
12088138a154SMatthew Dillon 		return 0;
1209ea155208SMatthew Dillon 
12101897c66eSMatthew Dillon 	/*
12118138a154SMatthew Dillon 	 * Calculate blockmap pointer
12121897c66eSMatthew Dillon 	 */
12130dea3156SMatthew Dillon 	switch(parent->bref.type) {
12140dea3156SMatthew Dillon 	case HAMMER2_BREF_TYPE_INODE:
1215ea155208SMatthew Dillon 		/*
12163f5b8b3bSMatthew Dillon 		 * Access the inode's block array.  However, there is no
12173f5b8b3bSMatthew Dillon 		 * block array if the inode is flagged DIRECTDATA.  The
12183f5b8b3bSMatthew Dillon 		 * DIRECTDATA case typicaly only occurs when a hardlink has
12193f5b8b3bSMatthew Dillon 		 * been shifted up the tree and the original inode gets
12203f5b8b3bSMatthew Dillon 		 * replaced with an OBJTYPE_HARDLINK placeholding inode.
1221ea155208SMatthew Dillon 		 */
12223f5b8b3bSMatthew Dillon 		if (parent->data &&
12233f5b8b3bSMatthew Dillon 		    (parent->data->ipdata.op_flags &
12243f5b8b3bSMatthew Dillon 		     HAMMER2_OPFLAG_DIRECTDATA) == 0) {
12250dea3156SMatthew Dillon 			base = &parent->data->ipdata.u.blockset.blockref[0];
12263f5b8b3bSMatthew Dillon 		} else {
1227a4dc31e0SMatthew Dillon 			base = NULL;
12283f5b8b3bSMatthew Dillon 		}
12290dea3156SMatthew Dillon 		count = HAMMER2_SET_COUNT;
12300dea3156SMatthew Dillon 		break;
12310dea3156SMatthew Dillon 	case HAMMER2_BREF_TYPE_INDIRECT:
12321a7cfe5aSMatthew Dillon 	case HAMMER2_BREF_TYPE_FREEMAP_NODE:
1233a4dc31e0SMatthew Dillon 		if (parent->data)
123493f3933aSMatthew Dillon 			base = &parent->data->npdata[0];
1235a4dc31e0SMatthew Dillon 		else
12360dea3156SMatthew Dillon 			base = NULL;
12370dea3156SMatthew Dillon 		count = parent->bytes / sizeof(hammer2_blockref_t);
12380dea3156SMatthew Dillon 		break;
12390dea3156SMatthew Dillon 	case HAMMER2_BREF_TYPE_VOLUME:
12400dea3156SMatthew Dillon 		base = &hmp->voldata.sroot_blockset.blockref[0];
12410dea3156SMatthew Dillon 		count = HAMMER2_SET_COUNT;
12420dea3156SMatthew Dillon 		break;
12431a7cfe5aSMatthew Dillon 	case HAMMER2_BREF_TYPE_FREEMAP:
124493f3933aSMatthew Dillon 		base = &parent->data->npdata[0];
12451a7cfe5aSMatthew Dillon 		count = HAMMER2_SET_COUNT;
12461a7cfe5aSMatthew Dillon 		break;
12470dea3156SMatthew Dillon 	default:
12480dea3156SMatthew Dillon 		base = NULL;
12490dea3156SMatthew Dillon 		count = 0;
125050456506SMatthew Dillon 		panic("hammer2_flush_pass2: unrecognized blockref type: %d",
12510dea3156SMatthew Dillon 		      parent->bref.type);
12520dea3156SMatthew Dillon 	}
12530dea3156SMatthew Dillon 
12540dea3156SMatthew Dillon 	/*
12558138a154SMatthew Dillon 	 * Removal
12568138a154SMatthew Dillon 	 *	- child is flagged for removal
12578138a154SMatthew Dillon 	 *	- child deleted before or during this transaction
12588138a154SMatthew Dillon 	 *	- child created prior or during parent synchronization point
12598138a154SMatthew Dillon 	 *	- parent not yet synchronized to child's deletion
12601897c66eSMatthew Dillon 	 */
126150456506SMatthew Dillon 	if (child->delete_xid <= trans->sync_xid &&
126250456506SMatthew Dillon 	    child->modify_xid <= parent->update_xlo &&
126350456506SMatthew Dillon 	    child->delete_xid > parent->update_xlo) {
12648138a154SMatthew Dillon 		/* can't assert BMAPPED because state adjustment may occur
12658138a154SMatthew Dillon 		 * before we are done, and BMAPPED only applies to the live
12668138a154SMatthew Dillon 		 * parent.
12678138a154SMatthew Dillon 		 *KKASSERT(child->flags & HAMMER2_CHAIN_BMAPPED);*/
12688138a154SMatthew Dillon 		if (base) {
126991abd410SMatthew Dillon 			hammer2_rollup_stats(parent, child, -1);
1270623d43d4SMatthew Dillon 			hammer2_base_delete(trans, parent, base, count,
1271a7720be7SMatthew Dillon 					    &info->cache_index, child);
127293f3933aSMatthew Dillon 		}
12738138a154SMatthew Dillon 	}
12748138a154SMatthew Dillon 
12758138a154SMatthew Dillon 	return 0;
12768138a154SMatthew Dillon }
12778138a154SMatthew Dillon 
12781897c66eSMatthew Dillon /*
12798138a154SMatthew Dillon  * PASS3 - BLOCKTABLE INSERTIONS
12801897c66eSMatthew Dillon  */
12818138a154SMatthew Dillon static int
12828138a154SMatthew Dillon hammer2_flush_pass3(hammer2_chain_t *child, void *data)
12838138a154SMatthew Dillon {
12848138a154SMatthew Dillon 	hammer2_flush_info_t *info = data;
12858138a154SMatthew Dillon 	hammer2_chain_t *parent = info->parent;
12868138a154SMatthew Dillon 	hammer2_mount_t *hmp = child->hmp;
12878138a154SMatthew Dillon 	hammer2_trans_t *trans = info->trans;
12888138a154SMatthew Dillon 	hammer2_blockref_t *base;
12898138a154SMatthew Dillon 	int count;
12908138a154SMatthew Dillon 
12918138a154SMatthew Dillon 	/*
12928138a154SMatthew Dillon 	 * Prefilter - Ignore children not flagged as needing a parent
12938138a154SMatthew Dillon 	 *	       blocktable update.
12948138a154SMatthew Dillon 	 */
12958138a154SMatthew Dillon 	if ((child->flags & HAMMER2_CHAIN_FLUSH_CREATE) == 0)
12968138a154SMatthew Dillon 		return (0);
12978138a154SMatthew Dillon 
12988138a154SMatthew Dillon 	/*
12998138a154SMatthew Dillon 	 * Prefilter - Ignore children created after our flush_tid (not
13008138a154SMatthew Dillon 	 *	       visible to our flush).
13018138a154SMatthew Dillon 	 */
130250456506SMatthew Dillon 	if (child->modify_xid > trans->sync_xid) {
130350456506SMatthew Dillon 		KKASSERT(child->delete_xid >= child->modify_xid);
13048138a154SMatthew Dillon 		return 0;
13058138a154SMatthew Dillon 	}
13068138a154SMatthew Dillon 
13078138a154SMatthew Dillon 	/*
13088138a154SMatthew Dillon 	 * Prefilter - Don't bother updating the blockrefs for a deleted
13098138a154SMatthew Dillon 	 *	       parent (from the flush's perspective).  Otherwise,
13108138a154SMatthew Dillon 	 *	       we need to be COUNTEDBREFS synchronized for the
13118138a154SMatthew Dillon 	 *	       hammer2_base_*() functions.
13128138a154SMatthew Dillon 	 *
13138138a154SMatthew Dillon 	 * NOTE: This test must match the similar one in flush_core.
13148138a154SMatthew Dillon 	 */
13158138a154SMatthew Dillon 	if (h2ignore_deleted(info, parent))
13168138a154SMatthew Dillon 		return 0;
13178138a154SMatthew Dillon 
13188138a154SMatthew Dillon 	/*
13198138a154SMatthew Dillon 	 * Calculate blockmap pointer
13208138a154SMatthew Dillon 	 */
13218138a154SMatthew Dillon 	switch(parent->bref.type) {
13228138a154SMatthew Dillon 	case HAMMER2_BREF_TYPE_INODE:
13238138a154SMatthew Dillon 		/*
13248138a154SMatthew Dillon 		 * Access the inode's block array.  However, there is no
13258138a154SMatthew Dillon 		 * block array if the inode is flagged DIRECTDATA.  The
13268138a154SMatthew Dillon 		 * DIRECTDATA case typicaly only occurs when a hardlink has
13278138a154SMatthew Dillon 		 * been shifted up the tree and the original inode gets
13288138a154SMatthew Dillon 		 * replaced with an OBJTYPE_HARDLINK placeholding inode.
13298138a154SMatthew Dillon 		 */
13308138a154SMatthew Dillon 		if (parent->data &&
13318138a154SMatthew Dillon 		    (parent->data->ipdata.op_flags &
13328138a154SMatthew Dillon 		     HAMMER2_OPFLAG_DIRECTDATA) == 0) {
13338138a154SMatthew Dillon 			base = &parent->data->ipdata.u.blockset.blockref[0];
13348138a154SMatthew Dillon 		} else {
13358138a154SMatthew Dillon 			base = NULL;
13368138a154SMatthew Dillon 		}
13378138a154SMatthew Dillon 		count = HAMMER2_SET_COUNT;
13388138a154SMatthew Dillon 		break;
13398138a154SMatthew Dillon 	case HAMMER2_BREF_TYPE_INDIRECT:
13408138a154SMatthew Dillon 	case HAMMER2_BREF_TYPE_FREEMAP_NODE:
13418138a154SMatthew Dillon 		if (parent->data)
13428138a154SMatthew Dillon 			base = &parent->data->npdata[0];
13438138a154SMatthew Dillon 		else
13448138a154SMatthew Dillon 			base = NULL;
13458138a154SMatthew Dillon 		count = parent->bytes / sizeof(hammer2_blockref_t);
13468138a154SMatthew Dillon 		break;
13478138a154SMatthew Dillon 	case HAMMER2_BREF_TYPE_VOLUME:
13488138a154SMatthew Dillon 		base = &hmp->voldata.sroot_blockset.blockref[0];
13498138a154SMatthew Dillon 		count = HAMMER2_SET_COUNT;
13508138a154SMatthew Dillon 		break;
13518138a154SMatthew Dillon 	case HAMMER2_BREF_TYPE_FREEMAP:
13528138a154SMatthew Dillon 		base = &parent->data->npdata[0];
13538138a154SMatthew Dillon 		count = HAMMER2_SET_COUNT;
13548138a154SMatthew Dillon 		break;
13558138a154SMatthew Dillon 	default:
13568138a154SMatthew Dillon 		base = NULL;
13578138a154SMatthew Dillon 		count = 0;
135850456506SMatthew Dillon 		panic("hammer2_flush_pass3: "
13598138a154SMatthew Dillon 		      "unrecognized blockref type: %d",
13608138a154SMatthew Dillon 		      parent->bref.type);
13618138a154SMatthew Dillon 	}
13628138a154SMatthew Dillon 
13638138a154SMatthew Dillon 	/*
13648138a154SMatthew Dillon 	 * Insertion
13658138a154SMatthew Dillon 	 *	- child is flagged as possibly needing block table insertion.
13668138a154SMatthew Dillon 	 *	- child not deleted or deletion is beyond transaction id
13678138a154SMatthew Dillon 	 *	- child created beyond parent synchronization point
13688138a154SMatthew Dillon 	 */
136950456506SMatthew Dillon 	if (child->delete_xid > trans->sync_xid &&
137050456506SMatthew Dillon 	    child->modify_xid > parent->update_xlo) {
13718138a154SMatthew Dillon 		if (base) {
13721897c66eSMatthew Dillon 			hammer2_rollup_stats(parent, child, 1);
1373623d43d4SMatthew Dillon 			hammer2_base_insert(trans, parent, base, count,
1374a7720be7SMatthew Dillon 					    &info->cache_index, child);
137593f3933aSMatthew Dillon 		}
13768138a154SMatthew Dillon 	}
13778138a154SMatthew Dillon 
13788138a154SMatthew Dillon 	return 0;
13798138a154SMatthew Dillon }
13808138a154SMatthew Dillon 
13810dea3156SMatthew Dillon /*
13828138a154SMatthew Dillon  * PASS4 - CLEANUP CHILDREN (non-recursive, but CAN be re-entrant)
1383623d43d4SMatthew Dillon  *
13848138a154SMatthew Dillon  * Adjust queues and set or clear BMAPPED appropriately if processing
1385052e0aa0SMatthew Dillon  * the live parent.  pass4 handles deletions, pass5 handles insertions.
1386052e0aa0SMatthew Dillon  * Separate passes are required because both deletions and insertions can
1387052e0aa0SMatthew Dillon  * occur on dbtree.
13888138a154SMatthew Dillon  *
13898138a154SMatthew Dillon  * Cleanup FLUSH_CREATE/FLUSH_DELETE on the last parent.
13900dea3156SMatthew Dillon  */
13918138a154SMatthew Dillon static int
13928138a154SMatthew Dillon hammer2_flush_pass4(hammer2_chain_t *child, void *data)
13938138a154SMatthew Dillon {
13948138a154SMatthew Dillon 	hammer2_flush_info_t *info = data;
13958138a154SMatthew Dillon 	hammer2_chain_t *parent = info->parent;
1396052e0aa0SMatthew Dillon 	hammer2_chain_core_t *above = child->above;
1397052e0aa0SMatthew Dillon 	hammer2_trans_t *trans = info->trans;
1398052e0aa0SMatthew Dillon 
1399052e0aa0SMatthew Dillon 	/*
1400052e0aa0SMatthew Dillon 	 * Prefilter - Ignore children created after our flush_tid (not
1401052e0aa0SMatthew Dillon 	 *	       visible to our flush).
1402052e0aa0SMatthew Dillon 	 */
140350456506SMatthew Dillon 	if (child->modify_xid > trans->sync_xid) {
140450456506SMatthew Dillon 		KKASSERT(child->delete_xid >= child->modify_xid);
1405052e0aa0SMatthew Dillon 		return 0;
1406052e0aa0SMatthew Dillon 	}
1407052e0aa0SMatthew Dillon 
1408052e0aa0SMatthew Dillon 	/*
1409052e0aa0SMatthew Dillon 	 * Ref and lock child for operation, spinlock must be temporarily
1410052e0aa0SMatthew Dillon 	 * Make sure child is referenced before we unlock.
1411052e0aa0SMatthew Dillon 	 */
1412052e0aa0SMatthew Dillon 	hammer2_chain_ref(child);
1413052e0aa0SMatthew Dillon 	spin_unlock(&above->cst.spin);
1414052e0aa0SMatthew Dillon 	hammer2_chain_lock(child, HAMMER2_RESOLVE_NEVER);
1415052e0aa0SMatthew Dillon 	KKASSERT(child->above == above);
1416052e0aa0SMatthew Dillon 	KKASSERT(parent->core == above);
1417052e0aa0SMatthew Dillon 
1418052e0aa0SMatthew Dillon 	/*
1419052e0aa0SMatthew Dillon 	 * Adjust BMAPPED state and rbtree/queue only when we hit the
1420052e0aa0SMatthew Dillon 	 * actual live parent.
1421052e0aa0SMatthew Dillon 	 */
1422052e0aa0SMatthew Dillon 	if ((parent->flags & HAMMER2_CHAIN_DELETED) == 0) {
1423052e0aa0SMatthew Dillon 		spin_lock(&above->cst.spin);
1424052e0aa0SMatthew Dillon 
1425052e0aa0SMatthew Dillon 		/*
1426052e0aa0SMatthew Dillon 		 * Deleting from blockmap, move child out of dbtree
1427052e0aa0SMatthew Dillon 		 * and clear BMAPPED.  Child should not be on RBTREE.
1428052e0aa0SMatthew Dillon 		 */
142950456506SMatthew Dillon 		if (child->delete_xid <= trans->sync_xid &&
143050456506SMatthew Dillon 		    child->modify_xid <= parent->update_xlo &&
143150456506SMatthew Dillon 		    child->delete_xid > parent->update_xlo &&
1432052e0aa0SMatthew Dillon 		    (child->flags & HAMMER2_CHAIN_BMAPPED)) {
1433052e0aa0SMatthew Dillon 			KKASSERT(child->flags & HAMMER2_CHAIN_ONDBTREE);
1434052e0aa0SMatthew Dillon 			RB_REMOVE(hammer2_chain_tree, &above->dbtree, child);
1435052e0aa0SMatthew Dillon 			atomic_clear_int(&child->flags, HAMMER2_CHAIN_ONDBTREE);
1436052e0aa0SMatthew Dillon 			atomic_clear_int(&child->flags, HAMMER2_CHAIN_BMAPPED);
1437052e0aa0SMatthew Dillon 		}
1438052e0aa0SMatthew Dillon 
1439052e0aa0SMatthew Dillon 		/*
1440052e0aa0SMatthew Dillon 		 * Not on any list, place child on DBQ
1441052e0aa0SMatthew Dillon 		 */
1442052e0aa0SMatthew Dillon 		if ((child->flags & (HAMMER2_CHAIN_ONRBTREE |
1443052e0aa0SMatthew Dillon 				     HAMMER2_CHAIN_ONDBTREE |
1444052e0aa0SMatthew Dillon 				     HAMMER2_CHAIN_ONDBQ)) == 0) {
1445052e0aa0SMatthew Dillon 			KKASSERT((child->flags & HAMMER2_CHAIN_BMAPPED) == 0);
1446052e0aa0SMatthew Dillon 			TAILQ_INSERT_TAIL(&above->dbq, child, db_entry);
1447052e0aa0SMatthew Dillon 			atomic_set_int(&child->flags, HAMMER2_CHAIN_ONDBQ);
1448052e0aa0SMatthew Dillon 		}
1449052e0aa0SMatthew Dillon 		spin_unlock(&above->cst.spin);
1450052e0aa0SMatthew Dillon 	}
1451052e0aa0SMatthew Dillon 
1452052e0aa0SMatthew Dillon 	/*
1453052e0aa0SMatthew Dillon 	 * Unlock the child.  This can wind up dropping the child's
1454052e0aa0SMatthew Dillon 	 * last ref, removing it from the parent's RB tree, and deallocating
1455052e0aa0SMatthew Dillon 	 * the structure.  The RB_SCAN() our caller is doing handles the
1456052e0aa0SMatthew Dillon 	 * situation.
1457052e0aa0SMatthew Dillon 	 */
1458052e0aa0SMatthew Dillon 	hammer2_chain_unlock(child);
1459052e0aa0SMatthew Dillon 	hammer2_chain_drop(child);
1460052e0aa0SMatthew Dillon 	spin_lock(&above->cst.spin);
1461052e0aa0SMatthew Dillon 
1462052e0aa0SMatthew Dillon 	/*
1463052e0aa0SMatthew Dillon 	 * The parent may have been delete-duplicated.
1464052e0aa0SMatthew Dillon 	 */
1465052e0aa0SMatthew Dillon 	return (0);
1466052e0aa0SMatthew Dillon }
1467052e0aa0SMatthew Dillon 
1468052e0aa0SMatthew Dillon static int
1469052e0aa0SMatthew Dillon hammer2_flush_pass5(hammer2_chain_t *child, void *data)
1470052e0aa0SMatthew Dillon {
1471052e0aa0SMatthew Dillon 	hammer2_flush_info_t *info = data;
1472052e0aa0SMatthew Dillon 	hammer2_chain_t *parent = info->parent;
14738138a154SMatthew Dillon 	hammer2_chain_t *xchain;
14748138a154SMatthew Dillon 	hammer2_chain_core_t *above = child->above;
14758138a154SMatthew Dillon 	hammer2_trans_t *trans = info->trans;
1476a7720be7SMatthew Dillon 
14778138a154SMatthew Dillon 	/*
14788138a154SMatthew Dillon 	 * Prefilter - Ignore children created after our flush_tid (not
14798138a154SMatthew Dillon 	 *	       visible to our flush).
14808138a154SMatthew Dillon 	 */
148150456506SMatthew Dillon 	if (child->modify_xid > trans->sync_xid) {
148250456506SMatthew Dillon 		KKASSERT(child->delete_xid >= child->modify_xid);
14838138a154SMatthew Dillon 		return 0;
14848138a154SMatthew Dillon 	}
1485731b2a84SMatthew Dillon 
14868138a154SMatthew Dillon 	/*
14878138a154SMatthew Dillon 	 * Ref and lock child for operation, spinlock must be temporarily
14888138a154SMatthew Dillon 	 * Make sure child is referenced before we unlock.
14898138a154SMatthew Dillon 	 */
14908138a154SMatthew Dillon 	hammer2_chain_ref(child);
14918138a154SMatthew Dillon 	spin_unlock(&above->cst.spin);
14928138a154SMatthew Dillon 	hammer2_chain_lock(child, HAMMER2_RESOLVE_NEVER);
14938138a154SMatthew Dillon 	KKASSERT(child->above == above);
14948138a154SMatthew Dillon 	KKASSERT(parent->core == above);
14958138a154SMatthew Dillon 
14968138a154SMatthew Dillon 	/*
14978138a154SMatthew Dillon 	 * Adjust BMAPPED state and rbtree/queue only when we hit the
14988138a154SMatthew Dillon 	 * actual live parent.
14998138a154SMatthew Dillon 	 */
15008138a154SMatthew Dillon 	if ((parent->flags & HAMMER2_CHAIN_DELETED) == 0) {
1501731b2a84SMatthew Dillon 		spin_lock(&above->cst.spin);
1502a4dc31e0SMatthew Dillon 
1503a4dc31e0SMatthew Dillon 		/*
15048138a154SMatthew Dillon 		 * Inserting into blockmap, place child in rbtree or dbtree.
1505a4dc31e0SMatthew Dillon 		 */
150650456506SMatthew Dillon 		if (child->delete_xid > trans->sync_xid &&
150750456506SMatthew Dillon 		    child->modify_xid > parent->update_xlo &&
15088138a154SMatthew Dillon 		    (child->flags & HAMMER2_CHAIN_BMAPPED) == 0) {
15098138a154SMatthew Dillon 			if (child->flags & HAMMER2_CHAIN_ONDBQ) {
15108138a154SMatthew Dillon 				TAILQ_REMOVE(&above->dbq, child, db_entry);
15110924b3f8SMatthew Dillon 				atomic_clear_int(&child->flags,
15128138a154SMatthew Dillon 						 HAMMER2_CHAIN_ONDBQ);
15130924b3f8SMatthew Dillon 			}
15148138a154SMatthew Dillon 			if ((child->flags & HAMMER2_CHAIN_DELETED) == 0 &&
15158138a154SMatthew Dillon 			    (child->flags & HAMMER2_CHAIN_ONRBTREE) == 0) {
15168138a154SMatthew Dillon 				KKASSERT((child->flags &
15178138a154SMatthew Dillon 					  (HAMMER2_CHAIN_ONDBTREE |
15188138a154SMatthew Dillon 					   HAMMER2_CHAIN_ONDBQ)) == 0);
15198138a154SMatthew Dillon 				xchain = RB_INSERT(hammer2_chain_tree,
15208138a154SMatthew Dillon 						   &above->rbtree, child);
15218138a154SMatthew Dillon 				KKASSERT(xchain == NULL);
15228138a154SMatthew Dillon 				atomic_set_int(&child->flags,
15238138a154SMatthew Dillon 					       HAMMER2_CHAIN_ONRBTREE);
15248138a154SMatthew Dillon 			} else
15258138a154SMatthew Dillon 			if ((child->flags & HAMMER2_CHAIN_DELETED) &&
15268138a154SMatthew Dillon 			    (child->flags & HAMMER2_CHAIN_ONDBTREE) == 0) {
15278138a154SMatthew Dillon 				KKASSERT((child->flags &
15288138a154SMatthew Dillon 					  (HAMMER2_CHAIN_ONRBTREE |
15298138a154SMatthew Dillon 					   HAMMER2_CHAIN_ONDBQ)) == 0);
15308138a154SMatthew Dillon 				xchain = RB_INSERT(hammer2_chain_tree,
15318138a154SMatthew Dillon 						   &above->dbtree, child);
15328138a154SMatthew Dillon 				KKASSERT(xchain == NULL);
15338138a154SMatthew Dillon 				atomic_set_int(&child->flags,
15348138a154SMatthew Dillon 					       HAMMER2_CHAIN_ONDBTREE);
15358138a154SMatthew Dillon 			}
15368138a154SMatthew Dillon 			atomic_set_int(&child->flags, HAMMER2_CHAIN_BMAPPED);
15378138a154SMatthew Dillon 			KKASSERT(child->flags &
15388138a154SMatthew Dillon 				 (HAMMER2_CHAIN_ONRBTREE |
15398138a154SMatthew Dillon 				  HAMMER2_CHAIN_ONDBTREE |
15408138a154SMatthew Dillon 				  HAMMER2_CHAIN_ONDBQ));
15418138a154SMatthew Dillon 		}
15428138a154SMatthew Dillon 
15438138a154SMatthew Dillon 		/*
15448138a154SMatthew Dillon 		 * Not on any list, place child on DBQ
15458138a154SMatthew Dillon 		 */
15468138a154SMatthew Dillon 		if ((child->flags & (HAMMER2_CHAIN_ONRBTREE |
15478138a154SMatthew Dillon 				     HAMMER2_CHAIN_ONDBTREE |
15488138a154SMatthew Dillon 				     HAMMER2_CHAIN_ONDBQ)) == 0) {
15498138a154SMatthew Dillon 			KKASSERT((child->flags & HAMMER2_CHAIN_BMAPPED) == 0);
15508138a154SMatthew Dillon 			TAILQ_INSERT_TAIL(&above->dbq, child, db_entry);
15518138a154SMatthew Dillon 			atomic_set_int(&child->flags, HAMMER2_CHAIN_ONDBQ);
15528138a154SMatthew Dillon 		}
15538138a154SMatthew Dillon 		spin_unlock(&above->cst.spin);
15548138a154SMatthew Dillon 	}
15558138a154SMatthew Dillon 
15568138a154SMatthew Dillon 	/*
15578138a154SMatthew Dillon 	 * Cleanup flags on last parent iterated for flush.
15588138a154SMatthew Dillon 	 */
15598138a154SMatthew Dillon 	if (info->domodify & 2) {
15608138a154SMatthew Dillon 		if (child->flags & HAMMER2_CHAIN_FLUSH_CREATE) {
15618138a154SMatthew Dillon 			atomic_clear_int(&child->flags,
15628138a154SMatthew Dillon 					 HAMMER2_CHAIN_FLUSH_CREATE);
15638138a154SMatthew Dillon 			hammer2_chain_drop(child);
15648138a154SMatthew Dillon 		}
15658138a154SMatthew Dillon 		if ((child->flags & HAMMER2_CHAIN_FLUSH_DELETE) &&
156650456506SMatthew Dillon 		    child->delete_xid <= trans->sync_xid) {
156772ebfa75SMatthew Dillon 			KKASSERT((parent->flags & HAMMER2_CHAIN_DELETED) ||
156872ebfa75SMatthew Dillon 				 (child->flags & HAMMER2_CHAIN_ONDBTREE) == 0);
156972ebfa75SMatthew Dillon 			/* XXX delete-duplicate chain insertion mech wrong */
157072ebfa75SMatthew Dillon 			KKASSERT((parent->flags & HAMMER2_CHAIN_DELETED) ||
157172ebfa75SMatthew Dillon 				 (child->flags & HAMMER2_CHAIN_BMAPPED) == 0);
15728138a154SMatthew Dillon 			atomic_clear_int(&child->flags,
15738138a154SMatthew Dillon 					 HAMMER2_CHAIN_FLUSH_DELETE);
15748138a154SMatthew Dillon 			hammer2_chain_drop(child);
1575ea155208SMatthew Dillon 		}
15760dea3156SMatthew Dillon 	}
15770dea3156SMatthew Dillon 
15780dea3156SMatthew Dillon 	/*
15790dea3156SMatthew Dillon 	 * Unlock the child.  This can wind up dropping the child's
15800dea3156SMatthew Dillon 	 * last ref, removing it from the parent's RB tree, and deallocating
15810dea3156SMatthew Dillon 	 * the structure.  The RB_SCAN() our caller is doing handles the
15820dea3156SMatthew Dillon 	 * situation.
15830dea3156SMatthew Dillon 	 */
15840dea3156SMatthew Dillon 	hammer2_chain_unlock(child);
1585ea155208SMatthew Dillon 	hammer2_chain_drop(child);
1586731b2a84SMatthew Dillon 	spin_lock(&above->cst.spin);
15870dea3156SMatthew Dillon 
15880dea3156SMatthew Dillon 	/*
1589a7720be7SMatthew Dillon 	 * The parent may have been delete-duplicated.
15900dea3156SMatthew Dillon 	 */
15910dea3156SMatthew Dillon 	return (0);
159232b800e6SMatthew Dillon }
159391abd410SMatthew Dillon 
159491abd410SMatthew Dillon void
159591abd410SMatthew Dillon hammer2_rollup_stats(hammer2_chain_t *parent, hammer2_chain_t *child, int how)
159691abd410SMatthew Dillon {
15971897c66eSMatthew Dillon #if 0
159891abd410SMatthew Dillon 	hammer2_chain_t *grandp;
15991897c66eSMatthew Dillon #endif
160091abd410SMatthew Dillon 
160191abd410SMatthew Dillon 	parent->data_count += child->data_count;
160291abd410SMatthew Dillon 	parent->inode_count += child->inode_count;
160391abd410SMatthew Dillon 	child->data_count = 0;
160491abd410SMatthew Dillon 	child->inode_count = 0;
160591abd410SMatthew Dillon 	if (how < 0) {
160691abd410SMatthew Dillon 		parent->data_count -= child->bytes;
160791abd410SMatthew Dillon 		if (child->bref.type == HAMMER2_BREF_TYPE_INODE) {
160891abd410SMatthew Dillon 			parent->inode_count -= 1;
16099ec04660SMatthew Dillon #if 0
16109ec04660SMatthew Dillon 			/* XXX child->data may be NULL atm */
161191abd410SMatthew Dillon 			parent->data_count -= child->data->ipdata.data_count;
161291abd410SMatthew Dillon 			parent->inode_count -= child->data->ipdata.inode_count;
16139ec04660SMatthew Dillon #endif
161491abd410SMatthew Dillon 		}
161591abd410SMatthew Dillon 	} else if (how > 0) {
161691abd410SMatthew Dillon 		parent->data_count += child->bytes;
161791abd410SMatthew Dillon 		if (child->bref.type == HAMMER2_BREF_TYPE_INODE) {
161891abd410SMatthew Dillon 			parent->inode_count += 1;
16199ec04660SMatthew Dillon #if 0
16209ec04660SMatthew Dillon 			/* XXX child->data may be NULL atm */
162191abd410SMatthew Dillon 			parent->data_count += child->data->ipdata.data_count;
162291abd410SMatthew Dillon 			parent->inode_count += child->data->ipdata.inode_count;
16239ec04660SMatthew Dillon #endif
162491abd410SMatthew Dillon 		}
162591abd410SMatthew Dillon 	}
162691abd410SMatthew Dillon 	if (parent->bref.type == HAMMER2_BREF_TYPE_INODE) {
162791abd410SMatthew Dillon 		parent->data->ipdata.data_count += parent->data_count;
162891abd410SMatthew Dillon 		parent->data->ipdata.inode_count += parent->inode_count;
16291897c66eSMatthew Dillon #if 0
163091abd410SMatthew Dillon 		for (grandp = parent->above->first_parent;
163191abd410SMatthew Dillon 		     grandp;
163291abd410SMatthew Dillon 		     grandp = grandp->next_parent) {
163391abd410SMatthew Dillon 			grandp->data_count += parent->data_count;
163491abd410SMatthew Dillon 			grandp->inode_count += parent->inode_count;
163591abd410SMatthew Dillon 		}
16361897c66eSMatthew Dillon #endif
163791abd410SMatthew Dillon 		parent->data_count = 0;
163891abd410SMatthew Dillon 		parent->inode_count = 0;
163991abd410SMatthew Dillon 	}
164091abd410SMatthew Dillon }
1641