summaryrefslogtreecommitdiffstats
path: root/sys/fs/pseudofs
diff options
context:
space:
mode:
authordes <des@FreeBSD.org>2001-04-07 19:51:12 +0000
committerdes <des@FreeBSD.org>2001-04-07 19:51:12 +0000
commitee97bef8dd89a184a3515d56baff6c1a781f1ba6 (patch)
tree05e8f2351e2792762e92f202ccb77647d13a5e37 /sys/fs/pseudofs
parenta14b691e19c0cf1fa72557fdb74ec97158b014d1 (diff)
downloadFreeBSD-src-ee97bef8dd89a184a3515d56baff6c1a781f1ba6.zip
FreeBSD-src-ee97bef8dd89a184a3515d56baff6c1a781f1ba6.tar.gz
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 :)
Diffstat (limited to 'sys/fs/pseudofs')
-rw-r--r--sys/fs/pseudofs/pseudofs.c172
-rw-r--r--sys/fs/pseudofs/pseudofs.h181
-rw-r--r--sys/fs/pseudofs/pseudofs_fileno.c285
-rw-r--r--sys/fs/pseudofs/pseudofs_internal.h64
-rw-r--r--sys/fs/pseudofs/pseudofs_vncache.c168
-rw-r--r--sys/fs/pseudofs/pseudofs_vnops.c419
6 files changed, 1289 insertions, 0 deletions
diff --git a/sys/fs/pseudofs/pseudofs.c b/sys/fs/pseudofs/pseudofs.c
new file mode 100644
index 0000000..474fb3a
--- /dev/null
+++ b/sys/fs/pseudofs/pseudofs.c
@@ -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);
diff --git a/sys/fs/pseudofs/pseudofs.h b/sys/fs/pseudofs/pseudofs.h
new file mode 100644
index 0000000..928d2db
--- /dev/null
+++ b/sys/fs/pseudofs/pseudofs.h
@@ -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
diff --git a/sys/fs/pseudofs/pseudofs_fileno.c b/sys/fs/pseudofs/pseudofs_fileno.c
new file mode 100644
index 0000000..877b7b8
--- /dev/null
+++ b/sys/fs/pseudofs/pseudofs_fileno.c
@@ -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;
+ }
+}
diff --git a/sys/fs/pseudofs/pseudofs_internal.h b/sys/fs/pseudofs/pseudofs_internal.h
new file mode 100644
index 0000000..0e25c47
--- /dev/null
+++ b/sys/fs/pseudofs/pseudofs_internal.h
@@ -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
diff --git a/sys/fs/pseudofs/pseudofs_vncache.c b/sys/fs/pseudofs/pseudofs_vncache.c
new file mode 100644
index 0000000..86b837e
--- /dev/null
+++ b/sys/fs/pseudofs/pseudofs_vncache.c
@@ -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);
+}
diff --git a/sys/fs/pseudofs/pseudofs_vnops.c b/sys/fs/pseudofs/pseudofs_vnops.c
new file mode 100644
index 0000000..5516100
--- /dev/null
+++ b/sys/fs/pseudofs/pseudofs_vnops.c
@@ -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);
+
OpenPOWER on IntegriCloud