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/ufs/ufs/ufs_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) 1982, 1986, 1989, 1993
    3  *      The Regents of the University of California.  All rights reserved.
    4  * (c) UNIX System Laboratories, Inc.
    5  * All or some portions of this file are derived from material licensed
    6  * to the University of California by American Telephone and Telegraph
    7  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
    8  * the permission of UNIX System Laboratories, Inc.
    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. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. All advertising materials mentioning features or use of this software
   19  *    must display the following acknowledgement:
   20  *      This product includes software developed by the University of
   21  *      California, Berkeley and its contributors.
   22  * 4. Neither the name of the University nor the names of its contributors
   23  *    may be used to endorse or promote products derived from this software
   24  *    without specific prior written permission.
   25  *
   26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   36  * SUCH DAMAGE.
   37  *
   38  *      @(#)ufs_vnops.c 8.10 (Berkeley) 4/1/94
   39  * $FreeBSD: src/sys/ufs/ufs/ufs_vnops.c,v 1.41.2.6 1999/09/05 08:24:10 peter Exp $
   40  */
   41 
   42 #include "opt_quota.h"
   43 
   44 #include <sys/param.h>
   45 #include <sys/systm.h>
   46 #include <sys/namei.h>
   47 #include <sys/resourcevar.h>
   48 #include <sys/kernel.h>
   49 #include <sys/fcntl.h>
   50 #include <sys/stat.h>
   51 #include <sys/buf.h>
   52 #include <sys/proc.h>
   53 #include <sys/conf.h>
   54 #include <sys/mount.h>
   55 #include <sys/unistd.h>
   56 #include <sys/vnode.h>
   57 #include <sys/malloc.h>
   58 #include <sys/dirent.h>
   59 #include <sys/lockf.h>
   60 
   61 #include <vm/vm.h>
   62 
   63 #include <miscfs/specfs/specdev.h>
   64 #include <miscfs/fifofs/fifo.h>
   65 
   66 #include <ufs/ufs/quota.h>
   67 #include <ufs/ufs/inode.h>
   68 #include <ufs/ufs/dir.h>
   69 #include <ufs/ufs/ufsmount.h>
   70 #include <ufs/ufs/ufs_extern.h>
   71 
   72 static int ufs_chmod __P((struct vnode *, int, struct ucred *, struct proc *));
   73 static int ufs_chown
   74         __P((struct vnode *, uid_t, gid_t, struct ucred *, struct proc *));
   75 
   76 #ifdef EXT2FS
   77 #include <gnu/ext2fs/ext2_extern.h>
   78 #include <gnu/ext2fs/ext2_fs.h>
   79 #include <gnu/ext2fs/ext2_fs_sb.h>
   80 #endif /* EXT2FS */
   81 
   82 union _qcvt {
   83         quad_t qcvt;
   84         long val[2];
   85 };
   86 #define SETHIGH(q, h) { \
   87         union _qcvt tmp; \
   88         tmp.qcvt = (q); \
   89         tmp.val[_QUAD_HIGHWORD] = (h); \
   90         (q) = tmp.qcvt; \
   91 }
   92 #define SETLOW(q, l) { \
   93         union _qcvt tmp; \
   94         tmp.qcvt = (q); \
   95         tmp.val[_QUAD_LOWWORD] = (l); \
   96         (q) = tmp.qcvt; \
   97 }
   98 
   99 /*
  100  * Create a regular file
  101  */
  102 int
  103 ufs_create(ap)
  104         struct vop_create_args /* {
  105                 struct vnode *a_dvp;
  106                 struct vnode **a_vpp;
  107                 struct componentname *a_cnp;
  108                 struct vattr *a_vap;
  109         } */ *ap;
  110 {
  111         int error;
  112 
  113         error =
  114             ufs_makeinode(MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode),
  115             ap->a_dvp, ap->a_vpp, ap->a_cnp);
  116         if (error)
  117                 return (error);
  118         return (0);
  119 }
  120 
  121 /*
  122  * Mknod vnode call
  123  */
  124 /* ARGSUSED */
  125 int
  126 ufs_mknod(ap)
  127         struct vop_mknod_args /* {
  128                 struct vnode *a_dvp;
  129                 struct vnode **a_vpp;
  130                 struct componentname *a_cnp;
  131                 struct vattr *a_vap;
  132         } */ *ap;
  133 {
  134         struct vattr *vap = ap->a_vap;
  135         struct vnode **vpp = ap->a_vpp;
  136         struct inode *ip;
  137         int error;
  138 
  139         error = ufs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode),
  140             ap->a_dvp, vpp, ap->a_cnp);
  141         if (error)
  142                 return (error);
  143         ip = VTOI(*vpp);
  144         ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
  145         if (vap->va_rdev != VNOVAL) {
  146                 /*
  147                  * Want to be able to use this to make badblock
  148                  * inodes, so don't truncate the dev number.
  149                  */
  150                 ip->i_rdev = vap->va_rdev;
  151         }
  152         /*
  153          * Remove inode so that it will be reloaded by VFS_VGET and
  154          * checked to see if it is an alias of an existing entry in
  155          * the inode cache.
  156          */
  157         vput(*vpp);
  158         (*vpp)->v_type = VNON;
  159         vgone(*vpp);
  160         *vpp = 0;
  161         return (0);
  162 }
  163 
  164 /*
  165  * Open called.
  166  *
  167  * Nothing to do.
  168  */
  169 /* ARGSUSED */
  170 int
  171 ufs_open(ap)
  172         struct vop_open_args /* {
  173                 struct vnode *a_vp;
  174                 int  a_mode;
  175                 struct ucred *a_cred;
  176                 struct proc *a_p;
  177         } */ *ap;
  178 {
  179 
  180         /*
  181          * Files marked append-only must be opened for appending.
  182          */
  183         if ((VTOI(ap->a_vp)->i_flags & APPEND) &&
  184             (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
  185                 return (EPERM);
  186         return (0);
  187 }
  188 
  189 /*
  190  * Close called.
  191  *
  192  * Update the times on the inode.
  193  */
  194 /* ARGSUSED */
  195 int
  196 ufs_close(ap)
  197         struct vop_close_args /* {
  198                 struct vnode *a_vp;
  199                 int  a_fflag;
  200                 struct ucred *a_cred;
  201                 struct proc *a_p;
  202         } */ *ap;
  203 {
  204         register struct vnode *vp = ap->a_vp;
  205         register struct inode *ip = VTOI(vp);
  206 
  207         if (vp->v_usecount > 1 && !(ip->i_flag & IN_LOCKED))
  208                 ITIMES(ip, &time, &time);
  209         return (0);
  210 }
  211 
  212 int
  213 ufs_access(ap)
  214         struct vop_access_args /* {
  215                 struct vnode *a_vp;
  216                 int  a_mode;
  217                 struct ucred *a_cred;
  218                 struct proc *a_p;
  219         } */ *ap;
  220 {
  221         struct vnode *vp = ap->a_vp;
  222         struct inode *ip = VTOI(vp);
  223         struct ucred *cred = ap->a_cred;
  224         mode_t mask, mode = ap->a_mode;
  225         register gid_t *gp;
  226         int i;
  227 #ifdef QUOTA
  228         int error;
  229 #endif
  230 
  231         /*
  232          * Disallow write attempts on read-only file systems;
  233          * unless the file is a socket, fifo, or a block or
  234          * character device resident on the file system.
  235          */
  236         if (mode & VWRITE) {
  237                 switch (vp->v_type) {
  238                 case VDIR:
  239                 case VLNK:
  240                 case VREG:
  241                         if (vp->v_mount->mnt_flag & MNT_RDONLY)
  242                                 return (EROFS);
  243 #ifdef QUOTA
  244                         if (error = getinoquota(ip))
  245                                 return (error);
  246 #endif
  247                         break;
  248                 }
  249         }
  250 
  251         /* If immutable bit set, nobody gets to write it. */
  252         if ((mode & VWRITE) && (ip->i_flags & IMMUTABLE))
  253                 return (EPERM);
  254 
  255         /* Otherwise, user id 0 always gets access. */
  256         if (cred->cr_uid == 0)
  257                 return (0);
  258 
  259         mask = 0;
  260 
  261         /* Otherwise, check the owner. */
  262         if (cred->cr_uid == ip->i_uid) {
  263                 if (mode & VEXEC)
  264                         mask |= S_IXUSR;
  265                 if (mode & VREAD)
  266                         mask |= S_IRUSR;
  267                 if (mode & VWRITE)
  268                         mask |= S_IWUSR;
  269                 return ((ip->i_mode & mask) == mask ? 0 : EACCES);
  270         }
  271 
  272         /* Otherwise, check the groups. */
  273         for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++)
  274                 if (ip->i_gid == *gp) {
  275                         if (mode & VEXEC)
  276                                 mask |= S_IXGRP;
  277                         if (mode & VREAD)
  278                                 mask |= S_IRGRP;
  279                         if (mode & VWRITE)
  280                                 mask |= S_IWGRP;
  281                         return ((ip->i_mode & mask) == mask ? 0 : EACCES);
  282                 }
  283 
  284         /* Otherwise, check everyone else. */
  285         if (mode & VEXEC)
  286                 mask |= S_IXOTH;
  287         if (mode & VREAD)
  288                 mask |= S_IROTH;
  289         if (mode & VWRITE)
  290                 mask |= S_IWOTH;
  291         return ((ip->i_mode & mask) == mask ? 0 : EACCES);
  292 }
  293 
  294 /* ARGSUSED */
  295 int
  296 ufs_getattr(ap)
  297         struct vop_getattr_args /* {
  298                 struct vnode *a_vp;
  299                 struct vattr *a_vap;
  300                 struct ucred *a_cred;
  301                 struct proc *a_p;
  302         } */ *ap;
  303 {
  304         register struct vnode *vp = ap->a_vp;
  305         register struct inode *ip = VTOI(vp);
  306         register struct vattr *vap = ap->a_vap;
  307 
  308         ITIMES(ip, &time, &time);
  309         /*
  310          * Copy from inode table
  311          */
  312         vap->va_fsid = ip->i_dev;
  313         vap->va_fileid = ip->i_number;
  314         vap->va_mode = ip->i_mode & ~IFMT;
  315         vap->va_nlink = ip->i_nlink;
  316         vap->va_uid = ip->i_uid;
  317         vap->va_gid = ip->i_gid;
  318         vap->va_rdev = (dev_t)ip->i_rdev;
  319         vap->va_size = ip->i_din.di_size;
  320         vap->va_atime = ip->i_atime;
  321         vap->va_mtime = ip->i_mtime;
  322         vap->va_ctime = ip->i_ctime;
  323         vap->va_flags = ip->i_flags;
  324         vap->va_gen = ip->i_gen;
  325         /* this doesn't belong here */
  326         if (vp->v_type == VBLK)
  327                 vap->va_blocksize = BLKDEV_IOSIZE;
  328         else if (vp->v_type == VCHR)
  329                 vap->va_blocksize = MAXBSIZE;
  330         else
  331                 vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
  332         vap->va_bytes = dbtob(ip->i_blocks);
  333         vap->va_type = vp->v_type;
  334         vap->va_filerev = ip->i_modrev;
  335         return (0);
  336 }
  337 
  338 /*
  339  * Set attribute vnode op. called from several syscalls
  340  */
  341 int
  342 ufs_setattr(ap)
  343         struct vop_setattr_args /* {
  344                 struct vnode *a_vp;
  345                 struct vattr *a_vap;
  346                 struct ucred *a_cred;
  347                 struct proc *a_p;
  348         } */ *ap;
  349 {
  350         struct vattr *vap = ap->a_vap;
  351         struct vnode *vp = ap->a_vp;
  352         struct inode *ip = VTOI(vp);
  353         struct ucred *cred = ap->a_cred;
  354         struct proc *p = ap->a_p;
  355         struct timeval atimeval, mtimeval;
  356         int error;
  357 
  358         /*
  359          * Check for unsettable attributes.
  360          */
  361         if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
  362             (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
  363             (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
  364             ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
  365                 return (EINVAL);
  366         }
  367         if (vap->va_flags != VNOVAL) {
  368                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
  369                         return (EROFS);
  370                 if (cred->cr_uid != ip->i_uid &&
  371                     (error = suser(cred, &p->p_acflag)))
  372                         return (error);
  373                 if (cred->cr_uid == 0) {
  374                         if ((ip->i_flags
  375                             & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND)) &&
  376                             securelevel > 0)
  377                                 return (EPERM);
  378                         ip->i_flags = vap->va_flags;
  379                 } else {
  380                         if (ip->i_flags
  381                             & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND))
  382                                 return (EPERM);
  383                         ip->i_flags &= SF_SETTABLE;
  384                         ip->i_flags |= (vap->va_flags & UF_SETTABLE);
  385                 }
  386                 ip->i_flag |= IN_CHANGE;
  387                 if (vap->va_flags & (IMMUTABLE | APPEND))
  388                         return (0);
  389         }
  390         if (ip->i_flags & (IMMUTABLE | APPEND))
  391                 return (EPERM);
  392         /*
  393          * Go through the fields and update iff not VNOVAL.
  394          */
  395         if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
  396                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
  397                         return (EROFS);
  398                 error = ufs_chown(vp, vap->va_uid, vap->va_gid, cred, p);
  399                 if (error)
  400                         return (error);
  401         }
  402         if (vap->va_size != VNOVAL) {
  403                 /*
  404                  * Disallow write attempts on read-only file systems;
  405                  * unless the file is a socket, fifo, or a block or
  406                  * character device resident on the file system.
  407                  */
  408                 switch (vp->v_type) {
  409                 case VDIR:
  410                         return (EISDIR);
  411                 case VLNK:
  412                 case VREG:
  413                         if (vp->v_mount->mnt_flag & MNT_RDONLY)
  414                                 return (EROFS);
  415                         break;
  416                 }
  417                 error = VOP_TRUNCATE(vp, vap->va_size, 0, cred, p);
  418                 if (error)
  419                         return (error);
  420         }
  421         ip = VTOI(vp);
  422         if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
  423                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
  424                         return (EROFS);
  425                 if (cred->cr_uid != ip->i_uid &&
  426                     (error = suser(cred, &p->p_acflag)) &&
  427                     ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
  428                     (error = VOP_ACCESS(vp, VWRITE, cred, p))))
  429                         return (error);
  430                 if (vap->va_atime.tv_sec != VNOVAL)
  431                         ip->i_flag |= IN_ACCESS;
  432                 if (vap->va_mtime.tv_sec != VNOVAL)
  433                         ip->i_flag |= IN_CHANGE | IN_UPDATE;
  434                 atimeval.tv_sec = vap->va_atime.tv_sec;
  435                 atimeval.tv_usec = vap->va_atime.tv_nsec / 1000;
  436                 mtimeval.tv_sec = vap->va_mtime.tv_sec;
  437                 mtimeval.tv_usec = vap->va_mtime.tv_nsec / 1000;
  438                 error = VOP_UPDATE(vp, &atimeval, &mtimeval, 1);
  439                 if (error)
  440                         return (error);
  441         }
  442         error = 0;
  443         if (vap->va_mode != (mode_t)VNOVAL) {
  444                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
  445                         return (EROFS);
  446                 error = ufs_chmod(vp, (int)vap->va_mode, cred, p);
  447         }
  448         return (error);
  449 }
  450 
  451 /*
  452  * Change the mode on a file.
  453  * Inode must be locked before calling.
  454  */
  455 static int
  456 ufs_chmod(vp, mode, cred, p)
  457         register struct vnode *vp;
  458         register int mode;
  459         register struct ucred *cred;
  460         struct proc *p;
  461 {
  462         register struct inode *ip = VTOI(vp);
  463         int error;
  464 
  465         if (cred->cr_uid != ip->i_uid) {
  466             error = suser(cred, &p->p_acflag);
  467             if (error)
  468                 return (error);
  469         }
  470         if (cred->cr_uid) {
  471                 if (vp->v_type != VDIR && (mode & S_ISTXT))
  472                         return (EFTYPE);
  473                 if (!groupmember(ip->i_gid, cred) && (mode & ISGID))
  474                         return (EPERM);
  475         }
  476         ip->i_mode &= ~ALLPERMS;
  477         ip->i_mode |= (mode & ALLPERMS);
  478         ip->i_flag |= IN_CHANGE;
  479         return (0);
  480 }
  481 
  482 /*
  483  * Perform chown operation on inode ip;
  484  * inode must be locked prior to call.
  485  */
  486 static int
  487 ufs_chown(vp, uid, gid, cred, p)
  488         register struct vnode *vp;
  489         uid_t uid;
  490         gid_t gid;
  491         struct ucred *cred;
  492         struct proc *p;
  493 {
  494         register struct inode *ip = VTOI(vp);
  495         uid_t ouid;
  496         gid_t ogid;
  497         int error = 0;
  498 #ifdef QUOTA
  499         register int i;
  500         long change;
  501 #endif
  502 
  503         if (uid == (uid_t)VNOVAL)
  504                 uid = ip->i_uid;
  505         if (gid == (gid_t)VNOVAL)
  506                 gid = ip->i_gid;
  507         /*
  508          * If we don't own the file, are trying to change the owner
  509          * of the file, or are not a member of the target group,
  510          * the caller must be superuser or the call fails.
  511          */
  512         if ((cred->cr_uid != ip->i_uid || uid != ip->i_uid ||
  513             (gid != ip->i_gid && !groupmember((gid_t)gid, cred))) &&
  514             (error = suser(cred, &p->p_acflag)))
  515                 return (error);
  516         ogid = ip->i_gid;
  517         ouid = ip->i_uid;
  518 #ifdef QUOTA
  519         if (error = getinoquota(ip))
  520                 return (error);
  521         if (ouid == uid) {
  522                 dqrele(vp, ip->i_dquot[USRQUOTA]);
  523                 ip->i_dquot[USRQUOTA] = NODQUOT;
  524         }
  525         if (ogid == gid) {
  526                 dqrele(vp, ip->i_dquot[GRPQUOTA]);
  527                 ip->i_dquot[GRPQUOTA] = NODQUOT;
  528         }
  529         change = ip->i_blocks;
  530         (void) chkdq(ip, -change, cred, CHOWN);
  531         (void) chkiq(ip, -1, cred, CHOWN);
  532         for (i = 0; i < MAXQUOTAS; i++) {
  533                 dqrele(vp, ip->i_dquot[i]);
  534                 ip->i_dquot[i] = NODQUOT;
  535         }
  536 #endif
  537         ip->i_gid = gid;
  538         ip->i_uid = uid;
  539 #ifdef QUOTA
  540         if ((error = getinoquota(ip)) == 0) {
  541                 if (ouid == uid) {
  542                         dqrele(vp, ip->i_dquot[USRQUOTA]);
  543                         ip->i_dquot[USRQUOTA] = NODQUOT;
  544                 }
  545                 if (ogid == gid) {
  546                         dqrele(vp, ip->i_dquot[GRPQUOTA]);
  547                         ip->i_dquot[GRPQUOTA] = NODQUOT;
  548                 }
  549                 if ((error = chkdq(ip, change, cred, CHOWN)) == 0) {
  550                         if ((error = chkiq(ip, 1, cred, CHOWN)) == 0)
  551                                 goto good;
  552                         else
  553                                 (void) chkdq(ip, -change, cred, CHOWN|FORCE);
  554                 }
  555                 for (i = 0; i < MAXQUOTAS; i++) {
  556                         dqrele(vp, ip->i_dquot[i]);
  557                         ip->i_dquot[i] = NODQUOT;
  558                 }
  559         }
  560         ip->i_gid = ogid;
  561         ip->i_uid = ouid;
  562         if (getinoquota(ip) == 0) {
  563                 if (ouid == uid) {
  564                         dqrele(vp, ip->i_dquot[USRQUOTA]);
  565                         ip->i_dquot[USRQUOTA] = NODQUOT;
  566                 }
  567                 if (ogid == gid) {
  568                         dqrele(vp, ip->i_dquot[GRPQUOTA]);
  569                         ip->i_dquot[GRPQUOTA] = NODQUOT;
  570                 }
  571                 (void) chkdq(ip, change, cred, FORCE|CHOWN);
  572                 (void) chkiq(ip, 1, cred, FORCE|CHOWN);
  573                 (void) getinoquota(ip);
  574         }
  575         return (error);
  576 good:
  577         if (getinoquota(ip))
  578                 panic("chown: lost quota");
  579 #endif /* QUOTA */
  580         if (ouid != uid || ogid != gid)
  581                 ip->i_flag |= IN_CHANGE;
  582         if (ouid != uid && cred->cr_uid != 0)
  583                 ip->i_mode &= ~ISUID;
  584         if (ogid != gid && cred->cr_uid != 0)
  585                 ip->i_mode &= ~ISGID;
  586         return (0);
  587 }
  588 
  589 /* ARGSUSED */
  590 int
  591 ufs_ioctl(ap)
  592         struct vop_ioctl_args /* {
  593                 struct vnode *a_vp;
  594                 int  a_command;
  595                 caddr_t  a_data;
  596                 int  a_fflag;
  597                 struct ucred *a_cred;
  598                 struct proc *a_p;
  599         } */ *ap;
  600 {
  601 
  602         return (ENOTTY);
  603 }
  604 
  605 /* ARGSUSED */
  606 int
  607 ufs_select(ap)
  608         struct vop_select_args /* {
  609                 struct vnode *a_vp;
  610                 int  a_which;
  611                 int  a_fflags;
  612                 struct ucred *a_cred;
  613                 struct proc *a_p;
  614         } */ *ap;
  615 {
  616 
  617         /*
  618          * We should really check to see if I/O is possible.
  619          */
  620         return (1);
  621 }
  622 
  623 /*
  624  * Mmap a file
  625  *
  626  * NB Currently unsupported.
  627  */
  628 /* ARGSUSED */
  629 int
  630 ufs_mmap(ap)
  631         struct vop_mmap_args /* {
  632                 struct vnode *a_vp;
  633                 int  a_fflags;
  634                 struct ucred *a_cred;
  635                 struct proc *a_p;
  636         } */ *ap;
  637 {
  638 
  639         return (EINVAL);
  640 }
  641 
  642 /*
  643  * Seek on a file
  644  *
  645  * Nothing to do, so just return.
  646  */
  647 /* ARGSUSED */
  648 int
  649 ufs_seek(ap)
  650         struct vop_seek_args /* {
  651                 struct vnode *a_vp;
  652                 off_t  a_oldoff;
  653                 off_t  a_newoff;
  654                 struct ucred *a_cred;
  655         } */ *ap;
  656 {
  657 
  658         return (0);
  659 }
  660 
  661 int
  662 ufs_remove(ap)
  663         struct vop_remove_args /* {
  664                 struct vnode *a_dvp;
  665                 struct vnode *a_vp;
  666                 struct componentname *a_cnp;
  667         } */ *ap;
  668 {
  669         struct inode *ip;
  670         struct vnode *vp = ap->a_vp;
  671         struct vnode *dvp = ap->a_dvp;
  672         int error;
  673 
  674         ip = VTOI(vp);
  675         if ((ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND)) ||
  676             (VTOI(dvp)->i_flags & APPEND)) {
  677                 error = EPERM;
  678                 goto out;
  679         }
  680 #ifdef EXT2FS
  681         if (IS_EXT2_VNODE(dvp)) {
  682                 error = ext2_dirremove(dvp, ap->a_cnp);
  683         } else {
  684                 error = ufs_dirremove(dvp, ap->a_cnp);
  685         }
  686 #else
  687         error = ufs_dirremove(dvp, ap->a_cnp);
  688 #endif /* EXT2FS */
  689         if (error == 0) {
  690                 ip->i_nlink--;
  691                 ip->i_flag |= IN_CHANGE;
  692         }
  693 out:
  694         if (dvp == vp)
  695                 vrele(vp);
  696         else
  697                 vput(vp);
  698         vput(dvp);
  699         return (error);
  700 }
  701 
  702 /*
  703  * link vnode call
  704  */
  705 int
  706 ufs_link(ap)
  707         struct vop_link_args /* {
  708                 struct vnode *a_tdvp;
  709                 struct vnode *a_vp;
  710                 struct componentname *a_cnp;
  711         } */ *ap;
  712 {
  713         struct vnode *vp = ap->a_vp;
  714         struct vnode *tdvp = ap->a_tdvp;
  715         struct componentname *cnp = ap->a_cnp;
  716         struct inode *ip;
  717         struct timeval tv;
  718         int error;
  719 
  720 #ifdef DIAGNOSTIC
  721         if ((cnp->cn_flags & HASBUF) == 0)
  722                 panic("ufs_link: no name");
  723 #endif
  724         if (vp->v_mount != tdvp->v_mount) {
  725                 VOP_ABORTOP(tdvp, cnp);
  726                 error = EXDEV;
  727                 goto out2;
  728         }
  729         if (vp != tdvp && (error = VOP_LOCK(vp))) {
  730                 VOP_ABORTOP(tdvp, cnp);
  731                 goto out2;
  732         }
  733         ip = VTOI(vp);
  734         if ((nlink_t)ip->i_nlink >= LINK_MAX) {
  735                 VOP_ABORTOP(tdvp, cnp);
  736                 error = EMLINK;
  737                 goto out1;
  738         }
  739         if (ip->i_flags & (IMMUTABLE | APPEND)) {
  740                 VOP_ABORTOP(tdvp, cnp);
  741                 error = EPERM;
  742                 goto out1;
  743         }
  744         ip->i_nlink++;
  745         ip->i_flag |= IN_CHANGE;
  746         tv = time;
  747         error = VOP_UPDATE(vp, &tv, &tv, 1);
  748         if (!error) {
  749 #ifdef EXT2FS
  750                 if (IS_EXT2_VNODE(tdvp)) {
  751                         error = ext2_direnter(ip, tdvp, cnp);
  752                 } else {
  753                         error = ufs_direnter(ip, tdvp, cnp);
  754                 }
  755 #else
  756                 error = ufs_direnter(ip, tdvp, cnp);
  757 #endif /* EXT2FS */
  758         }
  759 
  760         if (error) {
  761                 ip->i_nlink--;
  762                 ip->i_flag |= IN_CHANGE;
  763         }
  764         FREE(cnp->cn_pnbuf, M_NAMEI);
  765 out1:
  766         if (vp != tdvp)
  767                 VOP_UNLOCK(vp);
  768 out2:
  769         vput(tdvp);
  770         return (error);
  771 }
  772 
  773 
  774 /*
  775  * Rename system call.
  776  *      rename("foo", "bar");
  777  * is essentially
  778  *      unlink("bar");
  779  *      link("foo", "bar");
  780  *      unlink("foo");
  781  * but ``atomically''.  Can't do full commit without saving state in the
  782  * inode on disk which isn't feasible at this time.  Best we can do is
  783  * always guarantee the target exists.
  784  *
  785  * Basic algorithm is:
  786  *
  787  * 1) Bump link count on source while we're linking it to the
  788  *    target.  This also ensure the inode won't be deleted out
  789  *    from underneath us while we work (it may be truncated by
  790  *    a concurrent `trunc' or `open' for creation).
  791  * 2) Link source to destination.  If destination already exists,
  792  *    delete it first.
  793  * 3) Unlink source reference to inode if still around. If a
  794  *    directory was moved and the parent of the destination
  795  *    is different from the source, patch the ".." entry in the
  796  *    directory.
  797  */
  798 int
  799 ufs_rename(ap)
  800         struct vop_rename_args  /* {
  801                 struct vnode *a_fdvp;
  802                 struct vnode *a_fvp;
  803                 struct componentname *a_fcnp;
  804                 struct vnode *a_tdvp;
  805                 struct vnode *a_tvp;
  806                 struct componentname *a_tcnp;
  807         } */ *ap;
  808 {
  809         struct vnode *tvp = ap->a_tvp;
  810         register struct vnode *tdvp = ap->a_tdvp;
  811         struct vnode *fvp = ap->a_fvp;
  812         struct vnode *fdvp = ap->a_fdvp;
  813         struct componentname *tcnp = ap->a_tcnp;
  814         struct componentname *fcnp = ap->a_fcnp;
  815         struct inode *ip, *xp, *dp;
  816         struct dirtemplate dirbuf;
  817         struct timeval tv;
  818         int doingdirectory = 0, oldparent = 0, newparent = 0;
  819         int error = 0;
  820         u_char namlen;
  821 
  822 #ifdef DIAGNOSTIC
  823         if ((tcnp->cn_flags & HASBUF) == 0 ||
  824             (fcnp->cn_flags & HASBUF) == 0)
  825                 panic("ufs_rename: no name");
  826 #endif
  827         /*
  828          * Check for cross-device rename.
  829          */
  830         if ((fvp->v_mount != tdvp->v_mount) ||
  831             (tvp && (fvp->v_mount != tvp->v_mount))) {
  832                 error = EXDEV;
  833 abortit:
  834                 VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */
  835                 if (tdvp == tvp)
  836                         vrele(tdvp);
  837                 else
  838                         vput(tdvp);
  839                 if (tvp)
  840                         vput(tvp);
  841                 VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */
  842                 vrele(fdvp);
  843                 vrele(fvp);
  844                 return (error);
  845         }
  846 
  847         if (tvp && ((VTOI(tvp)->i_flags & (NOUNLINK | IMMUTABLE | APPEND)) ||
  848             (VTOI(tdvp)->i_flags & APPEND))) {
  849                 error = EPERM;
  850                 goto abortit;
  851         }
  852 
  853         /*
  854          * Check if just deleting a link name or if we've lost a race.
  855          * If another process completes the same rename after we've looked
  856          * up the source and have blocked looking up the target, then the
  857          * source and target inodes may be identical now although the
  858          * names were never linked.
  859          */
  860         if (fvp == tvp) {
  861                 if (fvp->v_type == VDIR) {
  862                         /*
  863                          * Linked directories are impossible, so we must
  864                          * have lost the race.  Pretend that the rename
  865                          * completed before the lookup.
  866                          */
  867 #ifdef UFS_RENAME_DEBUG
  868                         printf("ufs_rename: fvp == tvp for directories\n");
  869 #endif
  870                         error = ENOENT;
  871                         goto abortit;
  872                 }
  873 
  874                 /* Release destination completely. */
  875                 VOP_ABORTOP(tdvp, tcnp);
  876                 vput(tdvp);
  877                 vput(tvp);
  878 
  879                 /*
  880                  * Delete source.  There is another race now that everything
  881                  * is unlocked, but this doesn't cause any new complications.
  882                  * Relookup() may find a file that is unrelated to the
  883                  * original one, or it may fail.  Too bad.
  884                  */
  885                 vrele(fdvp);
  886                 vrele(fvp);
  887                 fcnp->cn_flags &= ~MODMASK;
  888                 fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
  889                 if ((fcnp->cn_flags & SAVESTART) == 0)
  890                         panic("ufs_rename: lost from startdir");
  891                 fcnp->cn_nameiop = DELETE;
  892                 VREF(fdvp);
  893                 error = relookup(fdvp, &fvp, fcnp);
  894                 if (error == 0)
  895                         vrele(fdvp);
  896                 if (fvp == NULL) {
  897 #ifdef UFS_RENAME_DEBUG
  898                         printf("ufs_rename: from name disappeared\n");
  899 #endif
  900                         return (ENOENT);
  901                 }
  902                 return (VOP_REMOVE(fdvp, fvp, fcnp));
  903         }
  904         error = VOP_LOCK(fvp);
  905         if (error)
  906                 goto abortit;
  907         dp = VTOI(fdvp);
  908         ip = VTOI(fvp);
  909         if (ip->i_nlink >= LINK_MAX) {
  910                 VOP_UNLOCK(fvp);
  911                 error = EMLINK;
  912                 goto abortit;
  913         }
  914         if ((ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND))
  915             || (dp->i_flags & APPEND)) {
  916                 VOP_UNLOCK(fvp);
  917                 error = EPERM;
  918                 goto abortit;
  919         }
  920         if ((ip->i_mode & IFMT) == IFDIR) {
  921                 /*
  922                  * Avoid ".", "..", and aliases of "." for obvious reasons.
  923                  */
  924                 if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
  925                     dp == ip || (fcnp->cn_flags | tcnp->cn_flags) & ISDOTDOT ||
  926                     (ip->i_flag & IN_RENAME)) {
  927                         VOP_UNLOCK(fvp);
  928                         error = EINVAL;
  929                         goto abortit;
  930                 }
  931                 ip->i_flag |= IN_RENAME;
  932                 oldparent = dp->i_number;
  933                 doingdirectory++;
  934         }
  935         vrele(fdvp);
  936 
  937         /*
  938          * When the target exists, both the directory
  939          * and target vnodes are returned locked.
  940          */
  941         dp = VTOI(tdvp);
  942         xp = NULL;
  943         if (tvp)
  944                 xp = VTOI(tvp);
  945 
  946         /*
  947          * 1) Bump link count while we're moving stuff
  948          *    around.  If we crash somewhere before
  949          *    completing our work, the link count
  950          *    may be wrong, but correctable.
  951          */
  952         ip->i_nlink++;
  953         ip->i_flag |= IN_CHANGE;
  954         tv = time;
  955         error = VOP_UPDATE(fvp, &tv, &tv, 1);
  956         if (error) {
  957                 VOP_UNLOCK(fvp);
  958                 goto bad;
  959         }
  960 
  961         /*
  962          * If ".." must be changed (ie the directory gets a new
  963          * parent) then the source directory must not be in the
  964          * directory heirarchy above the target, as this would
  965          * orphan everything below the source directory. Also
  966          * the user must have write permission in the source so
  967          * as to be able to change "..". We must repeat the call
  968          * to namei, as the parent directory is unlocked by the
  969          * call to checkpath().
  970          */
  971         error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
  972         VOP_UNLOCK(fvp);
  973         if (oldparent != dp->i_number)
  974                 newparent = dp->i_number;
  975         if (doingdirectory && newparent) {
  976                 if (error)      /* write access check above */
  977                         goto bad;
  978                 if (xp != NULL)
  979                         vput(tvp);
  980 #ifdef EXT2FS
  981                 if (IS_EXT2_VNODE(tdvp)) {
  982                         error = ext2_checkpath(ip, dp, tcnp->cn_cred);
  983                 } else {
  984                         error = ufs_checkpath(ip, dp, tcnp->cn_cred);
  985                 }
  986 #else
  987                 error = ufs_checkpath(ip, dp, tcnp->cn_cred);
  988 #endif /* EXT2FS */
  989                 if (error)
  990                         goto out;
  991                 if ((tcnp->cn_flags & SAVESTART) == 0)
  992                         panic("ufs_rename: lost to startdir");
  993                 VREF(tdvp);
  994                 error = relookup(tdvp, &tvp, tcnp);
  995                 if (error)
  996                         goto out;
  997                 vrele(tdvp);
  998                 dp = VTOI(tdvp);
  999                 xp = NULL;
 1000                 if (tvp)
 1001                         xp = VTOI(tvp);
 1002         }
 1003         /*
 1004          * 2) If target doesn't exist, link the target
 1005          *    to the source and unlink the source.
 1006          *    Otherwise, rewrite the target directory
 1007          *    entry to reference the source inode and
 1008          *    expunge the original entry's existence.
 1009          */
 1010         if (xp == NULL) {
 1011                 if (dp->i_dev != ip->i_dev)
 1012                         panic("rename: EXDEV");
 1013                 /*
 1014                  * Account for ".." in new directory.
 1015                  * When source and destination have the same
 1016                  * parent we don't fool with the link count.
 1017                  */
 1018                 if (doingdirectory && newparent) {
 1019                         if ((nlink_t)dp->i_nlink >= LINK_MAX) {
 1020                                 error = EMLINK;
 1021                                 goto bad;
 1022                         }
 1023                         dp->i_nlink++;
 1024                         dp->i_flag |= IN_CHANGE;
 1025                         error = VOP_UPDATE(tdvp, &tv, &tv, 1);
 1026                         if (error)
 1027                                 goto bad;
 1028                 }
 1029 #ifdef EXT2FS
 1030                 if (IS_EXT2_VNODE(tdvp)) {
 1031                         error = ext2_direnter(ip, tdvp, tcnp);
 1032                 } else {
 1033                         error = ufs_direnter(ip, tdvp, tcnp);
 1034                 }
 1035 #else
 1036                 error = ufs_direnter(ip, tdvp, tcnp);
 1037 #endif /* EXT2FS */
 1038                 if (error) {
 1039                         if (doingdirectory && newparent) {
 1040                                 dp->i_nlink--;
 1041                                 dp->i_flag |= IN_CHANGE;
 1042                                 (void)VOP_UPDATE(tdvp, &tv, &tv, 1);
 1043                         }
 1044                         goto bad;
 1045                 }
 1046                 vput(tdvp);
 1047         } else {
 1048                 if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
 1049                         panic("rename: EXDEV");
 1050                 /*
 1051                  * Short circuit rename(foo, foo).
 1052                  */
 1053                 if (xp->i_number == ip->i_number)
 1054                         panic("rename: same file");
 1055                 /*
 1056                  * If the parent directory is "sticky", then the user must
 1057                  * own the parent directory, or the destination of the rename,
 1058                  * otherwise the destination may not be changed (except by
 1059                  * root). This implements append-only directories.
 1060                  */
 1061                 if ((dp->i_mode & S_ISTXT) && tcnp->cn_cred->cr_uid != 0 &&
 1062                     tcnp->cn_cred->cr_uid != dp->i_uid &&
 1063                     xp->i_uid != tcnp->cn_cred->cr_uid) {
 1064                         error = EPERM;
 1065                         goto bad;
 1066                 }
 1067                 /*
 1068                  * Target must be empty if a directory and have no links
 1069                  * to it. Also, ensure source and target are compatible
 1070                  * (both directories, or both not directories).
 1071                  */
 1072                 if ((xp->i_mode&IFMT) == IFDIR) {
 1073 #ifdef EXT2FS
 1074                         if (! (IS_EXT2_VNODE(ITOV(xp)) ? 
 1075                                         ext2_dirempty : ufs_dirempty)
 1076 #else
 1077                         if (! ufs_dirempty
 1078 #endif /* EXT2FS */
 1079                                          (xp, dp->i_number, tcnp->cn_cred) || 
 1080                             xp->i_nlink > 2) {
 1081                                 error = ENOTEMPTY;
 1082                                 goto bad;
 1083                         }
 1084                         if (!doingdirectory) {
 1085                                 error = ENOTDIR;
 1086                                 goto bad;
 1087                         }
 1088                         cache_purge(tdvp);
 1089                 } else if (doingdirectory) {
 1090                         error = EISDIR;
 1091                         goto bad;
 1092                 }
 1093 #ifdef EXT2FS
 1094                 if (IS_EXT2_VNODE(ITOV(dp))) {
 1095                         error = ext2_dirrewrite(dp, ip, tcnp);
 1096                 } else {
 1097                         error = ufs_dirrewrite(dp, ip, tcnp);
 1098                 }
 1099 #else
 1100                 error = ufs_dirrewrite(dp, ip, tcnp);
 1101 #endif /* EXT2FS */
 1102                 if (error)
 1103                         goto bad;
 1104                 /*
 1105                  * If the target directory is in the same
 1106                  * directory as the source directory,
 1107                  * decrement the link count on the parent
 1108                  * of the target directory.
 1109                  */
 1110                  if (doingdirectory && !newparent) {
 1111                         dp->i_nlink--;
 1112                         dp->i_flag |= IN_CHANGE;
 1113                 }
 1114                 vput(tdvp);
 1115                 /*
 1116                  * Adjust the link count of the target to
 1117                  * reflect the dirrewrite above.  If this is
 1118                  * a directory it is empty and there are
 1119                  * no links to it, so we can squash the inode and
 1120                  * any space associated with it.  We disallowed
 1121                  * renaming over top of a directory with links to
 1122                  * it above, as the remaining link would point to
 1123                  * a directory without "." or ".." entries.
 1124                  */
 1125                 xp->i_nlink--;
 1126                 if (doingdirectory) {
 1127                         if (--xp->i_nlink != 0)
 1128                                 panic("rename: linked directory");
 1129                         error = VOP_TRUNCATE(tvp, (off_t)0, IO_SYNC,
 1130                             tcnp->cn_cred, tcnp->cn_proc);
 1131                 }
 1132                 xp->i_flag |= IN_CHANGE;
 1133                 vput(tvp);
 1134                 xp = NULL;
 1135         }
 1136 
 1137         /*
 1138          * 3) Unlink the source.
 1139          */
 1140         fcnp->cn_flags &= ~MODMASK;
 1141         fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
 1142         if ((fcnp->cn_flags & SAVESTART) == 0)
 1143                 panic("ufs_rename: lost from startdir");
 1144         VREF(fdvp);
 1145         error = relookup(fdvp, &fvp, fcnp);
 1146         if (error == 0)
 1147                 vrele(fdvp);
 1148         if (fvp != NULL) {
 1149                 xp = VTOI(fvp);
 1150                 dp = VTOI(fdvp);
 1151         } else {
 1152                 /*
 1153                  * From name has disappeared.
 1154                  */
 1155                 if (doingdirectory)
 1156                         panic("rename: lost dir entry");
 1157                 vrele(ap->a_fvp);
 1158                 return (0);
 1159         }
 1160         /*
 1161          * Ensure that the directory entry still exists and has not
 1162          * changed while the new name has been entered. If the source is
 1163          * a file then the entry may have been unlinked or renamed. In
 1164          * either case there is no further work to be done. If the source
 1165          * is a directory then it cannot have been rmdir'ed; its link
 1166          * count of three would cause a rmdir to fail with ENOTEMPTY.
 1167          * The IN_RENAME flag ensures that it cannot be moved by another
 1168          * rename.
 1169          */
 1170         if (xp != ip) {
 1171                 if (doingdirectory)
 1172                         panic("rename: lost dir entry");
 1173         } else {
 1174                 /*
 1175                  * If the source is a directory with a
 1176                  * new parent, the link count of the old
 1177                  * parent directory must be decremented
 1178                  * and ".." set to point to the new parent.
 1179                  */
 1180                 if (doingdirectory && newparent) {
 1181                         dp->i_nlink--;
 1182                         dp->i_flag |= IN_CHANGE;
 1183                         error = vn_rdwr(UIO_READ, fvp, (caddr_t)&dirbuf,
 1184                                 sizeof (struct dirtemplate), (off_t)0,
 1185                                 UIO_SYSSPACE, IO_NODELOCKED,
 1186                                 tcnp->cn_cred, (int *)0, (struct proc *)0);
 1187                         if (error == 0) {
 1188 #                               if (BYTE_ORDER == LITTLE_ENDIAN)
 1189                                         if (fvp->v_mount->mnt_maxsymlinklen <= 0)
 1190                                                 namlen = dirbuf.dotdot_type;
 1191                                         else
 1192                                                 namlen = dirbuf.dotdot_namlen;
 1193 #                               else
 1194                                         namlen = dirbuf.dotdot_namlen;
 1195 #                               endif
 1196 #ifdef EXT2FS
 1197                                 if(IS_EXT2_VNODE(fvp))
 1198                                         namlen = ((struct odirtemplate *)
 1199                                                     &dirbuf)->dotdot_namlen;
 1200 #endif /* EXT2FS */
 1201                                 if (namlen != 2 ||
 1202                                     dirbuf.dotdot_name[0] != '.' ||
 1203                                     dirbuf.dotdot_name[1] != '.') {
 1204                                         ufs_dirbad(xp, (doff_t)12,
 1205                                             "rename: mangled dir");
 1206                                 } else {
 1207                                         dirbuf.dotdot_ino = newparent;
 1208                                         (void) vn_rdwr(UIO_WRITE, fvp,
 1209                                             (caddr_t)&dirbuf,
 1210                                             sizeof (struct dirtemplate),
 1211                                             (off_t)0, UIO_SYSSPACE,
 1212                                             IO_NODELOCKED|IO_SYNC,
 1213                                             tcnp->cn_cred, (int *)0,
 1214                                             (struct proc *)0);
 1215                                         cache_purge(fdvp);
 1216                                 }
 1217                         }
 1218                 }
 1219 #ifdef EXT2FS
 1220                 if (IS_EXT2_VNODE(fdvp)) {
 1221                         error = ext2_dirremove(fdvp, fcnp);
 1222                 } else {
 1223                         error = ufs_dirremove(fdvp, fcnp);
 1224                 }
 1225 #else
 1226                 error = ufs_dirremove(fdvp, fcnp);
 1227 #endif /* EXT2FS */
 1228                 if (!error) {
 1229                         xp->i_nlink--;
 1230                         xp->i_flag |= IN_CHANGE;
 1231                 }
 1232                 xp->i_flag &= ~IN_RENAME;
 1233         }
 1234         if (dp)
 1235                 vput(fdvp);
 1236         if (xp)
 1237                 vput(fvp);
 1238         vrele(ap->a_fvp);
 1239         return (error);
 1240 
 1241 bad:
 1242         if (xp)
 1243                 vput(ITOV(xp));
 1244         vput(ITOV(dp));
 1245 out:
 1246         if (VOP_LOCK(fvp) == 0) {
 1247                 ip->i_nlink--;
 1248                 ip->i_flag |= IN_CHANGE;
 1249                 ip->i_flag &= ~IN_RENAME;
 1250                 vput(fvp);
 1251         } else
 1252                 vrele(fvp);
 1253         return (error);
 1254 }
 1255 
 1256 /*
 1257  * A virgin directory (no blushing please).
 1258  */
 1259 static struct dirtemplate mastertemplate = {
 1260         0, 12, DT_DIR, 1, { '.', 0 },
 1261         0, DIRBLKSIZ - 12, DT_DIR, 2, { '.', '.', 0 }
 1262 };
 1263 static struct odirtemplate omastertemplate = {
 1264         0, 12, 1, { '.', 0 },
 1265         0, DIRBLKSIZ - 12, 2, { '.', '.', 0 }
 1266 };
 1267 
 1268 /*
 1269  * Mkdir system call
 1270  */
 1271 int
 1272 ufs_mkdir(ap)
 1273         struct vop_mkdir_args /* {
 1274                 struct vnode *a_dvp;
 1275                 struct vnode **a_vpp;
 1276                 struct componentname *a_cnp;
 1277                 struct vattr *a_vap;
 1278         } */ *ap;
 1279 {
 1280         register struct vnode *dvp = ap->a_dvp;
 1281         register struct vattr *vap = ap->a_vap;
 1282         register struct componentname *cnp = ap->a_cnp;
 1283         register struct inode *ip, *dp;
 1284         struct vnode *tvp;
 1285         struct dirtemplate dirtemplate, *dtp;
 1286         struct timeval tv;
 1287         int error, dmode;
 1288 
 1289 #ifdef DIAGNOSTIC
 1290         if ((cnp->cn_flags & HASBUF) == 0)
 1291                 panic("ufs_mkdir: no name");
 1292 #endif
 1293         dp = VTOI(dvp);
 1294         if ((nlink_t)dp->i_nlink >= LINK_MAX) {
 1295                 error = EMLINK;
 1296                 goto out;
 1297         }
 1298         dmode = vap->va_mode & 0777;
 1299         dmode |= IFDIR;
 1300         /*
 1301          * Must simulate part of ufs_makeinode here to acquire the inode,
 1302          * but not have it entered in the parent directory. The entry is
 1303          * made later after writing "." and ".." entries.
 1304          */
 1305         error = VOP_VALLOC(dvp, dmode, cnp->cn_cred, &tvp);
 1306         if (error)
 1307                 goto out;
 1308         ip = VTOI(tvp);
 1309         ip->i_uid = cnp->cn_cred->cr_uid;
 1310         ip->i_gid = dp->i_gid;
 1311 #ifdef QUOTA
 1312         if ((error = getinoquota(ip)) ||
 1313             (error = chkiq(ip, 1, cnp->cn_cred, 0))) {
 1314                 free(cnp->cn_pnbuf, M_NAMEI);
 1315                 VOP_VFREE(tvp, ip->i_number, dmode);
 1316                 vput(tvp);
 1317                 vput(dvp);
 1318                 return (error);
 1319         }
 1320 #endif
 1321         ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
 1322         ip->i_mode = dmode;
 1323         tvp->v_type = VDIR;     /* Rest init'd in getnewvnode(). */
 1324         ip->i_nlink = 2;
 1325         tv = time;
 1326         error = VOP_UPDATE(tvp, &tv, &tv, 1);
 1327 
 1328         /*
 1329          * Bump link count in parent directory
 1330          * to reflect work done below.  Should
 1331          * be done before reference is created
 1332          * so reparation is possible if we crash.
 1333          */
 1334         dp->i_nlink++;
 1335         dp->i_flag |= IN_CHANGE;
 1336         error = VOP_UPDATE(dvp, &tv, &tv, 1);
 1337         if (error)
 1338                 goto bad;
 1339 
 1340         /* Initialize directory with "." and ".." from static template. */
 1341         if (dvp->v_mount->mnt_maxsymlinklen > 0
 1342 #ifdef EXT2FS
 1343                 /* omastertemplate is want we want for EXT2 */
 1344                 && !IS_EXT2_VNODE(dvp) 
 1345 #endif /* EXT2FS */
 1346         )
 1347                 dtp = &mastertemplate;
 1348         else
 1349                 dtp = (struct dirtemplate *)&omastertemplate;
 1350         dirtemplate = *dtp;
 1351         dirtemplate.dot_ino = ip->i_number;
 1352         dirtemplate.dotdot_ino = dp->i_number;
 1353 #ifdef EXT2FS
 1354         /* note that in ext2 DIRBLKSIZ == blocksize, not DEV_BSIZE 
 1355          * so let's just redefine it - for this function only
 1356          */
 1357 #undef  DIRBLKSIZ 
 1358 #define DIRBLKSIZ (IS_EXT2_VNODE(dvp) ? \
 1359                    VTOI(dvp)->i_e2fs->s_blocksize : DEV_BSIZE)
 1360         if(IS_EXT2_VNODE(dvp))
 1361                 dirtemplate.dotdot_reclen = DIRBLKSIZ - 12;
 1362 #endif /* EXT2FS */
 1363         error = vn_rdwr(UIO_WRITE, tvp, (caddr_t)&dirtemplate,
 1364             sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE,
 1365             IO_NODELOCKED|IO_SYNC, cnp->cn_cred, (int *)0, (struct proc *)0);
 1366         if (error) {
 1367                 dp->i_nlink--;
 1368                 dp->i_flag |= IN_CHANGE;
 1369                 goto bad;
 1370         }
 1371         if (DIRBLKSIZ > VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
 1372                 panic("ufs_mkdir: blksize"); /* XXX should grow with balloc() */
 1373         else {
 1374                 ip->i_size = DIRBLKSIZ;
 1375                 ip->i_flag |= IN_CHANGE;
 1376         }
 1377 
 1378         /* Directory set up, now install it's entry in the parent directory. */
 1379 #ifdef EXT2FS
 1380         if (IS_EXT2_VNODE(dvp)) {
 1381                 error = ext2_direnter(ip, dvp, cnp);
 1382         } else {
 1383                 error = ufs_direnter(ip, dvp, cnp);
 1384         }
 1385 #else
 1386         error = ufs_direnter(ip, dvp, cnp);
 1387 #endif /* EXT2FS */
 1388         if (error) {
 1389                 dp->i_nlink--;
 1390                 dp->i_flag |= IN_CHANGE;
 1391         }
 1392 bad:
 1393         /*
 1394          * No need to do an explicit VOP_TRUNCATE here, vrele will do this
 1395          * for us because we set the link count to 0.
 1396          */
 1397         if (error) {
 1398                 ip->i_nlink = 0;
 1399                 ip->i_flag |= IN_CHANGE;
 1400                 vput(tvp);
 1401         } else
 1402                 *ap->a_vpp = tvp;
 1403 out:
 1404         FREE(cnp->cn_pnbuf, M_NAMEI);
 1405         vput(dvp);
 1406         return (error);
 1407 #ifdef EXT2FS
 1408 #undef  DIRBLKSIZ
 1409 #define DIRBLKSIZ  DEV_BSIZE
 1410 #endif /* EXT2FS */
 1411 }
 1412 
 1413 /*
 1414  * Rmdir system call.
 1415  */
 1416 int
 1417 ufs_rmdir(ap)
 1418         struct vop_rmdir_args /* {
 1419                 struct vnode *a_dvp;
 1420                 struct vnode *a_vp;
 1421                 struct componentname *a_cnp;
 1422         } */ *ap;
 1423 {
 1424         struct vnode *vp = ap->a_vp;
 1425         struct vnode *dvp = ap->a_dvp;
 1426         struct componentname *cnp = ap->a_cnp;
 1427         struct inode *ip, *dp;
 1428         int error;
 1429 
 1430         ip = VTOI(vp);
 1431         dp = VTOI(dvp);
 1432         /*
 1433          * No rmdir "." please.
 1434          */
 1435         if (dp == ip) {
 1436                 vrele(dvp);
 1437                 vput(vp);
 1438                 return (EINVAL);
 1439         }
 1440         /*
 1441          * Verify the directory is empty (and valid).
 1442          * (Rmdir ".." won't be valid since
 1443          *  ".." will contain a reference to
 1444          *  the current directory and thus be
 1445          *  non-empty.)
 1446          * Do not allow the removal of mounted on
 1447          * directories (this can happen when an NFS
 1448          * exported filesystem tries to remove a
 1449          * locally mounted on directory).
 1450          */
 1451         error = 0;
 1452         if (ip->i_nlink != 2 ||
 1453 #ifdef EXT2FS
 1454             !(IS_EXT2_VNODE(ITOV(ip)) ? ext2_dirempty : ufs_dirempty)
 1455                          (ip, dp->i_number, cnp->cn_cred)) {
 1456 #else
 1457             !ufs_dirempty(ip, dp->i_number, cnp->cn_cred)) {
 1458 #endif /* EXT2FS */
 1459                 error = ENOTEMPTY;
 1460                 goto out;
 1461         }
 1462         if ((dp->i_flags & APPEND)
 1463             || (ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND))) {
 1464                 error = EPERM;
 1465                 goto out;
 1466         }
 1467         if (vp->v_mountedhere != 0) {
 1468                 error = EINVAL;
 1469                 goto out;
 1470         }
 1471         /*
 1472          * Delete reference to directory before purging
 1473          * inode.  If we crash in between, the directory
 1474          * will be reattached to lost+found,
 1475          */
 1476 #ifdef EXT2FS
 1477         if (IS_EXT2_VNODE(dvp)) {
 1478                 error = ext2_dirremove(dvp, cnp);
 1479         } else {
 1480                 error = ufs_dirremove(dvp, cnp);
 1481         }
 1482 #else
 1483         error = ufs_dirremove(dvp, cnp);
 1484 #endif /* EXT2FS */
 1485         if (error)
 1486                 goto out;
 1487         dp->i_nlink--;
 1488         dp->i_flag |= IN_CHANGE;
 1489         cache_purge(dvp);
 1490         vput(dvp);
 1491         dvp = NULL;
 1492         /*
 1493          * Truncate inode.  The only stuff left
 1494          * in the directory is "." and "..".  The
 1495          * "." reference is inconsequential since
 1496          * we're quashing it.  The ".." reference
 1497          * has already been adjusted above.  We've
 1498          * removed the "." reference and the reference
 1499          * in the parent directory, but there may be
 1500          * other hard links so decrement by 2 and
 1501          * worry about them later.
 1502          */
 1503         ip->i_nlink -= 2;
 1504         error = VOP_TRUNCATE(vp, (off_t)0, IO_SYNC, cnp->cn_cred,
 1505             cnp->cn_proc);
 1506         cache_purge(ITOV(ip));
 1507 out:
 1508         if (dvp)
 1509                 vput(dvp);
 1510         vput(vp);
 1511         return (error);
 1512 }
 1513 
 1514 /*
 1515  * symlink -- make a symbolic link
 1516  */
 1517 int
 1518 ufs_symlink(ap)
 1519         struct vop_symlink_args /* {
 1520                 struct vnode *a_dvp;
 1521                 struct vnode **a_vpp;
 1522                 struct componentname *a_cnp;
 1523                 struct vattr *a_vap;
 1524                 char *a_target;
 1525         } */ *ap;
 1526 {
 1527         register struct vnode *vp, **vpp = ap->a_vpp;
 1528         register struct inode *ip;
 1529         int len, error;
 1530 
 1531         error = ufs_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp,
 1532             vpp, ap->a_cnp);
 1533         if (error)
 1534                 return (error);
 1535         vp = *vpp;
 1536         len = strlen(ap->a_target);
 1537         if (len < vp->v_mount->mnt_maxsymlinklen) {
 1538                 ip = VTOI(vp);
 1539                 bcopy(ap->a_target, (char *)ip->i_shortlink, len);
 1540                 ip->i_size = len;
 1541                 ip->i_flag |= IN_CHANGE | IN_UPDATE;
 1542         } else
 1543                 error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
 1544                     UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred, (int *)0,
 1545                     (struct proc *)0);
 1546         vput(vp);
 1547         return (error);
 1548 }
 1549 
 1550 /*
 1551  * Vnode op for reading directories.
 1552  *
 1553  * The routine below assumes that the on-disk format of a directory
 1554  * is the same as that defined by <sys/dirent.h>. If the on-disk
 1555  * format changes, then it will be necessary to do a conversion
 1556  * from the on-disk format that read returns to the format defined
 1557  * by <sys/dirent.h>.
 1558  */
 1559 int
 1560 ufs_readdir(ap)
 1561         struct vop_readdir_args /* {
 1562                 struct vnode *a_vp;
 1563                 struct uio *a_uio;
 1564                 struct ucred *a_cred;
 1565                 int *a_ncookies;
 1566                 u_int **cookies;
 1567         } */ *ap;
 1568 {
 1569         register struct uio *uio = ap->a_uio;
 1570         off_t off;
 1571         int count, lost, error;
 1572 
 1573         if (ap->a_ncookies != NULL)
 1574                 /*
 1575                  * Ensure that the block is aligned.  The caller can use
 1576                  * the cookies to determine where in the block to start.
 1577                  */
 1578                 uio->uio_offset &= ~(DIRBLKSIZ - 1);
 1579         off = uio->uio_offset;
 1580         count = uio->uio_resid;
 1581         count &= ~(DIRBLKSIZ - 1);
 1582         lost = uio->uio_resid - count;
 1583         if (count < DIRBLKSIZ || (uio->uio_offset & (DIRBLKSIZ -1)))
 1584                 return (EINVAL);
 1585         uio->uio_resid = count;
 1586         uio->uio_iov->iov_len = count;
 1587 #       if (BYTE_ORDER == LITTLE_ENDIAN)
 1588                 if (ap->a_vp->v_mount->mnt_maxsymlinklen > 0) {
 1589                         error = VOP_READ(ap->a_vp, uio, 0, ap->a_cred);
 1590                 } else {
 1591                         struct dirent *dp, *edp;
 1592                         struct uio auio;
 1593                         struct iovec aiov;
 1594                         caddr_t dirbuf;
 1595                         int readcnt;
 1596                         u_char tmp;
 1597 
 1598                         auio = *uio;
 1599                         auio.uio_iov = &aiov;
 1600                         auio.uio_iovcnt = 1;
 1601                         auio.uio_segflg = UIO_SYSSPACE;
 1602                         aiov.iov_len = count;
 1603                         MALLOC(dirbuf, caddr_t, count, M_TEMP, M_WAITOK);
 1604                         aiov.iov_base = dirbuf;
 1605                         error = VOP_READ(ap->a_vp, &auio, 0, ap->a_cred);
 1606                         if (error == 0) {
 1607                                 readcnt = count - auio.uio_resid;
 1608                                 edp = (struct dirent *)&dirbuf[readcnt];
 1609                                 for (dp = (struct dirent *)dirbuf; dp < edp; ) {
 1610                                         tmp = dp->d_namlen;
 1611                                         dp->d_namlen = dp->d_type;
 1612                                         dp->d_type = tmp;
 1613                                         if (dp->d_reclen > 0) {
 1614                                                 dp = (struct dirent *)
 1615                                                     ((char *)dp + dp->d_reclen);
 1616                                         } else {
 1617                                                 error = EIO;
 1618                                                 break;
 1619                                         }
 1620                                 }
 1621                                 if (dp >= edp)
 1622                                         error = uiomove(dirbuf, readcnt, uio);
 1623                         }
 1624                         FREE(dirbuf, M_TEMP);
 1625                 }
 1626 #       else
 1627                 error = VOP_READ(ap->a_vp, uio, 0, ap->a_cred);
 1628 #       endif
 1629         if (!error && ap->a_ncookies != NULL) {
 1630                 struct dirent* dpStart;
 1631                 struct dirent* dpEnd;
 1632                 struct dirent* dp;
 1633                 int ncookies;
 1634                 u_int *cookies;
 1635                 u_int *cookiep;
 1636 
 1637                 if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
 1638                         panic("ufs_readdir: unexpected uio from NFS server");
 1639                 dpStart = (struct dirent *)
 1640                      (uio->uio_iov->iov_base - (uio->uio_offset - off));
 1641                 dpEnd = (struct dirent *) uio->uio_iov->iov_base;
 1642                 for (dp = dpStart, ncookies = 0;
 1643                      dp < dpEnd;
 1644                      dp = (struct dirent *)((caddr_t) dp + dp->d_reclen))
 1645                         ncookies++;
 1646                 MALLOC(cookies, u_int *, ncookies * sizeof(u_int),
 1647                        M_TEMP, M_WAITOK);
 1648                 for (dp = dpStart, cookiep = cookies;
 1649                      dp < dpEnd;
 1650                      dp = (struct dirent *)((caddr_t) dp + dp->d_reclen)) {
 1651                         off += dp->d_reclen;
 1652                         *cookiep++ = (u_int) off;
 1653                 }
 1654                 *ap->a_ncookies = ncookies;
 1655                 *ap->a_cookies = cookies;
 1656         }
 1657         if (ap->a_eofflag)
 1658             *ap->a_eofflag = VTOI(ap->a_vp)->i_size <= uio->uio_offset;
 1659         uio->uio_resid += lost;
 1660         return (error);
 1661 }
 1662 
 1663 /*
 1664  * Return target name of a symbolic link
 1665  */
 1666 int
 1667 ufs_readlink(ap)
 1668         struct vop_readlink_args /* {
 1669                 struct vnode *a_vp;
 1670                 struct uio *a_uio;
 1671                 struct ucred *a_cred;
 1672         } */ *ap;
 1673 {
 1674         register struct vnode *vp = ap->a_vp;
 1675         register struct inode *ip = VTOI(vp);
 1676         int isize;
 1677 
 1678         isize = ip->i_size;
 1679         if ((isize < vp->v_mount->mnt_maxsymlinklen) ||
 1680             (ip->i_din.di_blocks == 0)) {       /* XXX - for old fastlink support */
 1681                 uiomove((char *)ip->i_shortlink, isize, ap->a_uio);
 1682                 return (0);
 1683         }
 1684         return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred));
 1685 }
 1686 
 1687 /*
 1688  * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually
 1689  * done. If a buffer has been saved in anticipation of a CREATE, delete it.
 1690  */
 1691 /* ARGSUSED */
 1692 int
 1693 ufs_abortop(ap)
 1694         struct vop_abortop_args /* {
 1695                 struct vnode *a_dvp;
 1696                 struct componentname *a_cnp;
 1697         } */ *ap;
 1698 {
 1699         if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
 1700                 FREE(ap->a_cnp->cn_pnbuf, M_NAMEI);
 1701         return (0);
 1702 }
 1703 
 1704 /*
 1705  * Lock an inode. If its already locked, set the WANT bit and sleep.
 1706  */
 1707 int
 1708 ufs_lock(ap)
 1709         struct vop_lock_args /* {
 1710                 struct vnode *a_vp;
 1711         } */ *ap;
 1712 {
 1713         struct proc *p = curproc;
 1714         register struct vnode *vp = ap->a_vp;
 1715         register struct inode *ip;
 1716 
 1717 start:
 1718         while (vp->v_flag & VXLOCK) {
 1719                 vp->v_flag |= VXWANT;
 1720                 (void) tsleep((caddr_t)vp, PINOD, "ufslk1", 0);
 1721         }
 1722         if (vp->v_tag == VT_NON)
 1723                 return (ENOENT);
 1724         ip = VTOI(vp);
 1725         if (ip->i_flag & IN_LOCKED) {
 1726                 if (p->p_pid == ip->i_lockholder) {
 1727                         if( (ip->i_flag & IN_RECURSE) == 0)
 1728                                 panic("ufs_lock: recursive lock not expected, pid: %d\n",
 1729                                         ip->i_lockholder);
 1730                 } else {
 1731                         ip->i_flag |= IN_WANTED;
 1732 #ifdef DIAGNOSTIC
 1733                         if (p)
 1734                                 ip->i_lockwaiter = p->p_pid;
 1735                         else
 1736                                 ip->i_lockwaiter = -1;
 1737 #endif
 1738                         (void) tsleep((caddr_t)ip, PINOD, "ufslk2", 0);
 1739                         goto start;
 1740                 }
 1741         }
 1742 #ifdef DIAGNOSTIC
 1743         ip->i_lockwaiter = 0;
 1744         if (((ip->i_flag & IN_RECURSE) == 0) && (ip->i_lockholder != 0))
 1745                 panic("lockholder (%d) != 0", ip->i_lockholder);
 1746         if (p && p->p_pid == 0)
 1747                 printf("locking by process 0\n");
 1748 #endif
 1749 
 1750         if ((ip->i_flag & IN_RECURSE) == 0)
 1751                 ip->i_lockcount = 1;
 1752         else
 1753                 ++ip->i_lockcount;
 1754 
 1755         if (p)
 1756                 ip->i_lockholder = p->p_pid;
 1757         else
 1758                 ip->i_lockholder = -1;
 1759         ip->i_flag |= IN_LOCKED;
 1760         return (0);
 1761 }
 1762 
 1763 /*
 1764  * Unlock an inode.  If WANT bit is on, wakeup.
 1765  */
 1766 int lockcount = 90;
 1767 int
 1768 ufs_unlock(ap)
 1769         struct vop_unlock_args /* {
 1770                 struct vnode *a_vp;
 1771         } */ *ap;
 1772 {
 1773         register struct inode *ip = VTOI(ap->a_vp);
 1774 
 1775 #ifdef DIAGNOSTIC
 1776         struct proc *p = curproc;
 1777 
 1778         if ((ip->i_flag & IN_LOCKED) == 0) {
 1779                 vprint("ufs_unlock: unlocked inode", ap->a_vp);
 1780                 panic("ufs_unlock NOT LOCKED");
 1781         }
 1782         if (p && p->p_pid != ip->i_lockholder && p->p_pid > -1 &&
 1783             ip->i_lockholder > -1 && lockcount++ < 100)
 1784                 panic("unlocker (%d) != lock holder (%d)",
 1785                     p->p_pid, ip->i_lockholder);
 1786 #endif
 1787         if (--ip->i_lockcount > 0) {
 1788                 if ((ip->i_flag & IN_RECURSE) == 0)
 1789                         panic("ufs_unlock: recursive lock prematurely released, pid=%d\n",
 1790                                 ip->i_lockholder);
 1791                 return (0);
 1792         }
 1793         ip->i_lockholder = 0;
 1794         ip->i_flag &= ~(IN_LOCKED|IN_RECURSE);
 1795         if (ip->i_flag & IN_WANTED) {
 1796                 ip->i_flag &= ~IN_WANTED;
 1797                 wakeup((caddr_t)ip);
 1798         }
 1799         return (0);
 1800 }
 1801 
 1802 /*
 1803  * Check for a locked inode.
 1804  */
 1805 int
 1806 ufs_islocked(ap)
 1807         struct vop_islocked_args /* {
 1808                 struct vnode *a_vp;
 1809         } */ *ap;
 1810 {
 1811 
 1812         if (VTOI(ap->a_vp)->i_flag & IN_LOCKED)
 1813                 return (1);
 1814         return (0);
 1815 }
 1816 
 1817 /*
 1818  * Calculate the logical to physical mapping if not done already,
 1819  * then call the device strategy routine.
 1820  */
 1821 int
 1822 ufs_strategy(ap)
 1823         struct vop_strategy_args /* {
 1824                 struct buf *a_bp;
 1825         } */ *ap;
 1826 {
 1827         register struct buf *bp = ap->a_bp;
 1828         register struct vnode *vp = bp->b_vp;
 1829         register struct inode *ip;
 1830         int error;
 1831 
 1832         ip = VTOI(vp);
 1833         if (vp->v_type == VBLK || vp->v_type == VCHR)
 1834                 panic("ufs_strategy: spec");
 1835         if (bp->b_blkno == bp->b_lblkno) {
 1836                 error = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL, NULL);
 1837                 if (error) {
 1838                         bp->b_error = error;
 1839                         bp->b_flags |= B_ERROR;
 1840                         biodone(bp);
 1841                         return (error);
 1842                 }
 1843                 if ((long)bp->b_blkno == -1)
 1844                         vfs_bio_clrbuf(bp);
 1845         }
 1846         if ((long)bp->b_blkno == -1) {
 1847                 biodone(bp);
 1848                 return (0);
 1849         }
 1850         vp = ip->i_devvp;
 1851         bp->b_dev = vp->v_rdev;
 1852         VOCALL (vp->v_op, VOFFSET(vop_strategy), ap);
 1853         return (0);
 1854 }
 1855 
 1856 /*
 1857  * Print out the contents of an inode.
 1858  */
 1859 int
 1860 ufs_print(ap)
 1861         struct vop_print_args /* {
 1862                 struct vnode *a_vp;
 1863         } */ *ap;
 1864 {
 1865         register struct vnode *vp = ap->a_vp;
 1866         register struct inode *ip = VTOI(vp);
 1867 
 1868         printf("tag VT_UFS, ino %ld, on dev %d, %d", ip->i_number,
 1869                 major(ip->i_dev), minor(ip->i_dev));
 1870         if (vp->v_type == VFIFO)
 1871                 fifo_printinfo(vp);
 1872         printf("%s\n", (ip->i_flag & IN_LOCKED) ? " (LOCKED)" : "");
 1873         if (ip->i_lockholder == 0)
 1874                 return (0);
 1875         printf("\towner pid %lu", (u_long)ip->i_lockholder);
 1876         if (ip->i_lockwaiter)
 1877                 printf(" waiting pid %lu", (u_long)ip->i_lockwaiter);
 1878         printf("\n");
 1879         return (0);
 1880 }
 1881 
 1882 /*
 1883  * Read wrapper for special devices.
 1884  */
 1885 int
 1886 ufsspec_read(ap)
 1887         struct vop_read_args /* {
 1888                 struct vnode *a_vp;
 1889                 struct uio *a_uio;
 1890                 int  a_ioflag;
 1891                 struct ucred *a_cred;
 1892         } */ *ap;
 1893 {
 1894 
 1895         /*
 1896          * Set access flag.
 1897          */
 1898         VTOI(ap->a_vp)->i_flag |= IN_ACCESS;
 1899         return (VOCALL (spec_vnodeop_p, VOFFSET(vop_read), ap));
 1900 }
 1901 
 1902 /*
 1903  * Write wrapper for special devices.
 1904  */
 1905 int
 1906 ufsspec_write(ap)
 1907         struct vop_write_args /* {
 1908                 struct vnode *a_vp;
 1909                 struct uio *a_uio;
 1910                 int  a_ioflag;
 1911                 struct ucred *a_cred;
 1912         } */ *ap;
 1913 {
 1914 
 1915         /*
 1916          * Set update and change flags.
 1917          */
 1918         VTOI(ap->a_vp)->i_flag |= IN_CHANGE | IN_UPDATE;
 1919         return (VOCALL (spec_vnodeop_p, VOFFSET(vop_write), ap));
 1920 }
 1921 
 1922 /*
 1923  * Close wrapper for special devices.
 1924  *
 1925  * Update the times on the inode then do device close.
 1926  */
 1927 int
 1928 ufsspec_close(ap)
 1929         struct vop_close_args /* {
 1930                 struct vnode *a_vp;
 1931                 int  a_fflag;
 1932                 struct ucred *a_cred;
 1933                 struct proc *a_p;
 1934         } */ *ap;
 1935 {
 1936         register struct inode *ip = VTOI(ap->a_vp);
 1937 
 1938         if (ap->a_vp->v_usecount > 1 && !(ip->i_flag & IN_LOCKED))
 1939                 ITIMES(ip, &time, &time);
 1940         return (VOCALL (spec_vnodeop_p, VOFFSET(vop_close), ap));
 1941 }
 1942 
 1943 /*
 1944  * Read wrapper for fifo's
 1945  */
 1946 int
 1947 ufsfifo_read(ap)
 1948         struct vop_read_args /* {
 1949                 struct vnode *a_vp;
 1950                 struct uio *a_uio;
 1951                 int  a_ioflag;
 1952                 struct ucred *a_cred;
 1953         } */ *ap;
 1954 {
 1955         /*
 1956          * Set access flag.
 1957          */
 1958         VTOI(ap->a_vp)->i_flag |= IN_ACCESS;
 1959         return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_read), ap));
 1960 }
 1961 
 1962 /*
 1963  * Write wrapper for fifo's.
 1964  */
 1965 int
 1966 ufsfifo_write(ap)
 1967         struct vop_write_args /* {
 1968                 struct vnode *a_vp;
 1969                 struct uio *a_uio;
 1970                 int  a_ioflag;
 1971                 struct ucred *a_cred;
 1972         } */ *ap;
 1973 {
 1974         /*
 1975          * Set update and change flags.
 1976          */
 1977         VTOI(ap->a_vp)->i_flag |= IN_CHANGE | IN_UPDATE;
 1978         return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_write), ap));
 1979 }
 1980 
 1981 /*
 1982  * Close wrapper for fifo's.
 1983  *
 1984  * Update the times on the inode then do device close.
 1985  */
 1986 int
 1987 ufsfifo_close(ap)
 1988         struct vop_close_args /* {
 1989                 struct vnode *a_vp;
 1990                 int  a_fflag;
 1991                 struct ucred *a_cred;
 1992                 struct proc *a_p;
 1993         } */ *ap;
 1994 {
 1995         register struct inode *ip = VTOI(ap->a_vp);
 1996 
 1997         if (ap->a_vp->v_usecount > 1 && !(ip->i_flag & IN_LOCKED))
 1998                 ITIMES(ip, &time, &time);
 1999         return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_close), ap));
 2000 }
 2001 
 2002 /*
 2003  * Return POSIX pathconf information applicable to ufs filesystems.
 2004  */
 2005 int
 2006 ufs_pathconf(ap)
 2007         struct vop_pathconf_args /* {
 2008                 struct vnode *a_vp;
 2009                 int a_name;
 2010                 int *a_retval;
 2011         } */ *ap;
 2012 {
 2013 
 2014         switch (ap->a_name) {
 2015         case _PC_LINK_MAX:
 2016                 *ap->a_retval = LINK_MAX;
 2017                 return (0);
 2018         case _PC_NAME_MAX:
 2019                 *ap->a_retval = NAME_MAX;
 2020                 return (0);
 2021         case _PC_PATH_MAX:
 2022                 *ap->a_retval = PATH_MAX;
 2023                 return (0);
 2024         case _PC_PIPE_BUF:
 2025                 *ap->a_retval = PIPE_BUF;
 2026                 return (0);
 2027         case _PC_CHOWN_RESTRICTED:
 2028                 *ap->a_retval = 1;
 2029                 return (0);
 2030         case _PC_NO_TRUNC:
 2031                 *ap->a_retval = 1;
 2032                 return (0);
 2033         default:
 2034                 return (EINVAL);
 2035         }
 2036         /* NOTREACHED */
 2037 }
 2038 
 2039 /*
 2040  * Advisory record locking support
 2041  */
 2042 int
 2043 ufs_advlock(ap)
 2044         struct vop_advlock_args /* {
 2045                 struct vnode *a_vp;
 2046                 caddr_t  a_id;
 2047                 int  a_op;
 2048                 struct flock *a_fl;
 2049                 int  a_flags;
 2050         } */ *ap;
 2051 {
 2052         register struct inode *ip = VTOI(ap->a_vp);
 2053 
 2054         return (lf_advlock(ap, &(ip->i_lockf), ip->i_size));
 2055 }
 2056 
 2057 /*
 2058  * Initialize the vnode associated with a new inode, handle aliased
 2059  * vnodes.
 2060  */
 2061 int
 2062 ufs_vinit(mntp, specops, fifoops, vpp)
 2063         struct mount *mntp;
 2064         vop_t **specops;
 2065         vop_t **fifoops;
 2066         struct vnode **vpp;
 2067 {
 2068         struct inode *ip;
 2069         struct vnode *vp, *nvp;
 2070 
 2071         vp = *vpp;
 2072         ip = VTOI(vp);
 2073         switch(vp->v_type = IFTOVT(ip->i_mode)) {
 2074         case VCHR:
 2075         case VBLK:
 2076                 vp->v_op = specops;
 2077                 nvp = checkalias(vp, ip->i_rdev, mntp);
 2078                 if (nvp) {
 2079                         /*
 2080                          * Discard unneeded vnode, but save its inode.
 2081                          */
 2082                         ufs_ihashrem(ip);
 2083                         VOP_UNLOCK(vp);
 2084                         nvp->v_data = vp->v_data;
 2085                         vp->v_data = NULL;
 2086                         vp->v_op = spec_vnodeop_p;
 2087                         vrele(vp);
 2088                         vgone(vp);
 2089                         /*
 2090                          * Reinitialize aliased inode.
 2091                          */
 2092                         vp = nvp;
 2093                         ip->i_vnode = vp;
 2094                         ufs_ihashins(ip);
 2095                 }
 2096                 break;
 2097         case VFIFO:
 2098                 vp->v_op = fifoops;
 2099                 break;
 2100         default:
 2101                 break;
 2102 
 2103         }
 2104         if (ip->i_number == ROOTINO)
 2105                 vp->v_flag |= VROOT;
 2106         /*
 2107          * Initialize modrev times
 2108          */
 2109         SETHIGH(ip->i_modrev, mono_time.tv_sec);
 2110         SETLOW(ip->i_modrev, mono_time.tv_usec * 4294);
 2111         *vpp = vp;
 2112         return (0);
 2113 }
 2114 
 2115 /*
 2116  * Allocate a new inode.
 2117  */
 2118 int
 2119 ufs_makeinode(mode, dvp, vpp, cnp)
 2120         int mode;
 2121         struct vnode *dvp;
 2122         struct vnode **vpp;
 2123         struct componentname *cnp;
 2124 {
 2125         register struct inode *ip, *pdir;
 2126         struct timeval tv;
 2127         struct vnode *tvp;
 2128         int error;
 2129 
 2130         pdir = VTOI(dvp);
 2131 #ifdef DIAGNOSTIC
 2132         if ((cnp->cn_flags & HASBUF) == 0)
 2133                 panic("ufs_makeinode: no name");
 2134 #endif
 2135         *vpp = NULL;
 2136         if ((mode & IFMT) == 0)
 2137                 mode |= IFREG;
 2138 
 2139         error = VOP_VALLOC(dvp, mode, cnp->cn_cred, &tvp);
 2140         if (error) {
 2141                 free(cnp->cn_pnbuf, M_NAMEI);
 2142                 vput(dvp);
 2143                 return (error);
 2144         }
 2145         ip = VTOI(tvp);
 2146         ip->i_gid = pdir->i_gid;
 2147         ip->i_uid = cnp->cn_cred->cr_uid;
 2148 #ifdef QUOTA
 2149         if ((error = getinoquota(ip)) ||
 2150             (error = chkiq(ip, 1, cnp->cn_cred, 0))) {
 2151                 free(cnp->cn_pnbuf, M_NAMEI);
 2152                 VOP_VFREE(tvp, ip->i_number, mode);
 2153                 vput(tvp);
 2154                 vput(dvp);
 2155                 return (error);
 2156         }
 2157 #endif
 2158         ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
 2159         ip->i_mode = mode;
 2160         tvp->v_type = IFTOVT(mode);     /* Rest init'd in getnewvnode(). */
 2161         ip->i_nlink = 1;
 2162         if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, cnp->cn_cred) &&
 2163             suser(cnp->cn_cred, NULL))
 2164                 ip->i_mode &= ~ISGID;
 2165 
 2166         /*
 2167          * Make sure inode goes to disk before directory entry.
 2168          */
 2169         tv = time;
 2170         error = VOP_UPDATE(tvp, &tv, &tv, 1);
 2171         if (error)
 2172                 goto bad;
 2173 #ifdef EXT2FS
 2174         if (IS_EXT2_VNODE(dvp)) {
 2175                 error = ext2_direnter(ip, dvp, cnp);
 2176         } else {
 2177                 error = ufs_direnter(ip, dvp, cnp);
 2178         }
 2179 #else
 2180         error = ufs_direnter(ip, dvp, cnp);
 2181 #endif  /* EXT2FS */
 2182         if (error)
 2183                 goto bad;
 2184 
 2185         if ((cnp->cn_flags & SAVESTART) == 0)
 2186                 FREE(cnp->cn_pnbuf, M_NAMEI);
 2187         vput(dvp);
 2188         *vpp = tvp;
 2189         return (0);
 2190 
 2191 bad:
 2192         /*
 2193          * Write error occurred trying to update the inode
 2194          * or the directory so must deallocate the inode.
 2195          */
 2196         free(cnp->cn_pnbuf, M_NAMEI);
 2197         vput(dvp);
 2198         ip->i_nlink = 0;
 2199         ip->i_flag |= IN_CHANGE;
 2200         vput(tvp);
 2201         return (error);
 2202 }

Cache object: 53033de3097fc02ab774852c0f0c3e3f


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