1 /* 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 2022 Tomohiro Kusumi <tkusumi@netbsd.org> 5 * Copyright (c) 2011-2022 The DragonFly Project. All rights reserved. 6 * 7 * This code is derived from software contributed to The DragonFly Project 8 * by Matthew Dillon <dillon@dragonflybsd.org> 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in 18 * the documentation and/or other materials provided with the 19 * distribution. 20 * 3. Neither the name of The DragonFly Project nor the names of its 21 * contributors may be used to endorse or promote products derived 22 * from this software without specific, prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 27 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 28 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 29 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 32 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 33 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 34 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 */ 37 /* 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/kernel.h> 41 #include <sys/queue.h> 42 #include <sys/nlookup.h> 43 #include <sys/vnode.h> 44 #include <sys/mount.h> 45 #include <sys/buf.h> 46 #include <sys/uuid.h> 47 #include <sys/objcache.h> 48 #include <sys/lock.h> 49 */ 50 #include <sys/diskslice.h> 51 52 #include "hammer2.h" 53 #include "makefs.h" 54 55 #define hprintf(X, ...) kprintf("hammer2_ondisk: " X, ## __VA_ARGS__) 56 57 #if 0 58 static int 59 hammer2_lookup_device(const char *path, int rootmount, struct m_vnode **devvp) 60 { 61 struct m_vnode *vp = NULL; 62 struct nlookupdata nd; 63 int error = 0; 64 65 KKASSERT(path); 66 KKASSERT(*path != '\0'); 67 68 if (rootmount) { 69 error = bdevvp(kgetdiskbyname(path), &vp); 70 if (error) 71 hprintf("cannot find %s %d\n", path, error); 72 } else { 73 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW); 74 if (error == 0) 75 error = nlookup(&nd); 76 if (error == 0) 77 error = cache_vref(&nd.nl_nch, nd.nl_cred, &vp); 78 if (error) 79 hprintf("failed to nlookup %s %d\n", path, error); 80 nlookup_done(&nd); 81 } 82 83 if (error == 0) { 84 KKASSERT(vp); 85 if (!vn_isdisk(vp, &error)) { 86 KKASSERT(error); 87 hprintf("%s not a block device %d\n", path, error); 88 } 89 } 90 91 if (error && vp) { 92 vrele(vp); 93 vp = NULL; 94 } 95 96 *devvp = vp; 97 return error; 98 } 99 #endif 100 101 int 102 hammer2_open_devvp(const hammer2_devvp_list_t *devvpl, int ronly) 103 { 104 #if 0 105 hammer2_devvp_t *e; 106 struct m_vnode *devvp; 107 const char *path; 108 int count, error; 109 110 TAILQ_FOREACH(e, devvpl, entry) { 111 devvp = e->devvp; 112 path = e->path; 113 KKASSERT(devvp); 114 count = vcount(devvp); 115 if (count > 0) { 116 hprintf("%s already has %d references\n", path, count); 117 return EBUSY; 118 } 119 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 120 error = vinvalbuf(devvp, V_SAVE, 0, 0); 121 if (error == 0) { 122 KKASSERT(!e->open); 123 error = VOP_OPEN(devvp, (ronly ? FREAD : FREAD|FWRITE), 124 FSCRED, NULL); 125 if (error == 0) 126 e->open = 1; 127 else 128 hprintf("failed to open %s %d\n", path, error); 129 } 130 vn_unlock(devvp); 131 if (error) 132 return error; 133 KKASSERT(e->open); 134 } 135 #endif 136 137 return 0; 138 } 139 140 int 141 hammer2_close_devvp(const hammer2_devvp_list_t *devvpl, int ronly) 142 { 143 #if 0 144 hammer2_devvp_t *e; 145 struct m_vnode *devvp; 146 147 TAILQ_FOREACH(e, devvpl, entry) { 148 devvp = e->devvp; 149 KKASSERT(devvp); 150 if (e->open) { 151 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 152 vinvalbuf(devvp, (ronly ? 0 : V_SAVE), 0, 0); 153 VOP_CLOSE(devvp, (ronly ? FREAD : FREAD|FWRITE), NULL); 154 vn_unlock(devvp); 155 e->open = 0; 156 } 157 } 158 #endif 159 160 return 0; 161 } 162 163 int 164 hammer2_init_devvp(struct m_vnode *devvp, hammer2_devvp_list_t *devvpl) 165 { 166 hammer2_devvp_t *e; 167 int error = 0; 168 169 while (1) { 170 KKASSERT(devvp); 171 e = kmalloc(sizeof(*e), M_HAMMER2, M_WAITOK | M_ZERO); 172 e->devvp = devvp; 173 TAILQ_INSERT_TAIL(devvpl, e, entry); 174 break; 175 } 176 177 return error; 178 } 179 180 void 181 hammer2_cleanup_devvp(hammer2_devvp_list_t *devvpl) 182 { 183 hammer2_devvp_t *e; 184 185 while (!TAILQ_EMPTY(devvpl)) { 186 e = TAILQ_FIRST(devvpl); 187 TAILQ_REMOVE(devvpl, e, entry); 188 /* devvp */ 189 KKASSERT(e->devvp); 190 /* 191 if (e->devvp->v_rdev) 192 e->devvp->v_rdev->si_mountpoint = NULL; 193 */ 194 vrele(e->devvp); 195 e->devvp = NULL; 196 /* path */ 197 /* 198 KKASSERT(e->path); 199 kfree(e->path, M_HAMMER2); 200 */ 201 e->path = NULL; 202 kfree(e, M_HAMMER2); 203 } 204 } 205 206 static int 207 hammer2_verify_volumes_common(const hammer2_vfsvolume_t *volumes, 208 const hammer2_volume_data_t *rootvoldata) 209 { 210 const hammer2_vfsvolume_t *vol; 211 struct partinfo part; 212 struct stat st; 213 const char *path; 214 char *buf = NULL; 215 int i; 216 uuid_t uuid; 217 218 /* check volume header */ 219 if (rootvoldata->volu_id != HAMMER2_ROOT_VOLUME) { 220 hprintf("volume id %d must be %d\n", rootvoldata->volu_id, 221 HAMMER2_ROOT_VOLUME); 222 return EINVAL; 223 } 224 uuid = rootvoldata->fstype; 225 hammer2_uuid_to_str(&uuid, &buf); 226 if (strcmp(buf, HAMMER2_UUID_STRING)) { 227 hprintf("volume fstype uuid %s must be %s\n", buf, 228 HAMMER2_UUID_STRING); 229 return EINVAL; 230 } 231 232 for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) { 233 vol = &volumes[i]; 234 if (vol->id == -1) 235 continue; 236 path = vol->dev->path; 237 /* check volume fields are initialized */ 238 if (!vol->dev->devvp) { 239 hprintf("%s has NULL devvp\n", path); 240 return EINVAL; 241 } 242 if (vol->offset == (hammer2_off_t)-1) { 243 hprintf("%s has bad offset 0x%016jx\n", path, 244 (intmax_t)vol->offset); 245 return EINVAL; 246 } 247 if (vol->size == (hammer2_off_t)-1) { 248 hprintf("%s has bad size 0x%016jx\n", path, 249 (intmax_t)vol->size); 250 return EINVAL; 251 } 252 /* check volume size vs block device size */ 253 /* 254 if (VOP_IOCTL(vol->dev->devvp, DIOCGPART, (void*)&part, 0, 255 curthread->td_ucred , NULL) == 0) { 256 */ 257 assert(vol->dev->devvp->fs); 258 if (ioctl(vol->dev->devvp->fs->fd, DIOCGPART, &part) == 0) { 259 assert(part.media_blksize <= HAMMER2_PBUFSIZE); 260 assert(HAMMER2_PBUFSIZE % part.media_blksize == 0); 261 if (vol->size > part.media_size) { 262 hprintf("%s's size 0x%016jx exceeds " 263 "device size 0x%016jx\n", 264 path, (intmax_t)vol->size, 265 part.media_size); 266 return EINVAL; 267 } 268 } else if (fstat(vol->dev->devvp->fs->fd, &st) == 0) { 269 if (vol->size > st.st_size) { 270 hprintf("%s's size 0x%016jx exceeds " 271 "file size 0x%016jx\n", 272 path, (intmax_t)vol->size, 273 st.st_size); 274 return EINVAL; 275 } 276 } else { 277 hprintf("failed to get %s size\n", path); 278 return EINVAL; 279 } 280 if (vol->size == 0) { 281 hprintf("%s has size of 0\n", path); 282 return EINVAL; 283 } 284 } 285 286 return 0; 287 } 288 289 static int 290 hammer2_verify_volumes_1(const hammer2_vfsvolume_t *volumes, 291 const hammer2_volume_data_t *rootvoldata) 292 { 293 const hammer2_vfsvolume_t *vol; 294 hammer2_off_t off; 295 const char *path; 296 int i, nvolumes = 0; 297 298 /* check initialized volume count */ 299 for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) { 300 vol = &volumes[i]; 301 if (vol->id != -1) 302 nvolumes++; 303 } 304 if (nvolumes != 1) { 305 hprintf("only 1 volume supported\n"); 306 return EINVAL; 307 } 308 309 /* check volume header */ 310 if (rootvoldata->nvolumes) { 311 hprintf("volume count %d must be 0\n", rootvoldata->nvolumes); 312 return EINVAL; 313 } 314 if (rootvoldata->total_size) { 315 hprintf("total size 0x%016jx must be 0\n", 316 (intmax_t)rootvoldata->total_size); 317 return EINVAL; 318 } 319 for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) { 320 off = rootvoldata->volu_loff[i]; 321 if (off) { 322 hprintf("volume offset[%d] 0x%016jx must be 0\n", i, 323 (intmax_t)off); 324 return EINVAL; 325 } 326 } 327 328 /* check volume */ 329 vol = &volumes[HAMMER2_ROOT_VOLUME]; 330 path = vol->dev->path; 331 if (vol->id) { 332 hprintf("%s has non zero id %d\n", path, vol->id); 333 return EINVAL; 334 } 335 if (vol->offset) { 336 hprintf("%s has non zero offset 0x%016jx\n", path, 337 (intmax_t)vol->offset); 338 return EINVAL; 339 } 340 if (vol->size & HAMMER2_VOLUME_ALIGNMASK64) { 341 hprintf("%s's size is not 0x%016jx aligned\n", path, 342 (intmax_t)HAMMER2_VOLUME_ALIGN); 343 return EINVAL; 344 } 345 346 return 0; 347 } 348 349 static int 350 hammer2_verify_volumes_2(const hammer2_vfsvolume_t *volumes, 351 const hammer2_volume_data_t *rootvoldata) 352 { 353 const hammer2_vfsvolume_t *vol; 354 hammer2_off_t off, total_size = 0; 355 const char *path; 356 int i, nvolumes = 0; 357 358 /* check initialized volume count */ 359 for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) { 360 vol = &volumes[i]; 361 if (vol->id != -1) { 362 nvolumes++; 363 total_size += vol->size; 364 } 365 } 366 367 /* check volume header */ 368 if (rootvoldata->nvolumes != nvolumes) { 369 hprintf("volume header requires %d devices, %d specified\n", 370 rootvoldata->nvolumes, nvolumes); 371 return EINVAL; 372 } 373 if (rootvoldata->total_size != total_size) { 374 hprintf("total size 0x%016jx does not equal sum of volumes 0x%016jx\n", 375 rootvoldata->total_size, total_size); 376 return EINVAL; 377 } 378 for (i = 0; i < nvolumes; ++i) { 379 off = rootvoldata->volu_loff[i]; 380 if (off == (hammer2_off_t)-1) { 381 hprintf("volume offset[%d] 0x%016jx must not be -1\n", 382 i, (intmax_t)off); 383 return EINVAL; 384 } 385 } 386 for (i = nvolumes; i < HAMMER2_MAX_VOLUMES; ++i) { 387 off = rootvoldata->volu_loff[i]; 388 if (off != (hammer2_off_t)-1) { 389 hprintf("volume offset[%d] 0x%016jx must be -1\n", 390 i, (intmax_t)off); 391 return EINVAL; 392 } 393 } 394 395 /* check volumes */ 396 for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) { 397 vol = &volumes[i]; 398 if (vol->id == -1) 399 continue; 400 path = vol->dev->path; 401 /* check offset */ 402 if (vol->offset & HAMMER2_FREEMAP_LEVEL1_MASK) { 403 hprintf("%s's offset 0x%016jx not 0x%016jx aligned\n", 404 path, (intmax_t)vol->offset, 405 HAMMER2_FREEMAP_LEVEL1_SIZE); 406 return EINVAL; 407 } 408 /* check vs previous volume */ 409 if (i) { 410 if (vol->id <= (vol-1)->id) { 411 hprintf("%s has inconsistent id %d\n", path, 412 vol->id); 413 return EINVAL; 414 } 415 if (vol->offset != (vol-1)->offset + (vol-1)->size) { 416 hprintf("%s has inconsistent offset 0x%016jx\n", 417 path, (intmax_t)vol->offset); 418 return EINVAL; 419 } 420 } else { /* first */ 421 if (vol->offset) { 422 hprintf("%s has non zero offset 0x%016jx\n", 423 path, (intmax_t)vol->offset); 424 return EINVAL; 425 } 426 } 427 /* check size for non-last and last volumes */ 428 if (i != rootvoldata->nvolumes - 1) { 429 if (vol->size < HAMMER2_FREEMAP_LEVEL1_SIZE) { 430 hprintf("%s's size must be >= 0x%016jx\n", path, 431 (intmax_t)HAMMER2_FREEMAP_LEVEL1_SIZE); 432 return EINVAL; 433 } 434 if (vol->size & HAMMER2_FREEMAP_LEVEL1_MASK) { 435 hprintf("%s's size is not 0x%016jx aligned\n", 436 path, 437 (intmax_t)HAMMER2_FREEMAP_LEVEL1_SIZE); 438 return EINVAL; 439 } 440 } else { /* last */ 441 if (vol->size & HAMMER2_VOLUME_ALIGNMASK64) { 442 hprintf("%s's size is not 0x%016jx aligned\n", 443 path, 444 (intmax_t)HAMMER2_VOLUME_ALIGN); 445 return EINVAL; 446 } 447 } 448 } 449 450 return 0; 451 } 452 453 static int 454 hammer2_verify_vfsvolumes(const hammer2_vfsvolume_t *volumes, 455 const hammer2_volume_data_t *rootvoldata) 456 { 457 int error; 458 459 error = hammer2_verify_volumes_common(volumes, rootvoldata); 460 if (error) 461 return error; 462 463 if (rootvoldata->version >= HAMMER2_VOL_VERSION_MULTI_VOLUMES) 464 return hammer2_verify_volumes_2(volumes, rootvoldata); 465 else 466 return hammer2_verify_volumes_1(volumes, rootvoldata); 467 } 468 469 /* 470 * Returns zone# of returned volume header or < 0 on failure. 471 */ 472 static int 473 hammer2_read_volume_header(struct m_vnode *devvp, const char *path, 474 hammer2_volume_data_t *voldata) 475 { 476 hammer2_volume_data_t *vd; 477 struct m_buf *bp = NULL; 478 hammer2_crc32_t crc0, crc1; 479 hammer2_off_t size = check_volume(devvp->fs->fd); 480 off_t blkoff; 481 int zone = -1; 482 int i; 483 484 /* 485 * There are up to 4 copies of the volume header (syncs iterate 486 * between them so there is no single master). We don't trust the 487 * volu_size field so we don't know precisely how large the filesystem 488 * is, so depend on the OS to return an error if we go beyond the 489 * block device's EOF. 490 */ 491 for (i = 0; i < HAMMER2_NUM_VOLHDRS; ++i) { 492 /* ignore if blkoff is beyond media size */ 493 blkoff = (off_t)i * HAMMER2_ZONE_BYTES64; 494 if (blkoff >= (off_t)size) 495 continue; 496 497 if (breadx(devvp, i * HAMMER2_ZONE_BYTES64, HAMMER2_VOLUME_BYTES, 498 &bp)) { 499 brelse(bp); 500 bp = NULL; 501 continue; 502 } 503 504 vd = (struct hammer2_volume_data *)bp->b_data; 505 /* verify volume header magic */ 506 if ((vd->magic != HAMMER2_VOLUME_ID_HBO) && 507 (vd->magic != HAMMER2_VOLUME_ID_ABO)) { 508 hprintf("%s #%d: bad magic\n", path, i); 509 brelse(bp); 510 bp = NULL; 511 continue; 512 } 513 514 if (vd->magic == HAMMER2_VOLUME_ID_ABO) { 515 /* XXX: Reversed-endianness filesystem */ 516 hprintf("%s #%d: reverse-endian filesystem detected\n", 517 path, i); 518 brelse(bp); 519 bp = NULL; 520 continue; 521 } 522 523 /* verify volume header CRC's */ 524 crc0 = vd->icrc_sects[HAMMER2_VOL_ICRC_SECT0]; 525 crc1 = hammer2_icrc32(bp->b_data + HAMMER2_VOLUME_ICRC0_OFF, 526 HAMMER2_VOLUME_ICRC0_SIZE); 527 if (crc0 != crc1) { 528 hprintf("%s #%d: volume header crc mismatch sect0 %08x/%08x\n", 529 path, i, crc0, crc1); 530 brelse(bp); 531 bp = NULL; 532 continue; 533 } 534 crc0 = vd->icrc_sects[HAMMER2_VOL_ICRC_SECT1]; 535 crc1 = hammer2_icrc32(bp->b_data + HAMMER2_VOLUME_ICRC1_OFF, 536 HAMMER2_VOLUME_ICRC1_SIZE); 537 if (crc0 != crc1) { 538 hprintf("%s #%d: volume header crc mismatch sect1 %08x/%08x\n", 539 path, i, crc0, crc1); 540 brelse(bp); 541 bp = NULL; 542 continue; 543 } 544 crc0 = vd->icrc_volheader; 545 crc1 = hammer2_icrc32(bp->b_data + HAMMER2_VOLUME_ICRCVH_OFF, 546 HAMMER2_VOLUME_ICRCVH_SIZE); 547 if (crc0 != crc1) { 548 hprintf("%s #%d: volume header crc mismatch vh %08x/%08x\n", 549 path, i, crc0, crc1); 550 brelse(bp); 551 bp = NULL; 552 continue; 553 } 554 555 if (zone == -1 || voldata->mirror_tid < vd->mirror_tid) { 556 *voldata = *vd; 557 zone = i; 558 } 559 brelse(bp); 560 bp = NULL; 561 } 562 563 if (zone == -1) { 564 hprintf("%s has no valid volume headers\n", path); 565 return -EINVAL; 566 } 567 return zone; 568 } 569 570 static void 571 hammer2_print_uuid_mismatch(uuid_t *uuid1, uuid_t *uuid2, const char *id) 572 { 573 char *buf1 = NULL, *buf2 = NULL; 574 575 hammer2_uuid_to_str(uuid1, &buf1); 576 hammer2_uuid_to_str(uuid2, &buf2); 577 578 hprintf("volume %s uuid mismatch %s vs %s\n", id, buf1, buf2); 579 580 free(buf1); 581 free(buf2); 582 } 583 584 int 585 hammer2_init_vfsvolumes(struct mount *mp, const hammer2_devvp_list_t *devvpl, 586 hammer2_vfsvolume_t *volumes, 587 hammer2_volume_data_t *rootvoldata, 588 int *rootvolzone, 589 struct m_vnode **rootvoldevvp) 590 { 591 hammer2_devvp_t *e; 592 hammer2_volume_data_t *voldata; 593 hammer2_vfsvolume_t *vol; 594 struct m_vnode *devvp; 595 const char *path; 596 uuid_t fsid, fstype; 597 int i, zone, error = 0, version = -1, nvolumes = 0; 598 599 for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) { 600 vol = &volumes[i]; 601 vol->dev = NULL; 602 vol->id = -1; 603 vol->offset = (hammer2_off_t)-1; 604 vol->size = (hammer2_off_t)-1; 605 } 606 607 voldata = kmalloc(sizeof(*voldata), M_HAMMER2, M_WAITOK | M_ZERO); 608 bzero(&fsid, sizeof(fsid)); 609 bzero(&fstype, sizeof(fstype)); 610 bzero(rootvoldata, sizeof(*rootvoldata)); 611 612 TAILQ_FOREACH(e, devvpl, entry) { 613 devvp = e->devvp; 614 path = e->path; 615 KKASSERT(devvp); 616 617 /* returns negative error or positive zone# */ 618 error = hammer2_read_volume_header(devvp, path, voldata); 619 if (error < 0) { 620 hprintf("failed to read %s's volume header\n", path); 621 error = -error; 622 goto done; 623 } 624 zone = error; 625 error = 0; /* reset error */ 626 627 if (voldata->volu_id >= HAMMER2_MAX_VOLUMES) { 628 hprintf("%s has bad volume id %d\n", path, 629 voldata->volu_id); 630 error = EINVAL; 631 goto done; 632 } 633 vol = &volumes[voldata->volu_id]; 634 if (vol->id != -1) { 635 hprintf("volume id %d already initialized\n", 636 voldata->volu_id); 637 error = EINVAL; 638 goto done; 639 } 640 /* all headers must have the same version, nvolumes and uuid */ 641 if (version == -1) { 642 version = voldata->version; 643 nvolumes = voldata->nvolumes; 644 fsid = voldata->fsid; 645 fstype = voldata->fstype; 646 } else { 647 if (version != (int)voldata->version) { 648 hprintf("volume version mismatch %d vs %d\n", 649 version, (int)voldata->version); 650 error = ENXIO; 651 goto done; 652 } 653 if (nvolumes != voldata->nvolumes) { 654 hprintf("volume count mismatch %d vs %d\n", 655 nvolumes, voldata->nvolumes); 656 error = ENXIO; 657 goto done; 658 } 659 if (bcmp(&fsid, &voldata->fsid, sizeof(fsid))) { 660 hammer2_print_uuid_mismatch(&fsid, 661 &voldata->fsid, "fsid"); 662 error = ENXIO; 663 goto done; 664 } 665 if (bcmp(&fstype, &voldata->fstype, sizeof(fstype))) { 666 hammer2_print_uuid_mismatch(&fstype, 667 &voldata->fstype, "fstype"); 668 error = ENXIO; 669 goto done; 670 } 671 } 672 if (version < HAMMER2_VOL_VERSION_MIN || 673 version > HAMMER2_VOL_VERSION_WIP) { 674 hprintf("bad volume version %d\n", version); 675 error = EINVAL; 676 goto done; 677 } 678 /* all per-volume tests passed */ 679 vol->dev = e; 680 vol->id = voldata->volu_id; 681 vol->offset = voldata->volu_loff[vol->id]; 682 vol->size = voldata->volu_size; 683 if (vol->id == HAMMER2_ROOT_VOLUME) { 684 bcopy(voldata, rootvoldata, sizeof(*rootvoldata)); 685 *rootvolzone = zone; 686 KKASSERT(*rootvoldevvp == NULL); 687 *rootvoldevvp = e->devvp; 688 } 689 //devvp->v_rdev->si_mountpoint = mp; 690 hprintf("\"%s\" zone=%d id=%d offset=0x%016jx size=0x%016jx\n", 691 path, zone, vol->id, (intmax_t)vol->offset, 692 (intmax_t)vol->size); 693 } 694 done: 695 if (!error) { 696 if (!rootvoldata->version) { 697 hprintf("root volume not found\n"); 698 error = EINVAL; 699 } 700 if (!error) 701 error = hammer2_verify_vfsvolumes(volumes, rootvoldata); 702 } 703 kfree(voldata, M_HAMMER2); 704 705 return error; 706 } 707 708 hammer2_vfsvolume_t* 709 hammer2_get_volume_from_hmp(hammer2_dev_t *hmp, hammer2_off_t offset) 710 { 711 hammer2_vfsvolume_t *vol, *ret = NULL; 712 int i; 713 714 offset &= ~HAMMER2_OFF_MASK_RADIX; 715 716 /* locking is unneeded until volume-add support */ 717 //hammer2_voldata_lock(hmp); 718 /* do binary search if users really use this many supported volumes */ 719 for (i = 0; i < hmp->nvolumes; ++i) { 720 vol = &hmp->volumes[i]; 721 if ((offset >= vol->offset) && 722 (offset < vol->offset + vol->size)) { 723 ret = vol; 724 break; 725 } 726 } 727 //hammer2_voldata_unlock(hmp); 728 729 if (!ret) 730 panic("no volume for offset 0x%016jx", (intmax_t)offset); 731 732 KKASSERT(ret); 733 KKASSERT(ret->dev); 734 KKASSERT(ret->dev->devvp); 735 //KKASSERT(ret->dev->path); 736 737 return ret; 738 } 739