diff --git a/sbin/mount_dirfs/Makefile b/sbin/mount_dirfs/Makefile index 8800775..036b560 100644 --- a/sbin/mount_dirfs/Makefile +++ b/sbin/mount_dirfs/Makefile @@ -2,6 +2,9 @@ PROG= mount_dirfs SRCS= mount_dirfs.c NOMAN= sorry +LDADD= -lutil +DPADD= ${LIBUTIL} + #CFLAGS+= -I${.CURDIR}/../../sys -.include \ No newline at end of file +.include diff --git a/sbin/mount_dirfs/mount_dirfs.c b/sbin/mount_dirfs/mount_dirfs.c index c2fb497..7c4e840 100644 --- a/sbin/mount_dirfs/mount_dirfs.c +++ b/sbin/mount_dirfs/mount_dirfs.c @@ -1,29 +1,144 @@ +/* + * Copyright (c) 2011-2013 The DragonFly Project. All rights reserved. + * + * This code is derived from software contributed to The DragonFly Project + * by Venkatesh Srinivas + * by Matthew Dillon + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of The DragonFly Project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific, prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + #include +#include +#include +#include +#include +#include +#include #include +#include #include -#include -#include -#include +#include +#include +#include -#include -#include +#define MOPT_UPDATE { "update", 0, MNT_UPDATE, 0 } + +static struct mntopt mopts[] = { MOPT_STDOPTS, MOPT_UPDATE, MOPT_NULL }; + +static void usage(void); int -main(int argc, char *argv[]) +main(int ac, char **av) { + struct vfsconf vfc; + int mount_flags = 0; int error; - char *mntpt, *hostdir; + int ch; + int init_flags = 0; + char *mountpt, *hostdir; + + mount_flags = 0; + + while ((ch = getopt(ac, av, "o:u")) != -1) { + switch(ch) { + case 'u': + init_flags |= MNT_UPDATE; + break; + + case 'o': + getmntopts(optarg, mopts, &mount_flags, NULL); + break; + default: + usage(); + /* not reached */ + } + } + ac -= optind; + av += optind; + mount_flags |= init_flags; + + /* + * Only the mount point need be specified in update mode. + */ + if (init_flags & MNT_UPDATE) { + if (ac != 1) { + usage(); + /* not reached */ + } + mountpt = av[0]; + if (mount(vfc.vfc_name, mountpt, mount_flags, NULL)) + err(1, "mountpoint %s", mountpt); + exit(0); + } - if (argc != 3) - errx(1, "%s: [host dir] [mount point]", argv[0]); + if (ac < 2) { + usage(); + /* not reached */ + } - hostdir = argv[1]; - mntpt = argv[2]; + hostdir = av[0]; + mountpt = av[1]; - error = mount("dirfs", mntpt, 0, hostdir); + /* + * Load the dirfs module if necessary (this bit stolen from + * mount_null). + */ + error = getvfsbyname("dirfs", &vfc); + if (error && vfsisloadable("dirfs")) { + if (vfsload("dirfs") != 0) + err(1, "vfsload(dirfs)"); + endvfsent(); + error = getvfsbyname("dirfs", &vfc); + } if (error) - perror("mount"); + errx(1, "dirfs filesystem is not available"); - return 0; + error = mount(vfc.vfc_name, mountpt, mount_flags, hostdir); + if (error) + err(1, "failed to mount %s on %s", hostdir, mountpt); + + exit (0); } +static +void +usage(void) +{ + fprintf(stderr, "usage: mount_dirfs [-u] [-o options] " + "hostdir dir\n"); + exit(1); +} diff --git a/sys/kern/vfs_conf.c b/sys/kern/vfs_conf.c index 700413c..63c6935 100644 --- a/sys/kern/vfs_conf.c +++ b/sys/kern/vfs_conf.c @@ -378,7 +378,8 @@ vfs_mountroot_try(const char *mountfrom) char *mf; struct proc *p; struct vnode *vp; - + caddr_t data; + data = NULL; vfsname = NULL; devname = NULL; mp = NULL; @@ -409,6 +410,7 @@ vfs_mountroot_try(const char *mountfrom) goto end; /* allocate a root mount */ + kprintf("Allocating mp for %s at %s\n", vfsname, devname); error = vfs_rootmountalloc(vfsname, devname[0] != 0 ? devname : ROOTNAME, &mp); if (error != 0) { @@ -419,9 +421,15 @@ vfs_mountroot_try(const char *mountfrom) mp->mnt_flag |= MNT_ROOTFS; /* do our best to set rootdev */ - if ((strcmp(vfsname, "hammer") != 0) && (devname[0] != 0) && - setrootbyname(devname)) - kprintf("setrootbyname failed\n"); + kprintf("vfsname=%s devname=%s\n", vfsname, devname); + if ((strcmp(vfsname, "dirfs") == 0 && devname)) { + data = kmalloc(1024, M_TEMP, M_WAITOK | M_ZERO); + bcopy(devname, data, 1024); + } else { + if ((strcmp(vfsname, "hammer") != 0) && (devname[0] != 0) && + setrootbyname(devname)) + kprintf("setrootbyname failed\n"); + } /* If the root device is a type "memory disk", mount RW */ if (rootdev != NULL && dev_is_good(rootdev) && @@ -429,7 +437,9 @@ vfs_mountroot_try(const char *mountfrom) mp->mnt_flag &= ~MNT_RDONLY; } - error = VFS_MOUNT(mp, NULL, NULL, proc0.p_ucred); + error = VFS_MOUNT(mp, NULL, data, proc0.p_ucred); + if (data) + kfree(data, M_TEMP); if (!error) break; diff --git a/sys/vfs/dirfs/dirfs.h b/sys/vfs/dirfs/dirfs.h index 98c972c..6a41329 100644 --- a/sys/vfs/dirfs/dirfs.h +++ b/sys/vfs/dirfs/dirfs.h @@ -3,6 +3,7 @@ * * This code is derived from software contributed to The DragonFly Project * by Antonio Huete Jimenez + * by Matthew Dillon * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -37,9 +38,10 @@ #define _SYS_VFS_DIRFS_DIRFS_H_ #include -#include + #include #include +#include MALLOC_DECLARE(M_DIRFS); MALLOC_DECLARE(M_DIRFS_NODE); @@ -49,25 +51,27 @@ MALLOC_DECLARE(M_DIRFS_MISC); #define KTR_DIRFS KTR_ALL #endif -#define DIRFS_NOFD -1 +#define DIRFS_NOFD -1 /* No fd present */ #define DIRFS_ROOT 0x00000001 #define DIRFS_PASVFD 0x00000002 -#define DIRFS_NEEDSTAT 0x00000008 -#define DIRFS_TXTFLG "pasvfd", "wantfree" +#define DIRFS_TXTFLG "pasvfd" -#define BSIZE 16384 /* buffer cache size*/ +/* Used for buffer cache operations */ +#define BSIZE 16384 #define BMASK (BSIZE - 1) /* - * XXX Need to find a proper way + * XXX This should be temporary. A semi-proper solution would be to expose + * below prototypes in the _KERNEL_VIRTUAL case. */ extern int getdirentries(int, char *, int, long *); extern int statfs(const char *, struct statfs *); /* - * Debugging macros + * Debugging macros. The impact should be determined and in case it has a + * considerable performance penalty, it should be enclosed in a DEBUG #ifdef. */ #define debug_called() do { \ dbg(9, "called\n", __func__); \ @@ -109,9 +113,9 @@ extern int statfs(const char *, struct statfs *); #define dirfs_node_isroot(n) (n->dn_state & DIRFS_ROOT) /* - * dirfs' node in-memory struct. It corresponds exactly to a host file. - * dirfs nodes are stated upon VOP_NRESOLVE() to populate most of its - * generic fields. + * Main in-memory node structure which will represent a host file when active. + * Upon VOP_NRESOLVE() an attempt to initialize its generic fields will be made + * via a fstatat(2)/lstat(2) call. */ struct dirfs_node { enum vtype dn_type; /* Node type. Same as vnode @@ -166,18 +170,18 @@ struct dirfs_mount { struct lock dm_lock; struct lwkt_token dm_token; - dirfs_node_t dm_root; + dirfs_node_t dm_root; /* Root dirfs node */ struct mount * dm_mount; - int dm_flags; + int dm_rdonly; - int dm_fd_used; + int dm_fd_used; /* Opened file descriptors */ char dm_path[MAXPATHLEN]; }; typedef struct dirfs_mount *dirfs_mount_t; /* - * VFS conversion macros + * VFS <-> DIRFS conversion macros */ #define VFS_TO_DIRFS(mp) ((dirfs_mount_t)((mp)->mnt_data)) #define DIRFS_TO_VFS(dmp) ((struct mount *)((dmp)->dm_mount)) @@ -185,9 +189,9 @@ typedef struct dirfs_mount *dirfs_mount_t; #define NODE_TO_VP(dnp) ((dnp)->dn_vnode) /* Misc stuff */ +extern int debuglvl; extern int dirfs_fd_limit; extern int dirfs_fd_used; -extern int debuglvl; extern long passive_fd_list_miss; extern long passive_fd_list_hits; @@ -202,12 +206,12 @@ dirfs_node_ref(dirfs_node_t dnp) atomic_add_int(&dnp->dn_refcnt, 1); } -/* - * Returns non-zero on last unref. - */ static __inline int dirfs_node_unref(dirfs_node_t dnp) { + /* + * Returns non-zero on last unref. + */ KKASSERT(dnp->dn_refcnt > 0); return (atomic_fetchadd_int(&dnp->dn_refcnt, -1) == 1); } @@ -238,8 +242,8 @@ void dirfs_node_drop(dirfs_mount_t dmp, dirfs_node_t dnp); void dirfs_node_setpassive(dirfs_mount_t dmp, dirfs_node_t dnp, int state); void dirfs_alloc_vp(struct mount *, struct vnode **, int, dirfs_node_t); void dirfs_free_vp(dirfs_mount_t, dirfs_node_t); -int dirfs_alloc_file(dirfs_mount_t, dirfs_node_t *, dirfs_node_t, struct namecache *, - struct vnode **, struct vattr *, int); +int dirfs_alloc_file(dirfs_mount_t, dirfs_node_t *, dirfs_node_t, + struct namecache *, struct vnode **, struct vattr *, int); dirfs_node_t dirfs_findfd(dirfs_mount_t dmp, dirfs_node_t cur, char **pathto, char **pathfree); void dirfs_dropfd(dirfs_mount_t dmp, dirfs_node_t dnp1, char *pathfree); diff --git a/sys/vfs/dirfs/dirfs_subr.c b/sys/vfs/dirfs/dirfs_subr.c index c812fa8..1a1d6d7 100644 --- a/sys/vfs/dirfs/dirfs_subr.c +++ b/sys/vfs/dirfs/dirfs_subr.c @@ -3,6 +3,7 @@ * * This code is derived from software contributed to The DragonFly Project * by Antonio Huete Jimenez + * by Matthew Dillon * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,21 +34,25 @@ * */ -#include #include #include +#include #include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include #include #include "dirfs.h" +/* + * Allocate and setup all is needed for the dirfs node to hold the filename. + * Note: dn_name is NULL terminated. + */ void dirfs_node_setname(dirfs_node_t dnp, const char *name, int len) { @@ -61,6 +66,10 @@ dirfs_node_setname(dirfs_node_t dnp, const char *name, int len) dnp->dn_namelen = len; } +/* + * Allocate enough space to hold a dirfs node structure. + * Note: Node name and length isn't handled here. + */ dirfs_node_t dirfs_node_alloc(struct mount *mp) { @@ -76,6 +85,9 @@ dirfs_node_alloc(struct mount *mp) return dnp; } +/* + * Drops a reference to the node and. Node is freed when in the last reference. + */ void dirfs_node_drop(dirfs_mount_t dmp, dirfs_node_t dnp) { @@ -84,7 +96,9 @@ dirfs_node_drop(dirfs_mount_t dmp, dirfs_node_t dnp) } /* - * Do not call locked! + * Removes the association with its parent. Before freeing up its resources + * the node will be removed from the per-mount passive fd cache and its fd + * will be closed, either normally or forced. */ int dirfs_node_free(dirfs_mount_t dmp, dirfs_node_t dnp) @@ -105,6 +119,7 @@ dirfs_node_free(dirfs_mount_t dmp, dirfs_node_t dnp) * Root inode will be removed on VOP_UNMOUNT() */ dirfs_mount_gettoken(dmp); + if (dnp->dn_parent) { /* NULL when children reaped parents */ dirfs_node_drop(dmp, dnp->dn_parent); dnp->dn_parent = NULL; @@ -114,10 +129,19 @@ dirfs_node_free(dirfs_mount_t dmp, dirfs_node_t dnp) kfree(dnp->dn_name, M_DIRFS_MISC); dnp->dn_name = NULL; } - if (dnp->dn_fd) { + + /* + * The file descriptor should have been closed already by the + * previous call to dirfs_set-passive. If not, force a sync and + * close it. + */ + if (dnp->dn_fd != DIRFS_NOFD) { + if (dnp->dn_vnode) + VOP_FSYNC(vp, MNT_WAIT, 0); close(dnp->dn_fd); dnp->dn_fd = DIRFS_NOFD; } + lockuninit(&dnp->dn_lock); kfree(dnp, M_DIRFS_NODE); dnp = NULL; @@ -153,15 +177,18 @@ dirfs_alloc_file(dirfs_mount_t dmp, dirfs_node_t *dnpp, dirfs_node_t pdnp, vp = NULL; mp = DIRFS_TO_VFS(dmp); + /* Sanity check */ if (pdnp == NULL) return EINVAL; dnp = dirfs_node_alloc(mp); KKASSERT(dnp != NULL); + dirfs_node_lock(dnp); dirfs_node_setname(dnp, ncp->nc_name, ncp->nc_nlen); dnp->dn_parent = pdnp; dirfs_node_ref(pdnp); /* Children ref */ + dirfs_node_unlock(dnp); pathnp = dirfs_findfd(dmp, dnp, &tmp, &pathfree); @@ -550,7 +577,7 @@ dirfs_open_helper(dirfs_mount_t dmp, dirfs_node_t dnp, int parentfd, if (dnp->dn_type & VDIR) { flags |= O_DIRECTORY; } else { - if ((dmp->dm_flags & MNT_RDONLY) == 0 && canwrite) + if (canwrite) flags |= O_RDWR; else flags |= O_RDONLY; @@ -819,21 +846,21 @@ dirfs_node_setpassive(dirfs_mount_t dmp, dirfs_node_t dnp, int state) vp = dnp->dn_vnode; if (dirfs_node_refcnt(dnp) == 2 && vp && dnp->dn_fd != DIRFS_NOFD && - dnp != dmp->dm_root && + !dirfs_node_isroot(dnp) && (vp->v_flag & (VINACTIVE|VOBJDIRTY)) == VINACTIVE && RB_EMPTY(&vp->v_rbdirty_tree)) { dbg(5, "passive cache: closing %d\n", dnp->dn_fd); close(dnp->dn_fd); dnp->dn_fd = DIRFS_NOFD; - } else - if (dirfs_node_refcnt(dnp) == 1 && dnp->dn_vnode == NULL && - dnp->dn_fd != DIRFS_NOFD && - dnp != dmp->dm_root) { - dbg(5, "passive cache: closing %d\n", dnp->dn_fd); - close(dnp->dn_fd); - dnp->dn_fd = DIRFS_NOFD; + } else { + if (dirfs_node_refcnt(dnp) == 1 && dnp->dn_vnode == NULL && + dnp->dn_fd != DIRFS_NOFD && + dnp != dmp->dm_root) { + dbg(5, "passive cache: closing %d\n", dnp->dn_fd); + close(dnp->dn_fd); + dnp->dn_fd = DIRFS_NOFD; + } } - dirfs_node_drop(dmp, dnp); } } diff --git a/sys/vfs/dirfs/dirfs_vfsops.c b/sys/vfs/dirfs/dirfs_vfsops.c index cac313a..a09c1de 100644 --- a/sys/vfs/dirfs/dirfs_vfsops.c +++ b/sys/vfs/dirfs/dirfs_vfsops.c @@ -3,6 +3,7 @@ * * This code is derived from software contributed to The DragonFly Project * by Antonio Huete Jimenez + * by Matthew Dillon * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -65,7 +66,7 @@ KTR_INFO(KTR_DIRFS, dirfs, root, 31, dirfs_node_t dnp, struct vnode *vp, char *hostdir, int fd, int error); /* System wide sysctl stuff */ -int debuglvl = 5; +int debuglvl = 2; int dirfs_fd_limit = 100; int dirfs_fd_used = 0; long passive_fd_list_miss = 0; @@ -97,8 +98,18 @@ dirfs_mount(struct mount *mp, char *path, caddr_t data, struct ucred *cred) debug_called(); if (mp->mnt_flag & MNT_UPDATE) { - debug(2, "Can't update mountpoint\n"); - return EOPNOTSUPP; + dmp = VFS_TO_DIRFS(mp); + if (dmp->dm_rdonly == 0 && (mp->mnt_flag & MNT_RDONLY)) { + /* XXX We should make sure all writes are synced */ + dmp->dm_rdonly = 1; + debug(2, "dirfs read-write -> read-only\n"); + } + + if (dmp->dm_rdonly && (mp->mnt_kern_flag & MNTK_WANTRDWR)) { + debug(2, "dirfs read-only -> read-write\n"); + dmp->dm_rdonly = 0; + } + return 0; } dmp = kmalloc(sizeof(*dmp), M_DIRFS, M_WAITOK | M_ZERO); @@ -106,8 +117,14 @@ dirfs_mount(struct mount *mp, char *path, caddr_t data, struct ucred *cred) dmp->dm_mount = mp; error = copyinstr(data, &dmp->dm_path, MAXPATHLEN, &done); - if (error) - return error; + if (error) { + /* Attempt to copy from kernel address */ + error = copystr(data, &dmp->dm_path, MAXPATHLEN, &done); + if (error) { + kfree(dmp, M_DIRFS); + return error; + } + } /* Strip / character at the end to avoid problems */ nlen = strnlen(dmp->dm_path, MAXPATHLEN); diff --git a/sys/vfs/dirfs/dirfs_vnops.c b/sys/vfs/dirfs/dirfs_vnops.c index 046b4ff..f060f41 100644 --- a/sys/vfs/dirfs/dirfs_vnops.c +++ b/sys/vfs/dirfs/dirfs_vnops.c @@ -3,6 +3,7 @@ * * This code is derived from software contributed to The DragonFly Project * by Antonio Huete Jimenez + * by Matthew Dillon * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions