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.
This commit is contained in:
Dag-Erling Smørgrav 2001-10-19 01:43:06 +00:00
parent b51cc76c45
commit 33802b9eff
3 changed files with 288 additions and 62 deletions

View file

@ -44,9 +44,194 @@
#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
*/
@ -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);
}
/*

View file

@ -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 */
/*
@ -66,6 +67,15 @@ struct pfs_info;
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
*/
@ -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

View file

@ -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.