2005-01-06 18:10:42 +00:00
|
|
|
/*-
|
2017-11-20 19:43:44 +00:00
|
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
*
|
1997-02-10 02:22:35 +00:00
|
|
|
* Copyright (c) 1994, 1995 The Regents of the University of California.
|
|
|
|
* Copyright (c) 1994, 1995 Jan-Simon Pendry.
|
2012-05-01 07:46:30 +00:00
|
|
|
* Copyright (c) 2005, 2006, 2012 Masanori Ozawa <ozawa@ongs.co.jp>, ONGS Inc.
|
|
|
|
* Copyright (c) 2006, 2012 Daichi Goto <daichi@freebsd.org>
|
1994-05-24 10:09:53 +00:00
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This code is derived from software donated to Berkeley by
|
|
|
|
* Jan-Simon Pendry.
|
|
|
|
*
|
|
|
|
* 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.
|
2017-02-28 23:42:47 +00:00
|
|
|
* 3. Neither the name of the University nor the names of its contributors
|
1994-05-24 10:09:53 +00:00
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
|
|
|
|
*
|
1997-02-10 02:22:35 +00:00
|
|
|
* @(#)union_vfsops.c 8.20 (Berkeley) 5/20/95
|
1999-08-28 01:08:13 +00:00
|
|
|
* $FreeBSD$
|
1994-05-24 10:09:53 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
2006-12-02 19:35:56 +00:00
|
|
|
#include <sys/kdb.h>
|
2008-03-31 12:01:21 +00:00
|
|
|
#include <sys/fcntl.h>
|
1994-09-22 19:38:41 +00:00
|
|
|
#include <sys/kernel.h>
|
2001-06-28 03:50:17 +00:00
|
|
|
#include <sys/lock.h>
|
2006-12-02 19:35:56 +00:00
|
|
|
#include <sys/malloc.h>
|
1994-05-24 10:09:53 +00:00
|
|
|
#include <sys/mount.h>
|
|
|
|
#include <sys/namei.h>
|
2006-12-02 19:35:56 +00:00
|
|
|
#include <sys/proc.h>
|
|
|
|
#include <sys/vnode.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
2001-05-23 09:42:29 +00:00
|
|
|
#include <fs/unionfs/union.h>
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
static MALLOC_DEFINE(M_UNIONFSMNT, "UNIONFS mount", "UNIONFS mount structure");
|
1997-10-12 20:26:33 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
static vfs_fhtovp_t unionfs_fhtovp;
|
|
|
|
static vfs_checkexp_t unionfs_checkexp;
|
|
|
|
static vfs_mount_t unionfs_domount;
|
|
|
|
static vfs_quotactl_t unionfs_quotactl;
|
|
|
|
static vfs_root_t unionfs_root;
|
|
|
|
static vfs_sync_t unionfs_sync;
|
|
|
|
static vfs_statfs_t unionfs_statfs;
|
|
|
|
static vfs_unmount_t unionfs_unmount;
|
|
|
|
static vfs_vget_t unionfs_vget;
|
|
|
|
static vfs_extattrctl_t unionfs_extattrctl;
|
|
|
|
|
|
|
|
static struct vfsops unionfs_vfsops;
|
1995-03-16 18:17:34 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
/*
|
|
|
|
* Mount unionfs layer.
|
1994-05-24 10:09:53 +00:00
|
|
|
*/
|
1997-11-18 15:07:35 +00:00
|
|
|
static int
|
2009-05-11 15:33:26 +00:00
|
|
|
unionfs_domount(struct mount *mp)
|
1994-05-24 10:09:53 +00:00
|
|
|
{
|
2006-12-02 19:35:56 +00:00
|
|
|
int error;
|
|
|
|
struct vnode *lowerrootvp;
|
|
|
|
struct vnode *upperrootvp;
|
|
|
|
struct unionfs_mount *ump;
|
2009-05-11 15:33:26 +00:00
|
|
|
struct thread *td;
|
2006-12-02 19:35:56 +00:00
|
|
|
char *target;
|
|
|
|
char *tmp;
|
|
|
|
char *ep;
|
|
|
|
int len;
|
|
|
|
size_t done;
|
|
|
|
int below;
|
|
|
|
uid_t uid;
|
|
|
|
gid_t gid;
|
|
|
|
u_short udir;
|
|
|
|
u_short ufile;
|
|
|
|
unionfs_copymode copymode;
|
2007-10-14 13:55:38 +00:00
|
|
|
unionfs_whitemode whitemode;
|
2006-12-02 19:35:56 +00:00
|
|
|
struct nameidata nd, *ndp;
|
|
|
|
struct vattr va;
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
UNIONFSDEBUG("unionfs_mount(mp = %p)\n", (void *)mp);
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
error = 0;
|
|
|
|
below = 0;
|
|
|
|
uid = 0;
|
|
|
|
gid = 0;
|
|
|
|
udir = 0;
|
|
|
|
ufile = 0;
|
2007-10-14 13:53:38 +00:00
|
|
|
copymode = UNIONFS_TRANSPARENT; /* default */
|
2007-10-14 13:55:38 +00:00
|
|
|
whitemode = UNIONFS_WHITE_ALWAYS;
|
2006-12-02 19:35:56 +00:00
|
|
|
ndp = &nd;
|
2009-05-11 15:33:26 +00:00
|
|
|
td = curthread;
|
1997-09-27 13:40:20 +00:00
|
|
|
|
2006-12-09 17:21:25 +00:00
|
|
|
if (mp->mnt_flag & MNT_ROOTFS) {
|
|
|
|
vfs_mount_error(mp, "Cannot union mount root filesystem");
|
2004-11-09 22:21:10 +00:00
|
|
|
return (EOPNOTSUPP);
|
2006-12-09 17:21:25 +00:00
|
|
|
}
|
2006-12-02 19:35:56 +00:00
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
/*
|
2006-12-02 19:35:56 +00:00
|
|
|
* Update is a no operation.
|
1994-05-24 10:09:53 +00:00
|
|
|
*/
|
2006-12-09 17:21:25 +00:00
|
|
|
if (mp->mnt_flag & MNT_UPDATE) {
|
|
|
|
vfs_mount_error(mp, "unionfs does not support mount update");
|
2002-05-24 00:44:44 +00:00
|
|
|
return (EOPNOTSUPP);
|
2006-12-09 17:21:25 +00:00
|
|
|
}
|
1994-05-24 10:09:53 +00:00
|
|
|
|
|
|
|
/*
|
2006-12-02 19:35:56 +00:00
|
|
|
* Get argument
|
1994-05-24 10:09:53 +00:00
|
|
|
*/
|
2006-12-02 19:35:56 +00:00
|
|
|
error = vfs_getopt(mp->mnt_optnew, "target", (void **)&target, &len);
|
|
|
|
if (error)
|
|
|
|
error = vfs_getopt(mp->mnt_optnew, "from", (void **)&target,
|
|
|
|
&len);
|
|
|
|
if (error || target[len - 1] != '\0') {
|
|
|
|
vfs_mount_error(mp, "Invalid target");
|
2002-05-24 00:44:44 +00:00
|
|
|
return (EINVAL);
|
2006-12-02 19:35:56 +00:00
|
|
|
}
|
|
|
|
if (vfs_getopt(mp->mnt_optnew, "below", NULL, NULL) == 0)
|
|
|
|
below = 1;
|
|
|
|
if (vfs_getopt(mp->mnt_optnew, "udir", (void **)&tmp, NULL) == 0) {
|
|
|
|
if (tmp != NULL)
|
|
|
|
udir = (mode_t)strtol(tmp, &ep, 8);
|
|
|
|
if (tmp == NULL || *ep) {
|
|
|
|
vfs_mount_error(mp, "Invalid udir");
|
2002-06-15 22:48:14 +00:00
|
|
|
return (EINVAL);
|
2006-12-02 19:35:56 +00:00
|
|
|
}
|
2008-11-25 03:49:41 +00:00
|
|
|
udir &= S_IRWXU | S_IRWXG | S_IRWXO;
|
2002-06-15 22:48:14 +00:00
|
|
|
}
|
2006-12-02 19:35:56 +00:00
|
|
|
if (vfs_getopt(mp->mnt_optnew, "ufile", (void **)&tmp, NULL) == 0) {
|
|
|
|
if (tmp != NULL)
|
|
|
|
ufile = (mode_t)strtol(tmp, &ep, 8);
|
|
|
|
if (tmp == NULL || *ep) {
|
|
|
|
vfs_mount_error(mp, "Invalid ufile");
|
|
|
|
return (EINVAL);
|
|
|
|
}
|
2008-11-25 03:49:41 +00:00
|
|
|
ufile &= S_IRWXU | S_IRWXG | S_IRWXO;
|
2006-12-02 19:35:56 +00:00
|
|
|
}
|
|
|
|
/* check umask, uid and gid */
|
|
|
|
if (udir == 0 && ufile != 0)
|
|
|
|
udir = ufile;
|
|
|
|
if (ufile == 0 && udir != 0)
|
|
|
|
ufile = udir;
|
|
|
|
|
2008-01-10 01:10:58 +00:00
|
|
|
vn_lock(mp->mnt_vnodecovered, LK_SHARED | LK_RETRY);
|
2008-08-28 15:23:18 +00:00
|
|
|
error = VOP_GETATTR(mp->mnt_vnodecovered, &va, mp->mnt_cred);
|
2006-12-02 19:35:56 +00:00
|
|
|
if (!error) {
|
|
|
|
if (udir == 0)
|
|
|
|
udir = va.va_mode;
|
|
|
|
if (ufile == 0)
|
|
|
|
ufile = va.va_mode;
|
|
|
|
uid = va.va_uid;
|
|
|
|
gid = va.va_gid;
|
|
|
|
}
|
2012-05-01 07:46:30 +00:00
|
|
|
VOP_UNLOCK(mp->mnt_vnodecovered, LK_RELEASE);
|
1994-10-10 07:55:48 +00:00
|
|
|
if (error)
|
2006-12-02 19:35:56 +00:00
|
|
|
return (error);
|
This is a major fixup of unionfs. At least 30 serious bugs have been
fixed (many due to changing semantics in other parts of the kernel and not
the original author's fault), including one critical one: unionfs could
cause UFS corruption in the fronting store due to calling VOP_OPEN for
writing without turning on vmio for the UFS vnode.
Most of the bugs were related to semantics changes in VOP calls, lock
ordering problems (causing deadlocks), improper handling of a read-only
backing store (such as an NFS mount), improper referencing and locking
of vnodes, not using real struct locks for vnode locking, not using
recursive locks when accessing the fronting store, and things like that.
New functionality has been added: unionfs now has mmap() support, but
only partially tested, and rename has been enhanced considerably.
There are still some things that unionfs cannot do. You cannot
rename a directory without confusing unionfs, and there are issues
with softlinks, hardlinks, and special files. unionfs mostly doesn't
understand them (and never did).
There are probably still panic situations, but hopefully no where near
as many as before this commit.
The unionfs in this commit has been tested overlayed on /usr/src
(backing /usr/src being a read-only NFS mount, fronting /usr/src being
a local filesystem). kernel builds have been tested, buildworld is
undergoing testing. More testing is necessary.
1999-09-26 20:52:41 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
if (mp->mnt_cred->cr_ruid == 0) { /* root only */
|
|
|
|
if (vfs_getopt(mp->mnt_optnew, "uid", (void **)&tmp,
|
|
|
|
NULL) == 0) {
|
|
|
|
if (tmp != NULL)
|
|
|
|
uid = (uid_t)strtol(tmp, &ep, 10);
|
|
|
|
if (tmp == NULL || *ep) {
|
|
|
|
vfs_mount_error(mp, "Invalid uid");
|
|
|
|
return (EINVAL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (vfs_getopt(mp->mnt_optnew, "gid", (void **)&tmp,
|
|
|
|
NULL) == 0) {
|
|
|
|
if (tmp != NULL)
|
|
|
|
gid = (gid_t)strtol(tmp, &ep, 10);
|
|
|
|
if (tmp == NULL || *ep) {
|
|
|
|
vfs_mount_error(mp, "Invalid gid");
|
|
|
|
return (EINVAL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (vfs_getopt(mp->mnt_optnew, "copymode", (void **)&tmp,
|
|
|
|
NULL) == 0) {
|
|
|
|
if (tmp == NULL) {
|
|
|
|
vfs_mount_error(mp, "Invalid copymode");
|
|
|
|
return (EINVAL);
|
|
|
|
} else if (strcasecmp(tmp, "traditional") == 0)
|
|
|
|
copymode = UNIONFS_TRADITIONAL;
|
|
|
|
else if (strcasecmp(tmp, "transparent") == 0)
|
|
|
|
copymode = UNIONFS_TRANSPARENT;
|
|
|
|
else if (strcasecmp(tmp, "masquerade") == 0)
|
|
|
|
copymode = UNIONFS_MASQUERADE;
|
|
|
|
else {
|
|
|
|
vfs_mount_error(mp, "Invalid copymode");
|
|
|
|
return (EINVAL);
|
|
|
|
}
|
|
|
|
}
|
2007-10-14 13:55:38 +00:00
|
|
|
if (vfs_getopt(mp->mnt_optnew, "whiteout", (void **)&tmp,
|
|
|
|
NULL) == 0) {
|
|
|
|
if (tmp == NULL) {
|
|
|
|
vfs_mount_error(mp, "Invalid whiteout mode");
|
|
|
|
return (EINVAL);
|
|
|
|
} else if (strcasecmp(tmp, "always") == 0)
|
|
|
|
whitemode = UNIONFS_WHITE_ALWAYS;
|
|
|
|
else if (strcasecmp(tmp, "whenneeded") == 0)
|
|
|
|
whitemode = UNIONFS_WHITE_WHENNEEDED;
|
|
|
|
else {
|
|
|
|
vfs_mount_error(mp, "Invalid whiteout mode");
|
|
|
|
return (EINVAL);
|
|
|
|
}
|
|
|
|
}
|
1997-04-14 10:52:25 +00:00
|
|
|
}
|
2006-12-02 19:35:56 +00:00
|
|
|
/* If copymode is UNIONFS_TRADITIONAL, uid/gid is mounted user. */
|
|
|
|
if (copymode == UNIONFS_TRADITIONAL) {
|
|
|
|
uid = mp->mnt_cred->cr_ruid;
|
|
|
|
gid = mp->mnt_cred->cr_rgid;
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
1995-05-30 08:16:23 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
UNIONFSDEBUG("unionfs_mount: uid=%d, gid=%d\n", uid, gid);
|
|
|
|
UNIONFSDEBUG("unionfs_mount: udir=0%03o, ufile=0%03o\n", udir, ufile);
|
|
|
|
UNIONFSDEBUG("unionfs_mount: copymode=%d\n", copymode);
|
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
/*
|
2006-12-02 19:35:56 +00:00
|
|
|
* Find upper node
|
1994-05-24 10:09:53 +00:00
|
|
|
*/
|
2008-11-04 18:54:44 +00:00
|
|
|
NDINIT(ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, target, td);
|
2006-12-02 19:35:56 +00:00
|
|
|
if ((error = namei(ndp)))
|
|
|
|
return (error);
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
NDFREE(ndp, NDF_ONLY_PNBUF);
|
This is a major fixup of unionfs. At least 30 serious bugs have been
fixed (many due to changing semantics in other parts of the kernel and not
the original author's fault), including one critical one: unionfs could
cause UFS corruption in the fronting store due to calling VOP_OPEN for
writing without turning on vmio for the UFS vnode.
Most of the bugs were related to semantics changes in VOP calls, lock
ordering problems (causing deadlocks), improper handling of a read-only
backing store (such as an NFS mount), improper referencing and locking
of vnodes, not using real struct locks for vnode locking, not using
recursive locks when accessing the fronting store, and things like that.
New functionality has been added: unionfs now has mmap() support, but
only partially tested, and rename has been enhanced considerably.
There are still some things that unionfs cannot do. You cannot
rename a directory without confusing unionfs, and there are issues
with softlinks, hardlinks, and special files. unionfs mostly doesn't
understand them (and never did).
There are probably still panic situations, but hopefully no where near
as many as before this commit.
The unionfs in this commit has been tested overlayed on /usr/src
(backing /usr/src being a read-only NFS mount, fronting /usr/src being
a local filesystem). kernel builds have been tested, buildworld is
undergoing testing. More testing is necessary.
1999-09-26 20:52:41 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
/* get root vnodes */
|
|
|
|
lowerrootvp = mp->mnt_vnodecovered;
|
|
|
|
upperrootvp = ndp->ni_vp;
|
2004-10-05 05:59:29 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
/* create unionfs_mount */
|
|
|
|
ump = (struct unionfs_mount *)malloc(sizeof(struct unionfs_mount),
|
|
|
|
M_UNIONFSMNT, M_WAITOK | M_ZERO);
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
/*
|
|
|
|
* Save reference
|
|
|
|
*/
|
|
|
|
if (below) {
|
2012-05-01 07:46:30 +00:00
|
|
|
VOP_UNLOCK(upperrootvp, LK_RELEASE);
|
2008-01-10 01:10:58 +00:00
|
|
|
vn_lock(lowerrootvp, LK_EXCLUSIVE | LK_RETRY);
|
2006-12-02 19:35:56 +00:00
|
|
|
ump->um_lowervp = upperrootvp;
|
|
|
|
ump->um_uppervp = lowerrootvp;
|
|
|
|
} else {
|
|
|
|
ump->um_lowervp = lowerrootvp;
|
|
|
|
ump->um_uppervp = upperrootvp;
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
2006-12-02 19:35:56 +00:00
|
|
|
ump->um_rootvp = NULLVP;
|
|
|
|
ump->um_uid = uid;
|
|
|
|
ump->um_gid = gid;
|
|
|
|
ump->um_udir = udir;
|
|
|
|
ump->um_ufile = ufile;
|
|
|
|
ump->um_copymode = copymode;
|
2007-10-14 13:55:38 +00:00
|
|
|
ump->um_whitemode = whitemode;
|
2006-12-02 19:35:56 +00:00
|
|
|
|
2007-10-16 10:54:55 +00:00
|
|
|
mp->mnt_data = ump;
|
1994-05-24 10:09:53 +00:00
|
|
|
|
1997-02-10 02:22:35 +00:00
|
|
|
/*
|
2006-12-02 19:35:56 +00:00
|
|
|
* Copy upper layer's RDONLY flag.
|
|
|
|
*/
|
|
|
|
mp->mnt_flag |= ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Unlock the node
|
|
|
|
*/
|
2012-05-01 07:46:30 +00:00
|
|
|
VOP_UNLOCK(ump->um_uppervp, LK_RELEASE);
|
1994-05-24 10:09:53 +00:00
|
|
|
|
|
|
|
/*
|
2006-12-02 19:35:56 +00:00
|
|
|
* Get the unionfs root vnode.
|
1994-05-24 10:09:53 +00:00
|
|
|
*/
|
2006-12-02 19:35:56 +00:00
|
|
|
error = unionfs_nodeget(mp, ump->um_uppervp, ump->um_lowervp,
|
|
|
|
NULLVP, &(ump->um_rootvp), NULL, td);
|
2007-10-14 13:52:01 +00:00
|
|
|
vrele(upperrootvp);
|
2006-12-02 19:35:56 +00:00
|
|
|
if (error) {
|
|
|
|
free(ump, M_UNIONFSMNT);
|
|
|
|
mp->mnt_data = NULL;
|
|
|
|
return (error);
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
|
2014-10-20 17:53:49 +00:00
|
|
|
MNT_ILOCK(mp);
|
2006-12-02 19:35:56 +00:00
|
|
|
if ((ump->um_lowervp->v_mount->mnt_flag & MNT_LOCAL) &&
|
|
|
|
(ump->um_uppervp->v_mount->mnt_flag & MNT_LOCAL))
|
|
|
|
mp->mnt_flag |= MNT_LOCAL;
|
2014-10-20 17:53:49 +00:00
|
|
|
MNT_IUNLOCK(mp);
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
/*
|
|
|
|
* Get new fsid
|
|
|
|
*/
|
1997-02-10 02:22:35 +00:00
|
|
|
vfs_getnewfsid(mp);
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
len = MNAMELEN - 1;
|
|
|
|
tmp = mp->mnt_stat.f_mntfromname;
|
|
|
|
copystr((below ? "<below>:" : "<above>:"), tmp, len, &done);
|
|
|
|
len -= done - 1;
|
|
|
|
tmp += done - 1;
|
|
|
|
copystr(target, tmp, len, NULL);
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
UNIONFSDEBUG("unionfs_mount: from %s, on %s\n",
|
|
|
|
mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname);
|
1994-05-24 10:09:53 +00:00
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-12-02 19:35:56 +00:00
|
|
|
* Free reference to unionfs layer
|
1994-05-24 10:09:53 +00:00
|
|
|
*/
|
1997-11-18 15:07:35 +00:00
|
|
|
static int
|
2009-05-11 15:33:26 +00:00
|
|
|
unionfs_unmount(struct mount *mp, int mntflags)
|
1994-05-24 10:09:53 +00:00
|
|
|
{
|
2006-12-02 19:35:56 +00:00
|
|
|
struct unionfs_mount *ump;
|
|
|
|
int error;
|
|
|
|
int num;
|
|
|
|
int freeing;
|
|
|
|
int flags;
|
|
|
|
|
|
|
|
UNIONFSDEBUG("unionfs_unmount: mp = %p\n", (void *)mp);
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
ump = MOUNTTOUNIONFSMOUNT(mp);
|
|
|
|
flags = 0;
|
1994-05-24 10:09:53 +00:00
|
|
|
|
1997-02-10 02:22:35 +00:00
|
|
|
if (mntflags & MNT_FORCE)
|
|
|
|
flags |= FORCECLOSE;
|
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
/* vflush (no need to call vrele) */
|
2009-05-11 15:33:26 +00:00
|
|
|
for (freeing = 0; (error = vflush(mp, 1, flags, curthread)) != 0;) {
|
2006-12-02 19:35:56 +00:00
|
|
|
num = mp->mnt_nvnodelistsize;
|
|
|
|
if (num == freeing)
|
1997-02-10 02:22:35 +00:00
|
|
|
break;
|
2006-12-02 19:35:56 +00:00
|
|
|
freeing = num;
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
|
2001-05-16 18:04:37 +00:00
|
|
|
if (error)
|
|
|
|
return (error);
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
free(ump, M_UNIONFSMNT);
|
2012-03-13 10:04:13 +00:00
|
|
|
mp->mnt_data = NULL;
|
2006-12-02 19:35:56 +00:00
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
1997-11-18 15:07:35 +00:00
|
|
|
static int
|
2009-05-11 15:33:26 +00:00
|
|
|
unionfs_root(struct mount *mp, int flags, struct vnode **vpp)
|
1994-05-24 10:09:53 +00:00
|
|
|
{
|
2006-12-02 19:35:56 +00:00
|
|
|
struct unionfs_mount *ump;
|
|
|
|
struct vnode *vp;
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
ump = MOUNTTOUNIONFSMOUNT(mp);
|
|
|
|
vp = ump->um_rootvp;
|
|
|
|
|
|
|
|
UNIONFSDEBUG("unionfs_root: rootvp=%p locked=%x\n",
|
2008-02-25 18:45:57 +00:00
|
|
|
vp, VOP_ISLOCKED(vp));
|
This is a major fixup of unionfs. At least 30 serious bugs have been
fixed (many due to changing semantics in other parts of the kernel and not
the original author's fault), including one critical one: unionfs could
cause UFS corruption in the fronting store due to calling VOP_OPEN for
writing without turning on vmio for the UFS vnode.
Most of the bugs were related to semantics changes in VOP calls, lock
ordering problems (causing deadlocks), improper handling of a read-only
backing store (such as an NFS mount), improper referencing and locking
of vnodes, not using real struct locks for vnode locking, not using
recursive locks when accessing the fronting store, and things like that.
New functionality has been added: unionfs now has mmap() support, but
only partially tested, and rename has been enhanced considerably.
There are still some things that unionfs cannot do. You cannot
rename a directory without confusing unionfs, and there are issues
with softlinks, hardlinks, and special files. unionfs mostly doesn't
understand them (and never did).
There are probably still panic situations, but hopefully no where near
as many as before this commit.
The unionfs in this commit has been tested overlayed on /usr/src
(backing /usr/src being a read-only NFS mount, fronting /usr/src being
a local filesystem). kernel builds have been tested, buildworld is
undergoing testing. More testing is necessary.
1999-09-26 20:52:41 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
vref(vp);
|
|
|
|
if (flags & LK_TYPE_MASK)
|
2008-01-10 01:10:58 +00:00
|
|
|
vn_lock(vp, flags);
|
This is a major fixup of unionfs. At least 30 serious bugs have been
fixed (many due to changing semantics in other parts of the kernel and not
the original author's fault), including one critical one: unionfs could
cause UFS corruption in the fronting store due to calling VOP_OPEN for
writing without turning on vmio for the UFS vnode.
Most of the bugs were related to semantics changes in VOP calls, lock
ordering problems (causing deadlocks), improper handling of a read-only
backing store (such as an NFS mount), improper referencing and locking
of vnodes, not using real struct locks for vnode locking, not using
recursive locks when accessing the fronting store, and things like that.
New functionality has been added: unionfs now has mmap() support, but
only partially tested, and rename has been enhanced considerably.
There are still some things that unionfs cannot do. You cannot
rename a directory without confusing unionfs, and there are issues
with softlinks, hardlinks, and special files. unionfs mostly doesn't
understand them (and never did).
There are probably still panic situations, but hopefully no where near
as many as before this commit.
The unionfs in this commit has been tested overlayed on /usr/src
(backing /usr/src being a read-only NFS mount, fronting /usr/src being
a local filesystem). kernel builds have been tested, buildworld is
undergoing testing. More testing is necessary.
1999-09-26 20:52:41 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
*vpp = vp;
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
return (0);
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
|
1997-11-18 15:07:35 +00:00
|
|
|
static int
|
2009-05-11 15:33:26 +00:00
|
|
|
unionfs_quotactl(struct mount *mp, int cmd, uid_t uid, void *arg)
|
1994-05-24 10:09:53 +00:00
|
|
|
{
|
2006-12-02 19:35:56 +00:00
|
|
|
struct unionfs_mount *ump;
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
ump = MOUNTTOUNIONFSMOUNT(mp);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Writing is always performed to upper vnode.
|
|
|
|
*/
|
2009-05-11 15:33:26 +00:00
|
|
|
return (VFS_QUOTACTL(ump->um_uppervp->v_mount, cmd, uid, arg));
|
2006-12-02 19:35:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2009-05-11 15:33:26 +00:00
|
|
|
unionfs_statfs(struct mount *mp, struct statfs *sbp)
|
2006-12-02 19:35:56 +00:00
|
|
|
{
|
|
|
|
struct unionfs_mount *ump;
|
|
|
|
int error;
|
2017-01-05 17:19:26 +00:00
|
|
|
struct statfs *mstat;
|
2006-12-02 19:35:56 +00:00
|
|
|
uint64_t lbsize;
|
|
|
|
|
|
|
|
ump = MOUNTTOUNIONFSMOUNT(mp);
|
|
|
|
|
|
|
|
UNIONFSDEBUG("unionfs_statfs(mp = %p, lvp = %p, uvp = %p)\n",
|
|
|
|
(void *)mp, (void *)ump->um_lowervp, (void *)ump->um_uppervp);
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2017-01-05 17:19:26 +00:00
|
|
|
mstat = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK | M_ZERO);
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2017-01-05 17:19:26 +00:00
|
|
|
error = VFS_STATFS(ump->um_lowervp->v_mount, mstat);
|
|
|
|
if (error) {
|
|
|
|
free(mstat, M_STATFS);
|
2006-12-02 19:35:56 +00:00
|
|
|
return (error);
|
2017-01-05 17:19:26 +00:00
|
|
|
}
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
/* now copy across the "interesting" information and fake the rest */
|
2017-01-05 17:19:26 +00:00
|
|
|
sbp->f_blocks = mstat->f_blocks;
|
|
|
|
sbp->f_files = mstat->f_files;
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2017-01-05 17:19:26 +00:00
|
|
|
lbsize = mstat->f_bsize;
|
2006-12-02 19:35:56 +00:00
|
|
|
|
2017-01-05 17:19:26 +00:00
|
|
|
error = VFS_STATFS(ump->um_uppervp->v_mount, mstat);
|
|
|
|
if (error) {
|
|
|
|
free(mstat, M_STATFS);
|
1994-05-24 10:09:53 +00:00
|
|
|
return (error);
|
2017-01-05 17:19:26 +00:00
|
|
|
}
|
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
/*
|
|
|
|
* The FS type etc is copy from upper vfs.
|
|
|
|
* (write able vfs have priority)
|
|
|
|
*/
|
2017-01-05 17:19:26 +00:00
|
|
|
sbp->f_type = mstat->f_type;
|
|
|
|
sbp->f_flags = mstat->f_flags;
|
|
|
|
sbp->f_bsize = mstat->f_bsize;
|
|
|
|
sbp->f_iosize = mstat->f_iosize;
|
|
|
|
|
|
|
|
if (mstat->f_bsize != lbsize)
|
|
|
|
sbp->f_blocks = ((off_t)sbp->f_blocks * lbsize) /
|
|
|
|
mstat->f_bsize;
|
|
|
|
|
|
|
|
sbp->f_blocks += mstat->f_blocks;
|
|
|
|
sbp->f_bfree = mstat->f_bfree;
|
|
|
|
sbp->f_bavail = mstat->f_bavail;
|
|
|
|
sbp->f_files += mstat->f_files;
|
|
|
|
sbp->f_ffree = mstat->f_ffree;
|
|
|
|
|
|
|
|
free(mstat, M_STATFS);
|
1994-05-24 10:09:53 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
static int
|
2009-05-11 15:33:26 +00:00
|
|
|
unionfs_sync(struct mount *mp, int waitfor)
|
2006-12-02 19:35:56 +00:00
|
|
|
{
|
|
|
|
/* nothing to do */
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
unionfs_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp)
|
|
|
|
{
|
|
|
|
return (EOPNOTSUPP);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2011-05-22 01:07:54 +00:00
|
|
|
unionfs_fhtovp(struct mount *mp, struct fid *fidp, int flags,
|
|
|
|
struct vnode **vpp)
|
2006-12-02 19:35:56 +00:00
|
|
|
{
|
|
|
|
return (EOPNOTSUPP);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
unionfs_checkexp(struct mount *mp, struct sockaddr *nam, int *extflagsp,
|
Implement support for RPCSEC_GSS authentication to both the NFS client
and server. This replaces the RPC implementation of the NFS client and
server with the newer RPC implementation originally developed
(actually ported from the userland sunrpc code) to support the NFS
Lock Manager. I have tested this code extensively and I believe it is
stable and that performance is at least equal to the legacy RPC
implementation.
The NFS code currently contains support for both the new RPC
implementation and the older legacy implementation inherited from the
original NFS codebase. The default is to use the new implementation -
add the NFS_LEGACYRPC option to fall back to the old code. When I
merge this support back to RELENG_7, I will probably change this so
that users have to 'opt in' to get the new code.
To use RPCSEC_GSS on either client or server, you must build a kernel
which includes the KGSSAPI option and the crypto device. On the
userland side, you must build at least a new libc, mountd, mount_nfs
and gssd. You must install new versions of /etc/rc.d/gssd and
/etc/rc.d/nfsd and add 'gssd_enable=YES' to /etc/rc.conf.
As long as gssd is running, you should be able to mount an NFS
filesystem from a server that requires RPCSEC_GSS authentication. The
mount itself can happen without any kerberos credentials but all
access to the filesystem will be denied unless the accessing user has
a valid ticket file in the standard place (/tmp/krb5cc_<uid>). There
is currently no support for situations where the ticket file is in a
different place, such as when the user logged in via SSH and has
delegated credentials from that login. This restriction is also
present in Solaris and Linux. In theory, we could improve this in
future, possibly using Brooks Davis' implementation of variant
symlinks.
Supporting RPCSEC_GSS on a server is nearly as simple. You must create
service creds for the server in the form 'nfs/<fqdn>@<REALM>' and
install them in /etc/krb5.keytab. The standard heimdal utility ktutil
makes this fairly easy. After the service creds have been created, you
can add a '-sec=krb5' option to /etc/exports and restart both mountd
and nfsd.
The only other difference an administrator should notice is that nfsd
doesn't fork to create service threads any more. In normal operation,
there will be two nfsd processes, one in userland waiting for TCP
connections and one in the kernel handling requests. The latter
process will create as many kthreads as required - these should be
visible via 'top -H'. The code has some support for varying the number
of service threads according to load but initially at least, nfsd uses
a fixed number of threads according to the value supplied to its '-n'
option.
Sponsored by: Isilon Systems
MFC after: 1 month
2008-11-03 10:38:00 +00:00
|
|
|
struct ucred **credanonp, int *numsecflavors, int **secflavors)
|
2006-12-02 19:35:56 +00:00
|
|
|
{
|
|
|
|
return (EOPNOTSUPP);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
unionfs_extattrctl(struct mount *mp, int cmd, struct vnode *filename_vp,
|
2009-05-11 15:33:26 +00:00
|
|
|
int namespace, const char *attrname)
|
2006-12-02 19:35:56 +00:00
|
|
|
{
|
|
|
|
struct unionfs_mount *ump;
|
|
|
|
struct unionfs_node *unp;
|
|
|
|
|
|
|
|
ump = MOUNTTOUNIONFSMOUNT(mp);
|
|
|
|
unp = VTOUNIONFS(filename_vp);
|
|
|
|
|
|
|
|
if (unp->un_uppervp != NULLVP) {
|
|
|
|
return (VFS_EXTATTRCTL(ump->um_uppervp->v_mount, cmd,
|
2009-05-11 15:33:26 +00:00
|
|
|
unp->un_uppervp, namespace, attrname));
|
2006-12-02 19:35:56 +00:00
|
|
|
} else {
|
|
|
|
return (VFS_EXTATTRCTL(ump->um_lowervp->v_mount, cmd,
|
2009-05-11 15:33:26 +00:00
|
|
|
unp->un_lowervp, namespace, attrname));
|
2006-12-02 19:35:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct vfsops unionfs_vfsops = {
|
|
|
|
.vfs_checkexp = unionfs_checkexp,
|
|
|
|
.vfs_extattrctl = unionfs_extattrctl,
|
|
|
|
.vfs_fhtovp = unionfs_fhtovp,
|
|
|
|
.vfs_init = unionfs_init,
|
|
|
|
.vfs_mount = unionfs_domount,
|
|
|
|
.vfs_quotactl = unionfs_quotactl,
|
|
|
|
.vfs_root = unionfs_root,
|
|
|
|
.vfs_statfs = unionfs_statfs,
|
|
|
|
.vfs_sync = unionfs_sync,
|
|
|
|
.vfs_uninit = unionfs_uninit,
|
|
|
|
.vfs_unmount = unionfs_unmount,
|
|
|
|
.vfs_vget = unionfs_vget,
|
1994-05-24 10:09:53 +00:00
|
|
|
};
|
1994-09-21 03:47:43 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
VFS_SET(unionfs_vfsops, unionfs, VFCF_LOOPBACK);
|