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

Cache object: 82d748bdf76e47fccea52e9beb1b2d9b


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