Merge branches 'hammer2' and 'master' of ssh://crater.dragonflybsd.org/repository...
[dragonfly.git] / sys / vfs / hammer2 / hammer2_vfsops.c
1 /*-
2  * Copyright (c) 2011, 2012 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/nlookup.h>
38 #include <sys/vnode.h>
39 #include <sys/mount.h>
40 #include <sys/fcntl.h>
41 #include <sys/buf.h>
42 #include <sys/uuid.h>
43 #include <sys/vfsops.h>
44
45 #include "hammer2.h"
46 #include "hammer2_disk.h"
47 #include "hammer2_mount.h"
48
49 struct hammer2_sync_info {
50         int error;
51         int waitfor;
52 };
53
54 static int hammer2_vfs_init(struct vfsconf *conf);
55 static int hammer2_vfs_mount(struct mount *mp, char *path, caddr_t data,
56                                 struct ucred *cred);
57 static int hammer2_remount(struct mount *, char *, struct vnode *,
58                                 struct ucred *);
59 static int hammer2_vfs_unmount(struct mount *mp, int mntflags);
60 static int hammer2_vfs_root(struct mount *mp, struct vnode **vpp);
61 static int hammer2_vfs_statfs(struct mount *mp, struct statfs *sbp,
62                                 struct ucred *cred);
63 static int hammer2_vfs_statvfs(struct mount *mp, struct statvfs *sbp,
64                                 struct ucred *cred);
65 static int hammer2_vfs_sync(struct mount *mp, int waitfor);
66 static int hammer2_vfs_vget(struct mount *mp, struct vnode *dvp,
67                                 ino_t ino, struct vnode **vpp);
68 static int hammer2_vfs_fhtovp(struct mount *mp, struct vnode *rootvp,
69                                 struct fid *fhp, struct vnode **vpp);
70 static int hammer2_vfs_vptofh(struct vnode *vp, struct fid *fhp);
71 static int hammer2_vfs_checkexp(struct mount *mp, struct sockaddr *nam,
72                                 int *exflagsp, struct ucred **credanonp);
73
74 static int hammer2_install_volume_header(hammer2_mount_t *hmp);
75 static int hammer2_sync_scan1(struct mount *mp, struct vnode *vp, void *data);
76 static int hammer2_sync_scan2(struct mount *mp, struct vnode *vp, void *data);
77
78 /*
79  * HAMMER2 vfs operations.
80  */
81 static struct vfsops hammer2_vfsops = {
82         .vfs_init       = hammer2_vfs_init,
83         .vfs_sync       = hammer2_vfs_sync,
84         .vfs_mount      = hammer2_vfs_mount,
85         .vfs_unmount    = hammer2_vfs_unmount,
86         .vfs_root       = hammer2_vfs_root,
87         .vfs_statfs     = hammer2_vfs_statfs,
88         .vfs_statvfs    = hammer2_vfs_statvfs,
89         .vfs_vget       = hammer2_vfs_vget,
90         .vfs_vptofh     = hammer2_vfs_vptofh,
91         .vfs_fhtovp     = hammer2_vfs_fhtovp,
92         .vfs_checkexp   = hammer2_vfs_checkexp
93 };
94
95 MALLOC_DEFINE(M_HAMMER2, "HAMMER2-mount", "");
96
97 VFS_SET(hammer2_vfsops, hammer2, 0);
98 MODULE_VERSION(hammer2, 1);
99
100 static
101 int
102 hammer2_vfs_init(struct vfsconf *conf)
103 {
104         int error;
105
106         error = 0;
107
108         if (HAMMER2_BLOCKREF_BYTES != sizeof(struct hammer2_blockref))
109                 error = EINVAL;
110         if (HAMMER2_INODE_BYTES != sizeof(struct hammer2_inode_data))
111                 error = EINVAL;
112         if (HAMMER2_ALLOCREF_BYTES != sizeof(struct hammer2_allocref))
113                 error = EINVAL;
114         if (HAMMER2_VOLUME_BYTES != sizeof(struct hammer2_volume_data))
115                 error = EINVAL;
116
117         if (error)
118                 kprintf("HAMMER2 structure size mismatch; cannot continue.\n");
119
120         return (error);
121 }
122
123 /*
124  * Mount or remount HAMMER2 fileystem from physical media
125  *
126  *      mountroot
127  *              mp              mount point structure
128  *              path            NULL
129  *              data            <unused>
130  *              cred            <unused>
131  *
132  *      mount
133  *              mp              mount point structure
134  *              path            path to mount point
135  *              data            pointer to argument structure in user space
136  *                      volume  volume path (device@LABEL form)
137  *                      hflags  user mount flags
138  *              cred            user credentials
139  *
140  * RETURNS:     0       Success
141  *              !0      error number
142  */
143 static
144 int
145 hammer2_vfs_mount(struct mount *mp, char *path, caddr_t data,
146               struct ucred *cred)
147 {
148         struct hammer2_mount_info info;
149         hammer2_mount_t *hmp;
150         hammer2_key_t lhc;
151         struct vnode *devvp;
152         struct nlookupdata nd;
153         hammer2_chain_t *parent;
154         hammer2_chain_t *schain;
155         hammer2_chain_t *rchain;
156         char devstr[MNAMELEN];
157         size_t size;
158         size_t done;
159         char *dev;
160         char *label;
161         int ronly = 1;
162         int error;
163
164         hmp = NULL;
165         dev = NULL;
166         label = NULL;
167         devvp = NULL;
168
169         kprintf("hammer2_mount\n");
170
171         if (path == NULL) {
172                 /*
173                  * Root mount
174                  */
175                 return (EOPNOTSUPP);
176         } else {
177                 /*
178                  * Non-root mount or updating a mount
179                  */
180                 error = copyin(data, &info, sizeof(info));
181                 if (error)
182                         return (error);
183
184                 error = copyinstr(info.volume, devstr, MNAMELEN - 1, &done);
185                 if (error)
186                         return (error);
187
188                 /* Extract device and label */
189                 dev = devstr;
190                 label = strchr(devstr, '@');
191                 if (label == NULL ||
192                     ((label + 1) - dev) > done) {
193                         return (EINVAL);
194                 }
195                 *label = '\0';
196                 label++;
197                 if (*label == '\0')
198                         return (EINVAL);
199
200                 if (mp->mnt_flag & MNT_UPDATE) {
201                         /* Update mount */
202                         /* HAMMER2 implements NFS export via mountctl */
203                         hmp = MPTOH2(mp);
204                         devvp = hmp->devvp;
205                         error = hammer2_remount(mp, path, devvp, cred);
206                         return error;
207                 }
208         }
209
210         /*
211          * New non-root mount
212          */
213         /* Lookup name and verify it refers to a block device */
214         error = nlookup_init(&nd, dev, UIO_SYSSPACE, NLC_FOLLOW);
215         if (error == 0)
216                 error = nlookup(&nd);
217         if (error == 0)
218                 error = cache_vref(&nd.nl_nch, nd.nl_cred, &devvp);
219         nlookup_done(&nd);
220
221         if (error == 0) {
222                 if (vn_isdisk(devvp, &error))
223                         error = vfs_mountedon(devvp);
224         }
225         if (error == 0 && vcount(devvp) > 0)
226                 error = EBUSY;
227
228         /*
229          * Now open the device
230          */
231         if (error == 0) {
232                 ronly = ((mp->mnt_flag & MNT_RDONLY) != 0);
233                 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
234                 error = vinvalbuf(devvp, V_SAVE, 0, 0);
235                 if (error == 0) {
236                         error = VOP_OPEN(devvp, ronly ? FREAD : FREAD | FWRITE,
237                                          FSCRED, NULL);
238                 }
239                 vn_unlock(devvp);
240         }
241         if (error && devvp) {
242                 vrele(devvp);
243                 devvp = NULL;
244         }
245         if (error)
246                 return error;
247
248         /*
249          * Block device opened successfully, finish initializing the
250          * mount structure.
251          *
252          * From this point on we have to call hammer2_unmount() on failure.
253          */
254         hmp = kmalloc(sizeof(*hmp), M_HAMMER2, M_WAITOK | M_ZERO);
255         mp->mnt_data = (qaddr_t)hmp;
256         hmp->mp = mp;
257         hmp->ronly = ronly;
258         hmp->devvp = devvp;
259         kmalloc_create(&hmp->minode, "HAMMER2-inodes");
260         kmalloc_create(&hmp->mchain, "HAMMER2-chains");
261         
262         mp->mnt_flag = MNT_LOCAL;
263         mp->mnt_kern_flag |= MNTK_ALL_MPSAFE;   /* all entry pts are SMP */
264
265         /*
266          * vchain setup. vchain.data is special cased to NULL.  vchain.refs
267          * is initialized and will never drop to 0.
268          */
269         hmp->vchain.bref.type = HAMMER2_BREF_TYPE_VOLUME;
270         hmp->vchain.refs = 1;
271         hmp->vchain.data = (void *)&hmp->voldata;
272         hmp->vchain.bref.data_off = 0 | HAMMER2_PBUFRADIX;
273         /* hmp->vchain.u.xxx is left NULL */
274         lockinit(&hmp->vchain.lk, "volume", 0, LK_CANRECURSE);
275
276         /*
277          * Install the volume header
278          */
279         error = hammer2_install_volume_header(hmp);
280         if (error) {
281                 hammer2_vfs_unmount(mp, MNT_FORCE);
282                 return error;
283         }
284
285         /*
286          * required mount structure initializations
287          */
288         mp->mnt_stat.f_iosize = HAMMER2_PBUFSIZE;
289         mp->mnt_stat.f_bsize = HAMMER2_PBUFSIZE;
290
291         mp->mnt_vstat.f_frsize = HAMMER2_PBUFSIZE;
292         mp->mnt_vstat.f_bsize = HAMMER2_PBUFSIZE;
293
294         /*
295          * First locate the super-root inode, which is key 0 relative to the
296          * volume header's blockset.
297          *
298          * Then locate the root inode by scanning the directory keyspace
299          * represented by the label.
300          */
301         lhc = hammer2_dirhash(label, strlen(label));
302         parent = &hmp->vchain;
303         hammer2_chain_ref(hmp, parent);
304         hammer2_chain_lock(hmp, parent);
305         schain = hammer2_chain_lookup(hmp, &parent,
306                                       HAMMER2_SROOT_KEY, HAMMER2_SROOT_KEY);
307         hammer2_chain_put(hmp, parent);
308         if (schain == NULL) {
309                 kprintf("hammer2_mount: invalid super-root\n");
310                 hammer2_vfs_unmount(mp, MNT_FORCE);
311                 return EINVAL;
312         }
313
314         parent = schain;
315         hammer2_chain_ref(hmp, parent); /* parent: lock+ref, schain: ref */
316         rchain = hammer2_chain_lookup(hmp, &parent,
317                                       lhc, lhc + HAMMER2_DIRHASH_LOMASK);
318         while (rchain) {
319                 if (rchain->bref.type == HAMMER2_BREF_TYPE_INODE &&
320                     rchain->u.ip &&
321                     strcmp(label, rchain->data->ipdata.filename) == 0) {
322                         break;
323                 }
324                 rchain = hammer2_chain_next(hmp, &parent, rchain,
325                                             lhc, lhc + HAMMER2_DIRHASH_LOMASK);
326         }
327         hammer2_chain_put(hmp, parent);
328         if (rchain == NULL) {
329                 kprintf("hammer2_mount: root label not found\n");
330                 hammer2_chain_drop(hmp, schain);
331                 hammer2_vfs_unmount(mp, MNT_FORCE);
332                 return EINVAL;
333         }
334         hammer2_chain_unlock(hmp, rchain); /* rchain: ref */
335
336         hmp->schain = schain;           /* left held & unlocked */
337         hmp->rchain = rchain;           /* left held & unlocked */
338         hmp->iroot = rchain->u.ip;      /* implied hold from rchain */
339         kprintf("iroot %p\n", rchain->u.ip);
340
341         vfs_getnewfsid(mp);
342         vfs_add_vnodeops(mp, &hammer2_vnode_vops, &mp->mnt_vn_norm_ops);
343         vfs_add_vnodeops(mp, &hammer2_spec_vops, &mp->mnt_vn_spec_ops);
344         vfs_add_vnodeops(mp, &hammer2_fifo_vops, &mp->mnt_vn_fifo_ops);
345
346         copyinstr(info.volume, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size);
347         bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
348         bzero(mp->mnt_stat.f_mntonname, sizeof(mp->mnt_stat.f_mntonname));
349         copyinstr(path, mp->mnt_stat.f_mntonname,
350                   sizeof(mp->mnt_stat.f_mntonname) - 1,
351                   &size);
352
353         hammer2_vfs_statfs(mp, &mp->mnt_stat, cred);
354
355         return 0;
356 }
357
358 static
359 int
360 hammer2_remount(struct mount *mp, char *path, struct vnode *devvp,
361                 struct ucred *cred)
362 {
363         return (0);
364 }
365
366 static
367 int
368 hammer2_vfs_unmount(struct mount *mp, int mntflags)
369 {
370         hammer2_mount_t *hmp;
371         int flags;
372         int error = 0;
373         int ronly = ((mp->mnt_flag & MNT_RDONLY) != 0);
374         struct vnode *devvp;
375
376         kprintf("hammer2_unmount\n");
377
378         hmp = MPTOH2(mp);
379         flags = 0;
380
381         if (mntflags & MNT_FORCE)
382                 flags |= FORCECLOSE;
383
384         hammer2_mount_exlock(hmp);
385
386         /*
387          * If mount initialization proceeded far enough we must flush
388          * its vnodes.
389          */
390         kprintf("iroot %p\n", hmp->iroot);
391         if (hmp->iroot)
392                 error = vflush(mp, 0, flags);
393
394         if (error)
395                 return error;
396
397         /*
398          * Work to do:
399          *      1) Wait on the flusher having no work; heat up if needed
400          *      2) Scan inode RB tree till all the inodes are free
401          *      3) Destroy the kmalloc inode zone
402          *      4) Free the mount point
403          */
404         hmp->iroot = NULL;
405         if (hmp->rchain) {
406                 KKASSERT(hmp->rchain->refs == 1);
407                 hammer2_chain_drop(hmp, hmp->rchain);
408                 hmp->rchain = NULL;
409         }
410         if (hmp->schain) {
411                 KKASSERT(hmp->schain->refs == 1);
412                 hammer2_chain_drop(hmp, hmp->schain);
413                 hmp->schain = NULL;
414         }
415         if ((devvp = hmp->devvp) != NULL) {
416                 vinvalbuf(devvp, (ronly ? 0 : V_SAVE), 0, 0);
417                 hmp->devvp = NULL;
418                 VOP_CLOSE(devvp, (ronly ? FREAD : FREAD|FWRITE));
419                 vrele(devvp);
420                 devvp = NULL;
421         }
422
423         kmalloc_destroy(&hmp->minode);
424         kmalloc_destroy(&hmp->mchain);
425
426         hammer2_mount_unlock(hmp);
427
428         mp->mnt_data = NULL;
429         hmp->mp = NULL;
430         kfree(hmp, M_HAMMER2);
431
432         return (error);
433 }
434
435 static
436 int
437 hammer2_vfs_vget(struct mount *mp, struct vnode *dvp,
438              ino_t ino, struct vnode **vpp)
439 {
440         kprintf("hammer2_vget\n");
441         return (EOPNOTSUPP);
442 }
443
444 static
445 int
446 hammer2_vfs_root(struct mount *mp, struct vnode **vpp)
447 {
448         hammer2_mount_t *hmp;
449         int error;
450         struct vnode *vp;
451
452         kprintf("hammer2_root\n");
453
454         hmp = MPTOH2(mp);
455         hammer2_mount_exlock(hmp);
456         if (hmp->iroot == NULL) {
457                 *vpp = NULL;
458                 error = EINVAL;
459         } else {
460                 vp = hammer2_igetv(hmp->iroot, &error);
461                 *vpp = vp;
462                 if (vp == NULL)
463                         kprintf("vnodefail\n");
464         }
465         hammer2_mount_unlock(hmp);
466
467         return (error);
468 }
469
470 static
471 int
472 hammer2_vfs_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred)
473 {
474         hammer2_mount_t *hmp;
475
476         hmp = MPTOH2(mp);
477
478         mp->mnt_stat.f_files = 10;
479         mp->mnt_stat.f_bfree = 10;
480         mp->mnt_stat.f_bavail = mp->mnt_stat.f_bfree;
481
482         *sbp = mp->mnt_stat;
483         return (0);
484 }
485
486 static
487 int
488 hammer2_vfs_statvfs(struct mount *mp, struct statvfs *sbp, struct ucred *cred)
489 {
490         hammer2_mount_t *hmp;
491
492         hmp = MPTOH2(mp);
493
494         mp->mnt_vstat.f_files = 10;
495         mp->mnt_vstat.f_bfree = 10;
496         mp->mnt_vstat.f_bavail = mp->mnt_stat.f_bfree;
497
498         *sbp = mp->mnt_vstat;
499         return (0);
500 }
501
502 /*
503  * Sync the entire filesystem; this is called from the filesystem syncer
504  * process periodically and whenever a user calls sync(1) on the hammer
505  * mountpoint.
506  *
507  * Currently is actually called from the syncer! \o/
508  *
509  * This task will have to snapshot the state of the dirty inode chain.
510  * From that, it will have to make sure all of the inodes on the dirty
511  * chain have IO initiated. We make sure that io is initiated for the root
512  * block.
513  *
514  * If waitfor is set, we wait for media to acknowledge the new rootblock.
515  *
516  * THINKS: side A vs side B, to have sync not stall all I/O?
517  */
518 static
519 int
520 hammer2_vfs_sync(struct mount *mp, int waitfor)
521 {
522         struct hammer2_sync_info info;
523         hammer2_mount_t *hmp;
524         int flags;
525         int error;
526
527         kprintf("hammer2_sync \n");
528         hmp = MPTOH2(mp);
529
530         flags = VMSC_GETVP;
531         if (waitfor & MNT_LAZY)
532                 flags |= VMSC_ONEPASS;
533
534         info.error = 0;
535         info.waitfor = MNT_NOWAIT;
536         vmntvnodescan(mp, flags | VMSC_NOWAIT,
537                       hammer2_sync_scan1,
538                       hammer2_sync_scan2, &info);
539         if (info.error == 0 && (waitfor & MNT_WAIT)) {
540                 info.waitfor = waitfor;
541                     vmntvnodescan(mp, flags,
542                                   hammer2_sync_scan1,
543                                   hammer2_sync_scan2, &info);
544
545         }
546 #if 0
547         if (waitfor == MNT_WAIT) {
548                 /* XXX */
549         } else {
550                 /* XXX */
551         }
552 #endif
553         hammer2_chain_lock(hmp, &hmp->vchain);
554         hammer2_chain_flush(hmp, &hmp->vchain, NULL);
555         hammer2_chain_unlock(hmp, &hmp->vchain);
556         error = vinvalbuf(hmp->devvp, V_SAVE, 0, 0);
557         if (error == 0) {
558                 struct buf *bp;
559
560                 bp = getpbuf(NULL);
561                 bp->b_bio1.bio_offset = 0;
562                 bp->b_bufsize = 0;
563                 bp->b_bcount = 0;
564                 bp->b_cmd = BUF_CMD_FLUSH;
565                 bp->b_bio1.bio_done = biodone_sync;
566                 bp->b_bio1.bio_flags |= BIO_SYNC;
567                 vn_strategy(hmp->devvp, &bp->b_bio1);
568                 biowait(&bp->b_bio1, "h2vol");
569                 relpbuf(bp, NULL);
570
571                 kprintf("flush volume header\n");
572
573                 bp = getblk(hmp->devvp, 0, HAMMER2_PBUFSIZE, 0, 0);
574                 bcopy(&hmp->voldata, bp->b_data, HAMMER2_PBUFSIZE);
575                 bawrite(bp);
576         }
577         return (error);
578 }
579
580
581 static int
582 hammer2_sync_scan1(struct mount *mp, struct vnode *vp, void *data)
583 {
584         hammer2_inode_t *ip;
585
586         ip = VTOI(vp);
587         if (vp->v_type == VNON || ip == NULL ||
588             ((ip->chain.flags & HAMMER2_CHAIN_MODIFIED) == 0 &&
589              RB_EMPTY(&vp->v_rbdirty_tree))) {
590                 return(-1);
591         }
592         return(0);
593 }
594
595 static int
596 hammer2_sync_scan2(struct mount *mp, struct vnode *vp, void *data)
597 {
598         struct hammer2_sync_info *info = data;
599         hammer2_inode_t *ip;
600         int error;
601
602         ip = VTOI(vp);
603         if (vp->v_type == VNON || vp->v_type == VBAD ||
604             ((ip->chain.flags & HAMMER2_CHAIN_MODIFIED) == 0 &&
605              RB_EMPTY(&vp->v_rbdirty_tree))) {
606                 return(0);
607         }
608         error = VOP_FSYNC(vp, MNT_NOWAIT, 0);
609         if (error)
610                 info->error = error;
611         return(0);
612 }
613
614 static
615 int
616 hammer2_vfs_vptofh(struct vnode *vp, struct fid *fhp)
617 {
618         return (0);
619 }
620
621 static
622 int
623 hammer2_vfs_fhtovp(struct mount *mp, struct vnode *rootvp,
624                struct fid *fhp, struct vnode **vpp)
625 {
626         return (0);
627 }
628
629 static
630 int
631 hammer2_vfs_checkexp(struct mount *mp, struct sockaddr *nam,
632                  int *exflagsp, struct ucred **credanonp)
633 {
634         return (0);
635 }
636
637 /*
638  * Support code for hammer2_mount().  Read, verify, and install the volume
639  * header into the HMP
640  *
641  * XXX read four volhdrs and use the one with the highest TID whos CRC
642  *     matches.
643  *
644  * XXX check iCRCs.
645  *
646  * XXX For filesystems w/ less than 4 volhdrs, make sure to not write to
647  *     nonexistant locations.
648  *
649  * XXX Record selected volhdr and ring updates to each of 4 volhdrs
650  */
651 static
652 int
653 hammer2_install_volume_header(hammer2_mount_t *hmp)
654 {
655         hammer2_volume_data_t *vd;
656         struct buf *bp;
657         hammer2_crc32_t ccrc, crc;
658         int error_reported;
659         int error;
660         int valid;
661         int i;
662
663         error_reported = 0;
664         error = 0;
665         valid = 0;
666         bp = NULL;
667
668         /*
669          * There are up to 4 copies of the volume header (syncs iterate
670          * between them so there is no single master).  We don't trust the
671          * volu_size field so we don't know precisely how large the filesystem
672          * is, so depend on the OS to return an error if we go beyond the
673          * block device's EOF.
674          */
675         for (i = 0; i < HAMMER2_NUM_VOLHDRS; i++) {
676                 error = bread(hmp->devvp, i * HAMMER2_RESERVE_BYTES64, 
677                               HAMMER2_VOLUME_BYTES, &bp);
678                 if (error) {
679                         brelse(bp);
680                         bp = NULL;
681                         continue;
682                 }
683
684                 vd = (struct hammer2_volume_data *)bp->b_data;
685                 if (vd->magic != HAMMER2_VOLUME_ID_HBO) 
686                         continue;
687
688                 crc = vd->icrc_sects[HAMMER2_VOL_ICRC_SECT0];
689                 ccrc = hammer2_icrc32(bp->b_data + HAMMER2_VOLUME_ICRC0_OFF,
690                                       HAMMER2_VOLUME_ICRC0_SIZE);
691                 if (ccrc != crc) {
692                         kprintf("hammer2 volume header crc "
693                                 "mismatch copy #%d\t%08x %08x",
694                                 i, ccrc, crc);
695                         error_reported = 1;
696                         brelse(bp);
697                         bp = NULL;
698                         continue;
699                 }
700                 if (valid == 0 || hmp->voldata.last_tid < vd->last_tid) {
701                         valid = 1;
702                         hmp->voldata = *vd;
703                 }
704                 brelse(bp);
705                 bp = NULL;
706         }
707         if (valid) {
708                 error = 0;
709                 if (error_reported)
710                         kprintf("hammer2: a valid volume header was found\n");
711         } else {
712                 error = EINVAL;
713                 kprintf("hammer2: no valid volume headers found!\n");
714         }
715         return (error);
716 }
717