xref: /dragonfly/usr.sbin/makefs/hammer2/hammer2_ondisk.c (revision b4ddbe789819885eb6f829ae1760b9844c29eb07)
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