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/devfs/devfs_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  * Copyright (c) 2000
    5  *      Poul-Henning Kamp.  All rights reserved.
    6  *
    7  * This code is derived from software donated to Berkeley by
    8  * Jan-Simon Pendry.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Neither the name of the University nor the names of its contributors
   16  *    may be used to endorse or promote products derived from this software
   17  *    without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  *
   31  *      @(#)kernfs_vnops.c      8.15 (Berkeley) 5/21/95
   32  * From: FreeBSD: src/sys/miscfs/kernfs/kernfs_vnops.c 1.43
   33  *
   34  * $FreeBSD: releng/5.0/sys/fs/devfs/devfs_vnops.c 107698 2002-12-09 03:44:28Z rwatson $
   35  */
   36 
   37 /*
   38  * TODO:
   39  *      remove empty directories
   40  *      mknod: hunt down DE_DELETED, compare name, reinstantiate. 
   41  *      mkdir: want it ?
   42  */
   43 
   44 #include <opt_devfs.h>
   45 #include <opt_mac.h>
   46 #ifndef NODEVFS
   47 
   48 #include <sys/param.h>
   49 #include <sys/systm.h>
   50 #include <sys/conf.h>
   51 #include <sys/dirent.h>
   52 #include <sys/kernel.h>
   53 #include <sys/lock.h>
   54 #include <sys/mac.h>
   55 #include <sys/malloc.h>
   56 #include <sys/mount.h>
   57 #include <sys/namei.h>
   58 #include <sys/proc.h>
   59 #include <sys/time.h>
   60 #include <sys/unistd.h>
   61 #include <sys/vnode.h>
   62 
   63 #include <fs/devfs/devfs.h>
   64 
   65 static int      devfs_access(struct vop_access_args *ap);
   66 static int      devfs_getattr(struct vop_getattr_args *ap);
   67 static int      devfs_ioctl(struct vop_ioctl_args *ap);
   68 static int      devfs_lookupx(struct vop_lookup_args *ap);
   69 static int      devfs_mknod(struct vop_mknod_args *ap);
   70 static int      devfs_pathconf(struct vop_pathconf_args *ap);
   71 static int      devfs_read(struct vop_read_args *ap);
   72 static int      devfs_readdir(struct vop_readdir_args *ap);
   73 static int      devfs_readlink(struct vop_readlink_args *ap);
   74 static int      devfs_reclaim(struct vop_reclaim_args *ap);
   75 #ifdef MAC
   76 static int      devfs_refreshlabel(struct vop_refreshlabel_args *ap);
   77 #endif
   78 static int      devfs_remove(struct vop_remove_args *ap);
   79 static int      devfs_revoke(struct vop_revoke_args *ap);
   80 static int      devfs_setattr(struct vop_setattr_args *ap);
   81 #ifdef MAC
   82 static int      devfs_setlabel(struct vop_setlabel_args *ap);
   83 #endif
   84 static int      devfs_symlink(struct vop_symlink_args *ap);
   85 
   86 static vop_t **devfs_vnodeop_p;
   87 static vop_t **devfs_specop_p;
   88 
   89 /*
   90  * Construct the fully qualified path name relative to the mountpoint
   91  */ 
   92 static char *
   93 devfs_fqpn(char *buf, struct vnode *dvp, struct componentname *cnp)
   94 {
   95         int i;
   96         struct devfs_dirent *de, *dd;
   97         struct devfs_mount *dmp;
   98 
   99         dmp = VFSTODEVFS(dvp->v_mount);
  100         dd = dvp->v_data;
  101         i = SPECNAMELEN;
  102         buf[i] = '\0';
  103         i -= cnp->cn_namelen;
  104         if (i < 0)
  105                  return (NULL);
  106         bcopy(cnp->cn_nameptr, buf + i, cnp->cn_namelen);
  107         de = dd;
  108         while (de != dmp->dm_basedir) {
  109                 i--;
  110                 if (i < 0)
  111                          return (NULL);
  112                 buf[i] = '/';
  113                 i -= de->de_dirent->d_namlen;
  114                 if (i < 0)
  115                          return (NULL);
  116                 bcopy(de->de_dirent->d_name, buf + i,
  117                     de->de_dirent->d_namlen);
  118                 de = TAILQ_FIRST(&de->de_dlist);        /* "." */
  119                 de = TAILQ_NEXT(de, de_list);           /* ".." */
  120                 de = de->de_dir;
  121         }
  122         return (buf + i);
  123 }
  124 
  125 int
  126 devfs_allocv(struct devfs_dirent *de, struct mount *mp, struct vnode **vpp, struct thread *td)
  127 {
  128         int error;
  129         struct vnode *vp;
  130         dev_t dev;
  131 
  132         if (td == NULL)
  133                 td = curthread; /* XXX */
  134 loop:
  135         vp = de->de_vnode;
  136         if (vp != NULL) {
  137                 if (vget(vp, LK_EXCLUSIVE, td ? td : curthread))
  138                         goto loop;
  139                 *vpp = vp;
  140                 return (0);
  141         }
  142         if (de->de_dirent->d_type == DT_CHR) {
  143                 dev = *devfs_itod(de->de_inode);
  144                 if (dev == NULL)
  145                         return (ENOENT);
  146         } else {
  147                 dev = NODEV;
  148         }
  149         error = getnewvnode("devfs", mp, devfs_vnodeop_p, &vp);
  150         if (error != 0) {
  151                 printf("devfs_allocv: failed to allocate new vnode\n");
  152                 return (error);
  153         }
  154 
  155         if (de->de_dirent->d_type == DT_CHR) {
  156                 vp->v_type = VCHR;
  157                 vp = addaliasu(vp, dev->si_udev);
  158                 vp->v_op = devfs_specop_p;
  159         } else if (de->de_dirent->d_type == DT_DIR) {
  160                 vp->v_type = VDIR;
  161         } else if (de->de_dirent->d_type == DT_LNK) {
  162                 vp->v_type = VLNK;
  163         } else {
  164                 vp->v_type = VBAD;
  165         }
  166         vp->v_data = de;
  167         de->de_vnode = vp;
  168         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
  169 #ifdef MAC
  170         mac_associate_vnode_devfs(mp, de, vp);
  171 #endif
  172         *vpp = vp;
  173         return (0);
  174 }
  175 
  176 static int
  177 devfs_access(ap)
  178         struct vop_access_args /* {
  179                 struct vnode *a_vp;
  180                 int  a_mode;
  181                 struct ucred *a_cred;
  182                 struct thread *a_td;
  183         } */ *ap;
  184 {
  185         struct vnode *vp = ap->a_vp;
  186         struct devfs_dirent *de;
  187 
  188         de = vp->v_data;
  189         if (vp->v_type == VDIR)
  190                 de = de->de_dir;
  191 
  192         return (vaccess(vp->v_type, de->de_mode, de->de_uid, de->de_gid,
  193             ap->a_mode, ap->a_cred, NULL));
  194 }
  195 
  196 static int
  197 devfs_getattr(ap)
  198         struct vop_getattr_args /* {
  199                 struct vnode *a_vp;
  200                 struct vattr *a_vap;
  201                 struct ucred *a_cred;
  202                 struct thread *a_td;
  203         } */ *ap;
  204 {
  205         struct vnode *vp = ap->a_vp;
  206         struct vattr *vap = ap->a_vap;
  207         int error = 0;
  208         struct devfs_dirent *de;
  209         dev_t dev;
  210 
  211         de = vp->v_data;
  212         if (vp->v_type == VDIR)
  213                 de = de->de_dir;
  214         bzero((caddr_t) vap, sizeof(*vap));
  215         vattr_null(vap);
  216         vap->va_uid = de->de_uid;
  217         vap->va_gid = de->de_gid;
  218         vap->va_mode = de->de_mode;
  219         if (vp->v_type == VLNK) 
  220                 vap->va_size = de->de_dirent->d_namlen;
  221         else if (vp->v_type == VDIR)
  222                 vap->va_size = vap->va_bytes = DEV_BSIZE;
  223         else
  224                 vap->va_size = 0;
  225         if (vp->v_type != VDIR)
  226                 vap->va_bytes = 0;
  227         vap->va_blocksize = DEV_BSIZE;
  228         vap->va_type = vp->v_type;
  229 
  230 #define fix(aa)                                                 \
  231         do {                                                    \
  232                 if ((aa).tv_sec == 0) {                         \
  233                         (aa).tv_sec = boottime.tv_sec;          \
  234                         (aa).tv_nsec = boottime.tv_usec * 1000; \
  235                 }                                               \
  236         } while (0)
  237 
  238         if (vp->v_type != VCHR)  {
  239                 fix(de->de_atime);
  240                 vap->va_atime = de->de_atime;
  241                 fix(de->de_mtime);
  242                 vap->va_mtime = de->de_mtime;
  243                 fix(de->de_ctime);
  244                 vap->va_ctime = de->de_ctime;
  245         } else {
  246                 dev = vp->v_rdev;
  247                 fix(dev->si_atime);
  248                 vap->va_atime = dev->si_atime;
  249                 fix(dev->si_mtime);
  250                 vap->va_mtime = dev->si_mtime;
  251                 fix(dev->si_ctime);
  252                 vap->va_ctime = dev->si_ctime;
  253                 vap->va_rdev = dev->si_udev;
  254         }
  255         vap->va_gen = 0;
  256         vap->va_flags = 0;
  257         vap->va_nlink = de->de_links;
  258         vap->va_fileid = de->de_inode;
  259 
  260         return (error);
  261 }
  262 
  263 static int
  264 devfs_ioctl(ap)
  265         struct vop_ioctl_args /* {
  266                 struct vnode *a_vp;
  267                 u_long  a_command;
  268                 caddr_t  a_data;
  269                 int  a_fflag;
  270                 struct ucred *a_cred;
  271                 struct thread *a_td;
  272         } */ *ap;
  273 {
  274         int error;
  275 
  276         error = devfs_rules_ioctl(ap->a_vp->v_mount, ap->a_command, ap->a_data,
  277             ap->a_td);
  278         return (error);
  279 }
  280 
  281 static int
  282 devfs_lookupx(ap)
  283         struct vop_lookup_args /* {
  284                 struct vnode * a_dvp;
  285                 struct vnode ** a_vpp;
  286                 struct componentname * a_cnp;
  287         } */ *ap;
  288 {
  289         struct componentname *cnp;
  290         struct vnode *dvp, **vpp;
  291         struct thread *td;
  292         struct devfs_dirent *de, *dd;
  293         struct devfs_mount *dmp;
  294         dev_t cdev, *cpdev;
  295         int error, cloned, flags, nameiop;
  296         char specname[SPECNAMELEN + 1], *pname;
  297 
  298         cnp = ap->a_cnp;
  299         vpp = ap->a_vpp;
  300         dvp = ap->a_dvp;
  301         pname = cnp->cn_nameptr;
  302         td = cnp->cn_thread;
  303         flags = cnp->cn_flags;
  304         nameiop = cnp->cn_nameiop;
  305         dmp = VFSTODEVFS(dvp->v_mount);
  306         cloned = 0;
  307         dd = dvp->v_data;
  308         
  309         *vpp = NULLVP;
  310         cnp->cn_flags &= ~PDIRUNLOCK;
  311 
  312         if ((flags & ISLASTCN) && nameiop == RENAME)
  313                 return (EOPNOTSUPP);
  314 
  315         if (dvp->v_type != VDIR)
  316                 return (ENOTDIR);
  317 
  318         if ((flags & ISDOTDOT) && (dvp->v_vflag & VV_ROOT))
  319                 return (EIO);
  320 
  321         error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td);
  322         if (error)
  323                 return (error);
  324 
  325         if (cnp->cn_namelen == 1 && *pname == '.') {
  326                 if ((flags & ISLASTCN) && nameiop != LOOKUP)
  327                         return (EINVAL);
  328                 *vpp = dvp;
  329                 VREF(dvp);
  330                 return (0);
  331         }
  332 
  333         if (flags & ISDOTDOT) {
  334                 if ((flags & ISLASTCN) && nameiop != LOOKUP)
  335                         return (EINVAL);
  336                 VOP_UNLOCK(dvp, 0, td);
  337                 cnp->cn_flags |= PDIRUNLOCK;
  338                 de = TAILQ_FIRST(&dd->de_dlist);        /* "." */
  339                 de = TAILQ_NEXT(de, de_list);           /* ".." */
  340                 de = de->de_dir;
  341                 error = devfs_allocv(de, dvp->v_mount, vpp, td);
  342                 if (error || ((flags & LOCKPARENT) && (flags & ISLASTCN))) {
  343                         vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td);
  344                         cnp->cn_flags &= ~PDIRUNLOCK;
  345                 }
  346                 return (error);
  347         }
  348 
  349         devfs_populate(dmp);
  350         dd = dvp->v_data;
  351         TAILQ_FOREACH(de, &dd->de_dlist, de_list) {
  352                 if (cnp->cn_namelen != de->de_dirent->d_namlen)
  353                         continue;
  354                 if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name,
  355                     de->de_dirent->d_namlen) != 0)
  356                         continue;
  357                 if (de->de_flags & DE_WHITEOUT)
  358                         goto notfound;
  359                 goto found;
  360         }
  361 
  362         if (nameiop == DELETE)
  363                 goto notfound;
  364 
  365         /*
  366          * OK, we didn't have an entry for the name we were asked for
  367          * so we try to see if anybody can create it on demand.
  368          */
  369         pname = devfs_fqpn(specname, dvp, cnp);
  370         if (pname == NULL)
  371                 goto notfound;
  372 
  373         cdev = NODEV;
  374         EVENTHANDLER_INVOKE(dev_clone, pname, strlen(pname), &cdev);
  375         if (cdev == NODEV)
  376                 goto notfound;
  377 
  378         devfs_populate(dmp);
  379         dd = dvp->v_data;
  380 
  381         TAILQ_FOREACH(de, &dd->de_dlist, de_list) {
  382                 cpdev = devfs_itod(de->de_inode);
  383                 if (cpdev != NULL && cdev == *cpdev)
  384                         goto found;
  385                 continue;
  386         }
  387 
  388 notfound:
  389 
  390         if ((nameiop == CREATE || nameiop == RENAME) &&
  391             (flags & (LOCKPARENT | WANTPARENT)) && (flags & ISLASTCN)) {
  392                 cnp->cn_flags |= SAVENAME;
  393                 if (!(flags & LOCKPARENT)) {
  394                         VOP_UNLOCK(dvp, 0, td);
  395                         cnp->cn_flags |= PDIRUNLOCK;
  396                 }
  397                 return (EJUSTRETURN);
  398         }
  399         return (ENOENT);
  400 
  401 
  402 found:
  403 
  404         if ((cnp->cn_nameiop == DELETE) && (flags & ISLASTCN)) {
  405                 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td);
  406                 if (error)
  407                         return (error);
  408                 if (*vpp == dvp) {
  409                         VREF(dvp);
  410                         *vpp = dvp;
  411                         return (0);
  412                 }
  413                 error = devfs_allocv(de, dvp->v_mount, vpp, td);
  414                 if (error)
  415                         return (error);
  416                 if (!(flags & LOCKPARENT)) {
  417                         VOP_UNLOCK(dvp, 0, td);
  418                         cnp->cn_flags |= PDIRUNLOCK;
  419                 }
  420                 return (0);
  421         }
  422         error = devfs_allocv(de, dvp->v_mount, vpp, td);
  423         if (error)
  424                 return (error);
  425         if (!(flags & LOCKPARENT) || !(flags & ISLASTCN)) {
  426                 VOP_UNLOCK(dvp, 0, td);
  427                 cnp->cn_flags |= PDIRUNLOCK;
  428         }
  429         return (0);
  430 }
  431 
  432 static int
  433 devfs_lookup(struct vop_lookup_args *ap)
  434 {
  435         int j;
  436         struct devfs_mount *dmp;
  437 
  438         dmp = VFSTODEVFS(ap->a_dvp->v_mount);
  439         lockmgr(&dmp->dm_lock, LK_SHARED, 0, curthread);
  440         j = devfs_lookupx(ap);
  441         lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread);
  442         return (j);
  443 }
  444 
  445 static int
  446 devfs_mknod(struct vop_mknod_args *ap)
  447 /*
  448 struct vop_mknod_args {
  449         struct vnodeop_desc *a_desc;
  450         struct vnode *a_dvp;
  451         struct vnode **a_vpp;
  452         struct componentname *a_cnp;
  453         struct vattr *a_vap;
  454 };
  455 */
  456 {
  457         struct componentname *cnp;
  458         struct vnode *dvp, **vpp;
  459         struct thread *td;
  460         struct devfs_dirent *dd, *de;
  461         struct devfs_mount *dmp;
  462         int cloned, flags, nameiop;
  463         int error;
  464 
  465         dvp = ap->a_dvp;
  466         dmp = VFSTODEVFS(dvp->v_mount);
  467         lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread);
  468 
  469         cnp = ap->a_cnp;
  470         vpp = ap->a_vpp;
  471         td = cnp->cn_thread;
  472         flags = cnp->cn_flags;
  473         nameiop = cnp->cn_nameiop;
  474         cloned = 0;
  475         dd = dvp->v_data;
  476         
  477         error = ENOENT;
  478         TAILQ_FOREACH(de, &dd->de_dlist, de_list) {
  479                 if (cnp->cn_namelen != de->de_dirent->d_namlen)
  480                         continue;
  481                 if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name,
  482                     de->de_dirent->d_namlen) != 0)
  483                         continue;
  484                 if (de->de_flags & DE_WHITEOUT)
  485                         break;
  486                 goto notfound;
  487         }
  488         if (de == NULL)
  489                 goto notfound;
  490         de->de_flags &= ~DE_WHITEOUT;
  491         error = devfs_allocv(de, dvp->v_mount, vpp, td);
  492 notfound:
  493         lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread);
  494         return (error);
  495 }
  496 
  497 
  498 static int
  499 devfs_pathconf(ap)
  500         struct vop_pathconf_args /* {
  501                 struct vnode *a_vp;
  502                 int a_name;
  503                 int *a_retval;
  504         } */ *ap;
  505 {
  506 
  507         switch (ap->a_name) {
  508         case _PC_NAME_MAX:
  509                 *ap->a_retval = NAME_MAX;
  510                 return (0);
  511         case _PC_PATH_MAX:
  512                 *ap->a_retval = PATH_MAX;
  513                 return (0);
  514         case _PC_MAC_PRESENT:
  515 #ifdef MAC
  516                 /*
  517                  * If MAC is enabled, devfs automatically supports
  518                  * trivial non-persistant label storage.
  519                  */
  520                 *ap->a_retval = 1;
  521 #else
  522                 *ap->a_retval = 0;
  523 #endif
  524                 return (0);
  525         default:
  526                 return (vop_stdpathconf(ap));
  527         }
  528         /* NOTREACHED */
  529 }
  530 
  531 static int
  532 devfs_read(ap)
  533         struct vop_read_args /* {
  534                 struct vnode *a_vp;
  535                 struct uio *a_uio;
  536                 int a_ioflag;
  537                 struct ucred *a_cred;
  538         } */ *ap;
  539 {
  540 
  541         if (ap->a_vp->v_type != VDIR)
  542                 return (EINVAL);
  543         return (VOP_READDIR(ap->a_vp, ap->a_uio, ap->a_cred, NULL, NULL, NULL));
  544 }
  545 
  546 static int
  547 devfs_readdir(ap)
  548         struct vop_readdir_args /* {
  549                 struct vnode *a_vp;
  550                 struct uio *a_uio;
  551                 struct ucred *a_cred;
  552                 int *a_eofflag;
  553                 int *a_ncookies;
  554                 u_long **a_cookies;
  555         } */ *ap;
  556 {
  557         int error;
  558         struct uio *uio;
  559         struct dirent *dp;
  560         struct devfs_dirent *dd;
  561         struct devfs_dirent *de;
  562         struct devfs_mount *dmp;
  563         off_t off, oldoff;
  564         int ncookies = 0;
  565         u_long *cookiebuf, *cookiep;
  566         struct dirent *dps, *dpe;
  567 
  568         if (ap->a_vp->v_type != VDIR)
  569                 return (ENOTDIR);
  570 
  571         uio = ap->a_uio;
  572         if (uio->uio_offset < 0)
  573                 return (EINVAL);
  574 
  575         dmp = VFSTODEVFS(ap->a_vp->v_mount);
  576         lockmgr(&dmp->dm_lock, LK_SHARED, 0, curthread);
  577         devfs_populate(dmp);
  578         error = 0;
  579         de = ap->a_vp->v_data;
  580         off = 0;
  581         oldoff = uio->uio_offset;
  582         TAILQ_FOREACH(dd, &de->de_dlist, de_list) {
  583                 if (dd->de_flags & DE_WHITEOUT) 
  584                         continue;
  585                 if (dd->de_dirent->d_type == DT_DIR)
  586                         de = dd->de_dir;
  587                 else
  588                         de = dd;
  589                 dp = dd->de_dirent;
  590                 if (dp->d_reclen > uio->uio_resid)
  591                         break;
  592                 dp->d_fileno = de->de_inode;
  593                 if (off >= uio->uio_offset) {
  594                         ncookies++;
  595                         error = uiomove((caddr_t)dp, dp->d_reclen, uio);
  596                         if (error)
  597                                 break;
  598                 }
  599                 off += dp->d_reclen;
  600         }
  601         if( !error && ap->a_ncookies != NULL && ap->a_cookies != NULL ) {
  602                 MALLOC(cookiebuf, u_long *, ncookies * sizeof(u_long),
  603                        M_TEMP, M_WAITOK);
  604                 cookiep = cookiebuf;
  605                 dps = (struct dirent *)((char *)uio->uio_iov->iov_base -
  606                     (uio->uio_offset - oldoff));
  607                 dpe = (struct dirent *) uio->uio_iov->iov_base;
  608                 for( dp = dps; 
  609                         dp < dpe; 
  610                         dp = (struct dirent *)((caddr_t) dp + dp->d_reclen)) {
  611                                 oldoff += dp->d_reclen;
  612                                 *cookiep++ = (u_long) oldoff;
  613                 }
  614                 *ap->a_ncookies = ncookies;
  615                 *ap->a_cookies = cookiebuf;
  616         }
  617         lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread);
  618         uio->uio_offset = off;
  619         return (error);
  620 }
  621 
  622 static int
  623 devfs_readlink(ap)
  624         struct vop_readlink_args /* {
  625                 struct vnode *a_vp;
  626                 struct uio *a_uio;
  627                 struct ucred *a_cead;
  628         } */ *ap;
  629 {
  630         int error;
  631         struct devfs_dirent *de;
  632 
  633         de = ap->a_vp->v_data;
  634         error = uiomove(de->de_symlink, strlen(de->de_symlink), ap->a_uio);
  635         return (error);
  636 }
  637 
  638 static int
  639 devfs_reclaim(ap)
  640         struct vop_reclaim_args /* {
  641                 struct vnode *a_vp;
  642         } */ *ap;
  643 {
  644         struct vnode *vp = ap->a_vp;
  645         struct devfs_dirent *de;
  646         int i;
  647 
  648         de = vp->v_data;
  649         if (de != NULL)
  650                 de->de_vnode = NULL;
  651         vp->v_data = NULL;
  652         if (vp->v_rdev != NODEV && vp->v_rdev != NULL) {
  653                 i = vcount(vp);
  654                 if ((vp->v_rdev->si_flags & SI_CHEAPCLONE) && i == 0 &&
  655                     (vp->v_rdev->si_flags & SI_NAMED))
  656                         destroy_dev(vp->v_rdev);
  657         }
  658         return (0);
  659 }
  660 
  661 #ifdef MAC
  662 static int
  663 devfs_refreshlabel(ap)
  664         struct vop_refreshlabel_args /* {
  665                 struct vnode *a_vp;
  666                 struct ucred *a_cred;
  667         } */ *ap;
  668 {
  669 
  670         /* Labels are always in sync. */
  671         return (0);
  672 }
  673 #endif
  674 
  675 static int
  676 devfs_remove(ap)
  677         struct vop_remove_args /* {
  678                 struct vnode *a_dvp;
  679                 struct vnode *a_vp;
  680                 struct componentname *a_cnp;
  681         } */ *ap;
  682 {
  683         struct vnode *vp = ap->a_vp;
  684         struct devfs_dirent *dd;
  685         struct devfs_dirent *de;
  686         struct devfs_mount *dmp = VFSTODEVFS(vp->v_mount);
  687 
  688         lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread);
  689         dd = ap->a_dvp->v_data;
  690         de = vp->v_data;
  691         if (de->de_dirent->d_type == DT_LNK) {
  692                 TAILQ_REMOVE(&dd->de_dlist, de, de_list);
  693                 if (de->de_vnode)
  694                         de->de_vnode->v_data = NULL;
  695 #ifdef MAC
  696                 mac_destroy_devfsdirent(de);
  697 #endif
  698                 FREE(de, M_DEVFS);
  699         } else {
  700                 de->de_flags |= DE_WHITEOUT;
  701         }
  702         lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread);
  703         return (0);
  704 }
  705 
  706 /*
  707  * Revoke is called on a tty when a terminal session ends.  The vnode
  708  * is orphaned by setting v_op to deadfs so we need to let go of it
  709  * as well so that we create a new one next time around.
  710  */
  711 static int
  712 devfs_revoke(ap)
  713         struct vop_revoke_args /* {
  714                 struct vnode *a_vp;
  715                 int a_flags;
  716         } */ *ap;
  717 {
  718         struct vnode *vp = ap->a_vp;
  719         struct devfs_dirent *de;
  720 
  721         de = vp->v_data;
  722         de->de_vnode = NULL;
  723         vop_revoke(ap);
  724         return (0);
  725 }
  726 
  727 static int
  728 devfs_setattr(ap)
  729         struct vop_setattr_args /* {
  730                 struct vnode *a_vp;
  731                 struct vattr *a_vap;
  732                 struct ucred *a_cred;
  733                 struct proc *a_p;
  734         } */ *ap;
  735 {
  736         struct devfs_dirent *de;
  737         struct vattr *vap;
  738         struct vnode *vp;
  739         int c, error;
  740         uid_t uid;
  741         gid_t gid;
  742 
  743         vap = ap->a_vap;
  744         vp = ap->a_vp;
  745         if ((vap->va_type != VNON) ||
  746             (vap->va_nlink != VNOVAL) ||
  747             (vap->va_fsid != VNOVAL) ||
  748             (vap->va_fileid != VNOVAL) ||
  749             (vap->va_blocksize != VNOVAL) ||
  750             (vap->va_flags != VNOVAL && vap->va_flags != 0) ||
  751             (vap->va_rdev != VNOVAL) ||
  752             ((int)vap->va_bytes != VNOVAL) ||
  753             (vap->va_gen != VNOVAL)) {
  754                 return (EINVAL);
  755         }
  756 
  757         de = vp->v_data;
  758         if (vp->v_type == VDIR)
  759                 de = de->de_dir;
  760 
  761         error = c = 0;
  762         if (vap->va_uid == (uid_t)VNOVAL)
  763                 uid = de->de_uid;
  764         else
  765                 uid = vap->va_uid;
  766         if (vap->va_gid == (gid_t)VNOVAL)
  767                 gid = de->de_gid;
  768         else
  769                 gid = vap->va_gid;
  770         if (uid != de->de_uid || gid != de->de_gid) {
  771                 if (((ap->a_cred->cr_uid != de->de_uid) || uid != de->de_uid ||
  772                     (gid != de->de_gid && !groupmember(gid, ap->a_cred))) &&
  773                     (error = suser_cred(ap->a_td->td_ucred, PRISON_ROOT)) != 0)
  774                         return (error);
  775                 de->de_uid = uid;
  776                 de->de_gid = gid;
  777                 c = 1;
  778         }
  779 
  780         if (vap->va_mode != (mode_t)VNOVAL) {
  781                 if ((ap->a_cred->cr_uid != de->de_uid) &&
  782                     (error = suser_cred(ap->a_td->td_ucred, PRISON_ROOT)))
  783                         return (error);
  784                 de->de_mode = vap->va_mode;
  785                 c = 1;
  786         }
  787 
  788         if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
  789                 /* See the comment in ufs_vnops::ufs_setattr(). */
  790                 if ((error = VOP_ACCESS(vp, VADMIN, ap->a_cred, ap->a_td)) &&
  791                     ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
  792                     (error = VOP_ACCESS(vp, VWRITE, ap->a_cred, ap->a_td))))
  793                         return (error);
  794                 if (vap->va_atime.tv_sec != VNOVAL) {
  795                         if (vp->v_type == VCHR)
  796                                 vp->v_rdev->si_atime = vap->va_atime;
  797                         else
  798                                 de->de_atime = vap->va_atime;
  799                 }
  800                 if (vap->va_mtime.tv_sec != VNOVAL) {
  801                         if (vp->v_type == VCHR)
  802                                 vp->v_rdev->si_mtime = vap->va_mtime;
  803                         else
  804                                 de->de_mtime = vap->va_mtime;
  805                 }
  806                 c = 1;
  807         }
  808 
  809         if (c) {
  810                 if (vp->v_type == VCHR)
  811                         vfs_timestamp(&vp->v_rdev->si_ctime);
  812                 else
  813                         vfs_timestamp(&de->de_mtime);
  814         }
  815         return (0);
  816 }
  817 
  818 #ifdef MAC
  819 static int
  820 devfs_setlabel(ap)
  821         struct vop_setlabel_args /* {
  822                 struct vnode *a_vp;
  823                 struct mac *a_label;
  824                 struct ucred *a_cred;
  825                 struct thread *a_td;
  826         } */ *ap;
  827 {
  828         struct vnode *vp;
  829         struct devfs_dirent *de;
  830 
  831         vp = ap->a_vp;
  832         de = vp->v_data;
  833 
  834         mac_relabel_vnode(ap->a_cred, vp, ap->a_label);
  835         mac_update_devfsdirent(vp->v_mount, de, vp);
  836 
  837         return (0);
  838 }
  839 #endif
  840 
  841 static int
  842 devfs_symlink(ap)
  843         struct vop_symlink_args /* {
  844                 struct vnode *a_dvp;
  845                 struct vnode **a_vpp;
  846                 struct componentname *a_cnp;
  847                 struct vattr *a_vap;
  848                 char *a_target;
  849         } */ *ap;
  850 {
  851         int i, error;
  852         struct devfs_dirent *dd;
  853         struct devfs_dirent *de;
  854         struct devfs_mount *dmp;
  855 
  856         error = suser(ap->a_cnp->cn_thread);
  857         if (error)
  858                 return(error);
  859         dmp = VFSTODEVFS(ap->a_dvp->v_mount);
  860         dd = ap->a_dvp->v_data;
  861         de = devfs_newdirent(ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen);
  862         de->de_uid = 0;
  863         de->de_gid = 0;
  864         de->de_mode = 0755;
  865         de->de_inode = dmp->dm_inode++;
  866         de->de_dirent->d_type = DT_LNK;
  867         i = strlen(ap->a_target) + 1;
  868         MALLOC(de->de_symlink, char *, i, M_DEVFS, M_WAITOK);
  869         bcopy(ap->a_target, de->de_symlink, i);
  870         lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread);
  871 #ifdef MAC
  872         mac_create_devfs_symlink(ap->a_cnp->cn_cred, dmp->dm_mount, dd, de);
  873 #endif
  874         TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
  875         devfs_allocv(de, ap->a_dvp->v_mount, ap->a_vpp, 0);
  876         lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread);
  877         return (0);
  878 }
  879 
  880 static struct vnodeopv_entry_desc devfs_vnodeop_entries[] = {
  881         { &vop_default_desc,            (vop_t *) vop_defaultop },
  882         { &vop_access_desc,             (vop_t *) devfs_access },
  883         { &vop_getattr_desc,            (vop_t *) devfs_getattr },
  884         { &vop_ioctl_desc,              (vop_t *) devfs_ioctl },
  885         { &vop_islocked_desc,           (vop_t *) vop_stdislocked },
  886         { &vop_lock_desc,               (vop_t *) vop_stdlock },
  887         { &vop_lookup_desc,             (vop_t *) devfs_lookup },
  888         { &vop_mknod_desc,              (vop_t *) devfs_mknod },
  889         { &vop_pathconf_desc,           (vop_t *) devfs_pathconf },
  890         { &vop_print_desc,              (vop_t *) vop_null },
  891         { &vop_read_desc,               (vop_t *) devfs_read },
  892         { &vop_readdir_desc,            (vop_t *) devfs_readdir },
  893         { &vop_readlink_desc,           (vop_t *) devfs_readlink },
  894         { &vop_reclaim_desc,            (vop_t *) devfs_reclaim },
  895         { &vop_remove_desc,             (vop_t *) devfs_remove },
  896 #ifdef MAC
  897         { &vop_refreshlabel_desc,       (vop_t *) devfs_refreshlabel },
  898 #endif
  899         { &vop_revoke_desc,             (vop_t *) devfs_revoke },
  900         { &vop_setattr_desc,            (vop_t *) devfs_setattr },
  901 #ifdef MAC
  902         { &vop_setlabel_desc,           (vop_t *) devfs_setlabel },
  903 #endif
  904         { &vop_symlink_desc,            (vop_t *) devfs_symlink },
  905         { &vop_unlock_desc,             (vop_t *) vop_stdunlock },
  906         { NULL, NULL }
  907 };
  908 static struct vnodeopv_desc devfs_vnodeop_opv_desc =
  909         { &devfs_vnodeop_p, devfs_vnodeop_entries };
  910 
  911 VNODEOP_SET(devfs_vnodeop_opv_desc);
  912 
  913 static struct vnodeopv_entry_desc devfs_specop_entries[] = {
  914         { &vop_default_desc,            (vop_t *) spec_vnoperate },
  915         { &vop_access_desc,             (vop_t *) devfs_access },
  916         { &vop_getattr_desc,            (vop_t *) devfs_getattr },
  917         { &vop_islocked_desc,           (vop_t *) vop_stdislocked },
  918         { &vop_lock_desc,               (vop_t *) vop_stdlock },
  919         { &vop_pathconf_desc,           (vop_t *) devfs_pathconf },
  920         { &vop_print_desc,              (vop_t *) vop_null },
  921         { &vop_reclaim_desc,            (vop_t *) devfs_reclaim },
  922 #ifdef MAC
  923         { &vop_refreshlabel_desc,       (vop_t *) devfs_refreshlabel },
  924 #endif
  925         { &vop_remove_desc,             (vop_t *) devfs_remove },
  926         { &vop_revoke_desc,             (vop_t *) devfs_revoke },
  927         { &vop_setattr_desc,            (vop_t *) devfs_setattr },
  928 #ifdef MAC
  929         { &vop_setlabel_desc,           (vop_t *) devfs_setlabel },
  930 #endif
  931         { &vop_unlock_desc,             (vop_t *) vop_stdunlock },
  932         { NULL, NULL }
  933 };
  934 static struct vnodeopv_desc devfs_specop_opv_desc =
  935         { &devfs_specop_p, devfs_specop_entries };
  936 
  937 VNODEOP_SET(devfs_specop_opv_desc);
  938 #endif

Cache object: 816e9d8431367de6707bf6703094408e


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