hammer2 - correct icrc generation for sector 0
[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>
703720e4
MD
44
45#include "hammer2.h"
46#include "hammer2_disk.h"
47#include "hammer2_mount.h"
48
49static int hammer2_init(struct vfsconf *conf);
50static int hammer2_mount(struct mount *mp, char *path, caddr_t data,
51 struct ucred *cred);
52static int hammer2_remount(struct mount *, char *, struct vnode *,
53 struct ucred *);
54static int hammer2_unmount(struct mount *mp, int mntflags);
55static int hammer2_root(struct mount *mp, struct vnode **vpp);
56static int hammer2_statfs(struct mount *mp, struct statfs *sbp,
57 struct ucred *cred);
58static int hammer2_statvfs(struct mount *mp, struct statvfs *sbp,
59 struct ucred *cred);
60static int hammer2_sync(struct mount *mp, int waitfor);
61static int hammer2_vget(struct mount *mp, struct vnode *dvp,
62 ino_t ino, struct vnode **vpp);
63static int hammer2_fhtovp(struct mount *mp, struct vnode *rootvp,
64 struct fid *fhp, struct vnode **vpp);
65static int hammer2_vptofh(struct vnode *vp, struct fid *fhp);
66static int hammer2_checkexp(struct mount *mp, struct sockaddr *nam,
67 int *exflagsp, struct ucred **credanonp);
68
50e4f8f4
MD
69static int hammer2_install_volume_header(hammer2_mount_t *hmp);
70
703720e4
MD
71/*
72 * HAMMER2 vfs operations.
73 */
74static struct vfsops hammer2_vfsops = {
703720e4
MD
75 .vfs_init = hammer2_init,
76 .vfs_sync = hammer2_sync,
77 .vfs_mount = hammer2_mount,
78 .vfs_unmount = hammer2_unmount,
703720e4 79 .vfs_root = hammer2_root,
703720e4 80 .vfs_statfs = hammer2_statfs,
47902fef 81 .vfs_statvfs = hammer2_statvfs,
703720e4
MD
82 .vfs_vget = hammer2_vget,
83 .vfs_vptofh = hammer2_vptofh,
84 .vfs_fhtovp = hammer2_fhtovp,
85 .vfs_checkexp = hammer2_checkexp
86};
87
703720e4
MD
88MALLOC_DEFINE(M_HAMMER2, "HAMMER2-mount", "");
89
90VFS_SET(hammer2_vfsops, hammer2, 0);
91MODULE_VERSION(hammer2, 1);
92
e118c14f
MD
93static
94int
703720e4
MD
95hammer2_init(struct vfsconf *conf)
96{
97 int error;
98
99 error = 0;
100
0e92b724 101 if (HAMMER2_BLOCKREF_BYTES != sizeof(struct hammer2_blockref))
703720e4 102 error = EINVAL;
0e92b724 103 if (HAMMER2_INODE_BYTES != sizeof(struct hammer2_inode_data))
703720e4 104 error = EINVAL;
0e92b724 105 if (HAMMER2_ALLOCREF_BYTES != sizeof(struct hammer2_allocref))
703720e4 106 error = EINVAL;
0e92b724 107 if (HAMMER2_VOLUME_BYTES != sizeof(struct hammer2_volume_data))
703720e4
MD
108 error = EINVAL;
109
110 if (error)
111 kprintf("HAMMER2 structure size mismatch; cannot continue.\n");
112
113 return (error);
114}
115
116/*
117 * Mount or remount HAMMER2 fileystem from physical media
118 *
119 * mountroot
120 * mp mount point structure
121 * path NULL
122 * data <unused>
123 * cred <unused>
124 *
125 * mount
126 * mp mount point structure
127 * path path to mount point
128 * data pointer to argument structure in user space
129 * volume volume path (device@LABEL form)
130 * hflags user mount flags
131 * cred user credentials
132 *
133 * RETURNS: 0 Success
134 * !0 error number
135 */
e118c14f
MD
136static
137int
703720e4
MD
138hammer2_mount(struct mount *mp, char *path, caddr_t data,
139 struct ucred *cred)
140{
141 struct hammer2_mount_info info;
54eb943b 142 hammer2_mount_t *hmp;
703720e4
MD
143 struct vnode *devvp;
144 struct nlookupdata nd;
145 char devstr[MNAMELEN];
146 size_t size;
147 size_t done;
50e4f8f4
MD
148 char *dev;
149 char *label;
54eb943b 150 int ronly = 1;
703720e4 151 int error;
703720e4
MD
152
153 hmp = NULL;
50e4f8f4
MD
154 dev = NULL;
155 label = NULL;
703720e4
MD
156 devvp = NULL;
157
158 kprintf("hammer2_mount\n");
159
160 if (path == NULL) {
161 /*
162 * Root mount
163 */
703720e4
MD
164 return (EOPNOTSUPP);
165 } else {
166 /*
167 * Non-root mount or updating a mount
168 */
703720e4
MD
169 error = copyin(data, &info, sizeof(info));
170 if (error)
171 return (error);
172
173 error = copyinstr(info.volume, devstr, MNAMELEN - 1, &done);
174 if (error)
175 return (error);
176
177 /* Extract device and label */
178 dev = devstr;
179 label = strchr(devstr, '@');
180 if (label == NULL ||
50e4f8f4 181 ((label + 1) - dev) > done) {
703720e4 182 return (EINVAL);
50e4f8f4 183 }
703720e4
MD
184 *label = '\0';
185 label++;
186 if (*label == '\0')
187 return (EINVAL);
188
189 if (mp->mnt_flag & MNT_UPDATE) {
190 /* Update mount */
191 /* HAMMER2 implements NFS export via mountctl */
192 hmp = MPTOH2(mp);
54eb943b
MD
193 devvp = hmp->devvp;
194 error = hammer2_remount(mp, path, devvp, cred);
195 return error;
703720e4
MD
196 }
197 }
198
199 /*
200 * New non-root mount
201 */
202 /* Lookup name and verify it refers to a block device */
203 error = nlookup_init(&nd, dev, UIO_SYSSPACE, NLC_FOLLOW);
54eb943b
MD
204 if (error == 0)
205 error = nlookup(&nd);
206 if (error == 0)
207 error = cache_vref(&nd.nl_nch, nd.nl_cred, &devvp);
703720e4
MD
208 nlookup_done(&nd);
209
54eb943b
MD
210 if (error == 0) {
211 if (vn_isdisk(devvp, &error))
212 error = vfs_mountedon(devvp);
703720e4 213 }
54eb943b
MD
214 if (error == 0 && vcount(devvp) > 0)
215 error = EBUSY;
703720e4
MD
216
217 /*
54eb943b 218 * Now open the device
703720e4 219 */
54eb943b
MD
220 if (error == 0) {
221 ronly = ((mp->mnt_flag & MNT_RDONLY) != 0);
222 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
223 error = vinvalbuf(devvp, V_SAVE, 0, 0);
224 if (error == 0) {
225 error = VOP_OPEN(devvp, ronly ? FREAD : FREAD | FWRITE,
226 FSCRED, NULL);
227 }
228 vn_unlock(devvp);
703720e4 229 }
54eb943b 230 if (error && devvp) {
703720e4 231 vrele(devvp);
54eb943b 232 devvp = NULL;
703720e4 233 }
54eb943b
MD
234 if (error)
235 return error;
703720e4
MD
236
237 /*
54eb943b
MD
238 * Block device opened successfully, finish initializing the
239 * mount structure.
240 *
241 * From this point on we have to call hammer2_unmount() on failure.
703720e4 242 */
703720e4 243 hmp = kmalloc(sizeof(*hmp), M_HAMMER2, M_WAITOK | M_ZERO);
54eb943b
MD
244 mp->mnt_data = (qaddr_t)hmp;
245 hmp->mp = mp;
246 hmp->ronly = ronly;
247 hmp->devvp = devvp;
248 lockinit(&hmp->lk, "h2mp", 0, 0);
249 kmalloc_create(&hmp->inodes, "HAMMER2-inodes");
250 kmalloc_create(&hmp->ipstacks, "HAMMER2-ipstacks");
74d91941 251
f0206a67 252 mp->mnt_flag = MNT_LOCAL;
50e4f8f4
MD
253 mp->mnt_kern_flag |= MNTK_ALL_MPSAFE; /* all entry pts are SMP */
254
255 /*
256 * Install the volume header
257 */
258 error = hammer2_install_volume_header(hmp);
259 if (error) {
260 hammer2_unmount(mp, MNT_FORCE);
261 return error;
262 }
703720e4
MD
263
264 /*
50e4f8f4 265 * required mount structure initializations
703720e4 266 */
50e4f8f4
MD
267 mp->mnt_stat.f_iosize = HAMMER2_PBUFSIZE;
268 mp->mnt_stat.f_bsize = HAMMER2_PBUFSIZE;
269
270 mp->mnt_vstat.f_frsize = HAMMER2_PBUFSIZE;
271 mp->mnt_vstat.f_bsize = HAMMER2_PBUFSIZE;
272
273 /*
274 * Locate the root inode. The volume header points to the
275 * super-root directory.
276 */
277 /* XXX */
278
703720e4
MD
279
280 /* Setup root inode */
54eb943b
MD
281 hmp->iroot = hammer2_alloci(hmp);
282 hmp->iroot->type = HAMMER2_INODE_TYPE_DIR | HAMMER2_INODE_TYPE_ROOT;
283 hmp->iroot->data.inum = 1;
703720e4 284
f0206a67
VS
285 vfs_getnewfsid(mp);
286 vfs_add_vnodeops(mp, &hammer2_vnode_vops, &mp->mnt_vn_norm_ops);
287 vfs_add_vnodeops(mp, &hammer2_spec_vops, &mp->mnt_vn_spec_ops);
288 vfs_add_vnodeops(mp, &hammer2_fifo_vops, &mp->mnt_vn_fifo_ops);
703720e4 289
f0206a67 290 copystr(info.volume, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size);
703720e4
MD
291 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
292 bzero(mp->mnt_stat.f_mntonname, sizeof(mp->mnt_stat.f_mntonname));
293 copyinstr(path, mp->mnt_stat.f_mntonname,
294 sizeof(mp->mnt_stat.f_mntonname) - 1,
295 &size);
296
297 hammer2_statfs(mp, &mp->mnt_stat, cred);
298
54eb943b 299 hammer2_inode_unlock_ex(hmp->iroot);
703720e4 300
47902fef 301 return 0;
703720e4
MD
302}
303
e118c14f
MD
304static
305int
703720e4
MD
306hammer2_remount(struct mount *mp, char *path, struct vnode *devvp,
307 struct ucred *cred)
308{
309 return (0);
310}
311
e118c14f
MD
312static
313int
703720e4
MD
314hammer2_unmount(struct mount *mp, int mntflags)
315{
54eb943b 316 hammer2_mount_t *hmp;
703720e4 317 int flags;
50e4f8f4 318 int error = 0;
54eb943b
MD
319 int ronly = ((mp->mnt_flag & MNT_RDONLY) != 0);
320 struct vnode *devvp;
703720e4
MD
321
322 kprintf("hammer2_unmount\n");
323
324 hmp = MPTOH2(mp);
325 flags = 0;
326
327 if (mntflags & MNT_FORCE)
328 flags |= FORCECLOSE;
329
330 hammer2_mount_exlock(hmp);
331
50e4f8f4
MD
332 /*
333 * If mount initialization proceeded far enough we must flush
334 * its vnodes.
335 */
336 if (hmp->iroot)
337 error = vflush(mp, 0, flags);
338
339 if (error)
340 return error;
703720e4
MD
341
342 /*
343 * Work to do:
344 * 1) Wait on the flusher having no work; heat up if needed
345 * 2) Scan inode RB tree till all the inodes are free
346 * 3) Destroy the kmalloc inode zone
347 * 4) Free the mount point
348 */
349
54eb943b
MD
350 if (hmp->iroot) {
351 hammer2_inode_lock_ex(hmp->iroot);
352 hammer2_freei(hmp->iroot);
353 hmp->iroot = NULL;
354 }
355 if ((devvp = hmp->devvp) != NULL) {
356 vinvalbuf(devvp, (ronly ? 0 : V_SAVE), 0, 0);
357 hmp->devvp = NULL;
358 VOP_CLOSE(devvp, (ronly ? FREAD : FREAD|FWRITE));
359 vrele(devvp);
360 devvp = NULL;
361 }
703720e4 362
54eb943b
MD
363 kmalloc_destroy(&hmp->inodes);
364 kmalloc_destroy(&hmp->ipstacks);
703720e4 365
54eb943b 366 hammer2_mount_unlock(hmp);
703720e4 367
54eb943b
MD
368 mp->mnt_data = NULL;
369 hmp->mp = NULL;
370 kfree(hmp, M_HAMMER2);
703720e4
MD
371
372 return (error);
373}
374
e118c14f
MD
375static
376int
703720e4
MD
377hammer2_vget(struct mount *mp, struct vnode *dvp,
378 ino_t ino, struct vnode **vpp)
379{
380 kprintf("hammer2_vget\n");
381 return (EOPNOTSUPP);
382}
383
e118c14f
MD
384static
385int
703720e4
MD
386hammer2_root(struct mount *mp, struct vnode **vpp)
387{
54eb943b 388 hammer2_mount_t *hmp;
703720e4
MD
389 int error;
390 struct vnode *vp;
391
392 kprintf("hammer2_root\n");
393
394 hmp = MPTOH2(mp);
e118c14f 395 hammer2_mount_exlock(hmp);
54eb943b 396 if (hmp->iroot == NULL) {
703720e4
MD
397 *vpp = NULL;
398 error = EINVAL;
399 } else {
54eb943b 400 vp = hammer2_igetv(hmp->iroot, &error);
703720e4
MD
401 *vpp = vp;
402 if (vp == NULL)
403 kprintf("vnodefail\n");
404 }
405 hammer2_mount_unlock(hmp);
406
407 return (error);
408}
409
e118c14f
MD
410static
411int
703720e4
MD
412hammer2_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred)
413{
54eb943b 414 hammer2_mount_t *hmp;
703720e4 415
703720e4
MD
416 hmp = MPTOH2(mp);
417
50e4f8f4
MD
418 mp->mnt_stat.f_files = 10;
419 mp->mnt_stat.f_bfree = 10;
420 mp->mnt_stat.f_bavail = mp->mnt_stat.f_bfree;
703720e4 421
50e4f8f4 422 *sbp = mp->mnt_stat;
703720e4
MD
423 return (0);
424}
425
e118c14f
MD
426static
427int
703720e4
MD
428hammer2_statvfs(struct mount *mp, struct statvfs *sbp, struct ucred *cred)
429{
50e4f8f4
MD
430 hammer2_mount_t *hmp;
431
432 hmp = MPTOH2(mp);
433
434 mp->mnt_vstat.f_files = 10;
435 mp->mnt_vstat.f_bfree = 10;
436 mp->mnt_vstat.f_bavail = mp->mnt_stat.f_bfree;
437
438 *sbp = mp->mnt_vstat;
439 return (0);
703720e4
MD
440}
441
442/*
443 * Sync the entire filesystem; this is called from the filesystem syncer
444 * process periodically and whenever a user calls sync(1) on the hammer
445 * mountpoint.
446 *
447 * Currently is actually called from the syncer! \o/
448 *
449 * This task will have to snapshot the state of the dirty inode chain.
450 * From that, it will have to make sure all of the inodes on the dirty
451 * chain have IO initiated. We make sure that io is initiated for the root
452 * block.
453 *
454 * If waitfor is set, we wait for media to acknowledge the new rootblock.
455 *
456 * THINKS: side A vs side B, to have sync not stall all I/O?
457 */
e118c14f
MD
458static
459int
703720e4
MD
460hammer2_sync(struct mount *mp, int waitfor)
461{
e118c14f 462#if 0
54eb943b
MD
463 hammer2_mount_t *hmp;
464 hammer2_inode_t *ip;
e118c14f 465#endif
703720e4
MD
466
467 kprintf("hammer2_sync \n");
468
e118c14f
MD
469#if 0
470 hmp = MPTOH2(mp);
471#endif
703720e4
MD
472
473 return (0);
474}
475
e118c14f
MD
476static
477int
703720e4
MD
478hammer2_vptofh(struct vnode *vp, struct fid *fhp)
479{
480 return (0);
481}
482
e118c14f
MD
483static
484int
703720e4
MD
485hammer2_fhtovp(struct mount *mp, struct vnode *rootvp,
486 struct fid *fhp, struct vnode **vpp)
487{
488 return (0);
489}
490
e118c14f
MD
491static
492int
703720e4
MD
493hammer2_checkexp(struct mount *mp, struct sockaddr *nam,
494 int *exflagsp, struct ucred **credanonp)
495{
496 return (0);
497}
50e4f8f4
MD
498
499/*
500 * Support code for hammer2_mount(). Read, verify, and install the volume
501 * header into the HMP
502 *
503 * XXX read four volhdrs and use the one with the highest TID whos CRC
504 * matches.
505 *
506 * XXX check iCRCs.
57381c9e
VS
507 *
508 * XXX For filesystems w/ less than 4 volhdrs, make sure to not write to
509 * nonexistant locations.
510 *
511 * XXX Record selected volhdr and ring updates to each of 4 volhdrs
50e4f8f4
MD
512 */
513static
514int
515hammer2_install_volume_header(hammer2_mount_t *hmp)
516{
517 hammer2_volume_data_t *vd;
0b3147ba
VS
518 struct buf *bp[HAMMER2_NUM_VOLHDRS];
519 hammer2_tid_t hi_tid;
520 hammer2_crc32_t ccrc, crc;
521 int hi_idx;
522 int valid;
523 int i;
50e4f8f4
MD
524 int error;
525
0b3147ba
VS
526 error = 0;
527 valid = 0;
528 hi_tid = 0;
529 hi_idx = -1;
530 bzero(bp, sizeof(bp));
531
532 for (i = 0; i < HAMMER2_NUM_VOLHDRS; i++) {
533 error = bread(hmp->devvp, i * HAMMER2_RESERVE_BYTES64,
534 HAMMER2_VOLUME_BYTES, &bp[i]);
535 if (error) {
536 brelse(bp[i]);
537 bp[i] = NULL;
538 continue;
539 }
540
541 vd = (struct hammer2_volume_data *) bp[i]->b_data;
542
543 if (vd->magic != HAMMER2_VOLUME_ID_HBO)
544 continue;
545
546 crc = vd->icrc_sects[HAMMER2_VOL_ICRC_SECT0];
57381c9e
VS
547 ccrc = hammer2_icrc32(bp[i]->b_data + HAMMER2_VOLUME_ICRC0_OFF,
548 HAMMER2_VOLUME_ICRC0_SIZE);
0b3147ba
VS
549 if (ccrc != crc) {
550 kprintf("hammer2 volume header %d crc mismatch\n", i);
57381c9e 551 kprintf("%x %x\n", ccrc, crc);
0b3147ba
VS
552 continue;
553 }
554
555 valid++;
556
557 if (hi_tid < vd->last_tid) {
558 hi_tid = vd->last_tid;
559 hi_idx = i;
560 }
50e4f8f4 561 }
0b3147ba
VS
562 if (valid) {
563 KKASSERT(hi_idx != -1);
564
565 bcopy(bp[hi_idx]->b_data, &hmp->voldata, sizeof(hmp->voldata));
57381c9e 566 error = 0;
0b3147ba
VS
567 } else {
568 error = EINVAL;
569 }
570
571 for (i = 0; i < HAMMER2_NUM_VOLHDRS; i++) {
572 if (bp[i])
573 brelse(bp[i]);
574 bp[i] = NULL;
575 }
576
577 return (error);
50e4f8f4 578}
0b3147ba 579