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

1.33    ! pooka       1: /*     $NetBSD: tmpfs_vfsops.c,v 1.32 2007/11/26 19:01:55 pooka Exp $  */
1.1       jmmv        2:
                      3: /*
1.31      ad          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.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.33    ! pooka      52: __KERNEL_RCSID(0, "$NetBSD: tmpfs_vfsops.c,v 1.32 2007/11/26 19:01:55 pooka Exp $");
1.1       jmmv       53:
                     54: #include <sys/param.h>
                     55: #include <sys/types.h>
1.31      ad         56: #include <sys/malloc.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:
1.31      ad         65: MALLOC_JUSTDEFINE(M_TMPFSMNT, "tmpfs mount", "tmpfs mount structures");
                     66: MALLOC_JUSTDEFINE(M_TMPFSTMP, "tmpfs temp", "tmpfs temporary structures");
                     67:
1.1       jmmv       68: /* --------------------------------------------------------------------- */
                     69:
1.32      pooka      70: static int     tmpfs_mount(struct mount *, const char *, void *, size_t *);
                     71: static int     tmpfs_start(struct mount *, int);
                     72: static int     tmpfs_unmount(struct mount *, int);
1.1       jmmv       73: static int     tmpfs_root(struct mount *, struct vnode **);
                     74: static int     tmpfs_vget(struct mount *, ino_t, struct vnode **);
                     75: static int     tmpfs_fhtovp(struct mount *, struct fid *, struct vnode **);
1.13      martin     76: static int     tmpfs_vptofh(struct vnode *, struct fid *, size_t *);
1.32      pooka      77: static int     tmpfs_statvfs(struct mount *, struct statvfs *);
                     78: static int     tmpfs_sync(struct mount *, int, kauth_cred_t);
1.1       jmmv       79: static void    tmpfs_init(void);
                     80: static void    tmpfs_done(void);
                     81: static int     tmpfs_snapshot(struct mount *, struct vnode *,
                     82:                    struct timespec *);
                     83:
                     84: /* --------------------------------------------------------------------- */
                     85:
                     86: static int
1.32      pooka      87: tmpfs_mount(struct mount *mp, const char *path, void *data, size_t *data_len)
1.1       jmmv       88: {
1.32      pooka      89:        struct lwp *l = curlwp;
1.1       jmmv       90:        int error;
                     91:        ino_t nodes;
                     92:        size_t pages;
                     93:        struct tmpfs_mount *tmp;
                     94:        struct tmpfs_node *root;
1.23      dsl        95:        struct tmpfs_args *args = data;
                     96:
                     97:        if (*data_len < sizeof *args)
                     98:                return EINVAL;
1.1       jmmv       99:
                    100:        /* Handle retrieval of mount point arguments. */
                    101:        if (mp->mnt_flag & MNT_GETARGS) {
                    102:                if (mp->mnt_data == NULL)
                    103:                        return EIO;
                    104:                tmp = VFS_TO_TMPFS(mp);
                    105:
1.23      dsl       106:                args->ta_version = TMPFS_ARGS_VERSION;
                    107:                args->ta_nodes_max = tmp->tm_nodes_max;
                    108:                args->ta_size_max = tmp->tm_pages_max * PAGE_SIZE;
1.31      ad        109:
1.30      ad        110:                root = tmp->tm_root;
1.23      dsl       111:                args->ta_root_uid = root->tn_uid;
                    112:                args->ta_root_gid = root->tn_gid;
                    113:                args->ta_root_mode = root->tn_mode;
1.1       jmmv      114:
1.23      dsl       115:                *data_len = sizeof *args;
                    116:                return 0;
1.1       jmmv      117:        }
                    118:
                    119:        if (mp->mnt_flag & MNT_UPDATE) {
1.2       jmmv      120:                /* XXX: There is no support yet to update file system
1.1       jmmv      121:                 * settings.  Should be added. */
                    122:
                    123:                return EOPNOTSUPP;
                    124:        }
                    125:
1.23      dsl       126:        if (args->ta_version != TMPFS_ARGS_VERSION)
1.1       jmmv      127:                return EINVAL;
                    128:
                    129:        /* Do not allow mounts if we do not have enough memory to preserve
                    130:         * the minimum reserved pages. */
1.20      thorpej   131:        if (tmpfs_mem_info(true) < TMPFS_PAGES_RESERVED)
1.1       jmmv      132:                return EINVAL;
                    133:
1.2       jmmv      134:        /* Get the maximum number of memory pages this file system is
1.1       jmmv      135:         * allowed to use, based on the maximum size the user passed in
                    136:         * the mount structure.  A value of zero is treated as if the
                    137:         * maximum available space was requested. */
1.23      dsl       138:        if (args->ta_size_max < PAGE_SIZE || args->ta_size_max >= SIZE_MAX)
1.1       jmmv      139:                pages = SIZE_MAX;
                    140:        else
1.23      dsl       141:                pages = args->ta_size_max / PAGE_SIZE +
                    142:                    (args->ta_size_max % PAGE_SIZE == 0 ? 0 : 1);
1.7       jmmv      143:        KASSERT(pages > 0);
1.1       jmmv      144:
1.23      dsl       145:        if (args->ta_nodes_max <= 3)
1.7       jmmv      146:                nodes = 3 + pages * PAGE_SIZE / 1024;
1.1       jmmv      147:        else
1.23      dsl       148:                nodes = args->ta_nodes_max;
1.7       jmmv      149:        KASSERT(nodes >= 3);
1.1       jmmv      150:
                    151:        /* Allocate the tmpfs mount structure and fill it. */
1.31      ad        152:        tmp = (struct tmpfs_mount *)malloc(sizeof(struct tmpfs_mount),
                    153:            M_TMPFSMNT, M_WAITOK);
                    154:        KASSERT(tmp != NULL);
1.1       jmmv      155:
                    156:        tmp->tm_nodes_max = nodes;
1.31      ad        157:        tmp->tm_nodes_last = 2;
                    158:        LIST_INIT(&tmp->tm_nodes_used);
                    159:        LIST_INIT(&tmp->tm_nodes_avail);
1.1       jmmv      160:
                    161:        tmp->tm_pages_max = pages;
                    162:        tmp->tm_pages_used = 0;
                    163:        tmpfs_pool_init(&tmp->tm_dirent_pool, sizeof(struct tmpfs_dirent),
                    164:            "dirent", tmp);
                    165:        tmpfs_pool_init(&tmp->tm_node_pool, sizeof(struct tmpfs_node),
                    166:            "node", tmp);
                    167:        tmpfs_str_pool_init(&tmp->tm_str_pool, tmp);
                    168:
                    169:        /* Allocate the root node. */
1.23      dsl       170:        error = tmpfs_alloc_node(tmp, VDIR, args->ta_root_uid,
                    171:            args->ta_root_gid, args->ta_root_mode & ALLPERMS, NULL, NULL,
1.33    ! pooka     172:            VNOVAL, &root);
1.1       jmmv      173:        KASSERT(error == 0 && root != NULL);
                    174:        tmp->tm_root = root;
                    175:
                    176:        mp->mnt_data = tmp;
                    177:        mp->mnt_flag |= MNT_LOCAL;
                    178:        mp->mnt_stat.f_namemax = MAXNAMLEN;
1.27      pooka     179:        mp->mnt_fs_bshift = PAGE_SHIFT;
                    180:        mp->mnt_dev_bshift = DEV_BSHIFT;
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.32      pooka     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.32      pooka     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.31      ad        223:        node = LIST_FIRST(&tmp->tm_nodes_used);
                    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.31      ad        242:                next = LIST_NEXT(node, tn_entries);
1.1       jmmv      243:                tmpfs_free_node(tmp, node);
1.31      ad        244:                node = next;
                    245:        }
                    246:        node = LIST_FIRST(&tmp->tm_nodes_avail);
                    247:        while (node != NULL) {
                    248:                struct tmpfs_node *next;
                    249:
                    250:                next = LIST_NEXT(node, tn_entries);
                    251:                LIST_REMOVE(node, tn_entries);
                    252:                TMPFS_POOL_PUT(&tmp->tm_node_pool, node);
                    253:                node = next;
1.1       jmmv      254:        }
                    255:
                    256:        tmpfs_pool_destroy(&tmp->tm_dirent_pool);
                    257:        tmpfs_pool_destroy(&tmp->tm_node_pool);
                    258:        tmpfs_str_pool_destroy(&tmp->tm_str_pool);
                    259:
                    260:        KASSERT(tmp->tm_pages_used == 0);
                    261:
                    262:        /* Throw away the tmpfs_mount structure. */
1.31      ad        263:        free(mp->mnt_data, M_TMPFSMNT);
1.1       jmmv      264:        mp->mnt_data = NULL;
                    265:
                    266:        return 0;
                    267: }
                    268:
                    269: /* --------------------------------------------------------------------- */
                    270:
                    271: static int
                    272: tmpfs_root(struct mount *mp, struct vnode **vpp)
                    273: {
                    274:
                    275:        return tmpfs_alloc_vp(mp, VFS_TO_TMPFS(mp)->tm_root, vpp);
                    276: }
                    277:
                    278: /* --------------------------------------------------------------------- */
                    279:
                    280: static int
1.17      christos  281: tmpfs_vget(struct mount *mp, ino_t ino,
                    282:     struct vnode **vpp)
1.1       jmmv      283: {
                    284:
                    285:        printf("tmpfs_vget called; need for it unknown yet\n");
                    286:        return EOPNOTSUPP;
                    287: }
                    288:
                    289: /* --------------------------------------------------------------------- */
                    290:
                    291: static int
                    292: tmpfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
                    293: {
1.19      thorpej   294:        bool found;
1.13      martin    295:        struct tmpfs_fid tfh;
1.1       jmmv      296:        struct tmpfs_mount *tmp;
                    297:        struct tmpfs_node *node;
                    298:
                    299:        tmp = VFS_TO_TMPFS(mp);
                    300:
1.13      martin    301:        if (fhp->fid_len != sizeof(struct tmpfs_fid))
1.1       jmmv      302:                return EINVAL;
                    303:
1.13      martin    304:        memcpy(&tfh, fhp, sizeof(struct tmpfs_fid));
                    305:
1.31      ad        306:        if (tfh.tf_id >= tmp->tm_nodes_max)
1.1       jmmv      307:                return EINVAL;
                    308:
1.20      thorpej   309:        found = false;
1.31      ad        310:        LIST_FOREACH(node, &tmp->tm_nodes_used, tn_entries) {
1.13      martin    311:                if (node->tn_id == tfh.tf_id &&
                    312:                    node->tn_gen == tfh.tf_gen) {
1.20      thorpej   313:                        found = true;
1.1       jmmv      314:                        break;
                    315:                }
                    316:        }
                    317:
                    318:        return found ? tmpfs_alloc_vp(mp, node, vpp) : EINVAL;
                    319: }
                    320:
                    321: /* --------------------------------------------------------------------- */
                    322:
                    323: static int
1.13      martin    324: tmpfs_vptofh(struct vnode *vp, struct fid *fhp, size_t *fh_size)
1.1       jmmv      325: {
1.13      martin    326:        struct tmpfs_fid tfh;
1.1       jmmv      327:        struct tmpfs_node *node;
                    328:
1.13      martin    329:        if (*fh_size < sizeof(struct tmpfs_fid)) {
                    330:                *fh_size = sizeof(struct tmpfs_fid);
                    331:                return E2BIG;
                    332:        }
                    333:        *fh_size = sizeof(struct tmpfs_fid);
1.1       jmmv      334:        node = VP_TO_TMPFS_NODE(vp);
                    335:
1.13      martin    336:        memset(&tfh, 0, sizeof(tfh));
                    337:        tfh.tf_len = sizeof(struct tmpfs_fid);
                    338:        tfh.tf_gen = node->tn_gen;
                    339:        tfh.tf_id = node->tn_id;
                    340:        memcpy(fhp, &tfh, sizeof(tfh));
1.1       jmmv      341:
                    342:        return 0;
                    343: }
                    344:
                    345: /* --------------------------------------------------------------------- */
                    346:
                    347: /* ARGSUSED2 */
                    348: static int
1.32      pooka     349: tmpfs_statvfs(struct mount *mp, struct statvfs *sbp)
1.1       jmmv      350: {
1.31      ad        351:        fsfilcnt_t freenodes, usednodes;
1.1       jmmv      352:        struct tmpfs_mount *tmp;
1.31      ad        353:        struct tmpfs_node *dummy;
1.1       jmmv      354:
                    355:        tmp = VFS_TO_TMPFS(mp);
                    356:
                    357:        sbp->f_iosize = sbp->f_frsize = sbp->f_bsize = PAGE_SIZE;
                    358:
                    359:        sbp->f_blocks = TMPFS_PAGES_MAX(tmp);
                    360:        sbp->f_bavail = sbp->f_bfree = TMPFS_PAGES_AVAIL(tmp);
                    361:        sbp->f_bresvd = 0;
                    362:
1.31      ad        363:        freenodes = MIN(tmp->tm_nodes_max - tmp->tm_nodes_last,
1.1       jmmv      364:            TMPFS_PAGES_AVAIL(tmp) * PAGE_SIZE / sizeof(struct tmpfs_node));
1.31      ad        365:        LIST_FOREACH(dummy, &tmp->tm_nodes_avail, tn_entries)
                    366:                freenodes++;
1.1       jmmv      367:
1.31      ad        368:        usednodes = 0;
                    369:        LIST_FOREACH(dummy, &tmp->tm_nodes_used, tn_entries)
                    370:                usednodes++;
                    371:
                    372:        sbp->f_files = freenodes + usednodes;
1.1       jmmv      373:        sbp->f_favail = sbp->f_ffree = freenodes;
                    374:        sbp->f_fresvd = 0;
                    375:
                    376:        copy_statvfs_info(sbp, mp);
                    377:
                    378:        return 0;
                    379: }
                    380:
                    381: /* --------------------------------------------------------------------- */
                    382:
                    383: /* ARGSUSED0 */
                    384: static int
1.17      christos  385: tmpfs_sync(struct mount *mp, int waitfor,
1.32      pooka     386:     kauth_cred_t uc)
1.1       jmmv      387: {
                    388:
                    389:        return 0;
                    390: }
                    391:
                    392: /* --------------------------------------------------------------------- */
                    393:
                    394: static void
                    395: tmpfs_init(void)
                    396: {
                    397:
1.31      ad        398:        malloc_type_attach(M_TMPFSMNT);
                    399:        malloc_type_attach(M_TMPFSTMP);
1.1       jmmv      400: }
                    401:
                    402: /* --------------------------------------------------------------------- */
                    403:
                    404: static void
                    405: tmpfs_done(void)
                    406: {
                    407:
1.31      ad        408:        malloc_type_detach(M_TMPFSTMP);
                    409:        malloc_type_detach(M_TMPFSMNT);
1.1       jmmv      410: }
                    411:
                    412: /* --------------------------------------------------------------------- */
                    413:
                    414: static int
1.17      christos  415: tmpfs_snapshot(struct mount *mp, struct vnode *vp,
                    416:     struct timespec *ctime)
1.1       jmmv      417: {
                    418:
                    419:        return EOPNOTSUPP;
                    420: }
                    421:
                    422: /* --------------------------------------------------------------------- */
                    423:
                    424: /*
                    425:  * tmpfs vfs operations.
                    426:  */
                    427:
                    428: extern const struct vnodeopv_desc tmpfs_fifoop_opv_desc;
                    429: extern const struct vnodeopv_desc tmpfs_specop_opv_desc;
                    430: extern const struct vnodeopv_desc tmpfs_vnodeop_opv_desc;
                    431:
                    432: const struct vnodeopv_desc * const tmpfs_vnodeopv_descs[] = {
                    433:        &tmpfs_fifoop_opv_desc,
                    434:        &tmpfs_specop_opv_desc,
                    435:        &tmpfs_vnodeop_opv_desc,
                    436:        NULL,
                    437: };
                    438:
                    439: struct vfsops tmpfs_vfsops = {
                    440:        MOUNT_TMPFS,                    /* vfs_name */
1.23      dsl       441:        sizeof (struct tmpfs_args),
1.1       jmmv      442:        tmpfs_mount,                    /* vfs_mount */
                    443:        tmpfs_start,                    /* vfs_start */
                    444:        tmpfs_unmount,                  /* vfs_unmount */
                    445:        tmpfs_root,                     /* vfs_root */
1.32      pooka     446:        (void *)eopnotsupp,             /* vfs_quotactl */
1.1       jmmv      447:        tmpfs_statvfs,                  /* vfs_statvfs */
                    448:        tmpfs_sync,                     /* vfs_sync */
                    449:        tmpfs_vget,                     /* vfs_vget */
                    450:        tmpfs_fhtovp,                   /* vfs_fhtovp */
                    451:        tmpfs_vptofh,                   /* vfs_vptofh */
                    452:        tmpfs_init,                     /* vfs_init */
                    453:        NULL,                           /* vfs_reinit */
                    454:        tmpfs_done,                     /* vfs_done */
                    455:        NULL,                           /* vfs_mountroot */
                    456:        tmpfs_snapshot,                 /* vfs_snapshot */
                    457:        vfs_stdextattrctl,              /* vfs_extattrctl */
1.25      pooka     458:        (void *)eopnotsupp,             /* vfs_suspendctl */
1.1       jmmv      459:        tmpfs_vnodeopv_descs,
1.14      christos  460:        0,                              /* vfs_refcount */
                    461:        { NULL, NULL },
1.1       jmmv      462: };
                    463: VFS_ATTACH(tmpfs_vfsops);

CVSweb <webmaster@jp.NetBSD.org>