2 * Copyright (c) 2008 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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
34 * $DragonFly: src/sys/vfs/hammer/hammer_blockmap.c,v 1.27 2008/07/31 22:30:33 dillon Exp $
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
);
49 * Reserved big-blocks red-black tree support
51 RB_GENERATE2(hammer_res_rb_tree
, hammer_reserve
, rb_node
,
52 hammer_res_rb_compare
, hammer_off_t
, zone_offset
);
55 hammer_res_rb_compare(hammer_reserve_t res1
, hammer_reserve_t res2
)
57 if (res1
->zone_offset
< res2
->zone_offset
)
59 if (res1
->zone_offset
> res2
->zone_offset
)
65 * Allocate bytes from a zone
68 hammer_blockmap_alloc(hammer_transaction_t trans
, int zone
, int bytes
,
69 hammer_off_t hint
, int *errorp
)
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
;
88 int offset
; /* offset within big-block */
94 * Deal with alignment and buffer-boundary issues.
96 * Be careful, certain primary alignments are used below to allocate
97 * new blockmap blocks.
99 bytes
= (bytes
+ 15) & ~15;
100 KKASSERT(bytes
> 0 && bytes
<= HAMMER_XBUFSIZE
);
101 KKASSERT(zone
>= HAMMER_ZONE_BTREE_INDEX
&& zone
< HAMMER_MAX_ZONES
);
106 root_volume
= trans
->rootvol
;
108 blockmap
= &hmp
->blockmap
[zone
];
109 freemap
= &hmp
->blockmap
[HAMMER_ZONE_FREEMAP_INDEX
];
110 KKASSERT(HAMMER_ZONE_DECODE(blockmap
->next_offset
) == zone
);
113 * Use the hint if we have one.
115 if (hint
&& HAMMER_ZONE_DECODE(hint
) == zone
) {
116 next_offset
= (hint
+ 15) & ~(hammer_off_t
)15;
119 next_offset
= blockmap
->next_offset
;
125 * use_hint is turned off if we leave the hinted big-block.
127 if (use_hint
&& ((next_offset
^ hint
) & ~HAMMER_HINTBLOCK_MASK64
)) {
128 next_offset
= blockmap
->next_offset
;
135 if (next_offset
== HAMMER_ZONE_ENCODE(zone
+ 1, 0)) {
141 next_offset
= HAMMER_ZONE_ENCODE(zone
, 0);
145 * The allocation request may not cross a buffer boundary. Special
146 * large allocations must not cross a large-block boundary.
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
;
155 if ((next_offset
^ tmp_offset
) & ~HAMMER_LARGEBLOCK_MASK64
) {
156 next_offset
= tmp_offset
& ~HAMMER_LARGEBLOCK_MASK64
;
160 offset
= (int)next_offset
& HAMMER_LARGEBLOCK_MASK
;
165 layer1_offset
= freemap
->phys_offset
+
166 HAMMER_BLOCKMAP_LAYER1_OFFSET(next_offset
);
167 layer1
= hammer_bread(hmp
, layer1_offset
, errorp
, &buffer1
);
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
);
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.
188 if (offset
== 0 && layer1
->blocks_free
== 0) {
189 next_offset
= (next_offset
+ HAMMER_BLOCKMAP_LAYER2
) &
190 ~HAMMER_BLOCKMAP_LAYER2_MASK
;
193 KKASSERT(layer1
->phys_offset
!= HAMMER_BLOCKMAP_UNAVAIL
);
196 * Dive layer 2, each entry represents a large-block.
198 layer2_offset
= layer1
->phys_offset
+
199 HAMMER_BLOCKMAP_LAYER2_OFFSET(next_offset
);
200 layer2
= hammer_bread(hmp
, layer2_offset
, errorp
, &buffer2
);
207 * Check CRC. This can race another thread holding the lock
208 * and in the middle of modifying layer2.
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
);
218 * Skip the layer if the zone is owned by someone other then us.
220 if (layer2
->zone
&& layer2
->zone
!= zone
) {
221 next_offset
+= (HAMMER_LARGEBLOCK_SIZE
- offset
);
224 if (offset
< layer2
->append_off
) {
225 next_offset
+= layer2
->append_off
- offset
;
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.
234 * We do this for B-Tree and meta-data allocations to provide
235 * localization for updates.
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
)
242 if (offset
>= HAMMER_LARGEBLOCK_OVERFILL
) {
243 next_offset
+= (HAMMER_LARGEBLOCK_SIZE
- offset
);
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.
253 hammer_lock_ex(&hmp
->blkmap_lock
);
255 if (layer2
->zone
&& layer2
->zone
!= zone
) {
256 hammer_unlock(&hmp
->blkmap_lock
);
257 next_offset
+= (HAMMER_LARGEBLOCK_SIZE
- offset
);
260 if (offset
< layer2
->append_off
) {
261 hammer_unlock(&hmp
->blkmap_lock
);
262 next_offset
+= layer2
->append_off
- offset
;
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.
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
);
275 if (resv
->zone
!= zone
) {
276 hammer_unlock(&hmp
->blkmap_lock
);
277 next_offset
= (next_offset
+ HAMMER_LARGEBLOCK_SIZE
) &
278 ~HAMMER_LARGEBLOCK_MASK64
;
281 if (offset
< resv
->append_off
) {
282 hammer_unlock(&hmp
->blkmap_lock
);
283 next_offset
+= resv
->append_off
- offset
;
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.
294 if (layer2
->zone
== 0) {
296 * Assign the bigblock to our zone
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
));
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
);
316 hammer_modify_buffer(trans
, buffer2
,
317 layer2
, sizeof(*layer2
));
319 KKASSERT(layer2
->zone
== zone
);
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);
329 * We hold the blockmap lock and should be the only ones
330 * capable of modifying resv->append_off. Track the allocation
333 KKASSERT(bytes
!= 0);
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
);
342 * If we are allocating from the base of a new buffer we can avoid
343 * a disk read by calling hammer_bnew().
345 if ((next_offset
& HAMMER_BUFMASK
) == 0) {
346 hammer_bnew_ext(trans
->hmp
, next_offset
, bytes
,
349 result_offset
= next_offset
;
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
357 hammer_modify_volume(NULL
, root_volume
, NULL
, 0);
358 blockmap
->next_offset
= next_offset
+ bytes
;
359 hammer_modify_volume_done(root_volume
);
361 hammer_unlock(&hmp
->blkmap_lock
);
368 hammer_rel_buffer(buffer1
, 0);
370 hammer_rel_buffer(buffer2
, 0);
372 hammer_rel_buffer(buffer3
, 0);
374 return(result_offset
);
378 * Frontend function - Reserve bytes in a zone.
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
384 * The backend later finalizes the reservation with hammer_blockmap_finalize()
385 * upon committing the related record.
388 hammer_blockmap_reserve(hammer_mount_t hmp
, int zone
, int bytes
,
389 hammer_off_t
*zone_offp
, int *errorp
)
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
;
412 KKASSERT(zone
>= HAMMER_ZONE_BTREE_INDEX
&& zone
< HAMMER_MAX_ZONES
);
413 root_volume
= hammer_get_root_volume(hmp
, errorp
);
416 blockmap
= &hmp
->blockmap
[zone
];
417 freemap
= &hmp
->blockmap
[HAMMER_ZONE_FREEMAP_INDEX
];
418 KKASSERT(HAMMER_ZONE_DECODE(blockmap
->next_offset
) == zone
);
421 * Deal with alignment and buffer-boundary issues.
423 * Be careful, certain primary alignments are used below to allocate
424 * new blockmap blocks.
426 bytes
= (bytes
+ 15) & ~15;
427 KKASSERT(bytes
> 0 && bytes
<= HAMMER_XBUFSIZE
);
429 next_offset
= blockmap
->next_offset
;
435 if (next_offset
== HAMMER_ZONE_ENCODE(zone
+ 1, 0)) {
440 next_offset
= HAMMER_ZONE_ENCODE(zone
, 0);
444 * The allocation request may not cross a buffer boundary. Special
445 * large allocations must not cross a large-block boundary.
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
;
454 if ((next_offset
^ tmp_offset
) & ~HAMMER_LARGEBLOCK_MASK64
) {
455 next_offset
= tmp_offset
& ~HAMMER_LARGEBLOCK_MASK64
;
459 offset
= (int)next_offset
& HAMMER_LARGEBLOCK_MASK
;
464 layer1_offset
= freemap
->phys_offset
+
465 HAMMER_BLOCKMAP_LAYER1_OFFSET(next_offset
);
466 layer1
= hammer_bread(hmp
, layer1_offset
, errorp
, &buffer1
);
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
);
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.
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
;
491 KKASSERT(layer1
->phys_offset
!= HAMMER_BLOCKMAP_UNAVAIL
);
494 * Dive layer 2, each entry represents a large-block.
496 layer2_offset
= layer1
->phys_offset
+
497 HAMMER_BLOCKMAP_LAYER2_OFFSET(next_offset
);
498 layer2
= hammer_bread(hmp
, layer2_offset
, errorp
, &buffer2
);
503 * Check CRC if not allocating into uninitialized space (which we
504 * aren't when reserving space).
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
);
514 * Skip the layer if the zone is owned by someone other then us.
516 if (layer2
->zone
&& layer2
->zone
!= zone
) {
517 next_offset
+= (HAMMER_LARGEBLOCK_SIZE
- offset
);
520 if (offset
< layer2
->append_off
) {
521 next_offset
+= layer2
->append_off
- offset
;
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.
529 hammer_lock_ex(&hmp
->blkmap_lock
);
531 if (layer2
->zone
&& layer2
->zone
!= zone
) {
532 hammer_unlock(&hmp
->blkmap_lock
);
533 next_offset
+= (HAMMER_LARGEBLOCK_SIZE
- offset
);
536 if (offset
< layer2
->append_off
) {
537 hammer_unlock(&hmp
->blkmap_lock
);
538 next_offset
+= layer2
->append_off
- offset
;
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.
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
);
551 if (resv
->zone
!= zone
) {
552 hammer_unlock(&hmp
->blkmap_lock
);
553 next_offset
= (next_offset
+ HAMMER_LARGEBLOCK_SIZE
) &
554 ~HAMMER_LARGEBLOCK_MASK64
;
557 if (offset
< resv
->append_off
) {
558 hammer_unlock(&hmp
->blkmap_lock
);
559 next_offset
+= resv
->append_off
- offset
;
565 resx
= kmalloc(sizeof(*resv
), hmp
->m_misc
,
566 M_WAITOK
| M_ZERO
| M_USE_RESERVE
);
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
);
575 ++hammer_count_reservations
;
577 resv
->append_off
= offset
+ bytes
;
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.
583 * If we are reserving a whole buffer (or more), the caller will
584 * probably use a direct read, so do nothing.
586 if (bytes
< HAMMER_BUFSIZE
&& (next_offset
& HAMMER_BUFMASK
) == 0) {
587 hammer_bnew(hmp
, next_offset
, errorp
, &buffer3
);
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.
595 blockmap
->next_offset
= next_offset
+ bytes
;
596 hammer_unlock(&hmp
->blkmap_lock
);
600 hammer_rel_buffer(buffer1
, 0);
602 hammer_rel_buffer(buffer2
, 0);
604 hammer_rel_buffer(buffer3
, 0);
605 hammer_rel_volume(root_volume
, 0);
606 *zone_offp
= next_offset
;
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.
618 hammer_blockmap_reserve_complete(hammer_mount_t hmp
, hammer_reserve_t resv
)
620 hammer_off_t base_offset
;
623 KKASSERT(resv
->refs
> 0);
624 KKASSERT((resv
->zone_offset
& HAMMER_OFF_ZONE_MASK
) ==
625 HAMMER_ZONE_RAW_BUFFER
);
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.
632 * If we are unable to clean out all related HAMMER buffers we
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
,
641 HAMMER_LARGEBLOCK_SIZE
,
644 hammer_reserve_setdelay(hmp
, resv
);
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
;
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.
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.
665 hammer_reserve_setdelay_offset(hammer_mount_t hmp
, hammer_off_t base_offset
,
666 int zone
, struct hammer_blockmap_layer2
*layer2
)
668 hammer_reserve_t resv
;
671 * Allocate the reservation if necessary.
673 * NOTE: need lock in future around resv lookup/allocation and
674 * the setdelay call, currently refs is not bumped until the call.
677 resv
= RB_LOOKUP(hammer_res_rb_tree
, &hmp
->rb_resv_root
, base_offset
);
679 resv
= kmalloc(sizeof(*resv
), hmp
->m_misc
,
680 M_WAITOK
| M_ZERO
| M_USE_RESERVE
);
682 resv
->zone_offset
= base_offset
;
684 resv
->append_off
= HAMMER_LARGEBLOCK_SIZE
;
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
);
692 ++hammer_count_reservations
;
694 if (layer2
->bytes_free
== HAMMER_LARGEBLOCK_SIZE
)
695 resv
->flags
|= HAMMER_RESF_LAYER2FREE
;
697 hammer_reserve_setdelay(hmp
, resv
);
701 * Enter the reservation on the on-delay list, or move it if it
702 * is already on the list.
705 hammer_reserve_setdelay(hammer_mount_t hmp
, hammer_reserve_t resv
)
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
);
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
);
721 hammer_reserve_clrdelay(hammer_mount_t hmp
, hammer_reserve_t resv
)
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
);
731 * Backend function - free (offset, bytes) in a zone.
736 hammer_blockmap_free(hammer_transaction_t trans
,
737 hammer_off_t zone_offset
, int bytes
)
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
;
760 bytes
= (bytes
+ 15) & ~15;
761 KKASSERT(bytes
<= HAMMER_XBUFSIZE
);
762 KKASSERT(((zone_offset
^ (zone_offset
+ (bytes
- 1))) &
763 ~HAMMER_LARGEBLOCK_MASK64
) == 0);
766 * Basic zone validation & locking
768 zone
= HAMMER_ZONE_DECODE(zone_offset
);
769 KKASSERT(zone
>= HAMMER_ZONE_BTREE_INDEX
&& zone
< HAMMER_MAX_ZONES
);
770 root_volume
= trans
->rootvol
;
773 blockmap
= &hmp
->blockmap
[zone
];
774 freemap
= &hmp
->blockmap
[HAMMER_ZONE_FREEMAP_INDEX
];
779 layer1_offset
= freemap
->phys_offset
+
780 HAMMER_BLOCKMAP_LAYER1_OFFSET(zone_offset
);
781 layer1
= hammer_bread(hmp
, layer1_offset
, &error
, &buffer1
);
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
);
794 * Dive layer 2, each entry represents a large-block.
796 layer2_offset
= layer1
->phys_offset
+
797 HAMMER_BLOCKMAP_LAYER2_OFFSET(zone_offset
);
798 layer2
= hammer_bread(hmp
, layer2_offset
, &error
, &buffer2
);
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
);
808 hammer_lock_ex(&hmp
->blkmap_lock
);
810 hammer_modify_buffer(trans
, buffer2
, layer2
, sizeof(*layer2
));
813 * Free space previously allocated via blockmap_alloc().
815 KKASSERT(layer2
->zone
== zone
);
816 layer2
->bytes_free
+= bytes
;
817 KKASSERT(layer2
->bytes_free
<= HAMMER_LARGEBLOCK_SIZE
);
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.
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.
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
836 if (layer2
->bytes_free
== HAMMER_LARGEBLOCK_SIZE
) {
837 base_off
= (zone_offset
& (~HAMMER_LARGEBLOCK_MASK64
& ~HAMMER_OFF_ZONE_MASK
)) | HAMMER_ZONE_RAW_BUFFER
;
839 hammer_reserve_setdelay_offset(hmp
, base_off
, zone
, layer2
);
840 if (layer2
->bytes_free
== HAMMER_LARGEBLOCK_SIZE
) {
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
,
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
);
858 layer2
->entry_crc
= crc32(layer2
, HAMMER_LAYER2_CRCSIZE
);
859 hammer_modify_buffer_done(buffer2
);
860 hammer_unlock(&hmp
->blkmap_lock
);
864 hammer_rel_buffer(buffer1
, 0);
866 hammer_rel_buffer(buffer2
, 0);
870 * Backend function - finalize (offset, bytes) in a zone.
872 * Allocate space that was previously reserved by the frontend.
875 hammer_blockmap_finalize(hammer_transaction_t trans
,
876 hammer_reserve_t resv
,
877 hammer_off_t zone_offset
, int bytes
)
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
;
900 bytes
= (bytes
+ 15) & ~15;
901 KKASSERT(bytes
<= HAMMER_XBUFSIZE
);
904 * Basic zone validation & locking
906 zone
= HAMMER_ZONE_DECODE(zone_offset
);
907 KKASSERT(zone
>= HAMMER_ZONE_BTREE_INDEX
&& zone
< HAMMER_MAX_ZONES
);
908 root_volume
= trans
->rootvol
;
911 blockmap
= &hmp
->blockmap
[zone
];
912 freemap
= &hmp
->blockmap
[HAMMER_ZONE_FREEMAP_INDEX
];
917 layer1_offset
= freemap
->phys_offset
+
918 HAMMER_BLOCKMAP_LAYER1_OFFSET(zone_offset
);
919 layer1
= hammer_bread(hmp
, layer1_offset
, &error
, &buffer1
);
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
);
932 * Dive layer 2, each entry represents a large-block.
934 layer2_offset
= layer1
->phys_offset
+
935 HAMMER_BLOCKMAP_LAYER2_OFFSET(zone_offset
);
936 layer2
= hammer_bread(hmp
, layer2_offset
, &error
, &buffer2
);
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
);
946 hammer_lock_ex(&hmp
->blkmap_lock
);
948 hammer_modify_buffer(trans
, buffer2
, layer2
, sizeof(*layer2
));
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.
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
);
963 KKASSERT(layer2
->bytes_free
== HAMMER_LARGEBLOCK_SIZE
);
964 KKASSERT(layer2
->append_off
== 0);
965 hammer_modify_volume_field(trans
,
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
);
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
;
979 resv
->flags
&= ~HAMMER_RESF_LAYER2FREE
;
982 * Finalizations can occur out of order, or combined with allocations.
983 * append_off must be set to the highest allocated offset.
985 offset
= ((int)zone_offset
& HAMMER_LARGEBLOCK_MASK
) + bytes
;
986 if (layer2
->append_off
< offset
)
987 layer2
->append_off
= offset
;
989 layer2
->entry_crc
= crc32(layer2
, HAMMER_LAYER2_CRCSIZE
);
990 hammer_modify_buffer_done(buffer2
);
991 hammer_unlock(&hmp
->blkmap_lock
);
995 hammer_rel_buffer(buffer1
, 0);
997 hammer_rel_buffer(buffer2
, 0);
1002 * Return the number of free bytes in the big-block containing the
1003 * specified blockmap offset.
1006 hammer_blockmap_getfree(hammer_mount_t hmp
, hammer_off_t zone_offset
,
1007 int *curp
, int *errorp
)
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
;
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
);
1027 blockmap
= &hmp
->blockmap
[zone
];
1028 freemap
= &hmp
->blockmap
[HAMMER_ZONE_FREEMAP_INDEX
];
1033 layer1_offset
= freemap
->phys_offset
+
1034 HAMMER_BLOCKMAP_LAYER1_OFFSET(zone_offset
);
1035 layer1
= hammer_bread(hmp
, layer1_offset
, errorp
, &buffer
);
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
);
1049 * Dive layer 2, each entry represents a large-block.
1051 * (reuse buffer, layer1 pointer becomes invalid)
1053 layer2_offset
= layer1
->phys_offset
+
1054 HAMMER_BLOCKMAP_LAYER2_OFFSET(zone_offset
);
1055 layer2
= hammer_bread(hmp
, layer2_offset
, errorp
, &buffer
);
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
);
1066 KKASSERT(layer2
->zone
== zone
);
1068 bytes
= layer2
->bytes_free
;
1070 if ((blockmap
->next_offset
^ zone_offset
) & ~HAMMER_LARGEBLOCK_MASK64
)
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
);
1087 * Lookup a blockmap offset.
1090 hammer_blockmap_lookup(hammer_mount_t hmp
, hammer_off_t zone_offset
,
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
;
1106 * Calculate the zone-2 offset.
1108 zone
= HAMMER_ZONE_DECODE(zone_offset
);
1109 KKASSERT(zone
>= HAMMER_ZONE_BTREE_INDEX
&& zone
< HAMMER_MAX_ZONES
);
1111 result_offset
= (zone_offset
& ~HAMMER_OFF_ZONE_MASK
) |
1112 HAMMER_ZONE_RAW_BUFFER
;
1115 * We can actually stop here, normal blockmaps are now direct-mapped
1116 * onto the freemap and so represent zone-2 addresses.
1118 if (hammer_verify_zone
== 0) {
1120 return(result_offset
);
1124 * Validate the allocation zone
1126 root_volume
= hammer_get_root_volume(hmp
, errorp
);
1129 freemap
= &hmp
->blockmap
[HAMMER_ZONE_FREEMAP_INDEX
];
1130 KKASSERT(freemap
->phys_offset
!= 0);
1135 layer1_offset
= freemap
->phys_offset
+
1136 HAMMER_BLOCKMAP_LAYER1_OFFSET(zone_offset
);
1137 layer1
= hammer_bread(hmp
, layer1_offset
, errorp
, &buffer
);
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
);
1149 * Dive layer 2, each entry represents a large-block.
1151 layer2_offset
= layer1
->phys_offset
+
1152 HAMMER_BLOCKMAP_LAYER2_OFFSET(zone_offset
);
1153 layer2
= hammer_bread(hmp
, layer2_offset
, errorp
, &buffer
);
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
,
1161 KKASSERT(resv
&& resv
->zone
== zone
);
1163 } else if (layer2
->zone
!= zone
) {
1164 panic("hammer_blockmap_lookup: bad zone %d/%d\n",
1165 layer2
->zone
, zone
);
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
);
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
);
1182 return(result_offset
);
1187 * Check space availability
1190 hammer_checkspace(hammer_mount_t hmp
, int slop
)
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);
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
);
1204 hammer_count_extra_space_used
= usedbytes
; /* debugging */
1206 if (hmp
->copy_stat_freebigblocks
>=
1207 (usedbytes
>> HAMMER_LARGEBLOCK_BITS
)) {