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
hammer2_lookup_device(const char * path,int rootmount,struct vnode ** devvp)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
hammer2_open_devvp(const hammer2_devvp_list_t * devvpl,int ronly)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
hammer2_close_devvp(const hammer2_devvp_list_t * devvpl,int ronly)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
hammer2_init_devvp(const char * blkdevs,int rootmount,hammer2_devvp_list_t * devvpl)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
hammer2_cleanup_devvp(hammer2_devvp_list_t * devvpl)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
hammer2_verify_volumes_common(const hammer2_volume_t * volumes,const hammer2_volume_data_t * rootvoldata)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
hammer2_verify_volumes_1(const hammer2_volume_t * volumes,const hammer2_volume_data_t * rootvoldata)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
hammer2_verify_volumes_2(const hammer2_volume_t * volumes,const hammer2_volume_data_t * rootvoldata)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
hammer2_verify_volumes(const hammer2_volume_t * volumes,const hammer2_volume_data_t * rootvoldata)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
hammer2_read_volume_header(struct vnode * devvp,const char * path,hammer2_volume_data_t * voldata)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
hammer2_print_uuid_mismatch(uuid_t * uuid1,uuid_t * uuid2,const char * id)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
hammer2_init_volumes(struct mount * mp,const hammer2_devvp_list_t * devvpl,hammer2_volume_t * volumes,hammer2_volume_data_t * rootvoldata,int * rootvolzone,struct vnode ** rootvoldevvp)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*
hammer2_get_volume(hammer2_dev_t * hmp,hammer2_off_t offset)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