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/pseudofs/pseudofs_vnops.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 /*-
    2  * Copyright (c) 2001 Dag-Erling Coïdan Smørgrav
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer
   10  *    in this position and unchanged.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  * 3. The name of the author may not be used to endorse or promote products
   15  *    derived from this software without specific prior written permission.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD: releng/7.1/sys/fs/pseudofs/pseudofs_vnops.c 215103 2010-11-10 23:36:13Z cperciva $");
   31 
   32 #include "opt_pseudofs.h"
   33 
   34 #include <sys/param.h>
   35 #include <sys/kernel.h>
   36 #include <sys/systm.h>
   37 #include <sys/ctype.h>
   38 #include <sys/dirent.h>
   39 #include <sys/fcntl.h>
   40 #include <sys/limits.h>
   41 #include <sys/lock.h>
   42 #include <sys/malloc.h>
   43 #include <sys/mount.h>
   44 #include <sys/mutex.h>
   45 #include <sys/namei.h>
   46 #include <sys/proc.h>
   47 #include <sys/sbuf.h>
   48 #include <sys/sx.h>
   49 #include <sys/sysctl.h>
   50 #include <sys/vnode.h>
   51 
   52 #include <fs/pseudofs/pseudofs.h>
   53 #include <fs/pseudofs/pseudofs_internal.h>
   54 
   55 /*
   56  * Returns the fileno, adjusted for target pid
   57  */
   58 static uint32_t
   59 pn_fileno(struct pfs_node *pn, pid_t pid)
   60 {
   61 
   62         KASSERT(pn->pn_fileno > 0,
   63             ("%s(): no fileno allocated", __func__));
   64         if (pid != NO_PID)
   65                 return (pn->pn_fileno * NO_PID + pid);
   66         return (pn->pn_fileno);
   67 }
   68 
   69 /*
   70  * Returns non-zero if given file is visible to given thread.
   71  */
   72 static int
   73 pfs_visible_proc(struct thread *td, struct pfs_node *pn, struct proc *proc)
   74 {
   75         int visible;
   76 
   77         if (proc == NULL)
   78                 return (0);
   79 
   80         PROC_LOCK_ASSERT(proc, MA_OWNED);
   81 
   82         visible = ((proc->p_flag & P_WEXIT) == 0);
   83         if (visible)
   84                 visible = (p_cansee(td, proc) == 0);
   85         if (visible && pn->pn_vis != NULL)
   86                 visible = pn_vis(td, proc, pn);
   87         if (!visible)
   88                 return (0);
   89         return (1);
   90 }
   91 
   92 static int
   93 pfs_visible(struct thread *td, struct pfs_node *pn, pid_t pid, struct proc **p)
   94 {
   95         struct proc *proc;
   96 
   97         PFS_TRACE(("%s (pid: %d, req: %d)",
   98             pn->pn_name, pid, td->td_proc->p_pid));
   99 
  100         if (p)
  101                 *p = NULL;
  102         if (pid == NO_PID)
  103                 PFS_RETURN (1);
  104         if ((proc = pfind(pid)) == NULL)
  105                 PFS_RETURN (0);
  106         if (pfs_visible_proc(td, pn, proc)) {
  107                 if (p)
  108                         *p = proc;
  109                 else
  110                         PROC_UNLOCK(proc);
  111                 PFS_RETURN (1);
  112         }
  113         PROC_UNLOCK(proc);
  114         PFS_RETURN (0);
  115 }
  116 
  117 /*
  118  * Verify permissions
  119  */
  120 static int
  121 pfs_access(struct vop_access_args *va)
  122 {
  123         struct vnode *vn = va->a_vp;
  124         struct pfs_vdata *pvd = vn->v_data;
  125         struct vattr vattr;
  126         int error;
  127 
  128         PFS_TRACE(("%s", pvd->pvd_pn->pn_name));
  129         (void)pvd;
  130 
  131         error = VOP_GETATTR(vn, &vattr, va->a_cred, va->a_td);
  132         if (error)
  133                 PFS_RETURN (error);
  134         error = vaccess(vn->v_type, vattr.va_mode, vattr.va_uid,
  135             vattr.va_gid, va->a_mode, va->a_cred, NULL);
  136         PFS_RETURN (error);
  137 }
  138 
  139 /*
  140  * Close a file or directory
  141  */
  142 static int
  143 pfs_close(struct vop_close_args *va)
  144 {
  145         struct vnode *vn = va->a_vp;
  146         struct pfs_vdata *pvd = vn->v_data;
  147         struct pfs_node *pn = pvd->pvd_pn;
  148         struct proc *proc;
  149         int error;
  150 
  151         PFS_TRACE(("%s", pn->pn_name));
  152         pfs_assert_not_owned(pn);
  153 
  154         /*
  155          * Do nothing unless this is the last close and the node has a
  156          * last-close handler.
  157          */
  158         if (vrefcnt(vn) > 1 || pn->pn_close == NULL)
  159                 PFS_RETURN (0);
  160 
  161         if (pvd->pvd_pid != NO_PID) {
  162                 proc = pfind(pvd->pvd_pid);
  163         } else {
  164                 proc = NULL;
  165         }
  166 
  167         error = pn_close(va->a_td, proc, pn);
  168 
  169         if (proc != NULL)
  170                 PROC_UNLOCK(proc);
  171 
  172         PFS_RETURN (error);
  173 }
  174 
  175 /*
  176  * Get file attributes
  177  */
  178 static int
  179 pfs_getattr(struct vop_getattr_args *va)
  180 {
  181         struct vnode *vn = va->a_vp;
  182         struct pfs_vdata *pvd = vn->v_data;
  183         struct pfs_node *pn = pvd->pvd_pn;
  184         struct vattr *vap = va->a_vap;
  185         struct proc *proc;
  186         int error = 0;
  187 
  188         PFS_TRACE(("%s", pn->pn_name));
  189         pfs_assert_not_owned(pn);
  190 
  191         if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc))
  192                 PFS_RETURN (ENOENT);
  193 
  194         VATTR_NULL(vap);
  195         vap->va_type = vn->v_type;
  196         vap->va_fileid = pn_fileno(pn, pvd->pvd_pid);
  197         vap->va_flags = 0;
  198         vap->va_blocksize = PAGE_SIZE;
  199         vap->va_bytes = vap->va_size = 0;
  200         vap->va_fsid = vn->v_mount->mnt_stat.f_fsid.val[0];
  201         vap->va_nlink = 1;
  202         nanotime(&vap->va_ctime);
  203         vap->va_atime = vap->va_mtime = vap->va_ctime;
  204 
  205         switch (pn->pn_type) {
  206         case pfstype_procdir:
  207         case pfstype_root:
  208         case pfstype_dir:
  209 #if 0
  210                 pfs_lock(pn);
  211                 /* compute link count */
  212                 pfs_unlock(pn);
  213 #endif
  214                 vap->va_mode = 0555;
  215                 break;
  216         case pfstype_file:
  217         case pfstype_symlink:
  218                 vap->va_mode = 0444;
  219                 break;
  220         default:
  221                 printf("shouldn't be here!\n");
  222                 vap->va_mode = 0;
  223                 break;
  224         }
  225 
  226         if (proc != NULL) {
  227                 vap->va_uid = proc->p_ucred->cr_ruid;
  228                 vap->va_gid = proc->p_ucred->cr_rgid;
  229                 if (pn->pn_attr != NULL)
  230                         error = pn_attr(va->a_td, proc, pn, vap);
  231                 PROC_UNLOCK(proc);
  232         } else {
  233                 vap->va_uid = 0;
  234                 vap->va_gid = 0;
  235         }
  236 
  237         PFS_RETURN (error);
  238 }
  239 
  240 /*
  241  * Perform an ioctl
  242  */
  243 static int
  244 pfs_ioctl(struct vop_ioctl_args *va)
  245 {
  246         struct vnode *vn = va->a_vp;
  247         struct pfs_vdata *pvd = vn->v_data;
  248         struct pfs_node *pn = pvd->pvd_pn;
  249         struct proc *proc;
  250         int error;
  251 
  252         PFS_TRACE(("%s: %lx", pn->pn_name, va->a_command));
  253         pfs_assert_not_owned(pn);
  254 
  255         if (vn->v_type != VREG)
  256                 PFS_RETURN (EINVAL);
  257 
  258         if (pn->pn_ioctl == NULL)
  259                 PFS_RETURN (ENOTTY);
  260 
  261         /*
  262          * This is necessary because process' privileges may
  263          * have changed since the open() call.
  264          */
  265         if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc))
  266                 PFS_RETURN (EIO);
  267 
  268         error = pn_ioctl(curthread, proc, pn, va->a_command, va->a_data);
  269 
  270         if (proc != NULL)
  271                 PROC_UNLOCK(proc);
  272 
  273         PFS_RETURN (error);
  274 }
  275 
  276 /*
  277  * Perform getextattr
  278  */
  279 static int
  280 pfs_getextattr(struct vop_getextattr_args *va)
  281 {
  282         struct vnode *vn = va->a_vp;
  283         struct pfs_vdata *pvd = vn->v_data;
  284         struct pfs_node *pn = pvd->pvd_pn;
  285         struct proc *proc;
  286         int error;
  287 
  288         PFS_TRACE(("%s", pn->pn_name));
  289         pfs_assert_not_owned(pn);
  290 
  291         /*
  292          * This is necessary because either process' privileges may
  293          * have changed since the open() call.
  294          */
  295         if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc))
  296                 PFS_RETURN (EIO);
  297 
  298         if (pn->pn_getextattr == NULL)
  299                 error = EOPNOTSUPP;
  300         else
  301                 error = pn_getextattr(curthread, proc, pn,
  302                     va->a_attrnamespace, va->a_name, va->a_uio,
  303                     va->a_size, va->a_cred);
  304 
  305         if (proc != NULL)
  306                 PROC_UNLOCK(proc);
  307 
  308         PFS_RETURN (error);
  309 }
  310 
  311 /*
  312  * Look up a file or directory
  313  */
  314 static int
  315 pfs_lookup(struct vop_cachedlookup_args *va)
  316 {
  317         struct vnode *vn = va->a_dvp;
  318         struct vnode **vpp = va->a_vpp;
  319         struct componentname *cnp = va->a_cnp;
  320         struct pfs_vdata *pvd = vn->v_data;
  321         struct pfs_node *pd = pvd->pvd_pn;
  322         struct pfs_node *pn, *pdn = NULL;
  323         pid_t pid = pvd->pvd_pid;
  324         char *pname;
  325         int error, i, namelen, visible;
  326 
  327         PFS_TRACE(("%.*s", (int)cnp->cn_namelen, cnp->cn_nameptr));
  328         pfs_assert_not_owned(pd);
  329 
  330         if (vn->v_type != VDIR)
  331                 PFS_RETURN (ENOTDIR);
  332 
  333         error = VOP_ACCESS(vn, VEXEC, cnp->cn_cred, cnp->cn_thread);
  334         if (error)
  335                 PFS_RETURN (error);
  336 
  337         /*
  338          * Don't support DELETE or RENAME.  CREATE is supported so
  339          * that O_CREAT will work, but the lookup will still fail if
  340          * the file does not exist.
  341          */
  342         if ((cnp->cn_flags & ISLASTCN) &&
  343             (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
  344                 PFS_RETURN (EOPNOTSUPP);
  345 
  346         /* shortcut: check if the name is too long */
  347         if (cnp->cn_namelen >= PFS_NAMELEN)
  348                 PFS_RETURN (ENOENT);
  349 
  350         /* check that parent directory is visible... */
  351         if (!pfs_visible(curthread, pd, pvd->pvd_pid, NULL))
  352                 PFS_RETURN (ENOENT);
  353 
  354         /* self */
  355         namelen = cnp->cn_namelen;
  356         pname = cnp->cn_nameptr;
  357         if (namelen == 1 && pname[0] == '.') {
  358                 pn = pd;
  359                 *vpp = vn;
  360                 VREF(vn);
  361                 PFS_RETURN (0);
  362         }
  363 
  364         /* parent */
  365         if (cnp->cn_flags & ISDOTDOT) {
  366                 if (pd->pn_type == pfstype_root)
  367                         PFS_RETURN (EIO);
  368                 VOP_UNLOCK(vn, 0, cnp->cn_thread);
  369                 KASSERT(pd->pn_parent != NULL,
  370                     ("%s(): non-root directory has no parent", __func__));
  371                 /*
  372                  * This one is tricky.  Descendents of procdir nodes
  373                  * inherit their parent's process affinity, but
  374                  * there's no easy reverse mapping.  For simplicity,
  375                  * we assume that if this node is a procdir, its
  376                  * parent isn't (which is correct as long as
  377                  * descendents of procdir nodes are never procdir
  378                  * nodes themselves)
  379                  */
  380                 if (pd->pn_type == pfstype_procdir)
  381                         pid = NO_PID;
  382                 pfs_lock(pd);
  383                 pn = pd->pn_parent;
  384                 pfs_unlock(pd);
  385                 goto got_pnode;
  386         }
  387 
  388         pfs_lock(pd);
  389 
  390         /* named node */
  391         for (pn = pd->pn_nodes; pn != NULL; pn = pn->pn_next)
  392                 if (pn->pn_type == pfstype_procdir)
  393                         pdn = pn;
  394                 else if (pn->pn_name[namelen] == '\0' &&
  395                     bcmp(pname, pn->pn_name, namelen) == 0) {
  396                         pfs_unlock(pd);
  397                         goto got_pnode;
  398                 }
  399 
  400         /* process dependent node */
  401         if ((pn = pdn) != NULL) {
  402                 pid = 0;
  403                 for (pid = 0, i = 0; i < namelen && isdigit(pname[i]); ++i)
  404                         if ((pid = pid * 10 + pname[i] - '') > PID_MAX)
  405                                 break;
  406                 if (i == cnp->cn_namelen) {
  407                         pfs_unlock(pd);
  408                         goto got_pnode;
  409                 }
  410         }
  411 
  412         pfs_unlock(pd);
  413 
  414         PFS_RETURN (ENOENT);
  415 
  416  got_pnode:
  417         pfs_assert_not_owned(pd);
  418         pfs_assert_not_owned(pn);
  419         visible = pfs_visible(curthread, pn, pid, NULL);
  420         if (!visible) {
  421                 error = ENOENT;
  422                 goto failed;
  423         }
  424 
  425         error = pfs_vncache_alloc(vn->v_mount, vpp, pn, pid);
  426         if (error)
  427                 goto failed;
  428 
  429         if (cnp->cn_flags & ISDOTDOT)
  430                 vn_lock(vn, LK_EXCLUSIVE|LK_RETRY, cnp->cn_thread);
  431         if (cnp->cn_flags & MAKEENTRY)
  432                 cache_enter(vn, *vpp, cnp);
  433         PFS_RETURN (0);
  434  failed:
  435         if (cnp->cn_flags & ISDOTDOT)
  436                 vn_lock(vn, LK_EXCLUSIVE|LK_RETRY, cnp->cn_thread);
  437         PFS_RETURN(error);
  438 }
  439 
  440 /*
  441  * Open a file or directory.
  442  */
  443 static int
  444 pfs_open(struct vop_open_args *va)
  445 {
  446         struct vnode *vn = va->a_vp;
  447         struct pfs_vdata *pvd = vn->v_data;
  448         struct pfs_node *pn = pvd->pvd_pn;
  449         int mode = va->a_mode;
  450 
  451         PFS_TRACE(("%s (mode 0x%x)", pn->pn_name, mode));
  452         pfs_assert_not_owned(pn);
  453 
  454         /* check if the requested mode is permitted */
  455         if (((mode & FREAD) && !(mode & PFS_RD)) ||
  456             ((mode & FWRITE) && !(mode & PFS_WR)))
  457                 PFS_RETURN (EPERM);
  458 
  459         /* we don't support locking */
  460         if ((mode & O_SHLOCK) || (mode & O_EXLOCK))
  461                 PFS_RETURN (EOPNOTSUPP);
  462 
  463         PFS_RETURN (0);
  464 }
  465 
  466 /*
  467  * Read from a file
  468  */
  469 static int
  470 pfs_read(struct vop_read_args *va)
  471 {
  472         struct vnode *vn = va->a_vp;
  473         struct pfs_vdata *pvd = vn->v_data;
  474         struct pfs_node *pn = pvd->pvd_pn;
  475         struct uio *uio = va->a_uio;
  476         struct proc *proc;
  477         struct sbuf *sb = NULL;
  478         int error;
  479         unsigned int buflen, offset, resid;
  480 
  481         PFS_TRACE(("%s", pn->pn_name));
  482         pfs_assert_not_owned(pn);
  483 
  484         if (vn->v_type != VREG)
  485                 PFS_RETURN (EINVAL);
  486 
  487         if (!(pn->pn_flags & PFS_RD))
  488                 PFS_RETURN (EBADF);
  489 
  490         if (pn->pn_fill == NULL)
  491                 PFS_RETURN (EIO);
  492 
  493         /*
  494          * This is necessary because either process' privileges may
  495          * have changed since the open() call.
  496          */
  497         if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc))
  498                 PFS_RETURN (EIO);
  499         if (proc != NULL) {
  500                 _PHOLD(proc);
  501                 PROC_UNLOCK(proc);
  502         }
  503 
  504         if (pn->pn_flags & PFS_RAWRD) {
  505                 PFS_TRACE(("%lu resid", (unsigned long)uio->uio_resid));
  506                 error = pn_fill(curthread, proc, pn, NULL, uio);
  507                 PFS_TRACE(("%lu resid", (unsigned long)uio->uio_resid));
  508                 if (proc != NULL)
  509                         PRELE(proc);
  510                 PFS_RETURN (error);
  511         }
  512 
  513         /* beaucoup sanity checks so we don't ask for bogus allocation */
  514         if (uio->uio_offset < 0 || uio->uio_resid < 0 ||
  515             (offset = uio->uio_offset) != uio->uio_offset ||
  516             (resid = uio->uio_resid) != uio->uio_resid ||
  517             (buflen = offset + resid + 1) < offset || buflen > INT_MAX) {
  518                 if (proc != NULL)
  519                         PRELE(proc);
  520                 PFS_RETURN (EINVAL);
  521         }
  522         if (buflen > MAXPHYS + 1) {
  523                 if (proc != NULL)
  524                         PRELE(proc);
  525                 PFS_RETURN (EIO);
  526         }
  527 
  528         sb = sbuf_new(sb, NULL, buflen, 0);
  529         if (sb == NULL) {
  530                 if (proc != NULL)
  531                         PRELE(proc);
  532                 PFS_RETURN (EIO);
  533         }
  534 
  535         error = pn_fill(curthread, proc, pn, sb, uio);
  536 
  537         if (proc != NULL)
  538                 PRELE(proc);
  539 
  540         if (error) {
  541                 sbuf_delete(sb);
  542                 PFS_RETURN (error);
  543         }
  544 
  545         sbuf_finish(sb);
  546         error = uiomove_frombuf(sbuf_data(sb), sbuf_len(sb), uio);
  547         sbuf_delete(sb);
  548         PFS_RETURN (error);
  549 }
  550 
  551 /*
  552  * Iterate through directory entries
  553  */
  554 static int
  555 pfs_iterate(struct thread *td, struct proc *proc, struct pfs_node *pd,
  556             struct pfs_node **pn, struct proc **p)
  557 {
  558         int visible;
  559 
  560         sx_assert(&allproc_lock, SX_SLOCKED);
  561         pfs_assert_owned(pd);
  562  again:
  563         if (*pn == NULL) {
  564                 /* first node */
  565                 *pn = pd->pn_nodes;
  566         } else if ((*pn)->pn_type != pfstype_procdir) {
  567                 /* next node */
  568                 *pn = (*pn)->pn_next;
  569         }
  570         if (*pn != NULL && (*pn)->pn_type == pfstype_procdir) {
  571                 /* next process */
  572                 if (*p == NULL)
  573                         *p = LIST_FIRST(&allproc);
  574                 else
  575                         *p = LIST_NEXT(*p, p_list);
  576                 /* out of processes: next node */
  577                 if (*p == NULL)
  578                         *pn = (*pn)->pn_next;
  579                 else
  580                         PROC_LOCK(*p);
  581         }
  582 
  583         if ((*pn) == NULL)
  584                 return (-1);
  585 
  586         if (*p != NULL) {
  587                 visible = pfs_visible_proc(td, *pn, *p);
  588                 PROC_UNLOCK(*p);
  589         } else if (proc != NULL) {
  590                 visible = pfs_visible_proc(td, *pn, proc);
  591         } else {
  592                 visible = 1;
  593         }
  594         if (!visible)
  595                 goto again;
  596 
  597         return (0);
  598 }
  599 
  600 /*
  601  * Return directory entries.
  602  */
  603 static int
  604 pfs_readdir(struct vop_readdir_args *va)
  605 {
  606         struct vnode *vn = va->a_vp;
  607         struct pfs_vdata *pvd = vn->v_data;
  608         struct pfs_node *pd = pvd->pvd_pn;
  609         pid_t pid = pvd->pvd_pid;
  610         struct proc *p, *proc;
  611         struct pfs_node *pn;
  612         struct dirent *entry;
  613         struct uio *uio;
  614         off_t offset;
  615         int error, i, resid;
  616         char *buf, *ent;
  617 
  618         KASSERT(pd->pn_info == vn->v_mount->mnt_data,
  619             ("%s(): pn_info does not match mountpoint", __func__));
  620         PFS_TRACE(("%s pid %lu", pd->pn_name, (unsigned long)pid));
  621         pfs_assert_not_owned(pd);
  622 
  623         if (vn->v_type != VDIR)
  624                 PFS_RETURN (ENOTDIR);
  625         uio = va->a_uio;
  626 
  627         /* only allow reading entire entries */
  628         offset = uio->uio_offset;
  629         resid = uio->uio_resid;
  630         if (offset < 0 || offset % PFS_DELEN != 0 ||
  631             (resid && resid < PFS_DELEN))
  632                 PFS_RETURN (EINVAL);
  633         if (resid == 0)
  634                 PFS_RETURN (0);
  635 
  636         /* can't do this while holding the proc lock... */
  637         buf = malloc(resid, M_IOV, M_WAITOK | M_ZERO);
  638         sx_slock(&allproc_lock);
  639         pfs_lock(pd);
  640 
  641         /* check if the directory is visible to the caller */
  642         if (!pfs_visible(curthread, pd, pid, &proc)) {
  643                 sx_sunlock(&allproc_lock);
  644                 pfs_unlock(pd);
  645                 free(buf, M_IOV);
  646                 PFS_RETURN (ENOENT);
  647         }
  648         KASSERT(pid == NO_PID || proc != NULL,
  649             ("%s(): no process for pid %lu", __func__, (unsigned long)pid));
  650 
  651         /* skip unwanted entries */
  652         for (pn = NULL, p = NULL; offset > 0; offset -= PFS_DELEN) {
  653                 if (pfs_iterate(curthread, proc, pd, &pn, &p) == -1) {
  654                         /* nothing left... */
  655                         if (proc != NULL)
  656                                 PROC_UNLOCK(proc);
  657                         pfs_unlock(pd);
  658                         sx_sunlock(&allproc_lock);
  659                         free(buf, M_IOV);
  660                         PFS_RETURN (0);
  661                 }
  662         }
  663 
  664         /* fill in entries */
  665         ent = buf;
  666         while (pfs_iterate(curthread, proc, pd, &pn, &p) != -1 &&
  667             resid >= PFS_DELEN) {
  668                 entry = (struct dirent *)ent;
  669                 entry->d_reclen = PFS_DELEN;
  670                 entry->d_fileno = pn_fileno(pn, pid);
  671                 /* PFS_DELEN was picked to fit PFS_NAMLEN */
  672                 for (i = 0; i < PFS_NAMELEN - 1 && pn->pn_name[i] != '\0'; ++i)
  673                         entry->d_name[i] = pn->pn_name[i];
  674                 entry->d_name[i] = 0;
  675                 entry->d_namlen = i;
  676                 switch (pn->pn_type) {
  677                 case pfstype_procdir:
  678                         KASSERT(p != NULL,
  679                             ("reached procdir node with p == NULL"));
  680                         entry->d_namlen = snprintf(entry->d_name,
  681                             PFS_NAMELEN, "%d", p->p_pid);
  682                         /* fall through */
  683                 case pfstype_root:
  684                 case pfstype_dir:
  685                 case pfstype_this:
  686                 case pfstype_parent:
  687                         entry->d_type = DT_DIR;
  688                         break;
  689                 case pfstype_file:
  690                         entry->d_type = DT_REG;
  691                         break;
  692                 case pfstype_symlink:
  693                         entry->d_type = DT_LNK;
  694                         break;
  695                 default:
  696                         panic("%s has unexpected node type: %d", pn->pn_name, pn->pn_type);
  697                 }
  698                 PFS_TRACE(("%s", entry->d_name));
  699                 offset += PFS_DELEN;
  700                 resid -= PFS_DELEN;
  701                 ent += PFS_DELEN;
  702         }
  703         if (proc != NULL)
  704                 PROC_UNLOCK(proc);
  705         pfs_unlock(pd);
  706         sx_sunlock(&allproc_lock);
  707         PFS_TRACE(("%zd bytes", ent - buf));
  708         error = uiomove(buf, ent - buf, uio);
  709         free(buf, M_IOV);
  710         PFS_RETURN (error);
  711 }
  712 
  713 /*
  714  * Read a symbolic link
  715  */
  716 static int
  717 pfs_readlink(struct vop_readlink_args *va)
  718 {
  719         struct vnode *vn = va->a_vp;
  720         struct pfs_vdata *pvd = vn->v_data;
  721         struct pfs_node *pn = pvd->pvd_pn;
  722         struct uio *uio = va->a_uio;
  723         struct proc *proc = NULL;
  724         char buf[PATH_MAX];
  725         struct sbuf sb;
  726         int error;
  727 
  728         PFS_TRACE(("%s", pn->pn_name));
  729         pfs_assert_not_owned(pn);
  730 
  731         if (vn->v_type != VLNK)
  732                 PFS_RETURN (EINVAL);
  733 
  734         if (pn->pn_fill == NULL)
  735                 PFS_RETURN (EIO);
  736 
  737         if (pvd->pvd_pid != NO_PID) {
  738                 if ((proc = pfind(pvd->pvd_pid)) == NULL)
  739                         PFS_RETURN (EIO);
  740                 if (proc->p_flag & P_WEXIT) {
  741                         PROC_UNLOCK(proc);
  742                         PFS_RETURN (EIO);
  743                 }
  744                 _PHOLD(proc);
  745                 PROC_UNLOCK(proc);
  746         }
  747 
  748         /* sbuf_new() can't fail with a static buffer */
  749         sbuf_new(&sb, buf, sizeof buf, 0);
  750 
  751         error = pn_fill(curthread, proc, pn, &sb, NULL);
  752 
  753         if (proc != NULL)
  754                 PRELE(proc);
  755 
  756         if (error) {
  757                 sbuf_delete(&sb);
  758                 PFS_RETURN (error);
  759         }
  760 
  761         sbuf_finish(&sb);
  762         error = uiomove_frombuf(sbuf_data(&sb), sbuf_len(&sb), uio);
  763         sbuf_delete(&sb);
  764         PFS_RETURN (error);
  765 }
  766 
  767 /*
  768  * Reclaim a vnode
  769  */
  770 static int
  771 pfs_reclaim(struct vop_reclaim_args *va)
  772 {
  773         struct vnode *vn = va->a_vp;
  774         struct pfs_vdata *pvd = vn->v_data;
  775         struct pfs_node *pn = pvd->pvd_pn;
  776 
  777         PFS_TRACE(("%s", pn->pn_name));
  778         pfs_assert_not_owned(pn);
  779 
  780         return (pfs_vncache_free(va->a_vp));
  781 }
  782 
  783 /*
  784  * Set attributes
  785  */
  786 static int
  787 pfs_setattr(struct vop_setattr_args *va)
  788 {
  789         struct vnode *vn = va->a_vp;
  790         struct pfs_vdata *pvd = vn->v_data;
  791         struct pfs_node *pn = pvd->pvd_pn;
  792 
  793         PFS_TRACE(("%s", pn->pn_name));
  794         pfs_assert_not_owned(pn);
  795 
  796         PFS_RETURN (EOPNOTSUPP);
  797 }
  798 
  799 /*
  800  * Write to a file
  801  */
  802 static int
  803 pfs_write(struct vop_write_args *va)
  804 {
  805         struct vnode *vn = va->a_vp;
  806         struct pfs_vdata *pvd = vn->v_data;
  807         struct pfs_node *pn = pvd->pvd_pn;
  808         struct uio *uio = va->a_uio;
  809         struct proc *proc;
  810         struct sbuf sb;
  811         int error;
  812 
  813         PFS_TRACE(("%s", pn->pn_name));
  814         pfs_assert_not_owned(pn);
  815 
  816         if (vn->v_type != VREG)
  817                 PFS_RETURN (EINVAL);
  818         KASSERT(pn->pn_type != pfstype_file,
  819             ("%s(): VREG vnode refers to non-file pfs_node", __func__));
  820 
  821         if (!(pn->pn_flags & PFS_WR))
  822                 PFS_RETURN (EBADF);
  823 
  824         if (pn->pn_fill == NULL)
  825                 PFS_RETURN (EIO);
  826 
  827         /*
  828          * This is necessary because either process' privileges may
  829          * have changed since the open() call.
  830          */
  831         if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc))
  832                 PFS_RETURN (EIO);
  833         if (proc != NULL) {
  834                 _PHOLD(proc);
  835                 PROC_UNLOCK(proc);
  836         }
  837 
  838         if (pn->pn_flags & PFS_RAWWR) {
  839                 pfs_lock(pn);
  840                 error = pn_fill(curthread, proc, pn, NULL, uio);
  841                 pfs_unlock(pn);
  842                 if (proc != NULL)
  843                         PRELE(proc);
  844                 PFS_RETURN (error);
  845         }
  846 
  847         sbuf_uionew(&sb, uio, &error);
  848         if (error) {
  849                 if (proc != NULL)
  850                         PRELE(proc);
  851                 PFS_RETURN (error);
  852         }
  853 
  854         error = pn_fill(curthread, proc, pn, &sb, uio);
  855 
  856         sbuf_delete(&sb);
  857         if (proc != NULL)
  858                 PRELE(proc);
  859         PFS_RETURN (error);
  860 }
  861 
  862 /*
  863  * Vnode operations
  864  */
  865 struct vop_vector pfs_vnodeops = {
  866         .vop_default =          &default_vnodeops,
  867 
  868         .vop_access =           pfs_access,
  869         .vop_cachedlookup =     pfs_lookup,
  870         .vop_close =            pfs_close,
  871         .vop_create =           VOP_EOPNOTSUPP,
  872         .vop_getattr =          pfs_getattr,
  873         .vop_getextattr =       pfs_getextattr,
  874         .vop_ioctl =            pfs_ioctl,
  875         .vop_link =             VOP_EOPNOTSUPP,
  876         .vop_lookup =           vfs_cache_lookup,
  877         .vop_mkdir =            VOP_EOPNOTSUPP,
  878         .vop_mknod =            VOP_EOPNOTSUPP,
  879         .vop_open =             pfs_open,
  880         .vop_read =             pfs_read,
  881         .vop_readdir =          pfs_readdir,
  882         .vop_readlink =         pfs_readlink,
  883         .vop_reclaim =          pfs_reclaim,
  884         .vop_remove =           VOP_EOPNOTSUPP,
  885         .vop_rename =           VOP_EOPNOTSUPP,
  886         .vop_rmdir =            VOP_EOPNOTSUPP,
  887         .vop_setattr =          pfs_setattr,
  888         .vop_symlink =          VOP_EOPNOTSUPP,
  889         .vop_write =            pfs_write,
  890         /* XXX I've probably forgotten a few that need VOP_EOPNOTSUPP */
  891 };

Cache object: acc711e9d1f6945ce69c64f42b8d672d


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