[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

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