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         vap->va_type = vn->v_type;
  195         vap->va_fileid = pn_fileno(pn, pvd->pvd_pid);
  196         vap->va_flags = 0;
  197         vap->va_blocksize = PAGE_SIZE;
  198         vap->va_bytes = vap->va_size = 0;
  199         vap->va_filerev = 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, locked;
  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         vhold(vn);
  506         locked = VOP_ISLOCKED(vn, curthread);
  507         VOP_UNLOCK(vn, 0, curthread);
  508 
  509         if (pn->pn_flags & PFS_RAWRD) {
  510                 PFS_TRACE(("%lu resid", (unsigned long)uio->uio_resid));
  511                 error = pn_fill(curthread, proc, pn, NULL, uio);
  512                 PFS_TRACE(("%lu resid", (unsigned long)uio->uio_resid));
  513                 goto ret;
  514         }
  515 
  516         /* beaucoup sanity checks so we don't ask for bogus allocation */
  517         if (uio->uio_offset < 0 || uio->uio_resid < 0 ||
  518             (offset = uio->uio_offset) != uio->uio_offset ||
  519             (resid = uio->uio_resid) != uio->uio_resid ||
  520             (buflen = offset + resid + 1) < offset || buflen > INT_MAX) {
  521                 if (proc != NULL)
  522                         PRELE(proc);
  523                 error = EINVAL;
  524                 goto ret;
  525         }
  526         if (buflen > MAXPHYS + 1) {
  527                 error = EIO;
  528                 goto ret;
  529         }
  530 
  531         sb = sbuf_new(sb, NULL, buflen, 0);
  532         if (sb == NULL) {
  533                 error = EIO;
  534                 goto ret;
  535         }
  536 
  537         error = pn_fill(curthread, proc, pn, sb, uio);
  538 
  539         if (error) {
  540                 sbuf_delete(sb);
  541                 goto ret;
  542         }
  543 
  544         sbuf_finish(sb);
  545         error = uiomove_frombuf(sbuf_data(sb), sbuf_len(sb), uio);
  546         sbuf_delete(sb);
  547 ret:
  548         vn_lock(vn, locked | LK_RETRY, curthread);
  549         vdrop(vn);
  550         if (proc != NULL)
  551                 PRELE(proc);
  552         PFS_RETURN (error);
  553 }
  554 
  555 /*
  556  * Iterate through directory entries
  557  */
  558 static int
  559 pfs_iterate(struct thread *td, struct proc *proc, struct pfs_node *pd,
  560             struct pfs_node **pn, struct proc **p)
  561 {
  562         int visible;
  563 
  564         sx_assert(&allproc_lock, SX_SLOCKED);
  565         pfs_assert_owned(pd);
  566  again:
  567         if (*pn == NULL) {
  568                 /* first node */
  569                 *pn = pd->pn_nodes;
  570         } else if ((*pn)->pn_type != pfstype_procdir) {
  571                 /* next node */
  572                 *pn = (*pn)->pn_next;
  573         }
  574         if (*pn != NULL && (*pn)->pn_type == pfstype_procdir) {
  575                 /* next process */
  576                 if (*p == NULL)
  577                         *p = LIST_FIRST(&allproc);
  578                 else
  579                         *p = LIST_NEXT(*p, p_list);
  580                 /* out of processes: next node */
  581                 if (*p == NULL)
  582                         *pn = (*pn)->pn_next;
  583                 else
  584                         PROC_LOCK(*p);
  585         }
  586 
  587         if ((*pn) == NULL)
  588                 return (-1);
  589 
  590         if (*p != NULL) {
  591                 visible = pfs_visible_proc(td, *pn, *p);
  592                 PROC_UNLOCK(*p);
  593         } else if (proc != NULL) {
  594                 visible = pfs_visible_proc(td, *pn, proc);
  595         } else {
  596                 visible = 1;
  597         }
  598         if (!visible)
  599                 goto again;
  600 
  601         return (0);
  602 }
  603 
  604 /*
  605  * Return directory entries.
  606  */
  607 static int
  608 pfs_readdir(struct vop_readdir_args *va)
  609 {
  610         struct vnode *vn = va->a_vp;
  611         struct pfs_vdata *pvd = vn->v_data;
  612         struct pfs_node *pd = pvd->pvd_pn;
  613         pid_t pid = pvd->pvd_pid;
  614         struct proc *p, *proc;
  615         struct pfs_node *pn;
  616         struct dirent *entry;
  617         struct uio *uio;
  618         off_t offset;
  619         int error, i, resid;
  620         char *buf, *ent;
  621 
  622         KASSERT(pd->pn_info == vn->v_mount->mnt_data,
  623             ("%s(): pn_info does not match mountpoint", __func__));
  624         PFS_TRACE(("%s pid %lu", pd->pn_name, (unsigned long)pid));
  625         pfs_assert_not_owned(pd);
  626 
  627         if (vn->v_type != VDIR)
  628                 PFS_RETURN (ENOTDIR);
  629         uio = va->a_uio;
  630 
  631         /* only allow reading entire entries */
  632         offset = uio->uio_offset;
  633         resid = uio->uio_resid;
  634         if (offset < 0 || offset % PFS_DELEN != 0 ||
  635             (resid && resid < PFS_DELEN))
  636                 PFS_RETURN (EINVAL);
  637         if (resid == 0)
  638                 PFS_RETURN (0);
  639 
  640         /* can't do this while holding the proc lock... */
  641         buf = malloc(resid, M_IOV, M_WAITOK | M_ZERO);
  642         sx_slock(&allproc_lock);
  643         pfs_lock(pd);
  644 
  645         /* check if the directory is visible to the caller */
  646         if (!pfs_visible(curthread, pd, pid, &proc)) {
  647                 sx_sunlock(&allproc_lock);
  648                 pfs_unlock(pd);
  649                 free(buf, M_IOV);
  650                 PFS_RETURN (ENOENT);
  651         }
  652         KASSERT(pid == NO_PID || proc != NULL,
  653             ("%s(): no process for pid %lu", __func__, (unsigned long)pid));
  654 
  655         /* skip unwanted entries */
  656         for (pn = NULL, p = NULL; offset > 0; offset -= PFS_DELEN) {
  657                 if (pfs_iterate(curthread, proc, pd, &pn, &p) == -1) {
  658                         /* nothing left... */
  659                         if (proc != NULL)
  660                                 PROC_UNLOCK(proc);
  661                         pfs_unlock(pd);
  662                         sx_sunlock(&allproc_lock);
  663                         free(buf, M_IOV);
  664                         PFS_RETURN (0);
  665                 }
  666         }
  667 
  668         /* fill in entries */
  669         ent = buf;
  670         while (pfs_iterate(curthread, proc, pd, &pn, &p) != -1 &&
  671             resid >= PFS_DELEN) {
  672                 entry = (struct dirent *)ent;
  673                 entry->d_reclen = PFS_DELEN;
  674                 entry->d_fileno = pn_fileno(pn, pid);
  675                 /* PFS_DELEN was picked to fit PFS_NAMLEN */
  676                 for (i = 0; i < PFS_NAMELEN - 1 && pn->pn_name[i] != '\0'; ++i)
  677                         entry->d_name[i] = pn->pn_name[i];
  678                 entry->d_name[i] = 0;
  679                 entry->d_namlen = i;
  680                 switch (pn->pn_type) {
  681                 case pfstype_procdir:
  682                         KASSERT(p != NULL,
  683                             ("reached procdir node with p == NULL"));
  684                         entry->d_namlen = snprintf(entry->d_name,
  685                             PFS_NAMELEN, "%d", p->p_pid);
  686                         /* fall through */
  687                 case pfstype_root:
  688                 case pfstype_dir:
  689                 case pfstype_this:
  690                 case pfstype_parent:
  691                         entry->d_type = DT_DIR;
  692                         break;
  693                 case pfstype_file:
  694                         entry->d_type = DT_REG;
  695                         break;
  696                 case pfstype_symlink:
  697                         entry->d_type = DT_LNK;
  698                         break;
  699                 default:
  700                         panic("%s has unexpected node type: %d", pn->pn_name, pn->pn_type);
  701                 }
  702                 PFS_TRACE(("%s", entry->d_name));
  703                 offset += PFS_DELEN;
  704                 resid -= PFS_DELEN;
  705                 ent += PFS_DELEN;
  706         }
  707         if (proc != NULL)
  708                 PROC_UNLOCK(proc);
  709         pfs_unlock(pd);
  710         sx_sunlock(&allproc_lock);
  711         PFS_TRACE(("%zd bytes", ent - buf));
  712         error = uiomove(buf, ent - buf, uio);
  713         free(buf, M_IOV);
  714         PFS_RETURN (error);
  715 }
  716 
  717 /*
  718  * Read a symbolic link
  719  */
  720 static int
  721 pfs_readlink(struct vop_readlink_args *va)
  722 {
  723         struct vnode *vn = va->a_vp;
  724         struct pfs_vdata *pvd = vn->v_data;
  725         struct pfs_node *pn = pvd->pvd_pn;
  726         struct uio *uio = va->a_uio;
  727         struct proc *proc = NULL;
  728         char buf[PATH_MAX];
  729         struct sbuf sb;
  730         int error;
  731 
  732         PFS_TRACE(("%s", pn->pn_name));
  733         pfs_assert_not_owned(pn);
  734 
  735         if (vn->v_type != VLNK)
  736                 PFS_RETURN (EINVAL);
  737 
  738         if (pn->pn_fill == NULL)
  739                 PFS_RETURN (EIO);
  740 
  741         if (pvd->pvd_pid != NO_PID) {
  742                 if ((proc = pfind(pvd->pvd_pid)) == NULL)
  743                         PFS_RETURN (EIO);
  744                 if (proc->p_flag & P_WEXIT) {
  745                         PROC_UNLOCK(proc);
  746                         PFS_RETURN (EIO);
  747                 }
  748                 _PHOLD(proc);
  749                 PROC_UNLOCK(proc);
  750         }
  751 
  752         /* sbuf_new() can't fail with a static buffer */
  753         sbuf_new(&sb, buf, sizeof buf, 0);
  754 
  755         error = pn_fill(curthread, proc, pn, &sb, NULL);
  756 
  757         if (proc != NULL)
  758                 PRELE(proc);
  759 
  760         if (error) {
  761                 sbuf_delete(&sb);
  762                 PFS_RETURN (error);
  763         }
  764 
  765         sbuf_finish(&sb);
  766         error = uiomove_frombuf(sbuf_data(&sb), sbuf_len(&sb), uio);
  767         sbuf_delete(&sb);
  768         PFS_RETURN (error);
  769 }
  770 
  771 /*
  772  * Reclaim a vnode
  773  */
  774 static int
  775 pfs_reclaim(struct vop_reclaim_args *va)
  776 {
  777         struct vnode *vn = va->a_vp;
  778         struct pfs_vdata *pvd = vn->v_data;
  779         struct pfs_node *pn = pvd->pvd_pn;
  780 
  781         PFS_TRACE(("%s", pn->pn_name));
  782         pfs_assert_not_owned(pn);
  783 
  784         return (pfs_vncache_free(va->a_vp));
  785 }
  786 
  787 /*
  788  * Set attributes
  789  */
  790 static int
  791 pfs_setattr(struct vop_setattr_args *va)
  792 {
  793         struct vnode *vn = va->a_vp;
  794         struct pfs_vdata *pvd = vn->v_data;
  795         struct pfs_node *pn = pvd->pvd_pn;
  796 
  797         PFS_TRACE(("%s", pn->pn_name));
  798         pfs_assert_not_owned(pn);
  799 
  800         PFS_RETURN (EOPNOTSUPP);
  801 }
  802 
  803 /*
  804  * Write to a file
  805  */
  806 static int
  807 pfs_write(struct vop_write_args *va)
  808 {
  809         struct vnode *vn = va->a_vp;
  810         struct pfs_vdata *pvd = vn->v_data;
  811         struct pfs_node *pn = pvd->pvd_pn;
  812         struct uio *uio = va->a_uio;
  813         struct proc *proc;
  814         struct sbuf sb;
  815         int error;
  816 
  817         PFS_TRACE(("%s", pn->pn_name));
  818         pfs_assert_not_owned(pn);
  819 
  820         if (vn->v_type != VREG)
  821                 PFS_RETURN (EINVAL);
  822         KASSERT(pn->pn_type != pfstype_file,
  823             ("%s(): VREG vnode refers to non-file pfs_node", __func__));
  824 
  825         if (!(pn->pn_flags & PFS_WR))
  826                 PFS_RETURN (EBADF);
  827 
  828         if (pn->pn_fill == NULL)
  829                 PFS_RETURN (EIO);
  830 
  831         /*
  832          * This is necessary because either process' privileges may
  833          * have changed since the open() call.
  834          */
  835         if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc))
  836                 PFS_RETURN (EIO);
  837         if (proc != NULL) {
  838                 _PHOLD(proc);
  839                 PROC_UNLOCK(proc);
  840         }
  841 
  842         if (pn->pn_flags & PFS_RAWWR) {
  843                 pfs_lock(pn);
  844                 error = pn_fill(curthread, proc, pn, NULL, uio);
  845                 pfs_unlock(pn);
  846                 if (proc != NULL)
  847                         PRELE(proc);
  848                 PFS_RETURN (error);
  849         }
  850 
  851         sbuf_uionew(&sb, uio, &error);
  852         if (error) {
  853                 if (proc != NULL)
  854                         PRELE(proc);
  855                 PFS_RETURN (error);
  856         }
  857 
  858         error = pn_fill(curthread, proc, pn, &sb, uio);
  859 
  860         sbuf_delete(&sb);
  861         if (proc != NULL)
  862                 PRELE(proc);
  863         PFS_RETURN (error);
  864 }
  865 
  866 /*
  867  * Vnode operations
  868  */
  869 struct vop_vector pfs_vnodeops = {
  870         .vop_default =          &default_vnodeops,
  871 
  872         .vop_access =           pfs_access,
  873         .vop_cachedlookup =     pfs_lookup,
  874         .vop_close =            pfs_close,
  875         .vop_create =           VOP_EOPNOTSUPP,
  876         .vop_getattr =          pfs_getattr,
  877         .vop_getextattr =       pfs_getextattr,
  878         .vop_ioctl =            pfs_ioctl,
  879         .vop_link =             VOP_EOPNOTSUPP,
  880         .vop_lookup =           vfs_cache_lookup,
  881         .vop_mkdir =            VOP_EOPNOTSUPP,
  882         .vop_mknod =            VOP_EOPNOTSUPP,
  883         .vop_open =             pfs_open,
  884         .vop_read =             pfs_read,
  885         .vop_readdir =          pfs_readdir,
  886         .vop_readlink =         pfs_readlink,
  887         .vop_reclaim =          pfs_reclaim,
  888         .vop_remove =           VOP_EOPNOTSUPP,
  889         .vop_rename =           VOP_EOPNOTSUPP,
  890         .vop_rmdir =            VOP_EOPNOTSUPP,
  891         .vop_setattr =          pfs_setattr,
  892         .vop_symlink =          VOP_EOPNOTSUPP,
  893         .vop_write =            pfs_write,
  894         /* XXX I've probably forgotten a few that need VOP_EOPNOTSUPP */
  895 };

Cache object: 9a45346a9aba26bd12bdb9565e22aea7


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