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

Annotation of src/sys/fs/tmpfs/tmpfs_vfsops.c, Revision 1.27.4.3

1.27.4.3! matt        1: /*     $NetBSD: tmpfs_vfsops.c,v 1.27.4.2 2007/11/08 10:59:58 matt Exp $       */
1.1       jmmv        2:
                      3: /*
1.27.4.2  matt        4:  * Copyright (c) 2005, 2006, 2007 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.6       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: /*
1.2       jmmv       41:  * Efficient memory file system.
1.6       jmmv       42:  *
                     43:  * tmpfs is a file system that uses NetBSD's virtual memory sub-system
                     44:  * (the well-known UVM) to store file data and metadata in an efficient
                     45:  * way.  This means that it does not follow the structure of an on-disk
                     46:  * file system because it simply does not need to.  Instead, it uses
                     47:  * memory-specific data structures and algorithms to automatically
                     48:  * allocate and release resources.
1.1       jmmv       49:  */
                     50:
                     51: #include <sys/cdefs.h>
1.27.4.3! matt       52: __KERNEL_RCSID(0, "$NetBSD: tmpfs_vfsops.c,v 1.27.4.2 2007/11/08 10:59:58 matt Exp $");
1.1       jmmv       53:
                     54: #include <sys/param.h>
                     55: #include <sys/types.h>
1.27.4.2  matt       56: #include <sys/kmem.h>
1.1       jmmv       57: #include <sys/mount.h>
1.8       jmmv       58: #include <sys/stat.h>
1.1       jmmv       59: #include <sys/systm.h>
                     60: #include <sys/vnode.h>
1.22      ad         61: #include <sys/proc.h>
1.1       jmmv       62:
                     63: #include <fs/tmpfs/tmpfs.h>
                     64:
                     65: /* --------------------------------------------------------------------- */
                     66:
1.27.4.3! matt       67: static int     tmpfs_mount(struct mount *, const char *, void *, size_t *);
        !            68: static int     tmpfs_start(struct mount *, int);
        !            69: static int     tmpfs_unmount(struct mount *, int);
1.1       jmmv       70: static int     tmpfs_root(struct mount *, struct vnode **);
                     71: static int     tmpfs_vget(struct mount *, ino_t, struct vnode **);
                     72: static int     tmpfs_fhtovp(struct mount *, struct fid *, struct vnode **);
1.13      martin     73: static int     tmpfs_vptofh(struct vnode *, struct fid *, size_t *);
1.27.4.3! matt       74: static int     tmpfs_statvfs(struct mount *, struct statvfs *);
        !            75: static int     tmpfs_sync(struct mount *, int, kauth_cred_t);
1.1       jmmv       76: static void    tmpfs_init(void);
                     77: static void    tmpfs_done(void);
                     78: static int     tmpfs_snapshot(struct mount *, struct vnode *,
                     79:                    struct timespec *);
                     80:
                     81: /* --------------------------------------------------------------------- */
                     82:
                     83: static int
1.27.4.3! matt       84: tmpfs_mount(struct mount *mp, const char *path, void *data, size_t *data_len)
1.1       jmmv       85: {
1.27.4.3! matt       86:        struct lwp *l = curlwp;
1.1       jmmv       87:        int error;
                     88:        ino_t nodes;
                     89:        size_t pages;
                     90:        struct tmpfs_mount *tmp;
                     91:        struct tmpfs_node *root;
1.23      dsl        92:        struct tmpfs_args *args = data;
                     93:
                     94:        if (*data_len < sizeof *args)
                     95:                return EINVAL;
1.1       jmmv       96:
                     97:        /* Handle retrieval of mount point arguments. */
                     98:        if (mp->mnt_flag & MNT_GETARGS) {
                     99:                if (mp->mnt_data == NULL)
                    100:                        return EIO;
                    101:                tmp = VFS_TO_TMPFS(mp);
                    102:
1.23      dsl       103:                args->ta_version = TMPFS_ARGS_VERSION;
                    104:                args->ta_nodes_max = tmp->tm_nodes_max;
                    105:                args->ta_size_max = tmp->tm_pages_max * PAGE_SIZE;
1.27.4.2  matt      106:
1.27.4.3! matt      107:                root = tmp->tm_root;
1.23      dsl       108:                args->ta_root_uid = root->tn_uid;
                    109:                args->ta_root_gid = root->tn_gid;
                    110:                args->ta_root_mode = root->tn_mode;
1.1       jmmv      111:
1.23      dsl       112:                *data_len = sizeof *args;
                    113:                return 0;
1.1       jmmv      114:        }
                    115:
                    116:        if (mp->mnt_flag & MNT_UPDATE) {
1.2       jmmv      117:                /* XXX: There is no support yet to update file system
1.1       jmmv      118:                 * settings.  Should be added. */
                    119:
                    120:                return EOPNOTSUPP;
                    121:        }
                    122:
1.23      dsl       123:        if (args->ta_version != TMPFS_ARGS_VERSION)
1.1       jmmv      124:                return EINVAL;
                    125:
                    126:        /* Do not allow mounts if we do not have enough memory to preserve
                    127:         * the minimum reserved pages. */
1.20      thorpej   128:        if (tmpfs_mem_info(true) < TMPFS_PAGES_RESERVED)
1.1       jmmv      129:                return EINVAL;
                    130:
1.2       jmmv      131:        /* Get the maximum number of memory pages this file system is
1.1       jmmv      132:         * allowed to use, based on the maximum size the user passed in
                    133:         * the mount structure.  A value of zero is treated as if the
                    134:         * maximum available space was requested. */
1.23      dsl       135:        if (args->ta_size_max < PAGE_SIZE || args->ta_size_max >= SIZE_MAX)
1.1       jmmv      136:                pages = SIZE_MAX;
                    137:        else
1.23      dsl       138:                pages = args->ta_size_max / PAGE_SIZE +
                    139:                    (args->ta_size_max % PAGE_SIZE == 0 ? 0 : 1);
1.7       jmmv      140:        KASSERT(pages > 0);
1.1       jmmv      141:
1.23      dsl       142:        if (args->ta_nodes_max <= 3)
1.7       jmmv      143:                nodes = 3 + pages * PAGE_SIZE / 1024;
1.1       jmmv      144:        else
1.23      dsl       145:                nodes = args->ta_nodes_max;
1.7       jmmv      146:        KASSERT(nodes >= 3);
1.1       jmmv      147:
                    148:        /* Allocate the tmpfs mount structure and fill it. */
1.27.4.2  matt      149:        tmp = kmem_alloc(sizeof(struct tmpfs_mount), KM_SLEEP);
                    150:        if (tmp == NULL)
                    151:                return ENOMEM;
1.1       jmmv      152:
                    153:        tmp->tm_nodes_max = nodes;
1.27.4.2  matt      154:        tmp->tm_nodes_cnt = 0;
                    155:        LIST_INIT(&tmp->tm_nodes);
                    156:
                    157:        mutex_init(&tmp->tm_lock, MUTEX_DEFAULT, IPL_NONE);
1.1       jmmv      158:
                    159:        tmp->tm_pages_max = pages;
                    160:        tmp->tm_pages_used = 0;
                    161:        tmpfs_pool_init(&tmp->tm_dirent_pool, sizeof(struct tmpfs_dirent),
                    162:            "dirent", tmp);
                    163:        tmpfs_pool_init(&tmp->tm_node_pool, sizeof(struct tmpfs_node),
                    164:            "node", tmp);
                    165:        tmpfs_str_pool_init(&tmp->tm_str_pool, tmp);
                    166:
                    167:        /* Allocate the root node. */
1.23      dsl       168:        error = tmpfs_alloc_node(tmp, VDIR, args->ta_root_uid,
                    169:            args->ta_root_gid, args->ta_root_mode & ALLPERMS, NULL, NULL,
1.27.4.3! matt      170:            VNOVAL, &root);
1.1       jmmv      171:        KASSERT(error == 0 && root != NULL);
1.27.4.3! matt      172:        root->tn_links++;
1.1       jmmv      173:        tmp->tm_root = root;
                    174:
                    175:        mp->mnt_data = tmp;
                    176:        mp->mnt_flag |= MNT_LOCAL;
                    177:        mp->mnt_stat.f_namemax = MAXNAMLEN;
1.27      pooka     178:        mp->mnt_fs_bshift = PAGE_SHIFT;
                    179:        mp->mnt_dev_bshift = DEV_BSHIFT;
1.27.4.2  matt      180:        mp->mnt_iflag |= IMNT_MPSAFE;
1.1       jmmv      181:        vfs_getnewfsid(mp);
                    182:
                    183:        return set_statvfs_info(path, UIO_USERSPACE, "tmpfs", UIO_SYSSPACE,
1.24      pooka     184:            mp->mnt_op->vfs_name, mp, l);
1.1       jmmv      185: }
                    186:
                    187: /* --------------------------------------------------------------------- */
                    188:
                    189: static int
1.27.4.3! matt      190: tmpfs_start(struct mount *mp, int flags)
1.1       jmmv      191: {
                    192:
                    193:        return 0;
                    194: }
                    195:
                    196: /* --------------------------------------------------------------------- */
                    197:
                    198: /* ARGSUSED2 */
                    199: static int
1.27.4.3! matt      200: tmpfs_unmount(struct mount *mp, int mntflags)
1.1       jmmv      201: {
                    202:        int error;
                    203:        int flags = 0;
                    204:        struct tmpfs_mount *tmp;
                    205:        struct tmpfs_node *node;
                    206:
                    207:        /* Handle forced unmounts. */
                    208:        if (mntflags & MNT_FORCE)
                    209:                flags |= FORCECLOSE;
                    210:
                    211:        /* Finalize all pending I/O. */
                    212:        error = vflush(mp, NULL, flags);
                    213:        if (error != 0)
                    214:                return error;
                    215:
                    216:        tmp = VFS_TO_TMPFS(mp);
                    217:
                    218:        /* Free all associated data.  The loop iterates over the linked list
                    219:         * we have containing all used nodes.  For each of them that is
                    220:         * a directory, we free all its directory entries.  Note that after
                    221:         * freeing a node, it will automatically go to the available list,
                    222:         * so we will later have to iterate over it to release its items. */
1.27.4.3! matt      223:        node = LIST_FIRST(&tmp->tm_nodes);
        !           224:        while (node != NULL) {
        !           225:                struct tmpfs_node *next;
        !           226:
1.1       jmmv      227:                if (node->tn_type == VDIR) {
                    228:                        struct tmpfs_dirent *de;
                    229:
1.11      jmmv      230:                        de = TAILQ_FIRST(&node->tn_spec.tn_dir.tn_dir);
1.1       jmmv      231:                        while (de != NULL) {
                    232:                                struct tmpfs_dirent *nde;
                    233:
                    234:                                nde = TAILQ_NEXT(de, td_entries);
1.16      jmmv      235:                                KASSERT(de->td_node->tn_vnode == NULL);
1.20      thorpej   236:                                tmpfs_free_dirent(tmp, de, false);
1.1       jmmv      237:                                de = nde;
                    238:                                node->tn_size -= sizeof(struct tmpfs_dirent);
                    239:                        }
                    240:                }
                    241:
1.27.4.3! matt      242:                next = LIST_NEXT(node, tn_entries);
1.1       jmmv      243:                tmpfs_free_node(tmp, node);
1.27.4.3! matt      244:                node = next;
1.1       jmmv      245:        }
                    246:
                    247:        tmpfs_pool_destroy(&tmp->tm_dirent_pool);
                    248:        tmpfs_pool_destroy(&tmp->tm_node_pool);
                    249:        tmpfs_str_pool_destroy(&tmp->tm_str_pool);
                    250:
                    251:        KASSERT(tmp->tm_pages_used == 0);
                    252:
                    253:        /* Throw away the tmpfs_mount structure. */
1.27.4.2  matt      254:        mutex_destroy(&tmp->tm_lock);
                    255:        kmem_free(tmp, sizeof(*tmp));
1.1       jmmv      256:        mp->mnt_data = NULL;
                    257:
                    258:        return 0;
                    259: }
                    260:
                    261: /* --------------------------------------------------------------------- */
                    262:
                    263: static int
                    264: tmpfs_root(struct mount *mp, struct vnode **vpp)
                    265: {
                    266:
                    267:        return tmpfs_alloc_vp(mp, VFS_TO_TMPFS(mp)->tm_root, vpp);
                    268: }
                    269:
                    270: /* --------------------------------------------------------------------- */
                    271:
                    272: static int
1.17      christos  273: tmpfs_vget(struct mount *mp, ino_t ino,
                    274:     struct vnode **vpp)
1.1       jmmv      275: {
                    276:
                    277:        printf("tmpfs_vget called; need for it unknown yet\n");
                    278:        return EOPNOTSUPP;
                    279: }
                    280:
                    281: /* --------------------------------------------------------------------- */
                    282:
                    283: static int
                    284: tmpfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
                    285: {
1.19      thorpej   286:        bool found;
1.13      martin    287:        struct tmpfs_fid tfh;
1.1       jmmv      288:        struct tmpfs_mount *tmp;
                    289:        struct tmpfs_node *node;
                    290:
                    291:        tmp = VFS_TO_TMPFS(mp);
                    292:
1.13      martin    293:        if (fhp->fid_len != sizeof(struct tmpfs_fid))
1.1       jmmv      294:                return EINVAL;
                    295:
1.13      martin    296:        memcpy(&tfh, fhp, sizeof(struct tmpfs_fid));
                    297:
1.27.4.3! matt      298:        if (tfh.tf_id >= tmp->tm_nodes_max)
1.1       jmmv      299:                return EINVAL;
                    300:
1.20      thorpej   301:        found = false;
1.27.4.3! matt      302:        mutex_enter(&tmp->tm_lock);
1.27.4.2  matt      303:        LIST_FOREACH(node, &tmp->tm_nodes, tn_entries) {
1.13      martin    304:                if (node->tn_id == tfh.tf_id &&
                    305:                    node->tn_gen == tfh.tf_gen) {
1.20      thorpej   306:                        found = true;
1.1       jmmv      307:                        break;
                    308:                }
                    309:        }
1.27.4.2  matt      310:        mutex_exit(&tmp->tm_lock);
1.1       jmmv      311:
1.27.4.2  matt      312:        /* XXXAD nothing to prevent 'node' from being removed. */
1.1       jmmv      313:        return found ? tmpfs_alloc_vp(mp, node, vpp) : EINVAL;
                    314: }
                    315:
                    316: /* --------------------------------------------------------------------- */
                    317:
                    318: static int
1.13      martin    319: tmpfs_vptofh(struct vnode *vp, struct fid *fhp, size_t *fh_size)
1.1       jmmv      320: {
1.13      martin    321:        struct tmpfs_fid tfh;
1.1       jmmv      322:        struct tmpfs_node *node;
                    323:
1.13      martin    324:        if (*fh_size < sizeof(struct tmpfs_fid)) {
                    325:                *fh_size = sizeof(struct tmpfs_fid);
                    326:                return E2BIG;
                    327:        }
                    328:        *fh_size = sizeof(struct tmpfs_fid);
1.1       jmmv      329:        node = VP_TO_TMPFS_NODE(vp);
                    330:
1.13      martin    331:        memset(&tfh, 0, sizeof(tfh));
                    332:        tfh.tf_len = sizeof(struct tmpfs_fid);
                    333:        tfh.tf_gen = node->tn_gen;
                    334:        tfh.tf_id = node->tn_id;
                    335:        memcpy(fhp, &tfh, sizeof(tfh));
1.1       jmmv      336:
                    337:        return 0;
                    338: }
                    339:
                    340: /* --------------------------------------------------------------------- */
                    341:
                    342: /* ARGSUSED2 */
                    343: static int
1.27.4.3! matt      344: tmpfs_statvfs(struct mount *mp, struct statvfs *sbp)
1.1       jmmv      345: {
1.27.4.2  matt      346:        fsfilcnt_t freenodes;
1.1       jmmv      347:        struct tmpfs_mount *tmp;
                    348:
                    349:        tmp = VFS_TO_TMPFS(mp);
                    350:
                    351:        sbp->f_iosize = sbp->f_frsize = sbp->f_bsize = PAGE_SIZE;
                    352:
                    353:        sbp->f_blocks = TMPFS_PAGES_MAX(tmp);
                    354:        sbp->f_bavail = sbp->f_bfree = TMPFS_PAGES_AVAIL(tmp);
                    355:        sbp->f_bresvd = 0;
                    356:
1.27.4.2  matt      357:        freenodes = MIN(tmp->tm_nodes_max - tmp->tm_nodes_cnt,
1.1       jmmv      358:            TMPFS_PAGES_AVAIL(tmp) * PAGE_SIZE / sizeof(struct tmpfs_node));
                    359:
1.27.4.2  matt      360:        sbp->f_files = tmp->tm_nodes_cnt + freenodes;
1.1       jmmv      361:        sbp->f_favail = sbp->f_ffree = freenodes;
                    362:        sbp->f_fresvd = 0;
                    363:
                    364:        copy_statvfs_info(sbp, mp);
                    365:
                    366:        return 0;
                    367: }
                    368:
                    369: /* --------------------------------------------------------------------- */
                    370:
                    371: /* ARGSUSED0 */
                    372: static int
1.17      christos  373: tmpfs_sync(struct mount *mp, int waitfor,
1.27.4.3! matt      374:     kauth_cred_t uc)
1.1       jmmv      375: {
                    376:
                    377:        return 0;
                    378: }
                    379:
                    380: /* --------------------------------------------------------------------- */
                    381:
                    382: static void
                    383: tmpfs_init(void)
                    384: {
                    385:
                    386: }
                    387:
                    388: /* --------------------------------------------------------------------- */
                    389:
                    390: static void
                    391: tmpfs_done(void)
                    392: {
                    393:
                    394: }
                    395:
                    396: /* --------------------------------------------------------------------- */
                    397:
                    398: static int
1.17      christos  399: tmpfs_snapshot(struct mount *mp, struct vnode *vp,
                    400:     struct timespec *ctime)
1.1       jmmv      401: {
                    402:
                    403:        return EOPNOTSUPP;
                    404: }
                    405:
                    406: /* --------------------------------------------------------------------- */
                    407:
                    408: /*
                    409:  * tmpfs vfs operations.
                    410:  */
                    411:
                    412: extern const struct vnodeopv_desc tmpfs_fifoop_opv_desc;
                    413: extern const struct vnodeopv_desc tmpfs_specop_opv_desc;
                    414: extern const struct vnodeopv_desc tmpfs_vnodeop_opv_desc;
                    415:
                    416: const struct vnodeopv_desc * const tmpfs_vnodeopv_descs[] = {
                    417:        &tmpfs_fifoop_opv_desc,
                    418:        &tmpfs_specop_opv_desc,
                    419:        &tmpfs_vnodeop_opv_desc,
                    420:        NULL,
                    421: };
                    422:
                    423: struct vfsops tmpfs_vfsops = {
                    424:        MOUNT_TMPFS,                    /* vfs_name */
1.23      dsl       425:        sizeof (struct tmpfs_args),
1.1       jmmv      426:        tmpfs_mount,                    /* vfs_mount */
                    427:        tmpfs_start,                    /* vfs_start */
                    428:        tmpfs_unmount,                  /* vfs_unmount */
                    429:        tmpfs_root,                     /* vfs_root */
1.27.4.3! matt      430:        (void *)eopnotsupp,             /* vfs_quotactl */
1.1       jmmv      431:        tmpfs_statvfs,                  /* vfs_statvfs */
                    432:        tmpfs_sync,                     /* vfs_sync */
                    433:        tmpfs_vget,                     /* vfs_vget */
                    434:        tmpfs_fhtovp,                   /* vfs_fhtovp */
                    435:        tmpfs_vptofh,                   /* vfs_vptofh */
                    436:        tmpfs_init,                     /* vfs_init */
                    437:        NULL,                           /* vfs_reinit */
                    438:        tmpfs_done,                     /* vfs_done */
                    439:        NULL,                           /* vfs_mountroot */
                    440:        tmpfs_snapshot,                 /* vfs_snapshot */
                    441:        vfs_stdextattrctl,              /* vfs_extattrctl */
1.25      pooka     442:        (void *)eopnotsupp,             /* vfs_suspendctl */
1.1       jmmv      443:        tmpfs_vnodeopv_descs,
1.14      christos  444:        0,                              /* vfs_refcount */
                    445:        { NULL, NULL },
1.1       jmmv      446: };
                    447: VFS_ATTACH(tmpfs_vfsops);

CVSweb <webmaster@jp.NetBSD.org>