[BACK]Return to tmpfs_vnops.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / fs / tmpfs

Annotation of src/sys/fs/tmpfs/tmpfs_vnops.c, Revision 1.39

1.39    ! jmmv        1: /*     $NetBSD: tmpfs_vnops.c,v 1.38 2007/07/09 21:10:50 ad Exp $      */
1.1       jmmv        2:
                      3: /*
1.21      jmmv        4:  * Copyright (c) 2005, 2006 The NetBSD Foundation, Inc.
1.1       jmmv        5:  * All rights reserved.
                      6:  *
                      7:  * This code is derived from software contributed to The NetBSD Foundation
1.12      jmmv        8:  * by Julio M. Merino Vidal, developed as part of Google's Summer of Code
                      9:  * 2005 program.
1.1       jmmv       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:  * 3. All advertising materials mentioning features or use of this software
                     20:  *    must display the following acknowledgement:
                     21:  *        This product includes software developed by the NetBSD
                     22:  *        Foundation, Inc. and its contributors.
                     23:  * 4. Neither the name of The NetBSD Foundation nor the names of its
                     24:  *    contributors may be used to endorse or promote products derived
                     25:  *    from this software without specific prior written permission.
                     26:  *
                     27:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     28:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     29:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     30:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     31:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     32:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     33:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     34:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     35:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     36:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     37:  * POSSIBILITY OF SUCH DAMAGE.
                     38:  */
                     39:
                     40: /*
                     41:  * tmpfs vnode interface.
                     42:  */
                     43:
                     44: #include <sys/cdefs.h>
1.39    ! jmmv       45: __KERNEL_RCSID(0, "$NetBSD: tmpfs_vnops.c,v 1.38 2007/07/09 21:10:50 ad Exp $");
1.1       jmmv       46:
                     47: #include <sys/param.h>
                     48: #include <sys/dirent.h>
                     49: #include <sys/fcntl.h>
                     50: #include <sys/event.h>
                     51: #include <sys/malloc.h>
                     52: #include <sys/namei.h>
                     53: #include <sys/proc.h>
                     54: #include <sys/stat.h>
                     55: #include <sys/uio.h>
                     56: #include <sys/unistd.h>
                     57: #include <sys/vnode.h>
1.15      jmmv       58: #include <sys/lockf.h>
1.24      christos   59: #include <sys/kauth.h>
1.1       jmmv       60:
                     61: #include <uvm/uvm.h>
                     62:
                     63: #include <miscfs/fifofs/fifo.h>
                     64: #include <fs/tmpfs/tmpfs_vnops.h>
                     65: #include <fs/tmpfs/tmpfs.h>
                     66:
                     67: /* --------------------------------------------------------------------- */
                     68:
                     69: /*
1.2       jmmv       70:  * vnode operations vector used for files stored in a tmpfs file system.
1.1       jmmv       71:  */
                     72: int (**tmpfs_vnodeop_p)(void *);
                     73: const struct vnodeopv_entry_desc tmpfs_vnodeop_entries[] = {
                     74:        { &vop_default_desc,            vn_default_error },
                     75:        { &vop_lookup_desc,             tmpfs_lookup },
                     76:        { &vop_create_desc,             tmpfs_create },
                     77:        { &vop_mknod_desc,              tmpfs_mknod },
                     78:        { &vop_open_desc,               tmpfs_open },
                     79:        { &vop_close_desc,              tmpfs_close },
                     80:        { &vop_access_desc,             tmpfs_access },
                     81:        { &vop_getattr_desc,            tmpfs_getattr },
                     82:        { &vop_setattr_desc,            tmpfs_setattr },
                     83:        { &vop_read_desc,               tmpfs_read },
                     84:        { &vop_write_desc,              tmpfs_write },
                     85:        { &vop_ioctl_desc,              tmpfs_ioctl },
                     86:        { &vop_fcntl_desc,              tmpfs_fcntl },
                     87:        { &vop_poll_desc,               tmpfs_poll },
                     88:        { &vop_kqfilter_desc,           tmpfs_kqfilter },
                     89:        { &vop_revoke_desc,             tmpfs_revoke },
                     90:        { &vop_mmap_desc,               tmpfs_mmap },
                     91:        { &vop_fsync_desc,              tmpfs_fsync },
                     92:        { &vop_seek_desc,               tmpfs_seek },
                     93:        { &vop_remove_desc,             tmpfs_remove },
                     94:        { &vop_link_desc,               tmpfs_link },
                     95:        { &vop_rename_desc,             tmpfs_rename },
                     96:        { &vop_mkdir_desc,              tmpfs_mkdir },
                     97:        { &vop_rmdir_desc,              tmpfs_rmdir },
                     98:        { &vop_symlink_desc,            tmpfs_symlink },
                     99:        { &vop_readdir_desc,            tmpfs_readdir },
                    100:        { &vop_readlink_desc,           tmpfs_readlink },
                    101:        { &vop_abortop_desc,            tmpfs_abortop },
                    102:        { &vop_inactive_desc,           tmpfs_inactive },
                    103:        { &vop_reclaim_desc,            tmpfs_reclaim },
                    104:        { &vop_lock_desc,               tmpfs_lock },
                    105:        { &vop_unlock_desc,             tmpfs_unlock },
                    106:        { &vop_bmap_desc,               tmpfs_bmap },
                    107:        { &vop_strategy_desc,           tmpfs_strategy },
                    108:        { &vop_print_desc,              tmpfs_print },
                    109:        { &vop_pathconf_desc,           tmpfs_pathconf },
                    110:        { &vop_islocked_desc,           tmpfs_islocked },
                    111:        { &vop_advlock_desc,            tmpfs_advlock },
                    112:        { &vop_lease_desc,              tmpfs_lease },
                    113:        { &vop_bwrite_desc,             tmpfs_bwrite },
                    114:        { &vop_getpages_desc,           tmpfs_getpages },
                    115:        { &vop_putpages_desc,           tmpfs_putpages },
                    116:        { NULL, NULL }
                    117: };
                    118: const struct vnodeopv_desc tmpfs_vnodeop_opv_desc =
                    119:        { &tmpfs_vnodeop_p, tmpfs_vnodeop_entries };
                    120:
                    121: /* --------------------------------------------------------------------- */
                    122:
                    123: int
                    124: tmpfs_lookup(void *v)
                    125: {
                    126:        struct vnode *dvp = ((struct vop_lookup_args *)v)->a_dvp;
                    127:        struct vnode **vpp = ((struct vop_lookup_args *)v)->a_vpp;
                    128:        struct componentname *cnp = ((struct vop_lookup_args *)v)->a_cnp;
                    129:
                    130:        int error;
                    131:        struct tmpfs_dirent *de;
                    132:        struct tmpfs_node *dnode;
                    133:
                    134:        KASSERT(VOP_ISLOCKED(dvp));
                    135:
                    136:        dnode = VP_TO_TMPFS_DIR(dvp);
                    137:        *vpp = NULL;
                    138:
                    139:        /* Check accessibility of requested node as a first step. */
1.19      christos  140:        error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, cnp->cn_lwp);
1.1       jmmv      141:        if (error != 0)
                    142:                goto out;
                    143:
1.2       jmmv      144:        /* If requesting the last path component on a read-only file system
1.1       jmmv      145:         * with a write operation, deny it. */
                    146:        if ((cnp->cn_flags & ISLASTCN) &&
                    147:            (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
                    148:            (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
                    149:                error = EROFS;
                    150:                goto out;
                    151:        }
                    152:
                    153:        /* Avoid doing a linear scan of the directory if the requested
                    154:         * directory/name couple is already in the cache. */
                    155:        error = cache_lookup(dvp, vpp, cnp);
                    156:        if (error >= 0)
                    157:                goto out;
                    158:
                    159:        /* We cannot be requesting the parent directory of the root node. */
                    160:        KASSERT(IMPLIES(dnode->tn_type == VDIR &&
1.21      jmmv      161:            dnode->tn_spec.tn_dir.tn_parent == dnode,
                    162:            !(cnp->cn_flags & ISDOTDOT)));
1.1       jmmv      163:
                    164:        if (cnp->cn_flags & ISDOTDOT) {
                    165:                VOP_UNLOCK(dvp, 0);
                    166:
                    167:                /* Allocate a new vnode on the matching entry. */
1.21      jmmv      168:                error = tmpfs_alloc_vp(dvp->v_mount,
                    169:                    dnode->tn_spec.tn_dir.tn_parent, vpp);
1.1       jmmv      170:
1.33      chs       171:                vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
1.21      jmmv      172:                dnode->tn_spec.tn_dir.tn_parent->tn_lookup_dirent = NULL;
1.1       jmmv      173:        } else if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {
                    174:                VREF(dvp);
                    175:                *vpp = dvp;
                    176:                dnode->tn_lookup_dirent = NULL;
                    177:                error = 0;
                    178:        } else {
                    179:                de = tmpfs_dir_lookup(dnode, cnp);
                    180:                if (de == NULL) {
                    181:                        /* The entry was not found in the directory.
                    182:                         * This is OK iff we are creating or renaming an
                    183:                         * entry and are working on the last component of
                    184:                         * the path name. */
                    185:                        if ((cnp->cn_flags & ISLASTCN) &&
                    186:                            (cnp->cn_nameiop == CREATE || \
                    187:                            cnp->cn_nameiop == RENAME)) {
                    188:                                error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred,
1.19      christos  189:                                    cnp->cn_lwp);
1.1       jmmv      190:                                if (error != 0)
                    191:                                        goto out;
                    192:
                    193:                                /* Keep the component name in the buffer for
                    194:                                 * future uses. */
                    195:                                cnp->cn_flags |= SAVENAME;
                    196:
                    197:                                error = EJUSTRETURN;
                    198:                        } else
                    199:                                error = ENOENT;
                    200:                } else {
                    201:                        struct tmpfs_node *tnode;
                    202:
                    203:                        /* The entry was found, so get its associated
                    204:                         * tmpfs_node. */
                    205:                        tnode = de->td_node;
                    206:
                    207:                        /* If we are not at the last path component and
1.16      jmmv      208:                         * found a non-directory or non-link entry (which
                    209:                         * may itself be pointing to a directory), raise
                    210:                         * an error. */
                    211:                        if ((tnode->tn_type != VDIR &&
                    212:                            tnode->tn_type != VLNK) &&
1.1       jmmv      213:                            !(cnp->cn_flags & ISLASTCN)) {
                    214:                                error = ENOTDIR;
                    215:                                goto out;
                    216:                        }
                    217:
                    218:                        /* If we are deleting or renaming the entry, keep
                    219:                         * track of its tmpfs_dirent so that it can be
                    220:                         * easily deleted later. */
                    221:                        if ((cnp->cn_flags & ISLASTCN) &&
                    222:                            (cnp->cn_nameiop == DELETE ||
                    223:                            cnp->cn_nameiop == RENAME)) {
1.22      christos  224:                                if ((dnode->tn_mode & S_ISTXT) != 0 &&
1.35      elad      225:                                    kauth_authorize_generic(cnp->cn_cred,
                    226:                                     KAUTH_GENERIC_ISSUSER, NULL) != 0 &&
1.23      elad      227:                                    kauth_cred_geteuid(cnp->cn_cred) != dnode->tn_uid &&
                    228:                                    kauth_cred_geteuid(cnp->cn_cred) != tnode->tn_uid)
1.22      christos  229:                                        return EPERM;
1.1       jmmv      230:                                error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred,
1.19      christos  231:                                    cnp->cn_lwp);
1.1       jmmv      232:                                if (error != 0)
                    233:                                        goto out;
                    234:                                tnode->tn_lookup_dirent = de;
                    235:                        }
                    236:
                    237:                        /* Allocate a new vnode on the matching entry. */
                    238:                        error = tmpfs_alloc_vp(dvp->v_mount, tnode, vpp);
                    239:                }
                    240:        }
                    241:
                    242:        /* Store the result of this lookup in the cache.  Avoid this if the
                    243:         * request was for creation, as it does not improve timings on
                    244:         * emprical tests. */
                    245:        if ((cnp->cn_flags & MAKEENTRY) && cnp->cn_nameiop != CREATE)
                    246:                cache_enter(dvp, *vpp, cnp);
                    247:
                    248: out:
                    249:        /* If there were no errors, *vpp cannot be null and it must be
                    250:         * locked. */
                    251:        KASSERT(IFF(error == 0, *vpp != NULL && VOP_ISLOCKED(*vpp)));
                    252:
1.33      chs       253:        /* dvp must always be locked. */
                    254:        KASSERT(VOP_ISLOCKED(dvp));
1.1       jmmv      255:
                    256:        return error;
                    257: }
                    258:
                    259: /* --------------------------------------------------------------------- */
                    260:
                    261: int
                    262: tmpfs_create(void *v)
                    263: {
                    264:        struct vnode *dvp = ((struct vop_create_args *)v)->a_dvp;
                    265:        struct vnode **vpp = ((struct vop_create_args *)v)->a_vpp;
                    266:        struct componentname *cnp = ((struct vop_create_args *)v)->a_cnp;
                    267:        struct vattr *vap = ((struct vop_create_args *)v)->a_vap;
                    268:
                    269:        KASSERT(vap->va_type == VREG || vap->va_type == VSOCK);
                    270:
                    271:        return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL);
                    272: }
                    273: /* --------------------------------------------------------------------- */
                    274:
                    275: int
                    276: tmpfs_mknod(void *v)
                    277: {
                    278:        struct vnode *dvp = ((struct vop_mknod_args *)v)->a_dvp;
                    279:        struct vnode **vpp = ((struct vop_mknod_args *)v)->a_vpp;
                    280:        struct componentname *cnp = ((struct vop_mknod_args *)v)->a_cnp;
                    281:        struct vattr *vap = ((struct vop_mknod_args *)v)->a_vap;
                    282:
                    283:        if (vap->va_type != VBLK && vap->va_type != VCHR &&
                    284:            vap->va_type != VFIFO)
                    285:                return EINVAL;
                    286:
                    287:        return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL);
                    288: }
                    289:
                    290: /* --------------------------------------------------------------------- */
                    291:
                    292: int
                    293: tmpfs_open(void *v)
                    294: {
                    295:        struct vnode *vp = ((struct vop_open_args *)v)->a_vp;
                    296:        int mode = ((struct vop_open_args *)v)->a_mode;
                    297:
                    298:        int error;
                    299:        struct tmpfs_node *node;
                    300:
                    301:        KASSERT(VOP_ISLOCKED(vp));
                    302:
                    303:        node = VP_TO_TMPFS_NODE(vp);
                    304:
1.32      jmmv      305:        /* The file is still active but all its names have been removed
                    306:         * (e.g. by a "rmdir $(pwd)").  It cannot be opened any more as
                    307:         * it is about to die. */
                    308:        if (node->tn_links < 1) {
                    309:                error = ENOENT;
                    310:                goto out;
                    311:        }
                    312:
1.1       jmmv      313:        /* If the file is marked append-only, deny write requests. */
                    314:        if (node->tn_flags & APPEND && (mode & (FWRITE | O_APPEND)) == FWRITE)
                    315:                error = EPERM;
                    316:        else
                    317:                error = 0;
                    318:
1.32      jmmv      319: out:
1.1       jmmv      320:        KASSERT(VOP_ISLOCKED(vp));
                    321:
                    322:        return error;
                    323: }
                    324:
                    325: /* --------------------------------------------------------------------- */
                    326:
                    327: int
                    328: tmpfs_close(void *v)
                    329: {
                    330:        struct vnode *vp = ((struct vop_close_args *)v)->a_vp;
                    331:
                    332:        struct tmpfs_node *node;
                    333:
                    334:        KASSERT(VOP_ISLOCKED(vp));
                    335:
                    336:        node = VP_TO_TMPFS_NODE(vp);
                    337:
                    338:        if (node->tn_links > 0) {
                    339:                /* Update node times.  No need to do it if the node has
                    340:                 * been deleted, because it will vanish after we return. */
1.17      yamt      341:                tmpfs_update(vp, NULL, NULL, UPDATE_CLOSE);
                    342:        }
1.1       jmmv      343:
1.17      yamt      344:        return 0;
1.1       jmmv      345: }
                    346:
                    347: /* --------------------------------------------------------------------- */
                    348:
                    349: int
                    350: tmpfs_access(void *v)
                    351: {
                    352:        struct vnode *vp = ((struct vop_access_args *)v)->a_vp;
                    353:        int mode = ((struct vop_access_args *)v)->a_mode;
1.23      elad      354:        kauth_cred_t cred = ((struct vop_access_args *)v)->a_cred;
1.1       jmmv      355:
                    356:        int error;
                    357:        struct tmpfs_node *node;
                    358:
                    359:        KASSERT(VOP_ISLOCKED(vp));
                    360:
                    361:        node = VP_TO_TMPFS_NODE(vp);
                    362:
                    363:        switch (vp->v_type) {
                    364:        case VDIR:
                    365:                /* FALLTHROUGH */
                    366:        case VLNK:
                    367:                /* FALLTHROUGH */
                    368:        case VREG:
                    369:                if (mode & VWRITE && vp->v_mount->mnt_flag & MNT_RDONLY) {
                    370:                        error = EROFS;
                    371:                        goto out;
                    372:                }
                    373:                break;
                    374:
                    375:        case VBLK:
                    376:                /* FALLTHROUGH */
                    377:        case VCHR:
                    378:                /* FALLTHROUGH */
                    379:        case VSOCK:
                    380:                /* FALLTHROUGH */
                    381:        case VFIFO:
                    382:                break;
                    383:
                    384:        default:
                    385:                error = EINVAL;
                    386:                goto out;
                    387:        }
                    388:
                    389:        if (mode & VWRITE && node->tn_flags & IMMUTABLE) {
                    390:                error = EPERM;
                    391:                goto out;
                    392:        }
                    393:
                    394:        error = vaccess(vp->v_type, node->tn_mode, node->tn_uid,
                    395:            node->tn_gid, mode, cred);
                    396:
                    397: out:
                    398:        KASSERT(VOP_ISLOCKED(vp));
                    399:
                    400:        return error;
                    401: }
                    402:
                    403: /* --------------------------------------------------------------------- */
                    404:
                    405: int
                    406: tmpfs_getattr(void *v)
                    407: {
                    408:        struct vnode *vp = ((struct vop_getattr_args *)v)->a_vp;
                    409:        struct vattr *vap = ((struct vop_getattr_args *)v)->a_vap;
                    410:
                    411:        struct tmpfs_node *node;
                    412:
                    413:        node = VP_TO_TMPFS_NODE(vp);
                    414:
                    415:        VATTR_NULL(vap);
                    416:
1.14      yamt      417:        tmpfs_itimes(vp, NULL, NULL);
                    418:
1.1       jmmv      419:        vap->va_type = vp->v_type;
                    420:        vap->va_mode = node->tn_mode;
                    421:        vap->va_nlink = node->tn_links;
                    422:        vap->va_uid = node->tn_uid;
                    423:        vap->va_gid = node->tn_gid;
                    424:        vap->va_fsid = vp->v_mount->mnt_stat.f_fsidx.__fsid_val[0];
                    425:        vap->va_fileid = node->tn_id;
                    426:        vap->va_size = node->tn_size;
                    427:        vap->va_blocksize = PAGE_SIZE;
                    428:        vap->va_atime = node->tn_atime;
                    429:        vap->va_mtime = node->tn_mtime;
                    430:        vap->va_ctime = node->tn_ctime;
                    431:        vap->va_birthtime = node->tn_birthtime;
                    432:        vap->va_gen = node->tn_gen;
                    433:        vap->va_flags = node->tn_flags;
                    434:        vap->va_rdev = (vp->v_type == VBLK || vp->v_type == VCHR) ?
1.21      jmmv      435:                node->tn_spec.tn_dev.tn_rdev : VNOVAL;
1.1       jmmv      436:        vap->va_bytes = round_page(node->tn_size);
                    437:        vap->va_filerev = VNOVAL;
                    438:        vap->va_vaflags = 0;
                    439:        vap->va_spare = VNOVAL; /* XXX */
                    440:
                    441:        return 0;
                    442: }
                    443:
                    444: /* --------------------------------------------------------------------- */
                    445:
                    446: /* XXX Should this operation be atomic?  I think it should, but code in
                    447:  * XXX other places (e.g., ufs) doesn't seem to be... */
                    448: int
                    449: tmpfs_setattr(void *v)
                    450: {
                    451:        struct vnode *vp = ((struct vop_setattr_args *)v)->a_vp;
                    452:        struct vattr *vap = ((struct vop_setattr_args *)v)->a_vap;
1.23      elad      453:        kauth_cred_t cred = ((struct vop_setattr_args *)v)->a_cred;
1.19      christos  454:        struct lwp *l = ((struct vop_setattr_args *)v)->a_l;
1.1       jmmv      455:
1.17      yamt      456:        int error;
1.1       jmmv      457:
                    458:        KASSERT(VOP_ISLOCKED(vp));
                    459:
                    460:        error = 0;
                    461:
                    462:        /* Abort if any unsettable attribute is given. */
                    463:        if (vap->va_type != VNON ||
                    464:            vap->va_nlink != VNOVAL ||
                    465:            vap->va_fsid != VNOVAL ||
                    466:            vap->va_fileid != VNOVAL ||
                    467:            vap->va_blocksize != VNOVAL ||
                    468:            vap->va_ctime.tv_sec != VNOVAL ||
                    469:            vap->va_ctime.tv_nsec != VNOVAL ||
                    470:            vap->va_birthtime.tv_sec != VNOVAL ||
                    471:            vap->va_birthtime.tv_nsec != VNOVAL ||
                    472:            vap->va_gen != VNOVAL ||
                    473:            vap->va_rdev != VNOVAL ||
                    474:            vap->va_bytes != VNOVAL)
                    475:                error = EINVAL;
                    476:
                    477:        if (error == 0 && (vap->va_flags != VNOVAL))
1.25      ad        478:                error = tmpfs_chflags(vp, vap->va_flags, cred, l);
1.1       jmmv      479:
                    480:        if (error == 0 && (vap->va_size != VNOVAL))
1.25      ad        481:                error = tmpfs_chsize(vp, vap->va_size, cred, l);
1.1       jmmv      482:
                    483:        if (error == 0 && (vap->va_uid != VNOVAL || vap->va_gid != VNOVAL))
1.25      ad        484:                error = tmpfs_chown(vp, vap->va_uid, vap->va_gid, cred, l);
1.1       jmmv      485:
                    486:        if (error == 0 && (vap->va_mode != VNOVAL))
1.25      ad        487:                error = tmpfs_chmod(vp, vap->va_mode, cred, l);
1.1       jmmv      488:
                    489:        if (error == 0 && ((vap->va_atime.tv_sec != VNOVAL &&
                    490:            vap->va_atime.tv_nsec != VNOVAL) ||
                    491:            (vap->va_mtime.tv_sec != VNOVAL &&
                    492:            vap->va_mtime.tv_nsec != VNOVAL)))
                    493:                error = tmpfs_chtimes(vp, &vap->va_atime, &vap->va_mtime,
1.19      christos  494:                    vap->va_vaflags, cred, l);
1.1       jmmv      495:
                    496:        /* Update the node times.  We give preference to the error codes
                    497:         * generated by this function rather than the ones that may arise
                    498:         * from tmpfs_update. */
1.17      yamt      499:        tmpfs_update(vp, NULL, NULL, 0);
1.1       jmmv      500:
                    501:        KASSERT(VOP_ISLOCKED(vp));
                    502:
                    503:        return error;
                    504: }
                    505:
                    506: /* --------------------------------------------------------------------- */
                    507:
                    508: int
                    509: tmpfs_read(void *v)
                    510: {
                    511:        struct vnode *vp = ((struct vop_read_args *)v)->a_vp;
                    512:        struct uio *uio = ((struct vop_read_args *)v)->a_uio;
                    513:
1.7       jmmv      514:        int error;
                    515:        int flags;
1.6       yamt      516:        struct tmpfs_node *node;
                    517:        struct uvm_object *uobj;
1.1       jmmv      518:
                    519:        KASSERT(VOP_ISLOCKED(vp));
                    520:
                    521:        node = VP_TO_TMPFS_NODE(vp);
                    522:
1.5       yamt      523:        if (vp->v_type != VREG) {
                    524:                error = EISDIR;
                    525:                goto out;
                    526:        }
                    527:
                    528:        if (uio->uio_offset < 0) {
1.1       jmmv      529:                error = EINVAL;
                    530:                goto out;
                    531:        }
                    532:
                    533:        node->tn_status |= TMPFS_NODE_ACCESSED;
                    534:
1.21      jmmv      535:        uobj = node->tn_spec.tn_reg.tn_aobj;
1.6       yamt      536:        flags = UBC_WANT_UNMAP(vp) ? UBC_UNMAP : 0;
                    537:        error = 0;
1.7       jmmv      538:        while (error == 0 && uio->uio_resid > 0) {
1.6       yamt      539:                vsize_t len;
                    540:                void *win;
                    541:
1.8       yamt      542:                if (node->tn_size <= uio->uio_offset)
                    543:                        break;
                    544:
1.6       yamt      545:                len = MIN(node->tn_size - uio->uio_offset, uio->uio_resid);
1.7       jmmv      546:                if (len == 0)
1.6       yamt      547:                        break;
1.7       jmmv      548:
1.18      yamt      549:                win = ubc_alloc(uobj, uio->uio_offset, &len, UVM_ADV_NORMAL,
                    550:                    UBC_READ);
1.6       yamt      551:                error = uiomove(win, len, uio);
                    552:                ubc_release(win, flags);
1.1       jmmv      553:        }
                    554:
                    555: out:
                    556:        KASSERT(VOP_ISLOCKED(vp));
                    557:
                    558:        return error;
                    559: }
                    560:
                    561: /* --------------------------------------------------------------------- */
                    562:
                    563: int
                    564: tmpfs_write(void *v)
                    565: {
                    566:        struct vnode *vp = ((struct vop_write_args *)v)->a_vp;
                    567:        struct uio *uio = ((struct vop_write_args *)v)->a_uio;
                    568:        int ioflag = ((struct vop_write_args *)v)->a_ioflag;
                    569:
1.36      thorpej   570:        bool extended;
1.1       jmmv      571:        int error;
1.7       jmmv      572:        int flags;
1.1       jmmv      573:        off_t oldsize;
                    574:        struct tmpfs_node *node;
1.6       yamt      575:        struct uvm_object *uobj;
1.1       jmmv      576:
                    577:        KASSERT(VOP_ISLOCKED(vp));
                    578:
                    579:        node = VP_TO_TMPFS_NODE(vp);
                    580:        oldsize = node->tn_size;
                    581:
                    582:        if (uio->uio_offset < 0 || vp->v_type != VREG) {
                    583:                error = EINVAL;
                    584:                goto out;
                    585:        }
                    586:
                    587:        if (uio->uio_resid == 0) {
                    588:                error = 0;
                    589:                goto out;
                    590:        }
                    591:
                    592:        if (ioflag & IO_APPEND)
                    593:                uio->uio_offset = node->tn_size;
                    594:
                    595:        extended = uio->uio_offset + uio->uio_resid > node->tn_size;
                    596:        if (extended) {
                    597:                error = tmpfs_reg_resize(vp, uio->uio_offset + uio->uio_resid);
                    598:                if (error != 0)
                    599:                        goto out;
                    600:        }
                    601:
1.21      jmmv      602:        uobj = node->tn_spec.tn_reg.tn_aobj;
1.6       yamt      603:        flags = UBC_WANT_UNMAP(vp) ? UBC_UNMAP : 0;
                    604:        error = 0;
1.7       jmmv      605:        while (error == 0 && uio->uio_resid > 0) {
1.6       yamt      606:                vsize_t len;
                    607:                void *win;
                    608:
                    609:                len = MIN(node->tn_size - uio->uio_offset, uio->uio_resid);
1.7       jmmv      610:                if (len == 0)
1.6       yamt      611:                        break;
1.7       jmmv      612:
1.18      yamt      613:                win = ubc_alloc(uobj, uio->uio_offset, &len, UVM_ADV_NORMAL,
                    614:                    UBC_WRITE);
1.6       yamt      615:                error = uiomove(win, len, uio);
                    616:                ubc_release(win, flags);
1.1       jmmv      617:        }
1.6       yamt      618:
1.1       jmmv      619:        node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED |
                    620:            (extended ? TMPFS_NODE_CHANGED : 0);
                    621:
1.7       jmmv      622:        if (error != 0)
1.6       yamt      623:                (void)tmpfs_reg_resize(vp, oldsize);
                    624:
1.31      jmmv      625:        VN_KNOTE(vp, NOTE_WRITE);
                    626:
1.1       jmmv      627: out:
                    628:        KASSERT(VOP_ISLOCKED(vp));
                    629:        KASSERT(IMPLIES(error == 0, uio->uio_resid == 0));
                    630:        KASSERT(IMPLIES(error != 0, oldsize == node->tn_size));
                    631:
                    632:        return error;
                    633: }
                    634:
                    635: /* --------------------------------------------------------------------- */
                    636:
                    637: int
                    638: tmpfs_fsync(void *v)
                    639: {
                    640:        struct vnode *vp = ((struct vop_fsync_args *)v)->a_vp;
                    641:
                    642:        KASSERT(VOP_ISLOCKED(vp));
                    643:
1.17      yamt      644:        tmpfs_update(vp, NULL, NULL, 0);
                    645:
                    646:        return 0;
1.1       jmmv      647: }
                    648:
                    649: /* --------------------------------------------------------------------- */
                    650:
                    651: int
                    652: tmpfs_remove(void *v)
                    653: {
                    654:        struct vnode *dvp = ((struct vop_remove_args *)v)->a_dvp;
                    655:        struct vnode *vp = ((struct vop_remove_args *)v)->a_vp;
                    656:
                    657:        int error;
                    658:        struct tmpfs_dirent *de;
                    659:        struct tmpfs_mount *tmp;
                    660:        struct tmpfs_node *dnode;
                    661:        struct tmpfs_node *node;
                    662:
                    663:        KASSERT(VOP_ISLOCKED(dvp));
                    664:        KASSERT(VOP_ISLOCKED(vp));
                    665:
1.34      pooka     666:        if (vp->v_type == VDIR) {
                    667:                error = EPERM;
                    668:                goto out;
                    669:        }
                    670:
1.1       jmmv      671:        dnode = VP_TO_TMPFS_DIR(dvp);
                    672:        node = VP_TO_TMPFS_NODE(vp);
                    673:        tmp = VFS_TO_TMPFS(vp->v_mount);
                    674:        de = node->tn_lookup_dirent;
                    675:        KASSERT(de != NULL);
                    676:
                    677:        /* Files marked as immutable or append-only cannot be deleted. */
                    678:        if (node->tn_flags & (IMMUTABLE | APPEND)) {
                    679:                error = EPERM;
                    680:                goto out;
                    681:        }
                    682:
                    683:        /* Remove the entry from the directory; as it is a file, we do not
                    684:         * have to change the number of hard links of the directory. */
                    685:        tmpfs_dir_detach(dvp, de);
                    686:
                    687:        /* Free the directory entry we just deleted.  Note that the node
                    688:         * referred by it will not be removed until the vnode is really
                    689:         * reclaimed. */
1.37      thorpej   690:        tmpfs_free_dirent(tmp, de, true);
1.1       jmmv      691:
                    692:        error = 0;
                    693:
                    694: out:
                    695:        vput(vp);
1.34      pooka     696:        if (dvp == vp)
                    697:                vrele(dvp);
                    698:        else
                    699:                vput(dvp);
1.1       jmmv      700:
                    701:        KASSERT(!VOP_ISLOCKED(dvp));
                    702:
                    703:        return error;
                    704: }
                    705:
                    706: /* --------------------------------------------------------------------- */
                    707:
                    708: int
                    709: tmpfs_link(void *v)
                    710: {
                    711:        struct vnode *dvp = ((struct vop_link_args *)v)->a_dvp;
                    712:        struct vnode *vp = ((struct vop_link_args *)v)->a_vp;
                    713:        struct componentname *cnp = ((struct vop_link_args *)v)->a_cnp;
                    714:
                    715:        int error;
                    716:        struct tmpfs_dirent *de;
                    717:        struct tmpfs_node *dnode;
                    718:        struct tmpfs_node *node;
                    719:
                    720:        KASSERT(VOP_ISLOCKED(dvp));
                    721:        KASSERT(!VOP_ISLOCKED(vp));
                    722:        KASSERT(cnp->cn_flags & HASBUF);
                    723:        KASSERT(dvp != vp); /* XXX When can this be false? */
                    724:
                    725:        dnode = VP_TO_TMPFS_DIR(dvp);
                    726:        node = VP_TO_TMPFS_NODE(vp);
                    727:
1.17      yamt      728:        /* Lock vp because we will need to run tmpfs_update over it, which
1.1       jmmv      729:         * needs the vnode to be locked. */
                    730:        error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
                    731:        if (error != 0)
                    732:                goto out;
                    733:
                    734:        /* XXX: Why aren't the following two tests done by the caller? */
                    735:
                    736:        /* Hard links of directories are forbidden. */
                    737:        if (vp->v_type == VDIR) {
                    738:                error = EPERM;
                    739:                goto out;
                    740:        }
                    741:
                    742:        /* Cannot create cross-device links. */
                    743:        if (dvp->v_mount != vp->v_mount) {
                    744:                error = EXDEV;
                    745:                goto out;
                    746:        }
                    747:
                    748:        /* Ensure that we do not overflow the maximum number of links imposed
                    749:         * by the system. */
                    750:        KASSERT(node->tn_links <= LINK_MAX);
                    751:        if (node->tn_links == LINK_MAX) {
                    752:                error = EMLINK;
                    753:                goto out;
                    754:        }
                    755:
                    756:        /* We cannot create links of files marked immutable or append-only. */
                    757:        if (node->tn_flags & (IMMUTABLE | APPEND)) {
                    758:                error = EPERM;
                    759:                goto out;
                    760:        }
                    761:
                    762:        /* Allocate a new directory entry to represent the node. */
                    763:        error = tmpfs_alloc_dirent(VFS_TO_TMPFS(vp->v_mount), node,
                    764:            cnp->cn_nameptr, cnp->cn_namelen, &de);
                    765:        if (error != 0)
                    766:                goto out;
                    767:
                    768:        /* Insert the new directory entry into the appropriate directory. */
                    769:        tmpfs_dir_attach(dvp, de);
                    770:
                    771:        /* vp link count has changed, so update node times. */
                    772:        node->tn_status |= TMPFS_NODE_CHANGED;
1.17      yamt      773:        tmpfs_update(vp, NULL, NULL, 0);
1.1       jmmv      774:
                    775:        error = 0;
                    776:
                    777: out:
                    778:        if (VOP_ISLOCKED(vp))
                    779:                VOP_UNLOCK(vp, 0);
                    780:
1.4       yamt      781:        PNBUF_PUT(cnp->cn_pnbuf);
1.1       jmmv      782:
                    783:        vput(dvp);
                    784:
                    785:        /* XXX Locking status of dvp does not match manual page. */
                    786:        KASSERT(!VOP_ISLOCKED(dvp));
                    787:        KASSERT(!VOP_ISLOCKED(vp));
                    788:
                    789:        return error;
                    790: }
                    791:
                    792: /* --------------------------------------------------------------------- */
                    793:
                    794: int
                    795: tmpfs_rename(void *v)
                    796: {
                    797:        struct vnode *fdvp = ((struct vop_rename_args *)v)->a_fdvp;
                    798:        struct vnode *fvp = ((struct vop_rename_args *)v)->a_fvp;
                    799:        struct componentname *fcnp = ((struct vop_rename_args *)v)->a_fcnp;
                    800:        struct vnode *tdvp = ((struct vop_rename_args *)v)->a_tdvp;
                    801:        struct vnode *tvp = ((struct vop_rename_args *)v)->a_tvp;
                    802:        struct componentname *tcnp = ((struct vop_rename_args *)v)->a_tcnp;
                    803:
                    804:        char *newname;
                    805:        int error;
                    806:        struct tmpfs_dirent *de;
                    807:        struct tmpfs_mount *tmp;
                    808:        struct tmpfs_node *fdnode;
                    809:        struct tmpfs_node *fnode;
1.39    ! jmmv      810:        struct tmpfs_node *tnode;
1.1       jmmv      811:        struct tmpfs_node *tdnode;
                    812:
                    813:        KASSERT(VOP_ISLOCKED(tdvp));
                    814:        KASSERT(IMPLIES(tvp != NULL, VOP_ISLOCKED(tvp)));
                    815:        KASSERT(fcnp->cn_flags & HASBUF);
                    816:        KASSERT(tcnp->cn_flags & HASBUF);
                    817:
                    818:        fdnode = VP_TO_TMPFS_DIR(fdvp);
                    819:        fnode = VP_TO_TMPFS_NODE(fvp);
1.39    ! jmmv      820:        tnode = (tvp == NULL) ? NULL : VP_TO_TMPFS_NODE(tvp);
1.1       jmmv      821:        de = fnode->tn_lookup_dirent;
                    822:
                    823:        /* Disallow cross-device renames.
                    824:         * XXX Why isn't this done by the caller? */
                    825:        if (fvp->v_mount != tdvp->v_mount ||
                    826:            (tvp != NULL && fvp->v_mount != tvp->v_mount)) {
                    827:                error = EXDEV;
                    828:                goto out;
                    829:        }
                    830:
                    831:        tmp = VFS_TO_TMPFS(tdvp->v_mount);
                    832:        tdnode = VP_TO_TMPFS_DIR(tdvp);
                    833:
                    834:        /* If source and target are the same file, there is nothing to do. */
                    835:        if (fvp == tvp) {
                    836:                error = 0;
                    837:                goto out;
                    838:        }
                    839:
                    840:        /* Avoid manipulating '.' and '..' entries. */
                    841:        if (de == NULL) {
                    842:                KASSERT(fvp->v_type == VDIR);
                    843:                error = EINVAL;
                    844:                goto out;
                    845:        }
                    846:        KASSERT(de->td_node == fnode);
                    847:
1.39    ! jmmv      848:        /* If replacing an existing entry, ensure we can do the operation. */
        !           849:        if (tvp != NULL) {
        !           850:                KASSERT(tnode != NULL);
        !           851:                if (fnode->tn_type == VDIR && tnode->tn_type == VDIR) {
        !           852:                        if (tnode->tn_size > 0) {
        !           853:                                error = ENOTEMPTY;
        !           854:                                goto out;
        !           855:                        }
        !           856:                } else if (fnode->tn_type == VDIR && tnode->tn_type != VDIR) {
        !           857:                        error = ENOTDIR;
        !           858:                        goto out;
        !           859:                } else if (fnode->tn_type != VDIR && tnode->tn_type == VDIR) {
        !           860:                        error = EISDIR;
        !           861:                        goto out;
        !           862:                } else {
        !           863:                        KASSERT(fnode->tn_type != VDIR &&
        !           864:                                tnode->tn_type != VDIR);
        !           865:                }
        !           866:        }
        !           867:
1.11      jmmv      868:        /* If we need to move the directory between entries, lock the
                    869:         * source so that we can safely operate on it. */
                    870:        if (fdnode != tdnode) {
                    871:                error = vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY);
                    872:                if (error != 0)
1.13      yamt      873:                        goto out;
1.11      jmmv      874:        }
                    875:
1.1       jmmv      876:        /* Ensure that we have enough memory to hold the new name, if it
                    877:         * has to be changed. */
                    878:        if (fcnp->cn_namelen != tcnp->cn_namelen ||
                    879:            memcmp(fcnp->cn_nameptr, tcnp->cn_nameptr, fcnp->cn_namelen) != 0) {
                    880:                newname = tmpfs_str_pool_get(&tmp->tm_str_pool,
                    881:                    tcnp->cn_namelen, 0);
                    882:                if (newname == NULL) {
                    883:                        error = ENOSPC;
1.13      yamt      884:                        goto out_locked;
1.1       jmmv      885:                }
                    886:        } else
                    887:                newname = NULL;
                    888:
                    889:        /* If the node is being moved to another directory, we have to do
                    890:         * the move. */
                    891:        if (fdnode != tdnode) {
                    892:                /* In case we are moving a directory, we have to adjust its
                    893:                 * parent to point to the new parent. */
                    894:                if (de->td_node->tn_type == VDIR) {
                    895:                        struct tmpfs_node *n;
                    896:
                    897:                        /* Ensure the target directory is not a child of the
                    898:                         * directory being moved.  Otherwise, we'd end up
                    899:                         * with stale nodes. */
                    900:                        n = tdnode;
1.21      jmmv      901:                        while (n != n->tn_spec.tn_dir.tn_parent) {
1.1       jmmv      902:                                if (n == fnode) {
                    903:                                        error = EINVAL;
1.13      yamt      904:                                        goto out_locked;
1.1       jmmv      905:                                }
1.21      jmmv      906:                                n = n->tn_spec.tn_dir.tn_parent;
1.1       jmmv      907:                        }
                    908:
                    909:                        /* Adjust the parent pointer. */
                    910:                        TMPFS_VALIDATE_DIR(fnode);
1.21      jmmv      911:                        de->td_node->tn_spec.tn_dir.tn_parent = tdnode;
1.1       jmmv      912:
                    913:                        /* As a result of changing the target of the '..'
                    914:                         * entry, the link count of the source and target
                    915:                         * directories has to be adjusted. */
                    916:                        fdnode->tn_links--;
                    917:                        tdnode->tn_links++;
                    918:                }
                    919:
                    920:                /* Do the move: just remove the entry from the source directory
                    921:                 * and insert it into the target one. */
                    922:                tmpfs_dir_detach(fdvp, de);
                    923:                tmpfs_dir_attach(tdvp, de);
                    924:
                    925:                /* Notify listeners of fdvp about the change in the directory.
                    926:                 * We can do it at this point because we aren't touching fdvp
                    927:                 * any more below. */
                    928:                VN_KNOTE(fdvp, NOTE_WRITE);
                    929:        }
                    930:
                    931:        /* If the name has changed, we need to make it effective by changing
                    932:         * it in the directory entry. */
                    933:        if (newname != NULL) {
                    934:                KASSERT(tcnp->cn_namelen < MAXNAMLEN);
                    935:                KASSERT(tcnp->cn_namelen < 0xffff);
                    936:
                    937:                tmpfs_str_pool_put(&tmp->tm_str_pool, de->td_name,
                    938:                    de->td_namelen);
                    939:                de->td_namelen = (uint16_t)tcnp->cn_namelen;
                    940:                memcpy(newname, tcnp->cn_nameptr, tcnp->cn_namelen);
                    941:                de->td_name = newname;
                    942:
1.27      jmmv      943:                fnode->tn_status |= TMPFS_NODE_CHANGED;
1.26      jmmv      944:                tdnode->tn_status |= TMPFS_NODE_MODIFIED;
1.1       jmmv      945:        }
                    946:
                    947:        /* If we are overwriting an entry, we have to remove the old one
                    948:         * from the target directory. */
                    949:        if (tvp != NULL) {
1.39    ! jmmv      950:                KASSERT(tnode != NULL);
1.1       jmmv      951:
                    952:                /* Remove the old entry from the target directory. */
                    953:                de = tnode->tn_lookup_dirent;
                    954:                tmpfs_dir_detach(tdvp, de);
                    955:
                    956:                /* Free the directory entry we just deleted.  Note that the
                    957:                 * node referred by it will not be removed until the vnode is
                    958:                 * really reclaimed. */
1.37      thorpej   959:                tmpfs_free_dirent(VFS_TO_TMPFS(tvp->v_mount), de, true);
1.1       jmmv      960:        }
                    961:
                    962:        /* Notify listeners of tdvp about the change in the directory (either
1.31      jmmv      963:         * because a new entry was added or because one was removed) and
                    964:         * listeners of fvp about the rename. */
1.1       jmmv      965:        VN_KNOTE(tdvp, NOTE_WRITE);
1.31      jmmv      966:        VN_KNOTE(fvp, NOTE_RENAME);
1.1       jmmv      967:
                    968:        error = 0;
                    969:
1.11      jmmv      970: out_locked:
                    971:        if (fdnode != tdnode)
                    972:                VOP_UNLOCK(fdvp, 0);
                    973:
1.1       jmmv      974: out:
                    975:        /* Release target nodes. */
                    976:        /* XXX: I don't understand when tdvp can be the same as tvp, but
                    977:         * other code takes care of this... */
                    978:        if (tdvp == tvp)
                    979:                vrele(tdvp);
                    980:        else
                    981:                vput(tdvp);
                    982:        if (tvp != NULL)
                    983:                vput(tvp);
                    984:
                    985:        /* Release source nodes. */
                    986:        vrele(fdvp);
                    987:        vrele(fvp);
                    988:
                    989:        return error;
                    990: }
                    991:
                    992: /* --------------------------------------------------------------------- */
                    993:
                    994: int
                    995: tmpfs_mkdir(void *v)
                    996: {
                    997:        struct vnode *dvp = ((struct vop_mkdir_args *)v)->a_dvp;
                    998:        struct vnode **vpp = ((struct vop_mkdir_args *)v)->a_vpp;
                    999:        struct componentname *cnp = ((struct vop_mkdir_args *)v)->a_cnp;
                   1000:        struct vattr *vap = ((struct vop_mkdir_args *)v)->a_vap;
                   1001:
                   1002:        KASSERT(vap->va_type == VDIR);
                   1003:
                   1004:        return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL);
                   1005: }
                   1006:
                   1007: /* --------------------------------------------------------------------- */
                   1008:
                   1009: int
                   1010: tmpfs_rmdir(void *v)
                   1011: {
                   1012:        struct vnode *dvp = ((struct vop_rmdir_args *)v)->a_dvp;
                   1013:        struct vnode *vp = ((struct vop_rmdir_args *)v)->a_vp;
                   1014:
                   1015:        int error;
                   1016:        struct tmpfs_dirent *de;
                   1017:        struct tmpfs_mount *tmp;
                   1018:        struct tmpfs_node *dnode;
                   1019:        struct tmpfs_node *node;
                   1020:
                   1021:        KASSERT(VOP_ISLOCKED(dvp));
                   1022:        KASSERT(VOP_ISLOCKED(vp));
                   1023:
                   1024:        tmp = VFS_TO_TMPFS(dvp->v_mount);
                   1025:        dnode = VP_TO_TMPFS_DIR(dvp);
                   1026:        node = VP_TO_TMPFS_DIR(vp);
1.34      pooka    1027:
                   1028:        /* Directories with more than two entries ('.' and '..') cannot be
                   1029:         * removed. */
                   1030:        if (node->tn_size > 0) {
                   1031:                error = ENOTEMPTY;
                   1032:                goto out;
                   1033:        }
                   1034:
                   1035:        /* This invariant holds only if we are not trying to remove "..".
                   1036:         * We checked for that above so this is safe now. */
1.21      jmmv     1037:        KASSERT(node->tn_spec.tn_dir.tn_parent == dnode);
1.1       jmmv     1038:
                   1039:        /* Get the directory entry associated with node (vp).  This was
                   1040:         * filled by tmpfs_lookup while looking up the entry. */
                   1041:        de = node->tn_lookup_dirent;
                   1042:        KASSERT(TMPFS_DIRENT_MATCHES(de,
                   1043:            ((struct vop_rmdir_args *)v)->a_cnp->cn_nameptr,
                   1044:            ((struct vop_rmdir_args *)v)->a_cnp->cn_namelen));
                   1045:
                   1046:        /* Check flags to see if we are allowed to remove the directory. */
                   1047:        if (dnode->tn_flags & APPEND || node->tn_flags & (IMMUTABLE | APPEND)) {
                   1048:                error = EPERM;
                   1049:                goto out;
                   1050:        }
                   1051:
                   1052:        /* Detach the directory entry from the directory (dnode). */
                   1053:        tmpfs_dir_detach(dvp, de);
                   1054:
                   1055:        node->tn_links--;
                   1056:        node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | \
                   1057:            TMPFS_NODE_MODIFIED;
1.21      jmmv     1058:        node->tn_spec.tn_dir.tn_parent->tn_links--;
                   1059:        node->tn_spec.tn_dir.tn_parent->tn_status |= TMPFS_NODE_ACCESSED | \
1.1       jmmv     1060:            TMPFS_NODE_CHANGED | TMPFS_NODE_MODIFIED;
                   1061:
1.31      jmmv     1062:        /* Release the parent. */
1.1       jmmv     1063:        cache_purge(dvp); /* XXX Is this needed? */
                   1064:        vput(dvp);
                   1065:
                   1066:        /* Free the directory entry we just deleted.  Note that the node
                   1067:         * referred by it will not be removed until the vnode is really
                   1068:         * reclaimed. */
1.37      thorpej  1069:        tmpfs_free_dirent(tmp, de, true);
1.1       jmmv     1070:
                   1071:        /* Release the deleted vnode (will destroy the node, notify
                   1072:         * interested parties and clean it from the cache). */
                   1073:        vput(vp);
                   1074:
                   1075:        error = 0;
                   1076:
                   1077: out:
                   1078:        if (error != 0) {
                   1079:                vput(dvp);
                   1080:                vput(vp);
                   1081:        }
                   1082:
                   1083:        return error;
                   1084: }
                   1085:
                   1086: /* --------------------------------------------------------------------- */
                   1087:
                   1088: int
                   1089: tmpfs_symlink(void *v)
                   1090: {
                   1091:        struct vnode *dvp = ((struct vop_symlink_args *)v)->a_dvp;
                   1092:        struct vnode **vpp = ((struct vop_symlink_args *)v)->a_vpp;
                   1093:        struct componentname *cnp = ((struct vop_symlink_args *)v)->a_cnp;
                   1094:        struct vattr *vap = ((struct vop_symlink_args *)v)->a_vap;
                   1095:        char *target = ((struct vop_symlink_args *)v)->a_target;
                   1096:
                   1097:        KASSERT(vap->va_type == VLNK);
                   1098:
                   1099:        return tmpfs_alloc_file(dvp, vpp, vap, cnp, target);
                   1100: }
                   1101:
                   1102: /* --------------------------------------------------------------------- */
                   1103:
                   1104: int
                   1105: tmpfs_readdir(void *v)
                   1106: {
                   1107:        struct vnode *vp = ((struct vop_readdir_args *)v)->a_vp;
                   1108:        struct uio *uio = ((struct vop_readdir_args *)v)->a_uio;
                   1109:        int *eofflag = ((struct vop_readdir_args *)v)->a_eofflag;
                   1110:        off_t **cookies = ((struct vop_readdir_args *)v)->a_cookies;
                   1111:        int *ncookies = ((struct vop_readdir_args *)v)->a_ncookies;
                   1112:
                   1113:        int error;
1.10      yamt     1114:        off_t startoff;
                   1115:        off_t cnt;
1.1       jmmv     1116:        struct tmpfs_node *node;
                   1117:
                   1118:        KASSERT(VOP_ISLOCKED(vp));
                   1119:
                   1120:        /* This operation only makes sense on directory nodes. */
                   1121:        if (vp->v_type != VDIR) {
                   1122:                error = ENOTDIR;
                   1123:                goto out;
                   1124:        }
                   1125:
                   1126:        node = VP_TO_TMPFS_DIR(vp);
                   1127:
                   1128:        startoff = uio->uio_offset;
                   1129:
1.10      yamt     1130:        cnt = 0;
                   1131:        if (uio->uio_offset == TMPFS_DIRCOOKIE_DOT) {
1.1       jmmv     1132:                error = tmpfs_dir_getdotdent(node, uio);
                   1133:                if (error == -1) {
                   1134:                        error = 0;
                   1135:                        goto outok;
                   1136:                } else if (error != 0)
                   1137:                        goto outok;
1.10      yamt     1138:                cnt++;
1.1       jmmv     1139:        }
                   1140:
1.10      yamt     1141:        if (uio->uio_offset == TMPFS_DIRCOOKIE_DOTDOT) {
1.1       jmmv     1142:                error = tmpfs_dir_getdotdotdent(node, uio);
                   1143:                if (error == -1) {
                   1144:                        error = 0;
                   1145:                        goto outok;
                   1146:                } else if (error != 0)
                   1147:                        goto outok;
1.10      yamt     1148:                cnt++;
1.1       jmmv     1149:        }
                   1150:
1.10      yamt     1151:        error = tmpfs_dir_getdents(node, uio, &cnt);
1.1       jmmv     1152:        if (error == -1)
                   1153:                error = 0;
                   1154:        KASSERT(error >= 0);
                   1155:
                   1156: outok:
1.10      yamt     1157:        /* This label assumes that startoff has been
1.1       jmmv     1158:         * initialized.  If the compiler didn't spit out warnings, we'd
                   1159:         * simply make this one be 'out' and drop 'outok'. */
                   1160:
                   1161:        if (eofflag != NULL)
                   1162:                *eofflag =
1.10      yamt     1163:                    (error == 0 && uio->uio_offset == TMPFS_DIRCOOKIE_EOF);
1.1       jmmv     1164:
                   1165:        /* Update NFS-related variables. */
                   1166:        if (error == 0 && cookies != NULL && ncookies != NULL) {
                   1167:                off_t i;
1.10      yamt     1168:                off_t off = startoff;
                   1169:                struct tmpfs_dirent *de = NULL;
1.1       jmmv     1170:
1.10      yamt     1171:                *ncookies = cnt;
                   1172:                *cookies = malloc(cnt * sizeof(off_t), M_TEMP, M_WAITOK);
                   1173:
                   1174:                for (i = 0; i < cnt; i++) {
                   1175:                        KASSERT(off != TMPFS_DIRCOOKIE_EOF);
                   1176:                        if (off == TMPFS_DIRCOOKIE_DOT) {
                   1177:                                off = TMPFS_DIRCOOKIE_DOTDOT;
                   1178:                        } else {
                   1179:                                if (off == TMPFS_DIRCOOKIE_DOTDOT) {
1.21      jmmv     1180:                                        de = TAILQ_FIRST(&node->tn_spec.
                   1181:                                            tn_dir.tn_dir);
1.10      yamt     1182:                                } else if (de != NULL) {
                   1183:                                        de = TAILQ_NEXT(de, td_entries);
                   1184:                                } else {
                   1185:                                        de = tmpfs_dir_lookupbycookie(node,
                   1186:                                            off);
                   1187:                                        KASSERT(de != NULL);
                   1188:                                        de = TAILQ_NEXT(de, td_entries);
                   1189:                                }
                   1190:                                if (de == NULL) {
                   1191:                                        off = TMPFS_DIRCOOKIE_EOF;
                   1192:                                } else {
1.29      jmmv     1193:                                        off = tmpfs_dircookie(de);
1.10      yamt     1194:                                }
                   1195:                        }
                   1196:
                   1197:                        (*cookies)[i] = off;
                   1198:                }
                   1199:                KASSERT(uio->uio_offset == off);
1.1       jmmv     1200:        }
                   1201:
                   1202: out:
                   1203:        KASSERT(VOP_ISLOCKED(vp));
                   1204:
                   1205:        return error;
                   1206: }
                   1207:
                   1208: /* --------------------------------------------------------------------- */
                   1209:
                   1210: int
                   1211: tmpfs_readlink(void *v)
                   1212: {
                   1213:        struct vnode *vp = ((struct vop_readlink_args *)v)->a_vp;
                   1214:        struct uio *uio = ((struct vop_readlink_args *)v)->a_uio;
                   1215:
                   1216:        int error;
                   1217:        struct tmpfs_node *node;
                   1218:
                   1219:        KASSERT(VOP_ISLOCKED(vp));
                   1220:        KASSERT(uio->uio_offset == 0);
                   1221:        KASSERT(vp->v_type == VLNK);
                   1222:
                   1223:        node = VP_TO_TMPFS_NODE(vp);
                   1224:
1.21      jmmv     1225:        error = uiomove(node->tn_spec.tn_lnk.tn_link,
                   1226:            MIN(node->tn_size, uio->uio_resid), uio);
1.1       jmmv     1227:        node->tn_status |= TMPFS_NODE_ACCESSED;
                   1228:
                   1229:        KASSERT(VOP_ISLOCKED(vp));
                   1230:
                   1231:        return error;
                   1232: }
                   1233:
                   1234: /* --------------------------------------------------------------------- */
                   1235:
                   1236: int
                   1237: tmpfs_inactive(void *v)
                   1238: {
                   1239:        struct vnode *vp = ((struct vop_inactive_args *)v)->a_vp;
1.19      christos 1240:        struct lwp *l = ((struct vop_inactive_args *)v)->a_l;
1.38      ad       1241:        nlink_t links;
1.1       jmmv     1242:
                   1243:        struct tmpfs_node *node;
                   1244:
                   1245:        KASSERT(VOP_ISLOCKED(vp));
                   1246:
                   1247:        node = VP_TO_TMPFS_NODE(vp);
1.38      ad       1248:        links = node->tn_links;
1.1       jmmv     1249:
                   1250:        VOP_UNLOCK(vp, 0);
                   1251:
1.38      ad       1252:        if (links == 0)
1.19      christos 1253:                vrecycle(vp, NULL, l);
1.1       jmmv     1254:
                   1255:        return 0;
                   1256: }
                   1257:
                   1258: /* --------------------------------------------------------------------- */
                   1259:
                   1260: int
                   1261: tmpfs_reclaim(void *v)
                   1262: {
                   1263:        struct vnode *vp = ((struct vop_reclaim_args *)v)->a_vp;
                   1264:
                   1265:        struct tmpfs_mount *tmp;
                   1266:        struct tmpfs_node *node;
                   1267:
                   1268:        KASSERT(!VOP_ISLOCKED(vp));
                   1269:
                   1270:        node = VP_TO_TMPFS_NODE(vp);
                   1271:        tmp = VFS_TO_TMPFS(vp->v_mount);
                   1272:
                   1273:        cache_purge(vp);
                   1274:        tmpfs_free_vp(vp);
                   1275:
                   1276:        /* If the node referenced by this vnode was deleted by the user,
                   1277:         * we must free its associated data structures (now that the vnode
                   1278:         * is being reclaimed). */
                   1279:        if (node->tn_links == 0)
                   1280:                tmpfs_free_node(tmp, node);
                   1281:
                   1282:        KASSERT(!VOP_ISLOCKED(vp));
                   1283:        KASSERT(vp->v_data == NULL);
                   1284:
                   1285:        return 0;
                   1286: }
                   1287:
                   1288: /* --------------------------------------------------------------------- */
                   1289:
                   1290: int
                   1291: tmpfs_print(void *v)
                   1292: {
                   1293:        struct vnode *vp = ((struct vop_print_args *)v)->a_vp;
                   1294:
                   1295:        struct tmpfs_node *node;
                   1296:
                   1297:        node = VP_TO_TMPFS_NODE(vp);
                   1298:
                   1299:        printf("tag VT_TMPFS, tmpfs_node %p, flags 0x%x, links %d\n",
                   1300:            node, node->tn_flags, node->tn_links);
                   1301:        printf("\tmode 0%o, owner %d, group %d, size %" PRIdMAX
                   1302:            ", status 0x%x\n",
                   1303:            node->tn_mode, node->tn_uid, node->tn_gid,
                   1304:            (uintmax_t)node->tn_size, node->tn_status);
                   1305:
                   1306:        if (vp->v_type == VFIFO)
                   1307:                fifo_printinfo(vp);
                   1308:        lockmgr_printinfo(&vp->v_lock);
                   1309:
                   1310:        printf("\n");
                   1311:
                   1312:        return 0;
                   1313: }
                   1314:
                   1315: /* --------------------------------------------------------------------- */
                   1316:
                   1317: int
                   1318: tmpfs_pathconf(void *v)
                   1319: {
                   1320:        int name = ((struct vop_pathconf_args *)v)->a_name;
                   1321:        register_t *retval = ((struct vop_pathconf_args *)v)->a_retval;
                   1322:
                   1323:        int error;
                   1324:
                   1325:        error = 0;
                   1326:
                   1327:        switch (name) {
                   1328:        case _PC_LINK_MAX:
                   1329:                *retval = LINK_MAX;
                   1330:                break;
                   1331:
                   1332:        case _PC_NAME_MAX:
                   1333:                *retval = NAME_MAX;
                   1334:                break;
                   1335:
                   1336:        case _PC_PATH_MAX:
                   1337:                *retval = PATH_MAX;
                   1338:                break;
                   1339:
                   1340:        case _PC_PIPE_BUF:
                   1341:                *retval = PIPE_BUF;
                   1342:                break;
                   1343:
                   1344:        case _PC_CHOWN_RESTRICTED:
                   1345:                *retval = 1;
                   1346:                break;
                   1347:
                   1348:        case _PC_NO_TRUNC:
                   1349:                *retval = 1;
                   1350:                break;
                   1351:
                   1352:        case _PC_SYNC_IO:
                   1353:                *retval = 1;
                   1354:                break;
                   1355:
                   1356:        case _PC_FILESIZEBITS:
                   1357:                *retval = 0; /* XXX Don't know which value should I return. */
                   1358:                break;
                   1359:
                   1360:        default:
                   1361:                error = EINVAL;
                   1362:        }
                   1363:
                   1364:        return error;
                   1365: }
                   1366:
                   1367: /* --------------------------------------------------------------------- */
                   1368:
                   1369: int
1.15      jmmv     1370: tmpfs_advlock(void *v)
                   1371: {
                   1372:        struct vnode *vp = ((struct vop_advlock_args *)v)->a_vp;
                   1373:
                   1374:        struct tmpfs_node *node;
                   1375:
                   1376:        node = VP_TO_TMPFS_NODE(vp);
                   1377:
                   1378:        return lf_advlock(v, &node->tn_lockf, node->tn_size);
                   1379: }
                   1380:
                   1381: /* --------------------------------------------------------------------- */
                   1382:
                   1383: int
1.1       jmmv     1384: tmpfs_getpages(void *v)
                   1385: {
1.7       jmmv     1386:        struct vnode *vp = ((struct vop_getpages_args *)v)->a_vp;
                   1387:        voff_t offset = ((struct vop_getpages_args *)v)->a_offset;
                   1388:        struct vm_page **m = ((struct vop_getpages_args *)v)->a_m;
                   1389:        int *count = ((struct vop_getpages_args *)v)->a_count;
                   1390:        int centeridx = ((struct vop_getpages_args *)v)->a_centeridx;
                   1391:        vm_prot_t access_type = ((struct vop_getpages_args *)v)->a_access_type;
                   1392:        int advice = ((struct vop_getpages_args *)v)->a_advice;
                   1393:        int flags = ((struct vop_getpages_args *)v)->a_flags;
                   1394:
                   1395:        int error;
1.28      jmmv     1396:        int i;
1.7       jmmv     1397:        struct tmpfs_node *node;
1.6       yamt     1398:        struct uvm_object *uobj;
1.9       yamt     1399:        int npages = *count;
1.1       jmmv     1400:
1.6       yamt     1401:        KASSERT(vp->v_type == VREG);
1.7       jmmv     1402:        LOCK_ASSERT(simple_lock_held(&vp->v_interlock));
1.1       jmmv     1403:
1.7       jmmv     1404:        node = VP_TO_TMPFS_NODE(vp);
1.21      jmmv     1405:        uobj = node->tn_spec.tn_reg.tn_aobj;
1.1       jmmv     1406:
1.9       yamt     1407:        /* We currently don't rely on PGO_PASTEOF. */
                   1408:
                   1409:        if (vp->v_size <= offset + (centeridx << PAGE_SHIFT)) {
                   1410:                if ((flags & PGO_LOCKED) == 0)
                   1411:                        simple_unlock(&vp->v_interlock);
                   1412:                return EINVAL;
                   1413:        }
                   1414:
                   1415:        if (vp->v_size < offset + (npages << PAGE_SHIFT)) {
                   1416:                npages = (round_page(vp->v_size) - offset) >> PAGE_SHIFT;
                   1417:        }
                   1418:
1.7       jmmv     1419:        if ((flags & PGO_LOCKED) != 0)
1.6       yamt     1420:                return EBUSY;
1.1       jmmv     1421:
1.6       yamt     1422:        if ((flags & PGO_NOTIMESTAMP) == 0) {
1.7       jmmv     1423:                if ((vp->v_mount->mnt_flag & MNT_NOATIME) == 0)
1.6       yamt     1424:                        node->tn_status |= TMPFS_NODE_ACCESSED;
1.7       jmmv     1425:
                   1426:                if ((access_type & VM_PROT_WRITE) != 0)
1.6       yamt     1427:                        node->tn_status |= TMPFS_NODE_MODIFIED;
1.1       jmmv     1428:        }
                   1429:
1.6       yamt     1430:        simple_unlock(&vp->v_interlock);
                   1431:
1.28      jmmv     1432:        /*
                   1433:         * Make sure that the array on which we will store the
                   1434:         * gotten pages is clean.  Otherwise uao_get (pointed to by
                   1435:         * the pgo_get below) gets confused and does not return the
                   1436:         * appropriate pages.
                   1437:         *
                   1438:         * XXX This shall be revisited when kern/32166 is addressed
                   1439:         * because the loop to clean m[i] will most likely be redundant
                   1440:         * as well as the PGO_ALLPAGES flag.
                   1441:         */
                   1442:        if (m != NULL)
                   1443:                for (i = 0; i < npages; i++)
                   1444:                        m[i] = NULL;
1.6       yamt     1445:        simple_lock(&uobj->vmobjlock);
1.9       yamt     1446:        error = (*uobj->pgops->pgo_get)(uobj, offset, m, &npages, centeridx,
1.28      jmmv     1447:            access_type, advice, flags | PGO_ALLPAGES);
                   1448: #if defined(DEBUG)
                   1449:        {
                   1450:                /* Make sure that all the pages we return are valid. */
                   1451:                int dbgi;
                   1452:                if (error == 0 && m != NULL)
                   1453:                        for (dbgi = 0; dbgi < npages; dbgi++)
                   1454:                                KASSERT(m[dbgi] != NULL);
                   1455:        }
                   1456: #endif
1.1       jmmv     1457:
1.6       yamt     1458:        return error;
                   1459: }
                   1460:
                   1461: /* --------------------------------------------------------------------- */
                   1462:
                   1463: int
                   1464: tmpfs_putpages(void *v)
                   1465: {
1.7       jmmv     1466:        struct vnode *vp = ((struct vop_putpages_args *)v)->a_vp;
                   1467:        voff_t offlo = ((struct vop_putpages_args *)v)->a_offlo;
                   1468:        voff_t offhi = ((struct vop_putpages_args *)v)->a_offhi;
                   1469:        int flags = ((struct vop_putpages_args *)v)->a_flags;
                   1470:
                   1471:        int error;
                   1472:        struct tmpfs_node *node;
1.6       yamt     1473:        struct uvm_object *uobj;
                   1474:
                   1475:        LOCK_ASSERT(simple_lock_held(&vp->v_interlock));
                   1476:
1.7       jmmv     1477:        node = VP_TO_TMPFS_NODE(vp);
                   1478:
1.6       yamt     1479:        if (vp->v_type != VREG) {
                   1480:                simple_unlock(&vp->v_interlock);
                   1481:                return 0;
1.1       jmmv     1482:        }
                   1483:
1.21      jmmv     1484:        uobj = node->tn_spec.tn_reg.tn_aobj;
1.6       yamt     1485:        simple_unlock(&vp->v_interlock);
                   1486:
                   1487:        simple_lock(&uobj->vmobjlock);
1.7       jmmv     1488:        error = (*uobj->pgops->pgo_put)(uobj, offlo, offhi, flags);
1.6       yamt     1489:
                   1490:        /* XXX mtime */
1.1       jmmv     1491:
                   1492:        return error;
                   1493: }

CVSweb <webmaster@jp.NetBSD.org>