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); }