Add support for process-dependent directories. This means that save for

the lack of a man page, pseudofs is mostly complete now.
This commit is contained in:
des 2001-06-10 18:39:21 +00:00
parent 081b21dba9
commit da96d2410a
6 changed files with 195 additions and 147 deletions

View File

@ -101,7 +101,7 @@ pfs_root(struct mount *mp, struct vnode **vpp)
struct pfs_info *pi;
pi = (struct pfs_info *)mp->mnt_data;
return pfs_vncache_alloc(mp, vpp, pi->pi_root);
return pfs_vncache_alloc(mp, vpp, pi->pi_root, NO_PID);
}
/*

View File

@ -45,12 +45,9 @@ typedef enum {
pfstype_parent,
pfstype_file,
pfstype_symlink,
pfstype_procdep
pfstype_procdir
} pfs_type_t;
/* Flags */
#define PFS_DYNAMIC 1
/*
* Data structures
*/
@ -58,7 +55,11 @@ struct pfs_info;
struct pfs_node;
struct pfs_bitmap;
typedef int (*pfs_fill_t)(struct pfs_node *, struct proc *, struct sbuf *);
#define PFS_FILL_ARGS \
struct proc *curp, struct proc *p, struct pfs_node *pn, struct sbuf *sb
#define PFS_FILL_PROTO(name) \
int name(PFS_FILL_ARGS);
typedef int (*pfs_fill_t)(PFS_FILL_ARGS);
struct pfs_bitmap; /* opaque */
@ -75,7 +76,7 @@ struct pfs_info {
};
/*
* pfs_node: describes a node (file or directory) within a pseudofs
* pfs_node: describes a node (file or directory) within a pseudofs
*/
struct pfs_node {
char pn_name[PFS_NAMELEN];
@ -94,12 +95,7 @@ struct pfs_node {
#define pn_nodes u1._pn_nodes
/* members below this line aren't initialized */
struct pfs_node *pn_parent;
union {
u_int32_t _pn_fileno;
struct pfs_node *_pn_shadow;
} u2;
#define pn_fileno u2._pn_fileno
#define pn_shadow u2._pn_shadow
u_int32_t pn_fileno;
};
#define PFS_NODE(name, type, flags, uid, gid, mode, data) \
@ -116,6 +112,8 @@ struct pfs_node {
PFS_NODE(name, pfstype_file, flags, uid, gid, mode, func)
#define PFS_SYMLINK(name, flags, uid, gid, mode, func) \
PFS_NODE(name, pfstype_symlink, flags, uid, gid, mode, func)
#define PFS_PROCDIR(uid, gid, mode, nodes) \
PFS_NODE("", pfstype_procdir, 0, uid, gid, mode, nodes)
#define PFS_LASTNODE \
PFS_NODE("", pfstype_none, 0, 0, 0, 0, NULL)

View File

@ -43,12 +43,12 @@
#include <fs/pseudofs/pseudofs.h>
#include <fs/pseudofs/pseudofs_internal.h>
static MALLOC_DEFINE(M_PFSFILENO, "pseudofs_fileno", "pseudofs fileno bitmap");
static MALLOC_DEFINE(M_PFSFILENO, "pfs_fileno", "pseudofs fileno bitmap");
static struct mtx pfs_fileno_mutex;
#define PFS_BITMAP_SIZE 4096
#define PFS_SLOT_BITS (sizeof(unsigned int) * CHAR_BIT)
#define PFS_SLOT_BITS (int)(sizeof(unsigned int) * CHAR_BIT)
#define PFS_BITMAP_BITS (PFS_BITMAP_SIZE * PFS_SLOT_BITS)
struct pfs_bitmap {
u_int32_t pb_offset;
@ -117,8 +117,11 @@ pfs_fileno_uninit(struct pfs_info *pi)
used += pb->pb_used;
FREE(pb, M_PFSFILENO);
}
#if 0
/* we currently don't reclaim filenos */
if (used > 2)
printf("WARNING: %d file numbers still in use\n", used);
#endif
}
/*
@ -202,6 +205,7 @@ pfs_free_fileno(struct pfs_info *pi, u_int32_t fileno)
--pb->pb_used;
mtx_unlock(&pi->pi_mutex);
printf("pfs_free_fileno(): reclaimed %d\n", fileno);
}
/*
@ -219,6 +223,7 @@ pfs_fileno_alloc(struct pfs_info *pi, struct pfs_node *pn)
case pfstype_dir:
case pfstype_file:
case pfstype_symlink:
case pfstype_procdir:
pn->pn_fileno = pfs_get_fileno(pi);
break;
case pfstype_this:
@ -237,16 +242,13 @@ pfs_fileno_alloc(struct pfs_info *pi, struct pfs_node *pn)
("pfstype_parent node has no grandparent"));
pn->pn_fileno = pn->pn_parent->pn_parent->pn_fileno;
break;
case pfstype_procdep:
KASSERT(1,
("pfs_fileno_alloc() called for pfstype_procdep node"));
break;
case pfstype_none:
KASSERT(1,
KASSERT(0,
("pfs_fileno_alloc() called for pfstype_none node"));
break;
}
#if 0
printf("pfs_fileno_alloc(): %s: ", pi->pi_name);
if (pn->pn_parent) {
if (pn->pn_parent->pn_parent) {
@ -255,6 +257,7 @@ pfs_fileno_alloc(struct pfs_info *pi, struct pfs_node *pn)
printf("%s/", pn->pn_parent->pn_name);
}
printf("%s -> %d\n", pn->pn_name, pn->pn_fileno);
#endif
}
/*
@ -268,18 +271,15 @@ pfs_fileno_free(struct pfs_info *pi, struct pfs_node *pn)
case pfstype_dir:
case pfstype_file:
case pfstype_symlink:
case pfstype_procdir:
pfs_free_fileno(pi, pn->pn_fileno);
break;
case pfstype_this:
case pfstype_parent:
/* ignore these, as they don't "own" their file number */
break;
case pfstype_procdep:
KASSERT(1,
("pfs_fileno_free() called for pfstype_procdep node"));
break;
case pfstype_none:
KASSERT(1,
KASSERT(0,
("pfs_fileno_free() called for pfstype_none node"));
break;
}

View File

@ -36,13 +36,21 @@
*/
SYSCTL_DECL(_vfs_pfs);
/*
* Vnode data
*/
struct pfs_vdata {
struct pfs_node *pvd_pn;
pid_t pvd_pid;
};
/*
* Vnode cache
*/
void pfs_vncache_load (void);
void pfs_vncache_unload (void);
int pfs_vncache_alloc (struct mount *, struct vnode **,
struct pfs_node *);
struct pfs_node *, pid_t pid);
int pfs_vncache_free (struct vnode *);
/*
@ -55,10 +63,4 @@ void pfs_fileno_uninit (struct pfs_info *);
void pfs_fileno_alloc (struct pfs_info *, struct pfs_node *);
void pfs_fileno_free (struct pfs_info *, struct pfs_node *);
/*
* Shadow manager
*/
void pfs_create_shadow (struct pfs_info *, struct pfs_node *, pid_t);
void pfs_reap_shadows (pid_t);
#endif

View File

@ -41,7 +41,7 @@
#include <fs/pseudofs/pseudofs.h>
#include <fs/pseudofs/pseudofs_internal.h>
static MALLOC_DEFINE(M_PFSVNCACHE, "pseudofs_vncache", "pseudofs vnode cache");
static MALLOC_DEFINE(M_PFSVNCACHE, "pfs_vncache", "pseudofs vnode cache");
static struct mtx pfs_vncache_mutex;
@ -85,32 +85,40 @@ pfs_vncache_unload(void)
* Allocate a vnode
*/
int
pfs_vncache_alloc(struct mount *mp, struct vnode **vpp, struct pfs_node *pn)
pfs_vncache_alloc(struct mount *mp, struct vnode **vpp,
struct pfs_node *pn, pid_t pid)
{
struct pfs_vnode *pv;
struct pfs_vdata *pvd;
int error;
mtx_lock(&pfs_vncache_mutex);
/* see if the vnode is in the cache */
for (pv = pfs_vncache; pv; pv = pv->pv_next)
if (pv->pv_vnode->v_data == pn)
mtx_lock(&pfs_vncache_mutex);
for (pv = pfs_vncache; pv; pv = pv->pv_next) {
pvd = (struct pfs_vdata *)pv->pv_vnode->v_data;
if (pvd->pvd_pn == pn && pvd->pvd_pid == pid) {
if (vget(pv->pv_vnode, 0, curproc) == 0) {
++pfs_vncache_hits;
*vpp = pv->pv_vnode;
mtx_unlock(&pfs_vncache_mutex);
return (0);
}
/* XXX if this can happen, we're in trouble */
break;
}
}
mtx_unlock(&pfs_vncache_mutex);
++pfs_vncache_misses;
/* nope, get a new one */
MALLOC(pv, struct pfs_vnode *, sizeof *pv, M_PFSVNCACHE, M_WAITOK);
MALLOC(pvd, struct pfs_vdata *, sizeof *pvd, M_PFSVNCACHE, M_WAITOK);
error = getnewvnode(VT_PSEUDOFS, mp, pfs_vnodeop_p, vpp);
if (error) {
mtx_unlock(&pfs_vncache_mutex);
if (error)
return (error);
}
(*vpp)->v_data = pn;
pvd->pvd_pn = pn;
pvd->pvd_pid = pid;
(*vpp)->v_data = pvd;
switch (pn->pn_type) {
case pfstype_root:
(*vpp)->v_flag = VROOT;
@ -120,6 +128,7 @@ pfs_vncache_alloc(struct mount *mp, struct vnode **vpp, struct pfs_node *pn)
case pfstype_dir:
case pfstype_this:
case pfstype_parent:
case pfstype_procdir:
(*vpp)->v_type = VDIR;
break;
case pfstype_file:
@ -128,10 +137,13 @@ pfs_vncache_alloc(struct mount *mp, struct vnode **vpp, struct pfs_node *pn)
case pfstype_symlink:
(*vpp)->v_type = VLNK;
break;
case pfstype_none:
KASSERT(0, ("pfs_vncache_alloc called for null node\n"));
default:
panic("%s has unexpected type: %d", pn->pn_name, pn->pn_type);
}
pv->pv_vnode = *vpp;
mtx_lock(&pfs_vncache_mutex);
pv->pv_next = pfs_vncache;
pfs_vncache = pv;
mtx_unlock(&pfs_vncache_mutex);
@ -145,25 +157,22 @@ int
pfs_vncache_free(struct vnode *vp)
{
struct pfs_vnode *prev, *pv;
struct pfs_vdata *pvd;
mtx_lock(&pfs_vncache_mutex);
for (prev = NULL, pv = pfs_vncache; pv; prev = pv, pv = pv->pv_next)
if (pv->pv_vnode == vp)
break;
if (!pv)
printf("pfs_vncache_free(): not in cache\n"); /* it should be! */
#if 0
if (vp->v_data == ((struct pfs_info *)vp->v_mount->mnt_data)->pi_root)
printf("root vnode reclaimed\n");
#endif
vp->v_data = NULL;
if (pv) {
if (prev)
prev->pv_next = pv->pv_next;
else
pfs_vncache = pv->pv_next;
FREE(pv, M_PFSVNCACHE);
}
KASSERT(pv != NULL, ("pfs_vncache_free(): not in cache\n"));
if (prev)
prev->pv_next = pv->pv_next;
else
pfs_vncache = pv->pv_next;
mtx_unlock(&pfs_vncache_mutex);
pvd = (struct pfs_vdata *)vp->v_data;
FREE(pvd, M_PFSVNCACHE);
vp->v_data = NULL;
FREE(pv, M_PFSVNCACHE);
return (0);
}

View File

@ -79,7 +79,8 @@ static int
pfs_getattr(struct vop_getattr_args *va)
{
struct vnode *vn = va->a_vp;
struct pfs_node *pn = (struct pfs_node *)vn->v_data;
struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
struct pfs_node *pn = pvd->pvd_pn;
struct vattr *vap = va->a_vap;
VATTR_NULL(vap);
@ -105,19 +106,17 @@ pfs_getattr(struct vop_getattr_args *va)
static int
pfs_lookup(struct vop_lookup_args *va)
{
struct vnode *dvp = va->a_dvp;
struct vnode *vn = va->a_dvp;
struct vnode **vpp = va->a_vpp;
struct componentname *cnp = va->a_cnp;
#if 0
struct pfs_info *pi = (struct pfs_info *)dvp->v_mount->mnt_data;
#endif
struct pfs_node *pd = (struct pfs_node *)dvp->v_data, *pn;
struct proc *p;
struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
struct pfs_node *pd = pvd->pvd_pn;
struct pfs_node *pn, *pdn = NULL;
pid_t pid = pvd->pvd_pid;
char *pname;
int error, i;
pid_t pid;
int error, i, namelen;
if (dvp->v_type != VDIR)
if (vn->v_type != VDIR)
return (ENOTDIR);
/* don't support CREATE, RENAME or DELETE */
@ -129,11 +128,12 @@ pfs_lookup(struct vop_lookup_args *va)
return (ENOENT);
/* self */
namelen = cnp->cn_namelen;
pname = cnp->cn_nameptr;
if (cnp->cn_namelen == 1 && *pname == '.') {
if (namelen == 1 && *pname == '.') {
pn = pd;
*vpp = dvp;
VREF(dvp);
*vpp = vn;
VREF(vn);
goto got_vnode;
}
@ -142,61 +142,48 @@ pfs_lookup(struct vop_lookup_args *va)
if (pd->pn_type == pfstype_root)
return (EIO);
KASSERT(pd->pn_parent, ("non-root directory has no parent"));
return pfs_vncache_alloc(dvp->v_mount, vpp, pd->pn_parent);
/*
* This one is tricky. Descendents of procdir nodes
* inherit their parent's process affinity, but
* there's no easy reverse mapping. For simplicity,
* we assume that if this node is a procdir, its
* parent isn't (which is correct as long as
* descendents of procdir nodes are never procdir
* nodes themselves)
*/
if (pd->pn_type == pfstype_procdir)
pid = NO_PID;
return pfs_vncache_alloc(vn->v_mount, vpp, pd->pn_parent, pid);
}
/* process dependent */
for (i = 0, pid = 0; i < cnp->cn_namelen && isdigit(pname[i]); ++i)
pid = pid * 10 + pname[i] - '0';
/* XXX assume that 8 digits is the maximum safe length for a pid */
if (i == cnp->cn_namelen && i < 8) {
/* see if this directory has process-dependent children */
for (pn = pd->pn_nodes; pn->pn_type; ++pn)
if (pn->pn_type == pfstype_procdep)
break;
if (pn->pn_type) {
/* XXX pfind(0) should DTRT here */
p = pid ? pfind(pid) : &proc0;
if (p == NULL)
return (ENOENT);
if (p_can(cnp->cn_proc, p, P_CAN_SEE, NULL)) {
/* pretend it doesn't exist */
PROC_UNLOCK(p);
return (ENOENT);
}
#if 0
if (!pn->pn_shadow)
pfs_create_shadow(pn, p);
pn = pn->pn_shadow;
PROC_UNLOCK(p);
/* named node */
for (pn = pd->pn_nodes; pn->pn_type; ++pn)
if (pn->pn_type == pfstype_procdir)
pdn = pn;
else if (pn->pn_name[namelen] == '\0'
&& bcmp(pname, pn->pn_name, namelen) == 0)
goto got_pnode;
#else
/* not yet implemented */
PROC_UNLOCK(p);
return (EIO);
#endif
}
}
/* something else */
for (pn = pd->pn_nodes; pn->pn_type; ++pn) {
for (i = 0; i < cnp->cn_namelen && pn->pn_name[i]; ++i)
if (pname[i] != pn->pn_name[i])
/* process dependent node */
if ((pn = pdn) != NULL) {
pid = 0;
for (pid = 0, i = 0; i < namelen && isdigit(pname[i]); ++i)
if ((pid = pid * 10 + pname[i] - '0') > PID_MAX)
break;
if (i == cnp->cn_namelen)
goto got_pnode;
}
return (ENOENT);
got_pnode:
if (!pn->pn_parent)
pn->pn_parent = pd;
error = pfs_vncache_alloc(dvp->v_mount, vpp, pn);
error = pfs_vncache_alloc(vn->v_mount, vpp, pn, pid);
if (error)
return error;
got_vnode:
if (cnp->cn_flags & MAKEENTRY)
cache_enter(dvp, *vpp, cnp);
cache_enter(vn, *vpp, cnp);
return (0);
}
@ -217,8 +204,10 @@ static int
pfs_read(struct vop_read_args *va)
{
struct vnode *vn = va->a_vp;
struct pfs_node *pn = vn->v_data;
struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
struct pfs_node *pn = pvd->pvd_pn;
struct uio *uio = va->a_uio;
struct proc *proc = NULL;
struct sbuf *sb = NULL;
char *ps;
int error, xlen;
@ -226,11 +215,24 @@ pfs_read(struct vop_read_args *va)
if (vn->v_type != VREG)
return (EINVAL);
if (pvd->pvd_pid != NO_PID) {
if ((proc = pfind(pvd->pvd_pid)) == NULL)
return (EIO);
_PHOLD(proc);
PROC_UNLOCK(proc);
}
sb = sbuf_new(sb, NULL, uio->uio_offset + uio->uio_resid, 0);
if (sb == NULL)
if (sb == NULL) {
if (proc != NULL)
PRELE(proc);
return (EIO);
}
error = (pn->pn_func)(pn, curproc, sb);
error = (pn->pn_func)(curproc, proc, pn, sb);
if (proc != NULL)
PRELE(proc);
/* XXX we should possibly detect and handle overflows */
sbuf_finish(sb);
@ -242,6 +244,34 @@ pfs_read(struct vop_read_args *va)
return (error);
}
/*
* Iterate through directory entries
*/
static int
pfs_iterate(struct pfs_info *pi, struct pfs_node **pn, struct proc **p)
{
if ((*pn)->pn_type == pfstype_none)
return (-1);
if ((*pn)->pn_type != pfstype_procdir)
++*pn;
while ((*pn)->pn_type == pfstype_procdir) {
if (*p == NULL)
*p = LIST_FIRST(&allproc);
else
*p = LIST_NEXT(*p, p_list);
if (*p != NULL)
return (0);
++*pn;
}
if ((*pn)->pn_type == pfstype_none)
return (-1);
return (0);
}
/*
* Return directory entries.
*/
@ -249,21 +279,18 @@ static int
pfs_readdir(struct vop_readdir_args *va)
{
struct vnode *vn = va->a_vp;
struct pfs_info *pi;
struct pfs_node *pd, *pn;
struct pfs_info *pi = (struct pfs_info *)vn->v_mount->mnt_data;
struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
struct pfs_node *pd = pvd->pvd_pn;
struct pfs_node *pn;
struct dirent entry;
struct uio *uio;
#if 0
struct proc *p;
#endif
off_t offset;
int error, i, resid;
if (vn->v_type != VDIR)
return (ENOTDIR);
pi = (struct pfs_info *)vn->v_mount->mnt_data;
pd = (struct pfs_node *)vn->v_data;
pn = pd->pn_nodes;
uio = va->a_uio;
/* only allow reading entire entries */
@ -273,23 +300,35 @@ pfs_readdir(struct vop_readdir_args *va)
return (EINVAL);
/* skip unwanted entries */
for (; pn->pn_type && offset > 0; ++pn, offset -= PFS_DELEN)
/* nothing */ ;
sx_slock(&allproc_lock);
for (pn = pd->pn_nodes, p = NULL; offset > 0; offset -= PFS_DELEN)
if (pfs_iterate(pi, &pn, &p) == -1)
break;
/* fill in entries */
entry.d_reclen = PFS_DELEN;
for (; pn->pn_type && resid > 0; ++pn) {
while (pfs_iterate(pi, &pn, &p) != -1 && resid > 0) {
if (!pn->pn_parent)
pn->pn_parent = pd;
if (!pn->pn_fileno)
pfs_fileno_alloc(pi, pn);
entry.d_fileno = pn->pn_fileno;
if (pvd->pvd_pid != NO_PID)
entry.d_fileno = pn->pn_fileno * NO_PID + pvd->pvd_pid;
else
entry.d_fileno = pn->pn_fileno;
/* PFS_DELEN was picked to fit PFS_NAMLEN */
for (i = 0; i < PFS_NAMELEN - 1 && pn->pn_name[i] != '\0'; ++i)
entry.d_name[i] = pn->pn_name[i];
entry.d_name[i] = 0;
entry.d_namlen = i;
switch (pn->pn_type) {
case pfstype_procdir:
KASSERT(p != NULL,
("reached procdir node with p == NULL"));
entry.d_fileno = pn->pn_fileno * NO_PID + p->p_pid;
entry.d_namlen = snprintf(entry.d_name,
PFS_NAMELEN, "%d", p->p_pid);
/* fall through */
case pfstype_root:
case pfstype_dir:
case pfstype_this:
@ -302,32 +341,19 @@ pfs_readdir(struct vop_readdir_args *va)
case pfstype_symlink:
entry.d_type = DT_LNK;
break;
case pfstype_procdep:
/* don't handle process-dependent nodes here */
continue;
default:
sx_sunlock(&allproc_lock);
panic("%s has unexpected node type: %d", pn->pn_name, pn->pn_type);
}
if ((error = uiomove((caddr_t)&entry, PFS_DELEN, uio)))
if ((error = uiomove((caddr_t)&entry, PFS_DELEN, uio))) {
sx_sunlock(&allproc_lock);
return (error);
}
offset += PFS_DELEN;
resid -= PFS_DELEN;
}
#if 0
for (pn = pd->pn_nodes; pn->pn_type && resid > 0; ++pn) {
if (pn->pn_type != pfstype_procdep)
continue;
sx_slock(&allproc_lock);
p = LIST_FIRST(&allproc);
sx_sunlock(&allproc_lock);
offset += PFS_DELEN;
resid -= PFS_DELEN;
break;
}
#endif
sx_sunlock(&allproc_lock);
uio->uio_offset += offset;
return (0);
}
@ -339,8 +365,10 @@ static int
pfs_readlink(struct vop_readlink_args *va)
{
struct vnode *vn = va->a_vp;
struct pfs_node *pn = vn->v_data;
struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data;
struct pfs_node *pn = pvd->pvd_pn;
struct uio *uio = va->a_uio;
struct proc *proc = NULL;
char buf[MAXPATHLEN], *ps;
struct sbuf sb;
int error, xlen;
@ -348,10 +376,20 @@ pfs_readlink(struct vop_readlink_args *va)
if (vn->v_type != VLNK)
return (EINVAL);
if (pvd->pvd_pid != NO_PID) {
if ((proc = pfind(pvd->pvd_pid)) == NULL)
return (EIO);
_PHOLD(proc);
PROC_UNLOCK(proc);
}
/* sbuf_new() can't fail with a static buffer */
sbuf_new(&sb, buf, sizeof buf, 0);
error = (pn->pn_func)(pn, curproc, &sb);
error = (pn->pn_func)(curproc, proc, pn, &sb);
if (proc != NULL)
PRELE(proc);
/* XXX we should detect and handle overflows */
sbuf_finish(&sb);
@ -378,8 +416,9 @@ pfs_reclaim(struct vop_reclaim_args *va)
static int
pfs_setattr(struct vop_setattr_args *va)
{
if (va->a_vap->va_flags != VNOVAL)
if (va->a_vap->va_flags != (u_long)VNOVAL)
return (EOPNOTSUPP);
/* XXX it's a bit more complex than that, really... */
return (0);
}