[BACK]Return to ufs_vnops.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / ufs / ufs

Annotation of src/sys/ufs/ufs/ufs_vnops.c, Revision 1.177

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

CVSweb <webmaster@jp.NetBSD.org>