Merge branch 'master' into amd64
[dragonfly.git] / sys / vfs / hammer / hammer_blockmap.c
1 /*
2  * Copyright (c) 2008 The DragonFly Project.  All rights reserved.
3  * 
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
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  * $DragonFly: src/sys/vfs/hammer/hammer_blockmap.c,v 1.27 2008/07/31 22:30:33 dillon Exp $
35  */
36
37 /*
38  * HAMMER blockmap
39  */
40 #include "hammer.h"
41
42 static int hammer_res_rb_compare(hammer_reserve_t res1, hammer_reserve_t res2);
43 static void hammer_reserve_setdelay_offset(hammer_mount_t hmp,
44                                     hammer_off_t base_offset, int zone,
45                                     struct hammer_blockmap_layer2 *layer2);
46 static void hammer_reserve_setdelay(hammer_mount_t hmp, hammer_reserve_t resv);
47
48 /*
49  * Reserved big-blocks red-black tree support
50  */
51 RB_GENERATE2(hammer_res_rb_tree, hammer_reserve, rb_node,
52              hammer_res_rb_compare, hammer_off_t, zone_offset);
53
54 static int
55 hammer_res_rb_compare(hammer_reserve_t res1, hammer_reserve_t res2)
56 {
57         if (res1->zone_offset < res2->zone_offset)
58                 return(-1);
59         if (res1->zone_offset > res2->zone_offset)
60                 return(1);
61         return(0);
62 }
63
64 /*
65  * Allocate bytes from a zone
66  */
67 hammer_off_t
68 hammer_blockmap_alloc(hammer_transaction_t trans, int zone, int bytes,
69                       hammer_off_t hint, int *errorp)
70 {
71         hammer_mount_t hmp;
72         hammer_volume_t root_volume;
73         hammer_blockmap_t blockmap;
74         hammer_blockmap_t freemap;
75         hammer_reserve_t resv;
76         struct hammer_blockmap_layer1 *layer1;
77         struct hammer_blockmap_layer2 *layer2;
78         hammer_buffer_t buffer1 = NULL;
79         hammer_buffer_t buffer2 = NULL;
80         hammer_buffer_t buffer3 = NULL;
81         hammer_off_t tmp_offset;
82         hammer_off_t next_offset;
83         hammer_off_t result_offset;
84         hammer_off_t layer1_offset;
85         hammer_off_t layer2_offset;
86         hammer_off_t base_off;
87         int loops = 0;
88         int offset;             /* offset within big-block */
89         int use_hint;
90
91         hmp = trans->hmp;
92
93         /*
94          * Deal with alignment and buffer-boundary issues.
95          *
96          * Be careful, certain primary alignments are used below to allocate
97          * new blockmap blocks.
98          */
99         bytes = (bytes + 15) & ~15;
100         KKASSERT(bytes > 0 && bytes <= HAMMER_XBUFSIZE);
101         KKASSERT(zone >= HAMMER_ZONE_BTREE_INDEX && zone < HAMMER_MAX_ZONES);
102
103         /*
104          * Setup
105          */
106         root_volume = trans->rootvol;
107         *errorp = 0;
108         blockmap = &hmp->blockmap[zone];
109         freemap = &hmp->blockmap[HAMMER_ZONE_FREEMAP_INDEX];
110         KKASSERT(HAMMER_ZONE_DECODE(blockmap->next_offset) == zone);
111
112         /*
113          * Use the hint if we have one.
114          */
115         if (hint && HAMMER_ZONE_DECODE(hint) == zone) {
116                 next_offset = (hint + 15) & ~(hammer_off_t)15;
117                 use_hint = 1;
118         } else {
119                 next_offset = blockmap->next_offset;
120                 use_hint = 0;
121         }
122 again:
123
124         /*
125          * use_hint is turned off if we leave the hinted big-block.
126          */
127         if (use_hint && ((next_offset ^ hint) & ~HAMMER_HINTBLOCK_MASK64)) {
128                 next_offset = blockmap->next_offset;
129                 use_hint = 0;
130         }
131
132         /*
133          * Check for wrap
134          */
135         if (next_offset == HAMMER_ZONE_ENCODE(zone + 1, 0)) {
136                 if (++loops == 2) {
137                         result_offset = 0;
138                         *errorp = ENOSPC;
139                         goto failed;
140                 }
141                 next_offset = HAMMER_ZONE_ENCODE(zone, 0);
142         }
143
144         /*
145          * The allocation request may not cross a buffer boundary.  Special
146          * large allocations must not cross a large-block boundary.
147          */
148         tmp_offset = next_offset + bytes - 1;
149         if (bytes <= HAMMER_BUFSIZE) {
150                 if ((next_offset ^ tmp_offset) & ~HAMMER_BUFMASK64) {
151                         next_offset = tmp_offset & ~HAMMER_BUFMASK64;
152                         goto again;
153                 }
154         } else {
155                 if ((next_offset ^ tmp_offset) & ~HAMMER_LARGEBLOCK_MASK64) {
156                         next_offset = tmp_offset & ~HAMMER_LARGEBLOCK_MASK64;
157                         goto again;
158                 }
159         }
160         offset = (int)next_offset & HAMMER_LARGEBLOCK_MASK;
161
162         /*
163          * Dive layer 1.
164          */
165         layer1_offset = freemap->phys_offset +
166                         HAMMER_BLOCKMAP_LAYER1_OFFSET(next_offset);
167         layer1 = hammer_bread(hmp, layer1_offset, errorp, &buffer1);
168         if (*errorp) {
169                 result_offset = 0;
170                 goto failed;
171         }
172
173         /*
174          * Check CRC.
175          */
176         if (layer1->layer1_crc != crc32(layer1, HAMMER_LAYER1_CRCSIZE)) {
177                 hammer_lock_ex(&hmp->blkmap_lock);
178                 if (layer1->layer1_crc != crc32(layer1, HAMMER_LAYER1_CRCSIZE))
179                         panic("CRC FAILED: LAYER1");
180                 hammer_unlock(&hmp->blkmap_lock);
181         }
182
183         /*
184          * If we are at a big-block boundary and layer1 indicates no 
185          * free big-blocks, then we cannot allocate a new bigblock in
186          * layer2, skip to the next layer1 entry.
187          */
188         if (offset == 0 && layer1->blocks_free == 0) {
189                 next_offset = (next_offset + HAMMER_BLOCKMAP_LAYER2) &
190                               ~HAMMER_BLOCKMAP_LAYER2_MASK;
191                 goto again;
192         }
193         KKASSERT(layer1->phys_offset != HAMMER_BLOCKMAP_UNAVAIL);
194
195         /*
196          * Dive layer 2, each entry represents a large-block.
197          */
198         layer2_offset = layer1->phys_offset +
199                         HAMMER_BLOCKMAP_LAYER2_OFFSET(next_offset);
200         layer2 = hammer_bread(hmp, layer2_offset, errorp, &buffer2);
201         if (*errorp) {
202                 result_offset = 0;
203                 goto failed;
204         }
205
206         /*
207          * Check CRC.  This can race another thread holding the lock
208          * and in the middle of modifying layer2.
209          */
210         if (layer2->entry_crc != crc32(layer2, HAMMER_LAYER2_CRCSIZE)) {
211                 hammer_lock_ex(&hmp->blkmap_lock);
212                 if (layer2->entry_crc != crc32(layer2, HAMMER_LAYER2_CRCSIZE))
213                         panic("CRC FAILED: LAYER2");
214                 hammer_unlock(&hmp->blkmap_lock);
215         }
216
217         /*
218          * Skip the layer if the zone is owned by someone other then us.
219          */
220         if (layer2->zone && layer2->zone != zone) {
221                 next_offset += (HAMMER_LARGEBLOCK_SIZE - offset);
222                 goto again;
223         }
224         if (offset < layer2->append_off) {
225                 next_offset += layer2->append_off - offset;
226                 goto again;
227         }
228
229         /*
230          * If operating in the current non-hint blockmap block, do not
231          * allow it to get over-full.  Also drop any active hinting so
232          * blockmap->next_offset is updated at the end.
233          *
234          * We do this for B-Tree and meta-data allocations to provide
235          * localization for updates.
236          */
237         if ((zone == HAMMER_ZONE_BTREE_INDEX ||
238              zone == HAMMER_ZONE_META_INDEX) &&
239             offset >= HAMMER_LARGEBLOCK_OVERFILL &&
240             !((next_offset ^ blockmap->next_offset) & ~HAMMER_LARGEBLOCK_MASK64)
241         ) {
242                 if (offset >= HAMMER_LARGEBLOCK_OVERFILL) {
243                         next_offset += (HAMMER_LARGEBLOCK_SIZE - offset);
244                         use_hint = 0;
245                         goto again;
246                 }
247         }
248
249         /*
250          * We need the lock from this point on.  We have to re-check zone
251          * ownership after acquiring the lock and also check for reservations.
252          */
253         hammer_lock_ex(&hmp->blkmap_lock);
254
255         if (layer2->zone && layer2->zone != zone) {
256                 hammer_unlock(&hmp->blkmap_lock);
257                 next_offset += (HAMMER_LARGEBLOCK_SIZE - offset);
258                 goto again;
259         }
260         if (offset < layer2->append_off) {
261                 hammer_unlock(&hmp->blkmap_lock);
262                 next_offset += layer2->append_off - offset;
263                 goto again;
264         }
265
266         /*
267          * The bigblock might be reserved by another zone.  If it is reserved
268          * by our zone we may have to move next_offset past the append_off.
269          */
270         base_off = (next_offset &
271                     (~HAMMER_LARGEBLOCK_MASK64 & ~HAMMER_OFF_ZONE_MASK)) | 
272                     HAMMER_ZONE_RAW_BUFFER;
273         resv = RB_LOOKUP(hammer_res_rb_tree, &hmp->rb_resv_root, base_off);
274         if (resv) {
275                 if (resv->zone != zone) {
276                         hammer_unlock(&hmp->blkmap_lock);
277                         next_offset = (next_offset + HAMMER_LARGEBLOCK_SIZE) &
278                                       ~HAMMER_LARGEBLOCK_MASK64;
279                         goto again;
280                 }
281                 if (offset < resv->append_off) {
282                         hammer_unlock(&hmp->blkmap_lock);
283                         next_offset += resv->append_off - offset;
284                         goto again;
285                 }
286                 ++resv->refs;
287         }
288
289         /*
290          * Ok, we can allocate out of this layer2 big-block.  Assume ownership
291          * of the layer for real.  At this point we've validated any
292          * reservation that might exist and can just ignore resv.
293          */
294         if (layer2->zone == 0) {
295                 /*
296                  * Assign the bigblock to our zone
297                  */
298                 hammer_modify_buffer(trans, buffer1,
299                                      layer1, sizeof(*layer1));
300                 --layer1->blocks_free;
301                 layer1->layer1_crc = crc32(layer1,
302                                            HAMMER_LAYER1_CRCSIZE);
303                 hammer_modify_buffer_done(buffer1);
304                 hammer_modify_buffer(trans, buffer2,
305                                      layer2, sizeof(*layer2));
306                 layer2->zone = zone;
307                 KKASSERT(layer2->bytes_free == HAMMER_LARGEBLOCK_SIZE);
308                 KKASSERT(layer2->append_off == 0);
309                 hammer_modify_volume_field(trans, trans->rootvol,
310                                            vol0_stat_freebigblocks);
311                 --root_volume->ondisk->vol0_stat_freebigblocks;
312                 hmp->copy_stat_freebigblocks =
313                         root_volume->ondisk->vol0_stat_freebigblocks;
314                 hammer_modify_volume_done(trans->rootvol);
315         } else {
316                 hammer_modify_buffer(trans, buffer2,
317                                      layer2, sizeof(*layer2));
318         }
319         KKASSERT(layer2->zone == zone);
320
321         layer2->bytes_free -= bytes;
322         KKASSERT(layer2->append_off <= offset);
323         layer2->append_off = offset + bytes;
324         layer2->entry_crc = crc32(layer2, HAMMER_LAYER2_CRCSIZE);
325         hammer_modify_buffer_done(buffer2);
326         KKASSERT(layer2->bytes_free >= 0);
327
328         /*
329          * We hold the blockmap lock and should be the only ones
330          * capable of modifying resv->append_off.  Track the allocation
331          * as appropriate.
332          */
333         KKASSERT(bytes != 0);
334         if (resv) {
335                 KKASSERT(resv->append_off <= offset);
336                 resv->append_off = offset + bytes;
337                 resv->flags &= ~HAMMER_RESF_LAYER2FREE;
338                 hammer_blockmap_reserve_complete(hmp, resv);
339         }
340
341         /*
342          * If we are allocating from the base of a new buffer we can avoid
343          * a disk read by calling hammer_bnew().
344          */
345         if ((next_offset & HAMMER_BUFMASK) == 0) {
346                 hammer_bnew_ext(trans->hmp, next_offset, bytes,
347                                 errorp, &buffer3);
348         }
349         result_offset = next_offset;
350
351         /*
352          * If we weren't supplied with a hint or could not use the hint
353          * then we wound up using blockmap->next_offset as the hint and
354          * need to save it.
355          */
356         if (use_hint == 0) {
357                 hammer_modify_volume(NULL, root_volume, NULL, 0);
358                 blockmap->next_offset = next_offset + bytes;
359                 hammer_modify_volume_done(root_volume);
360         }
361         hammer_unlock(&hmp->blkmap_lock);
362 failed:
363
364         /*
365          * Cleanup
366          */
367         if (buffer1)
368                 hammer_rel_buffer(buffer1, 0);
369         if (buffer2)
370                 hammer_rel_buffer(buffer2, 0);
371         if (buffer3)
372                 hammer_rel_buffer(buffer3, 0);
373
374         return(result_offset);
375 }
376
377 /*
378  * Frontend function - Reserve bytes in a zone.
379  *
380  * This code reserves bytes out of a blockmap without committing to any
381  * meta-data modifications, allowing the front-end to directly issue disk
382  * write I/O for large blocks of data
383  *
384  * The backend later finalizes the reservation with hammer_blockmap_finalize()
385  * upon committing the related record.
386  */
387 hammer_reserve_t
388 hammer_blockmap_reserve(hammer_mount_t hmp, int zone, int bytes,
389                         hammer_off_t *zone_offp, int *errorp)
390 {
391         hammer_volume_t root_volume;
392         hammer_blockmap_t blockmap;
393         hammer_blockmap_t freemap;
394         struct hammer_blockmap_layer1 *layer1;
395         struct hammer_blockmap_layer2 *layer2;
396         hammer_buffer_t buffer1 = NULL;
397         hammer_buffer_t buffer2 = NULL;
398         hammer_buffer_t buffer3 = NULL;
399         hammer_off_t tmp_offset;
400         hammer_off_t next_offset;
401         hammer_off_t layer1_offset;
402         hammer_off_t layer2_offset;
403         hammer_off_t base_off;
404         hammer_reserve_t resv;
405         hammer_reserve_t resx;
406         int loops = 0;
407         int offset;
408
409         /*
410          * Setup
411          */
412         KKASSERT(zone >= HAMMER_ZONE_BTREE_INDEX && zone < HAMMER_MAX_ZONES);
413         root_volume = hammer_get_root_volume(hmp, errorp);
414         if (*errorp)
415                 return(NULL);
416         blockmap = &hmp->blockmap[zone];
417         freemap = &hmp->blockmap[HAMMER_ZONE_FREEMAP_INDEX];
418         KKASSERT(HAMMER_ZONE_DECODE(blockmap->next_offset) == zone);
419
420         /*
421          * Deal with alignment and buffer-boundary issues.
422          *
423          * Be careful, certain primary alignments are used below to allocate
424          * new blockmap blocks.
425          */
426         bytes = (bytes + 15) & ~15;
427         KKASSERT(bytes > 0 && bytes <= HAMMER_XBUFSIZE);
428
429         next_offset = blockmap->next_offset;
430 again:
431         resv = NULL;
432         /*
433          * Check for wrap
434          */
435         if (next_offset == HAMMER_ZONE_ENCODE(zone + 1, 0)) {
436                 if (++loops == 2) {
437                         *errorp = ENOSPC;
438                         goto failed;
439                 }
440                 next_offset = HAMMER_ZONE_ENCODE(zone, 0);
441         }
442
443         /*
444          * The allocation request may not cross a buffer boundary.  Special
445          * large allocations must not cross a large-block boundary.
446          */
447         tmp_offset = next_offset + bytes - 1;
448         if (bytes <= HAMMER_BUFSIZE) {
449                 if ((next_offset ^ tmp_offset) & ~HAMMER_BUFMASK64) {
450                         next_offset = tmp_offset & ~HAMMER_BUFMASK64;
451                         goto again;
452                 }
453         } else {
454                 if ((next_offset ^ tmp_offset) & ~HAMMER_LARGEBLOCK_MASK64) {
455                         next_offset = tmp_offset & ~HAMMER_LARGEBLOCK_MASK64;
456                         goto again;
457                 }
458         }
459         offset = (int)next_offset & HAMMER_LARGEBLOCK_MASK;
460
461         /*
462          * Dive layer 1.
463          */
464         layer1_offset = freemap->phys_offset +
465                         HAMMER_BLOCKMAP_LAYER1_OFFSET(next_offset);
466         layer1 = hammer_bread(hmp, layer1_offset, errorp, &buffer1);
467         if (*errorp)
468                 goto failed;
469
470         /*
471          * Check CRC.
472          */
473         if (layer1->layer1_crc != crc32(layer1, HAMMER_LAYER1_CRCSIZE)) {
474                 hammer_lock_ex(&hmp->blkmap_lock);
475                 if (layer1->layer1_crc != crc32(layer1, HAMMER_LAYER1_CRCSIZE))
476                         panic("CRC FAILED: LAYER1");
477                 hammer_unlock(&hmp->blkmap_lock);
478         }
479
480         /*
481          * If we are at a big-block boundary and layer1 indicates no 
482          * free big-blocks, then we cannot allocate a new bigblock in
483          * layer2, skip to the next layer1 entry.
484          */
485         if ((next_offset & HAMMER_LARGEBLOCK_MASK) == 0 &&
486             layer1->blocks_free == 0) {
487                 next_offset = (next_offset + HAMMER_BLOCKMAP_LAYER2) &
488                               ~HAMMER_BLOCKMAP_LAYER2_MASK;
489                 goto again;
490         }
491         KKASSERT(layer1->phys_offset != HAMMER_BLOCKMAP_UNAVAIL);
492
493         /*
494          * Dive layer 2, each entry represents a large-block.
495          */
496         layer2_offset = layer1->phys_offset +
497                         HAMMER_BLOCKMAP_LAYER2_OFFSET(next_offset);
498         layer2 = hammer_bread(hmp, layer2_offset, errorp, &buffer2);
499         if (*errorp)
500                 goto failed;
501
502         /*
503          * Check CRC if not allocating into uninitialized space (which we
504          * aren't when reserving space).
505          */
506         if (layer2->entry_crc != crc32(layer2, HAMMER_LAYER2_CRCSIZE)) {
507                 hammer_lock_ex(&hmp->blkmap_lock);
508                 if (layer2->entry_crc != crc32(layer2, HAMMER_LAYER2_CRCSIZE))
509                         panic("CRC FAILED: LAYER2");
510                 hammer_unlock(&hmp->blkmap_lock);
511         }
512
513         /*
514          * Skip the layer if the zone is owned by someone other then us.
515          */
516         if (layer2->zone && layer2->zone != zone) {
517                 next_offset += (HAMMER_LARGEBLOCK_SIZE - offset);
518                 goto again;
519         }
520         if (offset < layer2->append_off) {
521                 next_offset += layer2->append_off - offset;
522                 goto again;
523         }
524
525         /*
526          * We need the lock from this point on.  We have to re-check zone
527          * ownership after acquiring the lock and also check for reservations.
528          */
529         hammer_lock_ex(&hmp->blkmap_lock);
530
531         if (layer2->zone && layer2->zone != zone) {
532                 hammer_unlock(&hmp->blkmap_lock);
533                 next_offset += (HAMMER_LARGEBLOCK_SIZE - offset);
534                 goto again;
535         }
536         if (offset < layer2->append_off) {
537                 hammer_unlock(&hmp->blkmap_lock);
538                 next_offset += layer2->append_off - offset;
539                 goto again;
540         }
541
542         /*
543          * The bigblock might be reserved by another zone.  If it is reserved
544          * by our zone we may have to move next_offset past the append_off.
545          */
546         base_off = (next_offset &
547                     (~HAMMER_LARGEBLOCK_MASK64 & ~HAMMER_OFF_ZONE_MASK)) |
548                     HAMMER_ZONE_RAW_BUFFER;
549         resv = RB_LOOKUP(hammer_res_rb_tree, &hmp->rb_resv_root, base_off);
550         if (resv) {
551                 if (resv->zone != zone) {
552                         hammer_unlock(&hmp->blkmap_lock);
553                         next_offset = (next_offset + HAMMER_LARGEBLOCK_SIZE) &
554                                       ~HAMMER_LARGEBLOCK_MASK64;
555                         goto again;
556                 }
557                 if (offset < resv->append_off) {
558                         hammer_unlock(&hmp->blkmap_lock);
559                         next_offset += resv->append_off - offset;
560                         goto again;
561                 }
562                 ++resv->refs;
563                 resx = NULL;
564         } else {
565                 resx = kmalloc(sizeof(*resv), hmp->m_misc,
566                                M_WAITOK | M_ZERO | M_USE_RESERVE);
567                 resx->refs = 1;
568                 resx->zone = zone;
569                 resx->zone_offset = base_off;
570                 if (layer2->bytes_free == HAMMER_LARGEBLOCK_SIZE)
571                         resx->flags |= HAMMER_RESF_LAYER2FREE;
572                 resv = RB_INSERT(hammer_res_rb_tree, &hmp->rb_resv_root, resx);
573                 KKASSERT(resv == NULL);
574                 resv = resx;
575                 ++hammer_count_reservations;
576         }
577         resv->append_off = offset + bytes;
578
579         /*
580          * If we are not reserving a whole buffer but are at the start of
581          * a new block, call hammer_bnew() to avoid a disk read.
582          *
583          * If we are reserving a whole buffer (or more), the caller will
584          * probably use a direct read, so do nothing.
585          */
586         if (bytes < HAMMER_BUFSIZE && (next_offset & HAMMER_BUFMASK) == 0) {
587                 hammer_bnew(hmp, next_offset, errorp, &buffer3);
588         }
589
590         /*
591          * Adjust our iterator and alloc_offset.  The layer1 and layer2
592          * space beyond alloc_offset is uninitialized.  alloc_offset must
593          * be big-block aligned.
594          */
595         blockmap->next_offset = next_offset + bytes;
596         hammer_unlock(&hmp->blkmap_lock);
597
598 failed:
599         if (buffer1)
600                 hammer_rel_buffer(buffer1, 0);
601         if (buffer2)
602                 hammer_rel_buffer(buffer2, 0);
603         if (buffer3)
604                 hammer_rel_buffer(buffer3, 0);
605         hammer_rel_volume(root_volume, 0);
606         *zone_offp = next_offset;
607
608         return(resv);
609 }
610
611 /*
612  * Dereference a reservation structure.  Upon the final release the
613  * underlying big-block is checked and if it is entirely free we delete
614  * any related HAMMER buffers to avoid potential conflicts with future
615  * reuse of the big-block.
616  */
617 void
618 hammer_blockmap_reserve_complete(hammer_mount_t hmp, hammer_reserve_t resv)
619 {
620         hammer_off_t base_offset;
621         int error;
622
623         KKASSERT(resv->refs > 0);
624         KKASSERT((resv->zone_offset & HAMMER_OFF_ZONE_MASK) ==
625                  HAMMER_ZONE_RAW_BUFFER);
626
627         /*
628          * Setting append_off to the max prevents any new allocations
629          * from occuring while we are trying to dispose of the reservation,
630          * allowing us to safely delete any related HAMMER buffers.
631          *
632          * If we are unable to clean out all related HAMMER buffers we
633          * requeue the delay.
634          */
635         if (resv->refs == 1 && (resv->flags & HAMMER_RESF_LAYER2FREE)) {
636                 resv->append_off = HAMMER_LARGEBLOCK_SIZE;
637                 base_offset = resv->zone_offset & ~HAMMER_OFF_ZONE_MASK;
638                 base_offset = HAMMER_ZONE_ENCODE(resv->zone, base_offset);
639                 error = hammer_del_buffers(hmp, base_offset,
640                                            resv->zone_offset,
641                                            HAMMER_LARGEBLOCK_SIZE,
642                                            0);
643                 if (error)
644                         hammer_reserve_setdelay(hmp, resv);
645         }
646         if (--resv->refs == 0) {
647                 KKASSERT((resv->flags & HAMMER_RESF_ONDELAY) == 0);
648                 RB_REMOVE(hammer_res_rb_tree, &hmp->rb_resv_root, resv);
649                 kfree(resv, hmp->m_misc);
650                 --hammer_count_reservations;
651         }
652 }
653
654 /*
655  * Prevent a potentially free big-block from being reused until after
656  * the related flushes have completely cycled, otherwise crash recovery
657  * could resurrect a data block that was already reused and overwritten.
658  *
659  * The caller might reset the underlying layer2 entry's append_off to 0, so
660  * our covering append_off must be set to max to prevent any reallocation
661  * until after the flush delays complete, not to mention proper invalidation
662  * of any underlying cached blocks.
663  */
664 static void
665 hammer_reserve_setdelay_offset(hammer_mount_t hmp, hammer_off_t base_offset,
666                         int zone, struct hammer_blockmap_layer2 *layer2)
667 {
668         hammer_reserve_t resv;
669
670         /*
671          * Allocate the reservation if necessary.
672          *
673          * NOTE: need lock in future around resv lookup/allocation and
674          * the setdelay call, currently refs is not bumped until the call.
675          */
676 again:
677         resv = RB_LOOKUP(hammer_res_rb_tree, &hmp->rb_resv_root, base_offset);
678         if (resv == NULL) {
679                 resv = kmalloc(sizeof(*resv), hmp->m_misc,
680                                M_WAITOK | M_ZERO | M_USE_RESERVE);
681                 resv->zone = zone;
682                 resv->zone_offset = base_offset;
683                 resv->refs = 0;
684                 resv->append_off = HAMMER_LARGEBLOCK_SIZE;
685
686                 if (layer2->bytes_free == HAMMER_LARGEBLOCK_SIZE)
687                         resv->flags |= HAMMER_RESF_LAYER2FREE;
688                 if (RB_INSERT(hammer_res_rb_tree, &hmp->rb_resv_root, resv)) {
689                         kfree(resv, hmp->m_misc);
690                         goto again;
691                 }
692                 ++hammer_count_reservations;
693         } else {
694                 if (layer2->bytes_free == HAMMER_LARGEBLOCK_SIZE)
695                         resv->flags |= HAMMER_RESF_LAYER2FREE;
696         }
697         hammer_reserve_setdelay(hmp, resv);
698 }
699
700 /*
701  * Enter the reservation on the on-delay list, or move it if it
702  * is already on the list.
703  */
704 static void
705 hammer_reserve_setdelay(hammer_mount_t hmp, hammer_reserve_t resv)
706 {
707         if (resv->flags & HAMMER_RESF_ONDELAY) {
708                 TAILQ_REMOVE(&hmp->delay_list, resv, delay_entry);
709                 resv->flush_group = hmp->flusher.next + 1;
710                 TAILQ_INSERT_TAIL(&hmp->delay_list, resv, delay_entry);
711         } else {
712                 ++resv->refs;
713                 ++hmp->rsv_fromdelay;
714                 resv->flags |= HAMMER_RESF_ONDELAY;
715                 resv->flush_group = hmp->flusher.next + 1;
716                 TAILQ_INSERT_TAIL(&hmp->delay_list, resv, delay_entry);
717         }
718 }
719
720 void
721 hammer_reserve_clrdelay(hammer_mount_t hmp, hammer_reserve_t resv)
722 {
723         KKASSERT(resv->flags & HAMMER_RESF_ONDELAY);
724         resv->flags &= ~HAMMER_RESF_ONDELAY;
725         TAILQ_REMOVE(&hmp->delay_list, resv, delay_entry);
726         --hmp->rsv_fromdelay;
727         hammer_blockmap_reserve_complete(hmp, resv);
728 }
729
730 /*
731  * Backend function - free (offset, bytes) in a zone.
732  *
733  * XXX error return
734  */
735 void
736 hammer_blockmap_free(hammer_transaction_t trans,
737                      hammer_off_t zone_offset, int bytes)
738 {
739         hammer_mount_t hmp;
740         hammer_volume_t root_volume;
741         hammer_blockmap_t blockmap;
742         hammer_blockmap_t freemap;
743         struct hammer_blockmap_layer1 *layer1;
744         struct hammer_blockmap_layer2 *layer2;
745         hammer_buffer_t buffer1 = NULL;
746         hammer_buffer_t buffer2 = NULL;
747         hammer_off_t layer1_offset;
748         hammer_off_t layer2_offset;
749         hammer_off_t base_off;
750         int error;
751         int zone;
752
753         if (bytes == 0)
754                 return;
755         hmp = trans->hmp;
756
757         /*
758          * Alignment
759          */
760         bytes = (bytes + 15) & ~15;
761         KKASSERT(bytes <= HAMMER_XBUFSIZE);
762         KKASSERT(((zone_offset ^ (zone_offset + (bytes - 1))) & 
763                   ~HAMMER_LARGEBLOCK_MASK64) == 0);
764
765         /*
766          * Basic zone validation & locking
767          */
768         zone = HAMMER_ZONE_DECODE(zone_offset);
769         KKASSERT(zone >= HAMMER_ZONE_BTREE_INDEX && zone < HAMMER_MAX_ZONES);
770         root_volume = trans->rootvol;
771         error = 0;
772
773         blockmap = &hmp->blockmap[zone];
774         freemap = &hmp->blockmap[HAMMER_ZONE_FREEMAP_INDEX];
775
776         /*
777          * Dive layer 1.
778          */
779         layer1_offset = freemap->phys_offset +
780                         HAMMER_BLOCKMAP_LAYER1_OFFSET(zone_offset);
781         layer1 = hammer_bread(hmp, layer1_offset, &error, &buffer1);
782         if (error)
783                 goto failed;
784         KKASSERT(layer1->phys_offset &&
785                  layer1->phys_offset != HAMMER_BLOCKMAP_UNAVAIL);
786         if (layer1->layer1_crc != crc32(layer1, HAMMER_LAYER1_CRCSIZE)) {
787                 hammer_lock_ex(&hmp->blkmap_lock);
788                 if (layer1->layer1_crc != crc32(layer1, HAMMER_LAYER1_CRCSIZE))
789                         panic("CRC FAILED: LAYER1");
790                 hammer_unlock(&hmp->blkmap_lock);
791         }
792
793         /*
794          * Dive layer 2, each entry represents a large-block.
795          */
796         layer2_offset = layer1->phys_offset +
797                         HAMMER_BLOCKMAP_LAYER2_OFFSET(zone_offset);
798         layer2 = hammer_bread(hmp, layer2_offset, &error, &buffer2);
799         if (error)
800                 goto failed;
801         if (layer2->entry_crc != crc32(layer2, HAMMER_LAYER2_CRCSIZE)) {
802                 hammer_lock_ex(&hmp->blkmap_lock);
803                 if (layer2->entry_crc != crc32(layer2, HAMMER_LAYER2_CRCSIZE))
804                         panic("CRC FAILED: LAYER2");
805                 hammer_unlock(&hmp->blkmap_lock);
806         }
807
808         hammer_lock_ex(&hmp->blkmap_lock);
809
810         hammer_modify_buffer(trans, buffer2, layer2, sizeof(*layer2));
811
812         /*
813          * Free space previously allocated via blockmap_alloc().
814          */
815         KKASSERT(layer2->zone == zone);
816         layer2->bytes_free += bytes;
817         KKASSERT(layer2->bytes_free <= HAMMER_LARGEBLOCK_SIZE);
818
819         /*
820          * If a big-block becomes entirely free we must create a covering
821          * reservation to prevent premature reuse.  Note, however, that
822          * the big-block and/or reservation may still have an append_off
823          * that allows further (non-reused) allocations.
824          *
825          * Once the reservation has been made we re-check layer2 and if
826          * the big-block is still entirely free we reset the layer2 entry.
827          * The reservation will prevent premature reuse.
828          *
829          * NOTE: hammer_buffer's are only invalidated when the reservation
830          * is completed, if the layer2 entry is still completely free at
831          * that time.  Any allocations from the reservation that may have
832          * occured in the mean time, or active references on the reservation
833          * from new pending allocations, will prevent the invalidation from
834          * occuring.
835          */
836         if (layer2->bytes_free == HAMMER_LARGEBLOCK_SIZE) {
837                 base_off = (zone_offset & (~HAMMER_LARGEBLOCK_MASK64 & ~HAMMER_OFF_ZONE_MASK)) | HAMMER_ZONE_RAW_BUFFER;
838
839                 hammer_reserve_setdelay_offset(hmp, base_off, zone, layer2);
840                 if (layer2->bytes_free == HAMMER_LARGEBLOCK_SIZE) {
841                         layer2->zone = 0;
842                         layer2->append_off = 0;
843                         hammer_modify_buffer(trans, buffer1,
844                                              layer1, sizeof(*layer1));
845                         ++layer1->blocks_free;
846                         layer1->layer1_crc = crc32(layer1,
847                                                    HAMMER_LAYER1_CRCSIZE);
848                         hammer_modify_buffer_done(buffer1);
849                         hammer_modify_volume_field(trans,
850                                         trans->rootvol,
851                                         vol0_stat_freebigblocks);
852                         ++root_volume->ondisk->vol0_stat_freebigblocks;
853                         hmp->copy_stat_freebigblocks =
854                            root_volume->ondisk->vol0_stat_freebigblocks;
855                         hammer_modify_volume_done(trans->rootvol);
856                 }
857         }
858         layer2->entry_crc = crc32(layer2, HAMMER_LAYER2_CRCSIZE);
859         hammer_modify_buffer_done(buffer2);
860         hammer_unlock(&hmp->blkmap_lock);
861
862 failed:
863         if (buffer1)
864                 hammer_rel_buffer(buffer1, 0);
865         if (buffer2)
866                 hammer_rel_buffer(buffer2, 0);
867 }
868
869 /*
870  * Backend function - finalize (offset, bytes) in a zone.
871  *
872  * Allocate space that was previously reserved by the frontend.
873  */
874 int
875 hammer_blockmap_finalize(hammer_transaction_t trans,
876                          hammer_reserve_t resv,
877                          hammer_off_t zone_offset, int bytes)
878 {
879         hammer_mount_t hmp;
880         hammer_volume_t root_volume;
881         hammer_blockmap_t blockmap;
882         hammer_blockmap_t freemap;
883         struct hammer_blockmap_layer1 *layer1;
884         struct hammer_blockmap_layer2 *layer2;
885         hammer_buffer_t buffer1 = NULL;
886         hammer_buffer_t buffer2 = NULL;
887         hammer_off_t layer1_offset;
888         hammer_off_t layer2_offset;
889         int error;
890         int zone;
891         int offset;
892
893         if (bytes == 0)
894                 return(0);
895         hmp = trans->hmp;
896
897         /*
898          * Alignment
899          */
900         bytes = (bytes + 15) & ~15;
901         KKASSERT(bytes <= HAMMER_XBUFSIZE);
902
903         /*
904          * Basic zone validation & locking
905          */
906         zone = HAMMER_ZONE_DECODE(zone_offset);
907         KKASSERT(zone >= HAMMER_ZONE_BTREE_INDEX && zone < HAMMER_MAX_ZONES);
908         root_volume = trans->rootvol;
909         error = 0;
910
911         blockmap = &hmp->blockmap[zone];
912         freemap = &hmp->blockmap[HAMMER_ZONE_FREEMAP_INDEX];
913
914         /*
915          * Dive layer 1.
916          */
917         layer1_offset = freemap->phys_offset +
918                         HAMMER_BLOCKMAP_LAYER1_OFFSET(zone_offset);
919         layer1 = hammer_bread(hmp, layer1_offset, &error, &buffer1);
920         if (error)
921                 goto failed;
922         KKASSERT(layer1->phys_offset &&
923                  layer1->phys_offset != HAMMER_BLOCKMAP_UNAVAIL);
924         if (layer1->layer1_crc != crc32(layer1, HAMMER_LAYER1_CRCSIZE)) {
925                 hammer_lock_ex(&hmp->blkmap_lock);
926                 if (layer1->layer1_crc != crc32(layer1, HAMMER_LAYER1_CRCSIZE))
927                         panic("CRC FAILED: LAYER1");
928                 hammer_unlock(&hmp->blkmap_lock);
929         }
930
931         /*
932          * Dive layer 2, each entry represents a large-block.
933          */
934         layer2_offset = layer1->phys_offset +
935                         HAMMER_BLOCKMAP_LAYER2_OFFSET(zone_offset);
936         layer2 = hammer_bread(hmp, layer2_offset, &error, &buffer2);
937         if (error)
938                 goto failed;
939         if (layer2->entry_crc != crc32(layer2, HAMMER_LAYER2_CRCSIZE)) {
940                 hammer_lock_ex(&hmp->blkmap_lock);
941                 if (layer2->entry_crc != crc32(layer2, HAMMER_LAYER2_CRCSIZE))
942                         panic("CRC FAILED: LAYER2");
943                 hammer_unlock(&hmp->blkmap_lock);
944         }
945
946         hammer_lock_ex(&hmp->blkmap_lock);
947
948         hammer_modify_buffer(trans, buffer2, layer2, sizeof(*layer2));
949
950         /*
951          * Finalize some or all of the space covered by a current
952          * reservation.  An allocation in the same layer may have
953          * already assigned ownership.
954          */
955         if (layer2->zone == 0) {
956                 hammer_modify_buffer(trans, buffer1,
957                                      layer1, sizeof(*layer1));
958                 --layer1->blocks_free;
959                 layer1->layer1_crc = crc32(layer1,
960                                            HAMMER_LAYER1_CRCSIZE);
961                 hammer_modify_buffer_done(buffer1);
962                 layer2->zone = zone;
963                 KKASSERT(layer2->bytes_free == HAMMER_LARGEBLOCK_SIZE);
964                 KKASSERT(layer2->append_off == 0);
965                 hammer_modify_volume_field(trans,
966                                 trans->rootvol,
967                                 vol0_stat_freebigblocks);
968                 --root_volume->ondisk->vol0_stat_freebigblocks;
969                 hmp->copy_stat_freebigblocks =
970                    root_volume->ondisk->vol0_stat_freebigblocks;
971                 hammer_modify_volume_done(trans->rootvol);
972         }
973         if (layer2->zone != zone)
974                 kprintf("layer2 zone mismatch %d %d\n", layer2->zone, zone);
975         KKASSERT(layer2->zone == zone);
976         KKASSERT(bytes != 0);
977         layer2->bytes_free -= bytes;
978         if (resv)
979                 resv->flags &= ~HAMMER_RESF_LAYER2FREE;
980
981         /*
982          * Finalizations can occur out of order, or combined with allocations.
983          * append_off must be set to the highest allocated offset.
984          */
985         offset = ((int)zone_offset & HAMMER_LARGEBLOCK_MASK) + bytes;
986         if (layer2->append_off < offset)
987                 layer2->append_off = offset;
988
989         layer2->entry_crc = crc32(layer2, HAMMER_LAYER2_CRCSIZE);
990         hammer_modify_buffer_done(buffer2);
991         hammer_unlock(&hmp->blkmap_lock);
992
993 failed:
994         if (buffer1)
995                 hammer_rel_buffer(buffer1, 0);
996         if (buffer2)
997                 hammer_rel_buffer(buffer2, 0);
998         return(error);
999 }
1000
1001 /*
1002  * Return the number of free bytes in the big-block containing the
1003  * specified blockmap offset.
1004  */
1005 int
1006 hammer_blockmap_getfree(hammer_mount_t hmp, hammer_off_t zone_offset,
1007                         int *curp, int *errorp)
1008 {
1009         hammer_volume_t root_volume;
1010         hammer_blockmap_t blockmap;
1011         hammer_blockmap_t freemap;
1012         struct hammer_blockmap_layer1 *layer1;
1013         struct hammer_blockmap_layer2 *layer2;
1014         hammer_buffer_t buffer = NULL;
1015         hammer_off_t layer1_offset;
1016         hammer_off_t layer2_offset;
1017         int bytes;
1018         int zone;
1019
1020         zone = HAMMER_ZONE_DECODE(zone_offset);
1021         KKASSERT(zone >= HAMMER_ZONE_BTREE_INDEX && zone < HAMMER_MAX_ZONES);
1022         root_volume = hammer_get_root_volume(hmp, errorp);
1023         if (*errorp) {
1024                 *curp = 0;
1025                 return(0);
1026         }
1027         blockmap = &hmp->blockmap[zone];
1028         freemap = &hmp->blockmap[HAMMER_ZONE_FREEMAP_INDEX];
1029
1030         /*
1031          * Dive layer 1.
1032          */
1033         layer1_offset = freemap->phys_offset +
1034                         HAMMER_BLOCKMAP_LAYER1_OFFSET(zone_offset);
1035         layer1 = hammer_bread(hmp, layer1_offset, errorp, &buffer);
1036         if (*errorp) {
1037                 bytes = 0;
1038                 goto failed;
1039         }
1040         KKASSERT(layer1->phys_offset);
1041         if (layer1->layer1_crc != crc32(layer1, HAMMER_LAYER1_CRCSIZE)) {
1042                 hammer_lock_ex(&hmp->blkmap_lock);
1043                 if (layer1->layer1_crc != crc32(layer1, HAMMER_LAYER1_CRCSIZE))
1044                         panic("CRC FAILED: LAYER1");
1045                 hammer_unlock(&hmp->blkmap_lock);
1046         }
1047
1048         /*
1049          * Dive layer 2, each entry represents a large-block.
1050          *
1051          * (reuse buffer, layer1 pointer becomes invalid)
1052          */
1053         layer2_offset = layer1->phys_offset +
1054                         HAMMER_BLOCKMAP_LAYER2_OFFSET(zone_offset);
1055         layer2 = hammer_bread(hmp, layer2_offset, errorp, &buffer);
1056         if (*errorp) {
1057                 bytes = 0;
1058                 goto failed;
1059         }
1060         if (layer2->entry_crc != crc32(layer2, HAMMER_LAYER2_CRCSIZE)) {
1061                 hammer_lock_ex(&hmp->blkmap_lock);
1062                 if (layer2->entry_crc != crc32(layer2, HAMMER_LAYER2_CRCSIZE))
1063                         panic("CRC FAILED: LAYER2");
1064                 hammer_unlock(&hmp->blkmap_lock);
1065         }
1066         KKASSERT(layer2->zone == zone);
1067
1068         bytes = layer2->bytes_free;
1069
1070         if ((blockmap->next_offset ^ zone_offset) & ~HAMMER_LARGEBLOCK_MASK64)
1071                 *curp = 0;
1072         else
1073                 *curp = 1;
1074 failed:
1075         if (buffer)
1076                 hammer_rel_buffer(buffer, 0);
1077         hammer_rel_volume(root_volume, 0);
1078         if (hammer_debug_general & 0x0800) {
1079                 kprintf("hammer_blockmap_getfree: %016llx -> %d\n",
1080                         (long long)zone_offset, bytes);
1081         }
1082         return(bytes);
1083 }
1084
1085
1086 /*
1087  * Lookup a blockmap offset.
1088  */
1089 hammer_off_t
1090 hammer_blockmap_lookup(hammer_mount_t hmp, hammer_off_t zone_offset,
1091                        int *errorp)
1092 {
1093         hammer_volume_t root_volume;
1094         hammer_blockmap_t freemap;
1095         struct hammer_blockmap_layer1 *layer1;
1096         struct hammer_blockmap_layer2 *layer2;
1097         hammer_buffer_t buffer = NULL;
1098         hammer_off_t layer1_offset;
1099         hammer_off_t layer2_offset;
1100         hammer_off_t result_offset;
1101         hammer_off_t base_off;
1102         hammer_reserve_t resv;
1103         int zone;
1104
1105         /*
1106          * Calculate the zone-2 offset.
1107          */
1108         zone = HAMMER_ZONE_DECODE(zone_offset);
1109         KKASSERT(zone >= HAMMER_ZONE_BTREE_INDEX && zone < HAMMER_MAX_ZONES);
1110
1111         result_offset = (zone_offset & ~HAMMER_OFF_ZONE_MASK) |
1112                         HAMMER_ZONE_RAW_BUFFER;
1113
1114         /*
1115          * We can actually stop here, normal blockmaps are now direct-mapped
1116          * onto the freemap and so represent zone-2 addresses.
1117          */
1118         if (hammer_verify_zone == 0) {
1119                 *errorp = 0;
1120                 return(result_offset);
1121         }
1122
1123         /*
1124          * Validate the allocation zone
1125          */
1126         root_volume = hammer_get_root_volume(hmp, errorp);
1127         if (*errorp)
1128                 return(0);
1129         freemap = &hmp->blockmap[HAMMER_ZONE_FREEMAP_INDEX];
1130         KKASSERT(freemap->phys_offset != 0);
1131
1132         /*
1133          * Dive layer 1.
1134          */
1135         layer1_offset = freemap->phys_offset +
1136                         HAMMER_BLOCKMAP_LAYER1_OFFSET(zone_offset);
1137         layer1 = hammer_bread(hmp, layer1_offset, errorp, &buffer);
1138         if (*errorp)
1139                 goto failed;
1140         KKASSERT(layer1->phys_offset != HAMMER_BLOCKMAP_UNAVAIL);
1141         if (layer1->layer1_crc != crc32(layer1, HAMMER_LAYER1_CRCSIZE)) {
1142                 hammer_lock_ex(&hmp->blkmap_lock);
1143                 if (layer1->layer1_crc != crc32(layer1, HAMMER_LAYER1_CRCSIZE))
1144                         panic("CRC FAILED: LAYER1");
1145                 hammer_unlock(&hmp->blkmap_lock);
1146         }
1147
1148         /*
1149          * Dive layer 2, each entry represents a large-block.
1150          */
1151         layer2_offset = layer1->phys_offset +
1152                         HAMMER_BLOCKMAP_LAYER2_OFFSET(zone_offset);
1153         layer2 = hammer_bread(hmp, layer2_offset, errorp, &buffer);
1154
1155         if (*errorp)
1156                 goto failed;
1157         if (layer2->zone == 0) {
1158                 base_off = (zone_offset & (~HAMMER_LARGEBLOCK_MASK64 & ~HAMMER_OFF_ZONE_MASK)) | HAMMER_ZONE_RAW_BUFFER;
1159                 resv = RB_LOOKUP(hammer_res_rb_tree, &hmp->rb_resv_root,
1160                                  base_off);
1161                 KKASSERT(resv && resv->zone == zone);
1162
1163         } else if (layer2->zone != zone) {
1164                 panic("hammer_blockmap_lookup: bad zone %d/%d\n",
1165                         layer2->zone, zone);
1166         }
1167         if (layer2->entry_crc != crc32(layer2, HAMMER_LAYER2_CRCSIZE)) {
1168                 hammer_lock_ex(&hmp->blkmap_lock);
1169                 if (layer2->entry_crc != crc32(layer2, HAMMER_LAYER2_CRCSIZE))
1170                         panic("CRC FAILED: LAYER2");
1171                 hammer_unlock(&hmp->blkmap_lock);
1172         }
1173
1174 failed:
1175         if (buffer)
1176                 hammer_rel_buffer(buffer, 0);
1177         hammer_rel_volume(root_volume, 0);
1178         if (hammer_debug_general & 0x0800) {
1179                 kprintf("hammer_blockmap_lookup: %016llx -> %016llx\n",
1180                         (long long)zone_offset, (long long)result_offset);
1181         }
1182         return(result_offset);
1183 }
1184
1185
1186 /*
1187  * Check space availability
1188  */
1189 int
1190 _hammer_checkspace(hammer_mount_t hmp, int slop, int64_t *resp)
1191 {
1192         const int in_size = sizeof(struct hammer_inode_data) +
1193                             sizeof(union hammer_btree_elm);
1194         const int rec_size = (sizeof(union hammer_btree_elm) * 2);
1195         int64_t usedbytes;
1196
1197         usedbytes = hmp->rsv_inodes * in_size +
1198                     hmp->rsv_recs * rec_size +
1199                     hmp->rsv_databytes +
1200                     ((int64_t)hmp->rsv_fromdelay << HAMMER_LARGEBLOCK_BITS) +
1201                     ((int64_t)hidirtybufspace << 2) +
1202                     (slop << HAMMER_LARGEBLOCK_BITS);
1203
1204         hammer_count_extra_space_used = usedbytes;      /* debugging */
1205         if (resp)
1206                 *resp = usedbytes;
1207
1208         if (hmp->copy_stat_freebigblocks >=
1209             (usedbytes >> HAMMER_LARGEBLOCK_BITS)) {
1210                 return(0);
1211         }
1212         return (ENOSPC);
1213 }
1214