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