diff options
Diffstat (limited to 'sys/fs')
-rw-r--r-- | sys/fs/ctlfs.c | 389 | ||||
-rw-r--r-- | sys/fs/devfs.c | 26 | ||||
-rw-r--r-- | sys/fs/initramfs.c | 5 | ||||
-rw-r--r-- | sys/fs/tmpfs.c | 420 |
4 files changed, 829 insertions, 11 deletions
diff --git a/sys/fs/ctlfs.c b/sys/fs/ctlfs.c new file mode 100644 index 0000000..9225114 --- /dev/null +++ b/sys/fs/ctlfs.c @@ -0,0 +1,389 @@ +/* + * Copyright (c) 2023-2025 Ian Marco Moffett and the Osmora Team. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Hyra nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/errno.h> +#include <sys/vnode.h> +#include <sys/device.h> +#include <sys/syslog.h> +#include <sys/mount.h> +#include <sys/queue.h> +#include <fs/ctlfs.h> +#include <vm/dynalloc.h> +#include <string.h> + +#define CTLFS_MPNAME "ctl" +#define CTLFS_ENTRY_MAG 0x43454E54UL /* 'CENT' */ +#define CTLFS_NODE_MAG 0x43544C4EUL /* 'CTLN' */ + +#define pr_trace(fmt, ...) kprintf("ctlfs: " fmt, ##__VA_ARGS__) +#define pr_error(...) pr_trace(__VA_ARGS__) + +static const struct vops ctlfs_vops; + +struct ctlfs_hdr { + uint32_t magic; + char *name; +}; + +/* + * Control fs entry, represents a control + * file within a ctlfs node. + * -- HDR START -- + * @magic: Magic number [MUST BE FIRST] (CTLFS_ENTRY_MAG) + * @name: Entry name [MUST BE SECOND] + * -- HDR END -- + * @parent: Parent (ctlfs_node) + * @io: Ctlfs operations. + * @mode: Access flags. + * @link: TAILQ link. + */ +struct ctlfs_entry { + uint32_t magic; + char *name; + struct ctlfs_node *parent; + const struct ctlops *io; + mode_t mode; + TAILQ_ENTRY(ctlfs_entry) link; +}; + +/* + * Control fs node, represents a directory + * within ctlfs. These directories represent + * devices, each device directory contains + * control files. + * + * For example: + * + * /ctl/sd1/bsize # Block size + * /ctl/sd1/health # Health + * [et cetera] + * + * @magic: Magic number [MUST BE FIRST] (CTLFS_NODE_MAG) + * @name: Name of node [MUST BE SECOND] + * @mode: Access flags. + * @major: Device major number. + * @minor: Device major number. + * @eq: Entries for this ctlfs node. + */ +struct ctlfs_node { + uint32_t magic; + char *name; + mode_t mode; + TAILQ_HEAD(, ctlfs_entry) eq; + TAILQ_ENTRY(ctlfs_node) link; +}; + +static TAILQ_HEAD(, ctlfs_node) nodeq; + +/* + * Look up entries within a ctlfs + * node by name. + */ +static struct ctlfs_entry * +entry_lookup(struct ctlfs_node *cnp, const char *name) +{ + struct ctlfs_entry *ep; + + TAILQ_FOREACH(ep, &cnp->eq, link) { + if (strcmp(ep->name, name) == 0) { + return ep; + } + } + + return NULL; +} + +/* + * Lookup a ctlfs entry by name. + */ +static struct ctlfs_node * +node_lookup(const char *name) +{ + struct ctlfs_node *cnp; + + TAILQ_FOREACH(cnp, &nodeq, link) { + if (strcmp(cnp->name, name) == 0) { + return cnp; + } + } + + return NULL; +} + +static int +ctlfs_init(struct fs_info *fip) +{ + struct vnode *vp; + struct mount *mp; + int error; + + if ((error = vfs_alloc_vnode(&vp, VDIR)) != 0) { + pr_error("failed to alloc vnode\n"); + return error; + } + + vp->vops = &ctlfs_vops; + if ((mp = vfs_alloc_mount(vp, fip)) == NULL) { + pr_trace("failed to alloc mountpoint\n"); + return -ENOMEM; + } + + error = vfs_name_mount(mp, CTLFS_MPNAME); + if (error != 0) { + pr_trace("failed to mount @ /%s\n", CTLFS_MPNAME); + return error; + } + + TAILQ_INSERT_TAIL(&g_mountlist, mp, mnt_list); + TAILQ_INIT(&nodeq); + return 0; +} + +static int +ctlfs_lookup(struct vop_lookup_args *args) +{ + int error; + const char *name = args->name; + struct vnode *vp, *dirvp; + struct ctlfs_node *cnp = NULL; + struct ctlfs_entry *enp = NULL; + + if (name == NULL) { + return -EINVAL; + } + + dirvp = args->dirvp; + if (dirvp == NULL) { + return -EIO; + } + + /* + * If we already have data within this vnode + * it *might* be a control node but we'll have + * to verify its magic number... + */ + if (dirvp->data != NULL) { + cnp = (struct ctlfs_node *)dirvp->data; + if (cnp->magic != CTLFS_NODE_MAG) { + pr_error("bad `cnp' magic (name=%s)\n", name); + return -EIO; + } + } + + /* + * Handle cases where we are looking up + * relative to a control node. + */ + if (cnp != NULL) { + enp = entry_lookup(cnp, name); + if (enp == NULL) { + return -ENOENT; + } + + /* Create a vnode for this enp */ + error = vfs_alloc_vnode(&vp, VCHR); + if (error != 0) { + return error; + } + + vp->data = (void *)enp; + vp->vops = &ctlfs_vops; + *args->vpp = vp; + return 0; + } + + /* Does this entry exist? */ + if ((cnp = node_lookup(name)) == NULL) { + return -ENOENT; + } + + if ((error = vfs_alloc_vnode(&vp, VDIR)) != 0) { + return error; + } + + vp->data = cnp; + vp->vops = &ctlfs_vops; + *args->vpp = vp; + return 0; +} + +/* + * Create a ctlfs node (directory) within the + * root fs. + * + * @name: Node name (e.g., "sd1" for "/ctl/sd1/") + * @dp: Device related arguments (see ctlfs_dev) + * Args used: + * - mode (access flags) + * + */ +int +ctlfs_create_node(const char *name, const struct ctlfs_dev *dp) +{ + struct ctlfs_node *cnp; + size_t namelen; + + if (name == NULL || dp == NULL) { + return -EINVAL; + } + + cnp = dynalloc(sizeof(*cnp)); + if (cnp == NULL) { + return -ENOMEM; + } + + namelen = strlen(name); + cnp->name = dynalloc(namelen + 1); + if (cnp->name == NULL) { + dynfree(cnp); + return -ENOMEM; + } + + memcpy(cnp->name, name, namelen); + cnp->name[namelen] = '\0'; + cnp->mode = dp->mode; + cnp->magic = CTLFS_NODE_MAG; + TAILQ_INSERT_TAIL(&nodeq, cnp, link); + TAILQ_INIT(&cnp->eq); + return 0; +} + +/* + * Create a ctlfs entry within a specific node. + * + * @name: Name e.g., "/health" for "/ctl/xxx/health". + * @dp: Device related arguments (see ctlfs_dev) + * Args used: + * - devname (name of device) + * - mode (access flags) + * - ops (operations vector) + */ +int +ctlfs_create_entry(const char *name, const struct ctlfs_dev *dp) +{ + struct ctlfs_entry *enp; + struct ctlfs_node *parent; + size_t namelen; + + if (name == NULL || dp == NULL) { + return -EINVAL; + } + if (dp->devname == NULL) { + return -EINVAL; + } + if (dp->ops == NULL) { + return -EINVAL; + } + + parent = node_lookup(dp->devname); + if (parent == NULL) { + pr_trace("could not find %s\n", dp->devname); + return -ENOENT; + } + + enp = dynalloc(sizeof(*enp)); + if (enp == NULL) { + return -ENOMEM; + } + + namelen = strlen(name); + enp->name = dynalloc(namelen + 1); + if (enp->name == NULL) { + dynfree(enp); + return -ENOMEM; + } + + memcpy(enp->name, name, namelen); + enp->name[namelen] = '\0'; + enp->io = dp->ops; + enp->magic = CTLFS_ENTRY_MAG; + enp->mode = dp->mode; + enp->parent = parent; + TAILQ_INSERT_TAIL(&parent->eq, enp, link); + return 0; +} + +/* + * Read a control file + * + * Args passed to driver: + * - ctlfs_dev.ctlname + * - ctlfs_dev.iop + * - ctlfs_dev.mode + */ +static int +ctlfs_read(struct vnode *vp, struct sio_txn *sio) +{ + const struct ctlops *iop; + struct ctlfs_entry *enp; + struct ctlfs_dev dev; + + if ((enp = vp->data) == NULL) { + pr_error("no vnode data for ctlfs entry\n"); + return -EIO; + } + if (enp->magic != CTLFS_ENTRY_MAG) { + pr_error("ctlfs entry has bad magic\n"); + return -EIO; + } + if ((iop = enp->io) == NULL) { + pr_error("no i/o ops for ctlfs entry\n"); + return -EIO; + } + if (iop->read == NULL) { + pr_trace("no read op for ctlfs entry\n"); + return -EIO; + } + + dev.ctlname = enp->name; + dev.ops = iop; + dev.mode = enp->mode; + return iop->read(&dev, sio); +} + +static int +ctlfs_reclaim(struct vnode *vp) +{ + vp->data = NULL; + return 0; +} + +static const struct vops ctlfs_vops = { + .lookup = ctlfs_lookup, + .read = ctlfs_read, + .getattr = NULL, + .write = NULL, + .reclaim = ctlfs_reclaim, + .create = NULL +}; + +const struct vfsops g_ctlfs_vfsops = { + .init = ctlfs_init +}; diff --git a/sys/fs/devfs.c b/sys/fs/devfs.c index 024239d..293ee0a 100644 --- a/sys/fs/devfs.c +++ b/sys/fs/devfs.c @@ -30,6 +30,7 @@ #include <sys/types.h> #include <sys/vnode.h> #include <sys/errno.h> +#include <sys/stat.h> #include <sys/mount.h> #include <sys/device.h> #include <fs/devfs.h> @@ -126,6 +127,8 @@ devfs_lookup(struct vop_lookup_args *args) vp->data = dnp; vp->vops = &g_devfs_vops; + vp->major = dnp->major; + vp->dev = dnp->dev; *args->vpp = vp; return 0; } @@ -136,6 +139,8 @@ devfs_getattr(struct vop_getattr_args *args) struct vnode *vp; struct vattr *attr; struct devfs_node *dnp; + struct bdevsw *bdev; + size_t size = 0; vp = args->vp; if ((dnp = vp->data) == NULL) { @@ -145,6 +150,13 @@ devfs_getattr(struct vop_getattr_args *args) return -EIO; } + if (dnp->is_block) { + bdev = dev_get(dnp->major, dnp->dev); + if (bdev->bsize != NULL) { + size = bdev->bsize(dnp->dev); + } + } + /* * Set stat attributes from device node structure * found within vnode data. @@ -153,20 +165,13 @@ devfs_getattr(struct vop_getattr_args *args) * size is hardwired to 0. */ attr->mode = dnp->mode; - attr->size = 0; + attr->size = size; return 0; } static int devfs_reclaim(struct vnode *vp) { - struct devfs_node *dnp; - - if ((dnp = vp->data) != NULL) { - dynfree(dnp->name); - dynfree(vp->data); - } - vp->data = NULL; return 0; } @@ -255,7 +260,7 @@ devfs_create_entry(const char *name, devmajor_t major, dev_t dev, mode_t mode) memcpy(dnp->name, name, name_len); dnp->name[name_len] = '\0'; - + dnp->is_block = ISSET(mode, S_IFBLK) ? 1 : 0; dnp->major = major; dnp->dev = dev; dnp->mode = mode; @@ -268,7 +273,8 @@ const struct vops g_devfs_vops = { .reclaim = devfs_reclaim, .read = devfs_read, .write = devfs_write, - .getattr = devfs_getattr + .getattr = devfs_getattr, + .create = NULL }; const struct vfsops g_devfs_vfsops = { diff --git a/sys/fs/initramfs.c b/sys/fs/initramfs.c index b12a64b..c41deb4 100644 --- a/sys/fs/initramfs.c +++ b/sys/fs/initramfs.c @@ -223,6 +223,8 @@ initramfs_read(struct vnode *vp, struct sio_txn *sio) return -EIO; if (sio->buf == NULL) return -EIO; + if (sio->len > n->size) + sio->len = n->size; src = n->data; dest = sio->buf; @@ -277,7 +279,8 @@ const struct vops g_initramfs_vops = { .read = initramfs_read, .write = NULL, .reclaim = initramfs_reclaim, - .getattr = initramfs_getattr + .getattr = initramfs_getattr, + .create = NULL, }; const struct vfsops g_initramfs_vfsops = { diff --git a/sys/fs/tmpfs.c b/sys/fs/tmpfs.c new file mode 100644 index 0000000..a6e40e1 --- /dev/null +++ b/sys/fs/tmpfs.c @@ -0,0 +1,420 @@ +/* + * Copyright (c) 2023-2025 Ian Marco Moffett and the Osmora Team. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Hyra nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/mount.h> +#include <sys/errno.h> +#include <sys/syslog.h> +#include <sys/types.h> +#include <sys/cdefs.h> +#include <sys/param.h> +#include <sys/panic.h> +#include <sys/vnode.h> +#include <vm/dynalloc.h> +#include <vm/vm_obj.h> +#include <vm/vm_page.h> +#include <vm/vm_pager.h> +#include <fs/tmpfs.h> +#include <string.h> + +#define ROOT_RPATH "/tmp" +#define TMPFS_BSIZE DEFAULT_PAGESIZE + +#define pr_trace(fmt, ...) kprintf("tmpfs: " fmt, ##__VA_ARGS__) +#define pr_error(...) pr_trace(__VA_ARGS__) + +static TAILQ_HEAD(, tmpfs_node) root; + +/* + * Generate a vnode for a specific tmpfs + * node. + */ +static int +tmpfs_ref(struct tmpfs_node *np) +{ + struct vnode *vp = NULL; + int retval = 0; + + if (np->vp == NULL) { + spinlock_acquire(&np->lock); + retval = vfs_alloc_vnode(&vp, np->type); + np->vp = vp; + spinlock_release(&np->lock); + } + + if (vp != NULL) { + vp->data = np; + vp->vops = &g_tmpfs_vops; + } + + return retval; +} + +/* + * Perform lookup within the tmpfs namespace + * + * XXX: This operations is serialized + * TODO: Support multiple directories (only fs root now) + * + * @rpath: /tmp/ relative path to lookup + * @res: The result is written here (must NOT be NULL) + */ +static int +tmpfs_do_lookup(const char *rpath, struct tmpfs_node **res) +{ + struct tmpfs_node *cnp; + struct tmpfs_node *dirent; + int error = 0; + + /* + * If the directory is the node that we are + * looking for, return it. But if it is not + * and it is empty then there is nothing + * we can do. + */ + cnp = TAILQ_FIRST(&root); + if (strcmp(cnp->rpath, rpath) == 0) { + *res = cnp; + return 0; + } + if (TAILQ_NELEM(&cnp->dirents) == 0) { + return -ENOENT; + } + + /* + * Go through each tmpfs dirent to see if we can + * find the file we are looking for. + */ + spinlock_acquire(&cnp->lock); + dirent = TAILQ_FIRST(&cnp->dirents); + while (dirent != NULL) { + if (strcmp(dirent->rpath, rpath) == 0) { + break; + } + + dirent = TAILQ_NEXT(dirent, link); + } + + spinlock_release(&cnp->lock); + if (res == NULL) { + return -ENOENT; + } + + if ((error = tmpfs_ref(dirent)) != 0) { + return error; + } + + *res = dirent; + return 0; +} + +/* + * TMPFS lookup callback for the VFS + * + * Takes some arguments and returns a vnode + * in args->vpp + */ +static int +tmpfs_lookup(struct vop_lookup_args *args) +{ + struct tmpfs_node *np; + int error; + + if (args == NULL) { + return -EINVAL; + } + if (args->name == NULL) { + return -EINVAL; + } + + /* + * Attempt to find the node we want, if it already + * has a vnode attached to it then that's something we + * want. However we should allocate a new vnode if we + * need to. + */ + error = tmpfs_do_lookup(args->name, &np); + if (error != 0) { + return error; + } + + *args->vpp = np->vp; + return 0; +} + +/* + * TMPFS create callback for the VFS + * + * Creates a new TMPFS node + */ +static int +tmpfs_create(struct vop_create_args *args) +{ + const char *pcp = args->path; /* Stay away from boat, kids */ + struct vnode *dirvp; + struct tmpfs_node *np; + struct tmpfs_node *root_np; + int error; + + /* Validate inputs */ + if (args == NULL) + return -EINVAL; + if (pcp == NULL) + return -EIO; + if ((dirvp = args->dirvp) == NULL) + return -EIO; + + /* Remove the leading "/tmp/" */ + pcp += sizeof(ROOT_RPATH); + if (*pcp == '\0') { + return -ENOENT; + } + + np = dynalloc(sizeof(*np)); + if (np == NULL) { + return -ENOMEM; + } + + memset(np, 0, sizeof(*np)); + + /* + * TODO: Support multiple directories. + * + * XXX: We currently only create a TMPFS_REG node as + * to keep things initially simple. + */ + root_np = TAILQ_FIRST(&root); + np->dirvp = dirvp; + np->type = TMPFS_REG; + np->real_size = 0; + np->mode = 0700; + memcpy(np->rpath, pcp, strlen(pcp) + 1); + TAILQ_INSERT_TAIL(&root_np->dirents, np, link); + + if ((error = tmpfs_ref(np)) != 0) { + return error; + } + + *args->vpp = np->vp; + return 0; +} + +/* + * TMPFS write callback for VFS + * + * Node buffers are orthogonally managed. That is, each + * node has their own respective data buffers. When + * writing to a node, we need to take into account of the + * length of the buffer. This value may need to expanded as + * well as more pages allocated if the amount of bytes to + * be written exceeds it. + */ +static int +tmpfs_write(struct vnode *vp, struct sio_txn *sio) +{ + struct tmpfs_node *np; + uint8_t *buf; + + if (sio->buf == NULL || sio->len == 0) { + return -EINVAL; + } + + /* This should not happen but you never know */ + if ((np = vp->data) == NULL) { + return -EIO; + } + + /* Is this even a regular file? */ + if (np->type != VREG) { + return -EISDIR; + } + + spinlock_acquire(&np->lock); + + /* + * If the residual byte count is zero, we need to + * allocate a new page to be used. However if this + * fails we'll throw back an -ENOMEM. + */ + if (np->len == 0) { + np->data = dynalloc(TMPFS_BSIZE); + if (np->data == NULL) { + spinlock_release(&np->lock); + return -ENOMEM; + } + np->len += TMPFS_BSIZE; + } + + /* + * Bring up the real size if we are writing + * more bytes. + */ + if (sio->offset >= np->real_size) { + np->real_size = sio->offset; + } + + /* + * If the length to be written exceeds the residual byte + * count. We will try to expand the buffer by the page + * size. However, if this fails, we will split the write + * into a suitable size that does not overflow what we + * have left. + */ + if ((sio->offset + sio->len) > np->len) { + np->data = dynrealloc(np->data, (sio->offset + sio->len)); + if (np->data == NULL) { + sio->len = np->len; + } else { + np->len = sio->offset + sio->len; + } + } + + buf = np->data; + memcpy(&buf[sio->offset], sio->buf, sio->len); + spinlock_release(&np->lock); + return sio->len; +} + +/* + * TMPFS read callback for VFS + */ +static int +tmpfs_read(struct vnode *vp, struct sio_txn *sio) +{ + struct tmpfs_node *np; + uint8_t *buf; + + if (sio->buf == NULL || sio->len == 0) { + return -EINVAL; + } + + /* This should not happen but you never know */ + if ((np = vp->data) == NULL) { + return -EIO; + } + + /* Is this even a regular file? */ + if (np->type != VREG) { + return -EISDIR; + } + + spinlock_acquire(&np->lock); + + if (sio->offset > np->real_size) { + return -EINVAL; + } + + buf = np->data; + memcpy(sio->buf, &buf[sio->offset], sio->len); + spinlock_release(&np->lock); + return sio->len; +} + +/* + * TMPFS get attribute callback for VFS + */ +static int +tmpfs_getattr(struct vop_getattr_args *args) +{ + struct vnode *vp; + struct tmpfs_node *np; + struct vattr attr; + + if ((vp = args->vp) == NULL) { + return -EIO; + } + if ((np = vp->data) == NULL) { + return -EIO; + } + + memset(&attr, VNOVAL, sizeof(attr)); + attr.size = np->real_size; + attr.mode = np->mode; + *args->res = attr; + return 0; +} + +static int +tmpfs_reclaim(struct vnode *vp) +{ + struct tmpfs_node *np; + + if ((np = vp->data) == NULL) { + return 0; + } + + np->vp = NULL; + vp->data = NULL; + return 0; +} + +static int +tmpfs_init(struct fs_info *fip) +{ + struct tmpfs_node *np; + struct vnode *vp; + struct mount *mp; + int error; + + /* Grab ourselves a new vnode for /tmp */ + if ((error = vfs_alloc_vnode(&vp, VDIR)) != 0) { + return error; + } + + vp->vops = &g_tmpfs_vops; + mp = vfs_alloc_mount(vp, fip); + vfs_name_mount(mp, "tmp"); + TAILQ_INSERT_TAIL(&g_mountlist, mp, mnt_list); + + /* Pre-allocate the first entry */ + if ((np = dynalloc(sizeof(*np))) == NULL) { + return -ENOMEM; + } + + TAILQ_INIT(&root); + memset(np, 0, sizeof(*np)); + + memcpy(np->rpath, ROOT_RPATH, sizeof(ROOT_RPATH)); + np->type = TMPFS_DIR; + TAILQ_INIT(&np->dirents); + TAILQ_INSERT_TAIL(&root, np, link); + return 0; +} + +const struct vops g_tmpfs_vops = { + .lookup = tmpfs_lookup, + .getattr = tmpfs_getattr, + .read = tmpfs_read, + .write = tmpfs_write, + .reclaim = tmpfs_reclaim, + .create = tmpfs_create, +}; + +const struct vfsops g_tmpfs_vfsops = { + .init = tmpfs_init +}; |