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

Cache object: 542399c4194d8d25f036d52c134d1148


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