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

Cache object: b759f96c161c6c2392927a1a6370efb6


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