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 #include <sys/sysctl.h>
45
46 #include "hammer2.h"
47 #include "hammer2_disk.h"
48 #include "hammer2_mount.h"
49
50 struct hammer2_sync_info {
51         int error;
52         int waitfor;
53 };
54
55 TAILQ_HEAD(hammer2_mntlist, hammer2_mount);
56 static struct hammer2_mntlist hammer2_mntlist;
57 static struct lock hammer2_mntlk;
58
59 int hammer2_debug;
60 int hammer2_cluster_enable = 1;
61 long hammer2_iod_file_read;
62 long hammer2_iod_meta_read;
63 long hammer2_iod_indr_read;
64 long hammer2_iod_file_write;
65 long hammer2_iod_meta_write;
66 long hammer2_iod_indr_write;
67 long hammer2_iod_volu_write;
68 long hammer2_ioa_file_read;
69 long hammer2_ioa_meta_read;
70 long hammer2_ioa_indr_read;
71 long hammer2_ioa_file_write;
72 long hammer2_ioa_meta_write;
73 long hammer2_ioa_indr_write;
74 long hammer2_ioa_volu_write;
75
76 SYSCTL_NODE(_vfs, OID_AUTO, hammer2, CTLFLAG_RW, 0, "HAMMER2 filesystem");
77
78 SYSCTL_INT(_vfs_hammer2, OID_AUTO, debug, CTLFLAG_RW,
79            &hammer2_debug, 0, "");
80 SYSCTL_INT(_vfs_hammer2, OID_AUTO, cluster_enable, CTLFLAG_RW,
81            &hammer2_cluster_enable, 0, "");
82 SYSCTL_LONG(_vfs_hammer2, OID_AUTO, iod_file_read, CTLFLAG_RW,
83            &hammer2_iod_file_read, 0, "");
84 SYSCTL_LONG(_vfs_hammer2, OID_AUTO, iod_meta_read, CTLFLAG_RW,
85            &hammer2_iod_meta_read, 0, "");
86 SYSCTL_LONG(_vfs_hammer2, OID_AUTO, iod_indr_read, CTLFLAG_RW,
87            &hammer2_iod_indr_read, 0, "");
88 SYSCTL_LONG(_vfs_hammer2, OID_AUTO, iod_file_write, CTLFLAG_RW,
89            &hammer2_iod_file_write, 0, "");
90 SYSCTL_LONG(_vfs_hammer2, OID_AUTO, iod_meta_write, CTLFLAG_RW,
91            &hammer2_iod_meta_write, 0, "");
92 SYSCTL_LONG(_vfs_hammer2, OID_AUTO, iod_indr_write, CTLFLAG_RW,
93            &hammer2_iod_indr_write, 0, "");
94 SYSCTL_LONG(_vfs_hammer2, OID_AUTO, iod_volu_write, CTLFLAG_RW,
95            &hammer2_iod_volu_write, 0, "");
96 SYSCTL_LONG(_vfs_hammer2, OID_AUTO, ioa_file_read, CTLFLAG_RW,
97            &hammer2_ioa_file_read, 0, "");
98 SYSCTL_LONG(_vfs_hammer2, OID_AUTO, ioa_meta_read, CTLFLAG_RW,
99            &hammer2_ioa_meta_read, 0, "");
100 SYSCTL_LONG(_vfs_hammer2, OID_AUTO, ioa_indr_read, CTLFLAG_RW,
101            &hammer2_ioa_indr_read, 0, "");
102 SYSCTL_LONG(_vfs_hammer2, OID_AUTO, ioa_file_write, CTLFLAG_RW,
103            &hammer2_ioa_file_write, 0, "");
104 SYSCTL_LONG(_vfs_hammer2, OID_AUTO, ioa_meta_write, CTLFLAG_RW,
105            &hammer2_ioa_meta_write, 0, "");
106 SYSCTL_LONG(_vfs_hammer2, OID_AUTO, ioa_indr_write, CTLFLAG_RW,
107            &hammer2_ioa_indr_write, 0, "");
108 SYSCTL_LONG(_vfs_hammer2, OID_AUTO, ioa_volu_write, CTLFLAG_RW,
109            &hammer2_ioa_volu_write, 0, "");
110
111 static int hammer2_vfs_init(struct vfsconf *conf);
112 static int hammer2_vfs_mount(struct mount *mp, char *path, caddr_t data,
113                                 struct ucred *cred);
114 static int hammer2_remount(struct mount *, char *, struct vnode *,
115                                 struct ucred *);
116 static int hammer2_vfs_unmount(struct mount *mp, int mntflags);
117 static int hammer2_vfs_root(struct mount *mp, struct vnode **vpp);
118 static int hammer2_vfs_statfs(struct mount *mp, struct statfs *sbp,
119                                 struct ucred *cred);
120 static int hammer2_vfs_statvfs(struct mount *mp, struct statvfs *sbp,
121                                 struct ucred *cred);
122 static int hammer2_vfs_sync(struct mount *mp, int waitfor);
123 static int hammer2_vfs_vget(struct mount *mp, struct vnode *dvp,
124                                 ino_t ino, struct vnode **vpp);
125 static int hammer2_vfs_fhtovp(struct mount *mp, struct vnode *rootvp,
126                                 struct fid *fhp, struct vnode **vpp);
127 static int hammer2_vfs_vptofh(struct vnode *vp, struct fid *fhp);
128 static int hammer2_vfs_checkexp(struct mount *mp, struct sockaddr *nam,
129                                 int *exflagsp, struct ucred **credanonp);
130
131 static int hammer2_install_volume_header(hammer2_mount_t *hmp);
132 static int hammer2_sync_scan1(struct mount *mp, struct vnode *vp, void *data);
133 static int hammer2_sync_scan2(struct mount *mp, struct vnode *vp, void *data);
134
135 /*
136  * HAMMER2 vfs operations.
137  */
138 static struct vfsops hammer2_vfsops = {
139         .vfs_init       = hammer2_vfs_init,
140         .vfs_sync       = hammer2_vfs_sync,
141         .vfs_mount      = hammer2_vfs_mount,
142         .vfs_unmount    = hammer2_vfs_unmount,
143         .vfs_root       = hammer2_vfs_root,
144         .vfs_statfs     = hammer2_vfs_statfs,
145         .vfs_statvfs    = hammer2_vfs_statvfs,
146         .vfs_vget       = hammer2_vfs_vget,
147         .vfs_vptofh     = hammer2_vfs_vptofh,
148         .vfs_fhtovp     = hammer2_vfs_fhtovp,
149         .vfs_checkexp   = hammer2_vfs_checkexp
150 };
151
152 MALLOC_DEFINE(M_HAMMER2, "HAMMER2-mount", "");
153
154 VFS_SET(hammer2_vfsops, hammer2, 0);
155 MODULE_VERSION(hammer2, 1);
156
157 static
158 int
159 hammer2_vfs_init(struct vfsconf *conf)
160 {
161         int error;
162
163         error = 0;
164
165         if (HAMMER2_BLOCKREF_BYTES != sizeof(struct hammer2_blockref))
166                 error = EINVAL;
167         if (HAMMER2_INODE_BYTES != sizeof(struct hammer2_inode_data))
168                 error = EINVAL;
169         if (HAMMER2_ALLOCREF_BYTES != sizeof(struct hammer2_allocref))
170                 error = EINVAL;
171         if (HAMMER2_VOLUME_BYTES != sizeof(struct hammer2_volume_data))
172                 error = EINVAL;
173
174         if (error)
175                 kprintf("HAMMER2 structure size mismatch; cannot continue.\n");
176
177         lockinit(&hammer2_mntlk, "mntlk", 0, 0);
178         TAILQ_INIT(&hammer2_mntlist);
179
180         return (error);
181 }
182
183 /*
184  * Mount or remount HAMMER2 fileystem from physical media
185  *
186  *      mountroot
187  *              mp              mount point structure
188  *              path            NULL
189  *              data            <unused>
190  *              cred            <unused>
191  *
192  *      mount
193  *              mp              mount point structure
194  *              path            path to mount point
195  *              data            pointer to argument structure in user space
196  *                      volume  volume path (device@LABEL form)
197  *                      hflags  user mount flags
198  *              cred            user credentials
199  *
200  * RETURNS:     0       Success
201  *              !0      error number
202  */
203 static
204 int
205 hammer2_vfs_mount(struct mount *mp, char *path, caddr_t data,
206               struct ucred *cred)
207 {
208         struct hammer2_mount_info info;
209         hammer2_pfsmount_t *pmp;
210         hammer2_mount_t *hmp;
211         hammer2_key_t lhc;
212         struct vnode *devvp;
213         struct nlookupdata nd;
214         hammer2_chain_t *parent;
215         hammer2_chain_t *schain;
216         hammer2_chain_t *rchain;
217         char devstr[MNAMELEN];
218         size_t size;
219         size_t done;
220         char *dev;
221         char *label;
222         int ronly = 1;
223         int create_hmp;
224         int error;
225
226         hmp = NULL;
227         pmp = NULL;
228         dev = NULL;
229         label = NULL;
230         devvp = NULL;
231
232         kprintf("hammer2_mount\n");
233
234         if (path == NULL) {
235                 /*
236                  * Root mount
237                  */
238                 return (EOPNOTSUPP);
239         } else {
240                 /*
241                  * Non-root mount or updating a mount
242                  */
243                 error = copyin(data, &info, sizeof(info));
244                 if (error)
245                         return (error);
246
247                 error = copyinstr(info.volume, devstr, MNAMELEN - 1, &done);
248                 if (error)
249                         return (error);
250
251                 /* Extract device and label */
252                 dev = devstr;
253                 label = strchr(devstr, '@');
254                 if (label == NULL ||
255                     ((label + 1) - dev) > done) {
256                         return (EINVAL);
257                 }
258                 *label = '\0';
259                 label++;
260                 if (*label == '\0')
261                         return (EINVAL);
262
263                 if (mp->mnt_flag & MNT_UPDATE) {
264                         /* Update mount */
265                         /* HAMMER2 implements NFS export via mountctl */
266                         hmp = MPTOHMP(mp);
267                         devvp = hmp->devvp;
268                         error = hammer2_remount(mp, path, devvp, cred);
269                         return error;
270                 }
271         }
272
273         /*
274          * New non-root mount
275          */
276         /* Lookup name and verify it refers to a block device */
277         error = nlookup_init(&nd, dev, UIO_SYSSPACE, NLC_FOLLOW);
278         if (error == 0)
279                 error = nlookup(&nd);
280         if (error == 0)
281                 error = cache_vref(&nd.nl_nch, nd.nl_cred, &devvp);
282         nlookup_done(&nd);
283
284         if (error == 0) {
285                 if (vn_isdisk(devvp, &error))
286                         error = vfs_mountedon(devvp);
287         }
288
289         /*
290          * Determine if the device has already been mounted.  After this
291          * check hmp will be non-NULL if we are doing the second or more
292          * hammer2 mounts from the same device.
293          */
294         lockmgr(&hammer2_mntlk, LK_EXCLUSIVE);
295         TAILQ_FOREACH(hmp, &hammer2_mntlist, mntentry) {
296                 if (hmp->devvp == devvp)
297                         break;
298         }
299
300         /*
301          * Open the device if this isn't a secondary mount
302          */
303         if (hmp) {
304                 create_hmp = 0;
305         } else {
306                 create_hmp = 1;
307                 if (error == 0 && vcount(devvp) > 0)
308                         error = EBUSY;
309
310                 /*
311                  * Now open the device
312                  */
313                 if (error == 0) {
314                         ronly = ((mp->mnt_flag & MNT_RDONLY) != 0);
315                         vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
316                         error = vinvalbuf(devvp, V_SAVE, 0, 0);
317                         if (error == 0) {
318                                 error = VOP_OPEN(devvp,
319                                                  ronly ? FREAD : FREAD | FWRITE,
320                                                  FSCRED, NULL);
321                         }
322                         vn_unlock(devvp);
323                 }
324                 if (error && devvp) {
325                         vrele(devvp);
326                         devvp = NULL;
327                 }
328                 if (error) {
329                         lockmgr(&hammer2_mntlk, LK_RELEASE);
330                         return error;
331                 }
332         }
333
334         /*
335          * Block device opened successfully, finish initializing the
336          * mount structure.
337          *
338          * From this point on we have to call hammer2_unmount() on failure.
339          */
340         pmp = kmalloc(sizeof(*pmp), M_HAMMER2, M_WAITOK | M_ZERO);
341         mp->mnt_data = (qaddr_t)pmp;
342         pmp->mp = mp;
343
344         if (create_hmp) {
345                 hmp = kmalloc(sizeof(*hmp), M_HAMMER2, M_WAITOK | M_ZERO);
346                 hmp->ronly = ronly;
347                 hmp->devvp = devvp;
348                 kmalloc_create(&hmp->minode, "HAMMER2-inodes");
349                 kmalloc_create(&hmp->mchain, "HAMMER2-chains");
350                 TAILQ_INSERT_TAIL(&hammer2_mntlist, hmp, mntentry);
351         }
352         pmp->hmp = hmp;
353         ++hmp->pmp_count;
354         lockmgr(&hammer2_mntlk, LK_RELEASE);
355         kprintf("hammer2_mount hmp=%p pmpcnt=%d\n", hmp, hmp->pmp_count);
356         
357         mp->mnt_flag = MNT_LOCAL;
358         mp->mnt_kern_flag |= MNTK_ALL_MPSAFE;   /* all entry pts are SMP */
359
360         if (create_hmp) {
361                 /*
362                  * vchain setup. vchain.data is special cased to NULL.
363                  * vchain.refs is initialized and will never drop to 0.
364                  */
365                 hmp->vchain.bref.type = HAMMER2_BREF_TYPE_VOLUME;
366                 hmp->vchain.refs = 1;
367                 hmp->vchain.data = (void *)&hmp->voldata;
368                 hmp->vchain.bref.data_off = 0 | HAMMER2_PBUFRADIX;
369                 /* hmp->vchain.u.xxx is left NULL */
370                 lockinit(&hmp->vchain.lk, "volume", 0, LK_CANRECURSE);
371                 lockinit(&hmp->alloclk, "h2alloc", 0, 0);
372                 lockinit(&hmp->voldatalk, "voldata", 0, LK_CANRECURSE);
373
374                 /*
375                  * Install the volume header
376                  */
377                 error = hammer2_install_volume_header(hmp);
378                 if (error) {
379                         hammer2_vfs_unmount(mp, MNT_FORCE);
380                         return error;
381                 }
382         }
383
384         /*
385          * required mount structure initializations
386          */
387         mp->mnt_stat.f_iosize = HAMMER2_PBUFSIZE;
388         mp->mnt_stat.f_bsize = HAMMER2_PBUFSIZE;
389
390         mp->mnt_vstat.f_frsize = HAMMER2_PBUFSIZE;
391         mp->mnt_vstat.f_bsize = HAMMER2_PBUFSIZE;
392
393         /*
394          * Optional fields
395          */
396         mp->mnt_iosize_max = MAXPHYS;
397
398         /*
399          * First locate the super-root inode, which is key 0 relative to the
400          * volume header's blockset.
401          *
402          * Then locate the root inode by scanning the directory keyspace
403          * represented by the label.
404          */
405         if (create_hmp) {
406                 parent = &hmp->vchain;
407                 hammer2_chain_lock(hmp, parent, HAMMER2_RESOLVE_ALWAYS);
408                 schain = hammer2_chain_lookup(hmp, &parent,
409                                       HAMMER2_SROOT_KEY, HAMMER2_SROOT_KEY, 0);
410                 hammer2_chain_unlock(hmp, parent);
411                 if (schain == NULL) {
412                         kprintf("hammer2_mount: invalid super-root\n");
413                         hammer2_vfs_unmount(mp, MNT_FORCE);
414                         return EINVAL;
415                 }
416                 hammer2_chain_ref(hmp, schain); /* for hmp->schain */
417                 hmp->schain = schain;           /* left locked */
418         } else {
419                 schain = hmp->schain;
420                 hammer2_chain_lock(hmp, schain, HAMMER2_RESOLVE_ALWAYS);
421         }
422
423         parent = schain;
424         lhc = hammer2_dirhash(label, strlen(label));
425         rchain = hammer2_chain_lookup(hmp, &parent,
426                                       lhc, lhc + HAMMER2_DIRHASH_LOMASK,
427                                       0);
428         while (rchain) {
429                 if (rchain->bref.type == HAMMER2_BREF_TYPE_INODE &&
430                     rchain->u.ip &&
431                     strcmp(label, rchain->data->ipdata.filename) == 0) {
432                         break;
433                 }
434                 rchain = hammer2_chain_next(hmp, &parent, rchain,
435                                             lhc, lhc + HAMMER2_DIRHASH_LOMASK,
436                                             0);
437         }
438         hammer2_chain_unlock(hmp, parent);
439         if (rchain == NULL) {
440                 kprintf("hammer2_mount: PFS label not found\n");
441                 hammer2_vfs_unmount(mp, MNT_FORCE);
442                 return EINVAL;
443         }
444         if (rchain->flags & HAMMER2_CHAIN_MOUNTED) {
445                 hammer2_chain_unlock(hmp, rchain);
446                 kprintf("hammer2_mount: PFS label already mounted!\n");
447                 hammer2_vfs_unmount(mp, MNT_FORCE);
448                 return EINVAL;
449         }
450         atomic_set_int(&rchain->flags, HAMMER2_CHAIN_MOUNTED);
451
452         hammer2_chain_ref(hmp, rchain); /* for pmp->rchain */
453         hammer2_chain_unlock(hmp, rchain);
454         pmp->rchain = rchain;           /* left held & unlocked */
455         pmp->iroot = rchain->u.ip;      /* implied hold from rchain */
456         pmp->iroot->pmp = pmp;
457         kprintf("iroot %p\n", pmp->iroot);
458
459         vfs_getnewfsid(mp);
460         vfs_add_vnodeops(mp, &hammer2_vnode_vops, &mp->mnt_vn_norm_ops);
461         vfs_add_vnodeops(mp, &hammer2_spec_vops, &mp->mnt_vn_spec_ops);
462         vfs_add_vnodeops(mp, &hammer2_fifo_vops, &mp->mnt_vn_fifo_ops);
463
464         copyinstr(info.volume, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size);
465         bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
466         bzero(mp->mnt_stat.f_mntonname, sizeof(mp->mnt_stat.f_mntonname));
467         copyinstr(path, mp->mnt_stat.f_mntonname,
468                   sizeof(mp->mnt_stat.f_mntonname) - 1,
469                   &size);
470
471         hammer2_vfs_statfs(mp, &mp->mnt_stat, cred);
472
473         return 0;
474 }
475
476 static
477 int
478 hammer2_remount(struct mount *mp, char *path, struct vnode *devvp,
479                 struct ucred *cred)
480 {
481         return (0);
482 }
483
484 static
485 int
486 hammer2_vfs_unmount(struct mount *mp, int mntflags)
487 {
488         hammer2_pfsmount_t *pmp;
489         hammer2_mount_t *hmp;
490         int flags;
491         int error = 0;
492         int ronly = ((mp->mnt_flag & MNT_RDONLY) != 0);
493         struct vnode *devvp;
494
495         pmp = MPTOPMP(mp);
496         hmp = pmp->hmp;
497         flags = 0;
498
499         if (mntflags & MNT_FORCE)
500                 flags |= FORCECLOSE;
501
502         hammer2_mount_exlock(hmp);
503
504         /*
505          * If mount initialization proceeded far enough we must flush
506          * its vnodes.
507          */
508         if (pmp->iroot)
509                 error = vflush(mp, 0, flags);
510
511         if (error)
512                 return error;
513
514         lockmgr(&hammer2_mntlk, LK_EXCLUSIVE);
515         --hmp->pmp_count;
516         kprintf("hammer2_unmount hmp=%p pmpcnt=%d\n", hmp, hmp->pmp_count);
517
518         /*
519          * Flush any left over chains.  The voldata lock is only used
520          * to synchronize against HAMMER2_CHAIN_MODIFIED_AUX.
521          */
522         hammer2_voldata_lock(hmp);
523         if (hmp->vchain.flags & (HAMMER2_CHAIN_MODIFIED |
524                                  HAMMER2_CHAIN_MODIFIED_AUX |
525                                  HAMMER2_CHAIN_SUBMODIFIED)) {
526                 hammer2_voldata_unlock(hmp);
527                 hammer2_vfs_sync(mp, MNT_WAIT);
528         } else {
529                 hammer2_voldata_unlock(hmp);
530         }
531         if (hmp->pmp_count == 0) {
532                 if (hmp->vchain.flags & (HAMMER2_CHAIN_MODIFIED |
533                                          HAMMER2_CHAIN_MODIFIED_AUX |
534                                          HAMMER2_CHAIN_SUBMODIFIED)) {
535                         kprintf("hammer2_unmount: chains left over after "
536                                 "final sync\n");
537                         if (hammer2_debug & 0x0010)
538                                 Debugger("entered debugger");
539                 }
540         }
541
542         /*
543          * Cleanup the root and super-root chain elements (which should be
544          * clean).
545          */
546         pmp->iroot = NULL;
547         if (pmp->rchain) {
548                 atomic_clear_int(&pmp->rchain->flags, HAMMER2_CHAIN_MOUNTED);
549                 KKASSERT(pmp->rchain->refs == 1);
550                 hammer2_chain_drop(hmp, pmp->rchain);
551                 pmp->rchain = NULL;
552         }
553         if (hmp->pmp_count == 0) {
554                 if (hmp->schain) {
555                         KKASSERT(hmp->schain->refs == 1);
556                         hammer2_chain_drop(hmp, hmp->schain);
557                         hmp->schain = NULL;
558                 }
559
560                 /*
561                  * Finish up with the device vnode
562                  */
563                 if ((devvp = hmp->devvp) != NULL) {
564                         vinvalbuf(devvp, (ronly ? 0 : V_SAVE), 0, 0);
565                         hmp->devvp = NULL;
566                         VOP_CLOSE(devvp, (ronly ? FREAD : FREAD|FWRITE));
567                         vrele(devvp);
568                         devvp = NULL;
569                 }
570                 kmalloc_destroy(&hmp->minode);
571                 kmalloc_destroy(&hmp->mchain);
572         }
573         hammer2_mount_unlock(hmp);
574
575         pmp->mp = NULL;
576         pmp->hmp = NULL;
577         mp->mnt_data = NULL;
578
579         kfree(pmp, M_HAMMER2);
580         if (hmp->pmp_count == 0) {
581                 TAILQ_REMOVE(&hammer2_mntlist, hmp, mntentry);
582                 kfree(hmp, M_HAMMER2);
583         }
584         lockmgr(&hammer2_mntlk, LK_RELEASE);
585         return (error);
586 }
587
588 static
589 int
590 hammer2_vfs_vget(struct mount *mp, struct vnode *dvp,
591              ino_t ino, struct vnode **vpp)
592 {
593         kprintf("hammer2_vget\n");
594         return (EOPNOTSUPP);
595 }
596
597 static
598 int
599 hammer2_vfs_root(struct mount *mp, struct vnode **vpp)
600 {
601         hammer2_pfsmount_t *pmp;
602         int error;
603         struct vnode *vp;
604
605         pmp = MPTOPMP(mp);
606         hammer2_mount_exlock(pmp->hmp);
607         if (pmp->iroot == NULL) {
608                 *vpp = NULL;
609                 error = EINVAL;
610         } else {
611                 vp = hammer2_igetv(pmp->iroot, &error);
612                 *vpp = vp;
613                 if (vp == NULL)
614                         kprintf("vnodefail\n");
615         }
616         hammer2_mount_unlock(pmp->hmp);
617
618         return (error);
619 }
620
621 static
622 int
623 hammer2_vfs_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred)
624 {
625         hammer2_mount_t *hmp;
626
627         hmp = MPTOHMP(mp);
628
629         mp->mnt_stat.f_files = 10;
630         mp->mnt_stat.f_bfree = 10;
631         mp->mnt_stat.f_bavail = mp->mnt_stat.f_bfree;
632
633         *sbp = mp->mnt_stat;
634         return (0);
635 }
636
637 static
638 int
639 hammer2_vfs_statvfs(struct mount *mp, struct statvfs *sbp, struct ucred *cred)
640 {
641         hammer2_mount_t *hmp;
642
643         hmp = MPTOHMP(mp);
644
645         mp->mnt_vstat.f_bsize = HAMMER2_PBUFSIZE;
646         mp->mnt_vstat.f_files = 0;
647         mp->mnt_vstat.f_bavail = mp->mnt_stat.f_bfree;
648
649         *sbp = mp->mnt_vstat;
650         return (0);
651 }
652
653 /*
654  * Sync the entire filesystem; this is called from the filesystem syncer
655  * process periodically and whenever a user calls sync(1) on the hammer
656  * mountpoint.
657  *
658  * Currently is actually called from the syncer! \o/
659  *
660  * This task will have to snapshot the state of the dirty inode chain.
661  * From that, it will have to make sure all of the inodes on the dirty
662  * chain have IO initiated. We make sure that io is initiated for the root
663  * block.
664  *
665  * If waitfor is set, we wait for media to acknowledge the new rootblock.
666  *
667  * THINKS: side A vs side B, to have sync not stall all I/O?
668  */
669 static
670 int
671 hammer2_vfs_sync(struct mount *mp, int waitfor)
672 {
673         struct hammer2_sync_info info;
674         hammer2_mount_t *hmp;
675         int flags;
676         int error;
677         int haswork;
678
679         hmp = MPTOHMP(mp);
680
681         flags = VMSC_GETVP;
682         if (waitfor & MNT_LAZY)
683                 flags |= VMSC_ONEPASS;
684
685         info.error = 0;
686         info.waitfor = MNT_NOWAIT;
687         vmntvnodescan(mp, flags | VMSC_NOWAIT,
688                       hammer2_sync_scan1,
689                       hammer2_sync_scan2, &info);
690         if (info.error == 0 && (waitfor & MNT_WAIT)) {
691                 info.waitfor = waitfor;
692                     vmntvnodescan(mp, flags,
693                                   hammer2_sync_scan1,
694                                   hammer2_sync_scan2, &info);
695
696         }
697 #if 0
698         if (waitfor == MNT_WAIT) {
699                 /* XXX */
700         } else {
701                 /* XXX */
702         }
703 #endif
704         hammer2_chain_lock(hmp, &hmp->vchain, HAMMER2_RESOLVE_ALWAYS);
705         if (hmp->vchain.flags & (HAMMER2_CHAIN_MODIFIED |
706                                  HAMMER2_CHAIN_MODIFIED_AUX |
707                                  HAMMER2_CHAIN_SUBMODIFIED)) {
708                 hammer2_chain_flush(hmp, &hmp->vchain);
709                 haswork = 1;
710         } else {
711                 haswork = 0;
712         }
713         hammer2_chain_unlock(hmp, &hmp->vchain);
714
715         error = 0;
716
717         if ((waitfor & MNT_LAZY) == 0) {
718                 waitfor = MNT_NOWAIT;
719                 vn_lock(hmp->devvp, LK_EXCLUSIVE | LK_RETRY);
720                 error = VOP_FSYNC(hmp->devvp, waitfor, 0);
721                 vn_unlock(hmp->devvp);
722         }
723
724         if (error == 0 && haswork) {
725                 struct buf *bp;
726
727                 /*
728                  * Synchronize the disk before flushing the volume
729                  * header.
730                  */
731                 bp = getpbuf(NULL);
732                 bp->b_bio1.bio_offset = 0;
733                 bp->b_bufsize = 0;
734                 bp->b_bcount = 0;
735                 bp->b_cmd = BUF_CMD_FLUSH;
736                 bp->b_bio1.bio_done = biodone_sync;
737                 bp->b_bio1.bio_flags |= BIO_SYNC;
738                 vn_strategy(hmp->devvp, &bp->b_bio1);
739                 biowait(&bp->b_bio1, "h2vol");
740                 relpbuf(bp, NULL);
741
742                 /*
743                  * Then we can safely flush the volume header.  Volume
744                  * data is locked separately to prevent ioctl functions
745                  * from deadlocking due to a configuration issue.
746                  */
747                 bp = getblk(hmp->devvp, 0, HAMMER2_PBUFSIZE, 0, 0);
748                 hammer2_voldata_lock(hmp);
749                 bcopy(&hmp->voldata, bp->b_data, HAMMER2_PBUFSIZE);
750                 hammer2_voldata_unlock(hmp);
751                 bawrite(bp);
752         }
753         return (error);
754 }
755
756 /*
757  * Sync passes.
758  *
759  * NOTE: We don't test SUBMODIFIED or MOVED here because the fsync code
760  *       won't flush on those flags.  The syncer code above will do a
761  *       general meta-data flush globally that will catch these flags.
762  */
763 static int
764 hammer2_sync_scan1(struct mount *mp, struct vnode *vp, void *data)
765 {
766         hammer2_inode_t *ip;
767
768         ip = VTOI(vp);
769         if (vp->v_type == VNON || ip == NULL ||
770             ((ip->chain.flags & (HAMMER2_CHAIN_MODIFIED |
771                                  HAMMER2_CHAIN_DIRTYEMBED)) == 0 &&
772              RB_EMPTY(&vp->v_rbdirty_tree))) {
773                 return(-1);
774         }
775         return(0);
776 }
777
778 static int
779 hammer2_sync_scan2(struct mount *mp, struct vnode *vp, void *data)
780 {
781         struct hammer2_sync_info *info = data;
782         hammer2_inode_t *ip;
783         int error;
784
785         ip = VTOI(vp);
786         if (vp->v_type == VNON || vp->v_type == VBAD ||
787             ((ip->chain.flags & (HAMMER2_CHAIN_MODIFIED |
788                                  HAMMER2_CHAIN_DIRTYEMBED)) == 0 &&
789             RB_EMPTY(&vp->v_rbdirty_tree))) {
790                 return(0);
791         }
792         error = VOP_FSYNC(vp, MNT_NOWAIT, 0);
793         if (error)
794                 info->error = error;
795         return(0);
796 }
797
798 static
799 int
800 hammer2_vfs_vptofh(struct vnode *vp, struct fid *fhp)
801 {
802         return (0);
803 }
804
805 static
806 int
807 hammer2_vfs_fhtovp(struct mount *mp, struct vnode *rootvp,
808                struct fid *fhp, struct vnode **vpp)
809 {
810         return (0);
811 }
812
813 static
814 int
815 hammer2_vfs_checkexp(struct mount *mp, struct sockaddr *nam,
816                  int *exflagsp, struct ucred **credanonp)
817 {
818         return (0);
819 }
820
821 /*
822  * Support code for hammer2_mount().  Read, verify, and install the volume
823  * header into the HMP
824  *
825  * XXX read four volhdrs and use the one with the highest TID whos CRC
826  *     matches.
827  *
828  * XXX check iCRCs.
829  *
830  * XXX For filesystems w/ less than 4 volhdrs, make sure to not write to
831  *     nonexistant locations.
832  *
833  * XXX Record selected volhdr and ring updates to each of 4 volhdrs
834  */
835 static
836 int
837 hammer2_install_volume_header(hammer2_mount_t *hmp)
838 {
839         hammer2_volume_data_t *vd;
840         struct buf *bp;
841         hammer2_crc32_t crc0, crc, bcrc0, bcrc;
842         int error_reported;
843         int error;
844         int valid;
845         int i;
846
847         error_reported = 0;
848         error = 0;
849         valid = 0;
850         bp = NULL;
851
852         /*
853          * There are up to 4 copies of the volume header (syncs iterate
854          * between them so there is no single master).  We don't trust the
855          * volu_size field so we don't know precisely how large the filesystem
856          * is, so depend on the OS to return an error if we go beyond the
857          * block device's EOF.
858          */
859         for (i = 0; i < HAMMER2_NUM_VOLHDRS; i++) {
860                 error = bread(hmp->devvp, i * HAMMER2_RESERVE_BYTES64, 
861                               HAMMER2_VOLUME_BYTES, &bp);
862                 if (error) {
863                         brelse(bp);
864                         bp = NULL;
865                         continue;
866                 }
867
868                 vd = (struct hammer2_volume_data *) bp->b_data;
869                 if ((vd->magic != HAMMER2_VOLUME_ID_HBO) &&
870                     (vd->magic != HAMMER2_VOLUME_ID_ABO)) {
871                         brelse(bp);
872                         bp = NULL;
873                         continue;
874                 }
875
876                 if (vd->magic == HAMMER2_VOLUME_ID_ABO) {
877                         /* XXX: Reversed-endianness filesystem */
878                         kprintf("hammer2: reverse-endian filesystem detected");
879                         brelse(bp);
880                         bp = NULL;
881                         continue;
882                 }
883
884                 crc = vd->icrc_sects[HAMMER2_VOL_ICRC_SECT0];
885                 crc0 = hammer2_icrc32(bp->b_data + HAMMER2_VOLUME_ICRC0_OFF,
886                                       HAMMER2_VOLUME_ICRC0_SIZE);
887                 bcrc = vd->icrc_sects[HAMMER2_VOL_ICRC_SECT1];
888                 bcrc0 = hammer2_icrc32(bp->b_data + HAMMER2_VOLUME_ICRC1_OFF,
889                                        HAMMER2_VOLUME_ICRC1_SIZE);
890                 if ((crc0 != crc) || (bcrc0 != bcrc)) {
891                         kprintf("hammer2 volume header crc "
892                                 "mismatch copy #%d\t%08x %08x",
893                                 i, crc0, crc);
894                         error_reported = 1;
895                         brelse(bp);
896                         bp = NULL;
897                         continue;
898                 }
899                 if (valid == 0 || hmp->voldata.last_tid < vd->last_tid) {
900                         valid = 1;
901                         hmp->voldata = *vd;
902                 }
903                 brelse(bp);
904                 bp = NULL;
905         }
906         if (valid) {
907                 error = 0;
908                 if (error_reported)
909                         kprintf("hammer2: a valid volume header was found\n");
910         } else {
911                 error = EINVAL;
912                 kprintf("hammer2: no valid volume headers found!\n");
913         }
914         return (error);
915 }
916