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