summaryrefslogtreecommitdiffstats
path: root/sys/fs/pseudofs
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
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')
-rw-r--r--sys/fs/pseudofs/pseudofs.c217
-rw-r--r--sys/fs/pseudofs/pseudofs.h72
-rw-r--r--sys/fs/pseudofs/pseudofs_vnops.c61
3 files changed, 288 insertions, 62 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);
}
/*
diff --git a/sys/fs/pseudofs/pseudofs.h b/sys/fs/pseudofs/pseudofs.h
index 8a6f918..ab8a542 100644
--- a/sys/fs/pseudofs/pseudofs.h
+++ b/sys/fs/pseudofs/pseudofs.h
@@ -57,6 +57,7 @@ typedef enum {
#define PFS_RAWRD 0x0004 /* raw reader */
#define PFS_RAWWR 0x0008 /* raw writer */
#define PFS_RAW (PFS_RAWRD|PFS_RAWWR)
+#define PFS_PROCDEP 0x0010 /* process-dependent */
#define PFS_DISABLED 0x8000 /* node is disabled */
/*
@@ -67,6 +68,15 @@ struct pfs_node;
struct pfs_bitmap;
/*
+ * Init / uninit callback
+ */
+#define PFS_INIT_ARGS \
+ struct pfs_info *pi, struct vfsconf *vfc
+#define PFS_INIT_PROTO(name) \
+ int name(PFS_INIT_ARGS);
+typedef int (*pfs_init_t)(PFS_INIT_ARGS);
+
+/*
* Filler callback
*/
#define PFS_FILL_ARGS \
@@ -103,8 +113,10 @@ typedef int (*pfs_vis_t)(PFS_VIS_ARGS);
*/
struct pfs_info {
char pi_name[MFSNAMELEN];
- struct pfs_node *pi_root;
+ pfs_init_t pi_init;
+ pfs_init_t pi_uninit;
/* members below this line aren't initialized */
+ struct pfs_node *pi_root;
/* currently, the mutex is only used to protect the bitmap */
struct mtx pi_mutex;
struct pfs_bitmap *pi_bitmap;
@@ -123,62 +135,56 @@ struct pfs_node {
} u1;
#define pn_func u1._pn_func
#define pn_nodes u1._pn_nodes
+ /*pfs_ioctl_t pn_ioctl;*/
pfs_attr_t pn_attr;
pfs_vis_t pn_vis;
void *pn_data;
int pn_flags;
- /* members below this line aren't initialized */
+
+ struct pfs_info *pn_info;
struct pfs_node *pn_parent;
+ struct pfs_node *pn_next;
u_int32_t pn_fileno;
};
-#define PFS_NODE(name, type, fill, attr, vis, data, flags) \
- { (name), (type), { (fill) }, (attr), (vis), (data), (flags) }
-#define PFS_DIR(name, nodes, attr, vis, data, flags) \
- PFS_NODE(name, pfstype_dir, nodes, attr, vis, data, flags)
-#define PFS_ROOT(nodes) \
- PFS_NODE("/", pfstype_root, nodes, NULL, NULL, NULL, 0)
-#define PFS_THIS \
- PFS_NODE(".", pfstype_this, NULL, NULL, NULL, NULL, 0)
-#define PFS_PARENT \
- PFS_NODE("..", pfstype_parent, NULL, NULL, NULL, NULL, 0)
-#define PFS_FILE(name, func, attr, vis, data, flags) \
- PFS_NODE(name, pfstype_file, func, attr, vis, data, flags)
-#define PFS_SYMLINK(name, func, attr, vis, data, flags) \
- PFS_NODE(name, pfstype_symlink, func, attr, vis, data, flags)
-#define PFS_PROCDIR(nodes, attr, vis, data, flags) \
- PFS_NODE("", pfstype_procdir, nodes, attr, vis, data, flags)
-#define PFS_LASTNODE \
- PFS_NODE("", pfstype_none, NULL, NULL, NULL, NULL, 0)
-
/*
* VFS interface
*/
-int pfs_mount (struct pfs_info *pi,
+int pfs_mount (struct pfs_info *pi,
struct mount *mp, char *path, caddr_t data,
struct nameidata *ndp, struct thread *td);
-int pfs_unmount (struct mount *mp, int mntflags,
+int pfs_unmount (struct mount *mp, int mntflags,
struct thread *td);
-int pfs_root (struct mount *mp, struct vnode **vpp);
-int pfs_statfs (struct mount *mp, struct statfs *sbp,
+int pfs_root (struct mount *mp, struct vnode **vpp);
+int pfs_statfs (struct mount *mp, struct statfs *sbp,
struct thread *td);
-int pfs_init (struct pfs_info *pi, struct vfsconf *vfc);
-int pfs_uninit (struct pfs_info *pi, struct vfsconf *vfc);
+int pfs_init (struct pfs_info *pi, struct vfsconf *vfc);
+int pfs_uninit (struct pfs_info *pi, struct vfsconf *vfc);
/*
- * Other utility functions
+ * Directory structure construction and manipulation
*/
-int pfs_disable (struct pfs_node *pn);
-int pfs_enable (struct pfs_node *pn);
+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 *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 *pfs_create_link(struct pfs_node *parent, char *name,
+ pfs_fill_t fill, pfs_attr_t attr,
+ pfs_vis_t vis, int flags);
+int pfs_disable (struct pfs_node *pn);
+int pfs_enable (struct pfs_node *pn);
+int pfs_destroy (struct pfs_node *pn);
/*
* Now for some initialization magic...
*/
-#define PSEUDOFS(name, root, version) \
+#define PSEUDOFS(name, version) \
\
static struct pfs_info name##_info = { \
#name, \
- &(root) \
+ &name##_init, \
+ &name##_uninit, \
}; \
\
static int \
@@ -215,6 +221,6 @@ static struct vfsops name##_vfsops = { \
}; \
VFS_SET(name##_vfsops, name, VFCF_SYNTHETIC); \
MODULE_VERSION(name, version); \
-MODULE_DEPEND(name, pseudofs, 2, 2, 2);
+MODULE_DEPEND(name, pseudofs, 3, 3, 3);
#endif
diff --git a/sys/fs/pseudofs/pseudofs_vnops.c b/sys/fs/pseudofs/pseudofs_vnops.c
index 5a29b0c..4c675aec 100644
--- a/sys/fs/pseudofs/pseudofs_vnops.c
+++ b/sys/fs/pseudofs/pseudofs_vnops.c
@@ -50,13 +50,14 @@
#if 0
#define PFS_TRACE(foo) \
do { \
- printf("pseudofs: %s(): ", __FUNCTION__); \
+ printf("pseudofs: %s(): line %d: ", __FUNCTION__, __LINE__); \
printf foo ; \
printf("\n"); \
} while (0)
#define PFS_RETURN(err) \
do { \
- printf("pseudofs: %s(): returning %d\n", __FUNCTION__, err); \
+ printf("pseudofs: %s(): line %d: returning %d\n", \
+ __FUNCTION__, __LINE__, err); \
return (err); \
} while (0)
#else
@@ -101,12 +102,10 @@ static int
pfs_access(struct vop_access_args *va)
{
struct vnode *vn = va->a_vp;
- struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
- struct pfs_node *pn = pvd->pvd_pn;
struct vattr vattr;
int error;
- PFS_TRACE((pn->pn_name));
+ PFS_TRACE((((struct pfs_vdata *)vn->v_data)->pvd_pn->pn_name));
error = VOP_GETATTR(vn, &vattr, va->a_cred, va->a_td);
if (error)
@@ -251,7 +250,7 @@ pfs_lookup(struct vop_lookup_args *va)
}
/* named node */
- for (pn = pd->pn_nodes; pn->pn_type; ++pn)
+ for (pn = pd->pn_nodes; pn != NULL; pn = pn->pn_next)
if (pn->pn_type == pfstype_procdir)
pdn = pn;
else if (pn->pn_name[namelen] == '\0'
@@ -343,6 +342,9 @@ pfs_read(struct vop_read_args *va)
if (!(pn->pn_flags & PFS_RD))
PFS_RETURN (EBADF);
+ if (pn->pn_func == NULL)
+ error = EIO;
+
/*
* This is necessary because either process' privileges may
* have changed since the open() call.
@@ -396,26 +398,27 @@ pfs_read(struct vop_read_args *va)
* Iterate through directory entries
*/
static int
-pfs_iterate(struct thread *td, pid_t pid, struct pfs_node **pn, struct proc **p)
+pfs_iterate(struct thread *td, pid_t pid, struct pfs_node *pd,
+ struct pfs_node **pn, struct proc **p)
{
- if ((*pn)->pn_type == pfstype_none)
- return (-1);
-
+ if ((*pn) == NULL)
+ *pn = pd->pn_nodes;
+ else
again:
if ((*pn)->pn_type != pfstype_procdir)
- ++*pn;
+ *pn = (*pn)->pn_next;
- while ((*pn)->pn_type == pfstype_procdir) {
+ while (*pn != NULL && (*pn)->pn_type == pfstype_procdir) {
if (*p == NULL)
*p = LIST_FIRST(&allproc);
else
*p = LIST_NEXT(*p, p_list);
if (*p != NULL)
break;
- ++*pn;
+ *pn = (*pn)->pn_next;
}
- if ((*pn)->pn_type == pfstype_none)
+ if ((*pn) == NULL)
return (-1);
if (!pfs_visible(td, *pn, *p ? (*p)->p_pid : pid))
@@ -460,13 +463,16 @@ pfs_readdir(struct vop_readdir_args *va)
/* skip unwanted entries */
sx_slock(&allproc_lock);
- for (pn = pd->pn_nodes, p = NULL; offset > 0; offset -= PFS_DELEN)
- if (pfs_iterate(curthread, pid, &pn, &p) == -1)
- break;
+ for (pn = NULL, p = NULL; offset > 0; offset -= PFS_DELEN)
+ if (pfs_iterate(curthread, pid, pd, &pn, &p) == -1) {
+ /* nothing left... */
+ sx_sunlock(&allproc_lock);
+ PFS_RETURN (0);
+ }
/* fill in entries */
entry.d_reclen = PFS_DELEN;
- while (pfs_iterate(curthread, pid, &pn, &p) != -1 && resid > 0) {
+ while (pfs_iterate(curthread, pid, pd, &pn, &p) != -1 && resid > 0) {
if (!pn->pn_parent)
pn->pn_parent = pd;
if (!pn->pn_fileno)
@@ -504,6 +510,7 @@ pfs_readdir(struct vop_readdir_args *va)
sx_sunlock(&allproc_lock);
panic("%s has unexpected node type: %d", pn->pn_name, pn->pn_type);
}
+ PFS_TRACE((entry.d_name));
if ((error = uiomove((caddr_t)&entry, PFS_DELEN, uio))) {
sx_sunlock(&allproc_lock);
PFS_RETURN (error);
@@ -537,6 +544,9 @@ pfs_readlink(struct vop_readlink_args *va)
if (vn->v_type != VLNK)
PFS_RETURN (EINVAL);
+ if (pn->pn_func == NULL)
+ error = EIO;
+
if (pvd->pvd_pid != NO_PID) {
if ((proc = pfind(pvd->pvd_pid)) == NULL)
PFS_RETURN (EIO);
@@ -573,11 +583,7 @@ pfs_readlink(struct vop_readlink_args *va)
static int
pfs_reclaim(struct vop_reclaim_args *va)
{
- struct vnode *vn = va->a_vp;
- struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
- struct pfs_node *pn = pvd->pvd_pn;
-
- PFS_TRACE((pn->pn_name));
+ PFS_TRACE((((struct pfs_vdata *)va->a_vp->v_data)->pvd_pn->pn_name));
return (pfs_vncache_free(va->a_vp));
}
@@ -588,11 +594,7 @@ pfs_reclaim(struct vop_reclaim_args *va)
static int
pfs_setattr(struct vop_setattr_args *va)
{
- struct vnode *vn = va->a_vp;
- struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
- struct pfs_node *pn = pvd->pvd_pn;
-
- PFS_TRACE((pn->pn_name));
+ PFS_TRACE((((struct pfs_vdata *)va->a_vp->v_data)->pvd_pn->pn_name));
if (va->a_vap->va_flags != (u_long)VNOVAL)
PFS_RETURN (EOPNOTSUPP);
@@ -622,6 +624,9 @@ pfs_write(struct vop_read_args *va)
if (!(pn->pn_flags & PFS_WR))
PFS_RETURN (EBADF);
+ if (pn->pn_func == NULL)
+ error = EIO;
+
/*
* This is necessary because either process' privileges may
* have changed since the open() call.
OpenPOWER on IntegriCloud