summaryrefslogtreecommitdiffstats
path: root/sys/fs/pseudofs/pseudofs.c
diff options
context:
space:
mode:
authordes <des@FreeBSD.org>2001-10-19 01:43:06 +0000
committerdes <des@FreeBSD.org>2001-10-19 01:43:06 +0000
commit393474fd4170aca38f42f133b0b46f47cbdbda86 (patch)
tree49b9bfc3549abb5b2182d988f03a5fe2b041af9b /sys/fs/pseudofs/pseudofs.c
parent8bbeedf7ceda38632a2db527a2b525e5cb194c18 (diff)
downloadFreeBSD-src-393474fd4170aca38f42f133b0b46f47cbdbda86.zip
FreeBSD-src-393474fd4170aca38f42f133b0b46f47cbdbda86.tar.gz
Switch to dynamic rather than static initialization.
This makes it possible (in theory) for nodes to be added and / or removed from pseudofs filesystems at runtime.
Diffstat (limited to 'sys/fs/pseudofs/pseudofs.c')
-rw-r--r--sys/fs/pseudofs/pseudofs.c217
1 files changed, 216 insertions, 1 deletions
diff --git a/sys/fs/pseudofs/pseudofs.c b/sys/fs/pseudofs/pseudofs.c
index afbf407..495d96a 100644
--- a/sys/fs/pseudofs/pseudofs.c
+++ b/sys/fs/pseudofs/pseudofs.c
@@ -44,10 +44,195 @@
#include <fs/pseudofs/pseudofs.h>
#include <fs/pseudofs/pseudofs_internal.h>
+static MALLOC_DEFINE(M_PFSNODES, "pfs_nodes", "pseudofs nodes");
+
SYSCTL_NODE(_vfs, OID_AUTO, pfs, CTLFLAG_RW, 0,
"pseudofs");
/*
+ * Add a node to a directory
+ */
+static int
+_pfs_add_node(struct pfs_node *parent, struct pfs_node *node)
+{
+ KASSERT(parent != NULL,
+ (__FUNCTION__ "(): parent is NULL"));
+ KASSERT(parent->pn_info != NULL,
+ (__FUNCTION__ "(): parent has no pn_info"));
+ KASSERT(parent->pn_type == pfstype_dir ||
+ parent->pn_type == pfstype_procdir ||
+ parent->pn_type == pfstype_root,
+ (__FUNCTION__ "(): parent is not a directory"));
+
+ /* XXX should check for duplicate names etc. */
+
+ mtx_lock(&parent->pn_info->pi_mutex);
+ node->pn_info = parent->pn_info;
+ node->pn_parent = parent;
+ node->pn_next = parent->pn_nodes;
+ parent->pn_nodes = node;
+ mtx_unlock(&parent->pn_info->pi_mutex);
+
+ return (0);
+}
+
+/*
+ * Add . and .. to a directory
+ */
+static int
+_pfs_fixup_dir(struct pfs_node *parent)
+{
+ struct pfs_node *dir;
+
+ MALLOC(dir, struct pfs_node *, sizeof *dir,
+ M_PFSNODES, M_WAITOK|M_ZERO);
+ dir->pn_name[0] = '.';
+ dir->pn_type = pfstype_this;
+
+ if (_pfs_add_node(parent, dir) != 0) {
+ FREE(dir, M_PFSNODES);
+ return (-1);
+ }
+
+ MALLOC(dir, struct pfs_node *, sizeof *dir,
+ M_PFSNODES, M_WAITOK|M_ZERO);
+ dir->pn_name[0] = dir->pn_name[1] = '.';
+ dir->pn_type = pfstype_parent;
+
+ if (_pfs_add_node(parent, dir) != 0) {
+ FREE(dir, M_PFSNODES);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * Create a directory
+ */
+struct pfs_node *
+pfs_create_dir(struct pfs_node *parent, char *name,
+ pfs_attr_t attr, pfs_vis_t vis, int flags)
+{
+ struct pfs_node *dir;
+
+ KASSERT(strlen(name) < PFS_NAMELEN,
+ (__FUNCTION__ "(): node name is too long"));
+
+ MALLOC(dir, struct pfs_node *, sizeof *dir,
+ M_PFSNODES, M_WAITOK|M_ZERO);
+ strcpy(dir->pn_name, name);
+ dir->pn_type = (flags & PFS_PROCDEP) ? pfstype_procdir : pfstype_dir;
+ dir->pn_attr = attr;
+ dir->pn_vis = vis;
+ dir->pn_flags = flags & ~PFS_PROCDEP;
+
+ if (_pfs_add_node(parent, dir) != 0) {
+ FREE(dir, M_PFSNODES);
+ return (NULL);
+ }
+
+ if (_pfs_fixup_dir(dir) != 0) {
+ pfs_destroy(dir);
+ return (NULL);
+ }
+
+ return (dir);
+}
+
+/*
+ * Create a file
+ */
+struct pfs_node *
+pfs_create_file(struct pfs_node *parent, char *name, pfs_fill_t fill,
+ pfs_attr_t attr, pfs_vis_t vis, int flags)
+{
+ struct pfs_node *node;
+
+ KASSERT(strlen(name) < PFS_NAMELEN,
+ (__FUNCTION__ "(): node name is too long"));
+
+ MALLOC(node, struct pfs_node *, sizeof *node,
+ M_PFSNODES, M_WAITOK|M_ZERO);
+ strcpy(node->pn_name, name);
+ node->pn_type = pfstype_file;
+ node->pn_func = fill;
+ node->pn_attr = attr;
+ node->pn_vis = vis;
+ node->pn_flags = flags;
+
+ if (_pfs_add_node(parent, node) != 0) {
+ FREE(node, M_PFSNODES);
+ return (NULL);
+ }
+
+ return (node);
+}
+
+/*
+ * Create a symlink
+ */
+struct pfs_node *
+pfs_create_link(struct pfs_node *parent, char *name, pfs_fill_t fill,
+ pfs_attr_t attr, pfs_vis_t vis, int flags)
+{
+ struct pfs_node *node;
+
+ node = pfs_create_file(parent, name, fill, attr, vis, flags);
+ if (node == NULL)
+ return (NULL);
+ node->pn_type = pfstype_symlink;
+ return (node);
+}
+
+/*
+ * Destroy a node or a tree of nodes
+ */
+int
+pfs_destroy(struct pfs_node *node)
+{
+ struct pfs_node *parent, *rover;
+
+ KASSERT(node != NULL,
+ (__FUNCTION__ "(): node is NULL"));
+ KASSERT(node->pn_info != NULL,
+ (__FUNCTION__ "(): node has no pn_info"));
+
+ /* destroy children */
+ if (node->pn_type == pfstype_dir ||
+ node->pn_type == pfstype_procdir ||
+ node->pn_type == pfstype_root)
+ while (node->pn_nodes != NULL)
+ pfs_destroy(node->pn_nodes);
+
+ /* unlink from parent */
+ if ((parent = node->pn_parent) != NULL) {
+ KASSERT(parent->pn_info == node->pn_info,
+ (__FUNCTION__ "(): parent has different pn_info"));
+ mtx_lock(&node->pn_info->pi_mutex);
+ if (parent->pn_nodes == node) {
+ parent->pn_nodes = node->pn_next;
+ } else {
+ rover = parent->pn_nodes;
+ while (rover->pn_next != NULL) {
+ if (rover->pn_next == node) {
+ rover->pn_next = node->pn_next;
+ break;
+ }
+ rover = rover->pn_next;
+ }
+ }
+ mtx_unlock(&node->pn_info->pi_mutex);
+ }
+
+ /* revoke vnodes and release memory */
+ pfs_disable(node);
+ FREE(node, M_PFSNODES);
+
+ return (0);
+}
+
+/*
* Mount a pseudofs instance
*/
int
@@ -121,7 +306,32 @@ pfs_statfs(struct mount *mp, struct statfs *sbp, struct thread *td)
int
pfs_init(struct pfs_info *pi, struct vfsconf *vfc)
{
+ struct pfs_node *root;
+ int error;
+
mtx_init(&pi->pi_mutex, "pseudofs", MTX_DEF);
+
+ /* set up the root diretory */
+ MALLOC(root, struct pfs_node *, sizeof *root,
+ M_PFSNODES, M_WAITOK|M_ZERO);
+ root->pn_type = pfstype_root;
+ root->pn_name[0] = '/';
+ root->pn_info = pi;
+ if (_pfs_fixup_dir(root) != 0) {
+ FREE(root, M_PFSNODES);
+ return (ENODEV); /* XXX not really the right errno */
+ }
+ pi->pi_root = root;
+
+ /* construct file hierarchy */
+ error = (pi->pi_init)(pi, vfc);
+ if (error) {
+ pfs_destroy(root);
+ pi->pi_root = NULL;
+ mtx_destroy(&pi->pi_mutex);
+ return (error);
+ }
+
pfs_fileno_init(pi);
if (bootverbose)
printf("%s registered\n", pi->pi_name);
@@ -134,11 +344,16 @@ pfs_init(struct pfs_info *pi, struct vfsconf *vfc)
int
pfs_uninit(struct pfs_info *pi, struct vfsconf *vfc)
{
+ int error;
+
pfs_fileno_uninit(pi);
+ pfs_destroy(pi->pi_root);
+ pi->pi_root = NULL;
mtx_destroy(&pi->pi_mutex);
if (bootverbose)
printf("%s unregistered\n", pi->pi_name);
- return (0);
+ error = (pi->pi_uninit)(pi, vfc);
+ return (error);
}
/*
OpenPOWER on IntegriCloud