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$");
   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_unlock(pn);
  309         PFS_RETURN (error);
  310 }
  311 
  312 /*
  313  * Look up a file or directory
  314  */
  315 static int
  316 pfs_lookup(struct vop_cachedlookup_args *va)
  317 {
  318         struct vnode *vn = va->a_dvp;
  319         struct vnode **vpp = va->a_vpp;
  320         struct componentname *cnp = va->a_cnp;
  321         struct pfs_vdata *pvd = vn->v_data;
  322         struct pfs_node *pd = pvd->pvd_pn;
  323         struct pfs_node *pn, *pdn = NULL;
  324         pid_t pid = pvd->pvd_pid;
  325         char *pname;
  326         int error, i, namelen, visible;
  327 
  328         PFS_TRACE(("%.*s", (int)cnp->cn_namelen, cnp->cn_nameptr));
  329         pfs_assert_not_owned(pd);
  330 
  331         if (vn->v_type != VDIR)
  332                 PFS_RETURN (ENOTDIR);
  333 
  334         error = VOP_ACCESS(vn, VEXEC, cnp->cn_cred, cnp->cn_thread);
  335         if (error)
  336                 PFS_RETURN (error);
  337 
  338         /*
  339          * Don't support DELETE or RENAME.  CREATE is supported so
  340          * that O_CREAT will work, but the lookup will still fail if
  341          * the file does not exist.
  342          */
  343         if ((cnp->cn_flags & ISLASTCN) &&
  344             (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
  345                 PFS_RETURN (EOPNOTSUPP);
  346 
  347         /* shortcut: check if the name is too long */
  348         if (cnp->cn_namelen >= PFS_NAMELEN)
  349                 PFS_RETURN (ENOENT);
  350 
  351         /* check that parent directory is visible... */
  352         if (!pfs_visible(curthread, pd, pvd->pvd_pid, NULL))
  353                 PFS_RETURN (ENOENT);
  354 
  355         /* self */
  356         namelen = cnp->cn_namelen;
  357         pname = cnp->cn_nameptr;
  358         if (namelen == 1 && pname[0] == '.') {
  359                 pn = pd;
  360                 *vpp = vn;
  361                 VREF(vn);
  362                 PFS_RETURN (0);
  363         }
  364 
  365         /* parent */
  366         if (cnp->cn_flags & ISDOTDOT) {
  367                 if (pd->pn_type == pfstype_root)
  368                         PFS_RETURN (EIO);
  369                 VOP_UNLOCK(vn, 0, cnp->cn_thread);
  370                 KASSERT(pd->pn_parent != NULL,
  371                     ("%s(): non-root directory has no parent", __func__));
  372                 /*
  373                  * This one is tricky.  Descendents of procdir nodes
  374                  * inherit their parent's process affinity, but
  375                  * there's no easy reverse mapping.  For simplicity,
  376                  * we assume that if this node is a procdir, its
  377                  * parent isn't (which is correct as long as
  378                  * descendents of procdir nodes are never procdir
  379                  * nodes themselves)
  380                  */
  381                 if (pd->pn_type == pfstype_procdir)
  382                         pid = NO_PID;
  383                 pfs_lock(pd);
  384                 pn = pd->pn_parent;
  385                 pfs_unlock(pd);
  386                 goto got_pnode;
  387         }
  388 
  389         pfs_lock(pd);
  390 
  391         /* named node */
  392         for (pn = pd->pn_nodes; pn != NULL; pn = pn->pn_next)
  393                 if (pn->pn_type == pfstype_procdir)
  394                         pdn = pn;
  395                 else if (pn->pn_name[namelen] == '\0' &&
  396                     bcmp(pname, pn->pn_name, namelen) == 0) {
  397                         pfs_unlock(pd);
  398                         goto got_pnode;
  399                 }
  400 
  401         /* process dependent node */
  402         if ((pn = pdn) != NULL) {
  403                 pid = 0;
  404                 for (pid = 0, i = 0; i < namelen && isdigit(pname[i]); ++i)
  405                         if ((pid = pid * 10 + pname[i] - '') > PID_MAX)
  406                                 break;
  407                 if (i == cnp->cn_namelen) {
  408                         pfs_unlock(pd);
  409                         goto got_pnode;
  410                 }
  411         }
  412 
  413         pfs_unlock(pd);
  414 
  415         PFS_RETURN (ENOENT);
  416 
  417  got_pnode:
  418         pfs_assert_not_owned(pd);
  419         pfs_assert_not_owned(pn);
  420         visible = pfs_visible(curthread, pn, pid, NULL);
  421         if (!visible) {
  422                 error = ENOENT;
  423                 goto failed;
  424         }
  425 
  426         error = pfs_vncache_alloc(vn->v_mount, vpp, pn, pid);
  427         if (error)
  428                 goto failed;
  429 
  430         if (cnp->cn_flags & ISDOTDOT)
  431                 vn_lock(vn, LK_EXCLUSIVE|LK_RETRY, cnp->cn_thread);
  432         if (cnp->cn_flags & MAKEENTRY)
  433                 cache_enter(vn, *vpp, cnp);
  434         PFS_RETURN (0);
  435  failed:
  436         if (cnp->cn_flags & ISDOTDOT)
  437                 vn_lock(vn, LK_EXCLUSIVE|LK_RETRY, cnp->cn_thread);
  438         PFS_RETURN(error);
  439 }
  440 
  441 /*
  442  * Open a file or directory.
  443  */
  444 static int
  445 pfs_open(struct vop_open_args *va)
  446 {
  447         struct vnode *vn = va->a_vp;
  448         struct pfs_vdata *pvd = vn->v_data;
  449         struct pfs_node *pn = pvd->pvd_pn;
  450         int mode = va->a_mode;
  451 
  452         PFS_TRACE(("%s (mode 0x%x)", pn->pn_name, mode));
  453         pfs_assert_not_owned(pn);
  454 
  455         /* check if the requested mode is permitted */
  456         if (((mode & FREAD) && !(mode & PFS_RD)) ||
  457             ((mode & FWRITE) && !(mode & PFS_WR)))
  458                 PFS_RETURN (EPERM);
  459 
  460         /* we don't support locking */
  461         if ((mode & O_SHLOCK) || (mode & O_EXLOCK))
  462                 PFS_RETURN (EOPNOTSUPP);
  463 
  464         PFS_RETURN (0);
  465 }
  466 
  467 /*
  468  * Read from a file
  469  */
  470 static int
  471 pfs_read(struct vop_read_args *va)
  472 {
  473         struct vnode *vn = va->a_vp;
  474         struct pfs_vdata *pvd = vn->v_data;
  475         struct pfs_node *pn = pvd->pvd_pn;
  476         struct uio *uio = va->a_uio;
  477         struct proc *proc;
  478         struct sbuf *sb = NULL;
  479         int error;
  480         unsigned int buflen, offset, resid;
  481 
  482         PFS_TRACE(("%s", pn->pn_name));
  483         pfs_assert_not_owned(pn);
  484 
  485         if (vn->v_type != VREG)
  486                 PFS_RETURN (EINVAL);
  487 
  488         if (!(pn->pn_flags & PFS_RD))
  489                 PFS_RETURN (EBADF);
  490 
  491         if (pn->pn_fill == NULL)
  492                 PFS_RETURN (EIO);
  493 
  494         /*
  495          * This is necessary because either process' privileges may
  496          * have changed since the open() call.
  497          */
  498         if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc))
  499                 PFS_RETURN (EIO);
  500         if (proc != NULL) {
  501                 _PHOLD(proc);
  502                 PROC_UNLOCK(proc);
  503         }
  504 
  505         if (pn->pn_flags & PFS_RAWRD) {
  506                 PFS_TRACE(("%lu resid", (unsigned long)uio->uio_resid));
  507                 error = pn_fill(curthread, proc, pn, NULL, uio);
  508                 PFS_TRACE(("%lu resid", (unsigned long)uio->uio_resid));
  509                 if (proc != NULL)
  510                         PRELE(proc);
  511                 PFS_RETURN (error);
  512         }
  513 
  514         /* beaucoup sanity checks so we don't ask for bogus allocation */
  515         if (uio->uio_offset < 0 || uio->uio_resid < 0 ||
  516             (offset = uio->uio_offset) != uio->uio_offset ||
  517             (resid = uio->uio_resid) != uio->uio_resid ||
  518             (buflen = offset + resid + 1) < offset || buflen > INT_MAX) {
  519                 if (proc != NULL)
  520                         PRELE(proc);
  521                 PFS_RETURN (EINVAL);
  522         }
  523         if (buflen > MAXPHYS + 1) {
  524                 if (proc != NULL)
  525                         PRELE(proc);
  526                 PFS_RETURN (EIO);
  527         }
  528 
  529         sb = sbuf_new(sb, NULL, buflen, 0);
  530         if (sb == NULL) {
  531                 if (proc != NULL)
  532                         PRELE(proc);
  533                 PFS_RETURN (EIO);
  534         }
  535 
  536         error = pn_fill(curthread, proc, pn, sb, uio);
  537 
  538         if (proc != NULL)
  539                 PRELE(proc);
  540 
  541         if (error) {
  542                 sbuf_delete(sb);
  543                 PFS_RETURN (error);
  544         }
  545 
  546         sbuf_finish(sb);
  547         error = uiomove_frombuf(sbuf_data(sb), sbuf_len(sb), uio);
  548         sbuf_delete(sb);
  549         PFS_RETURN (error);
  550 }
  551 
  552 /*
  553  * Iterate through directory entries
  554  */
  555 static int
  556 pfs_iterate(struct thread *td, struct proc *proc, struct pfs_node *pd,
  557             struct pfs_node **pn, struct proc **p)
  558 {
  559         int visible;
  560 
  561         sx_assert(&allproc_lock, SX_SLOCKED);
  562         pfs_assert_owned(pd);
  563  again:
  564         if (*pn == NULL) {
  565                 /* first node */
  566                 *pn = pd->pn_nodes;
  567         } else if ((*pn)->pn_type != pfstype_procdir) {
  568                 /* next node */
  569                 *pn = (*pn)->pn_next;
  570         }
  571         if (*pn != NULL && (*pn)->pn_type == pfstype_procdir) {
  572                 /* next process */
  573                 if (*p == NULL)
  574                         *p = LIST_FIRST(&allproc);
  575                 else
  576                         *p = LIST_NEXT(*p, p_list);
  577                 /* out of processes: next node */
  578                 if (*p == NULL)
  579                         *pn = (*pn)->pn_next;
  580                 else
  581                         PROC_LOCK(*p);
  582         }
  583 
  584         if ((*pn) == NULL)
  585                 return (-1);
  586 
  587         if (*p != NULL) {
  588                 visible = pfs_visible_proc(td, *pn, *p);
  589                 PROC_UNLOCK(*p);
  590         } else if (proc != NULL) {
  591                 visible = pfs_visible_proc(td, *pn, proc);
  592         } else {
  593                 visible = 1;
  594         }
  595         if (!visible)
  596                 goto again;
  597 
  598         return (0);
  599 }
  600 
  601 /*
  602  * Return directory entries.
  603  */
  604 static int
  605 pfs_readdir(struct vop_readdir_args *va)
  606 {
  607         struct vnode *vn = va->a_vp;
  608         struct pfs_vdata *pvd = vn->v_data;
  609         struct pfs_node *pd = pvd->pvd_pn;
  610         pid_t pid = pvd->pvd_pid;
  611         struct proc *p, *proc;
  612         struct pfs_node *pn;
  613         struct dirent *entry;
  614         struct uio *uio;
  615         off_t offset;
  616         int error, i, resid;
  617         char *buf, *ent;
  618 
  619         KASSERT(pd->pn_info == vn->v_mount->mnt_data,
  620             ("%s(): pn_info does not match mountpoint", __func__));
  621         PFS_TRACE(("%s pid %lu", pd->pn_name, (unsigned long)pid));
  622         pfs_assert_not_owned(pd);
  623 
  624         if (vn->v_type != VDIR)
  625                 PFS_RETURN (ENOTDIR);
  626         uio = va->a_uio;
  627 
  628         /* only allow reading entire entries */
  629         offset = uio->uio_offset;
  630         resid = uio->uio_resid;
  631         if (offset < 0 || offset % PFS_DELEN != 0 ||
  632             (resid && resid < PFS_DELEN))
  633                 PFS_RETURN (EINVAL);
  634         if (resid == 0)
  635                 PFS_RETURN (0);
  636 
  637         /* can't do this while holding the proc lock... */
  638         buf = malloc(resid, M_IOV, M_WAITOK | M_ZERO);
  639         sx_slock(&allproc_lock);
  640         pfs_lock(pd);
  641 
  642         /* check if the directory is visible to the caller */
  643         if (!pfs_visible(curthread, pd, pid, &proc)) {
  644                 sx_sunlock(&allproc_lock);
  645                 pfs_unlock(pd);
  646                 free(buf, M_IOV);
  647                 PFS_RETURN (ENOENT);
  648         }
  649         KASSERT(pid == NO_PID || proc != NULL,
  650             ("%s(): no process for pid %lu", __func__, (unsigned long)pid));
  651 
  652         /* skip unwanted entries */
  653         for (pn = NULL, p = NULL; offset > 0; offset -= PFS_DELEN) {
  654                 if (pfs_iterate(curthread, proc, pd, &pn, &p) == -1) {
  655                         /* nothing left... */
  656                         if (proc != NULL)
  657                                 PROC_UNLOCK(proc);
  658                         pfs_unlock(pd);
  659                         sx_sunlock(&allproc_lock);
  660                         free(buf, M_IOV);
  661                         PFS_RETURN (0);
  662                 }
  663         }
  664 
  665         /* fill in entries */
  666         ent = buf;
  667         while (pfs_iterate(curthread, proc, pd, &pn, &p) != -1 &&
  668             resid >= PFS_DELEN) {
  669                 entry = (struct dirent *)ent;
  670                 entry->d_reclen = PFS_DELEN;
  671                 entry->d_fileno = pn_fileno(pn, pid);
  672                 /* PFS_DELEN was picked to fit PFS_NAMLEN */
  673                 for (i = 0; i < PFS_NAMELEN - 1 && pn->pn_name[i] != '\0'; ++i)
  674                         entry->d_name[i] = pn->pn_name[i];
  675                 entry->d_name[i] = 0;
  676                 entry->d_namlen = i;
  677                 switch (pn->pn_type) {
  678                 case pfstype_procdir:
  679                         KASSERT(p != NULL,
  680                             ("reached procdir node with p == NULL"));
  681                         entry->d_namlen = snprintf(entry->d_name,
  682                             PFS_NAMELEN, "%d", p->p_pid);
  683                         /* fall through */
  684                 case pfstype_root:
  685                 case pfstype_dir:
  686                 case pfstype_this:
  687                 case pfstype_parent:
  688                         entry->d_type = DT_DIR;
  689                         break;
  690                 case pfstype_file:
  691                         entry->d_type = DT_REG;
  692                         break;
  693                 case pfstype_symlink:
  694                         entry->d_type = DT_LNK;
  695                         break;
  696                 default:
  697                         panic("%s has unexpected node type: %d", pn->pn_name, pn->pn_type);
  698                 }
  699                 PFS_TRACE(("%s", entry->d_name));
  700                 offset += PFS_DELEN;
  701                 resid -= PFS_DELEN;
  702                 ent += PFS_DELEN;
  703         }
  704         if (proc != NULL)
  705                 PROC_UNLOCK(proc);
  706         pfs_unlock(pd);
  707         sx_sunlock(&allproc_lock);
  708         PFS_TRACE(("%zd bytes", ent - buf));
  709         error = uiomove(buf, ent - buf, uio);
  710         free(buf, M_IOV);
  711         PFS_RETURN (error);
  712 }
  713 
  714 /*
  715  * Read a symbolic link
  716  */
  717 static int
  718 pfs_readlink(struct vop_readlink_args *va)
  719 {
  720         struct vnode *vn = va->a_vp;
  721         struct pfs_vdata *pvd = vn->v_data;
  722         struct pfs_node *pn = pvd->pvd_pn;
  723         struct uio *uio = va->a_uio;
  724         struct proc *proc = NULL;
  725         char buf[PATH_MAX];
  726         struct sbuf sb;
  727         int error;
  728 
  729         PFS_TRACE(("%s", pn->pn_name));
  730         pfs_assert_not_owned(pn);
  731 
  732         if (vn->v_type != VLNK)
  733                 PFS_RETURN (EINVAL);
  734 
  735         if (pn->pn_fill == NULL)
  736                 PFS_RETURN (EIO);
  737 
  738         if (pvd->pvd_pid != NO_PID) {
  739                 if ((proc = pfind(pvd->pvd_pid)) == NULL)
  740                         PFS_RETURN (EIO);
  741                 if (proc->p_flag & P_WEXIT) {
  742                         PROC_UNLOCK(proc);
  743                         PFS_RETURN (EIO);
  744                 }
  745                 _PHOLD(proc);
  746                 PROC_UNLOCK(proc);
  747         }
  748 
  749         /* sbuf_new() can't fail with a static buffer */
  750         sbuf_new(&sb, buf, sizeof buf, 0);
  751 
  752         error = pn_fill(curthread, proc, pn, &sb, NULL);
  753 
  754         if (proc != NULL)
  755                 PRELE(proc);
  756 
  757         if (error) {
  758                 sbuf_delete(&sb);
  759                 PFS_RETURN (error);
  760         }
  761 
  762         sbuf_finish(&sb);
  763         error = uiomove_frombuf(sbuf_data(&sb), sbuf_len(&sb), uio);
  764         sbuf_delete(&sb);
  765         PFS_RETURN (error);
  766 }
  767 
  768 /*
  769  * Reclaim a vnode
  770  */
  771 static int
  772 pfs_reclaim(struct vop_reclaim_args *va)
  773 {
  774         struct vnode *vn = va->a_vp;
  775         struct pfs_vdata *pvd = vn->v_data;
  776         struct pfs_node *pn = pvd->pvd_pn;
  777 
  778         PFS_TRACE(("%s", pn->pn_name));
  779         pfs_assert_not_owned(pn);
  780 
  781         return (pfs_vncache_free(va->a_vp));
  782 }
  783 
  784 /*
  785  * Set attributes
  786  */
  787 static int
  788 pfs_setattr(struct vop_setattr_args *va)
  789 {
  790         struct vnode *vn = va->a_vp;
  791         struct pfs_vdata *pvd = vn->v_data;
  792         struct pfs_node *pn = pvd->pvd_pn;
  793 
  794         PFS_TRACE(("%s", pn->pn_name));
  795         pfs_assert_not_owned(pn);
  796 
  797         PFS_RETURN (EOPNOTSUPP);
  798 }
  799 
  800 /*
  801  * Write to a file
  802  */
  803 static int
  804 pfs_write(struct vop_write_args *va)
  805 {
  806         struct vnode *vn = va->a_vp;
  807         struct pfs_vdata *pvd = vn->v_data;
  808         struct pfs_node *pn = pvd->pvd_pn;
  809         struct uio *uio = va->a_uio;
  810         struct proc *proc;
  811         struct sbuf sb;
  812         int error;
  813 
  814         PFS_TRACE(("%s", pn->pn_name));
  815         pfs_assert_not_owned(pn);
  816 
  817         if (vn->v_type != VREG)
  818                 PFS_RETURN (EINVAL);
  819         KASSERT(pn->pn_type != pfstype_file,
  820             ("%s(): VREG vnode refers to non-file pfs_node", __func__));
  821 
  822         if (!(pn->pn_flags & PFS_WR))
  823                 PFS_RETURN (EBADF);
  824 
  825         if (pn->pn_fill == NULL)
  826                 PFS_RETURN (EIO);
  827 
  828         /*
  829          * This is necessary because either process' privileges may
  830          * have changed since the open() call.
  831          */
  832         if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc))
  833                 PFS_RETURN (EIO);
  834         if (proc != NULL) {
  835                 _PHOLD(proc);
  836                 PROC_UNLOCK(proc);
  837         }
  838 
  839         if (pn->pn_flags & PFS_RAWWR) {
  840                 pfs_lock(pn);
  841                 error = pn_fill(curthread, proc, pn, NULL, uio);
  842                 pfs_unlock(pn);
  843                 if (proc != NULL)
  844                         PRELE(proc);
  845                 PFS_RETURN (error);
  846         }
  847 
  848         sbuf_uionew(&sb, uio, &error);
  849         if (error) {
  850                 if (proc != NULL)
  851                         PRELE(proc);
  852                 PFS_RETURN (error);
  853         }
  854 
  855         error = pn_fill(curthread, proc, pn, &sb, uio);
  856 
  857         sbuf_delete(&sb);
  858         if (proc != NULL)
  859                 PRELE(proc);
  860         PFS_RETURN (error);
  861 }
  862 
  863 /*
  864  * Vnode operations
  865  */
  866 struct vop_vector pfs_vnodeops = {
  867         .vop_default =          &default_vnodeops,
  868 
  869         .vop_access =           pfs_access,
  870         .vop_cachedlookup =     pfs_lookup,
  871         .vop_close =            pfs_close,
  872         .vop_create =           VOP_EOPNOTSUPP,
  873         .vop_getattr =          pfs_getattr,
  874         .vop_getextattr =       pfs_getextattr,
  875         .vop_ioctl =            pfs_ioctl,
  876         .vop_link =             VOP_EOPNOTSUPP,
  877         .vop_lookup =           vfs_cache_lookup,
  878         .vop_mkdir =            VOP_EOPNOTSUPP,
  879         .vop_mknod =            VOP_EOPNOTSUPP,
  880         .vop_open =             pfs_open,
  881         .vop_read =             pfs_read,
  882         .vop_readdir =          pfs_readdir,
  883         .vop_readlink =         pfs_readlink,
  884         .vop_reclaim =          pfs_reclaim,
  885         .vop_remove =           VOP_EOPNOTSUPP,
  886         .vop_rename =           VOP_EOPNOTSUPP,
  887         .vop_rmdir =            VOP_EOPNOTSUPP,
  888         .vop_setattr =          pfs_setattr,
  889         .vop_symlink =          VOP_EOPNOTSUPP,
  890         .vop_write =            pfs_write,
  891         /* XXX I've probably forgotten a few that need VOP_EOPNOTSUPP */
  892 };

Cache object: b9338208f56f4c440d9f3afa4f958bc1


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