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:
parent
081b21dba9
commit
da96d2410a
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user