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