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
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/nlookup.h>
39 #include <sys/vnode.h>
40 #include <sys/mount.h>
41 #include <sys/fcntl.h>
44 #include <sys/vfsops.h>
47 #include "hammer2_disk.h"
48 #include "hammer2_mount.h"
50 static int hammer2_init(struct vfsconf *conf);
51 static int hammer2_mount(struct mount *mp, char *path, caddr_t data,
53 static int hammer2_remount(struct mount *, char *, struct vnode *,
55 static int hammer2_unmount(struct mount *mp, int mntflags);
56 static int hammer2_root(struct mount *mp, struct vnode **vpp);
57 static int hammer2_statfs(struct mount *mp, struct statfs *sbp,
59 static int hammer2_statvfs(struct mount *mp, struct statvfs *sbp,
61 static int hammer2_sync(struct mount *mp, int waitfor);
62 static int hammer2_vget(struct mount *mp, struct vnode *dvp,
63 ino_t ino, struct vnode **vpp);
64 static int hammer2_fhtovp(struct mount *mp, struct vnode *rootvp,
65 struct fid *fhp, struct vnode **vpp);
66 static int hammer2_vptofh(struct vnode *vp, struct fid *fhp);
67 static int hammer2_checkexp(struct mount *mp, struct sockaddr *nam,
68 int *exflagsp, struct ucred **credanonp);
71 * HAMMER2 vfs operations.
73 static struct vfsops hammer2_vfsops = {
74 .vfs_init = hammer2_init,
75 .vfs_sync = hammer2_sync,
76 .vfs_mount = hammer2_mount,
77 .vfs_unmount = hammer2_unmount,
78 .vfs_root = hammer2_root,
79 .vfs_statfs = hammer2_statfs,
80 .vfs_statvfs = hammer2_statvfs,
81 .vfs_vget = hammer2_vget,
82 .vfs_vptofh = hammer2_vptofh,
83 .vfs_fhtovp = hammer2_fhtovp,
84 .vfs_checkexp = hammer2_checkexp
87 MALLOC_DEFINE(M_HAMMER2, "HAMMER2-mount", "");
89 VFS_SET(hammer2_vfsops, hammer2, 0);
90 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
135 hammer2_mount(struct mount *mp, char *path, caddr_t data,
138 struct hammer2_mount_info info;
139 struct hammer2_mount *hmp;
141 struct nlookupdata nd;
142 char devstr[MNAMELEN];
154 kprintf("hammer2_mount\n");
164 * Non-root mount or updating a mount
167 error = copyin(data, &info, sizeof(info));
171 error = copyinstr(info.volume, devstr, MNAMELEN - 1, &done);
175 /* Extract device and label */
177 label = strchr(devstr, '@');
179 ((label + 1) - dev) > done)
186 if (mp->mnt_flag & MNT_UPDATE) {
188 /* HAMMER2 implements NFS export via mountctl */
190 devvp = hmp->hm_devvp;
191 return hammer2_remount(mp, path, devvp, cred);
198 /* Lookup name and verify it refers to a block device */
199 error = nlookup_init(&nd, dev, UIO_SYSSPACE, NLC_FOLLOW);
202 error = nlookup(&nd);
205 error = cache_vref(&nd.nl_nch, nd.nl_cred, &devvp);
210 if (!vn_isdisk(devvp, &error)) {
216 * Common path for new root/non-root mounts;
217 * devvp is a ref-ed by not locked vnode referring to the fs device
220 error = vfs_mountedon(devvp);
226 if (vcount(devvp) > 0) {
234 ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
235 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
236 error = vinvalbuf(devvp, V_SAVE, 0, 0);
242 /* This is correct; however due to an NFS quirk of my setup, FREAD
245 error = VOP_OPEN(devvp, ronly ? FREAD : FREAD | FWRITE, FSCRED, NULL);
248 error = VOP_OPEN(devvp, FREAD, FSCRED, NULL);
256 /* VOP_IOCTL(EXTENDED_DISK_INFO, devvp); */
257 /* if vn device, never use bdwrite(); */
258 /* check if device supports BUF_CMD_READALL; */
259 /* check if device supports BUF_CMD_WRITEALL; */
262 hmp = kmalloc(sizeof(*hmp), M_HAMMER2, M_WAITOK | M_ZERO);
263 mp->mnt_data = (qaddr_t) hmp;
265 hmp->hm_ronly = ronly;
266 hmp->hm_devvp = devvp;
267 lockinit(&hmp->hm_lk, "h2mp", 0, 0);
268 kmalloc_create(&hmp->hm_inodes, "HAMMER2-inodes");
269 kmalloc_create(&hmp->hm_ipstacks, "HAMMER2-ipstacks");
271 mp->mnt_flag = MNT_LOCAL;
274 * Filesystem subroutines are self-synchronized
276 mp->mnt_kern_flag |= MNTK_ALL_MPSAFE;
278 /* Setup root inode */
279 hmp->hm_iroot = alloci(hmp);
280 hmp->hm_iroot->type = HAMMER2_INODE_TYPE_DIR | HAMMER2_INODE_TYPE_ROOT;
281 hmp->hm_iroot->inum = 1;
283 /* currently rely on tmpfs routines */
285 vfs_add_vnodeops(mp, &hammer2_vnode_vops, &mp->mnt_vn_norm_ops);
286 vfs_add_vnodeops(mp, &hammer2_spec_vops, &mp->mnt_vn_spec_ops);
287 vfs_add_vnodeops(mp, &hammer2_fifo_vops, &mp->mnt_vn_fifo_ops);
289 copystr(info.volume, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size);
290 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
291 bzero(mp->mnt_stat.f_mntonname, sizeof(mp->mnt_stat.f_mntonname));
292 copyinstr(path, mp->mnt_stat.f_mntonname,
293 sizeof(mp->mnt_stat.f_mntonname) - 1,
296 hammer2_statfs(mp, &mp->mnt_stat, cred);
298 hammer2_inode_unlock_ex(hmp->hm_iroot);
304 hammer2_remount(struct mount *mp, char *path, struct vnode *devvp,
311 hammer2_unmount(struct mount *mp, int mntflags)
313 struct hammer2_mount *hmp;
317 kprintf("hammer2_unmount\n");
322 if (mntflags & MNT_FORCE)
325 hammer2_mount_exlock(hmp);
327 error = vflush(mp, 0, flags);
331 * 1) Wait on the flusher having no work; heat up if needed
332 * 2) Scan inode RB tree till all the inodes are free
333 * 3) Destroy the kmalloc inode zone
334 * 4) Free the mount point
337 kmalloc_destroy(&hmp->hm_inodes);
338 kmalloc_destroy(&hmp->hm_ipstacks);
340 hammer2_mount_unlock(hmp);
343 //kfree(hmp, M_HAMMER2);
350 hammer2_vget(struct mount *mp, struct vnode *dvp,
351 ino_t ino, struct vnode **vpp)
353 kprintf("hammer2_vget\n");
358 hammer2_root(struct mount *mp, struct vnode **vpp)
360 struct hammer2_mount *hmp;
364 kprintf("hammer2_root\n");
367 hammer2_mount_lock_ex(hmp);
368 if (hmp->hm_iroot == NULL) {
372 vp = igetv(hmp->hm_iroot, &error);
375 kprintf("vnodefail\n");
377 hammer2_mount_unlock(hmp);
383 hammer2_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred)
385 struct hammer2_mount *hmp;
387 kprintf("hammer2_statfs\n");
391 sbp->f_iosize = PAGE_SIZE;
392 sbp->f_bsize = PAGE_SIZE;
406 hammer2_statvfs(struct mount *mp, struct statvfs *sbp, struct ucred *cred)
408 kprintf("hammer2_statvfs\n");
413 * Sync the entire filesystem; this is called from the filesystem syncer
414 * process periodically and whenever a user calls sync(1) on the hammer
417 * Currently is actually called from the syncer! \o/
419 * This task will have to snapshot the state of the dirty inode chain.
420 * From that, it will have to make sure all of the inodes on the dirty
421 * chain have IO initiated. We make sure that io is initiated for the root
424 * If waitfor is set, we wait for media to acknowledge the new rootblock.
426 * THINKS: side A vs side B, to have sync not stall all I/O?
429 hammer2_sync(struct mount *mp, int waitfor)
431 struct hammer2_mount *hmp;
432 struct hammer2_inode *ip;
434 kprintf("hammer2_sync \n");
442 hammer2_vptofh(struct vnode *vp, struct fid *fhp)
448 hammer2_fhtovp(struct mount *mp, struct vnode *rootvp,
449 struct fid *fhp, struct vnode **vpp)
455 hammer2_checkexp(struct mount *mp, struct sockaddr *nam,
456 int *exflagsp, struct ucred **credanonp)