From 393474fd4170aca38f42f133b0b46f47cbdbda86 Mon Sep 17 00:00:00 2001 From: des Date: Fri, 19 Oct 2001 01:43:06 +0000 Subject: 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. --- sys/fs/pseudofs/pseudofs.c | 217 ++++++++++++++++++++++++++++++++++++++- sys/fs/pseudofs/pseudofs.h | 72 +++++++------ sys/fs/pseudofs/pseudofs_vnops.c | 61 ++++++----- 3 files changed, 288 insertions(+), 62 deletions(-) (limited to 'sys/fs/pseudofs') 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 #include +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. -- cgit v1.1