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

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

CVSweb <webmaster@jp.NetBSD.org>