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