15f2707594a4419d8a9c8fb18f5f876b65eca288
[dragonfly.git] / sys / vfs / hammer2 / hammer2_bulkscan.c
1 /*
2  * Copyright (c) 2013-2015 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@dragonflybsd.org>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/fcntl.h>
38 #include <sys/buf.h>
39 #include <sys/proc.h>
40 #include <sys/namei.h>
41 #include <sys/mount.h>
42 #include <sys/vnode.h>
43 #include <sys/mountctl.h>
44 #include <vm/vm_kern.h>
45 #include <vm/vm_extern.h>
46
47 #include "hammer2.h"
48
49 /*
50  * breadth-first search
51  */
52 typedef struct hammer2_chain_save {
53         TAILQ_ENTRY(hammer2_chain_save) entry;
54         hammer2_chain_t *parent;
55 } hammer2_chain_save_t;
56
57 TAILQ_HEAD(hammer2_chain_save_list, hammer2_chain_save);
58 typedef struct hammer2_chain_save_list hammer2_chain_save_list_t;
59
60 /*
61  * General bulk scan function with callback.  Called with a referenced
62  * but UNLOCKED parent.  The original parent is returned in the same state.
63  */
64 int
65 hammer2_bulk_scan(hammer2_chain_t *parent,
66                   int (*func)(hammer2_chain_t *chain, void *info),
67                   void *info)
68 {
69         hammer2_chain_save_list_t list;
70         hammer2_chain_save_t *save;
71         int doabort = 0;
72
73         TAILQ_INIT(&list);
74         hammer2_chain_ref(parent);
75         save = kmalloc(sizeof(*save), M_HAMMER2, M_WAITOK | M_ZERO);
76         save->parent = parent;
77         TAILQ_INSERT_TAIL(&list, save, entry);
78
79         while ((save = TAILQ_FIRST(&list)) != NULL && doabort == 0) {
80                 hammer2_chain_t *chain;
81                 int cache_index;
82
83                 TAILQ_REMOVE(&list, save, entry);
84
85                 parent = save->parent;
86                 save->parent = NULL;
87                 chain = NULL;
88                 cache_index = -1;
89
90                 /*
91                  * lock the parent, the lock eats the ref.
92                  */
93                 hammer2_chain_lock(parent, HAMMER2_RESOLVE_ALWAYS |
94                                            HAMMER2_RESOLVE_SHARED);
95
96                 /*
97                  * Generally loop on the contents if we have not been flagged
98                  * for abort.
99                  */
100                 while ((doabort & HAMMER2_BULK_ABORT) == 0) {
101                         chain = hammer2_chain_scan(parent, chain, &cache_index,
102                                                    HAMMER2_LOOKUP_NODATA |
103                                                    HAMMER2_LOOKUP_SHARED);
104                         if (chain == NULL)
105                                 break;
106                         doabort |= func(chain, info);
107
108                         if (doabort & HAMMER2_BULK_ABORT) {
109                                 hammer2_chain_unlock(chain);
110                                 hammer2_chain_drop(chain);
111                                 chain = NULL;
112                                 break;
113                         }
114                         switch(chain->bref.type) {
115                         case HAMMER2_BREF_TYPE_INODE:
116                         case HAMMER2_BREF_TYPE_FREEMAP_NODE:
117                         case HAMMER2_BREF_TYPE_INDIRECT:
118                         case HAMMER2_BREF_TYPE_VOLUME:
119                         case HAMMER2_BREF_TYPE_FREEMAP:
120                                 /*
121                                  * Breadth-first scan.  Chain is referenced
122                                  * to save for later and will be unlocked on
123                                  * our loop (so it isn't left locked while on
124                                  * the list).
125                                  */
126                                 if (save == NULL) {
127                                         save = kmalloc(sizeof(*save),
128                                                        M_HAMMER2,
129                                                        M_WAITOK | M_ZERO);
130                                 }
131                                 hammer2_chain_ref(chain);
132                                 save->parent = chain;
133                                 TAILQ_INSERT_TAIL(&list, save, entry);
134                                 save = NULL;
135                                 break;
136                         default:
137                                 /* does not recurse */
138                                 break;
139                         }
140                 }
141
142                 /*
143                  * Releases the lock and the ref the lock inherited.  Free
144                  * save structure if we didn't recycle it above.
145                  */
146                 hammer2_chain_unlock(parent);
147                 hammer2_chain_drop(parent);
148                 if (save)
149                         kfree(save, M_HAMMER2);
150         }
151
152         /*
153          * Cleanup anything left undone due to an abort
154          */
155         while ((save = TAILQ_FIRST(&list)) != NULL) {
156                 TAILQ_REMOVE(&list, save, entry);
157                 hammer2_chain_drop(save->parent);
158                 kfree(save, M_HAMMER2);
159         }
160
161         return doabort;
162 }
163
164 /*
165  * Bulkfree algorithm -
166  *
167  * DoTwice {
168  *      flush sync
169  *      Scan the whole topology and build the freemap
170  *      ** -> 11 during scan for all elements scanned (and thus not free)
171  *      11 -> 10 after scan if allocated in-topo and free in-memory, mark 10
172  *      10 -> 00 after scan if possibly-free in-topo and free in-memory mark 00
173  * }
174  *
175  * Adjustment of the freemap ->10 and ->00 cannot occur until the topology
176  * scan is complete.  The scan runs concurrentlyt with normal filesystem
177  * operations and any allocation will also remark the freemap bitmap 11.
178  * We handle races by performing two scans and only changing the map to
179  * fully free (00) if both passes believe it is free.
180  *
181  * Temporary memory in multiples of 64KB is required to reconstruct leaf
182  * hammer2_bmap_data blocks so they can later be compared against the live
183  * freemap.  Each 64KB block represents 128 x 16KB x 1024 = ~2 GB of storage.
184  * A 32MB save area thus represents around ~1 TB.  The temporary memory
185  * allocated can be specified.  If it is not sufficient multiple topology
186  * passes will be made.
187  */
188
189 /*
190  * Bulkfree callback info
191  */
192 typedef struct hammer2_bulkfree_info {
193         hammer2_dev_t           *hmp;
194         kmem_anon_desc_t        kp;
195         hammer2_off_t           sbase;          /* sub-loop iteration */
196         hammer2_off_t           sstop;
197         hammer2_bmap_data_t     *bmap;
198         long                    count_10_00;
199         long                    count_11_10;
200         long                    count_10_11;
201         long                    count_l0cleans;
202         long                    count_linadjusts;
203         hammer2_off_t           adj_free;
204         hammer2_tid_t           mtid;
205         time_t                  save_time;
206 } hammer2_bulkfree_info_t;
207
208 static int h2_bulkfree_callback(hammer2_chain_t *chain, void *info);
209 static void h2_bulkfree_sync(hammer2_bulkfree_info_t *cbinfo);
210 static void h2_bulkfree_sync_adjust(hammer2_bulkfree_info_t *cbinfo,
211                         hammer2_bmap_data_t *live, hammer2_bmap_data_t *bmap);
212
213 int
214 hammer2_bulkfree_pass(hammer2_dev_t *hmp, hammer2_ioc_bulkfree_t *bfi)
215 {
216         hammer2_bulkfree_info_t cbinfo;
217         hammer2_off_t incr;
218         size_t size;
219         int doabort = 0;
220
221         /* hammer2_vfs_sync(hmp->mp, MNT_WAIT); XXX */
222
223         bzero(&cbinfo, sizeof(cbinfo));
224         size = (bfi->size + HAMMER2_FREEMAP_LEVELN_PSIZE - 1) &
225                ~(size_t)(HAMMER2_FREEMAP_LEVELN_PSIZE - 1);
226         cbinfo.hmp = hmp;
227         cbinfo.bmap = kmem_alloc_swapbacked(&cbinfo.kp, size);
228
229         /*
230          * Normalize start point to a 2GB boundary.  We operate on a
231          * 64KB leaf bitmap boundary which represents 2GB of storage.
232          */
233         cbinfo.sbase = bfi->sbase;
234         if (cbinfo.sbase > hmp->voldata.volu_size)
235                 cbinfo.sbase = hmp->voldata.volu_size;
236         cbinfo.sbase &= ~HAMMER2_FREEMAP_LEVEL1_MASK;
237
238         /*
239          * Loop on a full meta-data scan as many times as required to
240          * get through all available storage.
241          */
242         while (cbinfo.sbase < hmp->voldata.volu_size) {
243                 /*
244                  * We have enough ram to represent (incr) bytes of storage.
245                  * Each 64KB of ram represents 2GB of storage.
246                  */
247                 bzero(cbinfo.bmap, size);
248                 incr = size / HAMMER2_FREEMAP_LEVELN_PSIZE *
249                        HAMMER2_FREEMAP_LEVEL1_SIZE;
250                 if (hmp->voldata.volu_size - cbinfo.sbase < incr)
251                         cbinfo.sstop = hmp->voldata.volu_size;
252                 else
253                         cbinfo.sstop = cbinfo.sbase + incr;
254                 if (hammer2_debug & 1)
255                 kprintf("bulkfree pass %016jx/%jdGB\n",
256                         (intmax_t)cbinfo.sbase,
257                         (intmax_t)incr / HAMMER2_FREEMAP_LEVEL1_SIZE);
258
259                 hammer2_trans_init(hmp->spmp, 0);
260                 cbinfo.mtid = hammer2_trans_sub(hmp->spmp);
261                 doabort |= hammer2_bulk_scan(&hmp->vchain,
262                                             h2_bulkfree_callback, &cbinfo);
263
264                 /*
265                  * If complete scan succeeded we can synchronize our
266                  * in-memory freemap against live storage.  If an abort
267                  * did occur we cannot safely synchronize our partially
268                  * filled-out in-memory freemap.
269                  */
270                 if (doabort == 0) {
271                         h2_bulkfree_sync(&cbinfo);
272
273                         hammer2_voldata_lock(hmp);
274                         hammer2_voldata_modify(hmp);
275                         hmp->voldata.allocator_free += cbinfo.adj_free;
276                         hammer2_voldata_unlock(hmp);
277                 }
278
279                 /*
280                  * Cleanup for next loop.
281                  */
282                 hammer2_trans_done(hmp->spmp);
283                 if (doabort)
284                         break;
285                 cbinfo.sbase = cbinfo.sstop;
286         }
287         kmem_free_swapbacked(&cbinfo.kp);
288
289         bfi->sstop = cbinfo.sbase;
290
291         incr = bfi->sstop / (hmp->voldata.volu_size / 10000);
292         if (incr > 10000)
293                 incr = 10000;
294
295         kprintf("bulkfree pass statistics (%d.%02d%% storage processed):\n",
296                 (int)incr / 100,
297                 (int)incr % 100);
298
299         kprintf("    transition->free   %ld\n", cbinfo.count_10_00);
300         kprintf("    transition->staged %ld\n", cbinfo.count_11_10);
301         kprintf("    raced on           %ld\n", cbinfo.count_10_11);
302         kprintf("    ~2MB segs cleaned  %ld\n", cbinfo.count_l0cleans);
303         kprintf("    linear adjusts     %ld\n", cbinfo.count_linadjusts);
304
305         return doabort;
306 }
307
308 static int
309 h2_bulkfree_callback(hammer2_chain_t *chain, void *info)
310 {
311         hammer2_bulkfree_info_t *cbinfo = info;
312         hammer2_bmap_data_t *bmap;
313         hammer2_off_t data_off;
314         uint16_t class;
315         size_t bytes;
316         int radix;
317         int error;
318
319         /*
320          * Check for signal and allow yield to userland during scan
321          */
322         if (hammer2_signal_check(&cbinfo->save_time))
323                 return HAMMER2_BULK_ABORT;
324
325 #if 0
326         kprintf("scan chain %016jx %016jx/%-2d type=%02x\n",
327                 (intmax_t)chain->bref.data_off,
328                 (intmax_t)chain->bref.key,
329                 chain->bref.keybits,
330                 chain->bref.type);
331 #endif
332
333         /*
334          * Calculate the data offset and determine if it is within
335          * the current freemap range being gathered.
336          */
337         error = 0;
338         data_off = chain->bref.data_off & ~HAMMER2_OFF_MASK_RADIX;
339         if (data_off < cbinfo->sbase || data_off > cbinfo->sstop)
340                 return 0;
341         if (data_off < chain->hmp->voldata.allocator_beg)
342                 return 0;
343         if (data_off > chain->hmp->voldata.volu_size)
344                 return 0;
345
346         /*
347          * Calculate the information needed to generate the in-memory
348          * freemap record.
349          *
350          * Hammer2 does not allow allocations to cross the L1 (2GB) boundary,
351          * it's a problem if it does.  (Or L0 (2MB) for that matter).
352          */
353         radix = (int)(chain->bref.data_off & HAMMER2_OFF_MASK_RADIX);
354         bytes = (size_t)1 << radix;
355         class = (chain->bref.type << 8) | hammer2_devblkradix(radix);
356
357         if (data_off + bytes > cbinfo->sstop) {
358                 kprintf("hammer2_bulkfree_scan: illegal 2GB boundary "
359                         "%016jx %016jx/%d\n",
360                         (intmax_t)chain->bref.data_off,
361                         (intmax_t)chain->bref.key,
362                         chain->bref.keybits);
363                 bytes = cbinfo->sstop - data_off;       /* XXX */
364         }
365
366         /*
367          * Convert to a storage offset relative to the beginning of the
368          * storage range we are collecting.  Then lookup the level0 bmap entry.
369          */
370         data_off -= cbinfo->sbase;
371         bmap = cbinfo->bmap + (data_off >> HAMMER2_FREEMAP_LEVEL0_RADIX);
372
373         /*
374          * Convert data_off to a bmap-relative value (~2MB storage range).
375          * Adjust linear, class, and avail.
376          *
377          * Hammer2 does not allow allocations to cross the L0 (2MB) boundary,
378          */
379         data_off &= HAMMER2_FREEMAP_LEVEL0_MASK;
380         if (data_off + bytes > HAMMER2_FREEMAP_LEVEL0_SIZE) {
381                 kprintf("hammer2_bulkfree_scan: illegal 2MB boundary "
382                         "%016jx %016jx/%d\n",
383                         (intmax_t)chain->bref.data_off,
384                         (intmax_t)chain->bref.key,
385                         chain->bref.keybits);
386                 bytes = HAMMER2_FREEMAP_LEVEL0_SIZE - data_off;
387         }
388
389         if (bmap->class == 0) {
390                 bmap->class = class;
391                 bmap->avail = HAMMER2_FREEMAP_LEVEL0_SIZE;
392         }
393         if (bmap->class != class) {
394                 kprintf("hammer2_bulkfree_scan: illegal mixed class "
395                         "%016jx %016jx/%d (%04x vs %04x)\n",
396                         (intmax_t)chain->bref.data_off,
397                         (intmax_t)chain->bref.key,
398                         chain->bref.keybits,
399                         class, bmap->class);
400         }
401         if (bmap->linear < (int32_t)data_off + (int32_t)bytes)
402                 bmap->linear = (int32_t)data_off + (int32_t)bytes;
403
404         /*
405          * Adjust the hammer2_bitmap_t bitmap[HAMMER2_BMAP_ELEMENTS].
406          * 64-bit entries, 2 bits per entry, to code 11.
407          *
408          * NOTE: The allocation can be smaller than HAMMER2_FREEMAP_BLOCK_SIZE.
409          */
410         while (bytes > 0) {
411                 int bindex;
412                 hammer2_bitmap_t bmask;
413
414                 bindex = (int)data_off >> (HAMMER2_FREEMAP_BLOCK_RADIX +
415                                            HAMMER2_BMAP_INDEX_RADIX);
416                 bmask = (hammer2_bitmap_t)3 <<
417                         ((((int)data_off & HAMMER2_BMAP_INDEX_MASK) >>
418                          HAMMER2_FREEMAP_BLOCK_RADIX) << 1);
419
420                 /*
421                  * NOTE! The (avail) calculation is bitmap-granular.  Multiple
422                  *       sub-granular records can wind up at the same bitmap
423                  *       position.
424                  */
425                 if ((bmap->bitmapq[bindex] & bmask) == 0) {
426                         if (bytes < HAMMER2_FREEMAP_BLOCK_SIZE) {
427                                 bmap->avail -= HAMMER2_FREEMAP_BLOCK_SIZE;
428                         } else {
429                                 bmap->avail -= bytes;
430                         }
431                         bmap->bitmapq[bindex] |= bmask;
432                 }
433                 data_off += HAMMER2_FREEMAP_BLOCK_SIZE;
434                 if (bytes < HAMMER2_FREEMAP_BLOCK_SIZE)
435                         bytes = 0;
436                 else
437                         bytes -= HAMMER2_FREEMAP_BLOCK_SIZE;
438         }
439         return error;
440 }
441
442 /*
443  * Synchronize the in-memory bitmap with the live freemap.  This is not a
444  * direct copy.  Instead the bitmaps must be compared:
445  *
446  *      In-memory       Live-freemap
447  *         00             11 -> 10
448  *                        10 -> 00
449  *         11             10 -> 11      handles race against live
450  *                        ** -> 11      nominally warn of corruption
451  * 
452  */
453 static void
454 h2_bulkfree_sync(hammer2_bulkfree_info_t *cbinfo)
455 {
456         hammer2_off_t data_off;
457         hammer2_key_t key;
458         hammer2_key_t key_dummy;
459         hammer2_bmap_data_t *bmap;
460         hammer2_bmap_data_t *live;
461         hammer2_chain_t *live_parent;
462         hammer2_chain_t *live_chain;
463         int cache_index = -1;
464         int bmapindex;
465
466         kprintf("hammer2_bulkfree - range %016jx-%016jx\n",
467                 (intmax_t)cbinfo->sbase,
468                 (intmax_t)cbinfo->sstop);
469                 
470         data_off = cbinfo->sbase;
471         bmap = cbinfo->bmap;
472
473         live_parent = &cbinfo->hmp->fchain;
474         hammer2_chain_ref(live_parent);
475         hammer2_chain_lock(live_parent, HAMMER2_RESOLVE_ALWAYS);
476         live_chain = NULL;
477
478         while (data_off < cbinfo->sstop) {
479                 /*
480                  * The freemap is not used below allocator_beg or beyond
481                  * volu_size.
482                  */
483                 if (data_off < cbinfo->hmp->voldata.allocator_beg)
484                         goto next;
485                 if (data_off > cbinfo->hmp->voldata.volu_size)
486                         goto next;
487
488                 /*
489                  * Locate the freemap leaf on the live filesystem
490                  */
491                 key = (data_off & ~HAMMER2_FREEMAP_LEVEL1_MASK);
492                 if (live_chain == NULL || live_chain->bref.key != key) {
493                         if (live_chain) {
494                                 hammer2_chain_unlock(live_chain);
495                                 hammer2_chain_drop(live_chain);
496                         }
497                         live_chain = hammer2_chain_lookup(
498                                             &live_parent,
499                                             &key_dummy,
500                                             key,
501                                             key + HAMMER2_FREEMAP_LEVEL1_MASK,
502                                             &cache_index,
503                                             HAMMER2_LOOKUP_ALWAYS);
504                         if (live_chain)
505                                 kprintf("live_chain %016jx\n", (intmax_t)key);
506                                         
507                 }
508                 if (live_chain == NULL) {
509                         if (bmap->class &&
510                             bmap->avail != HAMMER2_FREEMAP_LEVEL0_SIZE) {
511                                 kprintf("hammer2_bulkfree: cannot locate "
512                                         "live leaf for allocated data "
513                                         "near %016jx\n",
514                                         (intmax_t)data_off);
515                         }
516                         goto next;
517                 }
518                 if (live_chain->error) {
519                         kprintf("hammer2_bulkfree: error %s looking up "
520                                 "live leaf for allocated data near %016jx\n",
521                                 hammer2_error_str(live_chain->error),
522                                 (intmax_t)data_off);
523                         hammer2_chain_unlock(live_chain);
524                         hammer2_chain_drop(live_chain);
525                         live_chain = NULL;
526                         goto next;
527                 }
528
529                 bmapindex = (data_off & HAMMER2_FREEMAP_LEVEL1_MASK) >>
530                             HAMMER2_FREEMAP_LEVEL0_RADIX;
531                 live = &live_chain->data->bmdata[bmapindex];
532
533                 /*
534                  * For now just handle the 11->10, 10->00, and 10->11
535                  * transitions.
536                  */
537                 if (live->class == 0 ||
538                     live->avail == HAMMER2_FREEMAP_LEVEL0_SIZE) {
539                         goto next;
540                 }
541                 if (bcmp(live->bitmapq, bmap->bitmapq,
542                          sizeof(bmap->bitmapq)) == 0) {
543                         goto next;
544                 }
545                 if (hammer2_debug & 1)
546                 kprintf("live %016jx %04d.%04x (avail=%d)\n",
547                         data_off, bmapindex, live->class, live->avail);
548
549                 hammer2_chain_modify(live_chain, cbinfo->mtid, 0);
550                 h2_bulkfree_sync_adjust(cbinfo, live, bmap);
551 next:
552                 data_off += HAMMER2_FREEMAP_LEVEL0_SIZE;
553                 ++bmap;
554         }
555         if (live_chain) {
556                 hammer2_chain_unlock(live_chain);
557                 hammer2_chain_drop(live_chain);
558         }
559         if (live_parent) {
560                 hammer2_chain_unlock(live_parent);
561                 hammer2_chain_drop(live_parent);
562         }
563 }
564
565 static
566 void
567 h2_bulkfree_sync_adjust(hammer2_bulkfree_info_t *cbinfo,
568                         hammer2_bmap_data_t *live, hammer2_bmap_data_t *bmap)
569 {
570         int bindex;
571         int scount;
572         hammer2_bitmap_t lmask;
573         hammer2_bitmap_t mmask;
574
575         for (bindex = 0; bindex < HAMMER2_BMAP_ELEMENTS; ++bindex) {
576                 lmask = live->bitmapq[bindex];
577                 mmask = bmap->bitmapq[bindex];
578                 if (lmask == mmask)
579                         continue;
580
581                 for (scount = 0;
582                      scount < HAMMER2_BMAP_BITS_PER_ELEMENT;
583                      scount += 2) {
584                         if ((mmask & 3) == 0) {
585                                 /*
586                                  * in-memory 00         live 11 -> 10
587                                  *                      live 10 -> 00
588                                  */
589                                 switch (lmask & 3) {
590                                 case 0: /* 00 */
591                                         break;
592                                 case 1: /* 01 */
593                                         kprintf("hammer2_bulkfree: cannot "
594                                                 "transition m=00/l=01\n");
595                                         break;
596                                 case 2: /* 10 -> 00 */
597                                         live->bitmapq[bindex] &=
598                                             ~((hammer2_bitmap_t)2 << scount);
599                                         live->avail +=
600                                                 HAMMER2_FREEMAP_BLOCK_SIZE;
601                                         cbinfo->adj_free +=
602                                                 HAMMER2_FREEMAP_BLOCK_SIZE;
603                                         ++cbinfo->count_10_00;
604                                         break;
605                                 case 3: /* 11 -> 10 */
606                                         live->bitmapq[bindex] &=
607                                             ~((hammer2_bitmap_t)1 << scount);
608                                         ++cbinfo->count_11_10;
609                                         break;
610                                 }
611                         } else if ((lmask & 3) == 3) {
612                                 /*
613                                  * in-memory 11         live 10 -> 11
614                                  *                      live ** -> 11
615                                  */
616                                 switch (lmask & 3) {
617                                 case 0: /* 00 */
618                                         kprintf("hammer2_bulkfree: cannot "
619                                                 "transition m=11/l=00\n");
620                                         break;
621                                 case 1: /* 01 */
622                                         kprintf("hammer2_bulkfree: cannot "
623                                                 "transition m=11/l=01\n");
624                                         break;
625                                 case 2: /* 10 -> 11 */
626                                         live->bitmapq[bindex] |=
627                                                 ((hammer2_bitmap_t)1 << scount);
628                                         ++cbinfo->count_10_11;
629                                         break;
630                                 case 3: /* 11 */
631                                         break;
632                                 }
633                         }
634                         mmask >>= 2;
635                         lmask >>= 2;
636                 }
637         }
638
639         /*
640          * Determine if the live bitmap is completely free and reset its
641          * fields if so.  Otherwise check to see if we can reduce the linear
642          * offset.
643          */
644         for (bindex = HAMMER2_BMAP_ELEMENTS - 1; bindex >= 0; --bindex) {
645                 if (live->bitmapq[bindex] != 0)
646                         break;
647         }
648         if (bindex < 0) {
649                 live->avail = HAMMER2_FREEMAP_LEVEL0_SIZE;
650                 live->class = 0;
651                 live->linear = 0;
652                 ++cbinfo->count_l0cleans;
653         } else if (bindex < 7) {
654                 ++bindex;
655                 if (live->linear > bindex * HAMMER2_FREEMAP_BLOCK_SIZE) {
656                         live->linear = bindex * HAMMER2_FREEMAP_BLOCK_SIZE;
657                         ++cbinfo->count_linadjusts;
658                 }
659         }
660
661 #if 0
662         if (bmap->class) {
663                 kprintf("%016jx %04d.%04x (avail=%7d) "
664                         "%08x %08x %08x %08x %08x %08x %08x %08x\n",
665                         (intmax_t)data_off,
666                         (int)((data_off &
667                                HAMMER2_FREEMAP_LEVEL1_MASK) >>
668                               HAMMER2_FREEMAP_LEVEL0_RADIX),
669                         bmap->class,
670                         bmap->avail,
671                         bmap->bitmap[0], bmap->bitmap[1],
672                         bmap->bitmap[2], bmap->bitmap[3],
673                         bmap->bitmap[4], bmap->bitmap[5],
674                         bmap->bitmap[6], bmap->bitmap[7]);
675         }
676 #endif
677 }