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

1.37.4.2! ad          1: /*     $NetBSD: tmpfs_vnops.c,v 1.37.4.1 2007/03/21 20:10:19 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.37.4.2! ad         45: __KERNEL_RCSID(0, "$NetBSD: tmpfs_vnops.c,v 1.37.4.1 2007/03/21 20:10:19 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;
                    810:        struct tmpfs_node *tdnode;
                    811:
                    812:        KASSERT(VOP_ISLOCKED(tdvp));
                    813:        KASSERT(IMPLIES(tvp != NULL, VOP_ISLOCKED(tvp)));
                    814:        KASSERT(fcnp->cn_flags & HASBUF);
                    815:        KASSERT(tcnp->cn_flags & HASBUF);
                    816:
                    817:        fdnode = VP_TO_TMPFS_DIR(fdvp);
                    818:        fnode = VP_TO_TMPFS_NODE(fvp);
                    819:        de = fnode->tn_lookup_dirent;
                    820:
                    821:        /* Disallow cross-device renames.
                    822:         * XXX Why isn't this done by the caller? */
                    823:        if (fvp->v_mount != tdvp->v_mount ||
                    824:            (tvp != NULL && fvp->v_mount != tvp->v_mount)) {
                    825:                error = EXDEV;
                    826:                goto out;
                    827:        }
                    828:
                    829:        tmp = VFS_TO_TMPFS(tdvp->v_mount);
                    830:        tdnode = VP_TO_TMPFS_DIR(tdvp);
                    831:
                    832:        /* If source and target are the same file, there is nothing to do. */
                    833:        if (fvp == tvp) {
                    834:                error = 0;
                    835:                goto out;
                    836:        }
                    837:
                    838:        /* Avoid manipulating '.' and '..' entries. */
                    839:        if (de == NULL) {
                    840:                KASSERT(fvp->v_type == VDIR);
                    841:                error = EINVAL;
                    842:                goto out;
                    843:        }
                    844:        KASSERT(de->td_node == fnode);
                    845:
1.11      jmmv      846:        /* If we need to move the directory between entries, lock the
                    847:         * source so that we can safely operate on it. */
                    848:        if (fdnode != tdnode) {
                    849:                error = vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY);
                    850:                if (error != 0)
1.13      yamt      851:                        goto out;
1.11      jmmv      852:        }
                    853:
1.1       jmmv      854:        /* Ensure that we have enough memory to hold the new name, if it
                    855:         * has to be changed. */
                    856:        if (fcnp->cn_namelen != tcnp->cn_namelen ||
                    857:            memcmp(fcnp->cn_nameptr, tcnp->cn_nameptr, fcnp->cn_namelen) != 0) {
                    858:                newname = tmpfs_str_pool_get(&tmp->tm_str_pool,
                    859:                    tcnp->cn_namelen, 0);
                    860:                if (newname == NULL) {
                    861:                        error = ENOSPC;
1.13      yamt      862:                        goto out_locked;
1.1       jmmv      863:                }
                    864:        } else
                    865:                newname = NULL;
                    866:
                    867:        /* If the node is being moved to another directory, we have to do
                    868:         * the move. */
                    869:        if (fdnode != tdnode) {
                    870:                /* In case we are moving a directory, we have to adjust its
                    871:                 * parent to point to the new parent. */
                    872:                if (de->td_node->tn_type == VDIR) {
                    873:                        struct tmpfs_node *n;
                    874:
                    875:                        /* Ensure the target directory is not a child of the
                    876:                         * directory being moved.  Otherwise, we'd end up
                    877:                         * with stale nodes. */
                    878:                        n = tdnode;
1.21      jmmv      879:                        while (n != n->tn_spec.tn_dir.tn_parent) {
1.1       jmmv      880:                                if (n == fnode) {
                    881:                                        error = EINVAL;
1.13      yamt      882:                                        goto out_locked;
1.1       jmmv      883:                                }
1.21      jmmv      884:                                n = n->tn_spec.tn_dir.tn_parent;
1.1       jmmv      885:                        }
                    886:
                    887:                        /* Adjust the parent pointer. */
                    888:                        TMPFS_VALIDATE_DIR(fnode);
1.21      jmmv      889:                        de->td_node->tn_spec.tn_dir.tn_parent = tdnode;
1.1       jmmv      890:
                    891:                        /* As a result of changing the target of the '..'
                    892:                         * entry, the link count of the source and target
                    893:                         * directories has to be adjusted. */
                    894:                        fdnode->tn_links--;
                    895:                        tdnode->tn_links++;
                    896:                }
                    897:
                    898:                /* Do the move: just remove the entry from the source directory
                    899:                 * and insert it into the target one. */
                    900:                tmpfs_dir_detach(fdvp, de);
                    901:                tmpfs_dir_attach(tdvp, de);
                    902:
                    903:                /* Notify listeners of fdvp about the change in the directory.
                    904:                 * We can do it at this point because we aren't touching fdvp
                    905:                 * any more below. */
                    906:                VN_KNOTE(fdvp, NOTE_WRITE);
                    907:        }
                    908:
                    909:        /* If the name has changed, we need to make it effective by changing
                    910:         * it in the directory entry. */
                    911:        if (newname != NULL) {
                    912:                KASSERT(tcnp->cn_namelen < MAXNAMLEN);
                    913:                KASSERT(tcnp->cn_namelen < 0xffff);
                    914:
                    915:                tmpfs_str_pool_put(&tmp->tm_str_pool, de->td_name,
                    916:                    de->td_namelen);
                    917:                de->td_namelen = (uint16_t)tcnp->cn_namelen;
                    918:                memcpy(newname, tcnp->cn_nameptr, tcnp->cn_namelen);
                    919:                de->td_name = newname;
                    920:
1.27      jmmv      921:                fnode->tn_status |= TMPFS_NODE_CHANGED;
1.26      jmmv      922:                tdnode->tn_status |= TMPFS_NODE_MODIFIED;
1.1       jmmv      923:        }
                    924:
                    925:        /* If we are overwriting an entry, we have to remove the old one
                    926:         * from the target directory. */
                    927:        if (tvp != NULL) {
                    928:                struct tmpfs_node *tnode;
                    929:
                    930:                tnode = VP_TO_TMPFS_NODE(tvp);
                    931:
                    932:                /* The source node cannot be a directory in this case. */
                    933:                KASSERT(fnode->tn_type != VDIR);
                    934:
                    935:                /* Remove the old entry from the target directory. */
                    936:                de = tnode->tn_lookup_dirent;
                    937:                tmpfs_dir_detach(tdvp, de);
                    938:
                    939:                /* Free the directory entry we just deleted.  Note that the
                    940:                 * node referred by it will not be removed until the vnode is
                    941:                 * really reclaimed. */
1.37      thorpej   942:                tmpfs_free_dirent(VFS_TO_TMPFS(tvp->v_mount), de, true);
1.1       jmmv      943:        }
                    944:
                    945:        /* Notify listeners of tdvp about the change in the directory (either
1.31      jmmv      946:         * because a new entry was added or because one was removed) and
                    947:         * listeners of fvp about the rename. */
1.1       jmmv      948:        VN_KNOTE(tdvp, NOTE_WRITE);
1.31      jmmv      949:        VN_KNOTE(fvp, NOTE_RENAME);
1.1       jmmv      950:
                    951:        error = 0;
                    952:
1.11      jmmv      953: out_locked:
                    954:        if (fdnode != tdnode)
                    955:                VOP_UNLOCK(fdvp, 0);
                    956:
1.1       jmmv      957: out:
                    958:        /* Release target nodes. */
                    959:        /* XXX: I don't understand when tdvp can be the same as tvp, but
                    960:         * other code takes care of this... */
                    961:        if (tdvp == tvp)
                    962:                vrele(tdvp);
                    963:        else
                    964:                vput(tdvp);
                    965:        if (tvp != NULL)
                    966:                vput(tvp);
                    967:
                    968:        /* Release source nodes. */
                    969:        vrele(fdvp);
                    970:        vrele(fvp);
                    971:
                    972:        return error;
                    973: }
                    974:
                    975: /* --------------------------------------------------------------------- */
                    976:
                    977: int
                    978: tmpfs_mkdir(void *v)
                    979: {
                    980:        struct vnode *dvp = ((struct vop_mkdir_args *)v)->a_dvp;
                    981:        struct vnode **vpp = ((struct vop_mkdir_args *)v)->a_vpp;
                    982:        struct componentname *cnp = ((struct vop_mkdir_args *)v)->a_cnp;
                    983:        struct vattr *vap = ((struct vop_mkdir_args *)v)->a_vap;
                    984:
                    985:        KASSERT(vap->va_type == VDIR);
                    986:
                    987:        return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL);
                    988: }
                    989:
                    990: /* --------------------------------------------------------------------- */
                    991:
                    992: int
                    993: tmpfs_rmdir(void *v)
                    994: {
                    995:        struct vnode *dvp = ((struct vop_rmdir_args *)v)->a_dvp;
                    996:        struct vnode *vp = ((struct vop_rmdir_args *)v)->a_vp;
                    997:
                    998:        int error;
                    999:        struct tmpfs_dirent *de;
                   1000:        struct tmpfs_mount *tmp;
                   1001:        struct tmpfs_node *dnode;
                   1002:        struct tmpfs_node *node;
                   1003:
                   1004:        KASSERT(VOP_ISLOCKED(dvp));
                   1005:        KASSERT(VOP_ISLOCKED(vp));
                   1006:
                   1007:        tmp = VFS_TO_TMPFS(dvp->v_mount);
                   1008:        dnode = VP_TO_TMPFS_DIR(dvp);
                   1009:        node = VP_TO_TMPFS_DIR(vp);
1.34      pooka    1010:
                   1011:        /* Directories with more than two entries ('.' and '..') cannot be
                   1012:         * removed. */
                   1013:        if (node->tn_size > 0) {
                   1014:                error = ENOTEMPTY;
                   1015:                goto out;
                   1016:        }
                   1017:
                   1018:        /* This invariant holds only if we are not trying to remove "..".
                   1019:         * We checked for that above so this is safe now. */
1.21      jmmv     1020:        KASSERT(node->tn_spec.tn_dir.tn_parent == dnode);
1.1       jmmv     1021:
                   1022:        /* Get the directory entry associated with node (vp).  This was
                   1023:         * filled by tmpfs_lookup while looking up the entry. */
                   1024:        de = node->tn_lookup_dirent;
                   1025:        KASSERT(TMPFS_DIRENT_MATCHES(de,
                   1026:            ((struct vop_rmdir_args *)v)->a_cnp->cn_nameptr,
                   1027:            ((struct vop_rmdir_args *)v)->a_cnp->cn_namelen));
                   1028:
                   1029:        /* Check flags to see if we are allowed to remove the directory. */
                   1030:        if (dnode->tn_flags & APPEND || node->tn_flags & (IMMUTABLE | APPEND)) {
                   1031:                error = EPERM;
                   1032:                goto out;
                   1033:        }
                   1034:
                   1035:        /* Detach the directory entry from the directory (dnode). */
                   1036:        tmpfs_dir_detach(dvp, de);
                   1037:
                   1038:        node->tn_links--;
                   1039:        node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | \
                   1040:            TMPFS_NODE_MODIFIED;
1.21      jmmv     1041:        node->tn_spec.tn_dir.tn_parent->tn_links--;
                   1042:        node->tn_spec.tn_dir.tn_parent->tn_status |= TMPFS_NODE_ACCESSED | \
1.1       jmmv     1043:            TMPFS_NODE_CHANGED | TMPFS_NODE_MODIFIED;
                   1044:
1.31      jmmv     1045:        /* Release the parent. */
1.1       jmmv     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. */
1.37      thorpej  1052:        tmpfs_free_dirent(tmp, de, true);
1.1       jmmv     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) {
1.21      jmmv     1163:                                        de = TAILQ_FIRST(&node->tn_spec.
                   1164:                                            tn_dir.tn_dir);
1.10      yamt     1165:                                } else if (de != NULL) {
                   1166:                                        de = TAILQ_NEXT(de, td_entries);
                   1167:                                } else {
                   1168:                                        de = tmpfs_dir_lookupbycookie(node,
                   1169:                                            off);
                   1170:                                        KASSERT(de != NULL);
                   1171:                                        de = TAILQ_NEXT(de, td_entries);
                   1172:                                }
                   1173:                                if (de == NULL) {
                   1174:                                        off = TMPFS_DIRCOOKIE_EOF;
                   1175:                                } else {
1.29      jmmv     1176:                                        off = tmpfs_dircookie(de);
1.10      yamt     1177:                                }
                   1178:                        }
                   1179:
                   1180:                        (*cookies)[i] = off;
                   1181:                }
                   1182:                KASSERT(uio->uio_offset == off);
1.1       jmmv     1183:        }
                   1184:
                   1185: out:
                   1186:        KASSERT(VOP_ISLOCKED(vp));
                   1187:
                   1188:        return error;
                   1189: }
                   1190:
                   1191: /* --------------------------------------------------------------------- */
                   1192:
                   1193: int
                   1194: tmpfs_readlink(void *v)
                   1195: {
                   1196:        struct vnode *vp = ((struct vop_readlink_args *)v)->a_vp;
                   1197:        struct uio *uio = ((struct vop_readlink_args *)v)->a_uio;
                   1198:
                   1199:        int error;
                   1200:        struct tmpfs_node *node;
                   1201:
                   1202:        KASSERT(VOP_ISLOCKED(vp));
                   1203:        KASSERT(uio->uio_offset == 0);
                   1204:        KASSERT(vp->v_type == VLNK);
                   1205:
                   1206:        node = VP_TO_TMPFS_NODE(vp);
                   1207:
1.21      jmmv     1208:        error = uiomove(node->tn_spec.tn_lnk.tn_link,
                   1209:            MIN(node->tn_size, uio->uio_resid), uio);
1.1       jmmv     1210:        node->tn_status |= TMPFS_NODE_ACCESSED;
                   1211:
                   1212:        KASSERT(VOP_ISLOCKED(vp));
                   1213:
                   1214:        return error;
                   1215: }
                   1216:
                   1217: /* --------------------------------------------------------------------- */
                   1218:
                   1219: int
                   1220: tmpfs_inactive(void *v)
                   1221: {
                   1222:        struct vnode *vp = ((struct vop_inactive_args *)v)->a_vp;
1.19      christos 1223:        struct lwp *l = ((struct vop_inactive_args *)v)->a_l;
1.37.4.2! ad       1224:        nlink_t links;
1.1       jmmv     1225:
                   1226:        struct tmpfs_node *node;
                   1227:
                   1228:        KASSERT(VOP_ISLOCKED(vp));
                   1229:
                   1230:        node = VP_TO_TMPFS_NODE(vp);
1.37.4.2! ad       1231:        links = node->tn_links;
1.1       jmmv     1232:
                   1233:        VOP_UNLOCK(vp, 0);
                   1234:
1.37.4.2! ad       1235:        if (links == 0)
1.19      christos 1236:                vrecycle(vp, NULL, l);
1.1       jmmv     1237:
                   1238:        return 0;
                   1239: }
                   1240:
                   1241: /* --------------------------------------------------------------------- */
                   1242:
                   1243: int
                   1244: tmpfs_reclaim(void *v)
                   1245: {
                   1246:        struct vnode *vp = ((struct vop_reclaim_args *)v)->a_vp;
                   1247:
                   1248:        struct tmpfs_mount *tmp;
                   1249:        struct tmpfs_node *node;
                   1250:
                   1251:        KASSERT(!VOP_ISLOCKED(vp));
                   1252:
                   1253:        node = VP_TO_TMPFS_NODE(vp);
                   1254:        tmp = VFS_TO_TMPFS(vp->v_mount);
                   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
1.15      jmmv     1353: tmpfs_advlock(void *v)
                   1354: {
                   1355:        struct vnode *vp = ((struct vop_advlock_args *)v)->a_vp;
                   1356:
                   1357:        struct tmpfs_node *node;
                   1358:
                   1359:        node = VP_TO_TMPFS_NODE(vp);
                   1360:
                   1361:        return lf_advlock(v, &node->tn_lockf, node->tn_size);
                   1362: }
                   1363:
                   1364: /* --------------------------------------------------------------------- */
                   1365:
                   1366: int
1.1       jmmv     1367: tmpfs_getpages(void *v)
                   1368: {
1.7       jmmv     1369:        struct vnode *vp = ((struct vop_getpages_args *)v)->a_vp;
                   1370:        voff_t offset = ((struct vop_getpages_args *)v)->a_offset;
                   1371:        struct vm_page **m = ((struct vop_getpages_args *)v)->a_m;
                   1372:        int *count = ((struct vop_getpages_args *)v)->a_count;
                   1373:        int centeridx = ((struct vop_getpages_args *)v)->a_centeridx;
                   1374:        vm_prot_t access_type = ((struct vop_getpages_args *)v)->a_access_type;
                   1375:        int advice = ((struct vop_getpages_args *)v)->a_advice;
                   1376:        int flags = ((struct vop_getpages_args *)v)->a_flags;
                   1377:
                   1378:        int error;
1.28      jmmv     1379:        int i;
1.7       jmmv     1380:        struct tmpfs_node *node;
1.6       yamt     1381:        struct uvm_object *uobj;
1.9       yamt     1382:        int npages = *count;
1.1       jmmv     1383:
1.6       yamt     1384:        KASSERT(vp->v_type == VREG);
1.37.4.1  ad       1385:        KASSERT(mutex_owned(&vp->v_interlock));
1.1       jmmv     1386:
1.7       jmmv     1387:        node = VP_TO_TMPFS_NODE(vp);
1.21      jmmv     1388:        uobj = node->tn_spec.tn_reg.tn_aobj;
1.1       jmmv     1389:
1.9       yamt     1390:        /* We currently don't rely on PGO_PASTEOF. */
                   1391:
                   1392:        if (vp->v_size <= offset + (centeridx << PAGE_SHIFT)) {
                   1393:                if ((flags & PGO_LOCKED) == 0)
1.37.4.1  ad       1394:                        mutex_exit(&vp->v_interlock);
1.9       yamt     1395:                return EINVAL;
                   1396:        }
                   1397:
                   1398:        if (vp->v_size < offset + (npages << PAGE_SHIFT)) {
                   1399:                npages = (round_page(vp->v_size) - offset) >> PAGE_SHIFT;
                   1400:        }
                   1401:
1.7       jmmv     1402:        if ((flags & PGO_LOCKED) != 0)
1.6       yamt     1403:                return EBUSY;
1.1       jmmv     1404:
1.6       yamt     1405:        if ((flags & PGO_NOTIMESTAMP) == 0) {
1.7       jmmv     1406:                if ((vp->v_mount->mnt_flag & MNT_NOATIME) == 0)
1.6       yamt     1407:                        node->tn_status |= TMPFS_NODE_ACCESSED;
1.7       jmmv     1408:
                   1409:                if ((access_type & VM_PROT_WRITE) != 0)
1.6       yamt     1410:                        node->tn_status |= TMPFS_NODE_MODIFIED;
1.1       jmmv     1411:        }
                   1412:
1.37.4.1  ad       1413:        mutex_exit(&vp->v_interlock);
1.6       yamt     1414:
1.28      jmmv     1415:        /*
                   1416:         * Make sure that the array on which we will store the
                   1417:         * gotten pages is clean.  Otherwise uao_get (pointed to by
                   1418:         * the pgo_get below) gets confused and does not return the
                   1419:         * appropriate pages.
                   1420:         *
                   1421:         * XXX This shall be revisited when kern/32166 is addressed
                   1422:         * because the loop to clean m[i] will most likely be redundant
                   1423:         * as well as the PGO_ALLPAGES flag.
                   1424:         */
                   1425:        if (m != NULL)
                   1426:                for (i = 0; i < npages; i++)
                   1427:                        m[i] = NULL;
1.37.4.1  ad       1428:        mutex_enter(&uobj->vmobjlock);
1.9       yamt     1429:        error = (*uobj->pgops->pgo_get)(uobj, offset, m, &npages, centeridx,
1.28      jmmv     1430:            access_type, advice, flags | PGO_ALLPAGES);
                   1431: #if defined(DEBUG)
                   1432:        {
                   1433:                /* Make sure that all the pages we return are valid. */
                   1434:                int dbgi;
                   1435:                if (error == 0 && m != NULL)
                   1436:                        for (dbgi = 0; dbgi < npages; dbgi++)
                   1437:                                KASSERT(m[dbgi] != NULL);
                   1438:        }
                   1439: #endif
1.1       jmmv     1440:
1.6       yamt     1441:        return error;
                   1442: }
                   1443:
                   1444: /* --------------------------------------------------------------------- */
                   1445:
                   1446: int
                   1447: tmpfs_putpages(void *v)
                   1448: {
1.7       jmmv     1449:        struct vnode *vp = ((struct vop_putpages_args *)v)->a_vp;
                   1450:        voff_t offlo = ((struct vop_putpages_args *)v)->a_offlo;
                   1451:        voff_t offhi = ((struct vop_putpages_args *)v)->a_offhi;
                   1452:        int flags = ((struct vop_putpages_args *)v)->a_flags;
                   1453:
                   1454:        int error;
                   1455:        struct tmpfs_node *node;
1.6       yamt     1456:        struct uvm_object *uobj;
                   1457:
1.37.4.1  ad       1458:        KASSERT(mutex_owned(&vp->v_interlock));
1.6       yamt     1459:
1.7       jmmv     1460:        node = VP_TO_TMPFS_NODE(vp);
                   1461:
1.6       yamt     1462:        if (vp->v_type != VREG) {
1.37.4.1  ad       1463:                mutex_exit(&vp->v_interlock);
1.6       yamt     1464:                return 0;
1.1       jmmv     1465:        }
                   1466:
1.21      jmmv     1467:        uobj = node->tn_spec.tn_reg.tn_aobj;
1.37.4.1  ad       1468:        mutex_exit(&vp->v_interlock);
1.6       yamt     1469:
1.37.4.1  ad       1470:        mutex_enter(&uobj->vmobjlock);
1.7       jmmv     1471:        error = (*uobj->pgops->pgo_put)(uobj, offlo, offhi, flags);
1.6       yamt     1472:
                   1473:        /* XXX mtime */
1.1       jmmv     1474:
                   1475:        return error;
                   1476: }

CVSweb <webmaster@jp.NetBSD.org>