#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/kauth.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/vnode.h>
#include <sys/mount_internal.h>
#include <sys/namei.h>
#include <sys/malloc.h>
#include <miscfs/nullfs/null.h>
static int
nullfs_mount(mp, devvp, data, context)
struct mount *mp;
vnode_t devvp;
user_addr_t data;
vfs_context_t context;
{
int error = 0;
struct user_null_args args;
struct vnode *lowerrootvp, *vp;
struct vnode *nullm_rootvp;
struct null_mount *xmp;
u_int size;
#ifdef NULLFS_DIAGNOSTIC
printf("nullfs_mount(mp = %x)\n", mp);
#endif
if (mp->mnt_flag & MNT_UPDATE) {
return (ENOTSUP);
}
if (vfs_context_is64bit(context)) {
error = copyin(data, (caddr_t)&args, sizeof (args));
}
else {
struct null_args temp;
error = copyin(data, (caddr_t)&temp, sizeof (temp));
args.target = CAST_USER_ADDR_T(temp.target);
}
if (error)
return (error);
NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT|LOCKLEAF,
UIO_USERSPACE, args.target, context);
if (error = namei(ndp))
return (error);
nameidone(ndp);
lowerrootvp = ndp->ni_vp;
vnode_put(ndp->ni_dvp);
ndp->ni_dvp = NULL;
xmp = (struct null_mount *) _MALLOC(sizeof(struct null_mount),
M_UFSMNT, M_WAITOK);
xmp->nullm_vfs = lowerrootvp->v_mount;
error = null_node_create(mp, lowerrootvp, &vp);
if (error) {
vnode_put(lowerrootvp);
FREE(xmp, M_UFSMNT);
return (error);
}
nullm_rootvp = vp;
nullm_rootvp->v_flag |= VROOT;
xmp->nullm_rootvp = nullm_rootvp;
if (NULLVPTOLOWERVP(nullm_rootvp)->v_mount->mnt_flag & MNT_LOCAL)
mp->mnt_flag |= MNT_LOCAL;
mp->mnt_data = (qaddr_t) xmp;
vfs_getnewfsid(mp);
(void) copyinstr(args.target, mp->mnt_vfsstat.f_mntfromname, MAXPATHLEN - 1,
&size);
bzero(mp->mnt_vfsstat.f_mntfromname + size, MNAMELEN - size);
#ifdef NULLFS_DIAGNOSTIC
printf("nullfs_mount: lower %s, alias at %s\n",
mp->mnt_vfsstat.f_mntfromname, mp->mnt_vfsstat.f_mntonname);
#endif
return (0);
}
static int
nullfs_start(mp, flags, context)
struct mount *mp;
int flags;
vfs_context_t context;
{
return (0);
}
static int
nullfs_unmount(mp, mntflags, context)
struct mount *mp;
int mntflags;
vfs_context_t context;
{
struct vnode *nullm_rootvp = MOUNTTONULLMOUNT(mp)->nullm_rootvp;
int error;
int flags = 0;
int force = 0;
#ifdef NULLFS_DIAGNOSTIC
printf("nullfs_unmount(mp = %x)\n", mp);
#endif
if (mntflags & MNT_FORCE) {
flags |= FORCECLOSE;
force = 1;
}
if ( (nullm_rootvp->v_usecount > 1) && !force )
return (EBUSY);
if ( (error = vflush(mp, nullm_rootvp, flags)) && !force )
return (error);
#ifdef NULLFS_DIAGNOSTIC
vprint("alias root of lower", nullm_rootvp);
#endif
vnode_put(nullm_rootvp);
vnode_reclaim(nullm_rootvp);
FREE(mp->mnt_data, M_UFSMNT);
mp->mnt_data = 0;
return 0;
}
static int
nullfs_root(mp, vpp, context)
struct mount *mp;
struct vnode **vpp;
vfs_context_t context;
{
struct proc *p = curproc;
struct vnode *vp;
#ifdef NULLFS_DIAGNOSTIC
printf("nullfs_root(mp = %x, vp = %x->%x)\n", mp,
MOUNTTONULLMOUNT(mp)->nullm_rootvp,
NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)
);
#endif
vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp;
vnode_get(vp);
*vpp = vp;
return 0;
}
static int
nullfs_quotactl(mp, cmd, uid, datap, context)
struct mount *mp;
int cmd;
uid_t uid;
caddr_t datap;
vfs_context_t context;
{
return VFS_QUOTACTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, uid, datap, context);
}
static int
nullfs_statfs(mp, sbp, context)
struct mount *mp;
struct vfsstatfs *sbp;
vfs_context_t context;
{
int error;
struct vfsstatfs mstat;
#ifdef NULLFS_DIAGNOSTIC
printf("nullfs_statfs(mp = %x, vp = %x->%x)\n", mp,
MOUNTTONULLMOUNT(mp)->nullm_rootvp,
NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)
);
#endif
bzero(&mstat, sizeof(mstat));
error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, &mstat, context);
if (error)
return (error);
sbp->f_flags = mstat.f_flags;
sbp->f_bsize = mstat.f_bsize;
sbp->f_iosize = mstat.f_iosize;
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;
return (0);
}
static int
nullfs_sync(__unused struct mount *mp, __unused int waitfor,
__unused kauth_cred_t cred, __unused vfs_context_t context)
{
return (0);
}
static int
nullfs_vget(mp, ino, vpp, context)
struct mount *mp;
ino64_t ino;
struct vnode **vpp;
vfs_context_t context;
{
return VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, vpp, context);
}
static int
nullfs_fhtovp(mp, fhlen, fhp, vpp, context)
struct mount *mp;
int fhlen;
unsigned char *fhp;
struct vnode **vpp;
vfs_context_t context;
{
return VFS_FHTOVP(MOUNTTONULLMOUNT(mp)->nullm_vfs, fhlen, fhp, vpp, context);
}
static int
nullfs_vptofh(vp, fhlenp, fhp, context)
struct vnode *vp;
int *fhlenp;
unsigned char *fhp;
vfs_context_t context;
{
return VFS_VPTOFH(NULLVPTOLOWERVP(vp), fhlenp, fhp, context);
}
int nullfs_init (struct vfsconf *);
#define nullfs_sysctl (int (*) (int *, u_int, user_addr_t, size_t *, user_addr_t, size_t, proc_t))eopnotsupp
struct vfsops null_vfsops = {
nullfs_mount,
nullfs_start,
nullfs_unmount,
nullfs_root,
nullfs_quotactl,
nullfs_statfs,
nullfs_sync,
nullfs_vget,
nullfs_fhtovp,
nullfs_vptofh,
nullfs_init,
nullfs_sysctl
};