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 { 209 const hammer2_vfsvolume_t *vol; 210 struct partinfo part; 211 struct stat st; 212 const char *path; 213 int i; 214 215 for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) { 216 vol = &volumes[i]; 217 if (vol->id == -1) 218 continue; 219 path = vol->dev->path; 220 /* check volume fields are initialized */ 221 if (!vol->dev->devvp) { 222 hprintf("%s has NULL devvp\n", path); 223 return EINVAL; 224 } 225 if (vol->offset == (hammer2_off_t)-1) { 226 hprintf("%s has bad offset 0x%016jx\n", path, 227 (intmax_t)vol->offset); 228 return EINVAL; 229 } 230 if (vol->size == (hammer2_off_t)-1) { 231 hprintf("%s has bad size 0x%016jx\n", path, 232 (intmax_t)vol->size); 233 return EINVAL; 234 } 235 /* check volume size vs block device size */ 236 /* 237 if (VOP_IOCTL(vol->dev->devvp, DIOCGPART, (void*)&part, 0, 238 curthread->td_ucred , NULL) == 0) { 239 */ 240 assert(vol->dev->devvp->fs); 241 if (ioctl(vol->dev->devvp->fs->fd, DIOCGPART, &part) == 0) { 242 assert(part.media_blksize <= HAMMER2_PBUFSIZE); 243 assert(HAMMER2_PBUFSIZE % part.media_blksize == 0); 244 if (vol->size > part.media_size) { 245 hprintf("%s's size 0x%016jx exceeds " 246 "device size 0x%016jx\n", 247 path, (intmax_t)vol->size, 248 part.media_size); 249 return EINVAL; 250 } 251 } else if (fstat(vol->dev->devvp->fs->fd, &st) == 0) { 252 if (vol->size > st.st_size) { 253 hprintf("%s's size 0x%016jx exceeds " 254 "file size 0x%016jx\n", 255 path, (intmax_t)vol->size, 256 st.st_size); 257 return EINVAL; 258 } 259 } else { 260 hprintf("failed to get %s size\n", path); 261 return EINVAL; 262 } 263 } 264 265 return 0; 266 } 267 268 static int 269 hammer2_verify_volumes_1(const hammer2_vfsvolume_t *volumes, 270 const hammer2_volume_data_t *rootvoldata) 271 { 272 const hammer2_vfsvolume_t *vol; 273 hammer2_off_t off; 274 const char *path; 275 int i, nvolumes = 0; 276 277 /* check initialized volume count */ 278 for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) { 279 vol = &volumes[i]; 280 if (vol->id != -1) 281 nvolumes++; 282 } 283 if (nvolumes != 1) { 284 hprintf("only 1 volume supported\n"); 285 return EINVAL; 286 } 287 288 /* check volume header */ 289 if (rootvoldata->volu_id) { 290 hprintf("volume id %d must be 0\n", rootvoldata->volu_id); 291 return EINVAL; 292 } 293 if (rootvoldata->nvolumes) { 294 hprintf("volume count %d must be 0\n", rootvoldata->nvolumes); 295 return EINVAL; 296 } 297 if (rootvoldata->total_size) { 298 hprintf("total size 0x%016jx must be 0\n", 299 (intmax_t)rootvoldata->total_size); 300 return EINVAL; 301 } 302 for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) { 303 off = rootvoldata->volu_loff[i]; 304 if (off) { 305 hprintf("volume offset[%d] 0x%016jx must be 0\n", i, 306 (intmax_t)off); 307 return EINVAL; 308 } 309 } 310 311 /* check volume */ 312 vol = &volumes[HAMMER2_ROOT_VOLUME]; 313 path = vol->dev->path; 314 if (vol->id) { 315 hprintf("%s has non zero id %d\n", path, vol->id); 316 return EINVAL; 317 } 318 if (vol->offset) { 319 hprintf("%s has non zero offset 0x%016jx\n", path, 320 (intmax_t)vol->offset); 321 return EINVAL; 322 } 323 if (vol->size & HAMMER2_VOLUME_ALIGNMASK64) { 324 hprintf("%s's size is not 0x%016jx aligned\n", path, 325 (intmax_t)HAMMER2_VOLUME_ALIGN); 326 return EINVAL; 327 } 328 329 return 0; 330 } 331 332 static int 333 hammer2_verify_volumes_2(const hammer2_vfsvolume_t *volumes, 334 const hammer2_volume_data_t *rootvoldata) 335 { 336 const hammer2_vfsvolume_t *vol; 337 hammer2_off_t off, total_size = 0; 338 const char *path; 339 int i, nvolumes = 0; 340 341 /* check initialized volume count */ 342 for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) { 343 vol = &volumes[i]; 344 if (vol->id != -1) { 345 nvolumes++; 346 total_size += vol->size; 347 } 348 } 349 350 /* check volume header */ 351 if (rootvoldata->volu_id != HAMMER2_ROOT_VOLUME) { 352 hprintf("volume id %d must be %d\n", rootvoldata->volu_id, 353 HAMMER2_ROOT_VOLUME); 354 return EINVAL; 355 } 356 if (rootvoldata->nvolumes != nvolumes) { 357 hprintf("volume header requires %d devices, %d specified\n", 358 rootvoldata->nvolumes, nvolumes); 359 return EINVAL; 360 } 361 if (rootvoldata->total_size != total_size) { 362 hprintf("total size 0x%016jx does not equal sum of volumes 0x%016jx\n", 363 rootvoldata->total_size, total_size); 364 return EINVAL; 365 } 366 for (i = 0; i < nvolumes; ++i) { 367 off = rootvoldata->volu_loff[i]; 368 if (off == (hammer2_off_t)-1) { 369 hprintf("volume offset[%d] 0x%016jx must not be -1\n", 370 i, (intmax_t)off); 371 return EINVAL; 372 } 373 } 374 for (i = nvolumes; i < HAMMER2_MAX_VOLUMES; ++i) { 375 off = rootvoldata->volu_loff[i]; 376 if (off != (hammer2_off_t)-1) { 377 hprintf("volume offset[%d] 0x%016jx must be -1\n", 378 i, (intmax_t)off); 379 return EINVAL; 380 } 381 } 382 383 /* check volumes */ 384 for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) { 385 vol = &volumes[i]; 386 if (vol->id == -1) 387 continue; 388 path = vol->dev->path; 389 /* check offset */ 390 if (vol->offset & HAMMER2_FREEMAP_LEVEL1_MASK) { 391 hprintf("%s's offset 0x%016jx not 0x%016jx aligned\n", 392 path, (intmax_t)vol->offset, 393 HAMMER2_FREEMAP_LEVEL1_SIZE); 394 return EINVAL; 395 } 396 /* check vs previous volume */ 397 if (i) { 398 if (vol->id <= (vol-1)->id) { 399 hprintf("%s has inconsistent id %d\n", path, 400 vol->id); 401 return EINVAL; 402 } 403 if (vol->offset != (vol-1)->offset + (vol-1)->size) { 404 hprintf("%s has inconsistent offset 0x%016jx\n", 405 path, (intmax_t)vol->offset); 406 return EINVAL; 407 } 408 } else { /* first */ 409 if (vol->offset) { 410 hprintf("%s has non zero offset 0x%016jx\n", 411 path, (intmax_t)vol->offset); 412 return EINVAL; 413 } 414 } 415 /* check size for non-last and last volumes */ 416 if (i != rootvoldata->nvolumes - 1) { 417 if (vol->size < HAMMER2_FREEMAP_LEVEL1_SIZE) { 418 hprintf("%s's size must be >= 0x%016jx\n", path, 419 (intmax_t)HAMMER2_FREEMAP_LEVEL1_SIZE); 420 return EINVAL; 421 } 422 if (vol->size & HAMMER2_FREEMAP_LEVEL1_MASK) { 423 hprintf("%s's size is not 0x%016jx aligned\n", 424 path, 425 (intmax_t)HAMMER2_FREEMAP_LEVEL1_SIZE); 426 return EINVAL; 427 } 428 } else { /* last */ 429 if (vol->size & HAMMER2_VOLUME_ALIGNMASK64) { 430 hprintf("%s's size is not 0x%016jx aligned\n", 431 path, 432 (intmax_t)HAMMER2_VOLUME_ALIGN); 433 return EINVAL; 434 } 435 } 436 } 437 438 return 0; 439 } 440 441 static int 442 hammer2_verify_vfsvolumes(const hammer2_vfsvolume_t *volumes, 443 const hammer2_volume_data_t *rootvoldata) 444 { 445 int error; 446 447 error = hammer2_verify_volumes_common(volumes); 448 if (error) 449 return error; 450 451 if (rootvoldata->version >= HAMMER2_VOL_VERSION_MULTI_VOLUMES) 452 return hammer2_verify_volumes_2(volumes, rootvoldata); 453 else 454 return hammer2_verify_volumes_1(volumes, rootvoldata); 455 } 456 457 /* 458 * Returns zone# of returned volume header or < 0 on failure. 459 */ 460 static int 461 hammer2_read_volume_header(struct m_vnode *devvp, const char *path, 462 hammer2_volume_data_t *voldata) 463 { 464 hammer2_volume_data_t *vd; 465 struct m_buf *bp = NULL; 466 hammer2_crc32_t crc0, crc1; 467 hammer2_off_t size = check_volume(devvp->fs->fd); 468 off_t blkoff; 469 int zone = -1; 470 int i; 471 472 /* 473 * There are up to 4 copies of the volume header (syncs iterate 474 * between them so there is no single master). We don't trust the 475 * volu_size field so we don't know precisely how large the filesystem 476 * is, so depend on the OS to return an error if we go beyond the 477 * block device's EOF. 478 */ 479 for (i = 0; i < HAMMER2_NUM_VOLHDRS; ++i) { 480 /* ignore if blkoff is beyond media size */ 481 blkoff = (off_t)i * HAMMER2_ZONE_BYTES64; 482 if (blkoff >= (off_t)size) 483 continue; 484 485 if (breadx(devvp, i * HAMMER2_ZONE_BYTES64, HAMMER2_VOLUME_BYTES, 486 &bp)) { 487 brelse(bp); 488 bp = NULL; 489 continue; 490 } 491 492 vd = (struct hammer2_volume_data *)bp->b_data; 493 /* verify volume header magic */ 494 if ((vd->magic != HAMMER2_VOLUME_ID_HBO) && 495 (vd->magic != HAMMER2_VOLUME_ID_ABO)) { 496 hprintf("%s #%d: bad magic\n", path, i); 497 brelse(bp); 498 bp = NULL; 499 continue; 500 } 501 502 if (vd->magic == HAMMER2_VOLUME_ID_ABO) { 503 /* XXX: Reversed-endianness filesystem */ 504 hprintf("%s #%d: reverse-endian filesystem detected\n", 505 path, i); 506 brelse(bp); 507 bp = NULL; 508 continue; 509 } 510 511 /* verify volume header CRC's */ 512 crc0 = vd->icrc_sects[HAMMER2_VOL_ICRC_SECT0]; 513 crc1 = hammer2_icrc32(bp->b_data + HAMMER2_VOLUME_ICRC0_OFF, 514 HAMMER2_VOLUME_ICRC0_SIZE); 515 if (crc0 != crc1) { 516 hprintf("%s #%d: volume header crc mismatch sect0 %08x/%08x\n", 517 path, i, crc0, crc1); 518 brelse(bp); 519 bp = NULL; 520 continue; 521 } 522 crc0 = vd->icrc_sects[HAMMER2_VOL_ICRC_SECT1]; 523 crc1 = hammer2_icrc32(bp->b_data + HAMMER2_VOLUME_ICRC1_OFF, 524 HAMMER2_VOLUME_ICRC1_SIZE); 525 if (crc0 != crc1) { 526 hprintf("%s #%d: volume header crc mismatch sect1 %08x/%08x\n", 527 path, i, crc0, crc1); 528 brelse(bp); 529 bp = NULL; 530 continue; 531 } 532 crc0 = vd->icrc_volheader; 533 crc1 = hammer2_icrc32(bp->b_data + HAMMER2_VOLUME_ICRCVH_OFF, 534 HAMMER2_VOLUME_ICRCVH_SIZE); 535 if (crc0 != crc1) { 536 hprintf("%s #%d: volume header crc mismatch vh %08x/%08x\n", 537 path, i, crc0, crc1); 538 brelse(bp); 539 bp = NULL; 540 continue; 541 } 542 543 if (zone == -1 || voldata->mirror_tid < vd->mirror_tid) { 544 *voldata = *vd; 545 zone = i; 546 } 547 brelse(bp); 548 bp = NULL; 549 } 550 551 if (zone == -1) { 552 hprintf("%s has no valid volume headers\n", path); 553 return -EINVAL; 554 } 555 return zone; 556 } 557 558 static void 559 hammer2_print_uuid_mismatch(uuid_t *uuid1, uuid_t *uuid2, const char *id) 560 { 561 char *buf1 = NULL, *buf2 = NULL; 562 563 hammer2_uuid_to_str(uuid1, &buf1); 564 hammer2_uuid_to_str(uuid2, &buf2); 565 566 hprintf("%s uuid mismatch %s vs %s\n", id, buf1, buf2); 567 568 free(buf1); 569 free(buf2); 570 } 571 572 int 573 hammer2_init_vfsvolumes(struct mount *mp, const hammer2_devvp_list_t *devvpl, 574 hammer2_vfsvolume_t *volumes, 575 hammer2_volume_data_t *rootvoldata, 576 int *rootvolzone, 577 struct m_vnode **rootvoldevvp) 578 { 579 hammer2_devvp_t *e; 580 hammer2_volume_data_t *voldata; 581 hammer2_vfsvolume_t *vol; 582 struct m_vnode *devvp; 583 const char *path; 584 uuid_t fsid, fstype; 585 int i, zone, error = 0, version = -1, nvolumes = 0; 586 587 for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) { 588 vol = &volumes[i]; 589 vol->dev = NULL; 590 vol->id = -1; 591 vol->offset = (hammer2_off_t)-1; 592 vol->size = (hammer2_off_t)-1; 593 } 594 595 voldata = kmalloc(sizeof(*voldata), M_HAMMER2, M_WAITOK | M_ZERO); 596 bzero(&fsid, sizeof(fsid)); 597 bzero(&fstype, sizeof(fstype)); 598 bzero(rootvoldata, sizeof(*rootvoldata)); 599 600 TAILQ_FOREACH(e, devvpl, entry) { 601 devvp = e->devvp; 602 path = e->path; 603 KKASSERT(devvp); 604 605 /* returns negative error or positive zone# */ 606 error = hammer2_read_volume_header(devvp, path, voldata); 607 if (error < 0) { 608 hprintf("failed to read %s's volume header\n", path); 609 error = -error; 610 goto done; 611 } 612 zone = error; 613 error = 0; /* reset error */ 614 615 if (voldata->volu_id >= HAMMER2_MAX_VOLUMES) { 616 hprintf("%s has bad volume id %d\n", path, 617 voldata->volu_id); 618 error = EINVAL; 619 goto done; 620 } 621 vol = &volumes[voldata->volu_id]; 622 if (vol->id != -1) { 623 hprintf("volume id %d already initialized\n", 624 voldata->volu_id); 625 error = EINVAL; 626 goto done; 627 } 628 /* all headers must have the same version, nvolumes and uuid */ 629 if (version == -1) { 630 version = voldata->version; 631 nvolumes = voldata->nvolumes; 632 fsid = voldata->fsid; 633 fstype = voldata->fstype; 634 } else { 635 if (version != (int)voldata->version) { 636 hprintf("volume version mismatch %d vs %d\n", 637 version, (int)voldata->version); 638 error = ENXIO; 639 goto done; 640 } 641 if (nvolumes != voldata->nvolumes) { 642 hprintf("volume count mismatch %d vs %d\n", 643 nvolumes, voldata->nvolumes); 644 error = ENXIO; 645 goto done; 646 } 647 if (bcmp(&fsid, &voldata->fsid, sizeof(fsid))) { 648 hammer2_print_uuid_mismatch(&fsid, 649 &voldata->fsid, "fsid"); 650 error = ENXIO; 651 goto done; 652 } 653 if (bcmp(&fstype, &voldata->fstype, sizeof(fstype))) { 654 hammer2_print_uuid_mismatch(&fstype, 655 &voldata->fstype, "fstype"); 656 error = ENXIO; 657 goto done; 658 } 659 } 660 if (version < HAMMER2_VOL_VERSION_MIN || 661 version > HAMMER2_VOL_VERSION_WIP) { 662 hprintf("bad volume version %d\n", version); 663 error = EINVAL; 664 goto done; 665 } 666 /* all per-volume tests passed */ 667 vol->dev = e; 668 vol->id = voldata->volu_id; 669 vol->offset = voldata->volu_loff[vol->id]; 670 vol->size = voldata->volu_size; 671 if (vol->id == HAMMER2_ROOT_VOLUME) { 672 bcopy(voldata, rootvoldata, sizeof(*rootvoldata)); 673 *rootvolzone = zone; 674 KKASSERT(*rootvoldevvp == NULL); 675 *rootvoldevvp = e->devvp; 676 } 677 //devvp->v_rdev->si_mountpoint = mp; 678 hprintf("\"%s\" zone=%d id=%d offset=0x%016jx size=0x%016jx\n", 679 path, zone, vol->id, (intmax_t)vol->offset, 680 (intmax_t)vol->size); 681 } 682 done: 683 if (!error) { 684 if (!rootvoldata->version) { 685 hprintf("root volume not found\n"); 686 error = EINVAL; 687 } 688 if (!error) 689 error = hammer2_verify_vfsvolumes(volumes, rootvoldata); 690 } 691 kfree(voldata, M_HAMMER2); 692 693 return error; 694 } 695 696 hammer2_vfsvolume_t* 697 hammer2_get_volume_from_hmp(hammer2_dev_t *hmp, hammer2_off_t offset) 698 { 699 hammer2_vfsvolume_t *vol, *ret = NULL; 700 int i; 701 702 offset &= ~HAMMER2_OFF_MASK_RADIX; 703 704 /* locking is unneeded until volume-add support */ 705 //hammer2_voldata_lock(hmp); 706 /* do binary search if users really use this many supported volumes */ 707 for (i = 0; i < hmp->nvolumes; ++i) { 708 vol = &hmp->volumes[i]; 709 if ((offset >= vol->offset) && 710 (offset < vol->offset + vol->size)) { 711 ret = vol; 712 break; 713 } 714 } 715 //hammer2_voldata_unlock(hmp); 716 717 if (!ret) 718 panic("no volume for offset 0x%016jx", (intmax_t)offset); 719 720 KKASSERT(ret); 721 KKASSERT(ret->dev); 722 KKASSERT(ret->dev->devvp); 723 //KKASSERT(ret->dev->path); 724 725 return ret; 726 } 727