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

Cache object: 255d44e781b23e4b8341fe221ff0f01d


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