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