2 * Copyright (c) 2009 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> and
6 * Michael Neumann <mneumann@ntecs.de>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
18 * 3. Neither the name of The DragonFly Project nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific, prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 hammer_format_volume_header(struct hammer_mount
*hmp
,
41 struct hammer_volume_ondisk
*ondisk
,
42 const char *vol_name
, int vol_no
, int vol_count
,
43 int64_t vol_size
, int64_t boot_area_size
, int64_t mem_area_size
);
46 hammer_update_volumes_header(hammer_transaction_t trans
,
47 int64_t total_bigblocks
, int64_t empty_bigblocks
);
50 hammer_do_reblock(hammer_transaction_t trans
, hammer_inode_t ip
);
53 hammer_format_freemap(hammer_transaction_t trans
, hammer_volume_t volume
);
56 hammer_free_freemap(hammer_transaction_t trans
, hammer_volume_t volume
);
59 hammer_count_bigblocks(hammer_mount_t hmp
, hammer_volume_t volume
,
60 int64_t *total_bigblocks
, int64_t *empty_bigblocks
);
63 hammer_ioc_volume_add(hammer_transaction_t trans
, hammer_inode_t ip
,
64 struct hammer_ioc_volume
*ioc
)
66 struct hammer_mount
*hmp
= trans
->hmp
;
67 struct mount
*mp
= hmp
->mp
;
68 struct hammer_volume_ondisk ondisk
;
69 hammer_volume_t volume
;
70 int64_t total_bigblocks
, empty_bigblocks
;
74 if (mp
->mnt_flag
& MNT_RDONLY
) {
75 hmkprintf(hmp
, "Cannot add volume to read-only HAMMER filesystem\n");
79 if (hmp
->nvolumes
>= HAMMER_MAX_VOLUMES
) {
80 hmkprintf(hmp
, "Max number of HAMMER volumes exceeded\n");
84 if (hammer_lock_ex_try(&hmp
->volume_lock
) != 0) {
85 hmkprintf(hmp
, "Another volume operation is in progress!\n");
90 * Find an unused volume number.
92 while (free_vol_no
< HAMMER_MAX_VOLUMES
&&
93 HAMMER_VOLUME_NUMBER_IS_SET(hmp
, free_vol_no
)) {
96 if (free_vol_no
>= HAMMER_MAX_VOLUMES
) {
97 hmkprintf(hmp
, "Max number of HAMMER volumes exceeded\n");
102 error
= hammer_format_volume_header(
105 hmp
->rootvol
->ondisk
->vol_name
,
114 error
= hammer_install_volume(hmp
, ioc
->device_name
, NULL
, &ondisk
);
118 hammer_sync_lock_sh(trans
);
119 hammer_lock_ex(&hmp
->blkmap_lock
);
121 volume
= hammer_get_volume(hmp
, free_vol_no
, &error
);
122 KKASSERT(volume
!= NULL
&& error
== 0);
124 error
= hammer_format_freemap(trans
, volume
);
125 KKASSERT(error
== 0);
127 error
= hammer_count_bigblocks(hmp
, volume
,
128 &total_bigblocks
, &empty_bigblocks
);
129 KKASSERT(error
== 0);
130 KKASSERT(total_bigblocks
== empty_bigblocks
);
132 hammer_rel_volume(volume
, 0);
135 error
= hammer_update_volumes_header(trans
,
136 total_bigblocks
, empty_bigblocks
);
137 KKASSERT(error
== 0);
139 hammer_unlock(&hmp
->blkmap_lock
);
140 hammer_sync_unlock(trans
);
142 KKASSERT(error
== 0);
144 hammer_unlock(&hmp
->volume_lock
);
146 hmkprintf(hmp
, "An error occurred: %d\n", error
);
155 hammer_ioc_volume_del(hammer_transaction_t trans
, hammer_inode_t ip
,
156 struct hammer_ioc_volume
*ioc
)
158 struct hammer_mount
*hmp
= trans
->hmp
;
159 struct mount
*mp
= hmp
->mp
;
160 struct hammer_volume_ondisk
*ondisk
;
161 hammer_volume_t volume
;
162 int64_t total_bigblocks
, empty_bigblocks
;
166 if (mp
->mnt_flag
& MNT_RDONLY
) {
167 hmkprintf(hmp
, "Cannot del volume from read-only HAMMER filesystem\n");
171 if (hmp
->nvolumes
<= 1) {
172 hmkprintf(hmp
, "No HAMMER volume to delete\n");
176 if (hammer_lock_ex_try(&hmp
->volume_lock
) != 0) {
177 hmkprintf(hmp
, "Another volume operation is in progress!\n");
182 * find volume by volname
185 HAMMER_VOLUME_NUMBER_FOREACH(hmp
, vol_no
) {
186 volume
= hammer_get_volume(hmp
, vol_no
, &error
);
187 KKASSERT(volume
!= NULL
&& error
== 0);
188 if (strcmp(volume
->vol_name
, ioc
->device_name
) == 0) {
191 hammer_rel_volume(volume
, 0);
195 if (volume
== NULL
) {
196 hmkprintf(hmp
, "Couldn't find volume\n");
201 if (volume
== trans
->rootvol
) {
202 hmkprintf(hmp
, "Cannot remove root-volume\n");
203 hammer_rel_volume(volume
, 0);
209 * Reblock filesystem if the volume is not empty
211 hmp
->volume_to_remove
= volume
->vol_no
;
213 error
= hammer_count_bigblocks(hmp
, volume
,
214 &total_bigblocks
, &empty_bigblocks
);
215 KKASSERT(error
== 0);
217 if (total_bigblocks
== empty_bigblocks
) {
218 hmkprintf(hmp
, "%s is already empty\n", volume
->vol_name
);
220 error
= hammer_do_reblock(trans
, ip
);
222 hmp
->volume_to_remove
= -1;
223 hammer_rel_volume(volume
, 0);
231 hammer_flush_dirty(hmp
, 30);
233 hammer_sync_lock_sh(trans
);
234 hammer_lock_ex(&hmp
->blkmap_lock
);
236 error
= hammer_count_bigblocks(hmp
, volume
,
237 &total_bigblocks
, &empty_bigblocks
);
238 KKASSERT(error
== 0);
240 error
= hammer_free_freemap(trans
, volume
);
242 hmkprintf(hmp
, "Failed to free volume: ");
244 kprintf("Volume %d not empty\n", volume
->vol_no
);
246 kprintf("%d\n", error
);
247 hmp
->volume_to_remove
= -1;
248 hammer_rel_volume(volume
, 0);
251 hammer_rel_volume(volume
, 0);
256 RB_SCAN(hammer_buf_rb_tree
, &hmp
->rb_bufs_root
, NULL
,
257 hammer_unload_buffer
, volume
);
259 bzero(&ondisk
, sizeof(ondisk
));
260 error
= hammer_unload_volume(volume
, &ondisk
);
262 hmkprintf(hmp
, "Failed to unload volume\n");
267 error
= hammer_update_volumes_header(trans
,
268 -total_bigblocks
, -empty_bigblocks
);
269 KKASSERT(error
== 0);
270 hmp
->volume_to_remove
= -1;
273 hammer_unlock(&hmp
->blkmap_lock
);
274 hammer_sync_unlock(trans
);
277 hammer_unlock(&hmp
->volume_lock
);
279 hmkprintf(hmp
, "An error occurred: %d\n", error
);
285 hammer_ioc_volume_list(hammer_transaction_t trans
, hammer_inode_t ip
,
286 struct hammer_ioc_volume_list
*ioc
)
288 struct hammer_mount
*hmp
= trans
->hmp
;
289 hammer_volume_t volume
;
293 if (hammer_lock_ex_try(&hmp
->volume_lock
) != 0) {
294 hmkprintf(hmp
, "Another volume operation is in progress!\n");
298 HAMMER_VOLUME_NUMBER_FOREACH(hmp
, i
) {
299 if (cnt
>= ioc
->nvols
)
301 volume
= hammer_get_volume(hmp
, i
, &error
);
302 KKASSERT(volume
!= NULL
&& error
== 0);
304 len
= strlen(volume
->vol_name
) + 1;
305 KKASSERT(len
<= MAXPATHLEN
);
307 error
= copyout(volume
->vol_name
, ioc
->vols
[cnt
].device_name
,
309 hammer_rel_volume(volume
, 0);
317 hammer_unlock(&hmp
->volume_lock
);
323 hammer_do_reblock(hammer_transaction_t trans
, hammer_inode_t ip
)
325 struct hammer_mount
*hmp
= trans
->hmp
;
329 struct hammer_ioc_reblock reblock
;
330 bzero(&reblock
, sizeof(reblock
));
332 vol_no
= trans
->hmp
->volume_to_remove
;
333 KKASSERT(vol_no
!= -1);
335 reblock
.key_beg
.localization
= HAMMER_MIN_LOCALIZATION
;
336 reblock
.key_beg
.obj_id
= HAMMER_MIN_OBJID
;
337 reblock
.key_end
.localization
= HAMMER_MAX_LOCALIZATION
;
338 reblock
.key_end
.obj_id
= HAMMER_MAX_OBJID
;
339 reblock
.head
.flags
= HAMMER_IOC_DO_FLAGS
;
340 reblock
.free_level
= 0; /* reblock all big-blocks */
341 reblock
.allpfs
= 1; /* reblock all PFS */
342 reblock
.vol_no
= vol_no
;
344 hmkprintf(hmp
, "reblock started\n");
345 error
= hammer_ioc_reblock(trans
, ip
, &reblock
);
347 if (reblock
.head
.flags
& HAMMER_IOC_HEAD_INTR
) {
352 if (error
== EINTR
) {
353 hmkprintf(hmp
, "reblock was interrupted\n");
355 hmkprintf(hmp
, "reblock failed: %d\n", error
);
364 hammer_format_freemap(hammer_transaction_t trans
, hammer_volume_t volume
)
366 struct hammer_mount
*hmp
= trans
->hmp
;
367 struct hammer_volume_ondisk
*ondisk
;
368 hammer_blockmap_t freemap
;
369 hammer_off_t alloc_offset
;
370 hammer_off_t phys_offset
;
371 hammer_off_t block_offset
;
372 hammer_off_t layer1_offset
;
373 hammer_off_t layer2_offset
;
374 hammer_off_t vol_free_end
;
375 hammer_off_t aligned_vol_free_end
;
376 struct hammer_blockmap_layer1
*layer1
;
377 struct hammer_blockmap_layer2
*layer2
;
378 hammer_buffer_t buffer1
= NULL
;
379 hammer_buffer_t buffer2
= NULL
;
380 int64_t vol_buf_size
;
381 int64_t layer1_count
= 0;
384 KKASSERT(volume
->vol_no
!= HAMMER_ROOT_VOLNO
);
386 ondisk
= volume
->ondisk
;
387 vol_buf_size
= ondisk
->vol_buf_end
- ondisk
->vol_buf_beg
;
388 vol_free_end
= HAMMER_ENCODE_RAW_BUFFER(ondisk
->vol_no
,
389 vol_buf_size
& ~HAMMER_BIGBLOCK_MASK64
);
390 aligned_vol_free_end
= (vol_free_end
+ HAMMER_BLOCKMAP_LAYER2_MASK
)
391 & ~HAMMER_BLOCKMAP_LAYER2_MASK
;
393 freemap
= &hmp
->blockmap
[HAMMER_ZONE_FREEMAP_INDEX
];
394 alloc_offset
= HAMMER_ENCODE_RAW_BUFFER(volume
->vol_no
, 0);
396 hmkprintf(hmp
, "Initialize freemap volume %d\n", volume
->vol_no
);
398 for (phys_offset
= HAMMER_ENCODE_RAW_BUFFER(volume
->vol_no
, 0);
399 phys_offset
< aligned_vol_free_end
;
400 phys_offset
+= HAMMER_BLOCKMAP_LAYER2
) {
401 layer1_offset
= freemap
->phys_offset
+
402 HAMMER_BLOCKMAP_LAYER1_OFFSET(phys_offset
);
403 layer1
= hammer_bread(hmp
, layer1_offset
, &error
, &buffer1
);
406 if (layer1
->phys_offset
== HAMMER_BLOCKMAP_UNAVAIL
) {
407 hammer_modify_buffer(trans
, buffer1
, layer1
, sizeof(*layer1
));
408 bzero(layer1
, sizeof(*layer1
));
409 layer1
->phys_offset
= alloc_offset
;
410 layer1
->blocks_free
= 0;
411 layer1
->layer1_crc
= crc32(layer1
, HAMMER_LAYER1_CRCSIZE
);
412 hammer_modify_buffer_done(buffer1
);
413 alloc_offset
+= HAMMER_BIGBLOCK_SIZE
;
417 for (phys_offset
= HAMMER_ENCODE_RAW_BUFFER(volume
->vol_no
, 0);
418 phys_offset
< aligned_vol_free_end
;
419 phys_offset
+= HAMMER_BLOCKMAP_LAYER2
) {
421 layer1_offset
= freemap
->phys_offset
+
422 HAMMER_BLOCKMAP_LAYER1_OFFSET(phys_offset
);
423 layer1
= hammer_bread(hmp
, layer1_offset
, &error
, &buffer1
);
426 KKASSERT(layer1
->phys_offset
!= HAMMER_BLOCKMAP_UNAVAIL
);
428 for (block_offset
= 0;
429 block_offset
< HAMMER_BLOCKMAP_LAYER2
;
430 block_offset
+= HAMMER_BIGBLOCK_SIZE
) {
431 layer2_offset
= layer1
->phys_offset
+
432 HAMMER_BLOCKMAP_LAYER2_OFFSET(block_offset
);
433 layer2
= hammer_bread(hmp
, layer2_offset
, &error
, &buffer2
);
437 hammer_modify_buffer(trans
, buffer2
, layer2
, sizeof(*layer2
));
438 bzero(layer2
, sizeof(*layer2
));
440 if (phys_offset
+ block_offset
< alloc_offset
) {
441 layer2
->zone
= HAMMER_ZONE_FREEMAP_INDEX
;
442 layer2
->append_off
= HAMMER_BIGBLOCK_SIZE
;
443 layer2
->bytes_free
= 0;
444 } else if (phys_offset
+ block_offset
< vol_free_end
) {
446 layer2
->append_off
= 0;
447 layer2
->bytes_free
= HAMMER_BIGBLOCK_SIZE
;
450 layer2
->zone
= HAMMER_ZONE_UNAVAIL_INDEX
;
451 layer2
->append_off
= HAMMER_BIGBLOCK_SIZE
;
452 layer2
->bytes_free
= 0;
455 layer2
->entry_crc
= crc32(layer2
, HAMMER_LAYER2_CRCSIZE
);
456 hammer_modify_buffer_done(buffer2
);
459 hammer_modify_buffer(trans
, buffer1
, layer1
, sizeof(*layer1
));
460 layer1
->blocks_free
+= layer1_count
;
461 layer1
->layer1_crc
= crc32(layer1
, HAMMER_LAYER1_CRCSIZE
);
462 hammer_modify_buffer_done(buffer1
);
467 hammer_rel_buffer(buffer1
, 0);
469 hammer_rel_buffer(buffer2
, 0);
475 hammer_free_freemap(hammer_transaction_t trans
, hammer_volume_t volume
)
477 struct hammer_mount
*hmp
= trans
->hmp
;
478 struct hammer_volume_ondisk
*ondisk
;
479 hammer_blockmap_t freemap
;
480 hammer_off_t phys_offset
;
481 hammer_off_t block_offset
;
482 hammer_off_t layer1_offset
;
483 hammer_off_t layer2_offset
;
484 hammer_off_t vol_free_end
;
485 hammer_off_t aligned_vol_free_end
;
486 struct hammer_blockmap_layer1
*layer1
;
487 struct hammer_blockmap_layer2
*layer2
;
488 hammer_buffer_t buffer1
= NULL
;
489 hammer_buffer_t buffer2
= NULL
;
490 int64_t vol_buf_size
;
491 int64_t layer1_count
= 0;
494 KKASSERT(volume
->vol_no
!= HAMMER_ROOT_VOLNO
);
496 ondisk
= volume
->ondisk
;
497 vol_buf_size
= ondisk
->vol_buf_end
- ondisk
->vol_buf_beg
;
498 vol_free_end
= HAMMER_ENCODE_RAW_BUFFER(ondisk
->vol_no
,
499 vol_buf_size
& ~HAMMER_BIGBLOCK_MASK64
);
500 aligned_vol_free_end
= (vol_free_end
+ HAMMER_BLOCKMAP_LAYER2_MASK
)
501 & ~HAMMER_BLOCKMAP_LAYER2_MASK
;
503 freemap
= &hmp
->blockmap
[HAMMER_ZONE_FREEMAP_INDEX
];
505 hmkprintf(hmp
, "Free freemap volume %d\n", volume
->vol_no
);
507 for (phys_offset
= HAMMER_ENCODE_RAW_BUFFER(volume
->vol_no
, 0);
508 phys_offset
< aligned_vol_free_end
;
509 phys_offset
+= HAMMER_BLOCKMAP_LAYER2
) {
511 layer1_offset
= freemap
->phys_offset
+
512 HAMMER_BLOCKMAP_LAYER1_OFFSET(phys_offset
);
513 layer1
= hammer_bread(hmp
, layer1_offset
, &error
, &buffer1
);
516 KKASSERT(layer1
->phys_offset
!= HAMMER_BLOCKMAP_UNAVAIL
);
518 for (block_offset
= 0;
519 block_offset
< HAMMER_BLOCKMAP_LAYER2
;
520 block_offset
+= HAMMER_BIGBLOCK_SIZE
) {
521 layer2_offset
= layer1
->phys_offset
+
522 HAMMER_BLOCKMAP_LAYER2_OFFSET(block_offset
);
523 layer2
= hammer_bread(hmp
, layer2_offset
, &error
, &buffer2
);
527 switch (layer2
->zone
) {
528 case HAMMER_ZONE_UNDO_INDEX
:
530 case HAMMER_ZONE_FREEMAP_INDEX
:
531 case HAMMER_ZONE_UNAVAIL_INDEX
:
534 KKASSERT(phys_offset
+ block_offset
< aligned_vol_free_end
);
535 if (layer2
->append_off
== 0 &&
536 layer2
->bytes_free
== HAMMER_BIGBLOCK_SIZE
)
540 return EBUSY
; /* Not empty */
544 for (phys_offset
= HAMMER_ENCODE_RAW_BUFFER(volume
->vol_no
, 0);
545 phys_offset
< aligned_vol_free_end
;
546 phys_offset
+= HAMMER_BLOCKMAP_LAYER2
) {
548 layer1_offset
= freemap
->phys_offset
+
549 HAMMER_BLOCKMAP_LAYER1_OFFSET(phys_offset
);
550 layer1
= hammer_bread(hmp
, layer1_offset
, &error
, &buffer1
);
553 KKASSERT(layer1
->phys_offset
!= HAMMER_BLOCKMAP_UNAVAIL
);
555 hammer_modify_buffer(trans
, buffer1
, layer1
, sizeof(*layer1
));
556 bzero(layer1
, sizeof(*layer1
));
557 layer1
->phys_offset
= HAMMER_BLOCKMAP_UNAVAIL
;
558 layer1
->layer1_crc
= crc32(layer1
, HAMMER_LAYER1_CRCSIZE
);
559 hammer_modify_buffer_done(buffer1
);
564 hammer_rel_buffer(buffer1
, 0);
566 hammer_rel_buffer(buffer2
, 0);
572 hammer_format_volume_header(struct hammer_mount
*hmp
,
573 struct hammer_volume_ondisk
*ondisk
,
574 const char *vol_name
, int vol_no
, int vol_count
,
575 int64_t vol_size
, int64_t boot_area_size
, int64_t mem_area_size
)
579 KKASSERT(HAMMER_BUFSIZE
>= sizeof(struct hammer_volume_ondisk
));
581 bzero(ondisk
, sizeof(struct hammer_volume_ondisk
));
582 ksnprintf(ondisk
->vol_name
, sizeof(ondisk
->vol_name
), "%s", vol_name
);
583 ondisk
->vol_fstype
= hmp
->rootvol
->ondisk
->vol_fstype
;
584 ondisk
->vol_signature
= HAMMER_FSBUF_VOLUME
;
585 ondisk
->vol_fsid
= hmp
->fsid
;
586 ondisk
->vol_rootvol
= hmp
->rootvol
->vol_no
;
587 ondisk
->vol_no
= vol_no
;
588 ondisk
->vol_count
= vol_count
;
589 ondisk
->vol_version
= hmp
->version
;
592 * Reserve space for (future) header junk, copy volume relative
593 * offset from the existing root volume.
595 vol_alloc
= hmp
->rootvol
->ondisk
->vol_bot_beg
;
596 ondisk
->vol_bot_beg
= vol_alloc
;
597 vol_alloc
+= boot_area_size
;
598 ondisk
->vol_mem_beg
= vol_alloc
;
599 vol_alloc
+= mem_area_size
;
602 * The remaining area is the zone 2 buffer allocation area.
604 ondisk
->vol_buf_beg
= vol_alloc
;
605 ondisk
->vol_buf_end
= vol_size
& ~(int64_t)HAMMER_BUFMASK
;
607 if (ondisk
->vol_buf_end
< ondisk
->vol_buf_beg
) {
608 hmkprintf(hmp
, "volume %d %s is too small to hold the volume header\n",
609 ondisk
->vol_no
, ondisk
->vol_name
);
613 ondisk
->vol_nblocks
= (ondisk
->vol_buf_end
- ondisk
->vol_buf_beg
) /
615 ondisk
->vol_blocksize
= HAMMER_BUFSIZE
;
620 hammer_update_volumes_header(hammer_transaction_t trans
,
621 int64_t total_bigblocks
, int64_t empty_bigblocks
)
623 struct hammer_mount
*hmp
= trans
->hmp
;
624 struct mount
*mp
= hmp
->mp
;
625 hammer_volume_t volume
;
630 * Set each volume's new value of the vol_count field.
632 HAMMER_VOLUME_NUMBER_FOREACH(hmp
, vol_no
) {
633 volume
= hammer_get_volume(hmp
, vol_no
, &error
);
634 KKASSERT(volume
!= NULL
&& error
== 0);
635 hammer_modify_volume_field(trans
, volume
, vol_count
);
636 volume
->ondisk
->vol_count
= hmp
->nvolumes
;
637 hammer_modify_volume_done(volume
);
640 * Only changes to the header of the root volume
641 * are automatically flushed to disk. For all
642 * other volumes that we modify we do it here.
644 * No interlock is needed, volume buffers are not
645 * messed with by bioops.
647 if (volume
!= trans
->rootvol
&& volume
->io
.modified
) {
648 hammer_crc_set_volume(volume
->ondisk
);
649 hammer_io_flush(&volume
->io
, 0);
652 hammer_rel_volume(volume
, 0);
656 * Update the total number of big-blocks.
658 hammer_modify_volume_field(trans
, trans
->rootvol
, vol0_stat_bigblocks
);
659 trans
->rootvol
->ondisk
->vol0_stat_bigblocks
+= total_bigblocks
;
660 hammer_modify_volume_done(trans
->rootvol
);
663 * Big-block count changed so recompute the total number of blocks.
665 mp
->mnt_stat
.f_blocks
= trans
->rootvol
->ondisk
->vol0_stat_bigblocks
*
666 HAMMER_BUFFERS_PER_BIGBLOCK
;
667 mp
->mnt_vstat
.f_blocks
= trans
->rootvol
->ondisk
->vol0_stat_bigblocks
*
668 HAMMER_BUFFERS_PER_BIGBLOCK
;
671 * Update the total number of free big-blocks.
673 hammer_modify_volume_field(trans
, trans
->rootvol
,
674 vol0_stat_freebigblocks
);
675 trans
->rootvol
->ondisk
->vol0_stat_freebigblocks
+= empty_bigblocks
;
676 hammer_modify_volume_done(trans
->rootvol
);
679 * Update the copy in hmp.
681 hmp
->copy_stat_freebigblocks
=
682 trans
->rootvol
->ondisk
->vol0_stat_freebigblocks
;
688 * Count total big-blocks and empty big-blocks within the volume.
689 * The volume must be a non-root volume.
691 * Note that total big-blocks doesn't include big-blocks for layer2
692 * (and obviously layer1 and undomap). This is requirement of the
693 * volume header and this function is to retrieve that information.
696 hammer_count_bigblocks(hammer_mount_t hmp
, hammer_volume_t volume
,
697 int64_t *total_bigblocks
, int64_t *empty_bigblocks
)
699 struct hammer_volume_ondisk
*ondisk
;
700 hammer_blockmap_t freemap
;
701 hammer_off_t phys_offset
;
702 hammer_off_t block_offset
;
703 hammer_off_t layer1_offset
;
704 hammer_off_t layer2_offset
;
705 hammer_off_t vol_free_end
;
706 hammer_off_t aligned_vol_free_end
;
707 struct hammer_blockmap_layer1
*layer1
;
708 struct hammer_blockmap_layer2
*layer2
;
709 hammer_buffer_t buffer1
= NULL
;
710 hammer_buffer_t buffer2
= NULL
;
711 int64_t vol_buf_size
;
716 KKASSERT(volume
->vol_no
!= HAMMER_ROOT_VOLNO
);
718 ondisk
= volume
->ondisk
;
719 vol_buf_size
= ondisk
->vol_buf_end
- ondisk
->vol_buf_beg
;
720 vol_free_end
= HAMMER_ENCODE_RAW_BUFFER(ondisk
->vol_no
,
721 vol_buf_size
& ~HAMMER_BIGBLOCK_MASK64
);
722 aligned_vol_free_end
= (vol_free_end
+ HAMMER_BLOCKMAP_LAYER2_MASK
)
723 & ~HAMMER_BLOCKMAP_LAYER2_MASK
;
725 freemap
= &hmp
->blockmap
[HAMMER_ZONE_FREEMAP_INDEX
];
727 for (phys_offset
= HAMMER_ENCODE_RAW_BUFFER(volume
->ondisk
->vol_no
, 0);
728 phys_offset
< aligned_vol_free_end
;
729 phys_offset
+= HAMMER_BLOCKMAP_LAYER2
) {
730 layer1_offset
= freemap
->phys_offset
+
731 HAMMER_BLOCKMAP_LAYER1_OFFSET(phys_offset
);
732 layer1
= hammer_bread(hmp
, layer1_offset
, &error
, &buffer1
);
736 for (block_offset
= 0;
737 block_offset
< HAMMER_BLOCKMAP_LAYER2
;
738 block_offset
+= HAMMER_BIGBLOCK_SIZE
) {
739 layer2_offset
= layer1
->phys_offset
+
740 HAMMER_BLOCKMAP_LAYER2_OFFSET(block_offset
);
741 layer2
= hammer_bread(hmp
, layer2_offset
, &error
, &buffer2
);
745 switch (layer2
->zone
) {
746 case HAMMER_ZONE_UNDO_INDEX
:
748 case HAMMER_ZONE_FREEMAP_INDEX
:
749 case HAMMER_ZONE_UNAVAIL_INDEX
:
752 KKASSERT(phys_offset
+ block_offset
< aligned_vol_free_end
);
754 if (layer2
->append_off
== 0 &&
755 layer2
->bytes_free
== HAMMER_BIGBLOCK_SIZE
)
762 hmkprintf(hmp
, "big-blocks total=%jd empty=%jd\n", total
, empty
);
763 *total_bigblocks
= total
;
764 *empty_bigblocks
= empty
;
767 hammer_rel_buffer(buffer1
, 0);
769 hammer_rel_buffer(buffer2
, 0);