2 * Copyright (c) 2011, 2012 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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
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>
43 #include <sys/vfsops.h>
46 #include "hammer2_disk.h"
47 #include "hammer2_mount.h"
49 static int hammer2_init(struct vfsconf *conf);
50 static int hammer2_mount(struct mount *mp, char *path, caddr_t data,
52 static int hammer2_remount(struct mount *, char *, struct vnode *,
54 static int hammer2_unmount(struct mount *mp, int mntflags);
55 static int hammer2_root(struct mount *mp, struct vnode **vpp);
56 static int hammer2_statfs(struct mount *mp, struct statfs *sbp,
58 static int hammer2_statvfs(struct mount *mp, struct statvfs *sbp,
60 static int hammer2_sync(struct mount *mp, int waitfor);
61 static int hammer2_vget(struct mount *mp, struct vnode *dvp,
62 ino_t ino, struct vnode **vpp);
63 static int hammer2_fhtovp(struct mount *mp, struct vnode *rootvp,
64 struct fid *fhp, struct vnode **vpp);
65 static int hammer2_vptofh(struct vnode *vp, struct fid *fhp);
66 static int hammer2_checkexp(struct mount *mp, struct sockaddr *nam,
67 int *exflagsp, struct ucred **credanonp);
70 * HAMMER2 vfs operations.
72 static struct vfsops hammer2_vfsops = {
73 .vfs_init = hammer2_init,
74 .vfs_sync = hammer2_sync,
75 .vfs_mount = hammer2_mount,
76 .vfs_unmount = hammer2_unmount,
77 .vfs_root = hammer2_root,
78 .vfs_statfs = hammer2_statfs,
79 .vfs_statvfs = hammer2_statvfs,
80 .vfs_vget = hammer2_vget,
81 .vfs_vptofh = hammer2_vptofh,
82 .vfs_fhtovp = hammer2_fhtovp,
83 .vfs_checkexp = hammer2_checkexp
86 MALLOC_DEFINE(M_HAMMER2, "HAMMER2-mount", "");
88 VFS_SET(hammer2_vfsops, hammer2, 0);
89 MODULE_VERSION(hammer2, 1);
93 hammer2_init(struct vfsconf *conf)
99 if (HAMMER2_BLOCKREF_BYTES != sizeof(struct hammer2_blockref))
101 if (HAMMER2_INODE_BYTES != sizeof(struct hammer2_inode_data))
103 if (HAMMER2_ALLOCREF_BYTES != sizeof(struct hammer2_allocref))
105 if (HAMMER2_VOLUME_BYTES != sizeof(struct hammer2_volume_data))
109 kprintf("HAMMER2 structure size mismatch; cannot continue.\n");
115 * Mount or remount HAMMER2 fileystem from physical media
118 * mp mount point structure
124 * mp mount point structure
125 * path path to mount point
126 * data pointer to argument structure in user space
127 * volume volume path (device@LABEL form)
128 * hflags user mount flags
129 * cred user credentials
136 hammer2_mount(struct mount *mp, char *path, caddr_t data,
139 struct hammer2_mount_info info;
140 hammer2_mount_t *hmp;
142 struct hammer2_volume_data *vd;
143 struct nlookupdata nd;
145 char devstr[MNAMELEN];
157 kprintf("hammer2_mount\n");
166 * Non-root mount or updating a mount
168 error = copyin(data, &info, sizeof(info));
172 error = copyinstr(info.volume, devstr, MNAMELEN - 1, &done);
176 /* Extract device and label */
178 label = strchr(devstr, '@');
180 ((label + 1) - dev) > done)
187 if (mp->mnt_flag & MNT_UPDATE) {
189 /* HAMMER2 implements NFS export via mountctl */
192 error = hammer2_remount(mp, path, devvp, cred);
200 /* Lookup name and verify it refers to a block device */
201 error = nlookup_init(&nd, dev, UIO_SYSSPACE, NLC_FOLLOW);
203 error = nlookup(&nd);
205 error = cache_vref(&nd.nl_nch, nd.nl_cred, &devvp);
209 if (vn_isdisk(devvp, &error))
210 error = vfs_mountedon(devvp);
212 if (error == 0 && vcount(devvp) > 0)
216 * Now open the device
219 ronly = ((mp->mnt_flag & MNT_RDONLY) != 0);
220 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
221 error = vinvalbuf(devvp, V_SAVE, 0, 0);
223 error = VOP_OPEN(devvp, ronly ? FREAD : FREAD | FWRITE,
228 if (error && devvp) {
235 /* Read the volume header */
236 /* XXX: Read four volhdrs, find one w/ highest TID & CRC */
237 error = bread(devvp, 0, HAMMER2_PBUFSIZE, &bp);
238 vd = (struct hammer2_volume_data *) bp->b_data;
240 (vd->magic != HAMMER2_VOLUME_ID_HBO)) {
243 VOP_CLOSE(devvp, ronly ? FREAD : FREAD | FWRITE);
248 * Block device opened successfully, finish initializing the
251 * From this point on we have to call hammer2_unmount() on failure.
253 hmp = kmalloc(sizeof(*hmp), M_HAMMER2, M_WAITOK | M_ZERO);
254 mp->mnt_data = (qaddr_t)hmp;
258 lockinit(&hmp->lk, "h2mp", 0, 0);
259 kmalloc_create(&hmp->inodes, "HAMMER2-inodes");
260 kmalloc_create(&hmp->ipstacks, "HAMMER2-ipstacks");
262 bcopy(bp->b_data, &hmp->voldata, sizeof(struct hammer2_volume_data));
266 mp->mnt_flag = MNT_LOCAL;
269 * Filesystem subroutines are self-synchronized
271 mp->mnt_kern_flag |= MNTK_ALL_MPSAFE;
273 /* Setup root inode */
274 hmp->iroot = hammer2_alloci(hmp);
275 hmp->iroot->type = HAMMER2_INODE_TYPE_DIR | HAMMER2_INODE_TYPE_ROOT;
276 hmp->iroot->data.inum = 1;
279 vfs_add_vnodeops(mp, &hammer2_vnode_vops, &mp->mnt_vn_norm_ops);
280 vfs_add_vnodeops(mp, &hammer2_spec_vops, &mp->mnt_vn_spec_ops);
281 vfs_add_vnodeops(mp, &hammer2_fifo_vops, &mp->mnt_vn_fifo_ops);
283 copystr(info.volume, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size);
284 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
285 bzero(mp->mnt_stat.f_mntonname, sizeof(mp->mnt_stat.f_mntonname));
286 copyinstr(path, mp->mnt_stat.f_mntonname,
287 sizeof(mp->mnt_stat.f_mntonname) - 1,
290 hammer2_statfs(mp, &mp->mnt_stat, cred);
292 hammer2_inode_unlock_ex(hmp->iroot);
299 hammer2_remount(struct mount *mp, char *path, struct vnode *devvp,
307 hammer2_unmount(struct mount *mp, int mntflags)
309 hammer2_mount_t *hmp;
312 int ronly = ((mp->mnt_flag & MNT_RDONLY) != 0);
315 kprintf("hammer2_unmount\n");
320 if (mntflags & MNT_FORCE)
323 hammer2_mount_exlock(hmp);
325 error = vflush(mp, 0, flags);
329 * 1) Wait on the flusher having no work; heat up if needed
330 * 2) Scan inode RB tree till all the inodes are free
331 * 3) Destroy the kmalloc inode zone
332 * 4) Free the mount point
336 hammer2_inode_lock_ex(hmp->iroot);
337 hammer2_freei(hmp->iroot);
340 if ((devvp = hmp->devvp) != NULL) {
341 vinvalbuf(devvp, (ronly ? 0 : V_SAVE), 0, 0);
343 VOP_CLOSE(devvp, (ronly ? FREAD : FREAD|FWRITE));
348 kmalloc_destroy(&hmp->inodes);
349 kmalloc_destroy(&hmp->ipstacks);
351 hammer2_mount_unlock(hmp);
355 kfree(hmp, M_HAMMER2);
362 hammer2_vget(struct mount *mp, struct vnode *dvp,
363 ino_t ino, struct vnode **vpp)
365 kprintf("hammer2_vget\n");
371 hammer2_root(struct mount *mp, struct vnode **vpp)
373 hammer2_mount_t *hmp;
377 kprintf("hammer2_root\n");
380 hammer2_mount_exlock(hmp);
381 if (hmp->iroot == NULL) {
385 vp = hammer2_igetv(hmp->iroot, &error);
388 kprintf("vnodefail\n");
390 hammer2_mount_unlock(hmp);
397 hammer2_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred)
399 hammer2_mount_t *hmp;
401 kprintf("hammer2_statfs\n");
405 sbp->f_iosize = PAGE_SIZE;
406 sbp->f_bsize = PAGE_SIZE;
421 hammer2_statvfs(struct mount *mp, struct statvfs *sbp, struct ucred *cred)
423 kprintf("hammer2_statvfs\n");
428 * Sync the entire filesystem; this is called from the filesystem syncer
429 * process periodically and whenever a user calls sync(1) on the hammer
432 * Currently is actually called from the syncer! \o/
434 * This task will have to snapshot the state of the dirty inode chain.
435 * From that, it will have to make sure all of the inodes on the dirty
436 * chain have IO initiated. We make sure that io is initiated for the root
439 * If waitfor is set, we wait for media to acknowledge the new rootblock.
441 * THINKS: side A vs side B, to have sync not stall all I/O?
445 hammer2_sync(struct mount *mp, int waitfor)
448 hammer2_mount_t *hmp;
452 kprintf("hammer2_sync \n");
463 hammer2_vptofh(struct vnode *vp, struct fid *fhp)
470 hammer2_fhtovp(struct mount *mp, struct vnode *rootvp,
471 struct fid *fhp, struct vnode **vpp)
478 hammer2_checkexp(struct mount *mp, struct sockaddr *nam,
479 int *exflagsp, struct ucred **credanonp)