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

Annotation of src/sys/ufs/lfs/ulfs_vnops.c, Revision 1.21.6.6

1.21.6.6! skrll       1: /*     $NetBSD: ulfs_vnops.c,v 1.21.6.5 2016/07/09 20:25:25 skrll Exp $        */
1.10      dholland    2: /*  from NetBSD: ufs_vnops.c,v 1.213 2013/06/08 05:47:02 kardel Exp  */
1.1       dholland    3:
                      4: /*-
                      5:  * Copyright (c) 2008 The NetBSD Foundation, Inc.
                      6:  * All rights reserved.
                      7:  *
                      8:  * This code is derived from software contributed to The NetBSD Foundation
                      9:  * by Wasabi Systems, Inc.
                     10:  *
                     11:  * Redistribution and use in source and binary forms, with or without
                     12:  * modification, are permitted provided that the following conditions
                     13:  * are met:
                     14:  * 1. Redistributions of source code must retain the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer.
                     16:  * 2. Redistributions in binary form must reproduce the above copyright
                     17:  *    notice, this list of conditions and the following disclaimer in the
                     18:  *    documentation and/or other materials provided with the distribution.
                     19:  *
                     20:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     21:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     22:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     23:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     24:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     25:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     26:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     27:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     28:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     29:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     30:  * POSSIBILITY OF SUCH DAMAGE.
                     31:  */
                     32:
                     33: /*
                     34:  * Copyright (c) 1982, 1986, 1989, 1993, 1995
                     35:  *     The Regents of the University of California.  All rights reserved.
                     36:  * (c) UNIX System Laboratories, Inc.
                     37:  * All or some portions of this file are derived from material licensed
                     38:  * to the University of California by American Telephone and Telegraph
                     39:  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
                     40:  * the permission of UNIX System Laboratories, Inc.
                     41:  *
                     42:  * Redistribution and use in source and binary forms, with or without
                     43:  * modification, are permitted provided that the following conditions
                     44:  * are met:
                     45:  * 1. Redistributions of source code must retain the above copyright
                     46:  *    notice, this list of conditions and the following disclaimer.
                     47:  * 2. Redistributions in binary form must reproduce the above copyright
                     48:  *    notice, this list of conditions and the following disclaimer in the
                     49:  *    documentation and/or other materials provided with the distribution.
                     50:  * 3. Neither the name of the University nor the names of its contributors
                     51:  *    may be used to endorse or promote products derived from this software
                     52:  *    without specific prior written permission.
                     53:  *
                     54:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     55:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     56:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     57:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     58:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     59:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     60:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     61:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     62:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     63:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     64:  * SUCH DAMAGE.
                     65:  *
                     66:  *     @(#)ufs_vnops.c 8.28 (Berkeley) 7/31/95
                     67:  */
                     68:
                     69: #include <sys/cdefs.h>
1.21.6.6! skrll      70: __KERNEL_RCSID(0, "$NetBSD: ulfs_vnops.c,v 1.21.6.5 2016/07/09 20:25:25 skrll Exp $");
1.1       dholland   71:
                     72: #if defined(_KERNEL_OPT)
1.3       dholland   73: #include "opt_lfs.h"
1.1       dholland   74: #include "opt_quota.h"
                     75: #endif
                     76:
                     77: #include <sys/param.h>
                     78: #include <sys/systm.h>
                     79: #include <sys/namei.h>
                     80: #include <sys/resourcevar.h>
                     81: #include <sys/kernel.h>
                     82: #include <sys/file.h>
                     83: #include <sys/stat.h>
                     84: #include <sys/buf.h>
                     85: #include <sys/proc.h>
                     86: #include <sys/mount.h>
                     87: #include <sys/vnode.h>
                     88: #include <sys/kmem.h>
                     89: #include <sys/malloc.h>
                     90: #include <sys/dirent.h>
                     91: #include <sys/lockf.h>
                     92: #include <sys/kauth.h>
                     93:
                     94: #include <miscfs/specfs/specdev.h>
                     95: #include <miscfs/fifofs/fifo.h>
                     96: #include <miscfs/genfs/genfs.h>
                     97:
1.21.6.3  skrll      98: #include <ufs/lfs/lfs_extern.h>
                     99: #include <ufs/lfs/lfs.h>
                    100: #include <ufs/lfs/lfs_accessors.h>
                    101:
1.2       dholland  102: #include <ufs/lfs/ulfs_inode.h>
                    103: #include <ufs/lfs/ulfsmount.h>
                    104: #include <ufs/lfs/ulfs_bswap.h>
                    105: #include <ufs/lfs/ulfs_extern.h>
1.3       dholland  106: #ifdef LFS_DIRHASH
1.2       dholland  107: #include <ufs/lfs/ulfs_dirhash.h>
1.1       dholland  108: #endif
                    109:
                    110: #include <uvm/uvm.h>
                    111:
1.4       dholland  112: static int ulfs_chmod(struct vnode *, int, kauth_cred_t, struct lwp *);
                    113: static int ulfs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t,
1.1       dholland  114:     struct lwp *);
                    115:
                    116: /*
                    117:  * Open called.
                    118:  *
                    119:  * Nothing to do.
                    120:  */
                    121: /* ARGSUSED */
                    122: int
1.4       dholland  123: ulfs_open(void *v)
1.1       dholland  124: {
                    125:        struct vop_open_args /* {
                    126:                struct vnode    *a_vp;
                    127:                int             a_mode;
                    128:                kauth_cred_t    a_cred;
                    129:        } */ *ap = v;
                    130:
1.21.6.6! skrll     131:        KASSERT(VOP_ISLOCKED(ap->a_vp) == LK_EXCLUSIVE);
        !           132:
1.1       dholland  133:        /*
                    134:         * Files marked append-only must be opened for appending.
                    135:         */
                    136:        if ((VTOI(ap->a_vp)->i_flags & APPEND) &&
                    137:            (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
                    138:                return (EPERM);
                    139:        return (0);
                    140: }
                    141:
                    142: static int
1.4       dholland  143: ulfs_check_possible(struct vnode *vp, struct inode *ip, mode_t mode,
1.1       dholland  144:     kauth_cred_t cred)
                    145: {
1.3       dholland  146: #if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
1.1       dholland  147:        int error;
                    148: #endif
                    149:
                    150:        /*
                    151:         * Disallow write attempts on read-only file systems;
                    152:         * unless the file is a socket, fifo, or a block or
                    153:         * character device resident on the file system.
                    154:         */
                    155:        if (mode & VWRITE) {
                    156:                switch (vp->v_type) {
                    157:                case VDIR:
                    158:                case VLNK:
                    159:                case VREG:
                    160:                        if (vp->v_mount->mnt_flag & MNT_RDONLY)
                    161:                                return (EROFS);
1.3       dholland  162: #if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
1.5       dholland  163:                        error = lfs_chkdq(ip, 0, cred, 0);
1.1       dholland  164:                        if (error != 0)
                    165:                                return error;
                    166: #endif
                    167:                        break;
                    168:                case VBAD:
                    169:                case VBLK:
                    170:                case VCHR:
                    171:                case VSOCK:
                    172:                case VFIFO:
                    173:                case VNON:
                    174:                default:
                    175:                        break;
                    176:                }
                    177:        }
                    178:
                    179:        /* If it is a snapshot, nobody gets access to it. */
                    180:        if ((ip->i_flags & SF_SNAPSHOT))
                    181:                return (EPERM);
                    182:        /* If immutable bit set, nobody gets to write it. */
                    183:        if ((mode & VWRITE) && (ip->i_flags & IMMUTABLE))
                    184:                return (EPERM);
                    185:
                    186:        return 0;
                    187: }
                    188:
                    189: static int
1.4       dholland  190: ulfs_check_permitted(struct vnode *vp, struct inode *ip, mode_t mode,
1.1       dholland  191:     kauth_cred_t cred)
                    192: {
                    193:
                    194:        return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode, vp->v_type,
                    195:            ip->i_mode & ALLPERMS), vp, NULL, genfs_can_access(vp->v_type,
                    196:            ip->i_mode & ALLPERMS, ip->i_uid, ip->i_gid, mode, cred));
                    197: }
                    198:
                    199: int
1.4       dholland  200: ulfs_access(void *v)
1.1       dholland  201: {
                    202:        struct vop_access_args /* {
                    203:                struct vnode    *a_vp;
                    204:                int             a_mode;
                    205:                kauth_cred_t    a_cred;
                    206:        } */ *ap = v;
                    207:        struct vnode    *vp;
                    208:        struct inode    *ip;
                    209:        mode_t          mode;
                    210:        int             error;
                    211:
                    212:        vp = ap->a_vp;
                    213:        mode = ap->a_mode;
                    214:
1.21.6.6! skrll     215:        KASSERT(VOP_ISLOCKED(vp));
        !           216:
        !           217:        ip = VTOI(vp);
        !           218:
1.4       dholland  219:        error = ulfs_check_possible(vp, ip, mode, ap->a_cred);
1.1       dholland  220:        if (error)
                    221:                return error;
                    222:
1.4       dholland  223:        error = ulfs_check_permitted(vp, ip, mode, ap->a_cred);
1.1       dholland  224:
                    225:        return error;
                    226: }
                    227:
                    228: /*
                    229:  * Set attribute vnode op. called from several syscalls
                    230:  */
                    231: int
1.4       dholland  232: ulfs_setattr(void *v)
1.1       dholland  233: {
                    234:        struct vop_setattr_args /* {
                    235:                struct vnode    *a_vp;
                    236:                struct vattr    *a_vap;
                    237:                kauth_cred_t    a_cred;
                    238:        } */ *ap = v;
                    239:        struct vattr    *vap;
                    240:        struct vnode    *vp;
                    241:        struct inode    *ip;
1.21.6.3  skrll     242:        struct lfs      *fs;
1.1       dholland  243:        kauth_cred_t    cred;
                    244:        struct lwp      *l;
                    245:        int             error;
                    246:        kauth_action_t  action;
                    247:        bool            changing_sysflags;
                    248:
                    249:        vap = ap->a_vap;
                    250:        vp = ap->a_vp;
                    251:        cred = ap->a_cred;
                    252:        l = curlwp;
                    253:        action = KAUTH_VNODE_WRITE_FLAGS;
                    254:        changing_sysflags = false;
                    255:
1.21.6.6! skrll     256:        KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
        !           257:
        !           258:        ip = VTOI(vp);
        !           259:        fs = ip->i_lfs;
        !           260:
1.1       dholland  261:        /*
                    262:         * Check for unsettable attributes.
                    263:         */
                    264:        if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
                    265:            (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
                    266:            (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
                    267:            ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
                    268:                return (EINVAL);
                    269:        }
                    270:
                    271:        if (vap->va_flags != VNOVAL) {
                    272:                if (vp->v_mount->mnt_flag & MNT_RDONLY) {
                    273:                        error = EROFS;
                    274:                        goto out;
                    275:                }
                    276:
                    277:                /* Snapshot flag cannot be set or cleared */
                    278:                if ((vap->va_flags & (SF_SNAPSHOT | SF_SNAPINVAL)) !=
                    279:                    (ip->i_flags & (SF_SNAPSHOT | SF_SNAPINVAL))) {
                    280:                        error = EPERM;
                    281:                        goto out;
                    282:                }
                    283:
                    284:                if (ip->i_flags & (SF_IMMUTABLE | SF_APPEND)) {
                    285:                        action |= KAUTH_VNODE_HAS_SYSFLAGS;
                    286:                }
                    287:
1.21.6.5  skrll     288:                if ((vap->va_flags & SF_SETTABLE) !=
                    289:                    (ip->i_flags & SF_SETTABLE)) {
1.1       dholland  290:                        action |= KAUTH_VNODE_WRITE_SYSFLAGS;
                    291:                        changing_sysflags = true;
                    292:                }
                    293:
                    294:                error = kauth_authorize_vnode(cred, action, vp, NULL,
                    295:                    genfs_can_chflags(cred, vp->v_type, ip->i_uid,
                    296:                    changing_sysflags));
                    297:                if (error)
                    298:                        goto out;
                    299:
                    300:                if (changing_sysflags) {
                    301:                        ip->i_flags = vap->va_flags;
                    302:                        DIP_ASSIGN(ip, flags, ip->i_flags);
                    303:                } else {
                    304:                        ip->i_flags &= SF_SETTABLE;
                    305:                        ip->i_flags |= (vap->va_flags & UF_SETTABLE);
                    306:                        DIP_ASSIGN(ip, flags, ip->i_flags);
                    307:                }
1.21.6.6! skrll     308:                ip->i_state |= IN_CHANGE;
1.1       dholland  309:                if (vap->va_flags & (IMMUTABLE | APPEND)) {
                    310:                        error = 0;
                    311:                        goto out;
                    312:                }
                    313:        }
                    314:        if (ip->i_flags & (IMMUTABLE | APPEND)) {
                    315:                error = EPERM;
                    316:                goto out;
                    317:        }
                    318:        /*
                    319:         * Go through the fields and update iff not VNOVAL.
                    320:         */
                    321:        if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
                    322:                if (vp->v_mount->mnt_flag & MNT_RDONLY) {
                    323:                        error = EROFS;
                    324:                        goto out;
                    325:                }
1.4       dholland  326:                error = ulfs_chown(vp, vap->va_uid, vap->va_gid, cred, l);
1.1       dholland  327:                if (error)
                    328:                        goto out;
                    329:        }
                    330:        if (vap->va_size != VNOVAL) {
                    331:                /*
                    332:                 * Disallow write attempts on read-only file systems;
                    333:                 * unless the file is a socket, fifo, or a block or
                    334:                 * character device resident on the file system.
                    335:                 */
                    336:                switch (vp->v_type) {
                    337:                case VDIR:
                    338:                        error = EISDIR;
                    339:                        goto out;
                    340:                case VCHR:
                    341:                case VBLK:
                    342:                case VFIFO:
                    343:                        break;
                    344:                case VREG:
                    345:                        if (vp->v_mount->mnt_flag & MNT_RDONLY) {
                    346:                                error = EROFS;
                    347:                                goto out;
                    348:                        }
                    349:                        if ((ip->i_flags & SF_SNAPSHOT) != 0) {
                    350:                                error = EPERM;
                    351:                                goto out;
                    352:                        }
1.17      dholland  353:                        error = lfs_truncate(vp, vap->va_size, 0, cred);
1.1       dholland  354:                        if (error)
                    355:                                goto out;
                    356:                        break;
                    357:                default:
                    358:                        error = EOPNOTSUPP;
                    359:                        goto out;
                    360:                }
                    361:        }
                    362:        ip = VTOI(vp);
                    363:        if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL ||
                    364:            vap->va_birthtime.tv_sec != VNOVAL) {
                    365:                if (vp->v_mount->mnt_flag & MNT_RDONLY) {
                    366:                        error = EROFS;
                    367:                        goto out;
                    368:                }
                    369:                if ((ip->i_flags & SF_SNAPSHOT) != 0) {
                    370:                        error = EPERM;
                    371:                        goto out;
                    372:                }
                    373:                error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp,
                    374:                    NULL, genfs_can_chtimes(vp, vap->va_vaflags, ip->i_uid, cred));
                    375:                if (error)
                    376:                        goto out;
                    377:                if (vap->va_atime.tv_sec != VNOVAL)
                    378:                        if (!(vp->v_mount->mnt_flag & MNT_NOATIME))
1.21.6.6! skrll     379:                                ip->i_state |= IN_ACCESS;
1.1       dholland  380:                if (vap->va_mtime.tv_sec != VNOVAL) {
1.21.6.6! skrll     381:                        ip->i_state |= IN_CHANGE | IN_UPDATE;
1.1       dholland  382:                        if (vp->v_mount->mnt_flag & MNT_RELATIME)
1.21.6.6! skrll     383:                                ip->i_state |= IN_ACCESS;
1.1       dholland  384:                }
1.21.6.3  skrll     385:                if (vap->va_birthtime.tv_sec != VNOVAL) {
                    386:                        lfs_dino_setbirthtime(fs, ip->i_din,
                    387:                                              &vap->va_birthtime);
1.1       dholland  388:                }
1.17      dholland  389:                error = lfs_update(vp, &vap->va_atime, &vap->va_mtime, 0);
1.1       dholland  390:                if (error)
                    391:                        goto out;
                    392:        }
                    393:        error = 0;
                    394:        if (vap->va_mode != (mode_t)VNOVAL) {
                    395:                if (vp->v_mount->mnt_flag & MNT_RDONLY) {
                    396:                        error = EROFS;
                    397:                        goto out;
                    398:                }
                    399:                if ((ip->i_flags & SF_SNAPSHOT) != 0 &&
                    400:                    (vap->va_mode & (S_IXUSR | S_IWUSR | S_IXGRP | S_IWGRP |
                    401:                     S_IXOTH | S_IWOTH))) {
                    402:                        error = EPERM;
                    403:                        goto out;
                    404:                }
1.4       dholland  405:                error = ulfs_chmod(vp, (int)vap->va_mode, cred, l);
1.1       dholland  406:        }
                    407:        VN_KNOTE(vp, NOTE_ATTRIB);
                    408: out:
                    409:        return (error);
                    410: }
                    411:
                    412: /*
                    413:  * Change the mode on a file.
                    414:  * Inode must be locked before calling.
                    415:  */
                    416: static int
1.4       dholland  417: ulfs_chmod(struct vnode *vp, int mode, kauth_cred_t cred, struct lwp *l)
1.1       dholland  418: {
                    419:        struct inode    *ip;
                    420:        int             error;
                    421:
1.21.6.6! skrll     422:        KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
        !           423:
1.1       dholland  424:        ip = VTOI(vp);
                    425:
                    426:        error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY, vp,
                    427:            NULL, genfs_can_chmod(vp->v_type, cred, ip->i_uid, ip->i_gid, mode));
                    428:        if (error)
                    429:                return (error);
                    430:
                    431:        ip->i_mode &= ~ALLPERMS;
                    432:        ip->i_mode |= (mode & ALLPERMS);
1.21.6.6! skrll     433:        ip->i_state |= IN_CHANGE;
1.1       dholland  434:        DIP_ASSIGN(ip, mode, ip->i_mode);
                    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
1.4       dholland  443: ulfs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred,
1.1       dholland  444:        struct lwp *l)
                    445: {
                    446:        struct inode    *ip;
                    447:        int             error = 0;
1.3       dholland  448: #if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
1.1       dholland  449:        uid_t           ouid;
                    450:        gid_t           ogid;
                    451:        int64_t         change;
                    452: #endif
1.21.6.6! skrll     453:
        !           454:        KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
        !           455:
1.1       dholland  456:        ip = VTOI(vp);
                    457:        error = 0;
                    458:
                    459:        if (uid == (uid_t)VNOVAL)
                    460:                uid = ip->i_uid;
                    461:        if (gid == (gid_t)VNOVAL)
                    462:                gid = ip->i_gid;
                    463:
                    464:        error = kauth_authorize_vnode(cred, KAUTH_VNODE_CHANGE_OWNERSHIP, vp,
                    465:            NULL, genfs_can_chown(cred, ip->i_uid, ip->i_gid, uid, gid));
                    466:        if (error)
                    467:                return (error);
                    468:
1.3       dholland  469: #if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
1.1       dholland  470:        ogid = ip->i_gid;
                    471:        ouid = ip->i_uid;
                    472:        change = DIP(ip, blocks);
1.5       dholland  473:        (void) lfs_chkdq(ip, -change, cred, 0);
                    474:        (void) lfs_chkiq(ip, -1, cred, 0);
1.1       dholland  475: #endif
                    476:        ip->i_gid = gid;
                    477:        DIP_ASSIGN(ip, gid, gid);
                    478:        ip->i_uid = uid;
                    479:        DIP_ASSIGN(ip, uid, uid);
1.3       dholland  480: #if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
1.5       dholland  481:        if ((error = lfs_chkdq(ip, change, cred, 0)) == 0) {
                    482:                if ((error = lfs_chkiq(ip, 1, cred, 0)) == 0)
1.1       dholland  483:                        goto good;
                    484:                else
1.5       dholland  485:                        (void) lfs_chkdq(ip, -change, cred, FORCE);
1.1       dholland  486:        }
                    487:        ip->i_gid = ogid;
                    488:        DIP_ASSIGN(ip, gid, ogid);
                    489:        ip->i_uid = ouid;
                    490:        DIP_ASSIGN(ip, uid, ouid);
1.5       dholland  491:        (void) lfs_chkdq(ip, change, cred, FORCE);
                    492:        (void) lfs_chkiq(ip, 1, cred, FORCE);
1.1       dholland  493:        return (error);
                    494:  good:
1.3       dholland  495: #endif /* LFS_QUOTA || LFS_QUOTA2 */
1.21.6.6! skrll     496:        ip->i_state |= IN_CHANGE;
1.1       dholland  497:        return (0);
                    498: }
                    499:
                    500: int
1.4       dholland  501: ulfs_remove(void *v)
1.1       dholland  502: {
1.21.6.6! skrll     503:        struct vop_remove_v2_args /* {
1.1       dholland  504:                struct vnode            *a_dvp;
                    505:                struct vnode            *a_vp;
                    506:                struct componentname    *a_cnp;
                    507:        } */ *ap = v;
                    508:        struct vnode    *vp, *dvp;
                    509:        struct inode    *ip;
                    510:        int             error;
1.4       dholland  511:        struct ulfs_lookup_results *ulr;
1.1       dholland  512:
                    513:        dvp = ap->a_dvp;
1.21.6.6! skrll     514:        vp = ap->a_vp;
        !           515:
        !           516:        KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
        !           517:        KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
        !           518:        KASSERT(dvp->v_mount == vp->v_mount);
        !           519:
1.1       dholland  520:        ip = VTOI(vp);
                    521:
                    522:        /* XXX should handle this material another way */
                    523:        ulr = &VTOI(dvp)->i_crap;
1.4       dholland  524:        ULFS_CHECK_CRAPCOUNTER(VTOI(dvp));
1.1       dholland  525:
                    526:        if (vp->v_type == VDIR || (ip->i_flags & (IMMUTABLE | APPEND)) ||
                    527:            (VTOI(dvp)->i_flags & APPEND))
                    528:                error = EPERM;
                    529:        else {
1.12      dholland  530:                error = ulfs_dirremove(dvp, ulr,
                    531:                                      ip, ap->a_cnp->cn_flags, 0);
1.1       dholland  532:        }
                    533:        VN_KNOTE(vp, NOTE_DELETE);
                    534:        VN_KNOTE(dvp, NOTE_WRITE);
                    535:        if (dvp == vp)
                    536:                vrele(vp);
                    537:        else
                    538:                vput(vp);
                    539:        return (error);
                    540: }
                    541:
                    542: /*
1.4       dholland  543:  * ulfs_link: create hard link.
1.1       dholland  544:  */
                    545: int
1.4       dholland  546: ulfs_link(void *v)
1.1       dholland  547: {
1.21.6.2  skrll     548:        struct vop_link_v2_args /* {
1.1       dholland  549:                struct vnode *a_dvp;
                    550:                struct vnode *a_vp;
                    551:                struct componentname *a_cnp;
                    552:        } */ *ap = v;
                    553:        struct vnode *dvp = ap->a_dvp;
                    554:        struct vnode *vp = ap->a_vp;
                    555:        struct componentname *cnp = ap->a_cnp;
                    556:        struct inode *ip;
                    557:        int error;
1.4       dholland  558:        struct ulfs_lookup_results *ulr;
1.1       dholland  559:
1.21.6.6! skrll     560:        KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
1.1       dholland  561:        KASSERT(dvp != vp);
                    562:        KASSERT(vp->v_type != VDIR);
                    563:
                    564:        /* XXX should handle this material another way */
                    565:        ulr = &VTOI(dvp)->i_crap;
1.4       dholland  566:        ULFS_CHECK_CRAPCOUNTER(VTOI(dvp));
1.1       dholland  567:
                    568:        error = vn_lock(vp, LK_EXCLUSIVE);
                    569:        if (error) {
                    570:                VOP_ABORTOP(dvp, cnp);
                    571:                goto out2;
                    572:        }
1.21.6.6! skrll     573:        if (vp->v_mount != dvp->v_mount) {
        !           574:                error = ENOENT;
        !           575:                VOP_ABORTOP(dvp, cnp);
        !           576:                goto out2;
        !           577:        }
1.1       dholland  578:        ip = VTOI(vp);
                    579:        if ((nlink_t)ip->i_nlink >= LINK_MAX) {
                    580:                VOP_ABORTOP(dvp, cnp);
                    581:                error = EMLINK;
                    582:                goto out1;
                    583:        }
                    584:        if (ip->i_flags & (IMMUTABLE | APPEND)) {
                    585:                VOP_ABORTOP(dvp, cnp);
                    586:                error = EPERM;
                    587:                goto out1;
                    588:        }
                    589:        ip->i_nlink++;
                    590:        DIP_ASSIGN(ip, nlink, ip->i_nlink);
1.21.6.6! skrll     591:        ip->i_state |= IN_CHANGE;
1.17      dholland  592:        error = lfs_update(vp, NULL, NULL, UPDATE_DIROP);
1.1       dholland  593:        if (!error) {
1.21.6.3  skrll     594:                error = ulfs_direnter(dvp, ulr, vp,
                    595:                                      cnp, ip->i_number, LFS_IFTODT(ip->i_mode), NULL);
1.1       dholland  596:        }
                    597:        if (error) {
                    598:                ip->i_nlink--;
                    599:                DIP_ASSIGN(ip, nlink, ip->i_nlink);
1.21.6.6! skrll     600:                ip->i_state |= IN_CHANGE;
1.1       dholland  601:        }
                    602:  out1:
                    603:        VOP_UNLOCK(vp);
                    604:  out2:
                    605:        VN_KNOTE(vp, NOTE_LINK);
                    606:        VN_KNOTE(dvp, NOTE_WRITE);
                    607:        return (error);
                    608: }
                    609:
                    610: /*
                    611:  * whiteout vnode call
                    612:  */
                    613: int
1.4       dholland  614: ulfs_whiteout(void *v)
1.1       dholland  615: {
                    616:        struct vop_whiteout_args /* {
                    617:                struct vnode            *a_dvp;
                    618:                struct componentname    *a_cnp;
                    619:                int                     a_flags;
                    620:        } */ *ap = v;
                    621:        struct vnode            *dvp = ap->a_dvp;
                    622:        struct componentname    *cnp = ap->a_cnp;
                    623:        int                     error;
1.4       dholland  624:        struct ulfsmount        *ump = VFSTOULFS(dvp->v_mount);
1.18      dholland  625:        struct lfs *fs = ump->um_lfs;
1.4       dholland  626:        struct ulfs_lookup_results *ulr;
1.1       dholland  627:
1.21.6.6! skrll     628:        KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
        !           629:
1.1       dholland  630:        /* XXX should handle this material another way */
                    631:        ulr = &VTOI(dvp)->i_crap;
1.4       dholland  632:        ULFS_CHECK_CRAPCOUNTER(VTOI(dvp));
1.1       dholland  633:
                    634:        error = 0;
                    635:        switch (ap->a_flags) {
                    636:        case LOOKUP:
                    637:                /* 4.4 format directories support whiteout operations */
1.18      dholland  638:                if (fs->um_maxsymlinklen > 0)
1.1       dholland  639:                        return (0);
                    640:                return (EOPNOTSUPP);
                    641:
                    642:        case CREATE:
                    643:                /* create a new directory whiteout */
1.21.6.6! skrll     644:                KASSERTMSG((fs->um_maxsymlinklen > 0),
        !           645:                    "ulfs_whiteout: old format filesystem");
1.1       dholland  646:
1.21.6.3  skrll     647:                error = ulfs_direnter(dvp, ulr, NULL,
                    648:                                      cnp, ULFS_WINO, LFS_DT_WHT,  NULL);
1.1       dholland  649:                break;
                    650:
                    651:        case DELETE:
                    652:                /* remove an existing directory whiteout */
1.21.6.6! skrll     653:                KASSERTMSG((fs->um_maxsymlinklen > 0),
        !           654:                    "ulfs_whiteout: old format filesystem");
1.1       dholland  655:
                    656:                cnp->cn_flags &= ~DOWHITEOUT;
1.4       dholland  657:                error = ulfs_dirremove(dvp, ulr, NULL, cnp->cn_flags, 0);
1.1       dholland  658:                break;
                    659:        default:
1.4       dholland  660:                panic("ulfs_whiteout: unknown op");
1.1       dholland  661:                /* NOTREACHED */
                    662:        }
                    663:        return (error);
                    664: }
                    665:
                    666: int
1.4       dholland  667: ulfs_rmdir(void *v)
1.1       dholland  668: {
1.21.6.6! skrll     669:        struct vop_rmdir_v2_args /* {
1.1       dholland  670:                struct vnode            *a_dvp;
                    671:                struct vnode            *a_vp;
                    672:                struct componentname    *a_cnp;
                    673:        } */ *ap = v;
                    674:        struct vnode            *vp, *dvp;
                    675:        struct componentname    *cnp;
                    676:        struct inode            *ip, *dp;
                    677:        int                     error;
1.4       dholland  678:        struct ulfs_lookup_results *ulr;
1.1       dholland  679:
                    680:        dvp = ap->a_dvp;
1.21.6.6! skrll     681:        vp = ap->a_vp;
1.1       dholland  682:        cnp = ap->a_cnp;
1.21.6.6! skrll     683:
        !           684:        KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
        !           685:        KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
        !           686:
1.1       dholland  687:        dp = VTOI(dvp);
1.21.6.6! skrll     688:        ip = VTOI(vp);
1.1       dholland  689:
                    690:        /* XXX should handle this material another way */
                    691:        ulr = &dp->i_crap;
1.4       dholland  692:        ULFS_CHECK_CRAPCOUNTER(dp);
1.1       dholland  693:
                    694:        /*
                    695:         * No rmdir "." or of mounted directories please.
                    696:         */
                    697:        if (dp == ip || vp->v_mountedhere != NULL) {
                    698:                if (dp == ip)
1.21.6.6! skrll     699:                        vrele(vp);
1.1       dholland  700:                else
1.21.6.6! skrll     701:                        vput(vp);
1.1       dholland  702:                return (EINVAL);
                    703:        }
                    704:
                    705:        /*
                    706:         * Do not remove a directory that is in the process of being renamed.
                    707:         * Verify that the directory is empty (and valid). (Rmdir ".." won't
                    708:         * be valid since ".." will contain a reference to the current
                    709:         * directory and thus be non-empty.)
                    710:         */
                    711:        error = 0;
                    712:        if (ip->i_nlink != 2 ||
1.4       dholland  713:            !ulfs_dirempty(ip, dp->i_number, cnp->cn_cred)) {
1.1       dholland  714:                error = ENOTEMPTY;
                    715:                goto out;
                    716:        }
                    717:        if ((dp->i_flags & APPEND) ||
                    718:                (ip->i_flags & (IMMUTABLE | APPEND))) {
                    719:                error = EPERM;
                    720:                goto out;
                    721:        }
                    722:        /*
                    723:         * Delete reference to directory before purging
                    724:         * inode.  If we crash in between, the directory
                    725:         * will be reattached to lost+found,
                    726:         */
1.4       dholland  727:        error = ulfs_dirremove(dvp, ulr, ip, cnp->cn_flags, 1);
1.1       dholland  728:        if (error) {
                    729:                goto out;
                    730:        }
                    731:        VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
                    732:        cache_purge(dvp);
                    733:        /*
                    734:         * Truncate inode.  The only stuff left in the directory is "." and
                    735:         * "..".  The "." reference is inconsequential since we're quashing
                    736:         * it.
                    737:         */
                    738:        dp->i_nlink--;
                    739:        DIP_ASSIGN(dp, nlink, dp->i_nlink);
1.21.6.6! skrll     740:        dp->i_state |= IN_CHANGE;
1.1       dholland  741:        ip->i_nlink--;
                    742:        DIP_ASSIGN(ip, nlink, ip->i_nlink);
1.21.6.6! skrll     743:        ip->i_state |= IN_CHANGE;
1.17      dholland  744:        error = lfs_truncate(vp, (off_t)0, IO_SYNC, cnp->cn_cred);
1.1       dholland  745:        cache_purge(vp);
1.3       dholland  746: #ifdef LFS_DIRHASH
1.1       dholland  747:        if (ip->i_dirhash != NULL)
1.4       dholland  748:                ulfsdirhash_free(ip);
1.1       dholland  749: #endif
                    750:  out:
                    751:        VN_KNOTE(vp, NOTE_DELETE);
                    752:        vput(vp);
                    753:        return (error);
                    754: }
                    755:
                    756: /*
                    757:  * Vnode op for reading directories.
                    758:  *
                    759:  * This routine handles converting from the on-disk directory format
1.8       dholland  760:  * "struct lfs_direct" to the in-memory format "struct dirent" as well as
1.1       dholland  761:  * byte swapping the entries if necessary.
                    762:  */
                    763: int
1.4       dholland  764: ulfs_readdir(void *v)
1.1       dholland  765: {
                    766:        struct vop_readdir_args /* {
                    767:                struct vnode    *a_vp;
                    768:                struct uio      *a_uio;
                    769:                kauth_cred_t    a_cred;
                    770:                int             *a_eofflag;
                    771:                off_t           **a_cookies;
1.21.6.6! skrll     772:                int             *a_ncookies;
1.1       dholland  773:        } */ *ap = v;
1.21.6.6! skrll     774:
        !           775:        /* vnode and fs */
1.1       dholland  776:        struct vnode    *vp = ap->a_vp;
1.4       dholland  777:        struct ulfsmount *ump = VFSTOULFS(vp->v_mount);
1.18      dholland  778:        struct lfs *fs = ump->um_lfs;
1.21.6.6! skrll     779:        /* caller's buffer */
        !           780:        struct uio      *calleruio = ap->a_uio;
        !           781:        off_t           startoffset, endoffset;
        !           782:        size_t          callerbytes;
        !           783:        off_t           curoffset;
        !           784:        /* dirent production buffer */
        !           785:        char            *direntbuf;
        !           786:        size_t          direntbufmax;
        !           787:        struct dirent   *dirent, *stopdirent;
        !           788:        /* output cookies array */
        !           789:        off_t           *cookies;
        !           790:        size_t          numcookies, maxcookies;
        !           791:        /* disk buffer */
        !           792:        off_t           physstart, physend;
        !           793:        size_t          skipstart, dropend;
        !           794:        char            *rawbuf;
        !           795:        size_t          rawbufmax, rawbytes;
        !           796:        struct uio      rawuio;
        !           797:        struct iovec    rawiov;
        !           798:        LFS_DIRHEADER   *rawdp, *stoprawdp;
        !           799:        /* general */
        !           800:        int             error;
        !           801:
        !           802:        KASSERT(VOP_ISLOCKED(vp));
        !           803:
        !           804:        /* figure out where we want to read */
        !           805:        callerbytes = calleruio->uio_resid;
        !           806:        startoffset = calleruio->uio_offset;
        !           807:        endoffset = startoffset + callerbytes;
        !           808:
        !           809:        if (callerbytes < _DIRENT_MINSIZE(dirent)) {
        !           810:                /* no room for even one struct dirent */
        !           811:                return EINVAL;
        !           812:        }
1.1       dholland  813:
1.21.6.6! skrll     814:        /* round start and end down to block boundaries */
        !           815:        physstart = startoffset & ~(off_t)(fs->um_dirblksiz - 1);
        !           816:        physend = endoffset & ~(off_t)(fs->um_dirblksiz - 1);
        !           817:        skipstart = startoffset - physstart;
        !           818:        dropend = endoffset - physend;
        !           819:
        !           820:        if (callerbytes - dropend < LFS_DIRECTSIZ(fs, 0)) {
        !           821:                /* no room for even one dirheader + name */
1.1       dholland  822:                return EINVAL;
1.21.6.6! skrll     823:        }
1.1       dholland  824:
1.21.6.6! skrll     825:        /* how much to actually read */
        !           826:        rawbufmax = callerbytes + skipstart - dropend;
        !           827:
        !           828:        /* read it */
        !           829:        rawbuf = kmem_alloc(rawbufmax, KM_SLEEP);
        !           830:        rawiov.iov_base = rawbuf;
        !           831:        rawiov.iov_len = rawbufmax;
        !           832:        rawuio.uio_iov = &rawiov;
        !           833:        rawuio.uio_iovcnt = 1;
        !           834:        rawuio.uio_offset = physstart;
        !           835:        rawuio.uio_resid = rawbufmax;
        !           836:        UIO_SETUP_SYSSPACE(&rawuio);
        !           837:        rawuio.uio_rw = UIO_READ;
        !           838:        error = VOP_READ(vp, &rawuio, 0, ap->a_cred);
1.1       dholland  839:        if (error != 0) {
1.21.6.6! skrll     840:                kmem_free(rawbuf, rawbufmax);
1.1       dholland  841:                return error;
                    842:        }
1.21.6.6! skrll     843:        rawbytes = rawbufmax - rawuio.uio_resid;
1.1       dholland  844:
1.21.6.6! skrll     845:        /* the raw entries to iterate over */
        !           846:        rawdp = (LFS_DIRHEADER *)(void *)rawbuf;
        !           847:        stoprawdp = (LFS_DIRHEADER *)(void *)&rawbuf[rawbytes];
1.1       dholland  848:
1.21.6.6! skrll     849:        /* allocate space to produce dirents into */
        !           850:        direntbufmax = callerbytes;
        !           851:        direntbuf = kmem_alloc(direntbufmax, KM_SLEEP);
1.1       dholland  852:
1.21.6.6! skrll     853:        /* the dirents to iterate over */
        !           854:        dirent = (struct dirent *)(void *)direntbuf;
        !           855:        stopdirent = (struct dirent *)(void *)&direntbuf[direntbufmax];
1.1       dholland  856:
1.21.6.6! skrll     857:        /* the output "cookies" (seek positions of directory entries) */
1.1       dholland  858:        if (ap->a_cookies) {
1.21.6.6! skrll     859:                numcookies = 0;
        !           860:                maxcookies = rawbytes / LFS_DIRECTSIZ(fs, 1);
        !           861:                cookies = malloc(maxcookies * sizeof(*cookies),
1.1       dholland  862:                    M_TEMP, M_WAITOK);
                    863:        } else {
                    864:                /* XXX: GCC */
1.21.6.6! skrll     865:                maxcookies = 0;
        !           866:                cookies = NULL;
1.1       dholland  867:        }
                    868:
1.21.6.6! skrll     869:        /* now produce the dirents */
        !           870:        curoffset = calleruio->uio_offset;
        !           871:        while (rawdp < stoprawdp) {
        !           872:                if (skipstart > 0) {
        !           873:                        /* drain skipstart */
        !           874:                        if (lfs_dir_getreclen(fs, rawdp) <= skipstart) {
        !           875:                                skipstart -= lfs_dir_getreclen(fs, rawdp);
        !           876:                                rawdp = LFS_NEXTDIR(fs, rawdp);
1.1       dholland  877:                                continue;
                    878:                        }
1.21.6.6! skrll     879:                        /* caller's start position wasn't on an entry */
1.1       dholland  880:                        error = EINVAL;
                    881:                        goto out;
                    882:                }
1.21.6.6! skrll     883:                if (lfs_dir_getreclen(fs, rawdp) == 0) {
        !           884:                        struct dirent *save = dirent;
        !           885:                        dirent->d_reclen = _DIRENT_MINSIZE(dirent);
        !           886:                        dirent = _DIRENT_NEXT(dirent);
        !           887:                        save->d_reclen = 0;
        !           888:                        rawdp = stoprawdp;
1.1       dholland  889:                        break;
                    890:                }
1.21.6.6! skrll     891:
        !           892:                /* copy the header */
        !           893:                dirent->d_type = lfs_dir_gettype(fs, rawdp);
        !           894:                dirent->d_namlen = lfs_dir_getnamlen(fs, rawdp);
        !           895:                dirent->d_reclen = _DIRENT_RECLEN(dirent, dirent->d_namlen);
        !           896:
        !           897:                /* stop if there isn't room for the name AND another header */
        !           898:                if ((char *)(void *)dirent + dirent->d_reclen +
        !           899:                    _DIRENT_MINSIZE(dirent) > (char *)(void *)stopdirent)
1.1       dholland  900:                        break;
1.21.6.6! skrll     901:
        !           902:                /* copy the name (and inode (XXX: why after the test?)) */
        !           903:                dirent->d_fileno = lfs_dir_getino(fs, rawdp);
        !           904:                (void)memcpy(dirent->d_name, lfs_dir_nameptr(fs, rawdp),
        !           905:                             dirent->d_namlen);
        !           906:                memset(&dirent->d_name[dirent->d_namlen], 0,
        !           907:                    dirent->d_reclen - _DIRENT_NAMEOFF(dirent)
        !           908:                    - dirent->d_namlen);
        !           909:
        !           910:                /* onward */
        !           911:                curoffset += lfs_dir_getreclen(fs, rawdp);
1.1       dholland  912:                if (ap->a_cookies) {
1.21.6.6! skrll     913:                        KASSERT(numcookies < maxcookies);
        !           914:                        cookies[numcookies++] = curoffset;
1.1       dholland  915:                }
1.21.6.6! skrll     916:                dirent = _DIRENT_NEXT(dirent);
        !           917:                rawdp = LFS_NEXTDIR(fs, rawdp);
1.1       dholland  918:        }
                    919:
1.21.6.6! skrll     920:        /* transfer the dirents to the caller's buffer */
        !           921:        callerbytes = ((char *)(void *)dirent - direntbuf);
        !           922:        error = uiomove(direntbuf, callerbytes, calleruio);
        !           923:
1.1       dholland  924: out:
1.21.6.6! skrll     925:        calleruio->uio_offset = curoffset;
1.1       dholland  926:        if (ap->a_cookies) {
                    927:                if (error) {
1.21.6.6! skrll     928:                        free(cookies, M_TEMP);
        !           929:                        *ap->a_cookies = NULL;
        !           930:                        *ap->a_ncookies = 0;
1.1       dholland  931:                } else {
1.21.6.6! skrll     932:                        *ap->a_cookies = cookies;
        !           933:                        *ap->a_ncookies = numcookies;
1.1       dholland  934:                }
                    935:        }
1.21.6.6! skrll     936:        kmem_free(direntbuf, direntbufmax);
        !           937:        kmem_free(rawbuf, rawbufmax);
        !           938:        *ap->a_eofflag = VTOI(vp)->i_size <= calleruio->uio_offset;
1.1       dholland  939:        return error;
                    940: }
                    941:
                    942: /*
                    943:  * Return target name of a symbolic link
                    944:  */
                    945: int
1.4       dholland  946: ulfs_readlink(void *v)
1.1       dholland  947: {
                    948:        struct vop_readlink_args /* {
                    949:                struct vnode    *a_vp;
                    950:                struct uio      *a_uio;
                    951:                kauth_cred_t    a_cred;
                    952:        } */ *ap = v;
                    953:        struct vnode    *vp = ap->a_vp;
                    954:        struct inode    *ip = VTOI(vp);
1.4       dholland  955:        struct ulfsmount *ump = VFSTOULFS(vp->v_mount);
1.18      dholland  956:        struct lfs *fs = ump->um_lfs;
1.1       dholland  957:        int             isize;
                    958:
1.21.6.6! skrll     959:        KASSERT(VOP_ISLOCKED(vp));
        !           960:
1.21.6.5  skrll     961:        /*
                    962:         * The test against um_maxsymlinklen is off by one; it should
                    963:         * theoretically be <=, not <. However, it cannot be changed
                    964:         * as that would break compatibility with existing fs images.
                    965:         */
                    966:
1.1       dholland  967:        isize = ip->i_size;
1.18      dholland  968:        if (isize < fs->um_maxsymlinklen ||
                    969:            (fs->um_maxsymlinklen == 0 && DIP(ip, blocks) == 0)) {
1.1       dholland  970:                uiomove((char *)SHORTLINK(ip), isize, ap->a_uio);
                    971:                return (0);
                    972:        }
1.21.6.1  skrll     973:        return (lfs_bufrd(vp, ap->a_uio, 0, ap->a_cred));
1.1       dholland  974: }
                    975:
                    976: /*
                    977:  * Print out the contents of an inode.
                    978:  */
                    979: int
1.4       dholland  980: ulfs_print(void *v)
1.1       dholland  981: {
                    982:        struct vop_print_args /* {
                    983:                struct vnode    *a_vp;
                    984:        } */ *ap = v;
                    985:        struct vnode    *vp;
                    986:        struct inode    *ip;
                    987:
                    988:        vp = ap->a_vp;
                    989:        ip = VTOI(vp);
1.4       dholland  990:        printf("tag VT_ULFS, ino %llu, on dev %llu, %llu",
1.1       dholland  991:            (unsigned long long)ip->i_number,
                    992:            (unsigned long long)major(ip->i_dev),
                    993:            (unsigned long long)minor(ip->i_dev));
                    994:        printf(" flags 0x%x, nlink %d\n",
1.21.6.6! skrll     995:            ip->i_state, ip->i_nlink);
1.1       dholland  996:        printf("\tmode 0%o, owner %d, group %d, size %qd",
                    997:            ip->i_mode, ip->i_uid, ip->i_gid,
                    998:            (long long)ip->i_size);
                    999:        if (vp->v_type == VFIFO)
                   1000:                VOCALL(fifo_vnodeop_p, VOFFSET(vop_print), v);
                   1001:        printf("\n");
                   1002:        return (0);
                   1003: }
                   1004:
                   1005: /*
                   1006:  * Read wrapper for special devices.
                   1007:  */
                   1008: int
1.4       dholland 1009: ulfsspec_read(void *v)
1.1       dholland 1010: {
                   1011:        struct vop_read_args /* {
                   1012:                struct vnode    *a_vp;
                   1013:                struct uio      *a_uio;
                   1014:                int             a_ioflag;
                   1015:                kauth_cred_t    a_cred;
                   1016:        } */ *ap = v;
                   1017:
1.21.6.6! skrll    1018:        KASSERT(VOP_ISLOCKED(ap->a_vp));
        !          1019:
1.1       dholland 1020:        /*
                   1021:         * Set access flag.
                   1022:         */
                   1023:        if ((ap->a_vp->v_mount->mnt_flag & MNT_NODEVMTIME) == 0)
1.21.6.6! skrll    1024:                VTOI(ap->a_vp)->i_state |= IN_ACCESS;
1.1       dholland 1025:        return (VOCALL (spec_vnodeop_p, VOFFSET(vop_read), ap));
                   1026: }
                   1027:
                   1028: /*
                   1029:  * Write wrapper for special devices.
                   1030:  */
                   1031: int
1.4       dholland 1032: ulfsspec_write(void *v)
1.1       dholland 1033: {
                   1034:        struct vop_write_args /* {
                   1035:                struct vnode    *a_vp;
                   1036:                struct uio      *a_uio;
                   1037:                int             a_ioflag;
                   1038:                kauth_cred_t    a_cred;
                   1039:        } */ *ap = v;
                   1040:
1.21.6.6! skrll    1041:        KASSERT(VOP_ISLOCKED(ap->a_vp) == LK_EXCLUSIVE);
        !          1042:
1.1       dholland 1043:        /*
                   1044:         * Set update and change flags.
                   1045:         */
                   1046:        if ((ap->a_vp->v_mount->mnt_flag & MNT_NODEVMTIME) == 0)
1.21.6.6! skrll    1047:                VTOI(ap->a_vp)->i_state |= IN_MODIFY;
1.1       dholland 1048:        return (VOCALL (spec_vnodeop_p, VOFFSET(vop_write), ap));
                   1049: }
                   1050:
                   1051: /*
                   1052:  * Read wrapper for fifo's
                   1053:  */
                   1054: int
1.4       dholland 1055: ulfsfifo_read(void *v)
1.1       dholland 1056: {
                   1057:        struct vop_read_args /* {
                   1058:                struct vnode    *a_vp;
                   1059:                struct uio      *a_uio;
                   1060:                int             a_ioflag;
                   1061:                kauth_cred_t    a_cred;
                   1062:        } */ *ap = v;
                   1063:
1.21.6.6! skrll    1064:        KASSERT(VOP_ISLOCKED(ap->a_vp));
        !          1065:
1.1       dholland 1066:        /*
                   1067:         * Set access flag.
                   1068:         */
1.21.6.6! skrll    1069:        VTOI(ap->a_vp)->i_state |= IN_ACCESS;
1.1       dholland 1070:        return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_read), ap));
                   1071: }
                   1072:
                   1073: /*
                   1074:  * Write wrapper for fifo's.
                   1075:  */
                   1076: int
1.4       dholland 1077: ulfsfifo_write(void *v)
1.1       dholland 1078: {
                   1079:        struct vop_write_args /* {
                   1080:                struct vnode    *a_vp;
                   1081:                struct uio      *a_uio;
                   1082:                int             a_ioflag;
                   1083:                kauth_cred_t    a_cred;
                   1084:        } */ *ap = v;
                   1085:
1.21.6.6! skrll    1086:        KASSERT(VOP_ISLOCKED(ap->a_vp) == LK_EXCLUSIVE);
        !          1087:
1.1       dholland 1088:        /*
                   1089:         * Set update and change flags.
                   1090:         */
1.21.6.6! skrll    1091:        VTOI(ap->a_vp)->i_state |= IN_MODIFY;
1.1       dholland 1092:        return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_write), ap));
                   1093: }
                   1094:
                   1095: /*
1.4       dholland 1096:  * Return POSIX pathconf information applicable to ulfs filesystems.
1.1       dholland 1097:  */
                   1098: int
1.4       dholland 1099: ulfs_pathconf(void *v)
1.1       dholland 1100: {
                   1101:        struct vop_pathconf_args /* {
                   1102:                struct vnode    *a_vp;
                   1103:                int             a_name;
                   1104:                register_t      *a_retval;
                   1105:        } */ *ap = v;
                   1106:
                   1107:        switch (ap->a_name) {
                   1108:        case _PC_LINK_MAX:
                   1109:                *ap->a_retval = LINK_MAX;
                   1110:                return (0);
                   1111:        case _PC_NAME_MAX:
1.6       dholland 1112:                *ap->a_retval = LFS_MAXNAMLEN;
1.1       dholland 1113:                return (0);
                   1114:        case _PC_PATH_MAX:
                   1115:                *ap->a_retval = PATH_MAX;
                   1116:                return (0);
                   1117:        case _PC_PIPE_BUF:
                   1118:                *ap->a_retval = PIPE_BUF;
                   1119:                return (0);
                   1120:        case _PC_CHOWN_RESTRICTED:
                   1121:                *ap->a_retval = 1;
                   1122:                return (0);
                   1123:        case _PC_NO_TRUNC:
                   1124:                *ap->a_retval = 1;
                   1125:                return (0);
                   1126:        case _PC_SYNC_IO:
                   1127:                *ap->a_retval = 1;
                   1128:                return (0);
                   1129:        case _PC_FILESIZEBITS:
                   1130:                *ap->a_retval = 42;
                   1131:                return (0);
                   1132:        case _PC_SYMLINK_MAX:
                   1133:                *ap->a_retval = MAXPATHLEN;
                   1134:                return (0);
                   1135:        case _PC_2_SYMLINKS:
                   1136:                *ap->a_retval = 1;
                   1137:                return (0);
                   1138:        default:
                   1139:                return (EINVAL);
                   1140:        }
                   1141:        /* NOTREACHED */
                   1142: }
                   1143:
                   1144: /*
                   1145:  * Advisory record locking support
                   1146:  */
                   1147: int
1.4       dholland 1148: ulfs_advlock(void *v)
1.1       dholland 1149: {
                   1150:        struct vop_advlock_args /* {
                   1151:                struct vnode    *a_vp;
                   1152:                void *          a_id;
                   1153:                int             a_op;
                   1154:                struct flock    *a_fl;
                   1155:                int             a_flags;
                   1156:        } */ *ap = v;
                   1157:        struct inode *ip;
                   1158:
                   1159:        ip = VTOI(ap->a_vp);
                   1160:        return lf_advlock(ap, &ip->i_lockf, ip->i_size);
                   1161: }
                   1162:
                   1163: /*
                   1164:  * Initialize the vnode associated with a new inode, handle aliased
                   1165:  * vnodes.
                   1166:  */
                   1167: void
1.4       dholland 1168: ulfs_vinit(struct mount *mntp, int (**specops)(void *), int (**fifoops)(void *),
1.1       dholland 1169:        struct vnode **vpp)
                   1170: {
                   1171:        struct timeval  tv;
                   1172:        struct inode    *ip;
                   1173:        struct vnode    *vp;
                   1174:        dev_t           rdev;
1.4       dholland 1175:        struct ulfsmount *ump;
1.1       dholland 1176:
                   1177:        vp = *vpp;
                   1178:        ip = VTOI(vp);
                   1179:        switch(vp->v_type = IFTOVT(ip->i_mode)) {
                   1180:        case VCHR:
                   1181:        case VBLK:
                   1182:                vp->v_op = specops;
                   1183:                ump = ip->i_ump;
1.21.6.3  skrll    1184:                // XXX clean this up
1.4       dholland 1185:                if (ump->um_fstype == ULFS1)
1.21.6.3  skrll    1186:                        rdev = (dev_t)ulfs_rw32(ip->i_din->u_32.di_rdev,
1.18      dholland 1187:                            ULFS_MPNEEDSWAP(ump->um_lfs));
1.1       dholland 1188:                else
1.21.6.3  skrll    1189:                        rdev = (dev_t)ulfs_rw64(ip->i_din->u_64.di_rdev,
1.18      dholland 1190:                            ULFS_MPNEEDSWAP(ump->um_lfs));
1.1       dholland 1191:                spec_node_init(vp, rdev);
                   1192:                break;
                   1193:        case VFIFO:
                   1194:                vp->v_op = fifoops;
                   1195:                break;
                   1196:        case VNON:
                   1197:        case VBAD:
                   1198:        case VSOCK:
                   1199:        case VLNK:
                   1200:        case VDIR:
                   1201:        case VREG:
                   1202:                break;
                   1203:        }
1.4       dholland 1204:        if (ip->i_number == ULFS_ROOTINO)
1.1       dholland 1205:                 vp->v_vflag |= VV_ROOT;
                   1206:        /*
                   1207:         * Initialize modrev times
                   1208:         */
                   1209:        getmicrouptime(&tv);
                   1210:        ip->i_modrev = (uint64_t)(uint)tv.tv_sec << 32
                   1211:                        | tv.tv_usec * 4294u;
                   1212:        *vpp = vp;
                   1213: }
                   1214:
                   1215: /*
                   1216:  * Allocate len bytes at offset off.
                   1217:  */
                   1218: int
1.4       dholland 1219: ulfs_gop_alloc(struct vnode *vp, off_t off, off_t len, int flags,
1.1       dholland 1220:     kauth_cred_t cred)
                   1221: {
                   1222:         struct inode *ip = VTOI(vp);
                   1223:         int error, delta, bshift, bsize;
1.4       dholland 1224:         UVMHIST_FUNC("ulfs_gop_alloc"); UVMHIST_CALLED(ubchist);
1.1       dholland 1225:
1.21.6.6! skrll    1226:        KASSERT(genfs_node_wrlocked(vp));
        !          1227:
1.1       dholland 1228:         error = 0;
                   1229:         bshift = vp->v_mount->mnt_fs_bshift;
                   1230:         bsize = 1 << bshift;
                   1231:
                   1232:         delta = off & (bsize - 1);
                   1233:         off -= delta;
                   1234:         len += delta;
                   1235:
                   1236:         while (len > 0) {
                   1237:                 bsize = MIN(bsize, len);
                   1238:
1.17      dholland 1239:                 error = lfs_balloc(vp, off, bsize, cred, flags, NULL);
1.1       dholland 1240:                 if (error) {
                   1241:                         goto out;
                   1242:                 }
                   1243:
                   1244:                 /*
1.17      dholland 1245:                  * increase file size now, lfs_balloc() requires that
1.1       dholland 1246:                  * EOF be up-to-date before each call.
                   1247:                  */
                   1248:
                   1249:                 if (ip->i_size < off + bsize) {
                   1250:                         UVMHIST_LOG(ubchist, "vp %p old 0x%x new 0x%x",
                   1251:                             vp, ip->i_size, off + bsize, 0);
                   1252:                         ip->i_size = off + bsize;
                   1253:                        DIP_ASSIGN(ip, size, ip->i_size);
                   1254:                 }
                   1255:
                   1256:                 off += bsize;
                   1257:                 len -= bsize;
                   1258:         }
                   1259:
                   1260: out:
                   1261:        return error;
                   1262: }
                   1263:
                   1264: void
1.4       dholland 1265: ulfs_gop_markupdate(struct vnode *vp, int flags)
1.1       dholland 1266: {
                   1267:        u_int32_t mask = 0;
                   1268:
                   1269:        if ((flags & GOP_UPDATE_ACCESSED) != 0) {
                   1270:                mask = IN_ACCESS;
                   1271:        }
                   1272:        if ((flags & GOP_UPDATE_MODIFIED) != 0) {
                   1273:                if (vp->v_type == VREG) {
                   1274:                        mask |= IN_CHANGE | IN_UPDATE;
                   1275:                } else {
                   1276:                        mask |= IN_MODIFY;
                   1277:                }
                   1278:        }
                   1279:        if (mask) {
                   1280:                struct inode *ip = VTOI(vp);
                   1281:
1.21.6.6! skrll    1282:                ip->i_state |= mask;
1.1       dholland 1283:        }
                   1284: }
1.21.6.1  skrll    1285:
                   1286: int
                   1287: ulfs_bufio(enum uio_rw rw, struct vnode *vp, void *buf, size_t len, off_t off,
                   1288:     int ioflg, kauth_cred_t cred, size_t *aresid, struct lwp *l)
                   1289: {
                   1290:        struct iovec iov;
                   1291:        struct uio uio;
                   1292:        int error;
                   1293:
                   1294:        KASSERT(ISSET(ioflg, IO_NODELOCKED));
                   1295:        KASSERT(VOP_ISLOCKED(vp));
                   1296:        KASSERT(rw != UIO_WRITE || VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
                   1297:
                   1298:        iov.iov_base = buf;
                   1299:        iov.iov_len = len;
                   1300:        uio.uio_iov = &iov;
                   1301:        uio.uio_iovcnt = 1;
                   1302:        uio.uio_resid = len;
                   1303:        uio.uio_offset = off;
                   1304:        uio.uio_rw = rw;
                   1305:        UIO_SETUP_SYSSPACE(&uio);
                   1306:
                   1307:        switch (rw) {
                   1308:        case UIO_READ:
                   1309:                error = lfs_bufrd(vp, &uio, ioflg, cred);
                   1310:                break;
                   1311:        case UIO_WRITE:
                   1312:                error = lfs_bufwr(vp, &uio, ioflg, cred);
                   1313:                break;
                   1314:        default:
                   1315:                panic("invalid uio rw: %d", (int)rw);
                   1316:        }
                   1317:
                   1318:        if (aresid)
                   1319:                *aresid = uio.uio_resid;
                   1320:        else if (uio.uio_resid && error == 0)
                   1321:                error = EIO;
                   1322:
                   1323:        KASSERT(VOP_ISLOCKED(vp));
                   1324:        KASSERT(rw != UIO_WRITE || VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
                   1325:        return error;
                   1326: }

CVSweb <webmaster@jp.NetBSD.org>