next up previous contents
Next: 12. Appendix: Portability Using Up: A File System Component Previous: 10.3 Replicfs: A Persistent

   
11. Appendix: Wrapfs Mount Code

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



Erez Zadok
1999-12-07