200 lines
5.9 KiB
C
200 lines
5.9 KiB
C
/*-
|
|
* Copyright (c) 2001 Networks Associates Technology, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This software was developed for the FreeBSD Project by NAI Labs, the
|
|
* Security Research Division of Network Associates, Inc. under
|
|
* DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA
|
|
* CHATS research program.
|
|
*
|
|
* 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. The name of the author may not be used to endorse or promote
|
|
* products derived from this software without specific prior written
|
|
* permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
|
|
*
|
|
* $Id$
|
|
* $FreeBSD$
|
|
*/
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/lock.h>
|
|
#include <sys/mutex.h>
|
|
#include <sys/proc.h>
|
|
#include <sys/module.h>
|
|
#include <sys/mount.h>
|
|
#include <sys/namei.h>
|
|
#include <sys/vnode.h>
|
|
|
|
#include "lomacfs.h"
|
|
#include "kernel_mediate.h"
|
|
|
|
MALLOC_DEFINE(M_LOMACFS, "LOMACFS", "LOMAC filesystem objects");
|
|
|
|
static int lomacfs_mount(struct mount *mp, char *path, caddr_t data,
|
|
struct nameidata *ndp, struct thread *td);
|
|
static int lomacfs_statfs(struct mount *mp, struct statfs *sbp,
|
|
struct thread *td);
|
|
static int lomacfs_unmount(struct mount *mp, int mntflags, struct thread *td);
|
|
|
|
static int
|
|
lomacfs_mount(struct mount *mp, char *path, caddr_t data,
|
|
struct nameidata *ndp, struct thread *td) {
|
|
|
|
if (mp->mnt_flag & MNT_UPDATE || VISLOMAC(mp->mnt_vnodecovered))
|
|
return (EOPNOTSUPP);
|
|
|
|
mp->mnt_flag |= MNT_LOCAL;
|
|
mp->mnt_flag &= ~MNT_RDONLY;
|
|
mp->mnt_data = malloc(sizeof(struct lomac_mount), M_LOMACFS,
|
|
M_WAITOK | M_ZERO);
|
|
vfs_getnewfsid(mp);
|
|
|
|
strncpy(mp->mnt_stat.f_mntfromname, "lomacfs", MNAMELEN);
|
|
(void)lomacfs_statfs(mp, &mp->mnt_stat, td);
|
|
|
|
/*
|
|
* Keep around an extra ref for dounmount() to vrele() after the
|
|
* VFS_UNMOUNT()... (who knows...)
|
|
*/
|
|
vref(mp->mnt_vnodecovered);
|
|
if (VOP_ISLOCKED(mp->mnt_vnodecovered, NULL))
|
|
VOP_UNLOCK(mp->mnt_vnodecovered, 0, td);
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
lomacfs_statfs(struct mount *mp, struct statfs *sbp, struct thread *td) {
|
|
struct statfs tmpstat;
|
|
int error;
|
|
|
|
bzero(&tmpstat, sizeof(tmpstat));
|
|
|
|
error = VFS_STATFS(mp->mnt_vnodecovered->v_mount, &tmpstat, td);
|
|
if (error)
|
|
return (error);
|
|
|
|
sbp->f_type = tmpstat.f_type;
|
|
sbp->f_flags = tmpstat.f_flags;
|
|
sbp->f_bsize = tmpstat.f_bsize;
|
|
sbp->f_iosize = tmpstat.f_iosize;
|
|
sbp->f_blocks = tmpstat.f_blocks;
|
|
sbp->f_bfree = tmpstat.f_bfree;
|
|
sbp->f_bavail = tmpstat.f_bavail;
|
|
sbp->f_files = tmpstat.f_files;
|
|
sbp->f_ffree = tmpstat.f_ffree;
|
|
if (sbp != &mp->mnt_stat) {
|
|
bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
|
|
bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
|
|
bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
lomacfs_unmount(struct mount *mp, int mntflags, struct thread *td) {
|
|
struct vnode *crootvp = VFSTOLOMAC(mp)->lm_rootvp;
|
|
int error;
|
|
int flags = 0;
|
|
|
|
if (mntflags & MNT_FORCE)
|
|
flags |= FORCECLOSE;
|
|
|
|
if (VFSTOLOMAC(mp)->lm_flags & LM_TOOKROOT) {
|
|
mtx_lock(&crootvp->v_interlock);
|
|
crootvp->v_flag |= VROOT;
|
|
mtx_unlock(&crootvp->v_interlock);
|
|
}
|
|
|
|
error = vflush(mp, 1, flags); /* have an extra root ref */
|
|
if (error)
|
|
return (error);
|
|
|
|
free(VFSTOLOMAC(mp), M_LOMACFS);
|
|
|
|
/* bye, lomacfs. */
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
lomacfs_root(struct mount *mp, struct vnode **vpp) {
|
|
int error;
|
|
|
|
if (VFSTOLOMAC(mp)->lm_rootvp == NULL) {
|
|
struct vnode *rootvp, *crootvp;
|
|
|
|
crootvp = mp->mnt_vnodecovered;
|
|
error = lomacfs_node_alloc(mp, NULL, NULL, crootvp, &rootvp);
|
|
if (error)
|
|
return (error);
|
|
/*
|
|
* Reference twice to match the rest of the lomacfs vnodes.
|
|
*/
|
|
vref(crootvp);
|
|
vref(crootvp);
|
|
VFSTOLOMAC(mp)->lm_rootvp = rootvp;
|
|
/*
|
|
* This releases the lock on root, but it doesn't release
|
|
* the reference so that root won't "disappear" until
|
|
* unmount.
|
|
*/
|
|
error = VOP_UNLOCK(rootvp, 0, curthread);
|
|
if (error)
|
|
return (error);
|
|
/*
|
|
* This is some strange magic here... I need to pretend
|
|
* that the mounted-on directory isn't a root vnode if I
|
|
* want things like __getcwd() to just fail and not crash.
|
|
*/
|
|
mtx_lock(&crootvp->v_interlock);
|
|
if (crootvp->v_flag & VROOT && crootvp == rootvnode) {
|
|
crootvp->v_flag &= ~VROOT;
|
|
VFSTOLOMAC(mp)->lm_flags |= LM_TOOKROOT;
|
|
}
|
|
mtx_unlock(&crootvp->v_interlock);
|
|
}
|
|
*vpp = VFSTOLOMAC(mp)->lm_rootvp;
|
|
return (vget(*vpp, LK_EXCLUSIVE, curthread));
|
|
}
|
|
|
|
static struct vfsops lomacfs_vfsops = {
|
|
lomacfs_mount,
|
|
vfs_stdstart,
|
|
lomacfs_unmount,
|
|
lomacfs_root,
|
|
vfs_stdquotactl,
|
|
lomacfs_statfs,
|
|
vfs_stdsync,
|
|
vfs_stdvget,
|
|
vfs_stdfhtovp,
|
|
vfs_stdcheckexp,
|
|
vfs_stdvptofh,
|
|
vfs_stdinit,
|
|
vfs_stduninit,
|
|
vfs_stdextattrctl
|
|
};
|
|
VFS_SET(lomacfs_vfsops, lomacfs, VFCF_LOOPBACK);
|
|
MODULE_VERSION(lomacfs, 1);
|
|
MODULE_DEPEND(lomacfs, lomac_plm, 1, 1, 1);
|