diff --git a/sbin/mount_nullfs/mount_nullfs.8 b/sbin/mount_nullfs/mount_nullfs.8 index 177ecdd..71d1835 100644 --- a/sbin/mount_nullfs/mount_nullfs.8 +++ b/sbin/mount_nullfs/mount_nullfs.8 @@ -79,7 +79,13 @@ Options are specified with a flag followed by a comma separated string of options. See the .Xr mount 8 -man page for possible options and their meanings. +man page for standard options and their meanings. +Options specific for +.Nm : +.Bl -tag -width sobypass +.It Cm sobypass +Bypass unix socket operations to the lower layer. +.El .El .Pp The null layer has two purposes. diff --git a/sbin/mount_nullfs/mount_nullfs.c b/sbin/mount_nullfs/mount_nullfs.c index 4f84954..46ea1e6 100644 --- a/sbin/mount_nullfs/mount_nullfs.c +++ b/sbin/mount_nullfs/mount_nullfs.c @@ -48,6 +48,8 @@ static const char rcsid[] = #include #include +#include + #include #include #include @@ -59,25 +61,28 @@ static const char rcsid[] = static struct mntopt mopts[] = { MOPT_STDOPTS, + {"sobypass", 0, NULLMNT_SOBYPASS, 1}, MOPT_END }; +static char fstype[] = "nullfs"; + int subdir(const char *, const char *); static void usage(void) __dead2; int main(int argc, char *argv[]) { - struct iovec iov[6]; - int ch, mntflags; + struct iovec *iov; + int ch, mntflags, nullflags, iovlen; char source[MAXPATHLEN]; char target[MAXPATHLEN]; - mntflags = 0; + mntflags = nullflags = 0; while ((ch = getopt(argc, argv, "o:")) != -1) switch(ch) { case 'o': - getmntopts(optarg, mopts, &mntflags, 0); + getmntopts(optarg, mopts, &mntflags, &nullflags); break; case '?': default: @@ -97,20 +102,15 @@ main(int argc, char *argv[]) errx(EX_USAGE, "%s (%s) and %s are not distinct paths", argv[0], target, argv[1]); - iov[0].iov_base = strdup("fstype"); - iov[0].iov_len = sizeof("fstype"); - iov[1].iov_base = strdup("nullfs"); - iov[1].iov_len = strlen(iov[1].iov_base) + 1; - iov[2].iov_base = strdup("fspath"); - iov[2].iov_len = sizeof("fspath"); - iov[3].iov_base = source; - iov[3].iov_len = strlen(source) + 1; - iov[4].iov_base = strdup("target"); - iov[4].iov_len = sizeof("target"); - iov[5].iov_base = target; - iov[5].iov_len = strlen(target) + 1; - - if (nmount(iov, 6, mntflags)) + iov = NULL; + iovlen = 0; + build_iovec(&iov, &iovlen, "fstype", fstype, (size_t)-1); + build_iovec(&iov, &iovlen, "fspath", source, (size_t)-1); + build_iovec(&iov, &iovlen, "target", target, (size_t)-1); + if ((nullflags & NULLMNT_SOBYPASS) != 0) + build_iovec(&iov, &iovlen, "sobypass", NULL, 0); + + if (nmount(iov, iovlen, mntflags)) err(1, NULL); exit(0); } diff --git a/sys/fs/nullfs/null.h b/sys/fs/nullfs/null.h index c8fc5de..81acbee 100644 --- a/sys/fs/nullfs/null.h +++ b/sys/fs/nullfs/null.h @@ -37,8 +37,15 @@ struct null_mount { struct mount *nullm_vfs; struct vnode *nullm_rootvp; /* Reference to root null_node */ + int nullm_flags; /* nullfs options specific for mount */ }; +/* + * Flags stored in nullm_flags. + */ +#define NULLMNT_SOBYPASS 0x00000001 /* Bypass unix socket operations + to lower node */ + #ifdef _KERNEL /* * A cache of vnode references diff --git a/sys/fs/nullfs/null_vfsops.c b/sys/fs/nullfs/null_vfsops.c index 8c00f87..6d512fc 100644 --- a/sys/fs/nullfs/null_vfsops.c +++ b/sys/fs/nullfs/null_vfsops.c @@ -183,6 +183,11 @@ nullfs_mount(struct mount *mp) MNT_ILOCK(mp); mp->mnt_kern_flag |= lowerrootvp->v_mount->mnt_kern_flag & MNTK_MPSAFE; MNT_IUNLOCK(mp); + + xmp->nullm_flags = 0; + if (vfs_getopt(mp->mnt_optnew, "sobypass", NULL, NULL) == 0) + xmp->nullm_flags |= NULLMNT_SOBYPASS; + mp->mnt_data = xmp; vfs_getnewfsid(mp); diff --git a/sys/fs/nullfs/null_vnops.c b/sys/fs/nullfs/null_vnops.c index bcf8750..ff1a2d0 100644 --- a/sys/fs/nullfs/null_vnops.c +++ b/sys/fs/nullfs/null_vnops.c @@ -816,6 +816,48 @@ null_vptocnp(struct vop_vptocnp_args *ap) return (error); } +static int +null_unpbind(struct vop_unpbind_args *ap) +{ + struct vnode *vp; + struct null_mount *xmp; + + vp = ap->a_vp; + xmp = vp->v_mount->mnt_data; + if (xmp->nullm_flags & NULLMNT_SOBYPASS) + return (null_bypass((struct vop_generic_args *)ap)); + else + return (vop_stdunpbind(ap)); +} + +static int +null_unpconnect(struct vop_unpconnect_args *ap) +{ + struct vnode *vp; + struct null_mount *xmp; + + vp = ap->a_vp; + xmp = vp->v_mount->mnt_data; + if (xmp->nullm_flags & NULLMNT_SOBYPASS) + return (null_bypass((struct vop_generic_args *)ap)); + else + return (vop_stdunpconnect(ap)); +} + +static int +null_unpdetach(struct vop_unpdetach_args *ap) +{ + struct vnode *vp; + struct null_mount *xmp; + + vp = ap->a_vp; + xmp = vp->v_mount->mnt_data; + if (xmp->nullm_flags & NULLMNT_SOBYPASS) + return (null_bypass((struct vop_generic_args *)ap)); + else + return (vop_stdunpdetach(ap)); +} + /* * Global vfs data structures */ @@ -841,4 +883,7 @@ struct vop_vector null_vnodeops = { .vop_unlock = null_unlock, .vop_vptocnp = null_vptocnp, .vop_vptofh = null_vptofh, + .vop_unpbind = null_unpbind, + .vop_unpconnect = null_unpconnect, + .vop_unpdetach = null_unpdetach, }; diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c index 3a439ec..c7c2881 100644 --- a/sys/kern/uipc_usrreq.c +++ b/sys/kern/uipc_usrreq.c @@ -542,7 +542,7 @@ restart: UNP_LINK_WLOCK(); UNP_PCB_LOCK(unp); - vp->v_socket = unp->unp_socket; + VOP_UNPBIND(vp, unp->unp_socket); unp->unp_vnode = vp; unp->unp_addr = soun; unp->unp_flags &= ~UNP_BINDING; @@ -638,7 +638,7 @@ uipc_detach(struct socket *so) * XXXRW: Should assert vp->v_socket == so. */ if ((vp = unp->unp_vnode) != NULL) { - unp->unp_vnode->v_socket = NULL; + VOP_UNPDETACH(vp); unp->unp_vnode = NULL; } unp2 = unp->unp_conn; @@ -1308,7 +1308,7 @@ unp_connect(struct socket *so, struct sockaddr *nam, struct thread *td) * and to protect simultaneous locking of multiple pcbs. */ UNP_LINK_WLOCK(); - so2 = vp->v_socket; + VOP_UNPCONNECT(vp, &so2); if (so2 == NULL) { error = ECONNREFUSED; goto bad2; diff --git a/sys/kern/vfs_default.c b/sys/kern/vfs_default.c index e47498e..448e99b 100644 --- a/sys/kern/vfs_default.c +++ b/sys/kern/vfs_default.c @@ -123,6 +123,9 @@ struct vop_vector default_vnodeops = { .vop_unlock = vop_stdunlock, .vop_vptocnp = vop_stdvptocnp, .vop_vptofh = vop_stdvptofh, + .vop_unpbind = vop_stdunpbind, + .vop_unpconnect = vop_stdunpconnect, + .vop_unpdetach = vop_stdunpdetach, }; /* @@ -1037,6 +1040,39 @@ vop_stdadvise(struct vop_advise_args *ap) return (error); } +int +vop_stdunpbind(struct vop_unpbind_args *ap) +{ + struct vnode *vp; + + vp = ap->a_vp; + + vp->v_socket = ap->a_socket; + return (0); +} + +int +vop_stdunpconnect(struct vop_unpconnect_args *ap) +{ + struct vnode *vp; + + vp = ap->a_vp; + + *ap->a_socket = vp->v_socket; + return (0); +} + +int +vop_stdunpdetach(struct vop_unpdetach_args *ap) +{ + struct vnode *vp; + + vp = ap->a_vp; + + vp->v_socket = NULL; + return (0); +} + /* * vfs default ops * used to fill the vfs function table to get reasonable default return values. diff --git a/sys/kern/vnode_if.src b/sys/kern/vnode_if.src index 6f24d17..e17a034 100644 --- a/sys/kern/vnode_if.src +++ b/sys/kern/vnode_if.src @@ -637,3 +637,23 @@ vop_advise { IN off_t end; IN int advice; }; + +%% unpbind vp E E E + +vop_unpbind { + IN struct vnode *vp; + IN struct socket *socket; +}; + +%% unpconnect vp E E E + +vop_unpconnect { + IN struct vnode *vp; + OUT struct socket **socket; +}; + +%% unpdetach vp E E E + +vop_unpdetach { + IN struct vnode *vp; +};