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

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

CVSweb <webmaster@jp.NetBSD.org>