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