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