mirror of
https://github.com/freebsd/freebsd-src.git
synced 2024-11-30 02:12:45 +00:00
Let pseudofs into the warmth of the FreeBSD CVS repo.
It's not finished yet (I still have to find a way to implement process- dependent nodes without consuming too much memory, and the permission system needs tightening up), but it's becoming hard to work on without a repo (I've accidentally almost nuked it once already), and it works (except for the lack of process-dependent nodes, that is). I was supposed to commit this a week ago, but timed out waiting for jkh to reply to some questions I had. Pass him a spoonful of bad karma :)
This commit is contained in:
parent
525be862e6
commit
9733a80839
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=75295
172
sys/fs/pseudofs/pseudofs.c
Normal file
172
sys/fs/pseudofs/pseudofs.c
Normal file
@ -0,0 +1,172 @@
|
||||
/*-
|
||||
* Copyright (c) 2001 Dag-Erling Coïdan Smørgrav
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer
|
||||
* in this position and unchanged.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/sbuf.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <fs/pseudofs/pseudofs.h>
|
||||
#include <fs/pseudofs/pseudofs_internal.h>
|
||||
|
||||
SYSCTL_NODE(_vfs, OID_AUTO, pfs, CTLFLAG_RW, 0,
|
||||
"pseudofs");
|
||||
|
||||
/*
|
||||
* Mount a pseudofs instance
|
||||
*/
|
||||
int
|
||||
pfs_mount(struct pfs_info *pi, struct mount *mp, char *path, caddr_t data,
|
||||
struct nameidata *ndp, struct proc *p)
|
||||
{
|
||||
struct statfs *sbp;
|
||||
|
||||
if (mp->mnt_flag & MNT_UPDATE)
|
||||
return (EOPNOTSUPP);
|
||||
|
||||
mp->mnt_flag |= MNT_LOCAL;
|
||||
mp->mnt_data = (qaddr_t)pi;
|
||||
vfs_getnewfsid(mp);
|
||||
|
||||
sbp = &mp->mnt_stat;
|
||||
bcopy(pi->pi_name, sbp->f_mntfromname, sizeof pi->pi_name);
|
||||
sbp->f_bsize = PAGE_SIZE;
|
||||
sbp->f_iosize = PAGE_SIZE;
|
||||
sbp->f_blocks = 1;
|
||||
sbp->f_bfree = 0;
|
||||
sbp->f_bavail = 0;
|
||||
sbp->f_files = 1;
|
||||
sbp->f_ffree = 0;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unmount a pseudofs instance
|
||||
*/
|
||||
int
|
||||
pfs_unmount(struct mount *mp, int mntflags, struct proc *p)
|
||||
{
|
||||
struct pfs_info *pi;
|
||||
int error;
|
||||
|
||||
pi = (struct pfs_info *)mp->mnt_data;
|
||||
|
||||
/* XXX do stuff with pi... */
|
||||
|
||||
error = vflush(mp, 0, (mntflags & MNT_FORCE) ? FORCECLOSE : 0);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a root vnode
|
||||
*/
|
||||
int
|
||||
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 filesystem stats
|
||||
*/
|
||||
int
|
||||
pfs_statfs(struct mount *mp, struct statfs *sbp, struct proc *p)
|
||||
{
|
||||
bcopy(&mp->mnt_stat, sbp, sizeof *sbp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize a pseudofs instance
|
||||
*/
|
||||
int
|
||||
pfs_init(struct pfs_info *pi, struct vfsconf *vfc)
|
||||
{
|
||||
mtx_init(&pi->pi_mutex, "pseudofs", MTX_DEF);
|
||||
pfs_fileno_init(pi);
|
||||
printf("%s registered\n", pi->pi_name);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy a pseudofs instance
|
||||
*/
|
||||
int
|
||||
pfs_uninit(struct pfs_info *pi, struct vfsconf *vfc)
|
||||
{
|
||||
pfs_fileno_uninit(pi);
|
||||
mtx_destroy(&pi->pi_mutex);
|
||||
printf("%s unregistered\n", pi->pi_name);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle load / unload events
|
||||
*/
|
||||
static int
|
||||
pfs_modevent(module_t mod, int evt, void *arg)
|
||||
{
|
||||
switch (evt) {
|
||||
case MOD_LOAD:
|
||||
pfs_fileno_load();
|
||||
pfs_vncache_load();
|
||||
break;
|
||||
case MOD_UNLOAD:
|
||||
case MOD_SHUTDOWN:
|
||||
pfs_vncache_unload();
|
||||
pfs_fileno_unload();
|
||||
break;
|
||||
default:
|
||||
printf("pseudofs: unexpected event type %d\n", evt);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Module declaration
|
||||
*/
|
||||
static moduledata_t pseudofs_data = {
|
||||
"pseudofs",
|
||||
pfs_modevent,
|
||||
NULL
|
||||
};
|
||||
DECLARE_MODULE(pseudofs, pseudofs_data, SI_SUB_EXEC, SI_ORDER_FIRST);
|
||||
MODULE_VERSION(pseudofs, 1);
|
181
sys/fs/pseudofs/pseudofs.h
Normal file
181
sys/fs/pseudofs/pseudofs.h
Normal file
@ -0,0 +1,181 @@
|
||||
/*-
|
||||
* Copyright (c) 2001 Dag-Erling Coïdan Smørgrav
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer
|
||||
* in this position and unchanged.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _PSEUDOFS_H_INCLUDED
|
||||
#define _PSEUDOFS_H_INCLUDED
|
||||
|
||||
/*
|
||||
* Limits and constants
|
||||
*/
|
||||
#define PFS_NAMELEN 24
|
||||
#define PFS_DELEN (8 + PFS_NAMELEN)
|
||||
|
||||
typedef enum {
|
||||
pfstype_none = 0,
|
||||
pfstype_root,
|
||||
pfstype_dir,
|
||||
pfstype_this,
|
||||
pfstype_parent,
|
||||
pfstype_file,
|
||||
pfstype_symlink,
|
||||
pfstype_procdep
|
||||
} pfs_type_t;
|
||||
|
||||
/* Flags */
|
||||
#define PFS_DYNAMIC 1
|
||||
|
||||
/*
|
||||
* Data structures
|
||||
*/
|
||||
struct pfs_info;
|
||||
struct pfs_node;
|
||||
struct pfs_bitmap;
|
||||
|
||||
typedef int (*pfs_fill_t)(struct pfs_node *, struct proc *, struct sbuf *);
|
||||
|
||||
struct pfs_bitmap; /* opaque */
|
||||
|
||||
/*
|
||||
* pfs_info: describes a pseudofs instance
|
||||
*/
|
||||
struct pfs_info {
|
||||
char pi_name[MFSNAMELEN];
|
||||
struct pfs_node *pi_root;
|
||||
/* members below this line aren't initialized */
|
||||
/* currently, the mutex is only used to protect the bitmap */
|
||||
struct mtx pi_mutex;
|
||||
struct pfs_bitmap *pi_bitmap;
|
||||
};
|
||||
|
||||
/*
|
||||
* pfs_node: describes a node (file or directory) within a pseudofs
|
||||
*/
|
||||
struct pfs_node {
|
||||
char pn_name[PFS_NAMELEN];
|
||||
pfs_type_t pn_type;
|
||||
int pn_flags;
|
||||
uid_t pn_uid;
|
||||
gid_t pn_gid;
|
||||
mode_t pn_mode;
|
||||
union {
|
||||
void *_pn_data;
|
||||
pfs_fill_t _pn_func;
|
||||
struct pfs_node *_pn_nodes;
|
||||
} u1;
|
||||
#define pn_data u1._pn_data
|
||||
#define pn_func u1._pn_func
|
||||
#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
|
||||
};
|
||||
|
||||
#define PFS_NODE(name, type, flags, uid, gid, mode, data) \
|
||||
{ (name), (type), (flags), (uid), (gid), (mode), { (data) } }
|
||||
#define PFS_DIR(name, flags, uid, gid, mode, nodes) \
|
||||
PFS_NODE(name, pfstype_dir, flags, uid, gid, mode, nodes)
|
||||
#define PFS_ROOT(nodes) \
|
||||
PFS_NODE("/", pfstype_root, 0, 0, 0, 0555, nodes)
|
||||
#define PFS_THIS \
|
||||
PFS_NODE(".", pfstype_this, 0, 0, 0, 0, NULL)
|
||||
#define PFS_PARENT \
|
||||
PFS_NODE("..", pfstype_parent, 0, 0, 0, 0, NULL)
|
||||
#define PFS_FILE(name, flags, uid, gid, mode, func) \
|
||||
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_LASTNODE \
|
||||
PFS_NODE("", pfstype_none, 0, 0, 0, 0, NULL)
|
||||
|
||||
/*
|
||||
* VFS interface
|
||||
*/
|
||||
int pfs_mount (struct pfs_info *pi,
|
||||
struct mount *mp, char *path, caddr_t data,
|
||||
struct nameidata *ndp, struct proc *p);
|
||||
int pfs_unmount (struct mount *mp, int mntflags,
|
||||
struct proc *p);
|
||||
int pfs_root (struct mount *mp, struct vnode **vpp);
|
||||
int pfs_statfs (struct mount *mp, struct statfs *sbp,
|
||||
struct proc *p);
|
||||
int pfs_init (struct pfs_info *pi, struct vfsconf *vfc);
|
||||
int pfs_uninit (struct pfs_info *pi, struct vfsconf *vfc);
|
||||
|
||||
/*
|
||||
* Now for some initialization magic...
|
||||
*/
|
||||
#define PSEUDOFS(name, root) \
|
||||
\
|
||||
static struct pfs_info name##_info = { \
|
||||
#name, \
|
||||
&(root) \
|
||||
}; \
|
||||
\
|
||||
static int \
|
||||
_##name##_mount(struct mount *mp, char *path, caddr_t data, \
|
||||
struct nameidata *ndp, struct proc *p) { \
|
||||
return pfs_mount(&name##_info, mp, path, data, ndp, p); \
|
||||
} \
|
||||
\
|
||||
static int \
|
||||
_##name##_init(struct vfsconf *vfc) { \
|
||||
return pfs_init(&name##_info, vfc); \
|
||||
} \
|
||||
\
|
||||
static int \
|
||||
_##name##_uninit(struct vfsconf *vfc) { \
|
||||
return pfs_uninit(&name##_info, vfc); \
|
||||
} \
|
||||
\
|
||||
static struct vfsops testfs_vfsops = { \
|
||||
_##name##_mount, \
|
||||
vfs_stdstart, \
|
||||
pfs_unmount, \
|
||||
pfs_root, \
|
||||
vfs_stdquotactl, \
|
||||
pfs_statfs, \
|
||||
vfs_stdsync, \
|
||||
vfs_stdvget, \
|
||||
vfs_stdfhtovp, \
|
||||
vfs_stdcheckexp, \
|
||||
vfs_stdvptofh, \
|
||||
_##name##_init, \
|
||||
_##name##_uninit, \
|
||||
vfs_stdextattrctl, \
|
||||
}; \
|
||||
VFS_SET(name##_vfsops, name, VFCF_SYNTHETIC); \
|
||||
MODULE_DEPEND(name, pseudofs, 1, 1, 1);
|
||||
|
||||
#endif
|
285
sys/fs/pseudofs/pseudofs_fileno.c
Normal file
285
sys/fs/pseudofs/pseudofs_fileno.c
Normal file
@ -0,0 +1,285 @@
|
||||
/*-
|
||||
* Copyright (c) 2001 Dag-Erling Coïdan Smørgrav
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer
|
||||
* in this position and unchanged.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/sbuf.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include <machine/limits.h>
|
||||
|
||||
#include <fs/pseudofs/pseudofs.h>
|
||||
#include <fs/pseudofs/pseudofs_internal.h>
|
||||
|
||||
static MALLOC_DEFINE(M_PFSFILENO, "pseudofs_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_BITMAP_BITS (PFS_BITMAP_SIZE * PFS_SLOT_BITS)
|
||||
struct pfs_bitmap {
|
||||
u_int32_t pb_offset;
|
||||
int pb_used;
|
||||
unsigned int pb_bitmap[PFS_BITMAP_SIZE];
|
||||
struct pfs_bitmap *pb_next;
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialization
|
||||
*/
|
||||
void
|
||||
pfs_fileno_load(void)
|
||||
{
|
||||
mtx_init(&pfs_fileno_mutex, "pseudofs_fileno", MTX_DEF);
|
||||
}
|
||||
|
||||
/*
|
||||
* Teardown
|
||||
*/
|
||||
void
|
||||
pfs_fileno_unload(void)
|
||||
{
|
||||
mtx_destroy(&pfs_fileno_mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize fileno bitmap
|
||||
*/
|
||||
void
|
||||
pfs_fileno_init(struct pfs_info *pi)
|
||||
{
|
||||
struct pfs_bitmap *pb;
|
||||
|
||||
MALLOC(pb, struct pfs_bitmap *, sizeof *pb,
|
||||
M_PFSFILENO, M_WAITOK|M_ZERO);
|
||||
|
||||
mtx_lock(&pi->pi_mutex);
|
||||
|
||||
pb->pb_bitmap[0] = 07;
|
||||
pb->pb_used = 3;
|
||||
pi->pi_bitmap = pb;
|
||||
pi->pi_root->pn_fileno = 2;
|
||||
|
||||
mtx_unlock(&pi->pi_mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tear down fileno bitmap
|
||||
*/
|
||||
void
|
||||
pfs_fileno_uninit(struct pfs_info *pi)
|
||||
{
|
||||
struct pfs_bitmap *pb, *npb;
|
||||
int used;
|
||||
|
||||
mtx_lock(&pi->pi_mutex);
|
||||
|
||||
pb = pi->pi_bitmap;
|
||||
pi->pi_bitmap = NULL;
|
||||
|
||||
mtx_unlock(&pi->pi_mutex);
|
||||
|
||||
for (used = 0; pb; pb = npb) {
|
||||
npb = pb->pb_next;
|
||||
used += pb->pb_used;
|
||||
FREE(pb, M_PFSFILENO);
|
||||
}
|
||||
if (used > 2)
|
||||
printf("WARNING: %d file numbers still in use\n", used);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the next available file number
|
||||
*/
|
||||
static u_int32_t
|
||||
pfs_get_fileno(struct pfs_info *pi)
|
||||
{
|
||||
struct pfs_bitmap *pb, *ppb;
|
||||
u_int32_t fileno;
|
||||
unsigned int *p;
|
||||
int i;
|
||||
|
||||
mtx_lock(&pi->pi_mutex);
|
||||
|
||||
/* look for the first page with free bits */
|
||||
for (ppb = NULL, pb = pi->pi_bitmap; pb; ppb = pb, pb = pb->pb_next)
|
||||
if (pb->pb_used != PFS_BITMAP_BITS)
|
||||
break;
|
||||
|
||||
/* out of pages? */
|
||||
if (pb == NULL) {
|
||||
mtx_unlock(&pi->pi_mutex);
|
||||
MALLOC(pb, struct pfs_bitmap *, sizeof *pb,
|
||||
M_PFSFILENO, M_WAITOK|M_ZERO);
|
||||
mtx_lock(&pi->pi_mutex);
|
||||
/* protect against possible race */
|
||||
while (ppb->pb_next)
|
||||
ppb = ppb->pb_next;
|
||||
pb->pb_offset = ppb->pb_offset + PFS_BITMAP_BITS;
|
||||
ppb->pb_next = pb;
|
||||
}
|
||||
|
||||
/* find the first free slot */
|
||||
for (i = 0; i < PFS_BITMAP_SIZE; ++i)
|
||||
if (pb->pb_bitmap[i] != UINT_MAX)
|
||||
break;
|
||||
|
||||
/* find the first available bit and flip it */
|
||||
fileno = pb->pb_offset + i * PFS_SLOT_BITS;
|
||||
p = &pb->pb_bitmap[i];
|
||||
for (i = 0; i < PFS_SLOT_BITS; ++i, ++fileno)
|
||||
if ((*p & (unsigned int)(1 << i)) == 0)
|
||||
break;
|
||||
KASSERT(i < PFS_SLOT_BITS,
|
||||
("slot has free bits, yet doesn't"));
|
||||
*p |= (unsigned int)(1 << i);
|
||||
++pb->pb_used;
|
||||
|
||||
mtx_unlock(&pi->pi_mutex);
|
||||
|
||||
return fileno;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free a file number
|
||||
*/
|
||||
static void
|
||||
pfs_free_fileno(struct pfs_info *pi, u_int32_t fileno)
|
||||
{
|
||||
struct pfs_bitmap *pb;
|
||||
unsigned int *p;
|
||||
int i;
|
||||
|
||||
mtx_lock(&pi->pi_mutex);
|
||||
|
||||
/* find the right page */
|
||||
for (pb = pi->pi_bitmap;
|
||||
pb && fileno >= PFS_BITMAP_BITS;
|
||||
pb = pb->pb_next, fileno -= PFS_BITMAP_BITS)
|
||||
/* nothing */ ;
|
||||
KASSERT(pb,
|
||||
("fileno isn't in any bitmap"));
|
||||
|
||||
/* find the right bit in the right slot and flip it */
|
||||
p = &pb->pb_bitmap[fileno / PFS_SLOT_BITS];
|
||||
i = fileno % PFS_SLOT_BITS;
|
||||
KASSERT(*p & (unsigned int)(1 << i),
|
||||
("fileno is already free"));
|
||||
*p &= ~((unsigned int)(1 << i));
|
||||
--pb->pb_used;
|
||||
|
||||
mtx_unlock(&pi->pi_mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a file number
|
||||
*/
|
||||
void
|
||||
pfs_fileno_alloc(struct pfs_info *pi, struct pfs_node *pn)
|
||||
{
|
||||
/* make sure our parent has a file number */
|
||||
if (pn->pn_parent && !pn->pn_parent->pn_fileno)
|
||||
pfs_fileno_alloc(pi, pn->pn_parent);
|
||||
|
||||
switch (pn->pn_type) {
|
||||
case pfstype_root:
|
||||
case pfstype_dir:
|
||||
case pfstype_file:
|
||||
case pfstype_symlink:
|
||||
pn->pn_fileno = pfs_get_fileno(pi);
|
||||
break;
|
||||
case pfstype_this:
|
||||
KASSERT(pn->pn_parent != NULL,
|
||||
("pfstype_this node has no parent"));
|
||||
pn->pn_fileno = pn->pn_parent->pn_fileno;
|
||||
break;
|
||||
case pfstype_parent:
|
||||
KASSERT(pn->pn_parent != NULL,
|
||||
("pfstype_parent node has no parent"));
|
||||
if (pn->pn_parent == pi->pi_root) {
|
||||
pn->pn_fileno = pn->pn_parent->pn_fileno;
|
||||
break;
|
||||
}
|
||||
KASSERT(pn->pn_parent->pn_parent != NULL,
|
||||
("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,
|
||||
("pfs_fileno_alloc() called for pfstype_none node"));
|
||||
break;
|
||||
}
|
||||
|
||||
printf("pfs_fileno_alloc(): %s: ", pi->pi_name);
|
||||
if (pn->pn_parent) {
|
||||
if (pn->pn_parent->pn_parent) {
|
||||
printf("%s/", pn->pn_parent->pn_parent->pn_name);
|
||||
}
|
||||
printf("%s/", pn->pn_parent->pn_name);
|
||||
}
|
||||
printf("%s -> %d\n", pn->pn_name, pn->pn_fileno);
|
||||
}
|
||||
|
||||
/*
|
||||
* Release a file number
|
||||
*/
|
||||
void
|
||||
pfs_fileno_free(struct pfs_info *pi, struct pfs_node *pn)
|
||||
{
|
||||
switch (pn->pn_type) {
|
||||
case pfstype_root:
|
||||
case pfstype_dir:
|
||||
case pfstype_file:
|
||||
case pfstype_symlink:
|
||||
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,
|
||||
("pfs_fileno_free() called for pfstype_none node"));
|
||||
break;
|
||||
}
|
||||
}
|
64
sys/fs/pseudofs/pseudofs_internal.h
Normal file
64
sys/fs/pseudofs/pseudofs_internal.h
Normal file
@ -0,0 +1,64 @@
|
||||
/*-
|
||||
* Copyright (c) 2001 Dag-Erling Coïdan Smørgrav
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer
|
||||
* in this position and unchanged.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _PSEUDOFS_INTERNAL_H_INCLUDED
|
||||
#define _PSEUDOFS_INTERNAL_H_INCLUDED
|
||||
|
||||
/*
|
||||
* Sysctl subtree
|
||||
*/
|
||||
SYSCTL_DECL(_vfs_pfs);
|
||||
|
||||
/*
|
||||
* Vnode cache
|
||||
*/
|
||||
void pfs_vncache_load (void);
|
||||
void pfs_vncache_unload (void);
|
||||
int pfs_vncache_alloc (struct mount *, struct vnode **,
|
||||
struct pfs_node *);
|
||||
int pfs_vncache_free (struct vnode *);
|
||||
|
||||
/*
|
||||
* File number bitmap
|
||||
*/
|
||||
void pfs_fileno_load (void);
|
||||
void pfs_fileno_unload (void);
|
||||
void pfs_fileno_init (struct pfs_info *);
|
||||
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
|
168
sys/fs/pseudofs/pseudofs_vncache.c
Normal file
168
sys/fs/pseudofs/pseudofs_vncache.c
Normal file
@ -0,0 +1,168 @@
|
||||
/*-
|
||||
* Copyright (c) 2001 Dag-Erling Coïdan Smørgrav
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer
|
||||
* in this position and unchanged.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/sbuf.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <fs/pseudofs/pseudofs.h>
|
||||
#include <fs/pseudofs/pseudofs_internal.h>
|
||||
|
||||
static MALLOC_DEFINE(M_PFSVNCACHE, "pseudofs_vncache", "pseudofs vnode cache");
|
||||
|
||||
static struct mtx pfs_vncache_mutex;
|
||||
|
||||
struct pfs_vnode {
|
||||
struct vnode *pv_vnode;
|
||||
struct pfs_vnode *pv_next;
|
||||
} *pfs_vncache;
|
||||
|
||||
SYSCTL_NODE(_vfs_pfs, OID_AUTO, vncache, CTLFLAG_RW, 0,
|
||||
"pseudofs vnode cache");
|
||||
|
||||
static int pfs_vncache_hits;
|
||||
SYSCTL_INT(_vfs_pfs_vncache, OID_AUTO, hits, CTLFLAG_RD, &pfs_vncache_hits, 0,
|
||||
"number of cache hits since initialization");
|
||||
|
||||
static int pfs_vncache_misses;
|
||||
SYSCTL_INT(_vfs_pfs_vncache, OID_AUTO, misses, CTLFLAG_RD, &pfs_vncache_misses, 0,
|
||||
"number of cache misses since initialization");
|
||||
|
||||
extern vop_t **pfs_vnodeop_p;
|
||||
|
||||
/*
|
||||
* Initialize vnode cache
|
||||
*/
|
||||
void
|
||||
pfs_vncache_load(void)
|
||||
{
|
||||
mtx_init(&pfs_vncache_mutex, "pseudofs_vncache", MTX_DEF);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tear down vnode cache
|
||||
*/
|
||||
void
|
||||
pfs_vncache_unload(void)
|
||||
{
|
||||
mtx_destroy(&pfs_vncache_mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a vnode
|
||||
*/
|
||||
int
|
||||
pfs_vncache_alloc(struct mount *mp, struct vnode **vpp, struct pfs_node *pn)
|
||||
{
|
||||
struct pfs_vnode *pv;
|
||||
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)
|
||||
if (vget(pv->pv_vnode, 0, curproc) == 0) {
|
||||
++pfs_vncache_hits;
|
||||
*vpp = pv->pv_vnode;
|
||||
mtx_unlock(&pfs_vncache_mutex);
|
||||
return (0);
|
||||
}
|
||||
++pfs_vncache_misses;
|
||||
|
||||
/* nope, get a new one */
|
||||
MALLOC(pv, struct pfs_vnode *, sizeof *pv, M_PFSVNCACHE, M_WAITOK);
|
||||
error = getnewvnode(VT_PSEUDOFS, mp, pfs_vnodeop_p, vpp);
|
||||
if (error) {
|
||||
mtx_unlock(&pfs_vncache_mutex);
|
||||
return (error);
|
||||
}
|
||||
(*vpp)->v_data = pn;
|
||||
switch (pn->pn_type) {
|
||||
case pfstype_root:
|
||||
(*vpp)->v_flag = VROOT;
|
||||
#if 0
|
||||
printf("root vnode allocated\n");
|
||||
#endif
|
||||
case pfstype_dir:
|
||||
case pfstype_this:
|
||||
case pfstype_parent:
|
||||
(*vpp)->v_type = VDIR;
|
||||
break;
|
||||
case pfstype_file:
|
||||
(*vpp)->v_type = VREG;
|
||||
break;
|
||||
case pfstype_symlink:
|
||||
(*vpp)->v_type = VLNK;
|
||||
break;
|
||||
default:
|
||||
panic("%s has unexpected type: %d", pn->pn_name, pn->pn_type);
|
||||
}
|
||||
pv->pv_vnode = *vpp;
|
||||
pv->pv_next = pfs_vncache;
|
||||
pfs_vncache = pv;
|
||||
mtx_unlock(&pfs_vncache_mutex);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free a vnode
|
||||
*/
|
||||
int
|
||||
pfs_vncache_free(struct vnode *vp)
|
||||
{
|
||||
struct pfs_vnode *prev, *pv;
|
||||
|
||||
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);
|
||||
}
|
||||
mtx_unlock(&pfs_vncache_mutex);
|
||||
return (0);
|
||||
}
|
419
sys/fs/pseudofs/pseudofs_vnops.c
Normal file
419
sys/fs/pseudofs/pseudofs_vnops.c
Normal file
@ -0,0 +1,419 @@
|
||||
/*-
|
||||
* Copyright (c) 2001 Dag-Erling Coïdan Smørgrav
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer
|
||||
* in this position and unchanged.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/ctype.h>
|
||||
#include <sys/dirent.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/sbuf.h>
|
||||
#include <sys/sx.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <fs/pseudofs/pseudofs.h>
|
||||
#include <fs/pseudofs/pseudofs_internal.h>
|
||||
|
||||
/*
|
||||
* Verify permissions
|
||||
*/
|
||||
static int
|
||||
pfs_access(struct vop_access_args *va)
|
||||
{
|
||||
struct vnode *vn = va->a_vp;
|
||||
struct vattr vattr;
|
||||
int error;
|
||||
|
||||
error = VOP_GETATTR(vn, &vattr, va->a_cred, va->a_p);
|
||||
if (error)
|
||||
return (error);
|
||||
error = vaccess(vn->v_type, vattr.va_mode, vattr.va_uid,
|
||||
vattr.va_gid, va->a_mode, va->a_cred, NULL);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Close a file or directory
|
||||
*/
|
||||
static int
|
||||
pfs_close(struct vop_close_args *va)
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get file attributes
|
||||
*/
|
||||
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 vattr *vap = va->a_vap;
|
||||
|
||||
VATTR_NULL(vap);
|
||||
vap->va_type = vn->v_type;
|
||||
vap->va_mode = pn->pn_mode;
|
||||
vap->va_fileid = pn->pn_fileno;
|
||||
vap->va_flags = 0;
|
||||
vap->va_blocksize = PAGE_SIZE;
|
||||
vap->va_bytes = vap->va_size = 0;
|
||||
vap->va_fsid = vn->v_mount->mnt_stat.f_fsid.val[0];
|
||||
vap->va_nlink = 1;
|
||||
nanotime(&vap->va_ctime);
|
||||
vap->va_atime = vap->va_mtime = vap->va_ctime;
|
||||
vap->va_uid = pn->pn_uid;
|
||||
vap->va_gid = pn->pn_gid;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up a file or directory
|
||||
*/
|
||||
static int
|
||||
pfs_lookup(struct vop_lookup_args *va)
|
||||
{
|
||||
struct vnode *dvp = 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;
|
||||
char *pname;
|
||||
int error, i;
|
||||
pid_t pid;
|
||||
|
||||
if (dvp->v_type != VDIR)
|
||||
return (ENOTDIR);
|
||||
|
||||
/* don't support CREATE, RENAME or DELETE */
|
||||
if (cnp->cn_nameiop != LOOKUP)
|
||||
return (EROFS);
|
||||
|
||||
/* shortcut */
|
||||
if (cnp->cn_namelen >= PFS_NAMELEN)
|
||||
return (ENOENT);
|
||||
|
||||
/* self */
|
||||
pname = cnp->cn_nameptr;
|
||||
if (cnp->cn_namelen == 1 && *pname == '.') {
|
||||
pn = pd;
|
||||
*vpp = dvp;
|
||||
VREF(dvp);
|
||||
goto got_vnode;
|
||||
}
|
||||
|
||||
/* parent */
|
||||
if (cnp->cn_flags & ISDOTDOT) {
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
return (ENOENT);
|
||||
#if 0
|
||||
if (!pn->pn_shadow)
|
||||
pfs_create_shadow(pn, p);
|
||||
pn = pn->pn_shadow;
|
||||
goto got_pnode;
|
||||
#else
|
||||
/* not yet implemented */
|
||||
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])
|
||||
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);
|
||||
if (error)
|
||||
return error;
|
||||
got_vnode:
|
||||
if (cnp->cn_flags & MAKEENTRY)
|
||||
cache_enter(dvp, *vpp, cnp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Open a file or directory.
|
||||
*/
|
||||
static int
|
||||
pfs_open(struct vop_open_args *va)
|
||||
{
|
||||
/* XXX */
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read from a file
|
||||
*/
|
||||
static int
|
||||
pfs_read(struct vop_read_args *va)
|
||||
{
|
||||
struct vnode *vn = va->a_vp;
|
||||
struct pfs_node *pn = vn->v_data;
|
||||
struct uio *uio = va->a_uio;
|
||||
struct sbuf sb;
|
||||
char *ps;
|
||||
int error, xlen;
|
||||
|
||||
if (vn->v_type != VREG)
|
||||
return (EINVAL);
|
||||
|
||||
error = sbuf_new(&sb, NULL, uio->uio_offset + uio->uio_resid, 0);
|
||||
if (error)
|
||||
return (EIO);
|
||||
|
||||
error = (pn->pn_func)(pn, curproc, &sb);
|
||||
|
||||
/* XXX we should possibly detect and handle overflows */
|
||||
sbuf_finish(&sb);
|
||||
ps = sbuf_data(&sb) + uio->uio_offset;
|
||||
xlen = sbuf_len(&sb) - uio->uio_offset;
|
||||
xlen = imin(xlen, uio->uio_resid);
|
||||
error = (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
|
||||
sbuf_delete(&sb);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return directory entries.
|
||||
*/
|
||||
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 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 */
|
||||
offset = uio->uio_offset;
|
||||
resid = uio->uio_resid;
|
||||
if (offset < 0 || offset % PFS_DELEN != 0 || resid < PFS_DELEN)
|
||||
return (EINVAL);
|
||||
|
||||
/* skip unwanted entries */
|
||||
for (; pn->pn_type && offset > 0; ++pn, offset -= PFS_DELEN)
|
||||
/* nothing */ ;
|
||||
|
||||
/* fill in entries */
|
||||
entry.d_reclen = PFS_DELEN;
|
||||
for (; pn->pn_type && resid > 0; ++pn) {
|
||||
if (!pn->pn_parent)
|
||||
pn->pn_parent = pd;
|
||||
if (!pn->pn_fileno)
|
||||
pfs_fileno_alloc(pi, pn);
|
||||
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_root:
|
||||
case pfstype_dir:
|
||||
case pfstype_this:
|
||||
case pfstype_parent:
|
||||
entry.d_type = DT_DIR;
|
||||
break;
|
||||
case pfstype_file:
|
||||
entry.d_type = DT_REG;
|
||||
break;
|
||||
case pfstype_symlink:
|
||||
entry.d_type = DT_LNK;
|
||||
break;
|
||||
case pfstype_procdep:
|
||||
/* don't handle process-dependent nodes here */
|
||||
continue;
|
||||
default:
|
||||
panic("%s has unexpected node type: %d", pn->pn_name, pn->pn_type);
|
||||
}
|
||||
if ((error = uiomove((caddr_t)&entry, PFS_DELEN, uio)))
|
||||
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
|
||||
|
||||
uio->uio_offset += offset;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a symbolic link
|
||||
*/
|
||||
static int
|
||||
pfs_readlink(struct vop_readlink_args *va)
|
||||
{
|
||||
struct vnode *vn = va->a_vp;
|
||||
struct pfs_node *pn = vn->v_data;
|
||||
struct uio *uio = va->a_uio;
|
||||
char buf[MAXPATHLEN], *ps;
|
||||
struct sbuf sb;
|
||||
int error, xlen;
|
||||
|
||||
if (vn->v_type != VLNK)
|
||||
return (EINVAL);
|
||||
|
||||
/* sbuf_new() can't fail with a static buffer */
|
||||
sbuf_new(&sb, buf, sizeof buf, 0);
|
||||
|
||||
error = (pn->pn_func)(pn, curproc, &sb);
|
||||
|
||||
/* XXX we should detect and handle overflows */
|
||||
sbuf_finish(&sb);
|
||||
ps = sbuf_data(&sb) + uio->uio_offset;
|
||||
xlen = sbuf_len(&sb) - uio->uio_offset;
|
||||
xlen = imin(xlen, uio->uio_resid);
|
||||
error = (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
|
||||
sbuf_delete(&sb);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reclaim a vnode
|
||||
*/
|
||||
static int
|
||||
pfs_reclaim(struct vop_reclaim_args *va)
|
||||
{
|
||||
return (pfs_vncache_free(va->a_vp));
|
||||
}
|
||||
|
||||
/*
|
||||
* Set attributes
|
||||
*/
|
||||
static int
|
||||
pfs_setattr(struct vop_setattr_args *va)
|
||||
{
|
||||
if (va->a_vap->va_flags != VNOVAL)
|
||||
return (EOPNOTSUPP);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Dummy operations
|
||||
*/
|
||||
static int pfs_erofs(void *va) { return (EROFS); }
|
||||
static int pfs_null(void *va) { return (0); }
|
||||
|
||||
/*
|
||||
* Vnode operations
|
||||
*/
|
||||
vop_t **pfs_vnodeop_p;
|
||||
static struct vnodeopv_entry_desc pfs_vnodeop_entries[] = {
|
||||
{ &vop_default_desc, (vop_t *)vop_defaultop },
|
||||
{ &vop_access_desc, (vop_t *)pfs_access },
|
||||
{ &vop_close_desc, (vop_t *)pfs_close },
|
||||
{ &vop_create_desc, (vop_t *)pfs_erofs },
|
||||
{ &vop_getattr_desc, (vop_t *)pfs_getattr },
|
||||
{ &vop_link_desc, (vop_t *)pfs_erofs },
|
||||
{ &vop_lookup_desc, (vop_t *)pfs_lookup },
|
||||
{ &vop_mkdir_desc, (vop_t *)pfs_erofs },
|
||||
{ &vop_open_desc, (vop_t *)pfs_open },
|
||||
{ &vop_read_desc, (vop_t *)pfs_read },
|
||||
{ &vop_readdir_desc, (vop_t *)pfs_readdir },
|
||||
{ &vop_readlink_desc, (vop_t *)pfs_readlink },
|
||||
{ &vop_reclaim_desc, (vop_t *)pfs_reclaim },
|
||||
{ &vop_remove_desc, (vop_t *)pfs_erofs },
|
||||
{ &vop_rename_desc, (vop_t *)pfs_erofs },
|
||||
{ &vop_rmdir_desc, (vop_t *)pfs_erofs },
|
||||
{ &vop_setattr_desc, (vop_t *)pfs_setattr },
|
||||
{ &vop_symlink_desc, (vop_t *)pfs_erofs },
|
||||
{ &vop_write_desc, (vop_t *)pfs_erofs },
|
||||
/* XXX I've probably forgotten a few that need pfs_erofs */
|
||||
{ NULL, (vop_t *)NULL }
|
||||
};
|
||||
|
||||
static struct vnodeopv_desc pfs_vnodeop_opv_desc =
|
||||
{ &pfs_vnodeop_p, pfs_vnodeop_entries };
|
||||
|
||||
VNODEOP_SET(pfs_vnodeop_opv_desc);
|
||||
|
Loading…
Reference in New Issue
Block a user