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