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

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

CVSweb <webmaster@jp.NetBSD.org>