The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/puffs/puffs_vfsops.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: puffs_vfsops.c,v 1.13.2.1 2007/02/17 23:27:45 tron Exp $       */
    2 
    3 /*
    4  * Copyright (c) 2005, 2006  Antti Kantee.  All Rights Reserved.
    5  *
    6  * Development of this software was supported by the
    7  * Google Summer of Code program and the Ulla Tuominen Foundation.
    8  * The Google SoC project was mentored by Bill Studenmund.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. The name of the company nor the name of the author may be used to
   19  *    endorse or promote products derived from this software without specific
   20  *    prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
   23  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   24  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   25  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   28  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   32  * SUCH DAMAGE.
   33  */
   34 
   35 #include <sys/cdefs.h>
   36 __KERNEL_RCSID(0, "$NetBSD: puffs_vfsops.c,v 1.13.2.1 2007/02/17 23:27:45 tron Exp $");
   37 
   38 #include <sys/param.h>
   39 #include <sys/mount.h>
   40 #include <sys/malloc.h>
   41 #include <sys/extattr.h>
   42 #include <sys/queue.h>
   43 #include <sys/vnode.h>
   44 #include <sys/dirent.h>
   45 #include <sys/kauth.h>
   46 
   47 #include <lib/libkern/libkern.h>
   48 
   49 #include <fs/puffs/puffs_msgif.h>
   50 #include <fs/puffs/puffs_sys.h>
   51 
   52 VFS_PROTOS(puffs);
   53 
   54 MALLOC_DEFINE(M_PUFFS, "puffs", "pass-to-userspace file system structures");
   55 
   56 int
   57 puffs_mount(struct mount *mp, const char *path, void *data,
   58             struct nameidata *ndp, struct lwp *l)
   59 {
   60         struct puffs_mount *pmp;
   61         struct puffs_args args;
   62         char namebuf[PUFFSNAMESIZE+sizeof("puffs:")+1]; /* do I get a prize? */
   63         int error;
   64 
   65         if (mp->mnt_flag & MNT_GETARGS) {
   66                 pmp = MPTOPUFFSMP(mp);
   67                 return copyout(&pmp->pmp_args, data, sizeof(struct puffs_args));
   68         }
   69 
   70         /* update is not supported currently */
   71         if (mp->mnt_flag & MNT_UPDATE)
   72                 return EOPNOTSUPP;
   73 
   74         /*
   75          * We need the file system name
   76          */
   77         if (!data)
   78                 return EINVAL;
   79 
   80         error = copyin(data, &args, sizeof(struct puffs_args));
   81         if (error)
   82                 return error;
   83 
   84         /* nuke spy bits */
   85         args.pa_flags &= PUFFS_KFLAG_MASK;
   86 
   87         /* build real name */
   88         (void)strlcpy(namebuf, "puffs:", sizeof(namebuf));
   89         (void)strlcat(namebuf, args.pa_name, sizeof(namebuf));
   90 
   91         /* inform user server if it got the max request size it wanted */
   92         if (args.pa_maxreqlen == 0 || args.pa_maxreqlen > PUFFS_REQ_MAXSIZE)
   93                 args.pa_maxreqlen = PUFFS_REQ_MAXSIZE;
   94         else if (args.pa_maxreqlen < PUFFS_REQSTRUCT_MAX)
   95                 args.pa_maxreqlen = PUFFS_REQSTRUCT_MAX;
   96         (void)strlcpy(args.pa_name, namebuf, sizeof(args.pa_name));
   97 
   98         error = copyout(&args, data, sizeof(struct puffs_args)); 
   99         if (error)
  100                 return error;
  101 
  102         error = set_statvfs_info(path, UIO_USERSPACE, namebuf,
  103             UIO_SYSSPACE, mp, l);
  104         if (error)
  105                 return error;
  106         mp->mnt_stat.f_iosize = DEV_BSIZE;
  107 
  108         MALLOC(pmp, struct puffs_mount *, sizeof(struct puffs_mount),
  109             M_PUFFS, M_WAITOK | M_ZERO);
  110 
  111         mp->mnt_fs_bshift = DEV_BSHIFT;
  112         mp->mnt_dev_bshift = DEV_BSHIFT;
  113         mp->mnt_flag &= ~MNT_LOCAL; /* we don't really know, so ... */
  114         mp->mnt_data = pmp;
  115 
  116         pmp->pmp_status = PUFFSTAT_MOUNTING;
  117         pmp->pmp_nextreq = 0;
  118         pmp->pmp_mp = mp;
  119         pmp->pmp_req_maxsize = args.pa_maxreqlen;
  120         pmp->pmp_args = args;
  121 
  122         /*
  123          * Inform the fileops processing code that we have a mountpoint.
  124          * If it doesn't know about anyone with our pid/fd having the
  125          * device open, punt
  126          */
  127         if (puffs_setpmp(l->l_proc->p_pid, args.pa_fd, pmp)) {
  128                 FREE(pmp, M_PUFFS);
  129                 return ENOENT;
  130         }
  131 
  132         simple_lock_init(&pmp->pmp_lock);
  133         TAILQ_INIT(&pmp->pmp_req_touser);
  134         TAILQ_INIT(&pmp->pmp_req_replywait);
  135         TAILQ_INIT(&pmp->pmp_req_sizepark);
  136 
  137         DPRINTF(("puffs_mount: mount point at %p, puffs specific at %p\n",
  138             mp, MPTOPUFFSMP(mp)));
  139 
  140         vfs_getnewfsid(mp);
  141 
  142         return 0;
  143 }
  144 
  145 /*
  146  * This is called from the first "Hello, I'm alive" ioctl
  147  * from userspace.
  148  */
  149 int
  150 puffs_start2(struct puffs_mount *pmp, struct puffs_startreq *sreq)
  151 {
  152         struct puffs_node *pn;
  153         struct mount *mp;
  154 
  155         mp = PMPTOMP(pmp);
  156 
  157         simple_lock(&pmp->pmp_lock);
  158 
  159         /*
  160          * if someone has issued a VFS_ROOT() already, fill in the
  161          * vnode cookie.
  162          */
  163         pn = NULL;
  164         if (pmp->pmp_root) {
  165                 pn = VPTOPP(pmp->pmp_root);
  166                 pn->pn_cookie = sreq->psr_cookie;
  167         }
  168 
  169         /* We're good to fly */
  170         pmp->pmp_rootcookie = sreq->psr_cookie;
  171         pmp->pmp_status = PUFFSTAT_RUNNING;
  172         simple_unlock(&pmp->pmp_lock);
  173 
  174         /* do the VFS_STATVFS() we missed out on in sys_mount() */
  175         copy_statvfs_info(&sreq->psr_sb, mp);
  176         (void)memcpy(&mp->mnt_stat, &sreq->psr_sb, sizeof(mp->mnt_stat));
  177         mp->mnt_stat.f_iosize = DEV_BSIZE;
  178 
  179         DPRINTF(("puffs_start2: root vp %p, cur root pnode %p, cookie %p\n",
  180             pmp->pmp_root, pn, sreq->psr_cookie));
  181 
  182         return 0;
  183 }
  184 
  185 int
  186 puffs_start(struct mount *mp, int flags, struct lwp *l)
  187 {
  188 
  189         /*
  190          * This cannot travel to userspace, as this is called from
  191          * the kernel context of the process doing mount(2).  But
  192          * it's probably a safe bet that the process doing mount(2)
  193          * realizes it needs to start the filesystem also...
  194          */
  195         return 0;
  196 }
  197 
  198 int
  199 puffs_unmount(struct mount *mp, int mntflags, struct lwp *l)
  200 {
  201         struct puffs_mount *pmp;
  202         int error, force;
  203 
  204         PUFFS_VFSREQ(unmount);
  205 
  206         error = 0;
  207         force = mntflags & MNT_FORCE;
  208         pmp = MPTOPUFFSMP(mp);
  209 
  210         DPRINTF(("puffs_unmount: detach filesystem from vfs, current "
  211             "status 0x%x\n", pmp->pmp_status));
  212 
  213         /*
  214          * flush all the vnodes.  VOP_RECLAIM() takes care that the
  215          * root vnode does not get flushed until unmount.  The
  216          * userspace root node cookie is stored in the mount
  217          * structure, so we can always re-instantiate a root vnode,
  218          * should userspace unmount decide it doesn't want to
  219          * cooperate.
  220          */
  221         error = vflush(mp, NULLVP, force ? FORCECLOSE : 0);
  222         if (error)
  223                 goto out;
  224 
  225         /*
  226          * If we are not DYING, we should ask userspace's opinion
  227          * about the situation
  228          */
  229         if (pmp->pmp_status != PUFFSTAT_DYING) {
  230                 unmount_arg.pvfsr_flags = mntflags;
  231                 unmount_arg.pvfsr_pid = puffs_lwp2pid(l);
  232                 error = puffs_vfstouser(pmp, PUFFS_VFS_UNMOUNT,
  233                      &unmount_arg, sizeof(unmount_arg));
  234         }
  235 
  236         /*
  237          * if userspace cooperated or we really need to die,
  238          * screw what userland thinks and just die.
  239          */
  240         DPRINTF(("puffs_unmount: error %d force %d\n", error, force));
  241         if (error == 0 || force) {
  242                 pmp->pmp_status = PUFFSTAT_DYING;
  243                 puffs_nukebypmp(pmp);
  244                 FREE(pmp, M_PUFFS);
  245                 error = 0;
  246         }
  247 
  248  out:
  249         DPRINTF(("puffs_unmount: return %d\n", error));
  250         return error;
  251 }
  252 
  253 /*
  254  * This doesn't need to travel to userspace
  255  */
  256 int
  257 puffs_root(struct mount *mp, struct vnode **vpp)
  258 {
  259         struct puffs_mount *pmp;
  260         struct puffs_node *pn;
  261         struct vnode *vp;
  262 
  263         pmp = MPTOPUFFSMP(mp);
  264 
  265         /*
  266          * pmp_lock must be held if vref()'ing or vrele()'ing the
  267          * root vnode.
  268          */
  269         simple_lock(&pmp->pmp_lock);
  270         vp = pmp->pmp_root;
  271         if (vp) {
  272                 pn = VPTOPP(vp);
  273                 if (pn->pn_stat & PNODE_INACTIVE)  {
  274                         if (vget(vp, LK_NOWAIT)) {
  275                                 pmp->pmp_root = NULL;
  276                                 goto grabnew;
  277                         }
  278                 } else
  279                         vref(vp);
  280                 simple_unlock(&pmp->pmp_lock);
  281                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
  282                 *vpp = vp;
  283                 return 0;
  284         }
  285  grabnew:
  286         simple_unlock(&pmp->pmp_lock);
  287 
  288         /*
  289          * So, didn't have the magic root vnode available.
  290          * No matter, grab another an stuff it with the cookie.
  291          */
  292         if (puffs_getvnode(mp, pmp->pmp_rootcookie, VDIR, 0, 0, &vp))
  293                 panic("sloppy programming");
  294 
  295         simple_lock(&pmp->pmp_lock);
  296         /*
  297          * check if by mysterious force someone else created a root
  298          * vnode while we were executing.
  299          */
  300         if (pmp->pmp_root) {
  301                 vref(pmp->pmp_root);
  302                 simple_unlock(&pmp->pmp_lock);
  303                 puffs_putvnode(vp);
  304                 vn_lock(pmp->pmp_root, LK_EXCLUSIVE | LK_RETRY);
  305                 *vpp = pmp->pmp_root;
  306                 return 0;
  307         } 
  308 
  309         /* store cache */
  310         vp->v_flag = VROOT;
  311         pmp->pmp_root = vp;
  312         simple_unlock(&pmp->pmp_lock);
  313 
  314         vn_lock(pmp->pmp_root, LK_EXCLUSIVE | LK_RETRY);
  315 
  316         *vpp = vp;
  317         return 0;
  318 }
  319 
  320 int
  321 puffs_quotactl(struct mount *mp, int cmd, uid_t uid, void *arg, struct lwp *l)
  322 {
  323 
  324         return EOPNOTSUPP;
  325 }
  326 
  327 int
  328 puffs_statvfs(struct mount *mp, struct statvfs *sbp, struct lwp *l)
  329 {
  330         struct puffs_vfsreq_statvfs *statvfs_arg; /* too big for stack */
  331         struct puffs_mount *pmp;
  332         int error = 0;
  333 
  334         pmp = MPTOPUFFSMP(mp);
  335 
  336         /*
  337          * If we are mounting, it means that the userspace counterpart
  338          * is calling mount(2), but mount(2) also calls statvfs.  So
  339          * requesting statvfs from userspace would mean a deadlock.
  340          * Compensate.
  341          */
  342         if (pmp->pmp_status == PUFFSTAT_MOUNTING)
  343                 return EINPROGRESS;
  344 
  345         /* too big for stack */
  346         MALLOC(statvfs_arg, struct puffs_vfsreq_statvfs *,
  347             sizeof(struct puffs_vfsreq_statvfs), M_PUFFS, M_WAITOK | M_ZERO);
  348         statvfs_arg->pvfsr_pid = puffs_lwp2pid(l);
  349 
  350         error = puffs_vfstouser(pmp, PUFFS_VFS_STATVFS,
  351             statvfs_arg, sizeof(*statvfs_arg));
  352         statvfs_arg->pvfsr_sb.f_iosize = DEV_BSIZE;
  353 
  354         /*
  355          * Try to produce a sensible result even in the event
  356          * of userspace error.
  357          *
  358          * XXX: cache the copy in non-error case
  359          */
  360         if (!error) {
  361                 copy_statvfs_info(&statvfs_arg->pvfsr_sb, mp);
  362                 (void)memcpy(sbp, &statvfs_arg->pvfsr_sb,
  363                     sizeof(struct statvfs));
  364         } else {
  365                 copy_statvfs_info(sbp, mp);
  366         }
  367 
  368         FREE(statvfs_arg, M_PUFFS);
  369 
  370         return 0;
  371 }
  372 
  373 int
  374 puffs_sync(struct mount *mp, int waitfor, struct kauth_cred *cred,
  375         struct lwp *l)
  376 {
  377         int error;
  378 
  379         PUFFS_VFSREQ(sync);
  380 
  381         sync_arg.pvfsr_waitfor = waitfor;
  382         puffs_credcvt(&sync_arg.pvfsr_cred, cred);
  383         sync_arg.pvfsr_pid = puffs_lwp2pid(l);
  384 
  385         error = puffs_vfstouser(MPTOPUFFSMP(mp), PUFFS_VFS_SYNC,
  386             &sync_arg, sizeof(sync_arg));
  387 
  388         return error;
  389 }
  390 
  391 int
  392 puffs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
  393 {
  394 
  395         return EOPNOTSUPP;
  396 }
  397 
  398 #if 0
  399 /*ARGSUSED*/
  400 int
  401 puffs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
  402 {
  403 
  404         return EOPNOTSUPP;
  405 }
  406 
  407 /*ARGSUSED*/
  408 int
  409 puffs_vptofh(struct vnode *vp, struct fid *fhp)
  410 {
  411 
  412         return EOPNOTSUPP;
  413 }
  414 #endif
  415 
  416 void
  417 puffs_init()
  418 {
  419 
  420 #ifdef _LKM
  421         malloc_type_attach(M_PUFFS);
  422         pool_init(&puffs_pnpool, sizeof(struct puffs_node), 0, 0, 0,
  423             "puffspnpl", &pool_allocator_nointr);
  424 #endif
  425 
  426         return;
  427 }
  428 
  429 void
  430 puffs_done()
  431 {
  432 
  433 #ifdef _LKM
  434         pool_destroy(&puffs_pnpool);
  435         malloc_type_detach(M_PUFFS);
  436 #endif
  437 
  438         return;
  439 }
  440 
  441 int
  442 puffs_snapshot(struct mount *mp, struct vnode *vp, struct timespec *ts)
  443 {
  444 
  445         return EOPNOTSUPP;
  446 }
  447 
  448 const struct vnodeopv_desc * const puffs_vnodeopv_descs[] = {
  449         &puffs_vnodeop_opv_desc,
  450         &puffs_specop_opv_desc,
  451         &puffs_fifoop_opv_desc,
  452         &puffs_msgop_opv_desc,
  453         NULL,
  454 };
  455 
  456 struct vfsops puffs_vfsops = {
  457         MOUNT_PUFFS,
  458         puffs_mount,            /* mount        */
  459         puffs_start,            /* start        */
  460         puffs_unmount,          /* unmount      */
  461         puffs_root,             /* root         */
  462         puffs_quotactl,         /* quotactl     */
  463         puffs_statvfs,          /* statvfs      */
  464         puffs_sync,             /* sync         */
  465         puffs_vget,             /* vget         */
  466         (void *)eopnotsupp,     /* fhtovp       */
  467         (void *)eopnotsupp,     /* vptofh       */
  468         puffs_init,             /* init         */
  469         NULL,                   /* reinit       */
  470         puffs_done,             /* done         */
  471         NULL,                   /* mountroot    */
  472         puffs_snapshot,         /* snapshot     */
  473         vfs_stdextattrctl,      /* extattrctl   */
  474         puffs_vnodeopv_descs,   /* vnodeops     */
  475         0,                      /* refcount     */
  476         { NULL, NULL }
  477 };
  478 VFS_ATTACH(puffs_vfsops);

Cache object: 93d9692a6749ff0c4490193132b160da


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.