[BACK]Return to ufs_vnops.c CVS log [TXT][DIR] Up to [local] / sys / ufs / ufs

Annotation of sys/ufs/ufs/ufs_vnops.c, Revision 1.1

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

CVSweb