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