This section includes the actual C code that is used to mount an interposer file system on an interposed one, and is described in Section sec-design-implement-wrapfs-vfs.
static int
fist_wrap_mount(
vfs_t *vfsp, /* pre-made vfs structure to mount */
vnode_t *vp, /* existing vnode to mount on */
struct mounta *uap, /* user-area mount(2) arguments */
cred_t *cr /* user credentials */
)
{
int error = 0;
#ifdef HAVE_FIST_ARGS
struct fist_wrap_args args;
char datalen = uap->datalen;
#endif
struct fist_wrapinfo *fwip;
fist_wrapnode_t *fwnp;
dev_t fist_wrapfs_dev;
struct vnode *rootvp;
vnode_t *interposed_vp; /* interposed vnode */
#ifdef FIST_WRAPDEBUG
if (vfsp) {
fist_wrap_print_vfs("fist_wrap_mount", vfsp);
}
if (vp) {
fist_wrap_dprint(fist_wrapdebug, 4,
"%s: fist_wrap_vnodeops %x\n",
"fist_wrap_mount",
(int) &fist_wrap_vnodeops);
fist_wrap_print_vnode("fist_wrap_mount", vp);
}
if (uap) {
fist_wrap_print_uap("fist_wrap_mount", uap);
}
#endif
/*
* Make sure we're root
*/
if (!suser(cr)) {
error = EPERM;
goto out;
}
/* Make sure we mount on a directory */
if (vp->v_type != VDIR) {
error = ENOTDIR;
goto out;
}
/*
* check if vnode is already a root of a file system (i.e., there
* is already a mount on this vnode).
*/
mutex_enter(&vp->v_lock);
if ((uap->flags & MS_REMOUNT) == 0 &&
(uap->flags & MS_OVERLAY) == 0 &&
(vp->v_count != 1 || (vp->v_flag & VROOT))) {
mutex_exit(&vp->v_lock);
error = EBUSY;
goto out;
}
mutex_exit(&vp->v_lock);
/*
* Get arguments: (not needed yet)
*/
/*
* Get vnode for interposed directory.
*/
/* make sure special dir is a valid absolute pathname string */
if (!uap || !uap->spec || uap->spec[0] != '/') {
error = EINVAL;
goto out;
}
error = lookupname(uap->spec, UIO_USERSPACE, FOLLOW,
NULLVPP, &interposed_vp);
if (error)
goto out;
/* Make sure the thing we just looked up is a directory */
if (interposed_vp->v_type != VDIR) {
VN_RELE(interposed_vp);
error = ENOTDIR;
goto out;
}
#ifdef FIST_WRAPDEBUG
if (interposed_vp) {
fist_wrap_print_vnode("fist_wrap_mount", vp);
}
#endif
/*
* Now we can increment the count of module instances.
* meaning that from now, the mounting cannot fail.
*/
++module_keepcnt;
/**************************************************************************
* FIST_WRAPINFO:
* The private information stored by the vfs for fist_wrapfs.
*/
/* this implicitly allocates one vnode to be used for root vnode */
/* XXX: enter this vnode in dnlc? */
fwip = (struct fist_wrapinfo *)
kmem_alloc(sizeof(struct fist_wrapinfo), KM_SLEEP);
/* store the vfs of the stacked file system (pushed onto "stack") */
fwip->fwi_mountvfs = vp->v_vfsp;
/* initialize number of interposed vnodes */
fwip->fwi_num_vnodes = 0;
/* fwip->fwi_rootvnode: is setup in the "root vnode" section below */
/**************************************************************************
* FIST_WRAPNODE:
* The private information stored by interposing vnodes.
* The interposing vnode here is the new root vnode of fist_wrapfs. It
* interposes upon the uap->spec vnode we are mounting on (the directory,
* or partition interposed upon).
*/
fwnp = (fist_wrapnode_t *)
kmem_alloc(sizeof(fist_wrapnode_t), KM_SLEEP);
fwnp->fwn_vnodep = interposed_vp;
/**************************************************************************
* VFS FOR THE FIST_WRAP FILE SYSTEM:
*/
vfsp->vfs_bsize = 1024;
vfsp->vfs_fstype = fist_wrapfs_fstype;
/* Assign a unique device id to the mount */
mutex_enter(&fist_wrapfs_minor_lock);
do {
fist_wrapfs_minor = (fist_wrapfs_minor + 1) & MAXMIN;
fist_wrapfs_dev = makedevice(fist_wrapfs_major, fist_wrapfs_minor);
} while (vfs_devsearch(fist_wrapfs_dev));
mutex_exit(&fist_wrapfs_minor_lock);
/* set the rest of the fields */
vfsp->vfs_dev = fist_wrapfs_dev;
vfsp->vfs_fsid.val[0] = fist_wrapfs_dev;
vfsp->vfs_fsid.val[1] = fist_wrapfs_fstype;
vfsp->vfs_bcount = 0;
/* store private fist_wrap info in the pre-made vfs */
vfsp->vfs_data = (caddr_t) fwip;
/* fill in the vnode we are mounted on, in the vfs */
vfsp->vfs_vnodecovered = vp;
/**************************************************************************
* ROOT VNODE OF FIST_WRAPFS:
*/
rootvp = &(fwip->fwi_rootvnode);
VN_INIT(rootvp, vfsp, VDIR, (dev_t) NULL);
/* this is a root vnode of this file system */
rootvp->v_flag |= VROOT;
/* vnode operations of this root vnode are the fist_wrap */
rootvp->v_op = &fist_wrap_vnodeops;
/* this one is NOT a mount point at this stage */
rootvp->v_vfsmountedhere = NULL;
/*
* This v_data stores the interposed vnode in for now, but in the future
* it could hold more information which is specific to a single vnode
* within a file system. For example, in fist_gzipfs, we could store
* information about the file: type of compression (gzip, pack, zip, lzh,
* compress, etc), whether the file should not be compressed (maybe it is
* stored already in a compact format such as GIF files), etc.
*/
rootvp->v_data = (caddr_t) fwnp;
/* NULLify the rest, just in case */
rootvp->v_filocks = NULL;
/* rootvp->v_cv = NULL; */ /* don't do this one for now */
/**************************************************************************
* VNODE MOUNTED UPON:
*/
/* this vnode to mount on is a mount point for fist_wrap */
vp->v_vfsmountedhere = vfsp;
#ifdef FIST_WRAPDEBUG
/* print values after we change them */
if (vfsp) {
fist_wrap_print_vfs("fist_wrap_mount2", vfsp);
}
if (vp) {
fist_wrap_print_vnode("fist_wrap_mount2", vp);
}
fist_wrap_print_vnode("fist_wrap_mount2rvn", &(fwip->fwi_rootvnode));
#endif
out:
/*
* Cleanup our mess
*/
#ifdef FIST_WRAPDEBUG
fist_wrap_dprint(fist_wrapdebug, 4, "fist_wrap_mount: EXIT\n");
#endif
return (error);
}