xref: /dragonfly/sys/vfs/hammer2/hammer2_freemap.c (revision a3fd5153)
15c23d7f1SMatthew Dillon /*
20dea3156SMatthew Dillon  * Copyright (c) 2011-2013 The DragonFly Project.  All rights reserved.
35c23d7f1SMatthew Dillon  *
45c23d7f1SMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
55c23d7f1SMatthew Dillon  * by Matthew Dillon <dillon@dragonflybsd.org>
65c23d7f1SMatthew Dillon  * by Venkatesh Srinivas <vsrinivas@dragonflybsd.org>
75c23d7f1SMatthew Dillon  *
85c23d7f1SMatthew Dillon  * Redistribution and use in source and binary forms, with or without
95c23d7f1SMatthew Dillon  * modification, are permitted provided that the following conditions
105c23d7f1SMatthew Dillon  * are met:
115c23d7f1SMatthew Dillon  *
125c23d7f1SMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
135c23d7f1SMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
145c23d7f1SMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
155c23d7f1SMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
165c23d7f1SMatthew Dillon  *    the documentation and/or other materials provided with the
175c23d7f1SMatthew Dillon  *    distribution.
185c23d7f1SMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
195c23d7f1SMatthew Dillon  *    contributors may be used to endorse or promote products derived
205c23d7f1SMatthew Dillon  *    from this software without specific, prior written permission.
215c23d7f1SMatthew Dillon  *
225c23d7f1SMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
235c23d7f1SMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
245c23d7f1SMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
255c23d7f1SMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
265c23d7f1SMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
275c23d7f1SMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
285c23d7f1SMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
295c23d7f1SMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
305c23d7f1SMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
315c23d7f1SMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
325c23d7f1SMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
335c23d7f1SMatthew Dillon  * SUCH DAMAGE.
345c23d7f1SMatthew Dillon  */
355c23d7f1SMatthew Dillon #include <sys/param.h>
365c23d7f1SMatthew Dillon #include <sys/systm.h>
375c23d7f1SMatthew Dillon #include <sys/kernel.h>
385c23d7f1SMatthew Dillon #include <sys/fcntl.h>
395c23d7f1SMatthew Dillon #include <sys/buf.h>
405c23d7f1SMatthew Dillon #include <sys/proc.h>
415c23d7f1SMatthew Dillon #include <sys/namei.h>
425c23d7f1SMatthew Dillon #include <sys/mount.h>
435c23d7f1SMatthew Dillon #include <sys/vnode.h>
445c23d7f1SMatthew Dillon #include <sys/mountctl.h>
455c23d7f1SMatthew Dillon 
465c23d7f1SMatthew Dillon #include "hammer2.h"
475c23d7f1SMatthew Dillon 
4891abd410SMatthew Dillon struct hammer2_fiterate {
4991abd410SMatthew Dillon 	hammer2_off_t	bpref;
5091abd410SMatthew Dillon 	hammer2_off_t	bnext;
5191abd410SMatthew Dillon 	int		loops;
5291abd410SMatthew Dillon };
5391abd410SMatthew Dillon 
5491abd410SMatthew Dillon typedef struct hammer2_fiterate hammer2_fiterate_t;
5591abd410SMatthew Dillon 
561a7cfe5aSMatthew Dillon static int hammer2_freemap_try_alloc(hammer2_trans_t *trans,
571a7cfe5aSMatthew Dillon 			hammer2_chain_t **parentp, hammer2_blockref_t *bref,
5891abd410SMatthew Dillon 			int radix, hammer2_fiterate_t *iter);
59a5913bdfSMatthew Dillon static void hammer2_freemap_init(hammer2_trans_t *trans, hammer2_mount_t *hmp,
60a5913bdfSMatthew Dillon 			hammer2_key_t key, hammer2_chain_t *chain);
61a5913bdfSMatthew Dillon static int hammer2_bmap_alloc(hammer2_trans_t *trans, hammer2_mount_t *hmp,
6291abd410SMatthew Dillon 			hammer2_bmap_data_t *bmap, uint16_t class,
6393f3933aSMatthew Dillon 			int n, int radix, hammer2_key_t *basep);
641a7cfe5aSMatthew Dillon static int hammer2_freemap_iterate(hammer2_trans_t *trans,
651a7cfe5aSMatthew Dillon 			hammer2_chain_t **parentp, hammer2_chain_t **chainp,
6691abd410SMatthew Dillon 			hammer2_fiterate_t *iter);
671a7cfe5aSMatthew Dillon 
68a98aa0b0SMatthew Dillon static __inline
69a98aa0b0SMatthew Dillon int
70a98aa0b0SMatthew Dillon hammer2_freemapradix(int radix)
71a98aa0b0SMatthew Dillon {
72a98aa0b0SMatthew Dillon 	return(radix);
73a98aa0b0SMatthew Dillon }
74a98aa0b0SMatthew Dillon 
751a7cfe5aSMatthew Dillon /*
761a7cfe5aSMatthew Dillon  * Calculate the device offset for the specified FREEMAP_NODE or FREEMAP_LEAF
771a7cfe5aSMatthew Dillon  * bref.  Return a combined media offset and physical size radix.  Freemap
781a7cfe5aSMatthew Dillon  * chains use fixed storage offsets in the 4MB reserved area at the
791a7cfe5aSMatthew Dillon  * beginning of each 2GB zone
801a7cfe5aSMatthew Dillon  *
811a7cfe5aSMatthew Dillon  * Rotate between four possibilities.  Theoretically this means we have three
821a7cfe5aSMatthew Dillon  * good freemaps in case of a crash which we can use as a base for the fixup
831a7cfe5aSMatthew Dillon  * scan at mount-time.
841a7cfe5aSMatthew Dillon  */
851a7cfe5aSMatthew Dillon #define H2FMBASE(key, radix)	((key) & ~(((hammer2_off_t)1 << (radix)) - 1))
861a7cfe5aSMatthew Dillon #define H2FMSHIFT(radix)	((hammer2_off_t)1 << (radix))
871a7cfe5aSMatthew Dillon 
881a7cfe5aSMatthew Dillon static
891a7cfe5aSMatthew Dillon int
90623d43d4SMatthew Dillon hammer2_freemap_reserve(hammer2_trans_t *trans, hammer2_chain_t *chain,
911a7cfe5aSMatthew Dillon 			int radix)
921a7cfe5aSMatthew Dillon {
93623d43d4SMatthew Dillon 	hammer2_blockref_t *bref = &chain->bref;
941a7cfe5aSMatthew Dillon 	hammer2_off_t off;
95*a3fd5153SMatthew Dillon 	int index;
961a7cfe5aSMatthew Dillon 	size_t bytes;
971a7cfe5aSMatthew Dillon 
981a7cfe5aSMatthew Dillon 	/*
991a7cfe5aSMatthew Dillon 	 * Physical allocation size -> radix.  Typically either 256 for
1001a7cfe5aSMatthew Dillon 	 * a level 0 freemap leaf or 65536 for a level N freemap node.
1011a7cfe5aSMatthew Dillon 	 *
1021a7cfe5aSMatthew Dillon 	 * NOTE: A 256 byte bitmap represents 256 x 8 x 1024 = 2MB of storage.
1031a7cfe5aSMatthew Dillon 	 *	 Do not use hammer2_allocsize() here as it has a min cap.
1041a7cfe5aSMatthew Dillon 	 */
1051a7cfe5aSMatthew Dillon 	bytes = 1 << radix;
1061a7cfe5aSMatthew Dillon 
1071a7cfe5aSMatthew Dillon 	/*
108*a3fd5153SMatthew Dillon 	 * Calculate block selection index 0..7 of current block.
1091a7cfe5aSMatthew Dillon 	 */
1101a7cfe5aSMatthew Dillon 	if ((bref->data_off & ~HAMMER2_OFF_MASK_RADIX) == 0) {
111*a3fd5153SMatthew Dillon 		index = 0;
1121a7cfe5aSMatthew Dillon 	} else {
1131a7cfe5aSMatthew Dillon 		off = bref->data_off & ~HAMMER2_OFF_MASK_RADIX &
1141a7cfe5aSMatthew Dillon 		      (((hammer2_off_t)1 << HAMMER2_FREEMAP_LEVEL1_RADIX) - 1);
1151a7cfe5aSMatthew Dillon 		off = off / HAMMER2_PBUFSIZE;
116*a3fd5153SMatthew Dillon 		KKASSERT(off >= HAMMER2_ZONE_FREEMAP_00 &&
117*a3fd5153SMatthew Dillon 			 off < HAMMER2_ZONE_FREEMAP_END);
118*a3fd5153SMatthew Dillon 		index = (int)(off - HAMMER2_ZONE_FREEMAP_00) / 4;
119*a3fd5153SMatthew Dillon 		KKASSERT(index >= 0 && index < HAMMER2_ZONE_FREEMAP_COPIES);
120623d43d4SMatthew Dillon 	}
1211a7cfe5aSMatthew Dillon 
122623d43d4SMatthew Dillon 	/*
123*a3fd5153SMatthew Dillon 	 * Calculate new index (our 'allocation').  We have to be careful
124*a3fd5153SMatthew Dillon 	 * here as there can be two different transaction ids running
125*a3fd5153SMatthew Dillon 	 * concurrently when a flush is in-progress.
126*a3fd5153SMatthew Dillon 	 *
127*a3fd5153SMatthew Dillon 	 * We also want to make sure, for algorithmic repeatability, that
128*a3fd5153SMatthew Dillon 	 * the index sequences are monotonic with transaction ids.  Some
129*a3fd5153SMatthew Dillon 	 * skipping is allowed as long as we ensure that all four volume
130*a3fd5153SMatthew Dillon 	 * header backups have consistent freemaps.
131*a3fd5153SMatthew Dillon 	 *
132*a3fd5153SMatthew Dillon 	 * FLUSH  NORMAL FLUSH  NORMAL FLUSH  NORMAL FLUSH  NORMAL
133*a3fd5153SMatthew Dillon 	 * N+=1   N+=2
134*a3fd5153SMatthew Dillon 	 * (0->1) (1->3) (3->4) (4->6) (6->7) (7->9) (9->10) (10->12)
135*a3fd5153SMatthew Dillon 	 *
136*a3fd5153SMatthew Dillon 	 * [-concurrent-][-concurrent-][-concurrent-][-concurrent-]
137*a3fd5153SMatthew Dillon 	 *
138*a3fd5153SMatthew Dillon 	 * (alternative first NORMAL might be 0->2 if flush had not yet
139*a3fd5153SMatthew Dillon 	 *  modified the chain, this is the worst case).
140623d43d4SMatthew Dillon 	 */
141*a3fd5153SMatthew Dillon 	if ((trans->flags & HAMMER2_TRANS_ISFLUSH) == 0) {
142*a3fd5153SMatthew Dillon 		/*
143*a3fd5153SMatthew Dillon 		 * Normal transactions always run with the highest TID.
144*a3fd5153SMatthew Dillon 		 * But if a flush is in-progress we want to reserve a slot
145*a3fd5153SMatthew Dillon 		 * for the flush with a lower TID running concurrently to
146*a3fd5153SMatthew Dillon 		 * do a delete-duplicate.
147*a3fd5153SMatthew Dillon 		 */
148*a3fd5153SMatthew Dillon 		index = (index + 2) % HAMMER2_ZONE_FREEMAP_COPIES;
149*a3fd5153SMatthew Dillon 	} else if (trans->flags & HAMMER2_TRANS_ISALLOCATING) {
150*a3fd5153SMatthew Dillon 		/*
151*a3fd5153SMatthew Dillon 		 * Flush transaction, hammer2_freemap.c itself is doing a
152*a3fd5153SMatthew Dillon 		 * delete-duplicate during an allocation within the freemap.
153*a3fd5153SMatthew Dillon 		 */
154*a3fd5153SMatthew Dillon 		index = (index + 1) % HAMMER2_ZONE_FREEMAP_COPIES;
155623d43d4SMatthew Dillon 	} else {
156623d43d4SMatthew Dillon 		/*
157*a3fd5153SMatthew Dillon 		 * Flush transaction, hammer2_flush.c is doing a
158*a3fd5153SMatthew Dillon 		 * delete-duplicate on the freemap while flushing
159*a3fd5153SMatthew Dillon 		 * hmp->fchain.
160623d43d4SMatthew Dillon 		 */
161*a3fd5153SMatthew Dillon 		index = (index + 1) % HAMMER2_ZONE_FREEMAP_COPIES;
1621a7cfe5aSMatthew Dillon 	}
163623d43d4SMatthew Dillon 
1641a7cfe5aSMatthew Dillon 	/*
1651a7cfe5aSMatthew Dillon 	 * Calculate the block offset of the reserved block.  This will
1661a7cfe5aSMatthew Dillon 	 * point into the 4MB reserved area at the base of the appropriate
1671a7cfe5aSMatthew Dillon 	 * 2GB zone, once added to the FREEMAP_x selection above.
1681a7cfe5aSMatthew Dillon 	 */
1691a7cfe5aSMatthew Dillon 	switch(bref->keybits) {
1701a7cfe5aSMatthew Dillon 	/* case HAMMER2_FREEMAP_LEVEL5_RADIX: not applicable */
1711a7cfe5aSMatthew Dillon 	case HAMMER2_FREEMAP_LEVEL4_RADIX:	/* 2EB */
1721a7cfe5aSMatthew Dillon 		KKASSERT(bref->type == HAMMER2_BREF_TYPE_FREEMAP_NODE);
1731a7cfe5aSMatthew Dillon 		KKASSERT(bytes == HAMMER2_FREEMAP_LEVELN_PSIZE);
174*a3fd5153SMatthew Dillon 		off = H2FMBASE(bref->key, HAMMER2_FREEMAP_LEVEL4_RADIX) +
175*a3fd5153SMatthew Dillon 		      (index * 4 + HAMMER2_ZONEFM_LEVEL4) * HAMMER2_PBUFSIZE;
1761a7cfe5aSMatthew Dillon 		break;
1771a7cfe5aSMatthew Dillon 	case HAMMER2_FREEMAP_LEVEL3_RADIX:	/* 2PB */
1781a7cfe5aSMatthew Dillon 		KKASSERT(bref->type == HAMMER2_BREF_TYPE_FREEMAP_NODE);
1791a7cfe5aSMatthew Dillon 		KKASSERT(bytes == HAMMER2_FREEMAP_LEVELN_PSIZE);
180*a3fd5153SMatthew Dillon 		off = H2FMBASE(bref->key, HAMMER2_FREEMAP_LEVEL3_RADIX) +
181*a3fd5153SMatthew Dillon 		      (index * 4 + HAMMER2_ZONEFM_LEVEL3) * HAMMER2_PBUFSIZE;
1821a7cfe5aSMatthew Dillon 		break;
1831a7cfe5aSMatthew Dillon 	case HAMMER2_FREEMAP_LEVEL2_RADIX:	/* 2TB */
1841a7cfe5aSMatthew Dillon 		KKASSERT(bref->type == HAMMER2_BREF_TYPE_FREEMAP_NODE);
1851a7cfe5aSMatthew Dillon 		KKASSERT(bytes == HAMMER2_FREEMAP_LEVELN_PSIZE);
186*a3fd5153SMatthew Dillon 		off = H2FMBASE(bref->key, HAMMER2_FREEMAP_LEVEL2_RADIX) +
187*a3fd5153SMatthew Dillon 		      (index * 4 + HAMMER2_ZONEFM_LEVEL2) * HAMMER2_PBUFSIZE;
1881a7cfe5aSMatthew Dillon 		break;
1891a7cfe5aSMatthew Dillon 	case HAMMER2_FREEMAP_LEVEL1_RADIX:	/* 2GB */
19093f3933aSMatthew Dillon 		KKASSERT(bref->type == HAMMER2_BREF_TYPE_FREEMAP_LEAF);
1911a7cfe5aSMatthew Dillon 		KKASSERT(bytes == HAMMER2_FREEMAP_LEVELN_PSIZE);
192*a3fd5153SMatthew Dillon 		off = H2FMBASE(bref->key, HAMMER2_FREEMAP_LEVEL1_RADIX) +
193*a3fd5153SMatthew Dillon 		      (index * 4 + HAMMER2_ZONEFM_LEVEL1) * HAMMER2_PBUFSIZE;
1941a7cfe5aSMatthew Dillon 		break;
1951a7cfe5aSMatthew Dillon 	default:
1961a7cfe5aSMatthew Dillon 		panic("freemap: bad radix(2) %p %d\n", bref, bref->keybits);
1971a7cfe5aSMatthew Dillon 		/* NOT REACHED */
198*a3fd5153SMatthew Dillon 		off = (hammer2_off_t)-1;
1991a7cfe5aSMatthew Dillon 		break;
2001a7cfe5aSMatthew Dillon 	}
2011a7cfe5aSMatthew Dillon 	bref->data_off = off | radix;
202623d43d4SMatthew Dillon #if 0
203623d43d4SMatthew Dillon 	kprintf("-> %016jx\n", bref->data_off);
204623d43d4SMatthew Dillon #endif
2051a7cfe5aSMatthew Dillon 	return (0);
2061a7cfe5aSMatthew Dillon }
2071a7cfe5aSMatthew Dillon 
2085c23d7f1SMatthew Dillon /*
2091a7cfe5aSMatthew Dillon  * Normal freemap allocator
2101a7cfe5aSMatthew Dillon  *
2111a7cfe5aSMatthew Dillon  * Use available hints to allocate space using the freemap.  Create missing
2121a7cfe5aSMatthew Dillon  * freemap infrastructure on-the-fly as needed (including marking initial
2131a7cfe5aSMatthew Dillon  * allocations using the iterator as allocated, instantiating new 2GB zones,
2141a7cfe5aSMatthew Dillon  * and dealing with the end-of-media edge case).
2151a7cfe5aSMatthew Dillon  *
2161a7cfe5aSMatthew Dillon  * ip and bpref are only used as a heuristic to determine locality of
2171a7cfe5aSMatthew Dillon  * reference.  bref->key may also be used heuristically.
218a4dc31e0SMatthew Dillon  *
219a4dc31e0SMatthew Dillon  * WARNING! When called from a flush we have to use the 'live' sync_tid
220a4dc31e0SMatthew Dillon  *	    and not the flush sync_tid.  The live sync_tid is the flush
221a4dc31e0SMatthew Dillon  *	    sync_tid + 1.  That is, freemap allocations which occur during
222a4dc31e0SMatthew Dillon  *	    a flush are not part of the flush.  Crash-recovery will restore
223a4dc31e0SMatthew Dillon  *	    any lost allocations.
2241a7cfe5aSMatthew Dillon  */
2251a7cfe5aSMatthew Dillon int
226623d43d4SMatthew Dillon hammer2_freemap_alloc(hammer2_trans_t *trans, hammer2_chain_t *chain,
227623d43d4SMatthew Dillon 		      size_t bytes)
2281a7cfe5aSMatthew Dillon {
229623d43d4SMatthew Dillon 	hammer2_mount_t *hmp = chain->hmp;
230623d43d4SMatthew Dillon 	hammer2_blockref_t *bref = &chain->bref;
2311a7cfe5aSMatthew Dillon 	hammer2_chain_t *parent;
2321a7cfe5aSMatthew Dillon 	int radix;
2331a7cfe5aSMatthew Dillon 	int error;
23491abd410SMatthew Dillon 	unsigned int hindex;
23591abd410SMatthew Dillon 	hammer2_fiterate_t iter;
2361a7cfe5aSMatthew Dillon 
2371a7cfe5aSMatthew Dillon 	/*
2381a7cfe5aSMatthew Dillon 	 * Validate the allocation size.  It must be a power of 2.
23993f3933aSMatthew Dillon 	 *
24093f3933aSMatthew Dillon 	 * For now require that the caller be aware of the minimum
24193f3933aSMatthew Dillon 	 * allocation (1K).
2421a7cfe5aSMatthew Dillon 	 */
2431a7cfe5aSMatthew Dillon 	radix = hammer2_getradix(bytes);
2441a7cfe5aSMatthew Dillon 	KKASSERT((size_t)1 << radix == bytes);
2451a7cfe5aSMatthew Dillon 
2461a7cfe5aSMatthew Dillon 	/*
24793f3933aSMatthew Dillon 	 * Freemap blocks themselves are simply assigned from the reserve
24893f3933aSMatthew Dillon 	 * area, not allocated from the freemap.
2491a7cfe5aSMatthew Dillon 	 */
2501a7cfe5aSMatthew Dillon 	if (bref->type == HAMMER2_BREF_TYPE_FREEMAP_NODE ||
2511a7cfe5aSMatthew Dillon 	    bref->type == HAMMER2_BREF_TYPE_FREEMAP_LEAF) {
252623d43d4SMatthew Dillon 		return (hammer2_freemap_reserve(trans, chain, radix));
2531a7cfe5aSMatthew Dillon 	}
2541a7cfe5aSMatthew Dillon 
25510136ab6SMatthew Dillon 	/*
25610136ab6SMatthew Dillon 	 * Mark previously allocated block as possibly freeable.  There might
25710136ab6SMatthew Dillon 	 * be snapshots and other races so we can't just mark it fully free.
25810136ab6SMatthew Dillon 	 * (XXX optimize this for the current-transaction create+delete case)
25910136ab6SMatthew Dillon 	 */
26010136ab6SMatthew Dillon 	if (bref->data_off & ~HAMMER2_OFF_MASK_RADIX) {
26110136ab6SMatthew Dillon 		hammer2_freemap_adjust(trans, hmp, bref,
26210136ab6SMatthew Dillon 				       HAMMER2_FREEMAP_DOMAYFREE);
26310136ab6SMatthew Dillon 	}
26491abd410SMatthew Dillon 
26593f3933aSMatthew Dillon 	/*
266a4dc31e0SMatthew Dillon 	 * Setting ISALLOCATING ensures correct operation even when the
267a4dc31e0SMatthew Dillon 	 * flusher itself is making allocations.
26893f3933aSMatthew Dillon 	 */
26993f3933aSMatthew Dillon 	KKASSERT(bytes >= HAMMER2_MIN_ALLOC && bytes <= HAMMER2_MAX_ALLOC);
270a4dc31e0SMatthew Dillon 	KKASSERT((trans->flags & HAMMER2_TRANS_ISALLOCATING) == 0);
271a7720be7SMatthew Dillon 	atomic_set_int(&trans->flags, HAMMER2_TRANS_ISALLOCATING);
272a4dc31e0SMatthew Dillon 	if (trans->flags & HAMMER2_TRANS_ISFLUSH)
273a4dc31e0SMatthew Dillon 		++trans->sync_tid;
2741a7cfe5aSMatthew Dillon 
27501eabad4SMatthew Dillon 	/*
276a98aa0b0SMatthew Dillon 	 * Calculate the starting point for our allocation search.
277a98aa0b0SMatthew Dillon 	 *
278a98aa0b0SMatthew Dillon 	 * Each freemap leaf is dedicated to a specific freemap_radix.
279a98aa0b0SMatthew Dillon 	 * The freemap_radix can be more fine-grained than the device buffer
280a98aa0b0SMatthew Dillon 	 * radix which results in inodes being grouped together in their
281a98aa0b0SMatthew Dillon 	 * own segment, terminal-data (16K or less) and initial indirect
282a98aa0b0SMatthew Dillon 	 * block being grouped together, and then full-indirect and full-data
283a98aa0b0SMatthew Dillon 	 * blocks (64K) being grouped together.
284a98aa0b0SMatthew Dillon 	 *
285a98aa0b0SMatthew Dillon 	 * The single most important aspect of this is the inode grouping
286a98aa0b0SMatthew Dillon 	 * because that is what allows 'find' and 'ls' and other filesystem
287a98aa0b0SMatthew Dillon 	 * topology operations to run fast.
2881a7cfe5aSMatthew Dillon 	 */
289a98aa0b0SMatthew Dillon #if 0
2901a7cfe5aSMatthew Dillon 	if (bref->data_off & ~HAMMER2_OFF_MASK_RADIX)
2911a7cfe5aSMatthew Dillon 		bpref = bref->data_off & ~HAMMER2_OFF_MASK_RADIX;
2921a7cfe5aSMatthew Dillon 	else if (trans->tmp_bpref)
2931a7cfe5aSMatthew Dillon 		bpref = trans->tmp_bpref;
2941a7cfe5aSMatthew Dillon 	else if (trans->tmp_ip)
2951a7cfe5aSMatthew Dillon 		bpref = trans->tmp_ip->chain->bref.data_off;
2961a7cfe5aSMatthew Dillon 	else
2971a7cfe5aSMatthew Dillon #endif
29891abd410SMatthew Dillon 	/*
29991abd410SMatthew Dillon 	 * Heuristic tracking index.  We would like one for each distinct
30091abd410SMatthew Dillon 	 * bref type if possible.  heur_freemap[] has room for two classes
30191abd410SMatthew Dillon 	 * for each type.  At a minimum we have to break-up our heuristic
30291abd410SMatthew Dillon 	 * by device block sizes.
30391abd410SMatthew Dillon 	 */
30491abd410SMatthew Dillon 	hindex = hammer2_devblkradix(radix) - HAMMER2_MINIORADIX;
30591abd410SMatthew Dillon 	KKASSERT(hindex < HAMMER2_FREEMAP_HEUR_NRADIX);
30691abd410SMatthew Dillon 	hindex += bref->type * HAMMER2_FREEMAP_HEUR_NRADIX;
30791abd410SMatthew Dillon 	hindex &= HAMMER2_FREEMAP_HEUR_TYPES * HAMMER2_FREEMAP_HEUR_NRADIX - 1;
30891abd410SMatthew Dillon 	KKASSERT(hindex < HAMMER2_FREEMAP_HEUR);
30991abd410SMatthew Dillon 
31091abd410SMatthew Dillon 	iter.bpref = hmp->heur_freemap[hindex];
3111a7cfe5aSMatthew Dillon 
3121a7cfe5aSMatthew Dillon 	/*
3131a7cfe5aSMatthew Dillon 	 * Make sure bpref is in-bounds.  It's ok if bpref covers a zone's
3141a7cfe5aSMatthew Dillon 	 * reserved area, the try code will iterate past it.
3151a7cfe5aSMatthew Dillon 	 */
31691abd410SMatthew Dillon 	if (iter.bpref > hmp->voldata.volu_size)
31791abd410SMatthew Dillon 		iter.bpref = hmp->voldata.volu_size - 1;
3181a7cfe5aSMatthew Dillon 
3191a7cfe5aSMatthew Dillon 	/*
3201a7cfe5aSMatthew Dillon 	 * Iterate the freemap looking for free space before and after.
3211a7cfe5aSMatthew Dillon 	 */
3221a7cfe5aSMatthew Dillon 	parent = &hmp->fchain;
3231a7cfe5aSMatthew Dillon 	hammer2_chain_lock(parent, HAMMER2_RESOLVE_ALWAYS);
3241a7cfe5aSMatthew Dillon 	error = EAGAIN;
32591abd410SMatthew Dillon 	iter.bnext = iter.bpref;
32691abd410SMatthew Dillon 	iter.loops = 0;
3271a7cfe5aSMatthew Dillon 
3281a7cfe5aSMatthew Dillon 	while (error == EAGAIN) {
3291a7cfe5aSMatthew Dillon 		error = hammer2_freemap_try_alloc(trans, &parent, bref,
33091abd410SMatthew Dillon 						  radix, &iter);
3311a7cfe5aSMatthew Dillon 	}
33291abd410SMatthew Dillon 	hmp->heur_freemap[hindex] = iter.bnext;
3331a7cfe5aSMatthew Dillon 	hammer2_chain_unlock(parent);
3341a7cfe5aSMatthew Dillon 
335a7720be7SMatthew Dillon 	atomic_clear_int(&trans->flags, HAMMER2_TRANS_ISALLOCATING);
336a4dc31e0SMatthew Dillon 	if (trans->flags & HAMMER2_TRANS_ISFLUSH)
337a4dc31e0SMatthew Dillon 		--trans->sync_tid;
338a7720be7SMatthew Dillon 
3391a7cfe5aSMatthew Dillon 	return (error);
3401a7cfe5aSMatthew Dillon }
3411a7cfe5aSMatthew Dillon 
3421a7cfe5aSMatthew Dillon static int
3431a7cfe5aSMatthew Dillon hammer2_freemap_try_alloc(hammer2_trans_t *trans, hammer2_chain_t **parentp,
3441a7cfe5aSMatthew Dillon 			  hammer2_blockref_t *bref, int radix,
34591abd410SMatthew Dillon 			  hammer2_fiterate_t *iter)
3461a7cfe5aSMatthew Dillon {
347a5913bdfSMatthew Dillon 	hammer2_mount_t *hmp = (*parentp)->hmp;
3481a7cfe5aSMatthew Dillon 	hammer2_off_t l0size;
34993f3933aSMatthew Dillon 	hammer2_off_t l1size;
35093f3933aSMatthew Dillon 	hammer2_off_t l1mask;
3511897c66eSMatthew Dillon 	hammer2_key_t key_dummy;
3521a7cfe5aSMatthew Dillon 	hammer2_chain_t *chain;
3531a7cfe5aSMatthew Dillon 	hammer2_off_t key;
3541a7cfe5aSMatthew Dillon 	size_t bytes;
35591abd410SMatthew Dillon 	uint16_t class;
3561a7cfe5aSMatthew Dillon 	int error = 0;
3571897c66eSMatthew Dillon 	int cache_index = -1;
35893f3933aSMatthew Dillon 
3591a7cfe5aSMatthew Dillon 
3601a7cfe5aSMatthew Dillon 	/*
3611a7cfe5aSMatthew Dillon 	 * Calculate the number of bytes being allocated, the number
3621a7cfe5aSMatthew Dillon 	 * of contiguous bits of bitmap being allocated, and the bitmap
3631a7cfe5aSMatthew Dillon 	 * mask.
36401eabad4SMatthew Dillon 	 *
3651a7cfe5aSMatthew Dillon 	 * WARNING! cpu hardware may mask bits == 64 -> 0 and blow up the
3661a7cfe5aSMatthew Dillon 	 *	    mask calculation.
3671a7cfe5aSMatthew Dillon 	 */
3681a7cfe5aSMatthew Dillon 	bytes = (size_t)1 << radix;
36991abd410SMatthew Dillon 	class = (bref->type << 8) | hammer2_devblkradix(radix);
370a98aa0b0SMatthew Dillon 
3711a7cfe5aSMatthew Dillon 	/*
37293f3933aSMatthew Dillon 	 * Lookup the level1 freemap chain, creating and initializing one
3731a7cfe5aSMatthew Dillon 	 * if necessary.  Intermediate levels will be created automatically
3741a7cfe5aSMatthew Dillon 	 * when necessary by hammer2_chain_create().
3751a7cfe5aSMatthew Dillon 	 */
37691abd410SMatthew Dillon 	key = H2FMBASE(iter->bnext, HAMMER2_FREEMAP_LEVEL1_RADIX);
3771a7cfe5aSMatthew Dillon 	l0size = H2FMSHIFT(HAMMER2_FREEMAP_LEVEL0_RADIX);
37893f3933aSMatthew Dillon 	l1size = H2FMSHIFT(HAMMER2_FREEMAP_LEVEL1_RADIX);
37993f3933aSMatthew Dillon 	l1mask = l1size - 1;
3801a7cfe5aSMatthew Dillon 
3811897c66eSMatthew Dillon 	chain = hammer2_chain_lookup(parentp, &key_dummy, key, key + l1mask,
3821897c66eSMatthew Dillon 				     &cache_index,
3831a7cfe5aSMatthew Dillon 				     HAMMER2_LOOKUP_ALWAYS |
38410136ab6SMatthew Dillon 				     HAMMER2_LOOKUP_MATCHIND);
385623d43d4SMatthew Dillon 
3861a7cfe5aSMatthew Dillon 	if (chain == NULL) {
3871a7cfe5aSMatthew Dillon 		/*
3881a7cfe5aSMatthew Dillon 		 * Create the missing leaf, be sure to initialize
3891a7cfe5aSMatthew Dillon 		 * the auxillary freemap tracking information in
3901a7cfe5aSMatthew Dillon 		 * the bref.check.freemap structure.
3911a7cfe5aSMatthew Dillon 		 */
3921a7cfe5aSMatthew Dillon #if 0
39393f3933aSMatthew Dillon 		kprintf("freemap create L1 @ %016jx bpref %016jx\n",
39491abd410SMatthew Dillon 			key, iter->bpref);
3951a7cfe5aSMatthew Dillon #endif
3961a7cfe5aSMatthew Dillon 		error = hammer2_chain_create(trans, parentp, &chain,
39793f3933aSMatthew Dillon 				     key, HAMMER2_FREEMAP_LEVEL1_RADIX,
3981a7cfe5aSMatthew Dillon 				     HAMMER2_BREF_TYPE_FREEMAP_LEAF,
39993f3933aSMatthew Dillon 				     HAMMER2_FREEMAP_LEVELN_PSIZE);
4000924b3f8SMatthew Dillon 		KKASSERT(error == 0);
4011a7cfe5aSMatthew Dillon 		if (error == 0) {
4021a7cfe5aSMatthew Dillon 			hammer2_chain_modify(trans, &chain, 0);
40393f3933aSMatthew Dillon 			bzero(&chain->data->bmdata[0],
40493f3933aSMatthew Dillon 			      HAMMER2_FREEMAP_LEVELN_PSIZE);
40593f3933aSMatthew Dillon 			chain->bref.check.freemap.bigmask = (uint32_t)-1;
40693f3933aSMatthew Dillon 			chain->bref.check.freemap.avail = l1size;
40793f3933aSMatthew Dillon 			/* bref.methods should already be inherited */
4081a7cfe5aSMatthew Dillon 
409a5913bdfSMatthew Dillon 			hammer2_freemap_init(trans, hmp, key, chain);
4101a7cfe5aSMatthew Dillon 		}
41193f3933aSMatthew Dillon 	} else if ((chain->bref.check.freemap.bigmask & (1 << radix)) == 0) {
4121a7cfe5aSMatthew Dillon 		/*
4131a7cfe5aSMatthew Dillon 		 * Already flagged as not having enough space
4141a7cfe5aSMatthew Dillon 		 */
4151a7cfe5aSMatthew Dillon 		error = ENOSPC;
4161a7cfe5aSMatthew Dillon 	} else {
4171a7cfe5aSMatthew Dillon 		/*
4181a7cfe5aSMatthew Dillon 		 * Modify existing chain to setup for adjustment.
4191a7cfe5aSMatthew Dillon 		 */
4201a7cfe5aSMatthew Dillon 		hammer2_chain_modify(trans, &chain, 0);
4211a7cfe5aSMatthew Dillon 	}
4221a7cfe5aSMatthew Dillon 
4231a7cfe5aSMatthew Dillon 	/*
42493f3933aSMatthew Dillon 	 * Scan 2MB entries.
4251a7cfe5aSMatthew Dillon 	 */
42693f3933aSMatthew Dillon 	if (error == 0) {
42793f3933aSMatthew Dillon 		hammer2_bmap_data_t *bmap;
42893f3933aSMatthew Dillon 		hammer2_key_t base_key;
42993f3933aSMatthew Dillon 		int count;
43093f3933aSMatthew Dillon 		int start;
43193f3933aSMatthew Dillon 		int n;
4321a7cfe5aSMatthew Dillon 
43310136ab6SMatthew Dillon 		KKASSERT(chain->bref.type == HAMMER2_BREF_TYPE_FREEMAP_LEAF);
43491abd410SMatthew Dillon 		start = (int)((iter->bnext - key) >>
43591abd410SMatthew Dillon 			      HAMMER2_FREEMAP_LEVEL0_RADIX);
43693f3933aSMatthew Dillon 		KKASSERT(start >= 0 && start < HAMMER2_FREEMAP_COUNT);
43793f3933aSMatthew Dillon 		hammer2_chain_modify(trans, &chain, 0);
4381a7cfe5aSMatthew Dillon 
4391a7cfe5aSMatthew Dillon 		error = ENOSPC;
44093f3933aSMatthew Dillon 		for (count = 0; count < HAMMER2_FREEMAP_COUNT; ++count) {
44193f3933aSMatthew Dillon 			if (start + count >= HAMMER2_FREEMAP_COUNT &&
44293f3933aSMatthew Dillon 			    start - count < 0) {
44393f3933aSMatthew Dillon 				break;
44493f3933aSMatthew Dillon 			}
44593f3933aSMatthew Dillon 			n = start + count;
44693f3933aSMatthew Dillon 			bmap = &chain->data->bmdata[n];
44793f3933aSMatthew Dillon 			if (n < HAMMER2_FREEMAP_COUNT && bmap->avail &&
44891abd410SMatthew Dillon 			    (bmap->class == 0 || bmap->class == class)) {
44993f3933aSMatthew Dillon 				base_key = key + n * l0size;
45091abd410SMatthew Dillon 				error = hammer2_bmap_alloc(trans, hmp, bmap,
45191abd410SMatthew Dillon 							   class, n, radix,
45291abd410SMatthew Dillon 							   &base_key);
45393f3933aSMatthew Dillon 				if (error != ENOSPC) {
45493f3933aSMatthew Dillon 					key = base_key;
45593f3933aSMatthew Dillon 					break;
45693f3933aSMatthew Dillon 				}
45793f3933aSMatthew Dillon 			}
45893f3933aSMatthew Dillon 			n = start - count;
45993f3933aSMatthew Dillon 			bmap = &chain->data->bmdata[n];
46093f3933aSMatthew Dillon 			if (n >= 0 && bmap->avail &&
46191abd410SMatthew Dillon 			    (bmap->class == 0 || bmap->class == class)) {
46293f3933aSMatthew Dillon 				base_key = key + n * l0size;
46391abd410SMatthew Dillon 				error = hammer2_bmap_alloc(trans, hmp, bmap,
46491abd410SMatthew Dillon 							   class, n, radix,
46591abd410SMatthew Dillon 							   &base_key);
46693f3933aSMatthew Dillon 				if (error != ENOSPC) {
46793f3933aSMatthew Dillon 					key = base_key;
46893f3933aSMatthew Dillon 					break;
46993f3933aSMatthew Dillon 				}
47093f3933aSMatthew Dillon 			}
47193f3933aSMatthew Dillon 		}
47293f3933aSMatthew Dillon 		if (error == ENOSPC)
47393f3933aSMatthew Dillon 			chain->bref.check.freemap.bigmask &= ~(1 << radix);
47493f3933aSMatthew Dillon 		/* XXX also scan down from original count */
47593f3933aSMatthew Dillon 	}
4761a7cfe5aSMatthew Dillon 
4771a7cfe5aSMatthew Dillon 	if (error == 0) {
4781a7cfe5aSMatthew Dillon 		/*
4791a7cfe5aSMatthew Dillon 		 * Assert validity.  Must be beyond the static allocator used
4801a7cfe5aSMatthew Dillon 		 * by newfs_hammer2 (and thus also beyond the aux area),
4811a7cfe5aSMatthew Dillon 		 * not go past the volume size, and must not be in the
4821a7cfe5aSMatthew Dillon 		 * reserved segment area for a zone.
4831a7cfe5aSMatthew Dillon 		 */
4841a7cfe5aSMatthew Dillon 		KKASSERT(key >= hmp->voldata.allocator_beg &&
4851a7cfe5aSMatthew Dillon 			 key + bytes <= hmp->voldata.volu_size);
4861a7cfe5aSMatthew Dillon 		KKASSERT((key & HAMMER2_ZONE_MASK64) >= HAMMER2_ZONE_SEG);
4871a7cfe5aSMatthew Dillon 		bref->data_off = key | radix;
4881a7cfe5aSMatthew Dillon 
4891a7cfe5aSMatthew Dillon #if 0
49093f3933aSMatthew Dillon 		kprintf("alloc cp=%p %016jx %016jx using %016jx\n",
4911a7cfe5aSMatthew Dillon 			chain,
49293f3933aSMatthew Dillon 			bref->key, bref->data_off, chain->bref.data_off);
4931a7cfe5aSMatthew Dillon #endif
4941a7cfe5aSMatthew Dillon 	} else if (error == ENOSPC) {
4951a7cfe5aSMatthew Dillon 		/*
49691abd410SMatthew Dillon 		 * Return EAGAIN with next iteration in iter->bnext, or
4971a7cfe5aSMatthew Dillon 		 * return ENOSPC if the allocation map has been exhausted.
4981a7cfe5aSMatthew Dillon 		 */
49991abd410SMatthew Dillon 		error = hammer2_freemap_iterate(trans, parentp, &chain, iter);
5001a7cfe5aSMatthew Dillon 	}
5011a7cfe5aSMatthew Dillon 
5021a7cfe5aSMatthew Dillon 	/*
5031a7cfe5aSMatthew Dillon 	 * Cleanup
5041a7cfe5aSMatthew Dillon 	 */
5051a7cfe5aSMatthew Dillon 	if (chain)
5061a7cfe5aSMatthew Dillon 		hammer2_chain_unlock(chain);
5071a7cfe5aSMatthew Dillon 	return (error);
5081a7cfe5aSMatthew Dillon }
5091a7cfe5aSMatthew Dillon 
51093f3933aSMatthew Dillon /*
51193f3933aSMatthew Dillon  * Allocate (1<<radix) bytes from the bmap whos base data offset is (*basep).
51293f3933aSMatthew Dillon  *
51393f3933aSMatthew Dillon  * If the linear iterator is mid-block we use it directly (the bitmap should
51493f3933aSMatthew Dillon  * already be marked allocated), otherwise we search for a block in the bitmap
51593f3933aSMatthew Dillon  * that fits the allocation request.
51693f3933aSMatthew Dillon  *
51793f3933aSMatthew Dillon  * A partial bitmap allocation sets the minimum bitmap granularity (16KB)
51893f3933aSMatthew Dillon  * to fully allocated and adjusts the linear allocator to allow the
51993f3933aSMatthew Dillon  * remaining space to be allocated.
52093f3933aSMatthew Dillon  */
52193f3933aSMatthew Dillon static
52293f3933aSMatthew Dillon int
523a5913bdfSMatthew Dillon hammer2_bmap_alloc(hammer2_trans_t *trans, hammer2_mount_t *hmp,
524a5913bdfSMatthew Dillon 		   hammer2_bmap_data_t *bmap,
52591abd410SMatthew Dillon 		   uint16_t class, int n, int radix, hammer2_key_t *basep)
52693f3933aSMatthew Dillon {
527fdf62707SMatthew Dillon 	hammer2_io_t *dio;
52893f3933aSMatthew Dillon 	size_t size;
52991abd410SMatthew Dillon 	size_t bsize;
53093f3933aSMatthew Dillon 	int bmradix;
53193f3933aSMatthew Dillon 	uint32_t bmmask;
53293f3933aSMatthew Dillon 	int offset;
533fdf62707SMatthew Dillon 	int error;
53493f3933aSMatthew Dillon 	int i;
53593f3933aSMatthew Dillon 	int j;
53693f3933aSMatthew Dillon 
53793f3933aSMatthew Dillon 	/*
53893f3933aSMatthew Dillon 	 * Take into account 2-bits per block when calculating bmradix.
53993f3933aSMatthew Dillon 	 */
54093f3933aSMatthew Dillon 	size = (size_t)1 << radix;
54191abd410SMatthew Dillon 
54293f3933aSMatthew Dillon 	if (radix <= HAMMER2_FREEMAP_BLOCK_RADIX) {
54393f3933aSMatthew Dillon 		bmradix = 2;
54491abd410SMatthew Dillon 		bsize = HAMMER2_FREEMAP_BLOCK_SIZE;
54593f3933aSMatthew Dillon 		/* (16K) 2 bits per allocation block */
54693f3933aSMatthew Dillon 	} else {
54793f3933aSMatthew Dillon 		bmradix = 2 << (radix - HAMMER2_FREEMAP_BLOCK_RADIX);
54891abd410SMatthew Dillon 		bsize = size;
54993f3933aSMatthew Dillon 		/* (32K-256K) 4, 8, 16, 32 bits per allocation block */
55093f3933aSMatthew Dillon 	}
55193f3933aSMatthew Dillon 
55293f3933aSMatthew Dillon 	/*
55391abd410SMatthew Dillon 	 * Use the linear iterator to pack small allocations, otherwise
55491abd410SMatthew Dillon 	 * fall-back to finding a free 16KB chunk.  The linear iterator
55591abd410SMatthew Dillon 	 * is only valid when *NOT* on a freemap chunking boundary (16KB).
55691abd410SMatthew Dillon 	 * If it is the bitmap must be scanned.  It can become invalid
55791abd410SMatthew Dillon 	 * once we pack to the boundary.  We adjust it after a bitmap
55891abd410SMatthew Dillon 	 * allocation only for sub-16KB allocations (so the perfectly good
55991abd410SMatthew Dillon 	 * previous value can still be used for fragments when 16KB+
56091abd410SMatthew Dillon 	 * allocations are made).
56191abd410SMatthew Dillon 	 *
56291abd410SMatthew Dillon 	 * Beware of hardware artifacts when bmradix == 32 (intermediate
56391abd410SMatthew Dillon 	 * result can wind up being '1' instead of '0' if hardware masks
56491abd410SMatthew Dillon 	 * bit-count & 31).
56593f3933aSMatthew Dillon 	 *
56693f3933aSMatthew Dillon 	 * NOTE: j needs to be even in the j= calculation.  As an artifact
56793f3933aSMatthew Dillon 	 *	 of the /2 division, our bitmask has to clear bit 0.
56891abd410SMatthew Dillon 	 *
56991abd410SMatthew Dillon 	 * NOTE: TODO this can leave little unallocatable fragments lying
57091abd410SMatthew Dillon 	 *	 around.
57193f3933aSMatthew Dillon 	 */
57291abd410SMatthew Dillon 	if (((uint32_t)bmap->linear & HAMMER2_FREEMAP_BLOCK_MASK) + size <=
57391abd410SMatthew Dillon 	    HAMMER2_FREEMAP_BLOCK_SIZE &&
5742c6f594dSMatthew Dillon 	    (bmap->linear & HAMMER2_FREEMAP_BLOCK_MASK) &&
57591abd410SMatthew Dillon 	    bmap->linear < HAMMER2_SEGSIZE) {
57693f3933aSMatthew Dillon 		KKASSERT(bmap->linear >= 0 &&
57791abd410SMatthew Dillon 			 bmap->linear + size <= HAMMER2_SEGSIZE &&
57891abd410SMatthew Dillon 			 (bmap->linear & (HAMMER2_MIN_ALLOC - 1)) == 0);
57993f3933aSMatthew Dillon 		offset = bmap->linear;
58093f3933aSMatthew Dillon 		i = offset / (HAMMER2_SEGSIZE / 8);
58193f3933aSMatthew Dillon 		j = (offset / (HAMMER2_FREEMAP_BLOCK_SIZE / 2)) & 30;
58293f3933aSMatthew Dillon 		bmmask = (bmradix == 32) ?
58393f3933aSMatthew Dillon 			 0xFFFFFFFFU : (1 << bmradix) - 1;
58493f3933aSMatthew Dillon 		bmmask <<= j;
58591abd410SMatthew Dillon 		bmap->linear = offset + size;
58693f3933aSMatthew Dillon 	} else {
58793f3933aSMatthew Dillon 		for (i = 0; i < 8; ++i) {
58893f3933aSMatthew Dillon 			bmmask = (bmradix == 32) ?
58993f3933aSMatthew Dillon 				 0xFFFFFFFFU : (1 << bmradix) - 1;
59093f3933aSMatthew Dillon 			for (j = 0; j < 32; j += bmradix) {
59193f3933aSMatthew Dillon 				if ((bmap->bitmap[i] & bmmask) == 0)
59293f3933aSMatthew Dillon 					goto success;
59393f3933aSMatthew Dillon 				bmmask <<= bmradix;
59493f3933aSMatthew Dillon 			}
59593f3933aSMatthew Dillon 		}
59691abd410SMatthew Dillon 		/*fragments might remain*/
59791abd410SMatthew Dillon 		/*KKASSERT(bmap->avail == 0);*/
59893f3933aSMatthew Dillon 		return (ENOSPC);
59993f3933aSMatthew Dillon success:
60093f3933aSMatthew Dillon 		offset = i * (HAMMER2_SEGSIZE / 8) +
60193f3933aSMatthew Dillon 			 (j * (HAMMER2_FREEMAP_BLOCK_SIZE / 2));
60291abd410SMatthew Dillon 		if (size & HAMMER2_FREEMAP_BLOCK_MASK)
60391abd410SMatthew Dillon 			bmap->linear = offset + size;
60493f3933aSMatthew Dillon 	}
60593f3933aSMatthew Dillon 
60693f3933aSMatthew Dillon 	KKASSERT(i >= 0 && i < 8);	/* 8 x 16 -> 128 x 16K -> 2MB */
60793f3933aSMatthew Dillon 
60893f3933aSMatthew Dillon 	/*
60993f3933aSMatthew Dillon 	 * Optimize the buffer cache to avoid unnecessary read-before-write
61093f3933aSMatthew Dillon 	 * operations.
61191abd410SMatthew Dillon 	 *
61291abd410SMatthew Dillon 	 * The device block size could be larger than the allocation size
61391abd410SMatthew Dillon 	 * so the actual bitmap test is somewhat more involved.  We have
61491abd410SMatthew Dillon 	 * to use a compatible buffer size for this operation.
61593f3933aSMatthew Dillon 	 */
6162c6f594dSMatthew Dillon 	if ((bmap->bitmap[i] & bmmask) == 0 &&
6172c6f594dSMatthew Dillon 	    hammer2_devblksize(size) != size) {
61891abd410SMatthew Dillon 		size_t psize = hammer2_devblksize(size);
61991abd410SMatthew Dillon 		hammer2_off_t pmask = (hammer2_off_t)psize - 1;
62091abd410SMatthew Dillon 		int pbmradix = 2 << (hammer2_devblkradix(radix) -
62191abd410SMatthew Dillon 				     HAMMER2_FREEMAP_BLOCK_RADIX);
62291abd410SMatthew Dillon 		uint32_t pbmmask;
623fdf62707SMatthew Dillon 		int pradix = hammer2_getradix(psize);
62491abd410SMatthew Dillon 
62591abd410SMatthew Dillon 		pbmmask = (pbmradix == 32) ? 0xFFFFFFFFU : (1 << pbmradix) - 1;
62691abd410SMatthew Dillon 		while ((pbmmask & bmmask) == 0)
62791abd410SMatthew Dillon 			pbmmask <<= pbmradix;
62891abd410SMatthew Dillon 
6292c6f594dSMatthew Dillon #if 0
6302c6f594dSMatthew Dillon 		kprintf("%016jx mask %08x %08x %08x (%zd/%zd)\n",
6312c6f594dSMatthew Dillon 			*basep + offset, bmap->bitmap[i],
6322c6f594dSMatthew Dillon 			pbmmask, bmmask, size, psize);
6332c6f594dSMatthew Dillon #endif
6342c6f594dSMatthew Dillon 
63591abd410SMatthew Dillon 		if ((bmap->bitmap[i] & pbmmask) == 0) {
636fdf62707SMatthew Dillon 			error = hammer2_io_newq(hmp,
637fdf62707SMatthew Dillon 						(*basep + (offset & ~pmask)) |
638fdf62707SMatthew Dillon 						 pradix,
639fdf62707SMatthew Dillon 						psize, &dio);
640fdf62707SMatthew Dillon 			hammer2_io_bqrelse(&dio);
64193f3933aSMatthew Dillon 		}
64291abd410SMatthew Dillon 	}
64393f3933aSMatthew Dillon 
64493f3933aSMatthew Dillon #if 0
64593f3933aSMatthew Dillon 	/*
64693f3933aSMatthew Dillon 	 * When initializing a new inode segment also attempt to initialize
64793f3933aSMatthew Dillon 	 * an adjacent segment.  Be careful not to index beyond the array
64893f3933aSMatthew Dillon 	 * bounds.
64993f3933aSMatthew Dillon 	 *
65093f3933aSMatthew Dillon 	 * We do this to try to localize inode accesses to improve
65193f3933aSMatthew Dillon 	 * directory scan rates.  XXX doesn't improve scan rates.
65293f3933aSMatthew Dillon 	 */
65393f3933aSMatthew Dillon 	if (size == HAMMER2_INODE_BYTES) {
65493f3933aSMatthew Dillon 		if (n & 1) {
65593f3933aSMatthew Dillon 			if (bmap[-1].radix == 0 && bmap[-1].avail)
65693f3933aSMatthew Dillon 				bmap[-1].radix = radix;
65793f3933aSMatthew Dillon 		} else {
65893f3933aSMatthew Dillon 			if (bmap[1].radix == 0 && bmap[1].avail)
65993f3933aSMatthew Dillon 				bmap[1].radix = radix;
66093f3933aSMatthew Dillon 		}
66193f3933aSMatthew Dillon 	}
66293f3933aSMatthew Dillon #endif
66393f3933aSMatthew Dillon 
66493f3933aSMatthew Dillon 	/*
66593f3933aSMatthew Dillon 	 * Adjust the linear iterator, set the radix if necessary (might as
66693f3933aSMatthew Dillon 	 * well just set it unconditionally), adjust *basep to return the
66793f3933aSMatthew Dillon 	 * allocated data offset.
66893f3933aSMatthew Dillon 	 */
66993f3933aSMatthew Dillon 	bmap->bitmap[i] |= bmmask;
67091abd410SMatthew Dillon 	bmap->class = class;
67193f3933aSMatthew Dillon 	bmap->avail -= size;
67293f3933aSMatthew Dillon 	*basep += offset;
67393f3933aSMatthew Dillon 
6749f604b01SMatthew Dillon 	hammer2_voldata_lock(hmp);
6759f604b01SMatthew Dillon 	hmp->voldata.allocator_free -= size;  /* XXX */
6769f604b01SMatthew Dillon 	hammer2_voldata_unlock(hmp, 1);
6779f604b01SMatthew Dillon 
67893f3933aSMatthew Dillon 	return(0);
67993f3933aSMatthew Dillon }
68093f3933aSMatthew Dillon 
68193f3933aSMatthew Dillon static
68293f3933aSMatthew Dillon void
683a5913bdfSMatthew Dillon hammer2_freemap_init(hammer2_trans_t *trans, hammer2_mount_t *hmp,
684a5913bdfSMatthew Dillon 		     hammer2_key_t key, hammer2_chain_t *chain)
68593f3933aSMatthew Dillon {
68693f3933aSMatthew Dillon 	hammer2_off_t l1size;
68793f3933aSMatthew Dillon 	hammer2_off_t lokey;
68893f3933aSMatthew Dillon 	hammer2_off_t hikey;
68993f3933aSMatthew Dillon 	hammer2_bmap_data_t *bmap;
69093f3933aSMatthew Dillon 	int count;
69193f3933aSMatthew Dillon 
69293f3933aSMatthew Dillon 	l1size = H2FMSHIFT(HAMMER2_FREEMAP_LEVEL1_RADIX);
69393f3933aSMatthew Dillon 
69493f3933aSMatthew Dillon 	/*
69593f3933aSMatthew Dillon 	 * Calculate the portion of the 2GB map that should be initialized
69693f3933aSMatthew Dillon 	 * as free.  Portions below or after will be initialized as allocated.
69793f3933aSMatthew Dillon 	 * SEGMASK-align the areas so we don't have to worry about sub-scans
69893f3933aSMatthew Dillon 	 * or endianess when using memset.
69993f3933aSMatthew Dillon 	 *
70093f3933aSMatthew Dillon 	 * (1) Ensure that all statically allocated space from newfs_hammer2
70193f3933aSMatthew Dillon 	 *     is marked allocated.
70293f3933aSMatthew Dillon 	 *
70393f3933aSMatthew Dillon 	 * (2) Ensure that the reserved area is marked allocated (typically
70493f3933aSMatthew Dillon 	 *     the first 4MB of the 2GB area being represented).
70593f3933aSMatthew Dillon 	 *
70693f3933aSMatthew Dillon 	 * (3) Ensure that any trailing space at the end-of-volume is marked
70793f3933aSMatthew Dillon 	 *     allocated.
70893f3933aSMatthew Dillon 	 *
70993f3933aSMatthew Dillon 	 * WARNING! It is possible for lokey to be larger than hikey if the
71093f3933aSMatthew Dillon 	 *	    entire 2GB segment is within the static allocation.
71193f3933aSMatthew Dillon 	 */
712a5913bdfSMatthew Dillon 	lokey = (hmp->voldata.allocator_beg + HAMMER2_SEGMASK64) &
71393f3933aSMatthew Dillon 		~HAMMER2_SEGMASK64;
71493f3933aSMatthew Dillon 
71593f3933aSMatthew Dillon 	if (lokey < H2FMBASE(key, HAMMER2_FREEMAP_LEVEL1_RADIX) +
71693f3933aSMatthew Dillon 		  HAMMER2_ZONE_SEG64) {
71793f3933aSMatthew Dillon 		lokey = H2FMBASE(key, HAMMER2_FREEMAP_LEVEL1_RADIX) +
71893f3933aSMatthew Dillon 			HAMMER2_ZONE_SEG64;
71993f3933aSMatthew Dillon 	}
72093f3933aSMatthew Dillon 
72193f3933aSMatthew Dillon 	hikey = key + H2FMSHIFT(HAMMER2_FREEMAP_LEVEL1_RADIX);
722a5913bdfSMatthew Dillon 	if (hikey > hmp->voldata.volu_size) {
723a5913bdfSMatthew Dillon 		hikey = hmp->voldata.volu_size & ~HAMMER2_SEGMASK64;
72493f3933aSMatthew Dillon 	}
72593f3933aSMatthew Dillon 
72693f3933aSMatthew Dillon 	chain->bref.check.freemap.avail =
72793f3933aSMatthew Dillon 		H2FMSHIFT(HAMMER2_FREEMAP_LEVEL1_RADIX);
72893f3933aSMatthew Dillon 	bmap = &chain->data->bmdata[0];
72993f3933aSMatthew Dillon 
73093f3933aSMatthew Dillon 	for (count = 0; count < HAMMER2_FREEMAP_COUNT; ++count) {
73193f3933aSMatthew Dillon 		if (key < lokey || key >= hikey) {
73293f3933aSMatthew Dillon 			memset(bmap->bitmap, -1,
73393f3933aSMatthew Dillon 			       sizeof(bmap->bitmap));
73493f3933aSMatthew Dillon 			bmap->avail = 0;
7352c6f594dSMatthew Dillon 			bmap->linear = HAMMER2_SEGSIZE;
73693f3933aSMatthew Dillon 			chain->bref.check.freemap.avail -=
73793f3933aSMatthew Dillon 				H2FMSHIFT(HAMMER2_FREEMAP_LEVEL0_RADIX);
73893f3933aSMatthew Dillon 		} else {
73993f3933aSMatthew Dillon 			bmap->avail = H2FMSHIFT(HAMMER2_FREEMAP_LEVEL0_RADIX);
74093f3933aSMatthew Dillon 		}
74193f3933aSMatthew Dillon 		key += H2FMSHIFT(HAMMER2_FREEMAP_LEVEL0_RADIX);
74293f3933aSMatthew Dillon 		++bmap;
74393f3933aSMatthew Dillon 	}
74493f3933aSMatthew Dillon }
74593f3933aSMatthew Dillon 
74693f3933aSMatthew Dillon /*
74793f3933aSMatthew Dillon  * The current Level 1 freemap has been exhausted, iterate to the next
74893f3933aSMatthew Dillon  * one, return ENOSPC if no freemaps remain.
74993f3933aSMatthew Dillon  *
75093f3933aSMatthew Dillon  * XXX this should rotate back to the beginning to handle freed-up space
75193f3933aSMatthew Dillon  * XXX or use intermediate entries to locate free space. TODO
75293f3933aSMatthew Dillon  */
7531a7cfe5aSMatthew Dillon static int
7541a7cfe5aSMatthew Dillon hammer2_freemap_iterate(hammer2_trans_t *trans, hammer2_chain_t **parentp,
75591abd410SMatthew Dillon 			hammer2_chain_t **chainp, hammer2_fiterate_t *iter)
7561a7cfe5aSMatthew Dillon {
757a5913bdfSMatthew Dillon 	hammer2_mount_t *hmp = (*parentp)->hmp;
758a5913bdfSMatthew Dillon 
75991abd410SMatthew Dillon 	iter->bnext &= ~(H2FMSHIFT(HAMMER2_FREEMAP_LEVEL1_RADIX) - 1);
76091abd410SMatthew Dillon 	iter->bnext += H2FMSHIFT(HAMMER2_FREEMAP_LEVEL1_RADIX);
76191abd410SMatthew Dillon 	if (iter->bnext >= hmp->voldata.volu_size) {
76291abd410SMatthew Dillon 		iter->bnext = 0;
76391abd410SMatthew Dillon 		if (++iter->loops == 2)
7641a7cfe5aSMatthew Dillon 			return (ENOSPC);
76591abd410SMatthew Dillon 	}
7661a7cfe5aSMatthew Dillon 	return(EAGAIN);
76737aa19dfSMatthew Dillon }
7681a7cfe5aSMatthew Dillon 
76991abd410SMatthew Dillon /*
77091abd410SMatthew Dillon  * Free the specified blockref.  This code is only able to fully free
77191abd410SMatthew Dillon  * blocks when (how) is non-zero, otherwise the block is marked for
77291abd410SMatthew Dillon  * the bulk freeing pass to check.
77391abd410SMatthew Dillon  *
77491abd410SMatthew Dillon  * Normal use is to only mark inodes as possibly being free.  The underlying
77591abd410SMatthew Dillon  * file blocks are not necessarily marked.  The bulk freescan can
77691abd410SMatthew Dillon  * theoretically handle the case.
77791abd410SMatthew Dillon  *
77891abd410SMatthew Dillon  * XXX currently disabled when how == 0 (the normal real-time case).  At
77991abd410SMatthew Dillon  * the moment we depend on the bulk freescan to actually free blocks.  It
78091abd410SMatthew Dillon  * will still call this routine with a non-zero how to stage possible frees
78191abd410SMatthew Dillon  * and to do the actual free.
782a4dc31e0SMatthew Dillon  *
783a4dc31e0SMatthew Dillon  * WARNING! When called from a flush we have to use the 'live' sync_tid
784a4dc31e0SMatthew Dillon  *	    and not the flush sync_tid.  The live sync_tid is the flush
785a4dc31e0SMatthew Dillon  *	    sync_tid + 1.  That is, freemap allocations which occur during
786a4dc31e0SMatthew Dillon  *	    a flush are not part of the flush.  Crash-recovery will restore
787a4dc31e0SMatthew Dillon  *	    any lost allocations.
78891abd410SMatthew Dillon  */
789004f88b4SMatthew Dillon void
79010136ab6SMatthew Dillon hammer2_freemap_adjust(hammer2_trans_t *trans, hammer2_mount_t *hmp,
79191abd410SMatthew Dillon 		       hammer2_blockref_t *bref, int how)
792004f88b4SMatthew Dillon {
79391abd410SMatthew Dillon 	hammer2_off_t data_off = bref->data_off;
79491abd410SMatthew Dillon 	hammer2_chain_t *chain;
79591abd410SMatthew Dillon 	hammer2_chain_t *parent;
79691abd410SMatthew Dillon 	hammer2_bmap_data_t *bmap;
79791abd410SMatthew Dillon 	hammer2_key_t key;
7981897c66eSMatthew Dillon 	hammer2_key_t key_dummy;
79991abd410SMatthew Dillon 	hammer2_off_t l0size;
80091abd410SMatthew Dillon 	hammer2_off_t l1size;
80191abd410SMatthew Dillon 	hammer2_off_t l1mask;
80291abd410SMatthew Dillon 	uint32_t *bitmap;
80391abd410SMatthew Dillon 	const uint32_t bmmask00 = 0;
80491abd410SMatthew Dillon 	uint32_t bmmask01;
80591abd410SMatthew Dillon 	uint32_t bmmask10;
80691abd410SMatthew Dillon 	uint32_t bmmask11;
80791abd410SMatthew Dillon 	size_t bytes;
80891abd410SMatthew Dillon 	uint16_t class;
809004f88b4SMatthew Dillon 	int radix;
81091abd410SMatthew Dillon 	int start;
81191abd410SMatthew Dillon 	int count;
81291abd410SMatthew Dillon 	int modified = 0;
8131897c66eSMatthew Dillon 	int cache_index = -1;
81410136ab6SMatthew Dillon 	int error;
815004f88b4SMatthew Dillon 
816004f88b4SMatthew Dillon 	radix = (int)data_off & HAMMER2_OFF_MASK_RADIX;
817004f88b4SMatthew Dillon 	data_off &= ~HAMMER2_OFF_MASK_RADIX;
81891abd410SMatthew Dillon 	KKASSERT(radix <= HAMMER2_MAX_RADIX);
819004f88b4SMatthew Dillon 
82091abd410SMatthew Dillon 	bytes = (size_t)1 << radix;
82191abd410SMatthew Dillon 	class = (bref->type << 8) | hammer2_devblkradix(radix);
822004f88b4SMatthew Dillon 
8235c23d7f1SMatthew Dillon 	/*
82410136ab6SMatthew Dillon 	 * We can't adjust thre freemap for data allocations made by
82510136ab6SMatthew Dillon 	 * newfs_hammer2.
826355d67fcSMatthew Dillon 	 */
827355d67fcSMatthew Dillon 	if (data_off < hmp->voldata.allocator_beg)
828355d67fcSMatthew Dillon 		return;
829355d67fcSMatthew Dillon 
83010136ab6SMatthew Dillon 	KKASSERT((data_off & HAMMER2_ZONE_MASK64) >= HAMMER2_ZONE_SEG);
831a4dc31e0SMatthew Dillon 	KKASSERT((trans->flags & HAMMER2_TRANS_ISALLOCATING) == 0);
832a7720be7SMatthew Dillon 	atomic_set_int(&trans->flags, HAMMER2_TRANS_ISALLOCATING);
833a4dc31e0SMatthew Dillon 	if (trans->flags & HAMMER2_TRANS_ISFLUSH)
834a4dc31e0SMatthew Dillon 		++trans->sync_tid;
835a7720be7SMatthew Dillon 
836355d67fcSMatthew Dillon 	/*
83791abd410SMatthew Dillon 	 * Lookup the level1 freemap chain.  The chain must exist.
8385c23d7f1SMatthew Dillon 	 */
83991abd410SMatthew Dillon 	key = H2FMBASE(data_off, HAMMER2_FREEMAP_LEVEL1_RADIX);
84091abd410SMatthew Dillon 	l0size = H2FMSHIFT(HAMMER2_FREEMAP_LEVEL0_RADIX);
84191abd410SMatthew Dillon 	l1size = H2FMSHIFT(HAMMER2_FREEMAP_LEVEL1_RADIX);
84291abd410SMatthew Dillon 	l1mask = l1size - 1;
84391abd410SMatthew Dillon 
84491abd410SMatthew Dillon 	parent = &hmp->fchain;
84591abd410SMatthew Dillon 	hammer2_chain_lock(parent, HAMMER2_RESOLVE_ALWAYS);
84691abd410SMatthew Dillon 
8471897c66eSMatthew Dillon 	chain = hammer2_chain_lookup(&parent, &key_dummy, key, key + l1mask,
8481897c66eSMatthew Dillon 				     &cache_index,
84991abd410SMatthew Dillon 				     HAMMER2_LOOKUP_ALWAYS |
85010136ab6SMatthew Dillon 				     HAMMER2_LOOKUP_MATCHIND);
85110136ab6SMatthew Dillon 
85210136ab6SMatthew Dillon 	/*
85310136ab6SMatthew Dillon 	 * Stop early if we are trying to free something but no leaf exists.
85410136ab6SMatthew Dillon 	 */
85510136ab6SMatthew Dillon 	if (chain == NULL && how != HAMMER2_FREEMAP_DORECOVER) {
85610136ab6SMatthew Dillon 		kprintf("hammer2_freemap_adjust: %016jx: no chain\n",
85791abd410SMatthew Dillon 			(intmax_t)bref->data_off);
858623d43d4SMatthew Dillon 		goto done;
85991abd410SMatthew Dillon 	}
86091abd410SMatthew Dillon 
86191abd410SMatthew Dillon 	/*
86210136ab6SMatthew Dillon 	 * Create any missing leaf(s) if we are doing a recovery (marking
86310136ab6SMatthew Dillon 	 * the block(s) as being allocated instead of being freed).  Be sure
86410136ab6SMatthew Dillon 	 * to initialize the auxillary freemap tracking info in the
86510136ab6SMatthew Dillon 	 * bref.check.freemap structure.
86691abd410SMatthew Dillon 	 */
86710136ab6SMatthew Dillon 	if (chain == NULL && how == HAMMER2_FREEMAP_DORECOVER) {
86810136ab6SMatthew Dillon 		error = hammer2_chain_create(trans, &parent, &chain,
86910136ab6SMatthew Dillon 				     key, HAMMER2_FREEMAP_LEVEL1_RADIX,
87010136ab6SMatthew Dillon 				     HAMMER2_BREF_TYPE_FREEMAP_LEAF,
87110136ab6SMatthew Dillon 				     HAMMER2_FREEMAP_LEVELN_PSIZE);
8721fca819aSMatthew Dillon 
8731fca819aSMatthew Dillon 		if (hammer2_debug & 0x0040) {
8741fca819aSMatthew Dillon 			kprintf("fixup create chain %p %016jx:%d\n",
8751fca819aSMatthew Dillon 				chain, chain->bref.key, chain->bref.keybits);
8761fca819aSMatthew Dillon 		}
87791abd410SMatthew Dillon 
87810136ab6SMatthew Dillon 		if (error == 0) {
87910136ab6SMatthew Dillon 			hammer2_chain_modify(trans, &chain, 0);
88010136ab6SMatthew Dillon 			bzero(&chain->data->bmdata[0],
88110136ab6SMatthew Dillon 			      HAMMER2_FREEMAP_LEVELN_PSIZE);
88210136ab6SMatthew Dillon 			chain->bref.check.freemap.bigmask = (uint32_t)-1;
88310136ab6SMatthew Dillon 			chain->bref.check.freemap.avail = l1size;
88410136ab6SMatthew Dillon 			/* bref.methods should already be inherited */
88510136ab6SMatthew Dillon 
88610136ab6SMatthew Dillon 			hammer2_freemap_init(trans, hmp, key, chain);
88710136ab6SMatthew Dillon 		}
88810136ab6SMatthew Dillon 		/* XXX handle error */
88910136ab6SMatthew Dillon 	}
89010136ab6SMatthew Dillon 
89110136ab6SMatthew Dillon 	/*
89210136ab6SMatthew Dillon 	 * Calculate the bitmask (runs in 2-bit pairs).
89310136ab6SMatthew Dillon 	 */
89491abd410SMatthew Dillon 	start = ((int)(data_off >> HAMMER2_FREEMAP_BLOCK_RADIX) & 15) * 2;
89591abd410SMatthew Dillon 	bmmask01 = 1 << start;
89691abd410SMatthew Dillon 	bmmask10 = 2 << start;
89791abd410SMatthew Dillon 	bmmask11 = 3 << start;
89891abd410SMatthew Dillon 
89991abd410SMatthew Dillon 	/*
90010136ab6SMatthew Dillon 	 * Fixup the bitmap.  Partial blocks cannot be fully freed unless
90110136ab6SMatthew Dillon 	 * a bulk scan is able to roll them up.
90291abd410SMatthew Dillon 	 */
90391abd410SMatthew Dillon 	if (radix < HAMMER2_FREEMAP_BLOCK_RADIX) {
90491abd410SMatthew Dillon 		count = 1;
90510136ab6SMatthew Dillon 		if (how == HAMMER2_FREEMAP_DOREALFREE)
90610136ab6SMatthew Dillon 			how = HAMMER2_FREEMAP_DOMAYFREE;
90791abd410SMatthew Dillon 	} else {
90891abd410SMatthew Dillon 		count = 1 << (radix - HAMMER2_FREEMAP_BLOCK_RADIX);
9095c23d7f1SMatthew Dillon 	}
9105c23d7f1SMatthew Dillon 
91110136ab6SMatthew Dillon 	/*
91210136ab6SMatthew Dillon 	 * [re]load the bmap and bitmap pointers.  Each bmap entry covers
91310136ab6SMatthew Dillon 	 * a 2MB swath.  The bmap itself (LEVEL1) covers 2GB.
91410136ab6SMatthew Dillon 	 */
91510136ab6SMatthew Dillon again:
91691abd410SMatthew Dillon 	bmap = &chain->data->bmdata[(int)(data_off >> HAMMER2_SEGRADIX) &
91791abd410SMatthew Dillon 				    (HAMMER2_FREEMAP_COUNT - 1)];
91891abd410SMatthew Dillon 	bitmap = &bmap->bitmap[(int)(data_off >> (HAMMER2_SEGRADIX - 3)) & 7];
91910136ab6SMatthew Dillon 
92010136ab6SMatthew Dillon 
92110136ab6SMatthew Dillon 	while (count) {
92210136ab6SMatthew Dillon 		KKASSERT(bmmask11);
92310136ab6SMatthew Dillon 		if (how == HAMMER2_FREEMAP_DORECOVER) {
92410136ab6SMatthew Dillon 			/*
92510136ab6SMatthew Dillon 			 * Recovery request, mark as allocated.
92610136ab6SMatthew Dillon 			 */
92710136ab6SMatthew Dillon 			if ((*bitmap & bmmask11) != bmmask11) {
92810136ab6SMatthew Dillon 				if (modified == 0) {
92910136ab6SMatthew Dillon 					hammer2_chain_modify(trans, &chain, 0);
93010136ab6SMatthew Dillon 					modified = 1;
93110136ab6SMatthew Dillon 					goto again;
93291abd410SMatthew Dillon 				}
93310136ab6SMatthew Dillon 				if ((*bitmap & bmmask11) == bmmask00)
93410136ab6SMatthew Dillon 					bmap->avail -= 1 << radix;
93510136ab6SMatthew Dillon 				if (bmap->class == 0)
93610136ab6SMatthew Dillon 					bmap->class = class;
93710136ab6SMatthew Dillon 				*bitmap |= bmmask11;
9381fca819aSMatthew Dillon 				if (hammer2_debug & 0x0040) {
9391fca819aSMatthew Dillon 					kprintf("hammer2_freemap_recover: "
9401fca819aSMatthew Dillon 						"fixup type=%02x "
9411fca819aSMatthew Dillon 						"block=%016jx/%zd\n",
94210136ab6SMatthew Dillon 						bref->type, data_off, bytes);
9431fca819aSMatthew Dillon 				}
94410136ab6SMatthew Dillon 			} else {
94510136ab6SMatthew Dillon 				/*
94610136ab6SMatthew Dillon 				kprintf("hammer2_freemap_recover:  good "
94710136ab6SMatthew Dillon 					"type=%02x block=%016jx/%zd\n",
94810136ab6SMatthew Dillon 					bref->type, data_off, bytes);
94910136ab6SMatthew Dillon 				*/
95010136ab6SMatthew Dillon 			}
95110136ab6SMatthew Dillon 		} else if ((*bitmap & bmmask11) == bmmask11) {
95210136ab6SMatthew Dillon 			/*
95310136ab6SMatthew Dillon 			 * Mayfree/Realfree request and bitmap is currently
95410136ab6SMatthew Dillon 			 * marked as being fully allocated.
95510136ab6SMatthew Dillon 			 */
95610136ab6SMatthew Dillon 			if (!modified) {
95710136ab6SMatthew Dillon 				hammer2_chain_modify(trans, &chain, 0);
95810136ab6SMatthew Dillon 				modified = 1;
95910136ab6SMatthew Dillon 				goto again;
96010136ab6SMatthew Dillon 			}
96110136ab6SMatthew Dillon 			if (how == HAMMER2_FREEMAP_DOREALFREE)
96291abd410SMatthew Dillon 				*bitmap &= ~bmmask11;
96391abd410SMatthew Dillon 			else
96491abd410SMatthew Dillon 				*bitmap = (*bitmap & ~bmmask11) | bmmask10;
96591abd410SMatthew Dillon 		} else if ((*bitmap & bmmask11) == bmmask10) {
96610136ab6SMatthew Dillon 			/*
96710136ab6SMatthew Dillon 			 * Mayfree/Realfree request and bitmap is currently
96810136ab6SMatthew Dillon 			 * marked as being possibly freeable.
96910136ab6SMatthew Dillon 			 */
97010136ab6SMatthew Dillon 			if (how == HAMMER2_FREEMAP_DOREALFREE) {
97191abd410SMatthew Dillon 				if (!modified) {
97291abd410SMatthew Dillon 					hammer2_chain_modify(trans, &chain, 0);
97391abd410SMatthew Dillon 					modified = 1;
97410136ab6SMatthew Dillon 					goto again;
97591abd410SMatthew Dillon 				}
97691abd410SMatthew Dillon 				*bitmap &= ~bmmask11;
97791abd410SMatthew Dillon 			}
97810136ab6SMatthew Dillon 		} else {
97910136ab6SMatthew Dillon 			/*
98010136ab6SMatthew Dillon 			 * 01 - Not implemented, currently illegal state
98110136ab6SMatthew Dillon 			 * 00 - Not allocated at all, illegal free.
98210136ab6SMatthew Dillon 			 */
98310136ab6SMatthew Dillon 			panic("hammer2_freemap_adjust: "
98410136ab6SMatthew Dillon 			      "Illegal state %08x(%08x)",
98510136ab6SMatthew Dillon 			      *bitmap, *bitmap & bmmask11);
98691abd410SMatthew Dillon 		}
98791abd410SMatthew Dillon 		--count;
98891abd410SMatthew Dillon 		bmmask01 <<= 2;
98991abd410SMatthew Dillon 		bmmask10 <<= 2;
99091abd410SMatthew Dillon 		bmmask11 <<= 2;
99191abd410SMatthew Dillon 	}
99210136ab6SMatthew Dillon 	if (how == HAMMER2_FREEMAP_DOREALFREE && modified) {
99391abd410SMatthew Dillon 		bmap->avail += 1 << radix;
99491abd410SMatthew Dillon 		KKASSERT(bmap->avail <= HAMMER2_SEGSIZE);
99591abd410SMatthew Dillon 		if (bmap->avail == HAMMER2_SEGSIZE &&
99691abd410SMatthew Dillon 		    bmap->bitmap[0] == 0 &&
99791abd410SMatthew Dillon 		    bmap->bitmap[1] == 0 &&
99891abd410SMatthew Dillon 		    bmap->bitmap[2] == 0 &&
99991abd410SMatthew Dillon 		    bmap->bitmap[3] == 0 &&
100091abd410SMatthew Dillon 		    bmap->bitmap[4] == 0 &&
100191abd410SMatthew Dillon 		    bmap->bitmap[5] == 0 &&
100291abd410SMatthew Dillon 		    bmap->bitmap[6] == 0 &&
100391abd410SMatthew Dillon 		    bmap->bitmap[7] == 0) {
100491abd410SMatthew Dillon 			key = H2FMBASE(data_off, HAMMER2_FREEMAP_LEVEL0_RADIX);
100591abd410SMatthew Dillon 			kprintf("Freeseg %016jx\n", (intmax_t)key);
100691abd410SMatthew Dillon 			bmap->class = 0;
100791abd410SMatthew Dillon 		}
100891abd410SMatthew Dillon 	}
100991abd410SMatthew Dillon 
101091abd410SMatthew Dillon 	/*
101191abd410SMatthew Dillon 	 * chain->bref.check.freemap.bigmask (XXX)
101210136ab6SMatthew Dillon 	 *
101310136ab6SMatthew Dillon 	 * Setting bigmask is a hint to the allocation code that there might
101410136ab6SMatthew Dillon 	 * be something allocatable.  We also set this in recovery... it
101510136ab6SMatthew Dillon 	 * doesn't hurt and we might want to use the hint for other validation
101610136ab6SMatthew Dillon 	 * operations later on.
101791abd410SMatthew Dillon 	 */
101891abd410SMatthew Dillon 	if (modified)
101991abd410SMatthew Dillon 		chain->bref.check.freemap.bigmask |= 1 << radix;
102091abd410SMatthew Dillon 
102191abd410SMatthew Dillon 	hammer2_chain_unlock(chain);
1022623d43d4SMatthew Dillon done:
102391abd410SMatthew Dillon 	hammer2_chain_unlock(parent);
1024a7720be7SMatthew Dillon 	atomic_clear_int(&trans->flags, HAMMER2_TRANS_ISALLOCATING);
1025a4dc31e0SMatthew Dillon 	if (trans->flags & HAMMER2_TRANS_ISFLUSH)
1026a4dc31e0SMatthew Dillon 		--trans->sync_tid;
102791abd410SMatthew Dillon }
1028