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/fdescfs/fdesc_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) 1992, 1993
    3  *      The Regents of the University of California.  All rights reserved.
    4  *
    5  * This code is derived from software donated to Berkeley by
    6  * Jan-Simon Pendry.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   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  * 4. Neither the name of the University nor the names of its contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  *
   32  *      @(#)fdesc_vnops.c       8.9 (Berkeley) 1/21/94
   33  *
   34  * $FreeBSD$
   35  */
   36 
   37 /*
   38  * /dev/fd Filesystem
   39  */
   40 
   41 #include <sys/param.h>
   42 #include <sys/systm.h>
   43 #include <sys/conf.h>
   44 #include <sys/dirent.h>
   45 #include <sys/filedesc.h>
   46 #include <sys/kernel.h> /* boottime */
   47 #include <sys/lock.h>
   48 #include <sys/mutex.h>
   49 #include <sys/malloc.h>
   50 #include <sys/file.h>   /* Must come after sys/malloc.h */
   51 #include <sys/mount.h>
   52 #include <sys/namei.h>
   53 #include <sys/proc.h>
   54 #include <sys/stat.h>
   55 #include <sys/vnode.h>
   56 
   57 #include <fs/fdescfs/fdesc.h>
   58 
   59 #define FDL_WANT        0x01
   60 #define FDL_LOCKED      0x02
   61 static int fdcache_lock;
   62 
   63 #define NFDCACHE 4
   64 #define FD_NHASH(ix) \
   65         (&fdhashtbl[(ix) & fdhash])
   66 static LIST_HEAD(fdhashhead, fdescnode) *fdhashtbl;
   67 static u_long fdhash;
   68 
   69 static vop_getattr_t    fdesc_getattr;
   70 static vop_inactive_t   fdesc_inactive;
   71 static vop_lookup_t     fdesc_lookup;
   72 static vop_open_t       fdesc_open;
   73 static vop_readdir_t    fdesc_readdir;
   74 static vop_reclaim_t    fdesc_reclaim;
   75 static vop_setattr_t    fdesc_setattr;
   76 
   77 extern struct vop_vector fdesc_vnodeops;
   78 
   79 /*
   80  * Initialise cache headers
   81  */
   82 int
   83 fdesc_init(vfsp)
   84         struct vfsconf *vfsp;
   85 {
   86 
   87         fdhashtbl = hashinit(NFDCACHE, M_CACHE, &fdhash);
   88         return (0);
   89 }
   90 
   91 int
   92 fdesc_allocvp(ftype, ix, mp, vpp, td)
   93         fdntype ftype;
   94         int ix;
   95         struct mount *mp;
   96         struct vnode **vpp;
   97         struct thread *td;
   98 {
   99         struct fdhashhead *fc;
  100         struct fdescnode *fd;
  101         int error = 0;
  102 
  103         fc = FD_NHASH(ix);
  104 loop:
  105         LIST_FOREACH(fd, fc, fd_hash) {
  106                 if (fd->fd_ix == ix && fd->fd_vnode->v_mount == mp) {
  107                         if (vget(fd->fd_vnode, 0, td))
  108                                 goto loop;
  109                         *vpp = fd->fd_vnode;
  110                         return (error);
  111                 }
  112         }
  113 
  114         /*
  115          * otherwise lock the array while we call getnewvnode
  116          * since that can block.
  117          */
  118         if (fdcache_lock & FDL_LOCKED) {
  119                 fdcache_lock |= FDL_WANT;
  120                 (void) tsleep( &fdcache_lock, PINOD, "fdalvp", 0);
  121                 goto loop;
  122         }
  123         fdcache_lock |= FDL_LOCKED;
  124 
  125         /*
  126          * Do the MALLOC before the getnewvnode since doing so afterward
  127          * might cause a bogus v_data pointer to get dereferenced
  128          * elsewhere if MALLOC should block.
  129          */
  130         MALLOC(fd, struct fdescnode *, sizeof(struct fdescnode), M_TEMP, M_WAITOK);
  131 
  132         error = getnewvnode("fdesc", mp, &fdesc_vnodeops, vpp);
  133         if (error) {
  134                 FREE(fd, M_TEMP);
  135                 goto out;
  136         }
  137         (*vpp)->v_data = fd;
  138         fd->fd_vnode = *vpp;
  139         fd->fd_type = ftype;
  140         fd->fd_fd = -1;
  141         fd->fd_ix = ix;
  142         LIST_INSERT_HEAD(fc, fd, fd_hash);
  143 
  144 out:
  145         fdcache_lock &= ~FDL_LOCKED;
  146 
  147         if (fdcache_lock & FDL_WANT) {
  148                 fdcache_lock &= ~FDL_WANT;
  149                 wakeup( &fdcache_lock);
  150         }
  151 
  152         return (error);
  153 }
  154 
  155 /*
  156  * vp is the current namei directory
  157  * ndp is the name to locate in that directory...
  158  */
  159 static int
  160 fdesc_lookup(ap)
  161         struct vop_lookup_args /* {
  162                 struct vnode * a_dvp;
  163                 struct vnode ** a_vpp;
  164                 struct componentname * a_cnp;
  165         } */ *ap;
  166 {
  167         struct vnode **vpp = ap->a_vpp;
  168         struct vnode *dvp = ap->a_dvp;
  169         struct componentname *cnp = ap->a_cnp;
  170         char *pname = cnp->cn_nameptr;
  171         struct thread *td = cnp->cn_thread;
  172         struct file *fp;
  173         int nlen = cnp->cn_namelen;
  174         u_int fd;
  175         int error;
  176         struct vnode *fvp;
  177 
  178         if ((cnp->cn_flags & ISLASTCN) &&
  179             (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
  180                 error = EROFS;
  181                 goto bad;
  182         }
  183 
  184         if (cnp->cn_namelen == 1 && *pname == '.') {
  185                 *vpp = dvp;
  186                 VREF(dvp);
  187                 return (0);
  188         }
  189 
  190         if (VTOFDESC(dvp)->fd_type != Froot) {
  191                 error = ENOTDIR;
  192                 goto bad;
  193         }
  194 
  195         fd = 0;
  196         /* the only time a leading 0 is acceptable is if it's "" */
  197         if (*pname == '' && nlen != 1) {
  198                 error = ENOENT;
  199                 goto bad;
  200         }
  201         while (nlen--) {
  202                 if (*pname < '' || *pname > '9') {
  203                         error = ENOENT;
  204                         goto bad;
  205                 }
  206                 fd = 10 * fd + *pname++ - '';
  207         }
  208 
  209         if ((error = fget(td, fd, &fp)) != 0)
  210                 goto bad;
  211 
  212         error = fdesc_allocvp(Fdesc, FD_DESC+fd, dvp->v_mount, &fvp, td);
  213         fdrop(fp, td);
  214         if (error)
  215                 goto bad;
  216         VTOFDESC(fvp)->fd_fd = fd;
  217         if (fvp != dvp)
  218                 vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, td);
  219         *vpp = fvp;
  220         return (0);
  221 
  222 bad:
  223         *vpp = NULL;
  224         return (error);
  225 }
  226 
  227 static int
  228 fdesc_open(ap)
  229         struct vop_open_args /* {
  230                 struct vnode *a_vp;
  231                 int  a_mode;
  232                 struct ucred *a_cred;
  233                 struct thread *a_td;
  234         } */ *ap;
  235 {
  236         struct vnode *vp = ap->a_vp;
  237 
  238         if (VTOFDESC(vp)->fd_type == Froot)
  239                 return (0);
  240 
  241         /*
  242          * XXX Kludge: set td->td_proc->p_dupfd to contain the value of the the file
  243          * descriptor being sought for duplication. The error return ensures
  244          * that the vnode for this device will be released by vn_open. Open
  245          * will detect this special error and take the actions in dupfdopen.
  246          * Other callers of vn_open or VOP_OPEN will simply report the
  247          * error.
  248          */
  249         ap->a_td->td_dupfd = VTOFDESC(vp)->fd_fd;       /* XXX */
  250         return (ENODEV);
  251 }
  252 
  253 static int
  254 fdesc_getattr(ap)
  255         struct vop_getattr_args /* {
  256                 struct vnode *a_vp;
  257                 struct vattr *a_vap;
  258                 struct ucred *a_cred;
  259                 struct thread *a_td;
  260         } */ *ap;
  261 {
  262         struct vnode *vp = ap->a_vp;
  263         struct vattr *vap = ap->a_vap;
  264         struct file *fp;
  265         struct stat stb;
  266         u_int fd;
  267         int error = 0;
  268 
  269         switch (VTOFDESC(vp)->fd_type) {
  270         case Froot:
  271                 VATTR_NULL(vap);
  272 
  273                 vap->va_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
  274                 vap->va_type = VDIR;
  275                 vap->va_nlink = 2;
  276                 vap->va_size = DEV_BSIZE;
  277                 vap->va_fileid = VTOFDESC(vp)->fd_ix;
  278                 vap->va_uid = 0;
  279                 vap->va_gid = 0;
  280                 vap->va_blocksize = DEV_BSIZE;
  281                 vap->va_atime.tv_sec = boottime.tv_sec;
  282                 vap->va_atime.tv_nsec = 0;
  283                 vap->va_mtime = vap->va_atime;
  284                 vap->va_ctime = vap->va_mtime;
  285                 vap->va_gen = 0;
  286                 vap->va_flags = 0;
  287                 vap->va_rdev = 0;
  288                 vap->va_bytes = 0;
  289                 break;
  290 
  291         case Fdesc:
  292                 fd = VTOFDESC(vp)->fd_fd;
  293 
  294                 if ((error = fget(ap->a_td, fd, &fp)) != 0)
  295                         return (error);
  296 
  297                 bzero(&stb, sizeof(stb));
  298                 error = fo_stat(fp, &stb, ap->a_td->td_ucred, ap->a_td);
  299                 fdrop(fp, ap->a_td);
  300                 if (error == 0) {
  301                         VATTR_NULL(vap);
  302                         vap->va_type = IFTOVT(stb.st_mode);
  303                         vap->va_mode = stb.st_mode;
  304 #define FDRX (VREAD|VEXEC)
  305                         if (vap->va_type == VDIR)
  306                                 vap->va_mode &= ~((FDRX)|(FDRX>>3)|(FDRX>>6));
  307 #undef FDRX
  308                         vap->va_nlink = 1;
  309                         vap->va_flags = 0;
  310                         vap->va_bytes = stb.st_blocks * stb.st_blksize;
  311                         vap->va_fileid = VTOFDESC(vp)->fd_ix;
  312                         vap->va_size = stb.st_size;
  313                         vap->va_blocksize = stb.st_blksize;
  314                         vap->va_rdev = stb.st_rdev;
  315 
  316                         /*
  317                          * If no time data is provided, use the current time.
  318                          */
  319                         if (stb.st_atimespec.tv_sec == 0 &&
  320                             stb.st_atimespec.tv_nsec == 0)
  321                                 nanotime(&stb.st_atimespec);
  322 
  323                         if (stb.st_ctimespec.tv_sec == 0 &&
  324                             stb.st_ctimespec.tv_nsec == 0)
  325                                 nanotime(&stb.st_ctimespec);
  326 
  327                         if (stb.st_mtimespec.tv_sec == 0 &&
  328                             stb.st_mtimespec.tv_nsec == 0)
  329                                 nanotime(&stb.st_mtimespec);
  330 
  331                         vap->va_atime = stb.st_atimespec;
  332                         vap->va_mtime = stb.st_mtimespec;
  333                         vap->va_ctime = stb.st_ctimespec;
  334                         vap->va_uid = stb.st_uid;
  335                         vap->va_gid = stb.st_gid;
  336                 }
  337                 break;
  338 
  339         default:
  340                 panic("fdesc_getattr");
  341                 break;
  342         }
  343 
  344         if (error == 0)
  345                 vp->v_type = vap->va_type;
  346         return (error);
  347 }
  348 
  349 static int
  350 fdesc_setattr(ap)
  351         struct vop_setattr_args /* {
  352                 struct vnode *a_vp;
  353                 struct vattr *a_vap;
  354                 struct ucred *a_cred;
  355                 struct thread *a_td;
  356         } */ *ap;
  357 {
  358         struct vattr *vap = ap->a_vap;
  359         struct vnode *vp;
  360         struct mount *mp;
  361         struct file *fp;
  362         unsigned fd;
  363         int error;
  364 
  365         /*
  366          * Can't mess with the root vnode
  367          */
  368         if (VTOFDESC(ap->a_vp)->fd_type == Froot)
  369                 return (EACCES);
  370 
  371         fd = VTOFDESC(ap->a_vp)->fd_fd;
  372 
  373         /*
  374          * Allow setattr where there is an underlying vnode.
  375          */
  376         error = getvnode(ap->a_td->td_proc->p_fd, fd, &fp);
  377         if (error) {
  378                 /*
  379                  * getvnode() returns EINVAL if the file descriptor is not
  380                  * backed by a vnode.  Silently drop all changes except
  381                  * chflags(2) in this case.
  382                  */
  383                 if (error == EINVAL) {
  384                         if (vap->va_flags != VNOVAL)
  385                                 error = EOPNOTSUPP;
  386                         else
  387                                 error = 0;
  388                 }
  389                 return (error);
  390         }
  391         vp = fp->f_vnode;
  392         if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) == 0) {
  393                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, ap->a_td);
  394                 error = VOP_SETATTR(vp, ap->a_vap, ap->a_cred, ap->a_td);
  395                 VOP_UNLOCK(vp, 0, ap->a_td);
  396                 vn_finished_write(mp);
  397         }
  398         fdrop(fp, ap->a_td);
  399         return (error);
  400 }
  401 
  402 #define UIO_MX 16
  403 
  404 static int
  405 fdesc_readdir(ap)
  406         struct vop_readdir_args /* {
  407                 struct vnode *a_vp;
  408                 struct uio *a_uio;
  409                 struct ucred *a_cred;
  410                 int *a_eofflag;
  411                 u_long *a_cookies;
  412                 int a_ncookies;
  413         } */ *ap;
  414 {
  415         struct uio *uio = ap->a_uio;
  416         struct filedesc *fdp;
  417         struct dirent d;
  418         struct dirent *dp = &d;
  419         int error, i, off, fcnt;
  420 
  421         /*
  422          * We don't allow exporting fdesc mounts, and currently local
  423          * requests do not need cookies.
  424          */
  425         if (ap->a_ncookies)
  426                 panic("fdesc_readdir: not hungry");
  427 
  428         if (VTOFDESC(ap->a_vp)->fd_type != Froot)
  429                 panic("fdesc_readdir: not dir");
  430 
  431         off = (int)uio->uio_offset;
  432         if (off != uio->uio_offset || off < 0 || (u_int)off % UIO_MX != 0 ||
  433             uio->uio_resid < UIO_MX)
  434                 return (EINVAL);
  435         i = (u_int)off / UIO_MX;
  436         fdp = uio->uio_td->td_proc->p_fd;
  437         error = 0;
  438 
  439         fcnt = i - 2;           /* The first two nodes are `.' and `..' */
  440 
  441         FILEDESC_LOCK_FAST(fdp);
  442         while (i < fdp->fd_nfiles + 2 && uio->uio_resid >= UIO_MX) {
  443                 bzero((caddr_t)dp, UIO_MX);
  444                 switch (i) {
  445                 case 0: /* `.' */
  446                 case 1: /* `..' */
  447                         dp->d_fileno = i + FD_ROOT;
  448                         dp->d_namlen = i + 1;
  449                         dp->d_reclen = UIO_MX;
  450                         bcopy("..", dp->d_name, dp->d_namlen);
  451                         dp->d_name[i + 1] = '\0';
  452                         dp->d_type = DT_DIR;
  453                         break;
  454                 default:
  455                         if (fdp->fd_ofiles[fcnt] == NULL)
  456                                 break;
  457                         dp->d_namlen = sprintf(dp->d_name, "%d", fcnt);
  458                         dp->d_reclen = UIO_MX;
  459                         dp->d_type = DT_UNKNOWN;
  460                         dp->d_fileno = i + FD_DESC;
  461                         break;
  462                 }
  463                 if (dp->d_namlen != 0) {
  464                         /*
  465                          * And ship to userland
  466                          */
  467                         FILEDESC_UNLOCK_FAST(fdp);
  468                         error = uiomove(dp, UIO_MX, uio);
  469                         if (error)
  470                                 goto done;
  471                         FILEDESC_LOCK_FAST(fdp);
  472                 }
  473                 i++;
  474                 fcnt++;
  475         }
  476         FILEDESC_UNLOCK_FAST(fdp);
  477 
  478 done:
  479         uio->uio_offset = i * UIO_MX;
  480         return (error);
  481 }
  482 
  483 static int
  484 fdesc_inactive(ap)
  485         struct vop_inactive_args /* {
  486                 struct vnode *a_vp;
  487                 struct thread *a_td;
  488         } */ *ap;
  489 {
  490         struct vnode *vp = ap->a_vp;
  491 
  492         /*
  493          * Clear out the v_type field to avoid
  494          * nasty things happening in vgone().
  495          */
  496         vp->v_type = VNON;
  497         return (0);
  498 }
  499 
  500 static int
  501 fdesc_reclaim(ap)
  502         struct vop_reclaim_args /* {
  503                 struct vnode *a_vp;
  504         } */ *ap;
  505 {
  506         struct vnode *vp = ap->a_vp;
  507         struct fdescnode *fd = VTOFDESC(vp);
  508 
  509         LIST_REMOVE(fd, fd_hash);
  510         FREE(vp->v_data, M_TEMP);
  511         vp->v_data = 0;
  512 
  513         return (0);
  514 }
  515 
  516 static struct vop_vector fdesc_vnodeops = {
  517         .vop_default =          &default_vnodeops,
  518 
  519         .vop_access =           VOP_NULL,
  520         .vop_getattr =          fdesc_getattr,
  521         .vop_inactive =         fdesc_inactive,
  522         .vop_lookup =           fdesc_lookup,
  523         .vop_open =             fdesc_open,
  524         .vop_pathconf =         vop_stdpathconf,
  525         .vop_readdir =          fdesc_readdir,
  526         .vop_reclaim =          fdesc_reclaim,
  527         .vop_setattr =          fdesc_setattr,
  528 };

Cache object: f19dafda422282a3bb163ccc0de6d3a0


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