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 static struct vop_vector fdesc_vnodeops = {
   78         .vop_default =          &default_vnodeops,
   79 
   80         .vop_access =           VOP_NULL,
   81         .vop_getattr =          fdesc_getattr,
   82         .vop_inactive =         fdesc_inactive,
   83         .vop_lookup =           fdesc_lookup,
   84         .vop_open =             fdesc_open,
   85         .vop_pathconf =         vop_stdpathconf,
   86         .vop_readdir =          fdesc_readdir,
   87         .vop_reclaim =          fdesc_reclaim,
   88         .vop_setattr =          fdesc_setattr,
   89 };
   90 
   91 /*
   92  * Initialise cache headers
   93  */
   94 int
   95 fdesc_init(vfsp)
   96         struct vfsconf *vfsp;
   97 {
   98 
   99         fdhashtbl = hashinit(NFDCACHE, M_CACHE, &fdhash);
  100         return (0);
  101 }
  102 
  103 int
  104 fdesc_allocvp(ftype, ix, mp, vpp, td)
  105         fdntype ftype;
  106         int ix;
  107         struct mount *mp;
  108         struct vnode **vpp;
  109         struct thread *td;
  110 {
  111         struct fdhashhead *fc;
  112         struct fdescnode *fd;
  113         int error = 0;
  114 
  115         fc = FD_NHASH(ix);
  116 loop:
  117         LIST_FOREACH(fd, fc, fd_hash) {
  118                 if (fd->fd_ix == ix && fd->fd_vnode->v_mount == mp) {
  119                         if (vget(fd->fd_vnode, 0, td))
  120                                 goto loop;
  121                         *vpp = fd->fd_vnode;
  122                         return (error);
  123                 }
  124         }
  125 
  126         /*
  127          * otherwise lock the array while we call getnewvnode
  128          * since that can block.
  129          */
  130         if (fdcache_lock & FDL_LOCKED) {
  131                 fdcache_lock |= FDL_WANT;
  132                 (void) tsleep( &fdcache_lock, PINOD, "fdalvp", 0);
  133                 goto loop;
  134         }
  135         fdcache_lock |= FDL_LOCKED;
  136 
  137         /*
  138          * Do the MALLOC before the getnewvnode since doing so afterward
  139          * might cause a bogus v_data pointer to get dereferenced
  140          * elsewhere if MALLOC should block.
  141          */
  142         MALLOC(fd, struct fdescnode *, sizeof(struct fdescnode), M_TEMP, M_WAITOK);
  143 
  144         error = getnewvnode("fdesc", mp, &fdesc_vnodeops, vpp);
  145         if (error) {
  146                 FREE(fd, M_TEMP);
  147                 goto out;
  148         }
  149         (*vpp)->v_data = fd;
  150         fd->fd_vnode = *vpp;
  151         fd->fd_type = ftype;
  152         fd->fd_fd = -1;
  153         fd->fd_ix = ix;
  154         /* XXX: vnode should be locked here */
  155         error = insmntque(*vpp, mp); /* XXX: Too early for mpsafe fs */
  156         if (error != 0) {
  157                 free(fd, M_TEMP);
  158                 *vpp = NULLVP;
  159                 goto out;
  160         }
  161         LIST_INSERT_HEAD(fc, fd, fd_hash);
  162 
  163 out:
  164         fdcache_lock &= ~FDL_LOCKED;
  165 
  166         if (fdcache_lock & FDL_WANT) {
  167                 fdcache_lock &= ~FDL_WANT;
  168                 wakeup( &fdcache_lock);
  169         }
  170 
  171         return (error);
  172 }
  173 
  174 /*
  175  * vp is the current namei directory
  176  * ndp is the name to locate in that directory...
  177  */
  178 static int
  179 fdesc_lookup(ap)
  180         struct vop_lookup_args /* {
  181                 struct vnode * a_dvp;
  182                 struct vnode ** a_vpp;
  183                 struct componentname * a_cnp;
  184         } */ *ap;
  185 {
  186         struct vnode **vpp = ap->a_vpp;
  187         struct vnode *dvp = ap->a_dvp;
  188         struct componentname *cnp = ap->a_cnp;
  189         char *pname = cnp->cn_nameptr;
  190         struct thread *td = cnp->cn_thread;
  191         struct file *fp;
  192         int nlen = cnp->cn_namelen;
  193         u_int fd;
  194         int error;
  195         struct vnode *fvp;
  196 
  197         if ((cnp->cn_flags & ISLASTCN) &&
  198             (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
  199                 error = EROFS;
  200                 goto bad;
  201         }
  202 
  203         if (cnp->cn_namelen == 1 && *pname == '.') {
  204                 *vpp = dvp;
  205                 VREF(dvp);
  206                 return (0);
  207         }
  208 
  209         if (VTOFDESC(dvp)->fd_type != Froot) {
  210                 error = ENOTDIR;
  211                 goto bad;
  212         }
  213 
  214         fd = 0;
  215         /* the only time a leading 0 is acceptable is if it's "" */
  216         if (*pname == '' && nlen != 1) {
  217                 error = ENOENT;
  218                 goto bad;
  219         }
  220         while (nlen--) {
  221                 if (*pname < '' || *pname > '9') {
  222                         error = ENOENT;
  223                         goto bad;
  224                 }
  225                 fd = 10 * fd + *pname++ - '';
  226         }
  227 
  228         if ((error = fget(td, fd, &fp)) != 0)
  229                 goto bad;
  230 
  231         error = fdesc_allocvp(Fdesc, FD_DESC+fd, dvp->v_mount, &fvp, td);
  232         fdrop(fp, td);
  233         if (error)
  234                 goto bad;
  235         VTOFDESC(fvp)->fd_fd = fd;
  236         if (fvp != dvp)
  237                 vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, td);
  238         *vpp = fvp;
  239         return (0);
  240 
  241 bad:
  242         *vpp = NULL;
  243         return (error);
  244 }
  245 
  246 static int
  247 fdesc_open(ap)
  248         struct vop_open_args /* {
  249                 struct vnode *a_vp;
  250                 int  a_mode;
  251                 struct ucred *a_cred;
  252                 struct thread *a_td;
  253         } */ *ap;
  254 {
  255         struct vnode *vp = ap->a_vp;
  256 
  257         if (VTOFDESC(vp)->fd_type == Froot)
  258                 return (0);
  259 
  260         /*
  261          * XXX Kludge: set td->td_proc->p_dupfd to contain the value of the the file
  262          * descriptor being sought for duplication. The error return ensures
  263          * that the vnode for this device will be released by vn_open. Open
  264          * will detect this special error and take the actions in dupfdopen.
  265          * Other callers of vn_open or VOP_OPEN will simply report the
  266          * error.
  267          */
  268         ap->a_td->td_dupfd = VTOFDESC(vp)->fd_fd;       /* XXX */
  269         return (ENODEV);
  270 }
  271 
  272 static int
  273 fdesc_getattr(ap)
  274         struct vop_getattr_args /* {
  275                 struct vnode *a_vp;
  276                 struct vattr *a_vap;
  277                 struct ucred *a_cred;
  278                 struct thread *a_td;
  279         } */ *ap;
  280 {
  281         struct vnode *vp = ap->a_vp;
  282         struct vattr *vap = ap->a_vap;
  283         struct file *fp;
  284         struct stat stb;
  285         u_int fd;
  286         int error = 0;
  287 
  288         switch (VTOFDESC(vp)->fd_type) {
  289         case Froot:
  290                 VATTR_NULL(vap);
  291 
  292                 vap->va_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
  293                 vap->va_type = VDIR;
  294                 vap->va_nlink = 2;
  295                 vap->va_size = DEV_BSIZE;
  296                 vap->va_fileid = VTOFDESC(vp)->fd_ix;
  297                 vap->va_uid = 0;
  298                 vap->va_gid = 0;
  299                 vap->va_blocksize = DEV_BSIZE;
  300                 vap->va_atime.tv_sec = boottime.tv_sec;
  301                 vap->va_atime.tv_nsec = 0;
  302                 vap->va_mtime = vap->va_atime;
  303                 vap->va_ctime = vap->va_mtime;
  304                 vap->va_gen = 0;
  305                 vap->va_flags = 0;
  306                 vap->va_rdev = 0;
  307                 vap->va_bytes = 0;
  308                 break;
  309 
  310         case Fdesc:
  311                 fd = VTOFDESC(vp)->fd_fd;
  312 
  313                 if ((error = fget(ap->a_td, fd, &fp)) != 0)
  314                         return (error);
  315 
  316                 bzero(&stb, sizeof(stb));
  317                 error = fo_stat(fp, &stb, ap->a_td->td_ucred, ap->a_td);
  318                 fdrop(fp, ap->a_td);
  319                 if (error == 0) {
  320                         VATTR_NULL(vap);
  321                         vap->va_type = IFTOVT(stb.st_mode);
  322                         vap->va_mode = stb.st_mode;
  323 #define FDRX (VREAD|VEXEC)
  324                         if (vap->va_type == VDIR)
  325                                 vap->va_mode &= ~((FDRX)|(FDRX>>3)|(FDRX>>6));
  326 #undef FDRX
  327                         vap->va_nlink = 1;
  328                         vap->va_flags = 0;
  329                         vap->va_bytes = stb.st_blocks * stb.st_blksize;
  330                         vap->va_fileid = VTOFDESC(vp)->fd_ix;
  331                         vap->va_size = stb.st_size;
  332                         vap->va_blocksize = stb.st_blksize;
  333                         vap->va_rdev = stb.st_rdev;
  334 
  335                         /*
  336                          * If no time data is provided, use the current time.
  337                          */
  338                         if (stb.st_atimespec.tv_sec == 0 &&
  339                             stb.st_atimespec.tv_nsec == 0)
  340                                 nanotime(&stb.st_atimespec);
  341 
  342                         if (stb.st_ctimespec.tv_sec == 0 &&
  343                             stb.st_ctimespec.tv_nsec == 0)
  344                                 nanotime(&stb.st_ctimespec);
  345 
  346                         if (stb.st_mtimespec.tv_sec == 0 &&
  347                             stb.st_mtimespec.tv_nsec == 0)
  348                                 nanotime(&stb.st_mtimespec);
  349 
  350                         vap->va_atime = stb.st_atimespec;
  351                         vap->va_mtime = stb.st_mtimespec;
  352                         vap->va_ctime = stb.st_ctimespec;
  353                         vap->va_uid = stb.st_uid;
  354                         vap->va_gid = stb.st_gid;
  355                 }
  356                 break;
  357 
  358         default:
  359                 panic("fdesc_getattr");
  360                 break;
  361         }
  362 
  363         if (error == 0)
  364                 vp->v_type = vap->va_type;
  365         return (error);
  366 }
  367 
  368 static int
  369 fdesc_setattr(ap)
  370         struct vop_setattr_args /* {
  371                 struct vnode *a_vp;
  372                 struct vattr *a_vap;
  373                 struct ucred *a_cred;
  374                 struct thread *a_td;
  375         } */ *ap;
  376 {
  377         struct vattr *vap = ap->a_vap;
  378         struct vnode *vp;
  379         struct mount *mp;
  380         struct file *fp;
  381         unsigned fd;
  382         int error;
  383 
  384         /*
  385          * Can't mess with the root vnode
  386          */
  387         if (VTOFDESC(ap->a_vp)->fd_type == Froot)
  388                 return (EACCES);
  389 
  390         fd = VTOFDESC(ap->a_vp)->fd_fd;
  391 
  392         /*
  393          * Allow setattr where there is an underlying vnode.
  394          */
  395         error = getvnode(ap->a_td->td_proc->p_fd, fd, &fp);
  396         if (error) {
  397                 /*
  398                  * getvnode() returns EINVAL if the file descriptor is not
  399                  * backed by a vnode.  Silently drop all changes except
  400                  * chflags(2) in this case.
  401                  */
  402                 if (error == EINVAL) {
  403                         if (vap->va_flags != VNOVAL)
  404                                 error = EOPNOTSUPP;
  405                         else
  406                                 error = 0;
  407                 }
  408                 return (error);
  409         }
  410         vp = fp->f_vnode;
  411         if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) == 0) {
  412                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, ap->a_td);
  413                 error = VOP_SETATTR(vp, ap->a_vap, ap->a_cred, ap->a_td);
  414                 VOP_UNLOCK(vp, 0, ap->a_td);
  415                 vn_finished_write(mp);
  416         }
  417         fdrop(fp, ap->a_td);
  418         return (error);
  419 }
  420 
  421 #define UIO_MX 16
  422 
  423 static int
  424 fdesc_readdir(ap)
  425         struct vop_readdir_args /* {
  426                 struct vnode *a_vp;
  427                 struct uio *a_uio;
  428                 struct ucred *a_cred;
  429                 int *a_eofflag;
  430                 u_long *a_cookies;
  431                 int a_ncookies;
  432         } */ *ap;
  433 {
  434         struct uio *uio = ap->a_uio;
  435         struct filedesc *fdp;
  436         struct dirent d;
  437         struct dirent *dp = &d;
  438         int error, i, off, fcnt;
  439 
  440         /*
  441          * We don't allow exporting fdesc mounts, and currently local
  442          * requests do not need cookies.
  443          */
  444         if (ap->a_ncookies)
  445                 panic("fdesc_readdir: not hungry");
  446 
  447         if (VTOFDESC(ap->a_vp)->fd_type != Froot)
  448                 panic("fdesc_readdir: not dir");
  449 
  450         off = (int)uio->uio_offset;
  451         if (off != uio->uio_offset || off < 0 || (u_int)off % UIO_MX != 0 ||
  452             uio->uio_resid < UIO_MX)
  453                 return (EINVAL);
  454         i = (u_int)off / UIO_MX;
  455         fdp = uio->uio_td->td_proc->p_fd;
  456         error = 0;
  457 
  458         fcnt = i - 2;           /* The first two nodes are `.' and `..' */
  459 
  460         FILEDESC_SLOCK(fdp);
  461         while (i < fdp->fd_nfiles + 2 && uio->uio_resid >= UIO_MX) {
  462                 switch (i) {
  463                 case 0: /* `.' */
  464                 case 1: /* `..' */
  465                         bzero((caddr_t)dp, UIO_MX);
  466 
  467                         dp->d_fileno = i + FD_ROOT;
  468                         dp->d_namlen = i + 1;
  469                         dp->d_reclen = UIO_MX;
  470                         bcopy("..", dp->d_name, dp->d_namlen);
  471                         dp->d_name[i + 1] = '\0';
  472                         dp->d_type = DT_DIR;
  473                         break;
  474                 default:
  475                         if (fdp->fd_ofiles[fcnt] == NULL) {
  476                                 FILEDESC_SUNLOCK(fdp);
  477                                 goto done;
  478                         }
  479 
  480                         bzero((caddr_t) dp, UIO_MX);
  481                         dp->d_namlen = sprintf(dp->d_name, "%d", fcnt);
  482                         dp->d_reclen = UIO_MX;
  483                         dp->d_type = DT_UNKNOWN;
  484                         dp->d_fileno = i + FD_DESC;
  485                         break;
  486                 }
  487                 /*
  488                  * And ship to userland
  489                  */
  490                 FILEDESC_SUNLOCK(fdp);
  491                 error = uiomove(dp, UIO_MX, uio);
  492                 if (error)
  493                         goto done;
  494                 FILEDESC_SLOCK(fdp);
  495                 i++;
  496                 fcnt++;
  497         }
  498         FILEDESC_SUNLOCK(fdp);
  499 
  500 done:
  501         uio->uio_offset = i * UIO_MX;
  502         return (error);
  503 }
  504 
  505 static int
  506 fdesc_inactive(ap)
  507         struct vop_inactive_args /* {
  508                 struct vnode *a_vp;
  509                 struct thread *a_td;
  510         } */ *ap;
  511 {
  512         struct vnode *vp = ap->a_vp;
  513 
  514         /*
  515          * Clear out the v_type field to avoid
  516          * nasty things happening in vgone().
  517          */
  518         vp->v_type = VNON;
  519         return (0);
  520 }
  521 
  522 static int
  523 fdesc_reclaim(ap)
  524         struct vop_reclaim_args /* {
  525                 struct vnode *a_vp;
  526         } */ *ap;
  527 {
  528         struct vnode *vp = ap->a_vp;
  529         struct fdescnode *fd = VTOFDESC(vp);
  530 
  531         LIST_REMOVE(fd, fd_hash);
  532         FREE(vp->v_data, M_TEMP);
  533         vp->v_data = 0;
  534 
  535         return (0);
  536 }

Cache object: 644b473ad4cae9479bf1515c6007e0b2


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