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_subr.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_subr.c,v 1.9 2006/11/18 08:18:24 pooka 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_subr.c,v 1.9 2006/11/18 08:18:24 pooka Exp $");
   37 
   38 #include <sys/param.h>
   39 #include <sys/conf.h>
   40 #include <sys/malloc.h>
   41 #include <sys/mount.h>
   42 #include <sys/socketvar.h>
   43 #include <sys/vnode.h>
   44 #include <sys/kauth.h>
   45 #include <sys/namei.h>
   46 
   47 #include <fs/puffs/puffs_msgif.h>
   48 #include <fs/puffs/puffs_sys.h>
   49 
   50 #include <miscfs/genfs/genfs_node.h>
   51 #include <miscfs/specfs/specdev.h>
   52 
   53 POOL_INIT(puffs_pnpool, sizeof(struct puffs_node), 0, 0, 0, "puffspnpl",
   54     &pool_allocator_nointr);
   55 
   56 
   57 static void puffs_gop_size(struct vnode *, off_t, off_t *, int);
   58 static void puffs_gop_markupdate(struct vnode *, int);
   59 
   60 static const struct genfs_ops puffs_genfsops = {
   61         .gop_size = puffs_gop_size,
   62         .gop_write = genfs_gop_write,
   63         .gop_markupdate = puffs_gop_markupdate,
   64 #if 0
   65         .gop_alloc, should ask userspace
   66 #endif
   67 };
   68 
   69 /*
   70  * Grab a vnode, intialize all the puffs-dependant stuff.
   71  */
   72 int
   73 puffs_getvnode(struct mount *mp, void *cookie, enum vtype type,
   74         voff_t vsize, dev_t rdev, struct vnode **vpp)
   75 {
   76         struct puffs_mount *pmp;
   77         struct vnode *vp, *nvp;
   78         struct puffs_node *pnode;
   79         int error;
   80 
   81         pmp = MPTOPUFFSMP(mp);
   82 
   83         /*
   84          * XXX: there is a deadlock condition between vfs_busy() and
   85          * vnode locks.  For an unmounting file system the mountpoint
   86          * is frozen, but in unmount(FORCE) vflush() wants to access all
   87          * of the vnodes.  If we are here waiting for the mountpoint
   88          * lock while holding on to a vnode lock, well, we ain't
   89          * just pining for the fjords anymore.  If we release the
   90          * vnode lock, we will be in the situation "mount point
   91          * is dying" and panic() will ensue in insmntque.  So as a
   92          * temporary workaround, get a vnode without putting it on
   93          * the mount point list, check if mount point is still alive
   94          * and kicking and only then add the vnode to the list.
   95          */
   96         error = getnewvnode(VT_PUFFS, NULL, puffs_vnodeop_p, &vp);
   97         if (error)
   98                 return error;
   99         vp->v_vnlock = NULL;
  100         vp->v_type = type;
  101 
  102         /*
  103          * Check what mount point isn't going away.  This will work
  104          * until we decide to remove biglock or make the kernel
  105          * preemptive.  But hopefully the real problem will be fixed
  106          * by then.
  107          *
  108          * XXX: yes, should call vfs_busy(), but thar be rabbits with
  109          * vicious streaks a mile wide ...
  110          */
  111         if (mp->mnt_iflag & IMNT_UNMOUNT) {
  112                 DPRINTF(("puffs_getvnode: mp %p unmount, unable to create "
  113                     "vnode for cookie %p\n", mp, cookie));
  114                 ungetnewvnode(vp);
  115                 return ENXIO;
  116         }
  117 
  118         /* So it's not dead yet.. good.. inform new vnode of its master */
  119         simple_lock(&mntvnode_slock);
  120         if (TAILQ_EMPTY(&mp->mnt_vnodelist))
  121                 TAILQ_INSERT_HEAD(&mp->mnt_vnodelist, vp, v_mntvnodes);
  122         else
  123                 TAILQ_INSERT_TAIL(&mp->mnt_vnodelist, vp, v_mntvnodes);
  124         simple_unlock(&mntvnode_slock);
  125         vp->v_mount = mp;
  126 
  127         /*
  128          * clerical tasks & footwork
  129          */
  130 
  131         /* dances based on vnode type. almost ufs_vinit(), but not quite */
  132         switch (type) {
  133         case VCHR:
  134         case VBLK:
  135                 /*
  136                  * replace vnode operation vector with the specops vector.
  137                  * our user server has very little control over the node
  138                  * if it decides its a character or block special file
  139                  */
  140                 vp->v_op = puffs_specop_p;
  141 
  142                 /* do the standard checkalias-dance */
  143                 if ((nvp = checkalias(vp, rdev, mp)) != NULL) {
  144                         /*
  145                          * found: release & unallocate aliased
  146                          * old (well, actually, new) node
  147                          */
  148                         vp->v_op = spec_vnodeop_p;
  149                         vp->v_flag &= ~VLOCKSWORK;
  150                         vrele(vp);
  151                         vgone(vp); /* cya */
  152 
  153                         /* init "new" vnode */
  154                         vp = nvp;
  155                         vp->v_vnlock = NULL;
  156                         vp->v_mount = mp;
  157                 }
  158                 break;
  159 
  160         case VFIFO:
  161                 vp->v_op = puffs_fifoop_p;
  162                 break;
  163 
  164         case VREG:
  165                 uvm_vnp_setsize(vp, vsize);
  166                 break;
  167 
  168         case VDIR:
  169         case VLNK:
  170         case VSOCK:
  171                 break;
  172         default:
  173 #ifdef DIAGNOSTIC
  174                 panic("puffs_getvnode: invalid vtype %d", type);
  175 #endif
  176                 break;
  177         }
  178 
  179         pnode = pool_get(&puffs_pnpool, PR_WAITOK);
  180         pnode->pn_cookie = cookie;
  181         pnode->pn_stat = 0;
  182         LIST_INSERT_HEAD(&pmp->pmp_pnodelist, pnode, pn_entries);
  183         vp->v_data = pnode;
  184         vp->v_type = type;
  185         pnode->pn_vp = vp;
  186 
  187         genfs_node_init(vp, &puffs_genfsops);
  188         *vpp = vp;
  189 
  190         DPRINTF(("new vnode at %p, pnode %p, cookie %p\n", vp,
  191             pnode, pnode->pn_cookie));
  192 
  193         return 0;
  194 }
  195 
  196 /* new node creating for creative vop ops (create, symlink, mkdir, mknod) */
  197 int
  198 puffs_newnode(struct mount *mp, struct vnode *dvp, struct vnode **vpp,
  199         void *cookie, struct componentname *cnp, enum vtype type, dev_t rdev)
  200 {
  201         struct vnode *vp;
  202         int error;
  203 
  204         /* userspace probably has this as a NULL op */
  205         if (cookie == NULL) {
  206                 error = EOPNOTSUPP;
  207                 return error;
  208         }
  209 
  210         error = puffs_getvnode(dvp->v_mount, cookie, type, 0, rdev, &vp);
  211         if (error)
  212                 return error;
  213 
  214         vp->v_type = type;
  215         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
  216         *vpp = vp;
  217 
  218         return 0;
  219 }
  220 
  221 void
  222 puffs_putvnode(struct vnode *vp)
  223 {
  224         struct puffs_mount *pmp;
  225         struct puffs_node *pnode;
  226 
  227         pmp = VPTOPUFFSMP(vp);
  228         pnode = VPTOPP(vp);
  229 
  230 #ifdef DIAGNOSTIC
  231         if (vp->v_tag != VT_PUFFS)
  232                 panic("puffs_putvnode: %p not a puffs vnode", vp);
  233 #endif
  234 
  235         LIST_REMOVE(pnode, pn_entries);
  236         pool_put(&puffs_pnpool, vp->v_data);
  237         vp->v_data = NULL;
  238 
  239         return;
  240 }
  241 
  242 /*
  243  * Locate the in-kernel vnode based on the cookie received given
  244  * from userspace.  Returns a locked & referenced vnode, if found,
  245  * NULL otherwise.
  246  *
  247  * XXX: lists, although lookup cache mostly shields us from this
  248  */
  249 struct vnode *
  250 puffs_pnode2vnode(struct puffs_mount *pmp, void *cookie)
  251 {
  252         struct puffs_node *pnode;
  253         struct vnode *vp;
  254 
  255         simple_lock(&pmp->pmp_lock);
  256         LIST_FOREACH(pnode, &pmp->pmp_pnodelist, pn_entries) {
  257                 if (pnode->pn_cookie == cookie)
  258                         break;
  259         }
  260         simple_unlock(&pmp->pmp_lock);
  261         if (!pnode)
  262                 return NULL;
  263         vp = pnode->pn_vp;
  264 
  265         if (pnode->pn_stat & PNODE_INACTIVE) {
  266                 if (vget(vp, LK_EXCLUSIVE | LK_RETRY))
  267                         return NULL;
  268         } else {
  269                 vref(vp);
  270                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
  271         }
  272         return vp;
  273 }
  274 
  275 void
  276 puffs_makecn(struct puffs_cn *pcn, const struct componentname *cn)
  277 {
  278 
  279         pcn->pcn_nameiop = cn->cn_nameiop;
  280         pcn->pcn_flags = cn->cn_flags;
  281         pcn->pcn_pid = cn->cn_lwp->l_proc->p_pid;
  282         puffs_credcvt(&pcn->pcn_cred, cn->cn_cred);
  283 
  284         (void)memcpy(&pcn->pcn_name, cn->cn_nameptr, cn->cn_namelen);
  285         pcn->pcn_name[cn->cn_namelen] = '\0';
  286         pcn->pcn_namelen = cn->cn_namelen;
  287 }
  288 
  289 /*
  290  * Convert given credentials to struct puffs_cred for userspace.
  291  */
  292 void
  293 puffs_credcvt(struct puffs_cred *pcr, const kauth_cred_t cred)
  294 {
  295 
  296         memset(pcr, 0, sizeof(struct puffs_cred));
  297 
  298         if (cred == NOCRED || cred == FSCRED) {
  299                 pcr->pcr_type = PUFFCRED_TYPE_INTERNAL;
  300                 if (cred == NOCRED)
  301                         pcr->pcr_internal = PUFFCRED_CRED_NOCRED;
  302                 if (cred == FSCRED)
  303                         pcr->pcr_internal = PUFFCRED_CRED_FSCRED;
  304         } else {
  305                 pcr->pcr_type = PUFFCRED_TYPE_UUC;
  306                 kauth_cred_to_uucred(&pcr->pcr_uuc, cred);
  307         }
  308 }
  309 
  310 /*
  311  * Return pid.  In case the operation is coming from within the
  312  * kernel without any process context, borrow the swapper's pid.
  313  */
  314 pid_t
  315 puffs_lwp2pid(struct lwp *l)
  316 {
  317 
  318         return l ? l->l_proc->p_pid : 0;
  319 }
  320 
  321 
  322 static void
  323 puffs_gop_size(struct vnode *vp, off_t size, off_t *eobp,
  324         int flags)
  325 {
  326 
  327         *eobp = size;
  328 }
  329 
  330 static void
  331 puffs_gop_markupdate(struct vnode *vp, int flags)
  332 {
  333         int uflags = 0;
  334 
  335         if (flags & GOP_UPDATE_ACCESSED)
  336                 uflags |= PUFFS_UPDATEATIME;
  337         if (flags & GOP_UPDATE_MODIFIED)
  338                 uflags |= PUFFS_UPDATEMTIME;
  339 
  340         puffs_updatenode(vp, uflags);
  341 }
  342 
  343 void
  344 puffs_updatenode(struct vnode *vp, int flags)
  345 {
  346         struct timespec ts;
  347         struct puffs_vnreq_setattr *setattr_arg;
  348 
  349         if (flags == 0)
  350                 return;
  351 
  352         setattr_arg = malloc(sizeof(struct puffs_vnreq_setattr), M_PUFFS,
  353             M_NOWAIT | M_ZERO);
  354         if (setattr_arg == NULL)
  355                 return; /* 2bad */
  356 
  357         nanotime(&ts);
  358 
  359         VATTR_NULL(&setattr_arg->pvnr_va);
  360         if (flags & PUFFS_UPDATEATIME)
  361                 setattr_arg->pvnr_va.va_atime = ts;
  362         if (flags & PUFFS_UPDATECTIME)
  363                 setattr_arg->pvnr_va.va_ctime = ts;
  364         if (flags & PUFFS_UPDATEMTIME)
  365                 setattr_arg->pvnr_va.va_mtime = ts;
  366         if (flags & PUFFS_UPDATESIZE)
  367                 setattr_arg->pvnr_va.va_size = vp->v_size;
  368 
  369         setattr_arg->pvnr_pid = 0;
  370         puffs_credcvt(&setattr_arg->pvnr_cred, NOCRED);
  371 
  372         /* setattr_arg ownership shifted to callee */
  373         puffs_vntouser_faf(MPTOPUFFSMP(vp->v_mount), PUFFS_VN_SETATTR,
  374             setattr_arg, sizeof(struct puffs_vnreq_setattr), VPTOPNC(vp));
  375 }
  376 
  377 void
  378 puffs_updatevpsize(struct vnode *vp)
  379 {
  380         struct vattr va;
  381 
  382         if (VOP_GETATTR(vp, &va, FSCRED, NULL))
  383                 return;
  384 
  385         if (va.va_size != VNOVAL)
  386                 vp->v_size = va.va_size;
  387 }

Cache object: b80a0eb63eb0dade5ccd14d691bf387f


[ 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.