The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/pseudofs/pseudofs_vnops.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 0753379b0174e133e18fcfb85f7cacdb


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