1 /* 2 * Copyright (c) 2009 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> and 6 * Michael Neumann <mneumann@ntecs.de> 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 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 17 * distribution. 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. 21 * 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 33 * SUCH DAMAGE. 34 * 35 */ 36 37 #include "hammer.h" 38 #include <sys/fcntl.h> 39 #include <sys/nlookup.h> 40 #include <sys/buf.h> 41 42 static int 43 hammer_setup_device(struct vnode **devvpp, const char *dev_path, int ronly); 44 45 static void 46 hammer_close_device(struct vnode **devvpp, int ronly); 47 48 static int 49 hammer_format_volume_header(struct hammer_mount *hmp, struct vnode *devvp, 50 const char *vol_name, int vol_no, int vol_count, 51 int64_t vol_size, int64_t boot_area_size, int64_t mem_area_size); 52 53 static int 54 hammer_clear_volume_header(struct vnode *devvp); 55 56 struct bigblock_stat { 57 uint64_t total_bigblocks; 58 uint64_t total_free_bigblocks; 59 uint64_t counter; 60 }; 61 62 static int 63 hammer_format_freemap(hammer_transaction_t trans, hammer_volume_t volume, 64 struct bigblock_stat *stat); 65 66 static int 67 hammer_free_freemap(hammer_transaction_t trans, hammer_volume_t volume, 68 struct bigblock_stat *stat); 69 70 int 71 hammer_ioc_volume_add(hammer_transaction_t trans, hammer_inode_t ip, 72 struct hammer_ioc_volume *ioc) 73 { 74 struct hammer_mount *hmp = trans->hmp; 75 struct mount *mp = hmp->mp; 76 hammer_volume_t volume; 77 int error; 78 79 if (mp->mnt_flag & MNT_RDONLY) { 80 kprintf("Cannot add volume to read-only HAMMER filesystem\n"); 81 return (EINVAL); 82 } 83 84 if (hmp->nvolumes + 1 >= HAMMER_MAX_VOLUMES) { 85 kprintf("Max number of HAMMER volumes exceeded\n"); 86 return (EINVAL); 87 } 88 89 if (hammer_lock_ex_try(&hmp->volume_lock) != 0) { 90 kprintf("Another volume operation is in progress!\n"); 91 return (EAGAIN); 92 } 93 94 /* 95 * Find an unused volume number. 96 */ 97 int free_vol_no = 0; 98 while (free_vol_no < HAMMER_MAX_VOLUMES && 99 RB_LOOKUP(hammer_vol_rb_tree, &hmp->rb_vols_root, free_vol_no)) { 100 ++free_vol_no; 101 } 102 if (free_vol_no >= HAMMER_MAX_VOLUMES) { 103 kprintf("Max number of HAMMER volumes exceeded\n"); 104 hammer_unlock(&hmp->volume_lock); 105 return (EINVAL); 106 } 107 108 struct vnode *devvp = NULL; 109 error = hammer_setup_device(&devvp, ioc->device_name, 0); 110 if (error) 111 goto end; 112 KKASSERT(devvp); 113 error = hammer_format_volume_header( 114 hmp, 115 devvp, 116 hmp->rootvol->ondisk->vol_name, 117 free_vol_no, 118 hmp->nvolumes+1, 119 ioc->vol_size, 120 ioc->boot_area_size, 121 ioc->mem_area_size); 122 hammer_close_device(&devvp, 0); 123 if (error) 124 goto end; 125 126 error = hammer_install_volume(hmp, ioc->device_name, NULL); 127 if (error) 128 goto end; 129 130 hammer_sync_lock_sh(trans); 131 hammer_lock_ex(&hmp->blkmap_lock); 132 133 ++hmp->nvolumes; 134 135 /* 136 * Set each volumes new value of the vol_count field. 137 */ 138 for (int vol_no = 0; vol_no < HAMMER_MAX_VOLUMES; ++vol_no) { 139 volume = hammer_get_volume(hmp, vol_no, &error); 140 if (volume == NULL && error == ENOENT) { 141 /* 142 * Skip unused volume numbers 143 */ 144 error = 0; 145 continue; 146 } 147 KKASSERT(volume != NULL && error == 0); 148 hammer_modify_volume_field(trans, volume, vol_count); 149 volume->ondisk->vol_count = hmp->nvolumes; 150 hammer_modify_volume_done(volume); 151 152 /* 153 * Only changes to the header of the root volume 154 * are automatically flushed to disk. For all 155 * other volumes that we modify we do it here. 156 * 157 * No interlock is needed, volume buffers are not 158 * messed with by bioops. 159 */ 160 if (volume != trans->rootvol && volume->io.modified) { 161 hammer_crc_set_volume(volume->ondisk); 162 hammer_io_flush(&volume->io, 0); 163 } 164 165 hammer_rel_volume(volume, 0); 166 } 167 168 volume = hammer_get_volume(hmp, free_vol_no, &error); 169 KKASSERT(volume != NULL && error == 0); 170 171 struct bigblock_stat stat; 172 error = hammer_format_freemap(trans, volume, &stat); 173 KKASSERT(error == 0); 174 175 /* 176 * Increase the total number of bigblocks 177 */ 178 hammer_modify_volume_field(trans, trans->rootvol, 179 vol0_stat_bigblocks); 180 trans->rootvol->ondisk->vol0_stat_bigblocks += stat.total_bigblocks; 181 hammer_modify_volume_done(trans->rootvol); 182 183 /* 184 * Increase the number of free bigblocks 185 * (including the copy in hmp) 186 */ 187 hammer_modify_volume_field(trans, trans->rootvol, 188 vol0_stat_freebigblocks); 189 trans->rootvol->ondisk->vol0_stat_freebigblocks += stat.total_free_bigblocks; 190 hmp->copy_stat_freebigblocks = 191 trans->rootvol->ondisk->vol0_stat_freebigblocks; 192 hammer_modify_volume_done(trans->rootvol); 193 194 hammer_rel_volume(volume, 0); 195 196 hammer_unlock(&hmp->blkmap_lock); 197 hammer_sync_unlock(trans); 198 199 KKASSERT(error == 0); 200 end: 201 hammer_unlock(&hmp->volume_lock); 202 if (error) 203 kprintf("An error occurred: %d\n", error); 204 return (error); 205 } 206 207 208 /* 209 * Remove a volume. 210 */ 211 int 212 hammer_ioc_volume_del(hammer_transaction_t trans, hammer_inode_t ip, 213 struct hammer_ioc_volume *ioc) 214 { 215 struct hammer_mount *hmp = trans->hmp; 216 struct mount *mp = hmp->mp; 217 hammer_volume_t volume; 218 int error = 0; 219 220 if (mp->mnt_flag & MNT_RDONLY) { 221 kprintf("Cannot del volume from read-only HAMMER filesystem\n"); 222 return (EINVAL); 223 } 224 225 if (hammer_lock_ex_try(&hmp->volume_lock) != 0) { 226 kprintf("Another volume operation is in progress!\n"); 227 return (EAGAIN); 228 } 229 230 volume = NULL; 231 232 /* 233 * find volume by volname 234 */ 235 for (int vol_no = 0; vol_no < HAMMER_MAX_VOLUMES; ++vol_no) { 236 volume = hammer_get_volume(hmp, vol_no, &error); 237 if (volume == NULL && error == ENOENT) { 238 /* 239 * Skip unused volume numbers 240 */ 241 error = 0; 242 continue; 243 } 244 KKASSERT(volume != NULL && error == 0); 245 if (strcmp(volume->vol_name, ioc->device_name) == 0) { 246 break; 247 } 248 hammer_rel_volume(volume, 0); 249 volume = NULL; 250 } 251 252 if (volume == NULL) { 253 kprintf("Couldn't find volume\n"); 254 error = EINVAL; 255 goto end; 256 } 257 258 if (volume == trans->rootvol) { 259 kprintf("Cannot remove root-volume\n"); 260 hammer_rel_volume(volume, 0); 261 error = EINVAL; 262 goto end; 263 } 264 265 /* 266 * 267 */ 268 269 hmp->volume_to_remove = volume->vol_no; 270 271 struct hammer_ioc_reblock reblock; 272 bzero(&reblock, sizeof(reblock)); 273 274 reblock.key_beg.localization = HAMMER_MIN_LOCALIZATION; 275 reblock.key_beg.obj_id = HAMMER_MIN_OBJID; 276 reblock.key_end.localization = HAMMER_MAX_LOCALIZATION; 277 reblock.key_end.obj_id = HAMMER_MAX_OBJID; 278 reblock.head.flags = HAMMER_IOC_DO_FLAGS; 279 reblock.free_level = 0; 280 281 error = hammer_ioc_reblock(trans, ip, &reblock); 282 283 if (reblock.head.flags & HAMMER_IOC_HEAD_INTR) { 284 error = EINTR; 285 } 286 287 if (error) { 288 if (error == EINTR) { 289 kprintf("reblock was interrupted\n"); 290 } else { 291 kprintf("reblock failed: %d\n", error); 292 } 293 hmp->volume_to_remove = -1; 294 hammer_rel_volume(volume, 0); 295 goto end; 296 } 297 298 /* 299 * Sync filesystem 300 */ 301 int count = 0; 302 while (hammer_flusher_haswork(hmp)) { 303 hammer_flusher_sync(hmp); 304 ++count; 305 if (count >= 5) { 306 if (count == 5) 307 kprintf("HAMMER: flushing."); 308 else 309 kprintf("."); 310 tsleep(&count, 0, "hmrufl", hz); 311 } 312 if (count == 30) { 313 kprintf("giving up"); 314 break; 315 } 316 } 317 kprintf("\n"); 318 319 hammer_sync_lock_sh(trans); 320 hammer_lock_ex(&hmp->blkmap_lock); 321 322 /* 323 * We use stat later to update rootvol's bigblock stats 324 */ 325 struct bigblock_stat stat; 326 error = hammer_free_freemap(trans, volume, &stat); 327 if (error) { 328 kprintf("Failed to free volume. Volume not empty!\n"); 329 hmp->volume_to_remove = -1; 330 hammer_rel_volume(volume, 0); 331 hammer_unlock(&hmp->blkmap_lock); 332 hammer_sync_unlock(trans); 333 goto end; 334 } 335 336 hmp->volume_to_remove = -1; 337 338 hammer_rel_volume(volume, 0); 339 340 /* 341 * Unload buffers 342 */ 343 RB_SCAN(hammer_buf_rb_tree, &hmp->rb_bufs_root, NULL, 344 hammer_unload_buffer, volume); 345 346 error = hammer_unload_volume(volume, NULL); 347 if (error == -1) { 348 kprintf("Failed to unload volume\n"); 349 hammer_unlock(&hmp->blkmap_lock); 350 hammer_sync_unlock(trans); 351 goto end; 352 } 353 354 volume = NULL; 355 --hmp->nvolumes; 356 357 /* 358 * Set each volume's new value of the vol_count field. 359 */ 360 for (int vol_no = 0; vol_no < HAMMER_MAX_VOLUMES; ++vol_no) { 361 volume = hammer_get_volume(hmp, vol_no, &error); 362 if (volume == NULL && error == ENOENT) { 363 /* 364 * Skip unused volume numbers 365 */ 366 error = 0; 367 continue; 368 } 369 370 KKASSERT(volume != NULL && error == 0); 371 hammer_modify_volume_field(trans, volume, vol_count); 372 volume->ondisk->vol_count = hmp->nvolumes; 373 hammer_modify_volume_done(volume); 374 375 /* 376 * Only changes to the header of the root volume 377 * are automatically flushed to disk. For all 378 * other volumes that we modify we do it here. 379 * 380 * No interlock is needed, volume buffers are not 381 * messed with by bioops. 382 */ 383 if (volume != trans->rootvol && volume->io.modified) { 384 hammer_crc_set_volume(volume->ondisk); 385 hammer_io_flush(&volume->io, 0); 386 } 387 388 hammer_rel_volume(volume, 0); 389 } 390 391 /* 392 * Update the total number of bigblocks 393 */ 394 hammer_modify_volume_field(trans, trans->rootvol, 395 vol0_stat_bigblocks); 396 trans->rootvol->ondisk->vol0_stat_bigblocks -= stat.total_bigblocks; 397 hammer_modify_volume_done(trans->rootvol); 398 399 /* 400 * Update the number of free bigblocks 401 * (including the copy in hmp) 402 */ 403 hammer_modify_volume_field(trans, trans->rootvol, 404 vol0_stat_freebigblocks); 405 trans->rootvol->ondisk->vol0_stat_freebigblocks -= stat.total_free_bigblocks; 406 hmp->copy_stat_freebigblocks = 407 trans->rootvol->ondisk->vol0_stat_freebigblocks; 408 hammer_modify_volume_done(trans->rootvol); 409 410 411 hammer_unlock(&hmp->blkmap_lock); 412 hammer_sync_unlock(trans); 413 414 /* 415 * Erase the volume header of the removed device. 416 * 417 * This is to not accidentally mount the volume again. 418 */ 419 struct vnode *devvp = NULL; 420 error = hammer_setup_device(&devvp, ioc->device_name, 0); 421 if (error) { 422 kprintf("Failed to open device: %s\n", ioc->device_name); 423 goto end; 424 } 425 KKASSERT(devvp); 426 error = hammer_clear_volume_header(devvp); 427 if (error) { 428 kprintf("Failed to clear volume header of device: %s\n", 429 ioc->device_name); 430 goto end; 431 } 432 hammer_close_device(&devvp, 0); 433 434 KKASSERT(error == 0); 435 end: 436 hammer_unlock(&hmp->volume_lock); 437 return (error); 438 } 439 440 441 int 442 hammer_ioc_volume_list(hammer_transaction_t trans, hammer_inode_t ip, 443 struct hammer_ioc_volume_list *ioc) 444 { 445 struct hammer_mount *hmp = trans->hmp; 446 hammer_volume_t volume; 447 int error = 0; 448 int i, cnt, len; 449 450 for (i = 0, cnt = 0; i < HAMMER_MAX_VOLUMES && cnt < ioc->nvols; i++) { 451 volume = hammer_get_volume(hmp, i, &error); 452 if (volume == NULL && error == ENOENT) { 453 error = 0; 454 continue; 455 } 456 KKASSERT(volume != NULL && error == 0); 457 458 len = strlen(volume->vol_name) + 1; 459 KKASSERT(len <= MAXPATHLEN); 460 461 error = copyout(volume->vol_name, ioc->vols[cnt].device_name, 462 len); 463 if (error) { 464 hammer_rel_volume(volume, 0); 465 return (error); 466 } 467 cnt++; 468 hammer_rel_volume(volume, 0); 469 } 470 ioc->nvols = cnt; 471 472 return (error); 473 } 474 475 /* 476 * Iterate over all usable L1 entries of the volume and 477 * the corresponding L2 entries. 478 */ 479 static int 480 hammer_iterate_l1l2_entries(hammer_transaction_t trans, hammer_volume_t volume, 481 int (*callback)(hammer_transaction_t, hammer_volume_t, hammer_buffer_t*, 482 struct hammer_blockmap_layer1*, struct hammer_blockmap_layer2*, 483 hammer_off_t, hammer_off_t, void*), 484 void *data) 485 { 486 struct hammer_mount *hmp = trans->hmp; 487 hammer_blockmap_t freemap = &hmp->blockmap[HAMMER_ZONE_FREEMAP_INDEX]; 488 hammer_buffer_t buffer = NULL; 489 int error = 0; 490 491 hammer_off_t phys_off; 492 hammer_off_t block_off; 493 hammer_off_t layer1_off; 494 hammer_off_t layer2_off; 495 hammer_off_t aligned_buf_end_off; 496 struct hammer_blockmap_layer1 *layer1; 497 struct hammer_blockmap_layer2 *layer2; 498 499 /* 500 * Calculate the usable size of the volume, which 501 * must be aligned at a bigblock (8 MB) boundary. 502 */ 503 aligned_buf_end_off = (HAMMER_ENCODE_RAW_BUFFER(volume->ondisk->vol_no, 504 (volume->ondisk->vol_buf_end - volume->ondisk->vol_buf_beg) 505 & ~HAMMER_LARGEBLOCK_MASK64)); 506 507 /* 508 * Iterate the volume's address space in chunks of 4 TB, where each 509 * chunk consists of at least one physically available 8 MB bigblock. 510 * 511 * For each chunk we need one L1 entry and one L2 bigblock. 512 * We use the first bigblock of each chunk as L2 block. 513 */ 514 for (phys_off = HAMMER_ENCODE_RAW_BUFFER(volume->ondisk->vol_no, 0); 515 phys_off < aligned_buf_end_off; 516 phys_off += HAMMER_BLOCKMAP_LAYER2) { 517 for (block_off = 0; 518 block_off < HAMMER_BLOCKMAP_LAYER2; 519 block_off += HAMMER_LARGEBLOCK_SIZE) { 520 layer2_off = phys_off + 521 HAMMER_BLOCKMAP_LAYER2_OFFSET(block_off); 522 layer2 = hammer_bread(hmp, layer2_off, &error, &buffer); 523 if (error) 524 goto end; 525 526 error = callback(trans, volume, &buffer, NULL, 527 layer2, phys_off, block_off, data); 528 if (error) 529 goto end; 530 } 531 532 layer1_off = freemap->phys_offset + 533 HAMMER_BLOCKMAP_LAYER1_OFFSET(phys_off); 534 layer1 = hammer_bread(hmp, layer1_off, &error, &buffer); 535 if (error) 536 goto end; 537 538 error = callback(trans, volume, &buffer, layer1, NULL, 539 phys_off, 0, data); 540 if (error) 541 goto end; 542 } 543 544 end: 545 if (buffer) { 546 hammer_rel_buffer(buffer, 0); 547 buffer = NULL; 548 } 549 550 return error; 551 } 552 553 554 static int 555 format_callback(hammer_transaction_t trans, hammer_volume_t volume, 556 hammer_buffer_t *bufferp, 557 struct hammer_blockmap_layer1 *layer1, 558 struct hammer_blockmap_layer2 *layer2, 559 hammer_off_t phys_off, 560 hammer_off_t block_off, 561 void *data) 562 { 563 struct bigblock_stat *stat = (struct bigblock_stat*)data; 564 565 /* 566 * Calculate the usable size of the volume, which must be aligned 567 * at a bigblock (8 MB) boundary. 568 */ 569 hammer_off_t aligned_buf_end_off; 570 aligned_buf_end_off = (HAMMER_ENCODE_RAW_BUFFER(volume->ondisk->vol_no, 571 (volume->ondisk->vol_buf_end - volume->ondisk->vol_buf_beg) 572 & ~HAMMER_LARGEBLOCK_MASK64)); 573 574 if (layer1) { 575 KKASSERT(layer1->phys_offset == HAMMER_BLOCKMAP_UNAVAIL); 576 577 hammer_modify_buffer(trans, *bufferp, layer1, sizeof(*layer1)); 578 bzero(layer1, sizeof(layer1)); 579 layer1->phys_offset = phys_off; 580 layer1->blocks_free = stat->counter; 581 layer1->layer1_crc = crc32(layer1, HAMMER_LAYER1_CRCSIZE); 582 hammer_modify_buffer_done(*bufferp); 583 584 stat->total_free_bigblocks += stat->counter; 585 stat->counter = 0; /* reset */ 586 } else if (layer2) { 587 hammer_modify_buffer(trans, *bufferp, layer2, sizeof(*layer2)); 588 bzero(layer2, sizeof(*layer2)); 589 590 if (block_off == 0) { 591 /* 592 * The first entry represents the L2 bigblock itself. 593 */ 594 layer2->zone = HAMMER_ZONE_FREEMAP_INDEX; 595 layer2->append_off = HAMMER_LARGEBLOCK_SIZE; 596 layer2->bytes_free = 0; 597 ++stat->total_bigblocks; 598 } else if (phys_off + block_off < aligned_buf_end_off) { 599 /* 600 * Available bigblock 601 */ 602 layer2->zone = 0; 603 layer2->append_off = 0; 604 layer2->bytes_free = HAMMER_LARGEBLOCK_SIZE; 605 ++stat->total_bigblocks; 606 ++stat->counter; 607 } else { 608 /* 609 * Bigblock outside of physically available 610 * space 611 */ 612 layer2->zone = HAMMER_ZONE_UNAVAIL_INDEX; 613 layer2->append_off = HAMMER_LARGEBLOCK_SIZE; 614 layer2->bytes_free = 0; 615 } 616 617 layer2->entry_crc = crc32(layer2, HAMMER_LAYER2_CRCSIZE); 618 hammer_modify_buffer_done(*bufferp); 619 } else { 620 KKASSERT(0); 621 } 622 623 return 0; 624 } 625 626 static int 627 hammer_format_freemap(hammer_transaction_t trans, hammer_volume_t volume, 628 struct bigblock_stat *stat) 629 { 630 stat->total_bigblocks = 0; 631 stat->total_free_bigblocks = 0; 632 stat->counter = 0; 633 return hammer_iterate_l1l2_entries(trans, volume, format_callback, stat); 634 } 635 636 static int 637 free_callback(hammer_transaction_t trans, hammer_volume_t volume __unused, 638 hammer_buffer_t *bufferp, 639 struct hammer_blockmap_layer1 *layer1, 640 struct hammer_blockmap_layer2 *layer2, 641 hammer_off_t phys_off, 642 hammer_off_t block_off __unused, 643 void *data) 644 { 645 struct bigblock_stat *stat = (struct bigblock_stat*)data; 646 647 /* 648 * No modifications to ondisk structures 649 */ 650 int testonly = (stat == NULL); 651 652 if (layer1) { 653 if (layer1->phys_offset == HAMMER_BLOCKMAP_UNAVAIL) { 654 /* 655 * This layer1 entry is already free. 656 */ 657 return 0; 658 } 659 660 KKASSERT((int)HAMMER_VOL_DECODE(layer1->phys_offset) == 661 trans->hmp->volume_to_remove); 662 663 if (testonly) 664 return 0; 665 666 /* 667 * Free the L1 entry 668 */ 669 hammer_modify_buffer(trans, *bufferp, layer1, sizeof(*layer1)); 670 bzero(layer1, sizeof(layer1)); 671 layer1->phys_offset = HAMMER_BLOCKMAP_UNAVAIL; 672 layer1->layer1_crc = crc32(layer1, HAMMER_LAYER1_CRCSIZE); 673 hammer_modify_buffer_done(*bufferp); 674 675 return 0; 676 } else if (layer2) { 677 if (layer2->zone == HAMMER_ZONE_UNAVAIL_INDEX) { 678 return 0; 679 } 680 681 if (layer2->zone == HAMMER_ZONE_FREEMAP_INDEX) { 682 if (stat) { 683 ++stat->total_bigblocks; 684 } 685 return 0; 686 } 687 688 if (layer2->append_off == 0 && 689 layer2->bytes_free == HAMMER_LARGEBLOCK_SIZE) { 690 if (stat) { 691 ++stat->total_bigblocks; 692 ++stat->total_free_bigblocks; 693 } 694 return 0; 695 } 696 697 /* 698 * We found a layer2 entry that is not empty! 699 */ 700 return EBUSY; 701 } else { 702 KKASSERT(0); 703 } 704 705 return EINVAL; 706 } 707 708 static int 709 hammer_free_freemap(hammer_transaction_t trans, hammer_volume_t volume, 710 struct bigblock_stat *stat) 711 { 712 int error; 713 714 stat->total_bigblocks = 0; 715 stat->total_free_bigblocks = 0; 716 stat->counter = 0; 717 718 error = hammer_iterate_l1l2_entries(trans, volume, free_callback, NULL); 719 if (error) 720 return error; 721 722 error = hammer_iterate_l1l2_entries(trans, volume, free_callback, stat); 723 return error; 724 } 725 726 /************************************************************************ 727 * MISC * 728 ************************************************************************ 729 */ 730 731 static int 732 hammer_setup_device(struct vnode **devvpp, const char *dev_path, int ronly) 733 { 734 int error; 735 struct nlookupdata nd; 736 737 /* 738 * Get the device vnode 739 */ 740 if (*devvpp == NULL) { 741 error = nlookup_init(&nd, dev_path, UIO_SYSSPACE, NLC_FOLLOW); 742 if (error == 0) 743 error = nlookup(&nd); 744 if (error == 0) 745 error = cache_vref(&nd.nl_nch, nd.nl_cred, devvpp); 746 nlookup_done(&nd); 747 } else { 748 error = 0; 749 } 750 751 if (error == 0) { 752 if (vn_isdisk(*devvpp, &error)) { 753 error = vfs_mountedon(*devvpp); 754 } 755 } 756 if (error == 0 && vcount(*devvpp) > 0) 757 error = EBUSY; 758 if (error == 0) { 759 vn_lock(*devvpp, LK_EXCLUSIVE | LK_RETRY); 760 error = vinvalbuf(*devvpp, V_SAVE, 0, 0); 761 if (error == 0) { 762 error = VOP_OPEN(*devvpp, 763 (ronly ? FREAD : FREAD|FWRITE), 764 FSCRED, NULL); 765 } 766 vn_unlock(*devvpp); 767 } 768 if (error && *devvpp) { 769 vrele(*devvpp); 770 *devvpp = NULL; 771 } 772 return (error); 773 } 774 775 static void 776 hammer_close_device(struct vnode **devvpp, int ronly) 777 { 778 VOP_CLOSE(*devvpp, (ronly ? FREAD : FREAD|FWRITE)); 779 if (*devvpp) { 780 vinvalbuf(*devvpp, ronly ? 0 : V_SAVE, 0, 0); 781 vrele(*devvpp); 782 *devvpp = NULL; 783 } 784 } 785 786 static int 787 hammer_format_volume_header(struct hammer_mount *hmp, struct vnode *devvp, 788 const char *vol_name, int vol_no, int vol_count, 789 int64_t vol_size, int64_t boot_area_size, int64_t mem_area_size) 790 { 791 struct buf *bp = NULL; 792 struct hammer_volume_ondisk *ondisk; 793 int error; 794 795 /* 796 * Extract the volume number from the volume header and do various 797 * sanity checks. 798 */ 799 KKASSERT(HAMMER_BUFSIZE >= sizeof(struct hammer_volume_ondisk)); 800 error = bread(devvp, 0LL, HAMMER_BUFSIZE, &bp); 801 if (error || bp->b_bcount < sizeof(struct hammer_volume_ondisk)) 802 goto late_failure; 803 804 ondisk = (struct hammer_volume_ondisk*) bp->b_data; 805 806 /* 807 * Note that we do NOT allow to use a device that contains 808 * a valid HAMMER signature. It has to be cleaned up with dd 809 * before. 810 */ 811 if (ondisk->vol_signature == HAMMER_FSBUF_VOLUME) { 812 kprintf("hammer_volume_add: Formatting of valid HAMMER volume " 813 "%s denied. Erase with dd!\n", vol_name); 814 error = EFTYPE; 815 goto late_failure; 816 } 817 818 bzero(ondisk, sizeof(struct hammer_volume_ondisk)); 819 ksnprintf(ondisk->vol_name, sizeof(ondisk->vol_name), "%s", vol_name); 820 ondisk->vol_fstype = hmp->rootvol->ondisk->vol_fstype; 821 ondisk->vol_signature = HAMMER_FSBUF_VOLUME; 822 ondisk->vol_fsid = hmp->fsid; 823 ondisk->vol_rootvol = hmp->rootvol->vol_no; 824 ondisk->vol_no = vol_no; 825 ondisk->vol_count = vol_count; 826 ondisk->vol_version = hmp->version; 827 828 /* 829 * Reserve space for (future) header junk, setup our poor-man's 830 * bigblock allocator. 831 */ 832 int64_t vol_alloc = HAMMER_BUFSIZE * 16; 833 834 ondisk->vol_bot_beg = vol_alloc; 835 vol_alloc += boot_area_size; 836 ondisk->vol_mem_beg = vol_alloc; 837 vol_alloc += mem_area_size; 838 839 /* 840 * The remaining area is the zone 2 buffer allocation area. These 841 * buffers 842 */ 843 ondisk->vol_buf_beg = vol_alloc; 844 ondisk->vol_buf_end = vol_size & ~(int64_t)HAMMER_BUFMASK; 845 846 if (ondisk->vol_buf_end < ondisk->vol_buf_beg) { 847 kprintf("volume %d %s is too small to hold the volume header", 848 ondisk->vol_no, ondisk->vol_name); 849 error = EFTYPE; 850 goto late_failure; 851 } 852 853 ondisk->vol_nblocks = (ondisk->vol_buf_end - ondisk->vol_buf_beg) / 854 HAMMER_BUFSIZE; 855 ondisk->vol_blocksize = HAMMER_BUFSIZE; 856 857 /* 858 * Write volume header to disk 859 */ 860 error = bwrite(bp); 861 bp = NULL; 862 863 late_failure: 864 if (bp) 865 brelse(bp); 866 return (error); 867 } 868 869 /* 870 * Invalidates the volume header. Used by volume-del. 871 */ 872 static int 873 hammer_clear_volume_header(struct vnode *devvp) 874 { 875 struct buf *bp = NULL; 876 struct hammer_volume_ondisk *ondisk; 877 int error; 878 879 KKASSERT(HAMMER_BUFSIZE >= sizeof(struct hammer_volume_ondisk)); 880 error = bread(devvp, 0LL, HAMMER_BUFSIZE, &bp); 881 if (error || bp->b_bcount < sizeof(struct hammer_volume_ondisk)) 882 goto late_failure; 883 884 ondisk = (struct hammer_volume_ondisk*) bp->b_data; 885 bzero(ondisk, sizeof(struct hammer_volume_ondisk)); 886 887 error = bwrite(bp); 888 bp = NULL; 889 890 late_failure: 891 if (bp) 892 brelse(bp); 893 return (error); 894 } 895