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  * SPDX-License-Identifier: BSD-3-Clause
    3  *
    4  * Copyright (c) 2001 Dag-Erling Coïdan Smørgrav
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer
   12  *    in this position and unchanged.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. The name of the author may not be used to endorse or promote products
   17  *    derived from this software without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   29  */
   30 
   31 #include <sys/cdefs.h>
   32 __FBSDID("$FreeBSD$");
   33 
   34 #include "opt_pseudofs.h"
   35 
   36 #include <sys/param.h>
   37 #include <sys/kernel.h>
   38 #include <sys/systm.h>
   39 #include <sys/ctype.h>
   40 #include <sys/dirent.h>
   41 #include <sys/fcntl.h>
   42 #include <sys/limits.h>
   43 #include <sys/lock.h>
   44 #include <sys/malloc.h>
   45 #include <sys/mount.h>
   46 #include <sys/mutex.h>
   47 #include <sys/namei.h>
   48 #include <sys/proc.h>
   49 #include <sys/sbuf.h>
   50 #include <sys/sx.h>
   51 #include <sys/sysctl.h>
   52 #include <sys/vnode.h>
   53 
   54 #include <fs/pseudofs/pseudofs.h>
   55 #include <fs/pseudofs/pseudofs_internal.h>
   56 
   57 #define KASSERT_PN_IS_DIR(pn)                                           \
   58         KASSERT((pn)->pn_type == pfstype_root ||                        \
   59             (pn)->pn_type == pfstype_dir ||                             \
   60             (pn)->pn_type == pfstype_procdir,                           \
   61             ("%s(): VDIR vnode refers to non-directory pfs_node", __func__))
   62 
   63 #define KASSERT_PN_IS_FILE(pn)                                          \
   64         KASSERT((pn)->pn_type == pfstype_file,                          \
   65             ("%s(): VREG vnode refers to non-file pfs_node", __func__))
   66 
   67 #define KASSERT_PN_IS_LINK(pn)                                          \
   68         KASSERT((pn)->pn_type == pfstype_symlink,                       \
   69             ("%s(): VLNK vnode refers to non-link pfs_node", __func__))
   70 
   71 #define PFS_MAXBUFSIZ           1024 * 1024
   72 
   73 /*
   74  * Returns the fileno, adjusted for target pid
   75  */
   76 static uint32_t
   77 pn_fileno(struct pfs_node *pn, pid_t pid)
   78 {
   79 
   80         KASSERT(pn->pn_fileno > 0,
   81             ("%s(): no fileno allocated", __func__));
   82         if (pid != NO_PID)
   83                 return (pn->pn_fileno * NO_PID + pid);
   84         return (pn->pn_fileno);
   85 }
   86 
   87 /*
   88  * Returns non-zero if given file is visible to given thread.
   89  */
   90 static int
   91 pfs_visible_proc(struct thread *td, struct pfs_node *pn, struct proc *proc)
   92 {
   93         int visible;
   94 
   95         if (proc == NULL)
   96                 return (0);
   97 
   98         PROC_LOCK_ASSERT(proc, MA_OWNED);
   99 
  100         visible = ((proc->p_flag & P_WEXIT) == 0);
  101         if (visible)
  102                 visible = (p_cansee(td, proc) == 0);
  103         if (visible && pn->pn_vis != NULL)
  104                 visible = pn_vis(td, proc, pn);
  105         if (!visible)
  106                 return (0);
  107         return (1);
  108 }
  109 
  110 static int
  111 pfs_visible(struct thread *td, struct pfs_node *pn, pid_t pid,
  112     struct proc **p)
  113 {
  114         struct proc *proc;
  115 
  116         PFS_TRACE(("%s (pid: %d, req: %d)",
  117             pn->pn_name, pid, td->td_proc->p_pid));
  118 
  119         if (p)
  120                 *p = NULL;
  121         if (pid == NO_PID)
  122                 PFS_RETURN (1);
  123         proc = pfind(pid);
  124         if (proc == NULL)
  125                 PFS_RETURN (0);
  126         if (pfs_visible_proc(td, pn, proc)) {
  127                 if (p)
  128                         *p = proc;
  129                 else
  130                         PROC_UNLOCK(proc);
  131                 PFS_RETURN (1);
  132         }
  133         PROC_UNLOCK(proc);
  134         PFS_RETURN (0);
  135 }
  136 
  137 static int
  138 pfs_lookup_proc(pid_t pid, struct proc **p)
  139 {
  140         struct proc *proc;
  141 
  142         proc = pfind(pid);
  143         if (proc == NULL)
  144                 return (0);
  145         if ((proc->p_flag & P_WEXIT) != 0) {
  146                 PROC_UNLOCK(proc);
  147                 return (0);
  148         }
  149         _PHOLD(proc);
  150         PROC_UNLOCK(proc);
  151         *p = proc;
  152         return (1);
  153 }
  154 
  155 /*
  156  * Verify permissions
  157  */
  158 static int
  159 pfs_access(struct vop_access_args *va)
  160 {
  161         struct vnode *vn = va->a_vp;
  162         struct pfs_vdata *pvd = vn->v_data;
  163         struct vattr vattr;
  164         int error;
  165 
  166         PFS_TRACE(("%s", pvd->pvd_pn->pn_name));
  167         (void)pvd;
  168 
  169         error = VOP_GETATTR(vn, &vattr, va->a_cred);
  170         if (error)
  171                 PFS_RETURN (error);
  172         error = vaccess(vn->v_type, vattr.va_mode, vattr.va_uid, vattr.va_gid,
  173             va->a_accmode, va->a_cred);
  174         PFS_RETURN (error);
  175 }
  176 
  177 /*
  178  * Close a file or directory
  179  */
  180 static int
  181 pfs_close(struct vop_close_args *va)
  182 {
  183         struct vnode *vn = va->a_vp;
  184         struct pfs_vdata *pvd = vn->v_data;
  185         struct pfs_node *pn = pvd->pvd_pn;
  186         struct proc *proc;
  187         int error;
  188 
  189         PFS_TRACE(("%s", pn->pn_name));
  190         pfs_assert_not_owned(pn);
  191 
  192         /*
  193          * Do nothing unless this is the last close and the node has a
  194          * last-close handler.
  195          */
  196         if (vrefcnt(vn) > 1 || pn->pn_close == NULL)
  197                 PFS_RETURN (0);
  198 
  199         if (pvd->pvd_pid != NO_PID) {
  200                 proc = pfind(pvd->pvd_pid);
  201         } else {
  202                 proc = NULL;
  203         }
  204 
  205         error = pn_close(va->a_td, proc, pn);
  206 
  207         if (proc != NULL)
  208                 PROC_UNLOCK(proc);
  209 
  210         PFS_RETURN (error);
  211 }
  212 
  213 /*
  214  * Get file attributes
  215  */
  216 static int
  217 pfs_getattr(struct vop_getattr_args *va)
  218 {
  219         struct vnode *vn = va->a_vp;
  220         struct pfs_vdata *pvd = vn->v_data;
  221         struct pfs_node *pn = pvd->pvd_pn;
  222         struct vattr *vap = va->a_vap;
  223         struct proc *proc;
  224         int error = 0;
  225 
  226         PFS_TRACE(("%s", pn->pn_name));
  227         pfs_assert_not_owned(pn);
  228 
  229         if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc))
  230                 PFS_RETURN (ENOENT);
  231 
  232         vap->va_type = vn->v_type;
  233         vap->va_fileid = pn_fileno(pn, pvd->pvd_pid);
  234         vap->va_flags = 0;
  235         vap->va_blocksize = PAGE_SIZE;
  236         vap->va_bytes = vap->va_size = 0;
  237         vap->va_filerev = 0;
  238         vap->va_fsid = vn->v_mount->mnt_stat.f_fsid.val[0];
  239         vap->va_nlink = 1;
  240         nanotime(&vap->va_ctime);
  241         vap->va_atime = vap->va_mtime = vap->va_ctime;
  242 
  243         switch (pn->pn_type) {
  244         case pfstype_procdir:
  245         case pfstype_root:
  246         case pfstype_dir:
  247 #if 0
  248                 pfs_lock(pn);
  249                 /* compute link count */
  250                 pfs_unlock(pn);
  251 #endif
  252                 vap->va_mode = 0555;
  253                 break;
  254         case pfstype_file:
  255         case pfstype_symlink:
  256                 vap->va_mode = 0444;
  257                 break;
  258         default:
  259                 printf("shouldn't be here!\n");
  260                 vap->va_mode = 0;
  261                 break;
  262         }
  263 
  264         if (proc != NULL) {
  265                 vap->va_uid = proc->p_ucred->cr_ruid;
  266                 vap->va_gid = proc->p_ucred->cr_rgid;
  267         } else {
  268                 vap->va_uid = 0;
  269                 vap->va_gid = 0;
  270         }
  271 
  272         if (pn->pn_attr != NULL)
  273                 error = pn_attr(curthread, proc, pn, vap);
  274 
  275         if(proc != NULL)
  276                 PROC_UNLOCK(proc);
  277 
  278         PFS_RETURN (error);
  279 }
  280 
  281 /*
  282  * Perform an ioctl
  283  */
  284 static int
  285 pfs_ioctl(struct vop_ioctl_args *va)
  286 {
  287         struct vnode *vn;
  288         struct pfs_vdata *pvd;
  289         struct pfs_node *pn;
  290         struct proc *proc;
  291         int error;
  292 
  293         vn = va->a_vp;
  294         vn_lock(vn, LK_SHARED | LK_RETRY);
  295         if (VN_IS_DOOMED(vn)) {
  296                 VOP_UNLOCK(vn);
  297                 return (EBADF);
  298         }
  299         pvd = vn->v_data;
  300         pn = pvd->pvd_pn;
  301 
  302         PFS_TRACE(("%s: %lx", pn->pn_name, va->a_command));
  303         pfs_assert_not_owned(pn);
  304 
  305         if (vn->v_type != VREG) {
  306                 VOP_UNLOCK(vn);
  307                 PFS_RETURN (EINVAL);
  308         }
  309         KASSERT_PN_IS_FILE(pn);
  310 
  311         if (pn->pn_ioctl == NULL) {
  312                 VOP_UNLOCK(vn);
  313                 PFS_RETURN (ENOTTY);
  314         }
  315 
  316         /*
  317          * This is necessary because process' privileges may
  318          * have changed since the open() call.
  319          */
  320         if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc)) {
  321                 VOP_UNLOCK(vn);
  322                 PFS_RETURN (EIO);
  323         }
  324 
  325         error = pn_ioctl(curthread, proc, pn, va->a_command, va->a_data);
  326 
  327         if (proc != NULL)
  328                 PROC_UNLOCK(proc);
  329 
  330         VOP_UNLOCK(vn);
  331         PFS_RETURN (error);
  332 }
  333 
  334 /*
  335  * Perform getextattr
  336  */
  337 static int
  338 pfs_getextattr(struct vop_getextattr_args *va)
  339 {
  340         struct vnode *vn = va->a_vp;
  341         struct pfs_vdata *pvd = vn->v_data;
  342         struct pfs_node *pn = pvd->pvd_pn;
  343         struct proc *proc;
  344         int error;
  345 
  346         PFS_TRACE(("%s", pn->pn_name));
  347         pfs_assert_not_owned(pn);
  348 
  349         /*
  350          * This is necessary because either process' privileges may
  351          * have changed since the open() call.
  352          */
  353         if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc))
  354                 PFS_RETURN (EIO);
  355 
  356         if (pn->pn_getextattr == NULL)
  357                 error = EOPNOTSUPP;
  358         else
  359                 error = pn_getextattr(curthread, proc, pn,
  360                     va->a_attrnamespace, va->a_name, va->a_uio,
  361                     va->a_size, va->a_cred);
  362 
  363         if (proc != NULL)
  364                 PROC_UNLOCK(proc);
  365 
  366         PFS_RETURN (error);
  367 }
  368 
  369 /*
  370  * Convert a vnode to its component name
  371  */
  372 static int
  373 pfs_vptocnp(struct vop_vptocnp_args *ap)
  374 {
  375         struct vnode *vp = ap->a_vp;
  376         struct vnode **dvp = ap->a_vpp;
  377         struct pfs_vdata *pvd = vp->v_data;
  378         struct pfs_node *pd = pvd->pvd_pn;
  379         struct pfs_node *pn;
  380         struct mount *mp;
  381         char *buf = ap->a_buf;
  382         size_t *buflen = ap->a_buflen;
  383         char pidbuf[PFS_NAMELEN];
  384         pid_t pid = pvd->pvd_pid;
  385         int len, i, error, locked;
  386 
  387         i = *buflen;
  388         error = 0;
  389 
  390         pfs_lock(pd);
  391 
  392         if (vp->v_type == VDIR && pd->pn_type == pfstype_root) {
  393                 *dvp = vp;
  394                 vhold(*dvp);
  395                 pfs_unlock(pd);
  396                 PFS_RETURN (0);
  397         } else if (vp->v_type == VDIR && pd->pn_type == pfstype_procdir) {
  398                 len = snprintf(pidbuf, sizeof(pidbuf), "%d", pid);
  399                 i -= len;
  400                 if (i < 0) {
  401                         error = ENOMEM;
  402                         goto failed;
  403                 }
  404                 bcopy(pidbuf, buf + i, len);
  405         } else {
  406                 len = strlen(pd->pn_name);
  407                 i -= len;
  408                 if (i < 0) {
  409                         error = ENOMEM;
  410                         goto failed;
  411                 }
  412                 bcopy(pd->pn_name, buf + i, len);
  413         }
  414 
  415         pn = pd->pn_parent;
  416         pfs_unlock(pd);
  417 
  418         mp = vp->v_mount;
  419         error = vfs_busy(mp, 0);
  420         if (error)
  421                 return (error);
  422 
  423         /*
  424          * vp is held by caller.
  425          */
  426         locked = VOP_ISLOCKED(vp);
  427         VOP_UNLOCK(vp);
  428 
  429         error = pfs_vncache_alloc(mp, dvp, pn, pid);
  430         if (error) {
  431                 vn_lock(vp, locked | LK_RETRY);
  432                 vfs_unbusy(mp);
  433                 PFS_RETURN(error);
  434         }
  435 
  436         *buflen = i;
  437         VOP_UNLOCK(*dvp);
  438         vn_lock(vp, locked | LK_RETRY);
  439         vfs_unbusy(mp);
  440 
  441         PFS_RETURN (0);
  442 failed:
  443         pfs_unlock(pd);
  444         PFS_RETURN(error);
  445 }
  446 
  447 /*
  448  * Look up a file or directory
  449  */
  450 static int
  451 pfs_lookup(struct vop_cachedlookup_args *va)
  452 {
  453         struct vnode *vn = va->a_dvp;
  454         struct vnode **vpp = va->a_vpp;
  455         struct componentname *cnp = va->a_cnp;
  456         struct pfs_vdata *pvd = vn->v_data;
  457         struct pfs_node *pd = pvd->pvd_pn;
  458         struct pfs_node *pn, *pdn = NULL;
  459         struct mount *mp;
  460         pid_t pid = pvd->pvd_pid;
  461         char *pname;
  462         int error, i, namelen, visible;
  463 
  464         PFS_TRACE(("%.*s", (int)cnp->cn_namelen, cnp->cn_nameptr));
  465         pfs_assert_not_owned(pd);
  466 
  467         if (vn->v_type != VDIR)
  468                 PFS_RETURN (ENOTDIR);
  469         KASSERT_PN_IS_DIR(pd);
  470 
  471         /*
  472          * Don't support DELETE or RENAME.  CREATE is supported so
  473          * that O_CREAT will work, but the lookup will still fail if
  474          * the file does not exist.
  475          */
  476         if ((cnp->cn_flags & ISLASTCN) &&
  477             (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
  478                 PFS_RETURN (EOPNOTSUPP);
  479 
  480         /* shortcut: check if the name is too long */
  481         if (cnp->cn_namelen >= PFS_NAMELEN)
  482                 PFS_RETURN (ENOENT);
  483 
  484         /* check that parent directory is visible... */
  485         if (!pfs_visible(curthread, pd, pvd->pvd_pid, NULL))
  486                 PFS_RETURN (ENOENT);
  487 
  488         /* self */
  489         namelen = cnp->cn_namelen;
  490         pname = cnp->cn_nameptr;
  491         if (namelen == 1 && pname[0] == '.') {
  492                 pn = pd;
  493                 *vpp = vn;
  494                 VREF(vn);
  495                 PFS_RETURN (0);
  496         }
  497 
  498         mp = vn->v_mount;
  499 
  500         /* parent */
  501         if (cnp->cn_flags & ISDOTDOT) {
  502                 if (pd->pn_type == pfstype_root)
  503                         PFS_RETURN (EIO);
  504                 error = vfs_busy(mp, MBF_NOWAIT);
  505                 if (error != 0) {
  506                         vfs_ref(mp);
  507                         VOP_UNLOCK(vn);
  508                         error = vfs_busy(mp, 0);
  509                         vn_lock(vn, LK_EXCLUSIVE | LK_RETRY);
  510                         vfs_rel(mp);
  511                         if (error != 0)
  512                                 PFS_RETURN(ENOENT);
  513                         if (VN_IS_DOOMED(vn)) {
  514                                 vfs_unbusy(mp);
  515                                 PFS_RETURN(ENOENT);
  516                         }
  517                 }
  518                 VOP_UNLOCK(vn);
  519                 KASSERT(pd->pn_parent != NULL,
  520                     ("%s(): non-root directory has no parent", __func__));
  521                 /*
  522                  * This one is tricky.  Descendents of procdir nodes
  523                  * inherit their parent's process affinity, but
  524                  * there's no easy reverse mapping.  For simplicity,
  525                  * we assume that if this node is a procdir, its
  526                  * parent isn't (which is correct as long as
  527                  * descendents of procdir nodes are never procdir
  528                  * nodes themselves)
  529                  */
  530                 if (pd->pn_type == pfstype_procdir)
  531                         pid = NO_PID;
  532                 pfs_lock(pd);
  533                 pn = pd->pn_parent;
  534                 pfs_unlock(pd);
  535                 goto got_pnode;
  536         }
  537 
  538         pfs_lock(pd);
  539 
  540         /* named node */
  541         for (pn = pd->pn_nodes; pn != NULL; pn = pn->pn_next)
  542                 if (pn->pn_type == pfstype_procdir)
  543                         pdn = pn;
  544                 else if (pn->pn_name[namelen] == '\0' &&
  545                     bcmp(pname, pn->pn_name, namelen) == 0) {
  546                         pfs_unlock(pd);
  547                         goto got_pnode;
  548                 }
  549 
  550         /* process dependent node */
  551         if ((pn = pdn) != NULL) {
  552                 pid = 0;
  553                 for (pid = 0, i = 0; i < namelen && isdigit(pname[i]); ++i)
  554                         if ((pid = pid * 10 + pname[i] - '') > PID_MAX)
  555                                 break;
  556                 if (i == cnp->cn_namelen) {
  557                         pfs_unlock(pd);
  558                         goto got_pnode;
  559                 }
  560         }
  561 
  562         pfs_unlock(pd);
  563 
  564         PFS_RETURN (ENOENT);
  565 
  566  got_pnode:
  567         pfs_assert_not_owned(pd);
  568         pfs_assert_not_owned(pn);
  569         visible = pfs_visible(curthread, pn, pid, NULL);
  570         if (!visible) {
  571                 error = ENOENT;
  572                 goto failed;
  573         }
  574 
  575         error = pfs_vncache_alloc(mp, vpp, pn, pid);
  576         if (error)
  577                 goto failed;
  578 
  579         if (cnp->cn_flags & ISDOTDOT) {
  580                 vfs_unbusy(mp);
  581                 vn_lock(vn, LK_EXCLUSIVE | LK_RETRY);
  582                 if (VN_IS_DOOMED(vn)) {
  583                         vput(*vpp);
  584                         *vpp = NULL;
  585                         PFS_RETURN(ENOENT);
  586                 }
  587         }
  588         if (cnp->cn_flags & MAKEENTRY && !VN_IS_DOOMED(vn))
  589                 cache_enter(vn, *vpp, cnp);
  590         PFS_RETURN (0);
  591  failed:
  592         if (cnp->cn_flags & ISDOTDOT) {
  593                 vfs_unbusy(mp);
  594                 vn_lock(vn, LK_EXCLUSIVE | LK_RETRY);
  595                 *vpp = NULL;
  596         }
  597         PFS_RETURN(error);
  598 }
  599 
  600 /*
  601  * Open a file or directory.
  602  */
  603 static int
  604 pfs_open(struct vop_open_args *va)
  605 {
  606         struct vnode *vn = va->a_vp;
  607         struct pfs_vdata *pvd = vn->v_data;
  608         struct pfs_node *pn = pvd->pvd_pn;
  609         int mode = va->a_mode;
  610 
  611         PFS_TRACE(("%s (mode 0x%x)", pn->pn_name, mode));
  612         pfs_assert_not_owned(pn);
  613 
  614         /* check if the requested mode is permitted */
  615         if (((mode & FREAD) && !(mode & PFS_RD)) ||
  616             ((mode & FWRITE) && !(mode & PFS_WR)))
  617                 PFS_RETURN (EPERM);
  618 
  619         /* we don't support locking */
  620         if ((mode & O_SHLOCK) || (mode & O_EXLOCK))
  621                 PFS_RETURN (EOPNOTSUPP);
  622 
  623         PFS_RETURN (0);
  624 }
  625 
  626 struct sbuf_seek_helper {
  627         off_t           skip_bytes;
  628         struct uio      *uio;
  629 };
  630 
  631 static int
  632 pfs_sbuf_uio_drain(void *arg, const char *data, int len)
  633 {
  634         struct sbuf_seek_helper *ssh;
  635         struct uio *uio;
  636         int error, skipped;
  637 
  638         ssh = arg;
  639         uio = ssh->uio;
  640         skipped = 0;
  641 
  642         /* Need to discard first uio_offset bytes. */
  643         if (ssh->skip_bytes > 0) {
  644                 if (ssh->skip_bytes >= len) {
  645                         ssh->skip_bytes -= len;
  646                         return (len);
  647                 }
  648 
  649                 data += ssh->skip_bytes;
  650                 len -= ssh->skip_bytes;
  651                 skipped = ssh->skip_bytes;
  652                 ssh->skip_bytes = 0;
  653         }
  654 
  655         error = uiomove(__DECONST(void *, data), len, uio);
  656         if (error != 0)
  657                 return (-error);
  658 
  659         /*
  660          * The fill function has more to emit, but the reader is finished.
  661          * This is similar to the truncated read case for non-draining PFS
  662          * sbufs, and should be handled appropriately in fill-routines.
  663          */
  664         if (uio->uio_resid == 0)
  665                 return (-ENOBUFS);
  666 
  667         return (skipped + len);
  668 }
  669 
  670 /*
  671  * Read from a file
  672  */
  673 static int
  674 pfs_read(struct vop_read_args *va)
  675 {
  676         struct vnode *vn = va->a_vp;
  677         struct pfs_vdata *pvd = vn->v_data;
  678         struct pfs_node *pn = pvd->pvd_pn;
  679         struct uio *uio = va->a_uio;
  680         struct proc *proc;
  681         struct sbuf *sb = NULL;
  682         int error, locked;
  683         off_t buflen, buflim;
  684         struct sbuf_seek_helper ssh;
  685 
  686         PFS_TRACE(("%s", pn->pn_name));
  687         pfs_assert_not_owned(pn);
  688 
  689         if (vn->v_type != VREG)
  690                 PFS_RETURN (EINVAL);
  691         KASSERT_PN_IS_FILE(pn);
  692 
  693         if (!(pn->pn_flags & PFS_RD))
  694                 PFS_RETURN (EBADF);
  695 
  696         if (pn->pn_fill == NULL)
  697                 PFS_RETURN (EIO);
  698 
  699         /*
  700          * This is necessary because either process' privileges may
  701          * have changed since the open() call.
  702          */
  703         if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc))
  704                 PFS_RETURN (EIO);
  705         if (proc != NULL) {
  706                 _PHOLD(proc);
  707                 PROC_UNLOCK(proc);
  708         }
  709 
  710         vhold(vn);
  711         locked = VOP_ISLOCKED(vn);
  712         VOP_UNLOCK(vn);
  713 
  714         if (pn->pn_flags & PFS_RAWRD) {
  715                 PFS_TRACE(("%zd resid", uio->uio_resid));
  716                 error = pn_fill(curthread, proc, pn, NULL, uio);
  717                 PFS_TRACE(("%zd resid", uio->uio_resid));
  718                 goto ret;
  719         }
  720 
  721         if (uio->uio_resid < 0 || uio->uio_offset < 0 ||
  722             uio->uio_resid > OFF_MAX - uio->uio_offset) {
  723                 error = EINVAL;
  724                 goto ret;
  725         }
  726         buflen = uio->uio_offset + uio->uio_resid + 1;
  727         if (pn->pn_flags & PFS_AUTODRAIN)
  728                 /*
  729                  * We can use a smaller buffer if we can stream output to the
  730                  * consumer.
  731                  */
  732                 buflim = PAGE_SIZE;
  733         else
  734                 buflim = PFS_MAXBUFSIZ;
  735         if (buflen > buflim)
  736                 buflen = buflim;
  737 
  738         sb = sbuf_new(sb, NULL, buflen, 0);
  739         if (sb == NULL) {
  740                 error = EIO;
  741                 goto ret;
  742         }
  743 
  744         if (pn->pn_flags & PFS_AUTODRAIN) {
  745                 ssh.skip_bytes = uio->uio_offset;
  746                 ssh.uio = uio;
  747                 sbuf_set_drain(sb, pfs_sbuf_uio_drain, &ssh);
  748         }
  749 
  750         error = pn_fill(curthread, proc, pn, sb, uio);
  751 
  752         if (error) {
  753                 sbuf_delete(sb);
  754                 goto ret;
  755         }
  756 
  757         /*
  758          * XXX: If the buffer overflowed, sbuf_len() will not return
  759          * the data length. Then just use the full length because an
  760          * overflowed sbuf must be full.
  761          */
  762         error = sbuf_finish(sb);
  763         if ((pn->pn_flags & PFS_AUTODRAIN)) {
  764                 /*
  765                  * ENOBUFS just indicates early termination of the fill
  766                  * function as the caller's buffer was already filled.  Squash
  767                  * to zero.
  768                  */
  769                 if (uio->uio_resid == 0 && error == ENOBUFS)
  770                         error = 0;
  771         } else {
  772                 if (error == 0)
  773                         buflen = sbuf_len(sb);
  774                 else
  775                         /* The trailing byte is not valid. */
  776                         buflen--;
  777                 error = uiomove_frombuf(sbuf_data(sb), buflen, uio);
  778         }
  779         sbuf_delete(sb);
  780 ret:
  781         vn_lock(vn, locked | LK_RETRY);
  782         vdrop(vn);
  783         if (proc != NULL)
  784                 PRELE(proc);
  785         PFS_RETURN (error);
  786 }
  787 
  788 /*
  789  * Iterate through directory entries
  790  */
  791 static int
  792 pfs_iterate(struct thread *td, struct proc *proc, struct pfs_node *pd,
  793             struct pfs_node **pn, struct proc **p)
  794 {
  795         int visible;
  796 
  797         sx_assert(&allproc_lock, SX_SLOCKED);
  798         pfs_assert_owned(pd);
  799  again:
  800         if (*pn == NULL) {
  801                 /* first node */
  802                 *pn = pd->pn_nodes;
  803         } else if ((*pn)->pn_type != pfstype_procdir) {
  804                 /* next node */
  805                 *pn = (*pn)->pn_next;
  806         }
  807         if (*pn != NULL && (*pn)->pn_type == pfstype_procdir) {
  808                 /* next process */
  809                 if (*p == NULL)
  810                         *p = LIST_FIRST(&allproc);
  811                 else
  812                         *p = LIST_NEXT(*p, p_list);
  813                 /* out of processes: next node */
  814                 if (*p == NULL)
  815                         *pn = (*pn)->pn_next;
  816                 else
  817                         PROC_LOCK(*p);
  818         }
  819 
  820         if ((*pn) == NULL)
  821                 return (-1);
  822 
  823         if (*p != NULL) {
  824                 visible = pfs_visible_proc(td, *pn, *p);
  825                 PROC_UNLOCK(*p);
  826         } else if (proc != NULL) {
  827                 visible = pfs_visible_proc(td, *pn, proc);
  828         } else {
  829                 visible = 1;
  830         }
  831         if (!visible)
  832                 goto again;
  833 
  834         return (0);
  835 }
  836 
  837 /* Directory entry list */
  838 struct pfsentry {
  839         STAILQ_ENTRY(pfsentry)  link;
  840         struct dirent           entry;
  841 };
  842 STAILQ_HEAD(pfsdirentlist, pfsentry);
  843 
  844 /*
  845  * Return directory entries.
  846  */
  847 static int
  848 pfs_readdir(struct vop_readdir_args *va)
  849 {
  850         struct vnode *vn = va->a_vp;
  851         struct pfs_vdata *pvd = vn->v_data;
  852         struct pfs_node *pd = pvd->pvd_pn;
  853         pid_t pid = pvd->pvd_pid;
  854         struct proc *p, *proc;
  855         struct pfs_node *pn;
  856         struct uio *uio;
  857         struct pfsentry *pfsent, *pfsent2;
  858         struct pfsdirentlist lst;
  859         off_t offset;
  860         int error, i, resid;
  861 
  862         STAILQ_INIT(&lst);
  863         error = 0;
  864         KASSERT(pd->pn_info == vn->v_mount->mnt_data,
  865             ("%s(): pn_info does not match mountpoint", __func__));
  866         PFS_TRACE(("%s pid %lu", pd->pn_name, (unsigned long)pid));
  867         pfs_assert_not_owned(pd);
  868 
  869         if (vn->v_type != VDIR)
  870                 PFS_RETURN (ENOTDIR);
  871         KASSERT_PN_IS_DIR(pd);
  872         uio = va->a_uio;
  873 
  874         /* only allow reading entire entries */
  875         offset = uio->uio_offset;
  876         resid = uio->uio_resid;
  877         if (offset < 0 || offset % PFS_DELEN != 0 ||
  878             (resid && resid < PFS_DELEN))
  879                 PFS_RETURN (EINVAL);
  880         if (resid == 0)
  881                 PFS_RETURN (0);
  882 
  883         proc = NULL;
  884         if (pid != NO_PID && !pfs_lookup_proc(pid, &proc))
  885                 PFS_RETURN (ENOENT);
  886 
  887         sx_slock(&allproc_lock);
  888         pfs_lock(pd);
  889 
  890         KASSERT(pid == NO_PID || proc != NULL,
  891             ("%s(): no process for pid %lu", __func__, (unsigned long)pid));
  892 
  893         if (pid != NO_PID) {
  894                 PROC_LOCK(proc);
  895 
  896                 /* check if the directory is visible to the caller */
  897                 if (!pfs_visible_proc(curthread, pd, proc)) {
  898                         _PRELE(proc);
  899                         PROC_UNLOCK(proc);
  900                         sx_sunlock(&allproc_lock);
  901                         pfs_unlock(pd);
  902                         PFS_RETURN (ENOENT);
  903                 }
  904         }
  905 
  906         /* skip unwanted entries */
  907         for (pn = NULL, p = NULL; offset > 0; offset -= PFS_DELEN) {
  908                 if (pfs_iterate(curthread, proc, pd, &pn, &p) == -1) {
  909                         /* nothing left... */
  910                         if (proc != NULL) {
  911                                 _PRELE(proc);
  912                                 PROC_UNLOCK(proc);
  913                         }
  914                         pfs_unlock(pd);
  915                         sx_sunlock(&allproc_lock);
  916                         PFS_RETURN (0);
  917                 }
  918         }
  919 
  920         /* fill in entries */
  921         while (pfs_iterate(curthread, proc, pd, &pn, &p) != -1 &&
  922             resid >= PFS_DELEN) {
  923                 if ((pfsent = malloc(sizeof(struct pfsentry), M_IOV,
  924                     M_NOWAIT | M_ZERO)) == NULL) {
  925                         error = ENOMEM;
  926                         break;
  927                 }
  928                 pfsent->entry.d_reclen = PFS_DELEN;
  929                 pfsent->entry.d_fileno = pn_fileno(pn, pid);
  930                 /* PFS_DELEN was picked to fit PFS_NAMLEN */
  931                 for (i = 0; i < PFS_NAMELEN - 1 && pn->pn_name[i] != '\0'; ++i)
  932                         pfsent->entry.d_name[i] = pn->pn_name[i];
  933                 pfsent->entry.d_namlen = i;
  934                 /* NOTE: d_off is the offset of the *next* entry. */
  935                 pfsent->entry.d_off = offset + PFS_DELEN;
  936                 switch (pn->pn_type) {
  937                 case pfstype_procdir:
  938                         KASSERT(p != NULL,
  939                             ("reached procdir node with p == NULL"));
  940                         pfsent->entry.d_namlen = snprintf(pfsent->entry.d_name,
  941                             PFS_NAMELEN, "%d", p->p_pid);
  942                         /* fall through */
  943                 case pfstype_root:
  944                 case pfstype_dir:
  945                 case pfstype_this:
  946                 case pfstype_parent:
  947                         pfsent->entry.d_type = DT_DIR;
  948                         break;
  949                 case pfstype_file:
  950                         pfsent->entry.d_type = DT_REG;
  951                         break;
  952                 case pfstype_symlink:
  953                         pfsent->entry.d_type = DT_LNK;
  954                         break;
  955                 default:
  956                         panic("%s has unexpected node type: %d", pn->pn_name, pn->pn_type);
  957                 }
  958                 PFS_TRACE(("%s", pfsent->entry.d_name));
  959                 dirent_terminate(&pfsent->entry);
  960                 STAILQ_INSERT_TAIL(&lst, pfsent, link);
  961                 offset += PFS_DELEN;
  962                 resid -= PFS_DELEN;
  963         }
  964         if (proc != NULL) {
  965                 _PRELE(proc);
  966                 PROC_UNLOCK(proc);
  967         }
  968         pfs_unlock(pd);
  969         sx_sunlock(&allproc_lock);
  970         i = 0;
  971         STAILQ_FOREACH_SAFE(pfsent, &lst, link, pfsent2) {
  972                 if (error == 0)
  973                         error = uiomove(&pfsent->entry, PFS_DELEN, uio);
  974                 free(pfsent, M_IOV);
  975                 i++;
  976         }
  977         PFS_TRACE(("%ju bytes", (uintmax_t)(i * PFS_DELEN)));
  978         PFS_RETURN (error);
  979 }
  980 
  981 /*
  982  * Read a symbolic link
  983  */
  984 static int
  985 pfs_readlink(struct vop_readlink_args *va)
  986 {
  987         struct vnode *vn = va->a_vp;
  988         struct pfs_vdata *pvd = vn->v_data;
  989         struct pfs_node *pn = pvd->pvd_pn;
  990         struct uio *uio = va->a_uio;
  991         struct proc *proc = NULL;
  992         char buf[PATH_MAX];
  993         struct sbuf sb;
  994         int error, locked;
  995 
  996         PFS_TRACE(("%s", pn->pn_name));
  997         pfs_assert_not_owned(pn);
  998 
  999         if (vn->v_type != VLNK)
 1000                 PFS_RETURN (EINVAL);
 1001         KASSERT_PN_IS_LINK(pn);
 1002 
 1003         if (pn->pn_fill == NULL)
 1004                 PFS_RETURN (EIO);
 1005 
 1006         if (pvd->pvd_pid != NO_PID) {
 1007                 if ((proc = pfind(pvd->pvd_pid)) == NULL)
 1008                         PFS_RETURN (EIO);
 1009                 if (proc->p_flag & P_WEXIT) {
 1010                         PROC_UNLOCK(proc);
 1011                         PFS_RETURN (EIO);
 1012                 }
 1013                 _PHOLD(proc);
 1014                 PROC_UNLOCK(proc);
 1015         }
 1016         vhold(vn);
 1017         locked = VOP_ISLOCKED(vn);
 1018         VOP_UNLOCK(vn);
 1019 
 1020         /* sbuf_new() can't fail with a static buffer */
 1021         sbuf_new(&sb, buf, sizeof buf, 0);
 1022 
 1023         error = pn_fill(curthread, proc, pn, &sb, NULL);
 1024 
 1025         if (proc != NULL)
 1026                 PRELE(proc);
 1027         vn_lock(vn, locked | LK_RETRY);
 1028         vdrop(vn);
 1029 
 1030         if (error) {
 1031                 sbuf_delete(&sb);
 1032                 PFS_RETURN (error);
 1033         }
 1034 
 1035         if (sbuf_finish(&sb) != 0) {
 1036                 sbuf_delete(&sb);
 1037                 PFS_RETURN (ENAMETOOLONG);
 1038         }
 1039 
 1040         error = uiomove_frombuf(sbuf_data(&sb), sbuf_len(&sb), uio);
 1041         sbuf_delete(&sb);
 1042         PFS_RETURN (error);
 1043 }
 1044 
 1045 /*
 1046  * Reclaim a vnode
 1047  */
 1048 static int
 1049 pfs_reclaim(struct vop_reclaim_args *va)
 1050 {
 1051         struct vnode *vn = va->a_vp;
 1052         struct pfs_vdata *pvd = vn->v_data;
 1053         struct pfs_node *pn = pvd->pvd_pn;
 1054 
 1055         PFS_TRACE(("%s", pn->pn_name));
 1056         pfs_assert_not_owned(pn);
 1057 
 1058         return (pfs_vncache_free(va->a_vp));
 1059 }
 1060 
 1061 /*
 1062  * Set attributes
 1063  */
 1064 static int
 1065 pfs_setattr(struct vop_setattr_args *va)
 1066 {
 1067         struct vnode *vn = va->a_vp;
 1068         struct pfs_vdata *pvd = vn->v_data;
 1069         struct pfs_node *pn = pvd->pvd_pn;
 1070 
 1071         PFS_TRACE(("%s", pn->pn_name));
 1072         pfs_assert_not_owned(pn);
 1073 
 1074         /* Silently ignore unchangeable attributes. */
 1075         PFS_RETURN (0);
 1076 }
 1077 
 1078 /*
 1079  * Write to a file
 1080  */
 1081 static int
 1082 pfs_write(struct vop_write_args *va)
 1083 {
 1084         struct vnode *vn = va->a_vp;
 1085         struct pfs_vdata *pvd = vn->v_data;
 1086         struct pfs_node *pn = pvd->pvd_pn;
 1087         struct uio *uio = va->a_uio;
 1088         struct proc *proc;
 1089         struct sbuf sb;
 1090         int error;
 1091 
 1092         PFS_TRACE(("%s", pn->pn_name));
 1093         pfs_assert_not_owned(pn);
 1094 
 1095         if (vn->v_type != VREG)
 1096                 PFS_RETURN (EINVAL);
 1097         KASSERT_PN_IS_FILE(pn);
 1098 
 1099         if (!(pn->pn_flags & PFS_WR))
 1100                 PFS_RETURN (EBADF);
 1101 
 1102         if (pn->pn_fill == NULL)
 1103                 PFS_RETURN (EIO);
 1104 
 1105         /*
 1106          * This is necessary because either process' privileges may
 1107          * have changed since the open() call.
 1108          */
 1109         if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc))
 1110                 PFS_RETURN (EIO);
 1111         if (proc != NULL) {
 1112                 _PHOLD(proc);
 1113                 PROC_UNLOCK(proc);
 1114         }
 1115 
 1116         if (pn->pn_flags & PFS_RAWWR) {
 1117                 error = pn_fill(curthread, proc, pn, NULL, uio);
 1118                 if (proc != NULL)
 1119                         PRELE(proc);
 1120                 PFS_RETURN (error);
 1121         }
 1122 
 1123         sbuf_uionew(&sb, uio, &error);
 1124         if (error) {
 1125                 if (proc != NULL)
 1126                         PRELE(proc);
 1127                 PFS_RETURN (error);
 1128         }
 1129 
 1130         error = pn_fill(curthread, proc, pn, &sb, uio);
 1131 
 1132         sbuf_delete(&sb);
 1133         if (proc != NULL)
 1134                 PRELE(proc);
 1135         PFS_RETURN (error);
 1136 }
 1137 
 1138 /*
 1139  * Vnode operations
 1140  */
 1141 struct vop_vector pfs_vnodeops = {
 1142         .vop_default =          &default_vnodeops,
 1143 
 1144         .vop_access =           pfs_access,
 1145         .vop_cachedlookup =     pfs_lookup,
 1146         .vop_close =            pfs_close,
 1147         .vop_create =           VOP_EOPNOTSUPP,
 1148         .vop_getattr =          pfs_getattr,
 1149         .vop_getextattr =       pfs_getextattr,
 1150         .vop_ioctl =            pfs_ioctl,
 1151         .vop_link =             VOP_EOPNOTSUPP,
 1152         .vop_lookup =           vfs_cache_lookup,
 1153         .vop_mkdir =            VOP_EOPNOTSUPP,
 1154         .vop_mknod =            VOP_EOPNOTSUPP,
 1155         .vop_open =             pfs_open,
 1156         .vop_read =             pfs_read,
 1157         .vop_readdir =          pfs_readdir,
 1158         .vop_readlink =         pfs_readlink,
 1159         .vop_reclaim =          pfs_reclaim,
 1160         .vop_remove =           VOP_EOPNOTSUPP,
 1161         .vop_rename =           VOP_EOPNOTSUPP,
 1162         .vop_rmdir =            VOP_EOPNOTSUPP,
 1163         .vop_setattr =          pfs_setattr,
 1164         .vop_symlink =          VOP_EOPNOTSUPP,
 1165         .vop_vptocnp =          pfs_vptocnp,
 1166         .vop_write =            pfs_write,
 1167         /* XXX I've probably forgotten a few that need VOP_EOPNOTSUPP */
 1168 };
 1169 VFS_VOP_VECTOR_REGISTER(pfs_vnodeops);

Cache object: 30033c6858d48e029201b73c86e00423


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