summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>2000-08-20 21:34:39 +0000
committerphk <phk@FreeBSD.org>2000-08-20 21:34:39 +0000
commitb648921accec69a7e5c83e915ded3037cbca7f3d (patch)
treefa2e43c05e3c1d31732408f806d72db091c03d14
parent1c624ac57c791b6df4b51eb86e04dc404052c700 (diff)
downloadFreeBSD-src-b648921accec69a7e5c83e915ded3037cbca7f3d.zip
FreeBSD-src-b648921accec69a7e5c83e915ded3037cbca7f3d.tar.gz
Remove all traces of Julians DEVFS (incl from kern/subr_diskslice.c)
Remove old DEVFS support fields from dev_t. Make uid, gid & mode members of dev_t and set them in make_dev(). Use correct uid, gid & mode in make_dev in disk minilayer. Add support for registering alias names for a dev_t using the new function make_dev_alias(). These will show up as symlinks in DEVFS. Use makedev() rather than make_dev() for MFSs magic devices to prevent DEVFS from noticing this abuse. Add a field for DEVFS inode number in dev_t. Add new DEVFS in fs/devfs. Add devfs cloning to: disk minilayer (ie: ad(4), sd(4), cd(4) etc etc) md(4), tun(4), bpf(4), fd(4) If DEVFS add -d flag to /sbin/inits args to make it mount devfs. Add commented out DEVFS to GENERIC
-rw-r--r--sys/amd64/conf/GENERIC1
-rw-r--r--sys/conf/files6
-rw-r--r--sys/dev/bktr/bktr_os.c14
-rw-r--r--sys/dev/fdc/fdc.c88
-rw-r--r--sys/dev/md/md.c68
-rw-r--r--sys/fs/devfs/devfs.h97
-rw-r--r--sys/fs/devfs/devfs_devs.c230
-rw-r--r--sys/fs/devfs/devfs_vfsops.c243
-rw-r--r--sys/fs/devfs/devfs_vnops.c569
-rw-r--r--sys/i386/conf/GENERIC1
-rw-r--r--sys/i4b/driver/i4b_ctl.c11
-rw-r--r--sys/i4b/driver/i4b_rbch.c12
-rw-r--r--sys/i4b/driver/i4b_tel.c13
-rw-r--r--sys/i4b/driver/i4b_trace.c12
-rw-r--r--sys/i4b/layer4/i4b_i4bdrv.c11
-rw-r--r--sys/isa/fd.c88
-rw-r--r--sys/kern/init_main.c5
-rw-r--r--sys/kern/kern_conf.c69
-rw-r--r--sys/kern/subr_disk.c77
-rw-r--r--sys/kern/subr_diskslice.c108
-rw-r--r--sys/kern/tty_pty.c73
-rw-r--r--sys/miscfs/devfs/README118
-rw-r--r--sys/miscfs/devfs/devfs_proto.h27
-rw-r--r--sys/miscfs/devfs/devfs_tree.c1297
-rw-r--r--sys/miscfs/devfs/devfs_vfsops.c313
-rw-r--r--sys/miscfs/devfs/devfs_vnops.c2014
-rw-r--r--sys/miscfs/devfs/devfsdefs.h203
-rw-r--r--sys/miscfs/devfs/reproto.sh45
-rw-r--r--sys/net/bpf.c32
-rw-r--r--sys/net/if_tun.c34
-rw-r--r--sys/sys/conf.h15
-rw-r--r--sys/sys/devfsext.h80
-rw-r--r--sys/sys/kernel.h1
-rw-r--r--sys/sys/linedisc.h15
-rw-r--r--sys/ufs/mfs/mfs_vfsops.c3
35 files changed, 1643 insertions, 4350 deletions
diff --git a/sys/amd64/conf/GENERIC b/sys/amd64/conf/GENERIC
index 500cccb..54f13e0 100644
--- a/sys/amd64/conf/GENERIC
+++ b/sys/amd64/conf/GENERIC
@@ -36,6 +36,7 @@ options FFS #Berkeley Fast Filesystem
options FFS_ROOT #FFS usable as root device [keep this!]
options SOFTUPDATES #Enable FFS soft updates support
options MFS #Memory Filesystem
+#options DEVFS #Device Filesystem
options MD_ROOT #MD is a potential root device
options NFS #Network Filesystem
options NFS_ROOT #NFS usable as root device, NFS required
diff --git a/sys/conf/files b/sys/conf/files
index 7ee690d..a6dde43 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -337,6 +337,9 @@ dev/vx/if_vx.c count vx
dev/vx/if_vx_eisa.c optional vx eisa
dev/vx/if_vx_pci.c optional vx pci
dev/xe/if_xe.c optional xe
+fs/devfs/devfs_vnops.c optional devfs
+fs/devfs/devfs_vfsops.c optional devfs
+fs/devfs/devfs_devs.c optional devfs
gnu/ext2fs/ext2_alloc.c optional ext2fs
gnu/ext2fs/ext2_balloc.c optional ext2fs
gnu/ext2fs/ext2_inode.c optional ext2fs
@@ -525,9 +528,6 @@ libkern/strtoq.c standard
libkern/strtoul.c standard
libkern/strtouq.c standard
miscfs/deadfs/dead_vnops.c standard
-miscfs/devfs/devfs_tree.c optional devfs
-miscfs/devfs/devfs_vfsops.c optional devfs
-miscfs/devfs/devfs_vnops.c optional devfs
miscfs/fdesc/fdesc_vfsops.c optional fdesc
miscfs/fdesc/fdesc_vnops.c optional fdesc
miscfs/fifofs/fifo_vnops.c standard
diff --git a/sys/dev/bktr/bktr_os.c b/sys/dev/bktr/bktr_os.c
index 060e996..45ff376 100644
--- a/sys/dev/bktr/bktr_os.c
+++ b/sys/dev/bktr/bktr_os.c
@@ -80,12 +80,6 @@
#include <vm/pmap.h>
#include <vm/vm_extern.h>
-#if (__FreeBSD_version < 400000)
-#ifdef DEVFS
-#include <sys/devfsext.h>
-#endif /* DEVFS */
-#endif
-
#if (__FreeBSD_version >=400000) || (NSMBUS > 0)
#include <sys/bus.h> /* used by smbus and newbus */
#endif
@@ -972,14 +966,6 @@ bktr_attach( pcici_t tag, int unit )
/* call the common attach code */
common_bktr_attach( bktr, unit, fun, rev );
-
-#ifdef DEVFS
- /* XXX This just throw away the token, which should probably be fixed when
- DEVFS is finally made really operational. */
- devfs_add_devswf(&bktr_cdevsw, unit, DV_CHR, 0, 0, 0444, "bktr%d", unit);
- devfs_add_devswf(&bktr_cdevsw, unit+16, DV_CHR, 0, 0, 0444, "tuner%d", unit);
- devfs_add_devswf(&bktr_cdevsw, unit+32, DV_CHR, 0, 0, 0444, "vbi%d", unit);
-#endif /* DEVFS */
}
diff --git a/sys/dev/fdc/fdc.c b/sys/dev/fdc/fdc.c
index d901250..dd513e9 100644
--- a/sys/dev/fdc/fdc.c
+++ b/sys/dev/fdc/fdc.c
@@ -52,6 +52,7 @@
*/
#include "opt_fdc.h"
+#include "opt_devfs.h"
#include "card.h"
#include <sys/param.h>
@@ -83,6 +84,12 @@
#include <isa/fdc.h>
#include <isa/rtc.h>
+#ifdef DEVFS
+#include <sys/ctype.h>
+#include <sys/eventhandler.h>
+#include <fs/devfs/devfs.h>
+#endif
+
/* misuse a flag to identify format operation */
/* configuration flags */
@@ -945,6 +952,67 @@ DRIVER_MODULE(fdc, pccard, fdc_pccard_driver, fdc_devclass, 0, 0);
#endif /* NCARD > 0 */
+#ifdef DEVFS
+static void fd_clone __P((void *arg, char *name, int namelen, dev_t *dev));
+
+static struct {
+ char *match;
+ int minor;
+ int link;
+} fd_suffix[] = {
+ { "a", 0, 1 },
+ { "b", 0, 1 },
+ { "c", 0, 1 },
+ { "d", 0, 1 },
+ { "e", 0, 1 },
+ { "f", 0, 1 },
+ { "g", 0, 1 },
+ { "h", 0, 1 },
+ { ".1720", 1, 0 },
+ { ".1480", 2, 0 },
+ { ".1440", 3, 0 },
+ { ".1200", 4, 0 },
+ { ".820", 5, 0 },
+ { ".800", 6, 0 },
+ { ".720", 7, 0 },
+ { ".360", 8, 0 },
+ { ".640", 9, 0 },
+ { ".1232", 10, 0 },
+ { 0, 0 }
+};
+static void
+fd_clone(arg, name, namelen, dev)
+ void *arg;
+ char *name;
+ int namelen;
+ dev_t *dev;
+{
+ int u, d, i;
+ char *n;
+ dev_t pdev;
+
+ if (*dev != NODEV)
+ return;
+ if (devfs_stdclone(name, &n, "fd", &u) != 2)
+ return;
+ for (i = 0; ; i++) {
+ if (fd_suffix[i].match == NULL)
+ return;
+ if (strcmp(n, fd_suffix[i].match))
+ continue;
+ d = fd_suffix[i].minor;
+ break;
+ }
+ if (fd_suffix[i].link == 0) {
+ *dev = make_dev(&fd_cdevsw, (u << 6) + d,
+ UID_ROOT, GID_OPERATOR, 0640, name);
+ } else {
+ pdev = makedev(fd_cdevsw.d_maj, (u << 6) + d);
+ *dev = make_dev_alias(pdev, name);
+ }
+}
+#endif
+
/******************************************************************/
/*
* devices attached to the controller section.
@@ -1095,26 +1163,22 @@ static int
fd_attach(device_t dev)
{
struct fd_data *fd;
-#if 0
- int i;
- int mynor;
- int typemynor;
- int typesize;
-#endif
- static int cdevsw_add_done = 0;
fd = device_get_softc(dev);
+#ifndef DEVFS
+ {
+ static int cdevsw_add_done = 0;
if (!cdevsw_add_done) {
cdevsw_add(&fd_cdevsw); /* XXX */
cdevsw_add_done++;
}
- make_dev(&fd_cdevsw, (fd->fdu << 6),
- UID_ROOT, GID_OPERATOR, 0640, "rfd%d", fd->fdu);
-
-#if 0
- /* Other make_dev() go here. */
+ }
+#else
+ EVENTHANDLER_REGISTER(devfs_clone, fd_clone, 0, 1000);
#endif
+ make_dev(&fd_cdevsw, (fd->fdu << 6),
+ UID_ROOT, GID_OPERATOR, 0640, "fd%d", fd->fdu);
/*
* Export the drive to the devstat interface.
diff --git a/sys/dev/md/md.c b/sys/dev/md/md.c
index 725b407..59cd8d7 100644
--- a/sys/dev/md/md.c
+++ b/sys/dev/md/md.c
@@ -11,7 +11,8 @@
*/
#include "opt_mfs.h" /* We have adopted some tasks from MFS */
-#include "opt_md.h" /* We have adopted some tasks from MFS */
+#include "opt_md.h"
+#include "opt_devfs.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -23,6 +24,12 @@
#include <sys/malloc.h>
#include <sys/sysctl.h>
#include <sys/linker.h>
+#include <sys/queue.h>
+
+#ifdef DEVFS
+#include <sys/eventhandler.h>
+#include <fs/devfs/devfs.h>
+#endif
#ifndef MD_NSECT
#define MD_NSECT (10000 * 2)
@@ -52,7 +59,7 @@ static u_char end_mfs_root[] __unused = "MFS Filesystem had better STOP here";
static int mdrootready;
-static void mdcreate_malloc(void);
+static void mdcreate_malloc(int unit);
#define CDEV_MAJOR 95
#define BDEV_MAJOR 22
@@ -82,8 +89,11 @@ static struct cdevsw md_cdevsw = {
static struct cdevsw mddisk_cdevsw;
+static LIST_HEAD(, md_s) md_softc_list = LIST_HEAD_INITIALIZER(&md_softc_list);
+
struct md_s {
int unit;
+ LIST_ENTRY(md_s) list;
struct devstat stats;
struct bio_queue_head bio_queue;
struct disk disk;
@@ -114,8 +124,10 @@ mdopen(dev_t dev, int flag, int fmt, struct proc *p)
devtoname(dev), flag, fmt, p);
sc = dev->si_drv1;
+#ifndef DEVFS
if (sc->unit + 1 == mdunits)
- mdcreate_malloc();
+ mdcreate_malloc(-1);
+#endif
dl = &sc->disk.d_label;
bzero(dl, sizeof(*dl));
@@ -341,13 +353,21 @@ mdstrategy_preload(struct bio *bp)
}
static struct md_s *
-mdcreate(void)
+mdcreate(int unit)
{
struct md_s *sc;
+ if (unit == -1)
+ unit = mdunits++;
+ /* Make sure this unit isn't already in action */
+ LIST_FOREACH(sc, &md_softc_list, list) {
+ if (sc->unit == unit)
+ return (NULL);
+ }
MALLOC(sc, struct md_s *,sizeof(*sc), M_MD, M_WAITOK);
bzero(sc, sizeof(*sc));
- sc->unit = mdunits++;
+ LIST_INSERT_HEAD(&md_softc_list, sc, list);
+ sc->unit = unit;
bioq_init(&sc->bio_queue);
devstat_add_entry(&sc->stats, "md", sc->unit, DEV_BSIZE,
DEVSTAT_NO_ORDERED_TAGS,
@@ -363,7 +383,7 @@ mdcreate_preload(u_char *image, unsigned length)
{
struct md_s *sc;
- sc = mdcreate();
+ sc = mdcreate(-1);
sc->type = MD_PRELOAD;
sc->nsect = length / DEV_BSIZE;
sc->pl_ptr = image;
@@ -374,11 +394,14 @@ mdcreate_preload(u_char *image, unsigned length)
}
static void
-mdcreate_malloc(void)
+mdcreate_malloc(int unit)
{
struct md_s *sc;
- sc = mdcreate();
+ sc = mdcreate(unit);
+ if (sc == NULL)
+ return;
+
sc->type = MD_MALLOC;
sc->nsect = MD_NSECT; /* for now */
@@ -388,6 +411,28 @@ mdcreate_malloc(void)
printf("md%d: Malloc disk\n", sc->unit);
}
+#ifdef DEVFS
+static void
+md_clone (void *arg, char *name, int namelen, dev_t *dev)
+{
+ int i, u;
+
+ if (*dev != NODEV)
+ return;
+ i = devfs_stdclone(name, NULL, "md", &u);
+ if (i == 0)
+ return;
+ /* XXX: should check that next char is [\0sa-h] */
+ /*
+ * Now we cheat: We just create the disk, but don't match.
+ * Since we run before it, subr_disk.c::disk_clone() will
+ * find our disk and match the sought for device.
+ */
+ mdcreate_malloc(u);
+ return;
+}
+#endif
+
static void
md_drvinit(void *unused)
{
@@ -418,7 +463,11 @@ md_drvinit(void *unused)
mdunits, name, len, ptr);
mdcreate_preload(ptr, len);
}
- mdcreate_malloc();
+#ifdef DEVFS
+ EVENTHANDLER_REGISTER(devfs_clone, md_clone, 0, 999);
+#else
+ mdcreate_malloc(-1);
+#endif
}
SYSINIT(mddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR, md_drvinit,NULL)
@@ -433,3 +482,4 @@ md_takeroot(void *junk)
SYSINIT(md_root, SI_SUB_MOUNT_ROOT, SI_ORDER_FIRST, md_takeroot, NULL);
#endif
+
diff --git a/sys/fs/devfs/devfs.h b/sys/fs/devfs/devfs.h
new file mode 100644
index 0000000..00a34b1
--- /dev/null
+++ b/sys/fs/devfs/devfs.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2000
+ * Poul-Henning Kamp. All rights reserved.
+ *
+ * This code is derived from software donated to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * 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.
+ * 2. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ *
+ * @(#)kernfs.h 8.6 (Berkeley) 3/29/95
+ * From: FreeBSD: src/sys/miscfs/kernfs/kernfs.h 1.14
+ *
+ * $FreeBSD$
+ */
+
+#ifdef _KERNEL
+
+#ifdef DEVFS_INTERN
+
+#define NDEVINO 1024
+
+MALLOC_DECLARE(M_DEVFS);
+
+struct devfs_dir {
+ TAILQ_HEAD(, devfs_dirent) dd_list;
+};
+
+struct devfs_dirent {
+ int de_inode;
+ struct dirent *de_dirent;
+ TAILQ_ENTRY(devfs_dirent) de_list;
+ struct devfs_dir *de_dir;
+ mode_t de_mode;
+ uid_t de_uid;
+ gid_t de_gid;
+ struct timespec de_atime;
+ struct timespec de_mtime;
+ struct timespec de_ctime;
+ struct vnode *de_vnode;
+ char * de_symlink;
+};
+
+struct devfs_node {
+ struct kern_target *kf_kt;
+};
+
+struct devfs_mount {
+ struct vnode *dm_root; /* Root node */
+ struct devfs_dir *dm_rootdir;
+ struct devfs_dir *dm_basedir;
+ unsigned dm_generation;
+ struct devfs_dirent *dm_dirent[NDEVINO];
+ int dm_inode;
+};
+
+
+extern dev_t devfs_inot[NDEVINO];
+extern int devfs_nino;
+extern unsigned devfs_generation;
+
+#define VFSTODEVFS(mp) ((struct devfs_mount *)((mp)->mnt_data))
+
+extern vop_t **devfs_vnodeop_p;
+extern vop_t **devfs_specop_p;
+int devfs_populate __P((struct devfs_mount *dm));
+struct devfs_dir * devfs_vmkdir __P((void));
+struct devfs_dirent * devfs_newdirent __P((char *name, int namelen));
+void devfs_purge __P((struct devfs_dir *dd));
+void devfs_delete __P((struct devfs_dir *dd, struct devfs_dirent *de));
+#endif /* DEVFS_INTERN */
+
+typedef void (*devfs_clone_fn) __P((void *arg, char *name, int namelen, dev_t *result));
+
+int devfs_stdclone __P((char *name, char **namep, char *stem, int *unit));
+EVENTHANDLER_DECLARE(devfs_clone, devfs_clone_fn);
+#endif /* _KERNEL */
diff --git a/sys/fs/devfs/devfs_devs.c b/sys/fs/devfs/devfs_devs.c
new file mode 100644
index 0000000..4bcfc03
--- /dev/null
+++ b/sys/fs/devfs/devfs_devs.c
@@ -0,0 +1,230 @@
+#define DEBUG 1
+/*
+ * Copyright (c) 2000
+ * Poul-Henning Kamp. 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.
+ * 2. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ *
+ * From: FreeBSD: src/sys/miscfs/kernfs/kernfs_vfsops.c 1.36
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/dirent.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/malloc.h>
+#include <sys/eventhandler.h>
+#include <sys/ctype.h>
+
+#define DEVFS_INTERN
+#include <fs/devfs/devfs.h>
+
+struct devfs_dirent *
+devfs_newdirent(char *name, int namelen)
+{
+ int i;
+ struct devfs_dirent *de;
+ struct dirent d;
+
+ d.d_namlen = namelen;
+ i = sizeof (*de) + GENERIC_DIRSIZ(&d);
+ MALLOC(de, struct devfs_dirent *, i, M_DEVFS, M_WAITOK);
+ bzero(de, i);
+ de->de_dirent = (struct dirent *)(de + 1);
+ de->de_dirent->d_namlen = namelen;
+ de->de_dirent->d_reclen = GENERIC_DIRSIZ(&d);
+ bcopy(name, de->de_dirent->d_name, namelen + 1);
+ nanotime(&de->de_ctime);
+ return (de);
+}
+
+struct devfs_dir *
+devfs_vmkdir(void)
+{
+ struct devfs_dir *dd;
+ struct devfs_dirent *de;
+
+ MALLOC(dd, struct devfs_dir *, sizeof(*dd), M_DEVFS, M_WAITOK);
+ bzero(dd, sizeof(*dd));
+ TAILQ_INIT(&dd->dd_list);
+
+ de = devfs_newdirent(".", 1);
+ de->de_dirent->d_type = DT_DIR;
+ TAILQ_INSERT_TAIL(&dd->dd_list, de, de_list);
+ de = TAILQ_FIRST(&dd->dd_list);
+ de->de_mode = 0755;
+ return (dd);
+}
+
+void
+devfs_delete(struct devfs_dir *dd, struct devfs_dirent *de)
+{
+
+ if (de->de_symlink) {
+ FREE(de->de_symlink, M_DEVFS);
+ de->de_symlink = NULL;
+ }
+ if (de->de_vnode) {
+ de->de_vnode->v_data = NULL;
+ vdrop(de->de_vnode);
+ }
+ TAILQ_REMOVE(&dd->dd_list, de, de_list);
+ FREE(de, M_DEVFS);
+}
+
+void
+devfs_purge(struct devfs_dir *dd)
+{
+ struct devfs_dirent *de;
+
+ for (;;) {
+ de = TAILQ_FIRST(&dd->dd_list);
+ if (de == NULL)
+ break;
+ devfs_delete(dd, de);
+ }
+ FREE(dd, M_DEVFS);
+}
+
+
+int
+devfs_populate(struct devfs_mount *dm)
+{
+ int i, j;
+ dev_t dev, pdev;
+ struct devfs_dir *dd;
+ struct devfs_dirent *de;
+ char *q, *s;
+
+ while (dm->dm_generation != devfs_generation) {
+ dm->dm_generation = devfs_generation;
+ for (i = 0; i < NDEVINO; i++) {
+ dev = devfs_inot[i];
+ de = dm->dm_dirent[i];
+ if (dev == NULL && de != NULL) {
+#if 0
+ printf("Del ino%d %s\n", i, de->de_dirent->d_name);
+#endif
+ dd = de->de_dir;
+ dm->dm_dirent[i] = NULL;
+ TAILQ_REMOVE(&dd->dd_list, de, de_list);
+ if (de->de_vnode) {
+ de->de_vnode->v_data = NULL;
+ vdrop(de->de_vnode);
+ }
+ FREE(de, M_DEVFS);
+ continue;
+ }
+ if (dev == NULL)
+ continue;
+ if (de != NULL)
+ continue;
+ dd = dm->dm_basedir;
+ s = dev->si_name;
+ for (q = s; *q != '/' && *q != '\0'; q++)
+ continue;
+ if (*q == '/') {
+ continue;
+ }
+ de = devfs_newdirent(s, q - s);
+ if (dev->si_flags & SI_ALIAS) {
+ de->de_inode = dm->dm_inode++;
+ de->de_uid = 0;
+ de->de_gid = 0;
+ de->de_mode = 0642;
+ de->de_dirent->d_type = DT_LNK;
+ pdev = dev->si_drv1;
+ j = strlen(pdev->si_name) + 1;
+ MALLOC(de->de_symlink, char *, j, M_DEVFS, M_WAITOK);
+ bcopy(pdev->si_name, de->de_symlink, j);
+ } else {
+ de->de_inode = i;
+ de->de_uid = dev->si_uid;
+ de->de_gid = dev->si_gid;
+ de->de_mode = dev->si_mode;
+ de->de_dirent->d_type = DT_CHR;
+ dm->dm_dirent[i] = de;
+ }
+ TAILQ_INSERT_TAIL(&dd->dd_list, de, de_list);
+#if 0
+ printf("Add ino%d %s\n", i, dev->si_name);
+#endif
+ }
+ }
+ return (0);
+}
+
+dev_t devfs_inot[NDEVINO];
+int devfs_nino = 3;
+unsigned devfs_generation;
+
+static void
+devfs_create(dev_t dev)
+{
+ if (dev->si_inode == 0 && devfs_nino < NDEVINO)
+ dev->si_inode = devfs_nino++;
+ if (dev->si_inode == 0) {
+ printf("NDEVINO too small\n");
+ return;
+ }
+ devfs_inot[dev->si_inode] = dev;
+ devfs_generation++;
+}
+
+static void
+devfs_remove(dev_t dev)
+{
+ devfs_inot[dev->si_inode] = NULL;
+ devfs_generation++;
+}
+
+devfs_create_t *devfs_create_hook = devfs_create;
+devfs_remove_t *devfs_remove_hook = devfs_remove;
+
+int
+devfs_stdclone(char *name, char **namep, char *stem, int *unit)
+{
+ int u, i;
+
+ if (bcmp(stem, name, strlen(stem)) != 0)
+ return (0);
+ i = strlen(stem);
+ if (!isdigit(name[i]))
+ return (0);
+ u = 0;
+ while (isdigit(name[i])) {
+ u *= 10;
+ u += name[i++] - '0';
+ }
+ *unit = u;
+ if (namep)
+ *namep = &name[i];
+ if (name[i])
+ return (2);
+ return (1);
+}
diff --git a/sys/fs/devfs/devfs_vfsops.c b/sys/fs/devfs/devfs_vfsops.c
new file mode 100644
index 0000000..2cd7611
--- /dev/null
+++ b/sys/fs/devfs/devfs_vfsops.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 1992, 1993, 1995
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2000
+ * Poul-Henning Kamp. All rights reserved.
+ *
+ * This code is derived from software donated to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * 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.
+ * 2. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ *
+ * @(#)kernfs_vfsops.c 8.10 (Berkeley) 5/14/95
+ * From: FreeBSD: src/sys/miscfs/kernfs/kernfs_vfsops.c 1.36
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/dirent.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/malloc.h>
+#include <sys/eventhandler.h>
+
+#define DEVFS_INTERN
+#include <fs/devfs/devfs.h>
+
+MALLOC_DEFINE(M_DEVFS, "DEVFS", "DEVFS data");
+
+static int devfs_mount __P((struct mount *mp, char *path, caddr_t data,
+ struct nameidata *ndp, struct proc *p));
+static int devfs_unmount __P((struct mount *mp, int mntflags,
+ struct proc *p));
+static int devfs_root __P((struct mount *mp, struct vnode **vpp));
+static int devfs_statfs __P((struct mount *mp, struct statfs *sbp,
+ struct proc *p));
+
+/*
+ * Mount the filesystem
+ */
+static int
+devfs_mount(mp, path, data, ndp, p)
+ struct mount *mp;
+ char *path;
+ caddr_t data;
+ struct nameidata *ndp;
+ struct proc *p;
+{
+ int error = 0;
+ u_int size;
+ struct devfs_mount *fmp;
+ struct vnode *rvp;
+
+ /*
+ * Update is a no-op
+ */
+ if (mp->mnt_flag & MNT_UPDATE)
+ return (EOPNOTSUPP);
+
+ MALLOC(fmp, struct devfs_mount *, sizeof(struct devfs_mount), M_DEVFS, M_WAITOK);
+
+ bzero(fmp, sizeof(*fmp));
+
+ error = getnewvnode(VT_DEVFS, mp, devfs_vnodeop_p, &rvp);
+ if (error) {
+ FREE(fmp, M_DEVFS);
+ return (error);
+ }
+
+ vhold(rvp);
+ rvp->v_type = VDIR;
+ rvp->v_flag |= VROOT;
+ mp->mnt_flag |= MNT_LOCAL;
+ mp->mnt_data = (qaddr_t) fmp;
+ vfs_getnewfsid(mp);
+
+ fmp->dm_inode = NDEVINO;
+ fmp->dm_root = rvp;
+ fmp->dm_rootdir = devfs_vmkdir();
+ rvp->v_data = fmp->dm_rootdir;
+ TAILQ_FIRST(&fmp->dm_rootdir->dd_list)->de_vnode = rvp;
+ TAILQ_FIRST(&fmp->dm_rootdir->dd_list)->de_inode = 2;
+
+#ifdef DEVFS_DEVBASE
+ {
+ struct devfs_dirent *de;
+
+ fmp->dm_basedir = devfs_vmkdir();
+ de = devfs_newdirent("dev", 3);
+ de->de_inode = fmp->dm_inode++;
+ de->de_dir = fmp->dm_basedir;
+ TAILQ_FIRST(&de->de_dir->dd_list)->de_inode = de->de_inode;
+ de->de_uid = 0;
+ de->de_gid = 0;
+ de->de_mode = 0755;
+ de->de_dirent->d_type = DT_DIR;
+ TAILQ_INSERT_TAIL(&fmp->dm_rootdir->dd_list, de, de_list);
+ }
+#else
+ fmp->dm_basedir = fmp->dm_rootdir;
+#endif
+
+ if (path != NULL) {
+ (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
+ } else {
+ strcpy(mp->mnt_stat.f_mntonname, "/");
+ size = 1;
+ }
+ bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
+ bzero(mp->mnt_stat.f_mntfromname, MNAMELEN);
+ bcopy("devfs", mp->mnt_stat.f_mntfromname, sizeof("devfs"));
+ (void)devfs_statfs(mp, &mp->mnt_stat, p);
+ devfs_populate(fmp);
+
+ return (0);
+}
+
+static int
+devfs_unmount(mp, mntflags, p)
+ struct mount *mp;
+ int mntflags;
+ struct proc *p;
+{
+ int error;
+ int flags = 0;
+ struct vnode *rootvp = VFSTODEVFS(mp)->dm_root;
+ struct devfs_mount *fmp;
+
+ fmp = (struct devfs_mount*) mp->mnt_data;
+ if (mntflags & MNT_FORCE)
+ flags |= FORCECLOSE;
+
+ /*
+ * Clear out buffer cache. I don't think we
+ * ever get anything cached at this level at the
+ * moment, but who knows...
+ */
+ if (rootvp->v_usecount > 2)
+ return (EBUSY);
+ devfs_purge(fmp->dm_rootdir);
+ error = vflush(mp, rootvp, flags);
+ if (error)
+ return (error);
+
+ /*
+ * Release reference on underlying root vnode
+ */
+ vrele(rootvp);
+ /*
+ * And blow it away for future re-use
+ */
+ vgone(rootvp);
+ /*
+ * Finally, throw away the devfs_mount structure
+ */
+ free(mp->mnt_data, M_DEVFS);
+ mp->mnt_data = 0;
+ return 0;
+}
+
+static int
+devfs_root(mp, vpp)
+ struct mount *mp;
+ struct vnode **vpp;
+{
+ struct proc *p = curproc; /* XXX */
+ struct vnode *vp;
+
+ /*
+ * Return locked reference to root.
+ */
+ vp = VFSTODEVFS(mp)->dm_root;
+ VREF(vp);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
+ *vpp = vp;
+ return (0);
+}
+
+static int
+devfs_statfs(mp, sbp, p)
+ struct mount *mp;
+ struct statfs *sbp;
+ struct proc *p;
+{
+
+ sbp->f_flags = 0;
+ sbp->f_bsize = DEV_BSIZE;
+ sbp->f_iosize = DEV_BSIZE;
+ sbp->f_blocks = 2; /* 1K to keep df happy */
+ sbp->f_bfree = 0;
+ sbp->f_bavail = 0;
+ sbp->f_files = 0;
+ sbp->f_ffree = 0;
+ if (sbp != &mp->mnt_stat) {
+ sbp->f_type = mp->mnt_vfc->vfc_typenum;
+ bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
+ bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
+ bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
+ }
+ return (0);
+}
+
+static struct vfsops devfs_vfsops = {
+ devfs_mount,
+ vfs_stdstart,
+ devfs_unmount,
+ devfs_root,
+ vfs_stdquotactl,
+ devfs_statfs,
+ vfs_stdsync,
+ vfs_stdvget,
+ vfs_stdfhtovp,
+ vfs_stdcheckexp,
+ vfs_stdvptofh,
+ vfs_stdinit,
+ vfs_stduninit,
+ vfs_stdextattrctl,
+};
+
+VFS_SET(devfs_vfsops, devfs, VFCF_SYNTHETIC);
diff --git a/sys/fs/devfs/devfs_vnops.c b/sys/fs/devfs/devfs_vnops.c
new file mode 100644
index 0000000..fb14abf
--- /dev/null
+++ b/sys/fs/devfs/devfs_vnops.c
@@ -0,0 +1,569 @@
+#define DEBUG 1
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2000
+ * Poul-Henning Kamp. All rights reserved.
+ *
+ * This code is derived from software donated to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * 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.
+ * 2. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ *
+ * @(#)kernfs_vnops.c 8.15 (Berkeley) 5/21/95
+ * From: FreeBSD: src/sys/miscfs/kernfs/kernfs_vnops.c 1.43
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/vmmeter.h>
+#include <sys/time.h>
+#include <sys/conf.h>
+#include <sys/vnode.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <sys/namei.h>
+#include <sys/dirent.h>
+#include <sys/resource.h>
+#include <sys/eventhandler.h>
+
+#define DEVFS_INTERN
+#include <fs/devfs/devfs.h>
+
+#define KSTRING 256 /* Largest I/O available via this filesystem */
+#define UIO_MX 32
+
+static int devfs_access __P((struct vop_access_args *ap));
+static int devfs_badop __P((void));
+static int devfs_getattr __P((struct vop_getattr_args *ap));
+static int devfs_lookup __P((struct vop_lookup_args *ap));
+static int devfs_print __P((struct vop_print_args *ap));
+static int devfs_readdir __P((struct vop_readdir_args *ap));
+static int devfs_readlink __P((struct vop_readlink_args *ap));
+static int devfs_reclaim __P((struct vop_reclaim_args *ap));
+static int devfs_remove __P((struct vop_remove_args *ap));
+static int devfs_revoke __P((struct vop_revoke_args *ap));
+static int devfs_setattr __P((struct vop_setattr_args *ap));
+static int devfs_symlink __P((struct vop_symlink_args *ap));
+
+
+static int
+devfs_allocv(struct devfs_dirent *de, struct mount *mp, struct vnode **vpp, struct proc *p)
+{
+ int error;
+ struct vnode *vp;
+
+loop:
+ vp = de->de_vnode;
+ if (vp != NULL) {
+ if (vget(vp, 0, p ? p : curproc))
+ goto loop;
+ *vpp = vp;
+ return (0);
+ }
+ error = getnewvnode(VT_DEVFS, mp, devfs_vnodeop_p, &vp);
+ if (error != 0) {
+ printf("devfs_allocv: failed to allocate new vnode\n");
+ return (error);
+ }
+
+ if (de->de_dirent->d_type == DT_CHR) {
+ vp->v_type = VCHR;
+ vp = addaliasu(vp, devfs_inot[de->de_inode]->si_udev);
+ vp->v_op = devfs_specop_p;
+ vp->v_data = de;
+ } else if (de->de_dirent->d_type == DT_DIR) {
+ vp->v_type = VDIR;
+ vp->v_data = de->de_dir;
+ TAILQ_FIRST(&de->de_dir->dd_list)->de_vnode = vp;
+ } else if (de->de_dirent->d_type == DT_LNK) {
+ vp->v_type = VLNK;
+ vp->v_data = de;
+ } else {
+ vp->v_type = VBAD;
+ vp->v_data = de;
+ }
+ de->de_vnode = vp;
+ vhold(vp);
+ *vpp = vp;
+ return (0);
+}
+/*
+ * vp is the current namei directory
+ * ndp is the name to locate in that directory...
+ */
+static int
+devfs_lookup(ap)
+ struct vop_lookup_args /* {
+ struct vnode * a_dvp;
+ struct vnode ** a_vpp;
+ struct componentname * a_cnp;
+ } */ *ap;
+{
+ struct componentname *cnp = ap->a_cnp;
+ struct vnode **vpp = ap->a_vpp;
+ struct vnode *dvp = ap->a_dvp;
+ char *pname = cnp->cn_nameptr;
+ struct proc *p = cnp->cn_proc;
+ struct devfs_dir *dd;
+ struct devfs_dirent *de;
+ struct devfs_mount *fmp;
+ dev_t cdev;
+ int error, cloned;
+
+ *vpp = NULLVP;
+
+ VOP_UNLOCK(dvp, 0, p);
+ if (cnp->cn_namelen == 1 && *pname == '.') {
+ *vpp = dvp;
+ VREF(dvp);
+ vn_lock(dvp, LK_SHARED | LK_RETRY, p);
+ return (0);
+ }
+
+ cloned = 0;
+
+ fmp = (struct devfs_mount *)dvp->v_mount->mnt_data;
+again:
+
+ devfs_populate(fmp);
+ dd = dvp->v_data;
+ TAILQ_FOREACH(de, &dd->dd_list, de_list) {
+ if (cnp->cn_namelen != de->de_dirent->d_namlen)
+ continue;
+ if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name, de->de_dirent->d_namlen) != 0)
+ continue;
+ goto found;
+ }
+
+ if (!cloned) {
+ /* OK, we didn't have that one, so lets try to create it on the fly... */
+ cdev = NODEV;
+ EVENTHANDLER_INVOKE(devfs_clone, cnp->cn_nameptr, cnp->cn_namelen, &cdev);
+#if 0
+ printf("cloned %s -> %p %s\n", cnp->cn_nameptr, cdev,
+ cdev == NODEV ? "NODEV" : cdev->si_name);
+#endif
+ if (cdev != NODEV) {
+ cloned = 1;
+ goto again;
+ }
+ }
+
+ /* No luck, too bad. */
+
+ if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
+ (cnp->cn_flags & ISLASTCN)) {
+ cnp->cn_flags |= SAVENAME;
+ if (!(cnp->cn_flags & LOCKPARENT))
+ VOP_UNLOCK(dvp, 0, p);
+ return (EJUSTRETURN);
+ } else {
+ vn_lock(dvp, LK_SHARED | LK_RETRY, p);
+ return (ENOENT);
+ }
+
+
+found:
+
+ error = devfs_allocv(de, dvp->v_mount, vpp, p);
+ if (error != 0) {
+ vn_lock(dvp, LK_SHARED | LK_RETRY, p);
+ return (error);
+ }
+ if ((cnp->cn_nameiop == DELETE) && (cnp->cn_flags & ISLASTCN)) {
+ if (*vpp == dvp) {
+ VREF(dvp);
+ *vpp = dvp;
+ return (0);
+ }
+ VREF(*vpp);
+ if (!(cnp->cn_flags & LOCKPARENT))
+ VOP_UNLOCK(dvp, 0, p);
+ return (0);
+ }
+ vn_lock(*vpp, LK_SHARED | LK_RETRY, p);
+ if (!(cnp->cn_flags & LOCKPARENT))
+ VOP_UNLOCK(dvp, 0, p);
+ return (0);
+}
+
+static int
+devfs_access(ap)
+ struct vop_access_args /* {
+ struct vnode *a_vp;
+ int a_mode;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+ mode_t amode = ap->a_mode;
+ struct devfs_dirent *de = vp->v_data;
+ mode_t fmode = de->de_mode;
+
+ /* Some files are simply not modifiable. */
+ if ((amode & VWRITE) && (fmode & (S_IWUSR|S_IWGRP|S_IWOTH)) == 0)
+ return (EPERM);
+
+ return (vaccess(vp->v_type, de->de_mode, de->de_uid, de->de_gid,
+ ap->a_mode, ap->a_cred));
+}
+
+static int
+devfs_getattr(ap)
+ struct vop_getattr_args /* {
+ struct vnode *a_vp;
+ struct vattr *a_vap;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+ struct vattr *vap = ap->a_vap;
+ int error = 0;
+ struct devfs_dirent *de;
+ struct devfs_dir *dd;
+
+ if (vp->v_type == VDIR) {
+ dd = vp->v_data;
+ de = TAILQ_FIRST(&dd->dd_list);
+ } else {
+ de = vp->v_data;
+ }
+ bzero((caddr_t) vap, sizeof(*vap));
+ vattr_null(vap);
+ vap->va_uid = de->de_uid;
+ vap->va_gid = de->de_gid;
+ vap->va_mode = de->de_mode;
+ vap->va_size = 0;
+ vap->va_blocksize = DEV_BSIZE;
+ vap->va_atime = de->de_atime;
+ vap->va_mtime = de->de_mtime;
+ vap->va_ctime = de->de_ctime;
+ vap->va_gen = 0;
+ vap->va_flags = 0;
+ vap->va_rdev = 0;
+ vap->va_bytes = 0;
+ vap->va_nlink = 1;
+ vap->va_fileid = de->de_inode;
+
+#if 0
+ if (vp->v_flag & VROOT) {
+#ifdef DEBUG
+ printf("devfs_getattr: stat rootdir\n");
+#endif
+ vap->va_type = VDIR;
+ vap->va_nlink = 2;
+ vap->va_fileid = 2;
+ vap->va_size = DEV_BSIZE;
+ } else
+#endif
+
+ if (de->de_dirent->d_type == DT_DIR) {
+ vap->va_type = VDIR;
+ } else if (de->de_dirent->d_type == DT_LNK) {
+ vap->va_type = VLNK;
+ } else if (de->de_dirent->d_type == DT_CHR) {
+ vap->va_type = VCHR;
+ vap->va_rdev = devfs_inot[de->de_inode]->si_udev;
+ }
+
+#ifdef DEBUG
+ if (error)
+ printf("devfs_getattr: return error %d\n", error);
+#endif
+ return (error);
+}
+
+static int
+devfs_setattr(ap)
+ struct vop_setattr_args /* {
+ struct vnode *a_vp;
+ struct vattr *a_vap;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ } */ *ap;
+{
+ struct devfs_dir *dd;
+ struct devfs_dirent *de;
+
+ if (ap->a_vp->v_type == VDIR) {
+ dd = ap->a_vp->v_data;
+ de = TAILQ_FIRST(&dd->dd_list);
+ } else {
+ de = ap->a_vp->v_data;
+ }
+
+ if (ap->a_vap->va_flags != VNOVAL)
+ return (EOPNOTSUPP);
+ if (ap->a_vap->va_uid != (uid_t)VNOVAL)
+ de->de_uid = ap->a_vap->va_uid;
+ if (ap->a_vap->va_gid != (gid_t)VNOVAL)
+ de->de_gid = ap->a_vap->va_gid;
+ if (ap->a_vap->va_mode != (mode_t)VNOVAL)
+ de->de_mode = ap->a_vap->va_mode;
+ if (ap->a_vap->va_atime.tv_sec != VNOVAL)
+ de->de_atime = ap->a_vap->va_atime;
+ if (ap->a_vap->va_mtime.tv_sec != VNOVAL)
+ de->de_mtime = ap->a_vap->va_mtime;
+
+ /*
+ * Silently ignore attribute changes.
+ * This allows for open with truncate to have no
+ * effect until some data is written. I want to
+ * do it this way because all writes are atomic.
+ */
+ return (0);
+}
+
+static int
+devfs_readdir(ap)
+ struct vop_readdir_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ struct ucred *a_cred;
+ int *a_eofflag;
+ int *a_ncookies;
+ u_long **a_cookies;
+ } */ *ap;
+{
+ int error, i;
+ struct uio *uio = ap->a_uio;
+ struct dirent *dp;
+ struct devfs_dir *dd;
+ struct devfs_dirent *de;
+ off_t off;
+
+ if (ap->a_vp->v_type != VDIR)
+ return (ENOTDIR);
+
+ i = (u_int)off / UIO_MX;
+ error = 0;
+ dd = ap->a_vp->v_data;
+ de = TAILQ_FIRST(&dd->dd_list);
+ off = 0;
+ while (uio->uio_resid >= UIO_MX && de != NULL) {
+ dp = de->de_dirent;
+ dp->d_fileno = de->de_inode;
+ if (off >= uio->uio_offset)
+ if ((error = uiomove((caddr_t)dp, dp->d_reclen, uio)) != 0)
+ break;
+ off += dp->d_reclen;
+ de = TAILQ_NEXT(de, de_list);
+ }
+
+ uio->uio_offset = off;
+
+ return (error);
+}
+
+static int
+devfs_readlink(ap)
+ struct vop_readlink_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ struct ucred *a_cead;
+ } */ *ap;
+{
+ int error;
+ struct devfs_dirent *de;
+
+ de = ap->a_vp->v_data;
+ error = uiomove(de->de_symlink, strlen(de->de_symlink) + 1, ap->a_uio);
+ return (error);
+}
+
+static int
+devfs_reclaim(ap)
+ struct vop_reclaim_args /* {
+ struct vnode *a_vp;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+
+ vp->v_data = NULL;
+ return (0);
+}
+
+static int
+devfs_remove(ap)
+ struct vop_remove_args /* {
+ struct vnode *a_dvp;
+ struct vnode *a_vp;
+ struct componentname *a_cnp;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+ struct devfs_dir *dd;
+ struct devfs_dirent *de;
+
+ dd = ap->a_dvp->v_data;
+ de = vp->v_data;
+ devfs_delete(dd, de);
+ return (0);
+}
+
+/*
+ * Revoke is called on a tty when a terminal session ends. The vnode
+ * is orphaned by setting v_op to deadfs so we need to let go of it
+ * as well so that we create a new one next time around.
+ */
+static int
+devfs_revoke(ap)
+ struct vop_revoke_args /* {
+ struct vnode *a_vp;
+ int a_flags;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+ struct devfs_dirent *de;
+
+ de = vp->v_data;
+ vdrop(de->de_vnode);
+ de->de_vnode = NULL;
+ vop_revoke(ap);
+ return (0);
+}
+
+static int
+devfs_symlink(ap)
+ struct vop_symlink_args /* {
+ struct vnode *a_dvp;
+ struct vnode **a_vpp;
+ struct componentname *a_cnp;
+ struct vattr *a_vap;
+ char *a_target;
+ } */ *ap;
+{
+ int i;
+ struct devfs_dir *dd;
+ struct devfs_dirent *de;
+ struct devfs_mount *fmp;
+
+ fmp = (struct devfs_mount *)ap->a_dvp->v_mount->mnt_data;
+ dd = ap->a_dvp->v_data;
+ de = devfs_newdirent(ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen);
+ de->de_uid = 0;
+ de->de_gid = 0;
+ de->de_mode = 0642;
+ de->de_inode = fmp->dm_inode++;
+ de->de_dirent->d_type = DT_LNK;
+ i = strlen(ap->a_target) + 1;
+ MALLOC(de->de_symlink, char *, i, M_DEVFS, M_WAITOK);
+ bcopy(ap->a_target, de->de_symlink, i);
+ TAILQ_INSERT_TAIL(&dd->dd_list, de, de_list);
+ devfs_allocv(de, ap->a_dvp->v_mount, ap->a_vpp, 0);
+ VREF(*(ap->a_vpp));
+ return (0);
+}
+
+/*
+ * Print out the contents of a devfs vnode.
+ */
+/* ARGSUSED */
+static int
+devfs_print(ap)
+ struct vop_print_args /* {
+ struct vnode *a_vp;
+ } */ *ap;
+{
+
+ printf("tag VT_DEVFS, devfs vnode\n");
+ return (0);
+}
+
+/*
+ * Kernfs "should never get here" operation
+ */
+static int
+devfs_badop()
+{
+ return (EIO);
+}
+
+vop_t **devfs_vnodeop_p;
+static struct vnodeopv_entry_desc devfs_vnodeop_entries[] = {
+ { &vop_default_desc, (vop_t *) vop_defaultop },
+ { &vop_access_desc, (vop_t *) devfs_access },
+ { &vop_bmap_desc, (vop_t *) devfs_badop },
+ { &vop_getattr_desc, (vop_t *) devfs_getattr },
+ { &vop_lookup_desc, (vop_t *) devfs_lookup },
+ { &vop_pathconf_desc, (vop_t *) vop_stdpathconf },
+ { &vop_print_desc, (vop_t *) devfs_print },
+ { &vop_readdir_desc, (vop_t *) devfs_readdir },
+ { &vop_readlink_desc, (vop_t *) devfs_readlink },
+ { &vop_reclaim_desc, (vop_t *) devfs_reclaim },
+ { &vop_remove_desc, (vop_t *) devfs_remove },
+ { &vop_revoke_desc, (vop_t *) devfs_revoke },
+ { &vop_setattr_desc, (vop_t *) devfs_setattr },
+ { &vop_symlink_desc, (vop_t *) devfs_symlink },
+ { NULL, NULL }
+};
+static struct vnodeopv_desc devfs_vnodeop_opv_desc =
+ { &devfs_vnodeop_p, devfs_vnodeop_entries };
+
+VNODEOP_SET(devfs_vnodeop_opv_desc);
+
+#if 0
+int
+foo(ap)
+ struct vop_generic_args *ap;
+{
+ int i;
+
+ i = spec_vnoperate(ap);
+ printf("foo(%s) = %d\n", ap->a_desc->vdesc_name, i);
+ return (i);
+}
+#endif
+
+vop_t **devfs_specop_p;
+static struct vnodeopv_entry_desc devfs_specop_entries[] = {
+#if 1
+ { &vop_default_desc, (vop_t *) spec_vnoperate },
+#else
+ { &vop_default_desc, (vop_t *) foo },
+ { &vop_lock_desc, (vop_t *) spec_vnoperate },
+ { &vop_unlock_desc, (vop_t *) spec_vnoperate },
+ { &vop_lease_desc, (vop_t *) spec_vnoperate },
+ { &vop_strategy_desc, (vop_t *) spec_vnoperate },
+ { &vop_bmap_desc, (vop_t *) spec_vnoperate },
+#endif
+ { &vop_access_desc, (vop_t *) devfs_access },
+ { &vop_getattr_desc, (vop_t *) devfs_getattr },
+ { &vop_print_desc, (vop_t *) devfs_print },
+ { &vop_reclaim_desc, (vop_t *) devfs_reclaim },
+ { &vop_remove_desc, (vop_t *) devfs_remove },
+ { &vop_revoke_desc, (vop_t *) devfs_revoke },
+ { &vop_setattr_desc, (vop_t *) devfs_setattr },
+ { NULL, NULL }
+};
+static struct vnodeopv_desc devfs_specop_opv_desc =
+ { &devfs_specop_p, devfs_specop_entries };
+
+VNODEOP_SET(devfs_specop_opv_desc);
diff --git a/sys/i386/conf/GENERIC b/sys/i386/conf/GENERIC
index 500cccb..54f13e0 100644
--- a/sys/i386/conf/GENERIC
+++ b/sys/i386/conf/GENERIC
@@ -36,6 +36,7 @@ options FFS #Berkeley Fast Filesystem
options FFS_ROOT #FFS usable as root device [keep this!]
options SOFTUPDATES #Enable FFS soft updates support
options MFS #Memory Filesystem
+#options DEVFS #Device Filesystem
options MD_ROOT #MD is a potential root device
options NFS #Network Filesystem
options NFS_ROOT #NFS usable as root device, NFS required
diff --git a/sys/i4b/driver/i4b_ctl.c b/sys/i4b/driver/i4b_ctl.c
index a8d50cc..c88b35e 100644
--- a/sys/i4b/driver/i4b_ctl.c
+++ b/sys/i4b/driver/i4b_ctl.c
@@ -67,9 +67,6 @@
#include "opt_devfs.h"
#endif
-#ifdef DEVFS
-#include <sys/devfsext.h>
-#endif
#endif /* __FreeBSD__ */
@@ -138,9 +135,6 @@ PSEUDO_SET(i4bctlattach, i4b_i4bctldrv);
#endif /* __FreeBSD__ */
#if defined(__FreeBSD__) && __FreeBSD__ == 3
-#ifdef DEVFS
-static void *devfs_token;
-#endif
#endif
#ifndef __FreeBSD__
@@ -219,11 +213,6 @@ i4bctlattach()
#if defined(__FreeBSD__)
#if __FreeBSD__ == 3
-#ifdef DEVFS
- devfs_token = devfs_add_devswf(&i4bctl_cdevsw, 0, DV_CHR,
- UID_ROOT, GID_WHEEL, 0600,
- "i4bctl");
-#endif
#else
make_dev(&i4bctl_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "i4bctl");
diff --git a/sys/i4b/driver/i4b_rbch.c b/sys/i4b/driver/i4b_rbch.c
index 855f413..0ab29d9 100644
--- a/sys/i4b/driver/i4b_rbch.c
+++ b/sys/i4b/driver/i4b_rbch.c
@@ -62,9 +62,6 @@ extern cc_t ttydefchars;
#include "opt_devfs.h"
#endif
-#ifdef DEVFS
-#include <sys/devfsext.h>
-#endif
#endif /* __FreeBSD__ */
@@ -137,9 +134,6 @@ static struct rbch_softc {
struct selinfo selp; /* select / poll */
#if defined(__FreeBSD__) && __FreeBSD__ == 3
-#ifdef DEVFS
- void *devfs_token; /* device filesystem */
-#endif
#endif
#if I4BRBCHACCT
@@ -298,12 +292,6 @@ i4brbchattach()
#if defined(__FreeBSD__)
#if __FreeBSD__ == 3
-#ifdef DEVFS
- rbch_softc[i].devfs_token =
- devfs_add_devswf(&i4brbch_cdevsw, i, DV_CHR,
- UID_ROOT, GID_WHEEL, 0600,
- "i4brbch%d", i);
-#endif
#else
make_dev(&i4brbch_cdevsw, i,
diff --git a/sys/i4b/driver/i4b_tel.c b/sys/i4b/driver/i4b_tel.c
index 4cd1667..a9b2591 100644
--- a/sys/i4b/driver/i4b_tel.c
+++ b/sys/i4b/driver/i4b_tel.c
@@ -67,9 +67,6 @@
#include "opt_devfs.h"
#endif
-#ifdef DEVFS
-#include <sys/devfsext.h>
-#endif
#endif /* __FreeBSD__ */
@@ -138,9 +135,6 @@ typedef struct {
struct selinfo selp; /* select / poll */
#if defined(__FreeBSD__) && __FreeBSD__ == 3
-#ifdef DEVFS
- void *devfs_token; /* token for DEVFS */
-#endif
#endif
} tel_sc_t;
@@ -318,13 +312,6 @@ i4btelattach()
#if defined(__FreeBSD__)
#if __FreeBSD__ == 3
-#ifdef DEVFS
-
-/* XXX */ tel_sc[i][j].devfs_token
- = devfs_add_devswf(&i4btel_cdevsw, i, DV_CHR,
- UID_ROOT, GID_WHEEL, 0600,
- "i4btel%d", i);
-#endif
#else
switch(j)
diff --git a/sys/i4b/driver/i4b_trace.c b/sys/i4b/driver/i4b_trace.c
index 6324dbe..c3c1688 100644
--- a/sys/i4b/driver/i4b_trace.c
+++ b/sys/i4b/driver/i4b_trace.c
@@ -72,9 +72,6 @@
#ifdef __FreeBSD__
-#ifdef DEVFS
-#include <sys/devfsext.h>
-#endif
#include <machine/i4b_trace.h>
#include <machine/i4b_ioctl.h>
@@ -101,9 +98,6 @@ static int device_state[NI4BTRC];
#define ST_WAITDATA 0x02
#if defined(__FreeBSD__) && __FreeBSD__ == 3
-#ifdef DEVFS
-static void *devfs_token[NI4BTRC];
-#endif
#endif
static int analyzemode = 0;
@@ -244,12 +238,6 @@ i4btrcattach()
#if defined(__FreeBSD__)
#if __FreeBSD__ < 4
-#ifdef DEVFS
- devfs_token[i]
- = devfs_add_devswf(&i4btrc_cdevsw, i, DV_CHR,
- UID_ROOT, GID_WHEEL, 0600,
- "i4btrc%d", i);
-#endif
#else
make_dev(&i4btrc_cdevsw, i,
diff --git a/sys/i4b/layer4/i4b_i4bdrv.c b/sys/i4b/layer4/i4b_i4bdrv.c
index 1a07b95..8bc866f 100644
--- a/sys/i4b/layer4/i4b_i4bdrv.c
+++ b/sys/i4b/layer4/i4b_i4bdrv.c
@@ -77,9 +77,6 @@
#include "opt_devfs.h"
#endif
-#ifdef DEVFS
-#include <sys/devfsext.h>
-#endif
#endif /* __FreeBSD__*/
@@ -111,9 +108,6 @@ static int selflag = 0;
static int readflag = 0;
#if defined(__FreeBSD__) && __FreeBSD__ == 3
-#ifdef DEVFS
-static void *devfs_token;
-#endif
#endif
#ifndef __FreeBSD__
@@ -255,11 +249,6 @@ i4battach()
#if defined(__FreeBSD__)
#if __FreeBSD__ == 3
-#ifdef DEVFS
- devfs_token = devfs_add_devswf(&i4b_cdevsw, 0, DV_CHR,
- UID_ROOT, GID_WHEEL, 0600,
- "i4b");
-#endif
#else
make_dev(&i4b_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "i4b");
diff --git a/sys/isa/fd.c b/sys/isa/fd.c
index d901250..dd513e9 100644
--- a/sys/isa/fd.c
+++ b/sys/isa/fd.c
@@ -52,6 +52,7 @@
*/
#include "opt_fdc.h"
+#include "opt_devfs.h"
#include "card.h"
#include <sys/param.h>
@@ -83,6 +84,12 @@
#include <isa/fdc.h>
#include <isa/rtc.h>
+#ifdef DEVFS
+#include <sys/ctype.h>
+#include <sys/eventhandler.h>
+#include <fs/devfs/devfs.h>
+#endif
+
/* misuse a flag to identify format operation */
/* configuration flags */
@@ -945,6 +952,67 @@ DRIVER_MODULE(fdc, pccard, fdc_pccard_driver, fdc_devclass, 0, 0);
#endif /* NCARD > 0 */
+#ifdef DEVFS
+static void fd_clone __P((void *arg, char *name, int namelen, dev_t *dev));
+
+static struct {
+ char *match;
+ int minor;
+ int link;
+} fd_suffix[] = {
+ { "a", 0, 1 },
+ { "b", 0, 1 },
+ { "c", 0, 1 },
+ { "d", 0, 1 },
+ { "e", 0, 1 },
+ { "f", 0, 1 },
+ { "g", 0, 1 },
+ { "h", 0, 1 },
+ { ".1720", 1, 0 },
+ { ".1480", 2, 0 },
+ { ".1440", 3, 0 },
+ { ".1200", 4, 0 },
+ { ".820", 5, 0 },
+ { ".800", 6, 0 },
+ { ".720", 7, 0 },
+ { ".360", 8, 0 },
+ { ".640", 9, 0 },
+ { ".1232", 10, 0 },
+ { 0, 0 }
+};
+static void
+fd_clone(arg, name, namelen, dev)
+ void *arg;
+ char *name;
+ int namelen;
+ dev_t *dev;
+{
+ int u, d, i;
+ char *n;
+ dev_t pdev;
+
+ if (*dev != NODEV)
+ return;
+ if (devfs_stdclone(name, &n, "fd", &u) != 2)
+ return;
+ for (i = 0; ; i++) {
+ if (fd_suffix[i].match == NULL)
+ return;
+ if (strcmp(n, fd_suffix[i].match))
+ continue;
+ d = fd_suffix[i].minor;
+ break;
+ }
+ if (fd_suffix[i].link == 0) {
+ *dev = make_dev(&fd_cdevsw, (u << 6) + d,
+ UID_ROOT, GID_OPERATOR, 0640, name);
+ } else {
+ pdev = makedev(fd_cdevsw.d_maj, (u << 6) + d);
+ *dev = make_dev_alias(pdev, name);
+ }
+}
+#endif
+
/******************************************************************/
/*
* devices attached to the controller section.
@@ -1095,26 +1163,22 @@ static int
fd_attach(device_t dev)
{
struct fd_data *fd;
-#if 0
- int i;
- int mynor;
- int typemynor;
- int typesize;
-#endif
- static int cdevsw_add_done = 0;
fd = device_get_softc(dev);
+#ifndef DEVFS
+ {
+ static int cdevsw_add_done = 0;
if (!cdevsw_add_done) {
cdevsw_add(&fd_cdevsw); /* XXX */
cdevsw_add_done++;
}
- make_dev(&fd_cdevsw, (fd->fdu << 6),
- UID_ROOT, GID_OPERATOR, 0640, "rfd%d", fd->fdu);
-
-#if 0
- /* Other make_dev() go here. */
+ }
+#else
+ EVENTHANDLER_REGISTER(devfs_clone, fd_clone, 0, 1000);
#endif
+ make_dev(&fd_cdevsw, (fd->fdu << 6),
+ UID_ROOT, GID_OPERATOR, 0640, "fd%d", fd->fdu);
/*
* Export the drive to the devstat interface.
diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c
index 4ce9646..0229c56 100644
--- a/sys/kern/init_main.c
+++ b/sys/kern/init_main.c
@@ -43,6 +43,7 @@
*/
#include "opt_init_path.h"
+#include "opt_devfs.h"
#include <sys/param.h>
#include <sys/file.h>
@@ -498,6 +499,10 @@ start_init(void *dummy)
(void)subyte(--ucp, 'C');
options = 1;
#endif
+#ifdef DEVFS
+ (void)subyte(--ucp, 'd');
+ options = 1;
+#endif
if (options == 0)
(void)subyte(--ucp, '-');
(void)subyte(--ucp, '-'); /* leading hyphen */
diff --git a/sys/kern/kern_conf.c b/sys/kern/kern_conf.c
index d6116f7..1e344e3 100644
--- a/sys/kern/kern_conf.c
+++ b/sys/kern/kern_conf.c
@@ -195,13 +195,33 @@ makebdev(int x, int y)
return (makedev(bmaj2cmaj[x], y));
}
+static dev_t
+allocdev(void)
+{
+ static int stashed;
+ struct specinfo *si;
+
+ if (stashed >= DEVT_STASH) {
+ MALLOC(si, struct specinfo *, sizeof(*si), M_DEVT,
+ M_USE_RESERVE);
+ bzero(si, sizeof(*si));
+ } else if (LIST_FIRST(&dev_free)) {
+ si = LIST_FIRST(&dev_free);
+ LIST_REMOVE(si, si_hash);
+ } else {
+ si = devt_stash + stashed++;
+ si->si_flags |= SI_STASHED;
+ }
+ LIST_INIT(&si->si_names);
+ return (si);
+}
+
dev_t
makedev(int x, int y)
{
struct specinfo *si;
udev_t udev;
int hash;
- static int stashed;
if (x == umajor(NOUDEV) && y == uminor(NOUDEV))
Debugger("makedev of NOUDEV");
@@ -211,17 +231,7 @@ makedev(int x, int y)
if (si->si_udev == udev)
return (si);
}
- if (stashed >= DEVT_STASH) {
- MALLOC(si, struct specinfo *, sizeof(*si), M_DEVT,
- M_USE_RESERVE);
- bzero(si, sizeof(*si));
- } else if (LIST_FIRST(&dev_free)) {
- si = LIST_FIRST(&dev_free);
- LIST_REMOVE(si, si_hash);
- } else {
- si = devt_stash + stashed++;
- si->si_flags |= SI_STASHED;
- }
+ si = allocdev();
si->si_udev = udev;
LIST_INSERT_HEAD(&dev_hash[hash], si, si_hash);
return (si);
@@ -230,7 +240,7 @@ makedev(int x, int y)
void
freedev(dev_t dev)
{
- int hash;
+ dev_t adev;
if (!free_devt)
return;
@@ -238,7 +248,11 @@ freedev(dev_t dev)
return;
if (dev->si_devsw || dev->si_drv1 || dev->si_drv2)
return;
- hash = dev->si_udev % DEVT_HASH;
+ while (!LIST_EMPTY(&dev->si_names)) {
+ adev = LIST_FIRST(&dev->si_names);
+ adev->si_drv1 = NULL;
+ freedev(adev);
+ }
LIST_REMOVE(dev, si_hash);
if (dev->si_flags & SI_STASHED) {
bzero(dev, sizeof(*dev));
@@ -304,9 +318,34 @@ make_dev(struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms, char
dev->si_name[i] = '\0';
va_end(ap);
dev->si_devsw = devsw;
+ dev->si_uid = uid;
+ dev->si_gid = gid;
+ dev->si_mode = perms;
+
+ if (devfs_create_hook)
+ devfs_create_hook(dev);
+ return (dev);
+}
+
+dev_t
+make_dev_alias(dev_t pdev, char *fmt, ...)
+{
+ dev_t dev;
+ va_list ap;
+ int i;
+
+ dev = allocdev();
+ dev->si_flags |= SI_ALIAS;
+ dev->si_drv1 = pdev;
+ LIST_INSERT_HEAD(&pdev->si_names, dev, si_hash);
+
+ va_start(ap, fmt);
+ i = kvprintf(fmt, NULL, dev->si_name, 32, ap);
+ dev->si_name[i] = '\0';
+ va_end(ap);
if (devfs_create_hook)
- devfs_create_hook(dev, uid, gid, perms);
+ devfs_create_hook(dev);
return (dev);
}
diff --git a/sys/kern/subr_disk.c b/sys/kern/subr_disk.c
index 8bb0c6d..77fc4ee 100644
--- a/sys/kern/subr_disk.c
+++ b/sys/kern/subr_disk.c
@@ -10,6 +10,8 @@
*
*/
+#include "opt_devfs.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
@@ -21,6 +23,12 @@
#include <sys/sysctl.h>
#include <machine/md_var.h>
+#ifdef DEVFS
+#include <sys/eventhandler.h>
+#include <fs/devfs/devfs.h>
+#include <sys/ctype.h>
+#endif
+
MALLOC_DEFINE(M_DISK, "disk", "disk data");
static d_strategy_t diskstrategy;
@@ -30,7 +38,65 @@ static d_ioctl_t diskioctl;
static d_psize_t diskpsize;
static LIST_HEAD(, disk) disklist = LIST_HEAD_INITIALIZER(&disklist);
-
+
+#ifdef DEVFS
+static void
+disk_clone(void *arg, char *name, int namelen, dev_t *dev)
+{
+ struct disk *dp;
+ char const *d;
+ int i, u, s, p;
+ dev_t pdev;
+
+ if (*dev != NODEV)
+ return;
+
+ LIST_FOREACH(dp, &disklist, d_list) {
+ d = dp->d_devsw->d_name;
+ i = strlen(d);
+ if (bcmp(d, name, i) != 0)
+ continue;
+ u = 0;
+ if (!isdigit(name[i]))
+ continue;
+ while (isdigit(name[i])) {
+ u *= 10;
+ u += name[i++] - '0';
+ }
+ p = RAW_PART;
+ s = WHOLE_DISK_SLICE;
+ pdev = makedev(dp->d_devsw->d_maj, dkmakeminor(u, s, p));
+ if (pdev->si_disk == NULL)
+ continue;
+ if (name[i] != '\0') {
+ if (name[i] == 's') {
+ s = 0;
+ i++;
+ if (!isdigit(name[i]))
+ continue;
+ while (isdigit(name[i])) {
+ s *= 10;
+ s += name[i++] - '0';
+ }
+ s += BASE_SLICE - 1;
+ } else {
+ s = COMPATIBILITY_SLICE;
+ }
+ if (name[i] == '\0')
+ ;
+ else if (name[i] < 'a' || name[i] > 'h')
+ continue;
+ else
+ p = name[i] - 'a';
+ }
+
+ *dev = make_dev(pdev->si_devsw, dkmakeminor(u, s, p),
+ UID_ROOT, GID_OPERATOR, 0640, name);
+ return;
+ }
+}
+#endif
+
static void
inherit_raw(dev_t pdev, dev_t dev)
{
@@ -45,6 +111,7 @@ inherit_raw(dev_t pdev, dev_t dev)
dev_t
disk_create(int unit, struct disk *dp, int flags, struct cdevsw *cdevsw, struct cdevsw *proto)
{
+ static int once;
dev_t dev;
bzero(dp, sizeof(*dp));
@@ -63,13 +130,19 @@ disk_create(int unit, struct disk *dp, int flags, struct cdevsw *cdevsw, struct
if (bootverbose)
printf("Creating DISK %s%d\n", cdevsw->d_name, unit);
dev = make_dev(proto, dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART),
- 0, 0, 0, "%s%d", cdevsw->d_name, unit);
+ UID_ROOT, GID_OPERATOR, 0640, "%s%d", cdevsw->d_name, unit);
dev->si_disk = dp;
dp->d_dev = dev;
dp->d_dsflags = flags;
dp->d_devsw = cdevsw;
LIST_INSERT_HEAD(&disklist, dp, d_list);
+ if (!once) {
+#ifdef DEVFS
+ EVENTHANDLER_REGISTER(devfs_clone, disk_clone, 0, 1000);
+#endif
+ once++;
+ }
return (dev);
}
diff --git a/sys/kern/subr_diskslice.c b/sys/kern/subr_diskslice.c
index 68df0db..8d5d4ab 100644
--- a/sys/kern/subr_diskslice.c
+++ b/sys/kern/subr_diskslice.c
@@ -54,9 +54,6 @@
#include <sys/systm.h>
#include <sys/bio.h>
#include <sys/conf.h>
-#ifdef DEVFS
-#include <sys/devfsext.h>
-#endif
#include <sys/disklabel.h>
#include <sys/diskslice.h>
#include <sys/fcntl.h>
@@ -78,17 +75,11 @@ static void dsiodone __P((struct bio *bp));
static char *fixlabel __P((char *sname, struct diskslice *sp,
struct disklabel *lp, int writeflag));
static void free_ds_label __P((struct diskslices *ssp, int slice));
-#ifdef DEVFS
-static void free_ds_labeldevs __P((struct diskslices *ssp, int slice));
-#endif
static void partition_info __P((char *sname, int part, struct partition *pp));
static void slice_info __P((char *sname, struct diskslice *sp));
static void set_ds_label __P((struct diskslices *ssp, int slice,
struct disklabel *lp));
static void set_ds_labeldevs __P((dev_t dev, struct diskslices *ssp));
-#ifdef DEVFS
-static void set_ds_labeldevs_unaliased __P((dev_t dev, struct diskslices *ssp));
-#endif
static void set_ds_wlabel __P((struct diskslices *ssp, int slice,
int wlabel));
@@ -329,10 +320,6 @@ dsgone(sspp)
for (slice = 0, ssp = *sspp; slice < ssp->dss_nslices; slice++) {
sp = &ssp->dss_slices[slice];
-#ifdef DEVFS
- if (sp->ds_dev != NULL)
- devfs_remove_dev(sp->ds_dev);
-#endif
free_ds_label(ssp, slice);
}
free(ssp, M_DEVBUF);
@@ -634,9 +621,6 @@ dsopen(dev, mode, flags, sspp, lp)
struct disklabel *lp1;
char *msg;
u_char mask;
-#ifdef DEVFS
- int mynor;
-#endif
bool_t need_init;
int part;
char partname[2];
@@ -723,16 +707,6 @@ dsopen(dev, mode, flags, sspp, lp)
continue;
dev1 = dkmodslice(dkmodpart(dev, RAW_PART), slice);
sname = dsname(dev, unit, slice, RAW_PART, partname);
-#ifdef DEVFS
- if (slice != COMPATIBILITY_SLICE && sp->ds_dev == NULL
- && sp->ds_size != 0) {
- mynor = minor(dev1);
- sp->ds_dev =
- devfs_add_devswf(devsw(dev1), mynor, DV_CHR,
- UID_ROOT, GID_OPERATOR, 0640,
- "r%s", sname);
- }
-#endif
/*
* XXX this should probably only be done for the need_init
* case, but there may be a problem with DIOCSYNCSLICEINFO.
@@ -818,39 +792,10 @@ free_ds_label(ssp, slice)
lp = sp->ds_label;
if (lp == NULL)
return;
-#ifdef DEVFS
- free_ds_labeldevs(ssp, slice);
- if (slice == COMPATIBILITY_SLICE)
- free_ds_labeldevs(ssp, ssp->dss_first_bsd_slice);
- else if (slice == ssp->dss_first_bsd_slice)
- free_ds_labeldevs(ssp, COMPATIBILITY_SLICE);
-#endif
free(lp, M_DEVBUF);
set_ds_label(ssp, slice, (struct disklabel *)NULL);
}
-#ifdef DEVFS
-static void
-free_ds_labeldevs(ssp, slice)
- struct diskslices *ssp;
- int slice;
-{
- struct disklabel *lp;
- int part;
- struct diskslice *sp;
-
- sp = &ssp->dss_slices[slice];
- lp = sp->ds_label;
- if (lp == NULL)
- return;
- for (part = 0; part < lp->d_npartitions; part++) {
- if (sp->ds_devs[part] != NULL) {
- devfs_remove_dev(sp->ds_devs[part]);
- sp->ds_devs[part] = NULL;
- }
- }
-}
-#endif
static char *
fixlabel(sname, sp, lp, writeflag)
@@ -976,61 +921,8 @@ set_ds_labeldevs(dev, ssp)
dev_t dev;
struct diskslices *ssp;
{
-#ifdef DEVFS
- int slice;
-
- set_ds_labeldevs_unaliased(dev, ssp);
- if (ssp->dss_first_bsd_slice == COMPATIBILITY_SLICE)
- return;
- slice = dkslice(dev);
- if (slice == COMPATIBILITY_SLICE)
- set_ds_labeldevs_unaliased(
- dkmodslice(dev, ssp->dss_first_bsd_slice), ssp);
- else if (slice == ssp->dss_first_bsd_slice)
- set_ds_labeldevs_unaliased(
- dkmodslice(dev, COMPATIBILITY_SLICE), ssp);
-#endif /* DEVFS */
}
-#ifdef DEVFS
-static void
-set_ds_labeldevs_unaliased(dev, ssp)
- dev_t dev;
- struct diskslices *ssp;
-{
- struct disklabel *lp;
- int mynor;
- int part;
- char partname[2];
- struct partition *pp;
- int slice;
- char *sname;
- struct diskslice *sp;
-
- slice = dkslice(dev);
- sp = &ssp->dss_slices[slice];
- if (sp->ds_size == 0)
- return;
- lp = sp->ds_label;
- for (part = 0; part < lp->d_npartitions; part++) {
- pp = &lp->d_partitions[part];
- if (pp->p_size == 0)
- continue;
- sname = dsname(dev, dkunit(dev), slice, part, partname);
- if (part == RAW_PART && sp->ds_dev != NULL) {
- sp->ds_devs[part] =
- devfs_makelink(sp->ds_dev,
- "r%s%s", sname, partname);
- } else {
- mynor = minor(dkmodpart(dev, part));
- sp->ds_devs[part] =
- devfs_add_devswf(devsw(dev), mynor, DV_CHR,
- UID_ROOT, GID_OPERATOR, 0640,
- "r%s%s", sname, partname);
- }
- }
-}
-#endif /* DEVFS */
static void
set_ds_wlabel(ssp, slice, wlabel)
diff --git a/sys/kern/tty_pty.c b/sys/kern/tty_pty.c
index 6226e8c..d4402cd 100644
--- a/sys/kern/tty_pty.c
+++ b/sys/kern/tty_pty.c
@@ -39,6 +39,7 @@
* (Actually two drivers, requiring two entries in 'cdevsw')
*/
#include "opt_compat.h"
+#include "opt_devfs.h"
#include <sys/param.h>
#include <sys/systm.h>
#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
@@ -54,12 +55,17 @@
#include <sys/signalvar.h>
#include <sys/malloc.h>
+#ifdef DEVFS
+#include <sys/eventhandler.h>
+#include <fs/devfs/devfs.h>
+#endif
+
MALLOC_DEFINE(M_PTY, "ptys", "pty data structures");
static void ptsstart __P((struct tty *tp));
static void ptsstop __P((struct tty *tp, int rw));
static void ptcwakeup __P((struct tty *tp, int flag));
-static void ptyinit __P((int n));
+static dev_t ptyinit __P((int n));
static d_open_t ptsopen;
static d_close_t ptsclose;
@@ -135,7 +141,7 @@ struct pt_ioctl {
* XXX: define and add mapping of upper minor bits to allow more
* than 256 ptys.
*/
-static void
+static dev_t
ptyinit(n)
int n;
{
@@ -145,7 +151,7 @@ ptyinit(n)
/* For now we only map the lower 8 bits of the minor */
if (n & ~0xff)
- return;
+ return (NODEV);
pt = malloc(sizeof(*pt), M_PTY, M_WAITOK);
bzero(pt, sizeof(*pt));
@@ -157,6 +163,7 @@ ptyinit(n)
devs->si_drv1 = devc->si_drv1 = pt;
devs->si_tty = devc->si_tty = &pt->pt_tty;
ttyregister(&pt->pt_tty);
+ return (devc);
}
/*ARGSUSED*/
@@ -168,24 +175,25 @@ ptsopen(dev, flag, devtype, p)
{
register struct tty *tp;
int error;
- int minr;
- dev_t nextdev;
struct pt_ioctl *pti;
+#ifndef DEVFS
+ {
+ int minr = lminor(dev);
/*
- * XXX: Gross hack for DEVFS:
* If we openned this device, ensure we have the
* next one too, so people can open it.
*/
- minr = lminor(dev);
if (minr < 255) {
- nextdev = makedev(major(dev), minr + 1);
+ dev_t nextdev = makedev(major(dev), minr + 1);
if (!nextdev->si_drv1) {
ptyinit(minr + 1);
}
}
if (!dev->si_drv1)
ptyinit(minor(dev));
+ }
+#endif
if (!dev->si_drv1)
return(ENXIO);
pti = dev->si_drv1;
@@ -347,8 +355,10 @@ ptcopen(dev, flag, devtype, p)
register struct tty *tp;
struct pt_ioctl *pti;
+#ifndef DEVFS
if (!dev->si_drv1)
ptyinit(minor(dev));
+#endif
if (!dev->si_drv1)
return(ENXIO);
tp = dev->si_tty;
@@ -816,14 +826,59 @@ ptyioctl(dev, cmd, data, flag, p)
static void ptc_drvinit __P((void *unused));
+#ifdef DEVFS
+static void pty_clone __P((void *arg, char *name, int namelen, dev_t *dev));
+
+static void
+pty_clone(arg, name, namelen, dev)
+ void *arg;
+ char *name;
+ int namelen;
+ dev_t *dev;
+{
+ int u;
+
+ if (*dev != NODEV)
+ return;
+ if (bcmp(name, "pty", 3) != 0)
+ return;
+ if (name[5] != '\0')
+ return;
+ switch (name[3]) {
+ case 'p': u = 0; break;
+ case 'q': u = 32; break;
+ case 'r': u = 64; break;
+ case 's': u = 96; break;
+ case 'P': u = 128; break;
+ case 'Q': u = 160; break;
+ case 'R': u = 192; break;
+ case 'S': u = 224; break;
+ default: return;
+ }
+ if (name[4] >= '0' && name[4] <= '9')
+ u += name[4] - '0';
+ else if (name[4] >= 'a' && name[4] <= 'v')
+ u += name[4] - 'a' + 10;
+ else
+ return;
+ *dev = ptyinit(u);
+ return;
+}
+
+
+#endif
+
static void
ptc_drvinit(unused)
void *unused;
{
+#ifdef DEVFS
+ EVENTHANDLER_REGISTER(devfs_clone, pty_clone, 0, 1000);
+#else
cdevsw_add(&pts_cdevsw);
cdevsw_add(&ptc_cdevsw);
- /* XXX: Gross hack for DEVFS */
ptyinit(0);
+#endif
}
SYSINIT(ptcdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR_C,ptc_drvinit,NULL)
diff --git a/sys/miscfs/devfs/README b/sys/miscfs/devfs/README
deleted file mode 100644
index fba4214..0000000
--- a/sys/miscfs/devfs/README
+++ /dev/null
@@ -1,118 +0,0 @@
-$FreeBSD$
-
-this file is: /sys/miscfs/devfs/README
-
-to enable: add
-options DEVFS
-
-to your config file..
-expect it to be highly useless for a while,
-as the only devices that register themselves are the floppy,
-the pcaudio stuff, speaker, null,mem,zero,io,kmem.
-
-it works like this:
-
-There is a tree of nodes that describe the layout of the DEVFS as seen by
-the drivers.. they add nodes to this tree. This is called the 'back' layer
-for reasons that will become obvious in a second. Think of it as a
-BLUEPRINT of the DEVFS tree. Each back node has associated with it
-a "devnode" struct, that holds information about the device
-(or directory) and a pointer to the vnode if one has been associated
-with that node. The back node itself can be considered to be
-a directory entry, and contains the default name of the device,
-and a link to the directory that holds it. It is sometimes refered
-to in the code as the dev_name. The devnode can be considered the inode.
-
-When you mount the devfs somewhere (you can mount it multiple times in
-multiple places), a front layer is created that contains a tree of 'front'
-nodes.
-
-Think of this as a Transparency, layed over the top of the blueprint.
-(or possibly a photocopy).
-
-The front and back nodes are identical in type, but the back nodes
-are reserved for kernel use only, and are protected from the user.
-The back plane has a mount structure and all that stuff, but it is in
-fact not really mounted. (and is thus not reachable via namei).
-Internal kernel routines can open devices in this plane
-even if the external devfs has not been mounted yet :)
-(e.g. to find the root device)
-
-To start with there is a 1:1 relationship between the front nodes
-and the backing nodes, however once the front plane has been created
-the nodes can be moved around within that plane (or deleted).
-Think of this as the ability to revise a transparency...
-the blueprint is untouched.
-
-There is a "devnode" struct associated with each front note also.
-Front nodes that refer to devices, use the same "devnode" struct that is used
-by their associated backing node, so that multiple front nodes that
-point to the same device will use the same "devnode" struct, and through
-that, the same vnode, ops, modification times, flags, owner and group.
-Front nodes representing directories and symlinks have their own
-"devnode" structs, and may therefore differ. (have different vnodes)
-i.e. if you have two devfs trees mounted, you can change the
-directories in one without changing the other.
-e.g. remove or rename nodes
-
-Multiple mountings are like multiple transparencies,
-each showing through to the original blueprint.
-
-Information that is to be shared between these mounts is stored
-in the 'backing' node for that object. Once you have erased 'front'
-object, there is no memory of where the backing object was, and
-except for the possibility of searching the entire backing tree
-for the node with the correct major/minor/type, I don't see that
-it is easily recovered.. Particularly as there will eventually be
-(I hope) devices that go direct from the backing node to the driver
-without going via the cdevsw table.. they may not even have
-major/minor numbers.
-
-I see 'mount -u' as a possible solution to recovering a broken dev tree.
-(though umount+mount would do the same)
-
-Because non device nodes (directories and symlinks) have their own
-"devnode" structs on each layer, these may have different
-flags, owners, and contents on each layer.
-e.g. if you have a chroot tree like erf.tfs.com has, you
-may want different permissions or owners on the chroot mount of the DEVFS
-than you want in the real one. You might also want to delete some sensitive
-devices from the chroot tree.
-
-Directories also have backing nodes but there is nothing to stop
-the user from removing a front node from the directory front node.
-(except permissions of course). This is because the front directory
-nodes keep their own records as to which front nodes are members
-of that directory and do not refer to their original backing node
-for this information.
-
-The front nodes may be moved to other directories (including
-directories) however this does not break the linkage between the
-backing nodes and the front nodes. The backing node never moves. If
-a driver decides to remove a device from the backing tree, the FS
-code follows the links to all the front nodes linked to that backing
-node, and deletes them, no matter where they've been moved to.
-(active vnodes are redirected to point to the deadfs).
-
-If a directory has been moved, and a new backing node is inserted
-into its own back node, the new front node will appear in that front
-directory, even though it's been moved, because the directory that
-gets the front node is found via the links and not by name.
-
-a mount -u might be considered to be a request to 'refresh' the
-plane that controls to the mount being updated.. that would have the
-effect of 're-propogating' through any backing nodes that find they
-have no front nodes in that plane.
-
-
-NOTES FOR RELEASE 1.2
-1/ this is very preliminary
-2/ the routines have greatly simplified since release 1.1
-(I guess the break did me good :)
-3/ many features are not present yet..
-e.g. symlinks, a comprehensive registration interface (only a crude one)
-ability to unlink and mv nodes.
-4/ I'm pretty sure my use of vnodes is bad and it may be 'losing'
-them, or alternatively, corrupting things.. I need a vnode specialist
-to look at this.
-
diff --git a/sys/miscfs/devfs/devfs_proto.h b/sys/miscfs/devfs/devfs_proto.h
deleted file mode 100644
index 846c48e..0000000
--- a/sys/miscfs/devfs/devfs_proto.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/* $FreeBSD$ */
-/* THIS FILE HAS BEEN PRODUCED AUTOMATICALLY */
-void devfs_sinit(void *junk);
-devnm_p dev_findname(dn_p dir,char *name);
-int dev_finddir(char *orig_path, dn_p dirnode, int create, dn_p *dn_pp);
-int dev_add_name(char *name, dn_p dirnode, devnm_p back, dn_p dnp,
- devnm_p *devnm_pp);
-int dev_add_node(int entrytype, union typeinfo *by, dn_p proto,
- dn_p *dn_pp,struct devfsmount *dvm);
-int dev_touch(devnm_p key) /* update the node for this dev */;
-void devfs_dn_free(dn_p dnp);
-int devfs_propogate(devnm_p parent,devnm_p child);
-int dev_dup_plane(struct devfsmount *devfs_mp_p);
-void devfs_free_plane(struct devfsmount *devfs_mp_p);
-int dev_dup_entry(dn_p parent, devnm_p back, devnm_p *dnm_pp,
- struct devfsmount *dvm);
-int dev_free_name(devnm_p devnmp);
-void dev_free_hier(devnm_p devnmp);
-int devfs_vntodn(struct vnode *vn_p, dn_p *dn_pp);
-int devfs_dntovn(dn_p dnp, struct vnode **vn_pp);
-int dev_add_entry(char *name, dn_p parent, int type, union typeinfo *by,
- dn_p proto, struct devfsmount *dvm, devnm_p *nm_pp);
-int devfs_mount(struct mount *mp, char *path, caddr_t data,
- struct nameidata *ndp, struct proc *p);
-void devfs_dropvnode(dn_p dnp);
-/* THIS FILE PRODUCED AUTOMATICALLY */
-/* DO NOT EDIT (see reproto.sh) */
diff --git a/sys/miscfs/devfs/devfs_tree.c b/sys/miscfs/devfs/devfs_tree.c
deleted file mode 100644
index d47917a..0000000
--- a/sys/miscfs/devfs/devfs_tree.c
+++ /dev/null
@@ -1,1297 +0,0 @@
-
-/*
- * Copyright 1997,1998 Julian Elischer. All rights reserved.
- * julian@freebsd.org
- *
- * 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.
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``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 HOLDER OR CONTRIBUTORS 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$
- */
-
-
-/* SPLIT_DEVS means each devfs uses a different vnode for the same device */
-/* Otherwise the same device always ends up at the same vnode even if */
-/* reached througgh a different devfs instance. The practical difference */
-/* is that with the same vnode, chmods and chowns show up on all instances of */
-/* a device. (etc) */
-
-#define SPLIT_DEVS 1 /* maybe make this an option */
-/*#define SPLIT_DEVS 1*/
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/kernel.h>
-#include <sys/conf.h>
-#include <sys/malloc.h>
-#include <sys/mount.h>
-#include <sys/proc.h>
-#include <sys/vnode.h>
-#include <sys/devfsext.h>
-
-#include <machine/stdarg.h>
-
-#include <miscfs/devfs/devfsdefs.h>
-
-
-static MALLOC_DEFINE(M_DEVFSNODE, "DEVFS node", "DEVFS node");
-static MALLOC_DEFINE(M_DEVFSNAME, "DEVFS name", "DEVFS name");
-
-static void devfs_add_to_tree(dev_t dev, uid_t uid, gid_t gid, int perms);
-devnm_p dev_root; /* root of the backing tree */
-static struct mount *devfs_hidden_mount;
-int devfs_up_and_going;
-
-/*
- * Set up the root directory node in the backing plane
- * This is happenning before the vfs system has been
- * set up yet, so be careful about what we reference..
- * Notice that the ops are by indirection.. as they haven't
- * been set up yet!
- * DEVFS has a hidden mountpoint that is used as the anchor point
- * for the internal 'blueprint' version of the dev filesystem tree.
- */
-/*proto*/
-void
-devfs_sinit(void *junk)
-{
- int retval; /* we will discard this */
-
- /*
- * call the right routine at the right time with the right args....
- */
- retval = dev_add_entry("root", NULL, DEV_DIR, NULL, NULL, NULL, &dev_root);
- devfs_create_hook = devfs_add_to_tree;
-#ifdef PARANOID
- if(retval) panic("devfs_sinit: dev_add_entry failed ");
-#endif
- devfs_hidden_mount = (struct mount *)malloc(sizeof(struct mount),
- M_MOUNT,M_NOWAIT);
-#ifdef PARANOID
- if(!devfs_hidden_mount) panic("devfs_sinit: malloc failed");
-#endif
- bzero(devfs_hidden_mount,sizeof(struct mount));
- devfs_mount(devfs_hidden_mount,"dummy",NULL,NULL,NULL);
- dev_root->dnp->dvm = (struct devfsmount *)devfs_hidden_mount->mnt_data;
- devfs_up_and_going = 1;
- printf("DEVFS: ready for devices\n");
- /* part 2 of this is done later */
-}
-SYSINIT(devfs, SI_SUB_DEVFS, SI_ORDER_FIRST, devfs_sinit, NULL)
-
-
-/***********************************************************************\
-*************************************************************************
-* Routines used to find our way to a point in the tree *
-*************************************************************************
-\***********************************************************************/
-
-
-/***************************************************************\
-* Search down the linked list off a dir to find "name" *
-* return the dn_p for that node.
-\***************************************************************/
-/*proto*/
-devnm_p
-dev_findname(dn_p dir,char *name)
-{
- devnm_p newfp;
- DBPRINT((" dev_findname(%s)\n",name));
- if(dir->type != DEV_DIR) return 0;/*XXX*/ /* printf?*/
-
- if(name[0] == '.')
- {
- if(name[1] == 0)
- {
- return dir->by.Dir.myname;
- }
- if((name[1] == '.') && (name[2] == 0))
- {
- /* for root, .. == . */
- return dir->by.Dir.parent->by.Dir.myname;
- }
- }
- newfp = dir->by.Dir.dirlist;
- while(newfp)
- {
- if(!(strcmp(name,newfp->name)))
- return newfp;
- newfp = newfp->next;
- }
- return NULL;
-}
-
-/***********************************************************************\
-* Given a starting node (0 for root) and a pathname, return the node *
-* for the end item on the path. It MUST BE A DIRECTORY. If the 'CREATE' *
-* option is true, then create any missing nodes in the path and create *
-* and return the final node as well. *
-* This is used to set up a directory, before making nodes in it.. *
-* *
-* Warning: This function is RECURSIVE. *
-* char *orig_path, find this dir (err if not dir) *
-* dn_p dirnode, starting point (0 = root) *
-* int create, create path if not found *
-* dn_p *dn_pp) where to return the node of the dir *
-\***********************************************************************/
-/*proto*/
-int
-dev_finddir(char *orig_path, dn_p dirnode, int create, dn_p *dn_pp)
-{
- devnm_p devnmp;
- dn_p dnp;
- char pathbuf[DEVMAXPATHSIZE];
- char *path;
- char *name;
- register char *cp;
- int retval;
-
-
- DBPRINT(("dev_finddir\n"));
- /***************************************\
- * If no parent directory is given *
- * then start at the root of the tree *
- \***************************************/
- if(!dirnode) dirnode = dev_root->dnp;
-
- /***************************************\
- * Sanity Checks *
- \***************************************/
- if(dirnode->type != DEV_DIR) return ENOTDIR;
- if(strlen(orig_path) > (DEVMAXPATHSIZE - 1)) return ENAMETOOLONG;
-
-
- path = pathbuf;
- strcpy(path,orig_path);
-
- /***************************************\
- * always absolute, skip leading / *
- * get rid of / or // or /// etc. *
- \***************************************/
- while(*path == '/') path++;
-
- /***************************************\
- * If nothing left, then parent was it.. *
- \***************************************/
- if ( *path == '\0' ) {
- *dn_pp = dirnode;
- return 0;
- }
-
- /***************************************\
- * find the next segment of the name *
- \***************************************/
- cp = name = path;
- while((*cp != '/') && (*cp != 0)) {
- cp++;
- }
-
- /***********************************************\
- * Check to see if it's the last component *
- \***********************************************/
- if(*cp) {
- path = cp + 1; /* path refers to the rest */
- *cp = 0; /* name is now a separate string */
- if(!(*path)) {
- path = (char *)0; /* was trailing slash */
- }
- } else {
- path = NULL; /* no more to do */
- }
-
- /***************************************\
- * Start scanning along the linked list *
- \***************************************/
- devnmp = dev_findname(dirnode,name);
- if(devnmp) { /* check it's a directory */
- dnp = devnmp->dnp;
- if(dnp->type != DEV_DIR) return ENOTDIR;
- } else {
- /***************************************\
- * The required element does not exist *
- * So we will add it if asked to. *
- \***************************************/
- if(!create) return ENOENT;
-
- if((retval = dev_add_entry(name, dirnode, DEV_DIR,
- NULL, NULL, NULL, &devnmp)) != 0) {
- return retval;
- }
- dnp = devnmp->dnp;
- devfs_propogate(dirnode->by.Dir.myname,devnmp);
- }
- if(path != NULL) { /* decide whether to recurse more or return */
- return (dev_finddir(path,dnp,create,dn_pp));
- } else {
- *dn_pp = dnp;
- return 0;
- }
-}
-
-
-/***********************************************************************\
-* Add a new NAME element to the devfs *
-* If we're creating a root node, then dirname is NULL *
-* Basically this creates a new namespace entry for the device node *
-* *
-* Creates a name node, and links it to the supplied node *
-\***********************************************************************/
-/*proto*/
-int
-dev_add_name(char *name, dn_p dirnode, devnm_p back, dn_p dnp,
- devnm_p *devnm_pp)
-{
- devnm_p devnmp;
-
- DBPRINT(("dev_add_name\n"));
- if(dirnode != NULL ) {
- if(dirnode->type != DEV_DIR) return(ENOTDIR);
-
- if( dev_findname(dirnode,name))
- return(EEXIST);
- }
- /*
- * make sure the name is legal
- * slightly misleading in the case of NULL
- */
- if( !name || (strlen(name) > (DEVMAXNAMESIZE - 1)))
- return (ENAMETOOLONG);
-
- /*
- * Allocate and fill out a new directory entry
- */
- if(!(devnmp = (devnm_p)malloc(sizeof(devnm_t),
- M_DEVFSNAME, M_NOWAIT))) {
- return ENOMEM;
- }
- bzero(devnmp,sizeof(devnm_t));
-
- /* inherrit our parent's mount info */ /*XXX*/
- /* a kludge but.... */
- if(dirnode && ( dnp->dvm == NULL)) {
- dnp->dvm = dirnode->dvm;
- if(!dnp->dvm) printf("parent had null dvm ");
- }
-
- /*
- * Link the two together
- * include the implicit link in the count of links to the devnode..
- * this stops it from being accidentally freed later.
- */
- devnmp->dnp = dnp;
- dnp->links++ ; /* implicit from our own name-node */
-
- /*
- * Make sure that we can find all the links that reference a node
- * so that we can get them all if we need to zap the node.
- */
- if(dnp->linklist) {
- devnmp->nextlink = dnp->linklist;
- devnmp->prevlinkp = devnmp->nextlink->prevlinkp;
- devnmp->nextlink->prevlinkp = &(devnmp->nextlink);
- *devnmp->prevlinkp = devnmp;
- dnp->linklist = devnmp;
- } else {
- devnmp->nextlink = devnmp;
- devnmp->prevlinkp = &(devnmp->nextlink);
- dnp->linklist = devnmp;
- }
-
- /*
- * If the node is a directory, then we need to handle the
- * creation of the .. link.
- * A NULL dirnode indicates a root node, so point to ourself.
- */
- if(dnp->type == DEV_DIR) {
- dnp->by.Dir.myname = devnmp;
- /*
- * If we are unlinking from an old dir, decrement its links
- * as we point our '..' elsewhere
- * Note: it's up to the calling code to remove the
- * us from the original directory's list
- */
- if(dnp->by.Dir.parent) {
- dnp->by.Dir.parent->links--;
- }
- if(dirnode) {
- dnp->by.Dir.parent = dirnode;
- } else {
- dnp->by.Dir.parent = dnp;
- }
- dnp->by.Dir.parent->links++; /* account for the new '..' */
- }
-
- /*
- * put the name into the directory entry.
- */
- strcpy(devnmp->name, name);
-
-
- /*
- * Check if we are not making a root node..
- * (i.e. have parent)
- */
- if(dirnode) {
- /*
- * Put it on the END of the linked list of directory entries
- */
- devnmp->parent = dirnode; /* null for root */
- devnmp->prevp = dirnode->by.Dir.dirlast;
- devnmp->next = *(devnmp->prevp); /* should be NULL */ /*right?*/
- *(devnmp->prevp) = devnmp;
- dirnode->by.Dir.dirlast = &(devnmp->next);
- dirnode->by.Dir.entrycount++;
- dirnode->len += strlen(name) + 8;/*ok, ok?*/
- }
-
- *devnm_pp = devnmp;
- return 0 ;
-}
-
-
-/***********************************************************************\
-* Add a new element to the devfs plane. *
-* *
-* Creates a new dev_node to go with it if the prototype should not be *
-* reused. (Is a DIR, or we select SPLIT_DEVS at compile time) *
-* 'by' gives us info to make our node if we don't have a prototype. *
-* If 'by is null and proto exists, then the 'by' field of *
-* the proto is used intead in the CREATE case. *
-* note the 'links' count is 0 (except if a dir) *
-* but it is only cleared on a transition *
-* so this is ok till we link it to something *
-* Even in SPLIT_DEVS mode, *
-* if the node already exists on the wanted plane, just return it *
-\***********************************************************************/
-/*proto*/
-int
-dev_add_node(int entrytype, union typeinfo *by, dn_p proto,
- dn_p *dn_pp,struct devfsmount *dvm)
-{
- dn_p dnp;
-
- DBPRINT(("dev_add_node\n"));
-#if defined SPLIT_DEVS
- /*
- * If we have a prototype, then check if there is already a sibling
- * on the mount plane we are looking at, if so, just return it.
- */
- if (proto) {
- dnp = proto->nextsibling;
- while( dnp != proto) {
- if (dnp->dvm == dvm) {
- *dn_pp = dnp;
- return (0);
- }
- dnp = dnp->nextsibling;
- }
- if (by == NULL)
- by = &(proto->by);
- }
-#else /* SPLIT_DEVS */
- if ( proto ) {
- switch (proto->type) {
- case DEV_BDEV:
- case DEV_CDEV:
- case DEV_DDEV:
- *dn_pp = proto;
- return 0;
- }
- }
-#endif /* SPLIT_DEVS */
- if(!(dnp = (dn_p)malloc(sizeof(devnode_t),
- M_DEVFSNODE, M_NOWAIT)))
- {
- return ENOMEM;
- }
-
- /*
- * If we have a proto, that means that we are duplicating some
- * other device, which can only happen if we are not at the back plane
- */
- if(proto) {
- bcopy(proto, dnp, sizeof(devnode_t));
- dnp->links = 0;
- dnp->linklist = NULL;
- dnp->vn = NULL;
- dnp->len = 0;
- /* add to END of siblings list */
- dnp->prevsiblingp = proto->prevsiblingp;
- *(dnp->prevsiblingp) = dnp;
- dnp->nextsibling = proto;
- proto->prevsiblingp = &(dnp->nextsibling);
- } else {
- /*
- * We have no prototype, so start off with a clean slate
- */
- bzero(dnp,sizeof(devnode_t));
- dnp->type = entrytype;
- getnanotime(&(dnp->ctime));
- dnp->mtime = dnp->ctime;
- dnp->atime = dnp->ctime;
- dnp->nextsibling = dnp;
- dnp->prevsiblingp = &(dnp->nextsibling);
- }
- dnp->dvm = dvm;
-
- /*
- * fill out the dev node according to type
- */
- switch(entrytype) {
- case DEV_DIR:
- /*
- * As it's a directory, make sure
- * it has a null entries list
- */
- dnp->by.Dir.dirlast = &(dnp->by.Dir.dirlist);
- dnp->by.Dir.dirlist = (devnm_p)0;
- dnp->by.Dir.entrycount = 0;
- /* until we know better, it has a null parent pointer*/
- dnp->by.Dir.parent = NULL;
- dnp->links++; /* for .*/
- dnp->by.Dir.myname = NULL;
- /*
- * make sure that the ops associated with it are the ops
- * that we use (by default) for directories
- */
- dnp->ops = &devfs_vnodeop_p;
- dnp->mode |= 0555; /* default perms */
- break;
- case DEV_SLNK:
- /*
- * As it's a symlink allocate and store the link info
- * Symlinks should only ever be created by the user,
- * so they are not on the back plane and should not be
- * propogated forward.. a bit like directories in that way..
- * A symlink only exists on one plane and has its own
- * node.. therefore we might be on any random plane.
- */
- dnp->by.Slnk.name = malloc(by->Slnk.namelen+1,
- M_DEVFSNODE, M_NOWAIT);
- if (!dnp->by.Slnk.name) {
- free(dnp,M_DEVFSNODE);
- return ENOMEM;
- }
- strncpy(dnp->by.Slnk.name,by->Slnk.name,by->Slnk.namelen);
- dnp->by.Slnk.namelen = by->Slnk.namelen;
- dnp->ops = &devfs_vnodeop_p;
- dnp->mode |= 0555; /* default perms */
- break;
- case DEV_BDEV:
- /*
- * Make sure it has DEVICE type ops
- * and device specific fields are correct
- */
- dnp->ops = &devfs_spec_vnodeop_p;
- dnp->by.dev.dev = by->dev.dev;
- break;
- case DEV_CDEV:
- /*
- * Make sure it has DEVICE type ops
- * and device specific fields are correct
- */
- dnp->ops = &devfs_spec_vnodeop_p;
- dnp->by.dev.dev = by->dev.dev;
- break;
- case DEV_DDEV:
- /*
- * store the address of (the address of) the ops
- * and the magic cookie to use with them
- */
- dnp->by.Ddev.arg = by->Ddev.arg;
- dnp->by.Ddev.ops = by->Ddev.ops;
- dnp->ops = by->Ddev.ops;
- break;
- default:
- return EINVAL;
- }
-
- *dn_pp = dnp;
- return 0 ;
-}
-
-
-/*proto*/
-int
-dev_touch(devnm_p key) /* update the node for this dev */
-{
- DBPRINT(("dev_touch\n"));
- getnanotime(&(key->dnp->mtime));
- return 0; /*XXX*/
-}
-
-/*proto*/
-void
-devfs_dn_free(dn_p dnp)
-{
- if(--dnp->links <= 0 ) /* can be -1 for initial free, on error */
- {
- /*probably need to do other cleanups XXX */
- if (dnp->nextsibling != dnp) {
- dn_p* prevp = dnp->prevsiblingp;
- *prevp = dnp->nextsibling;
- dnp->nextsibling->prevsiblingp = prevp;
-
- }
- if(dnp->type == DEV_SLNK) {
- free(dnp->by.Slnk.name,M_DEVFSNODE);
- }
- devfs_dropvnode(dnp);
- free (dnp, M_DEVFSNODE);
- }
-}
-
-/***********************************************************************\
-* Front Node Operations *
-* Add or delete a chain of front nodes *
-\***********************************************************************/
-
-/***********************************************************************\
-* Given a directory backing node, and a child backing node, add the *
-* appropriate front nodes to the front nodes of the directory to *
-* represent the child node to the user *
-* *
-* on failure, front nodes will either be correct or not exist for each *
-* front dir, however dirs completed will not be stripped of completed *
-* frontnodes on failure of a later frontnode *
-* *
-* This allows a new node to be propogated through all mounted planes *
-* *
-\***********************************************************************/
-/*proto*/
-int
-devfs_propogate(devnm_p parent,devnm_p child)
-{
- int error;
- devnm_p newnmp;
- dn_p dnp = child->dnp;
- dn_p pdnp = parent->dnp;
- dn_p adnp = parent->dnp;
- int type = child->dnp->type;
-
- DBPRINT((" devfs_propogate\n"));
- /***********************************************\
- * Find the other instances of the parent node *
- \***********************************************/
- for (adnp = pdnp->nextsibling;
- adnp != pdnp;
- adnp = adnp->nextsibling)
- {
- /*
- * Make the node, using the original as a prototype)
- * if the node already exists on that plane it won't be
- * re-made..
- */
- if ((error = dev_add_entry(child->name, adnp, type,
- NULL, dnp, adnp->dvm, &newnmp)) != 0) {
- printf("duplicating %s failed\n",child->name);
- }
- }
- return 0; /* for now always succeed */
-}
-
-/***********************************************************************
- * remove all instances of this devicename [for backing nodes..]
- * note.. if there is another link to the node (non dir nodes only)
- * then the devfs_node will still exist as the ref count will be non-0
- * removing a directory node will remove all sup-nodes on all planes (ZAP)
- *
- * Used by device drivers to remove nodes that are no longer relevant
- * The argument is the 'cookie' they were given when they created the node
- * this function is exported.. see sys/devfsext.h
- ***********************************************************************/
-void
-devfs_remove_dev(void *devnmp)
-{
- dn_p dnp = ((devnm_p)devnmp)->dnp;
- dn_p dnp2;
-
- DBPRINT(("devfs_remove_dev\n"));
- /* keep removing the next sibling till only we exist. */
- while((dnp2 = dnp->nextsibling) != dnp) {
-
- /*
- * Keep removing the next front node till no more exist
- */
- dnp->nextsibling = dnp2->nextsibling;
- dnp->nextsibling->prevsiblingp = &(dnp->nextsibling);
- dnp2->nextsibling = dnp2;
- dnp2->prevsiblingp = &(dnp2->nextsibling);
- while(dnp2->linklist)
- {
- dev_free_name(dnp2->linklist);
- }
- }
-
- /*
- * then free the main node
- * If we are not running in SPLIT_DEVS mode, then
- * THIS is what gets rid of the propogated nodes.
- */
- while(dnp->linklist)
- {
- dev_free_name(dnp->linklist);
- }
- return ;
-}
-
-
-/***************************************************************
- * duplicate the backing tree into a tree of nodes hung off the
- * mount point given as the argument. Do this by
- * calling dev_dup_entry which recurses all the way
- * up the tree..
- * If we are the first plane, just return the base root
- **************************************************************/
-/*proto*/
-int
-dev_dup_plane(struct devfsmount *devfs_mp_p)
-{
- devnm_p new;
- int error = 0;
-
- DBPRINT((" dev_dup_plane\n"));
- if(devfs_up_and_going) {
- if((error = dev_dup_entry(NULL, dev_root, &new, devfs_mp_p)) != 0) {
- return error;
- }
- } else { /* we are doing the dummy mount during initialisation.. */
- new = dev_root;
- }
- devfs_mp_p->plane_root = new;
-
- return error;
-}
-
-
-
-/***************************************************************\
-* Free a whole plane
-\***************************************************************/
-/*proto*/
-void
-devfs_free_plane(struct devfsmount *devfs_mp_p)
-{
- devnm_p devnmp;
-
- DBPRINT((" devfs_free_plane\n"));
- devnmp = devfs_mp_p->plane_root;
- if(devnmp) {
- dev_free_hier(devnmp);
- dev_free_name(devnmp);
- }
- devfs_mp_p->plane_root = NULL;
-}
-
-/***************************************************************\
-* Create and link in a new front element.. *
-* Parent can be 0 for a root node *
-* Not presently usable to make a symlink XXX *
-* (Ok, symlinks don't propogate)
-* recursively will create subnodes corresponding to equivalent *
-* child nodes in the base level *
-\***************************************************************/
-/*proto*/
-int
-dev_dup_entry(dn_p parent, devnm_p back, devnm_p *dnm_pp,
- struct devfsmount *dvm)
-{
- devnm_p newnmp;
- devnm_p newback;
- devnm_p newfront;
- int error;
- dn_p dnp = back->dnp;
- int type = dnp->type;
-
- DBPRINT((" dev_dup_entry\n"));
- /*
- * go get the node made (if we need to)
- * use the back one as a prototype
- */
- if ((error = dev_add_entry(back->name, parent, type,
- NULL, dnp,
- parent?parent->dvm:dvm, &newnmp)) != 0) {
- printf("duplicating %s failed\n",back->name);
- }
-
- /*
- * If we have just made the root, then insert the pointer to the
- * mount information
- */
- if(dvm) {
- newnmp->dnp->dvm = dvm;
- }
-
- /*
- * If it is a directory, then recurse down all the other
- * subnodes in it....
- * note that this time we don't pass on the mount info..
- */
- if (type == DEV_DIR)
- {
- for(newback = back->dnp->by.Dir.dirlist;
- newback; newback = newback->next)
- {
- if((error = dev_dup_entry(newnmp->dnp,
- newback, &newfront, NULL)) != 0)
- {
- break; /* back out with an error */
- }
- }
- }
- *dnm_pp = newnmp;
- return error;
-}
-
-/***************************************************************\
-* Free a name node *
-* remember that if there are other names pointing to the *
-* dev_node then it may not get freed yet *
-* can handle if there is no dnp *
-\***************************************************************/
-/*proto*/
-int
-dev_free_name(devnm_p devnmp)
-{
- dn_p parent = devnmp->parent;
- dn_p dnp = devnmp->dnp;
-
- DBPRINT((" dev_free_name\n"));
- if(dnp) {
- if(dnp->type == DEV_DIR)
- {
- if(dnp->by.Dir.dirlist)
- return (ENOTEMPTY);
- devfs_dn_free(dnp); /* account for '.' */
- devfs_dn_free(dnp->by.Dir.parent); /* '..' */
- }
- /*
- * unlink us from the list of links for this node
- * If we are the only link, it's easy!
- * if we are a DIR of course there should not be any
- * other links.
- */
- if(devnmp->nextlink == devnmp) {
- dnp->linklist = NULL;
- } else {
- if(dnp->linklist == devnmp) {
- dnp->linklist = devnmp->nextlink;
- }
- devnmp->nextlink->prevlinkp = devnmp->prevlinkp;
- *devnmp->prevlinkp = devnmp->nextlink;
- }
- devfs_dn_free(dnp);
- }
-
- /*
- * unlink ourselves from the directory on this plane
- */
- if(parent) /* if not fs root */
- {
- if( (*devnmp->prevp = devnmp->next) )/* yes, assign */
- {
- devnmp->next->prevp = devnmp->prevp;
- }
- else
- {
- parent->by.Dir.dirlast
- = devnmp->prevp;
- }
- parent->by.Dir.entrycount--;
- parent->len -= strlen(devnmp->name) + 8;
- }
-
- /***************************************************************\
- * If the front node has its own devnode structure, *
- * then free it. *
- \***************************************************************/
- free(devnmp,M_DEVFSNAME);
- return 0;
-}
-
-/***************************************************************\
-* Free a hierarchy starting at a directory node name *
-* remember that if there are other names pointing to the *
-* dev_node then it may not get freed yet *
-* can handle if there is no dnp *
-* leave the node itself allocated. *
-\***************************************************************/
-/*proto*/
-void
-dev_free_hier(devnm_p devnmp)
-{
- dn_p dnp = devnmp->dnp;
-
- DBPRINT((" dev_free_hier\n"));
- if(dnp) {
- if(dnp->type == DEV_DIR)
- {
- while(dnp->by.Dir.dirlist)
- {
- dev_free_hier(dnp->by.Dir.dirlist);
- dev_free_name(dnp->by.Dir.dirlist);
- }
- }
- }
-}
-
-/*******************************************************\
-*********************************************************
-* ROUTINES to control the connection between devfs *
-* nodes and the system's vnodes *
-*********************************************************
-\*******************************************************/
-
-/*******************************************************\
-* Theoretically this could be called for any kind of *
-* vnode, however in practice it must be a DEVFS vnode *
-\*******************************************************/
-/*proto*/
-int
-devfs_vntodn(struct vnode *vn_p, dn_p *dn_pp)
-{
-
-DBPRINT((" vntodn "));
- if(vn_p->v_tag != VT_DEVFS)
- {
- printf("bad-tag2 ");
- Debugger("bad-tag ");
- return(EINVAL);
- }
-#if 0
- /*
- * XXX: This is actually a "normal" case when vclean calls us without
- * XXX: incrementing the reference count first.
- */
- if(vn_p->v_usecount == 0)
- {
- printf("No references! ");
- }
-#endif
- switch(vn_p->v_type) {
- case VBAD:
- printf("bad-type2 (VBAD)");
- return(EINVAL);
-#if 0
- case VNON:
- printf("bad-type2 (VNON)");
- return(EINVAL);
-#endif
- default:
- break;
- }
- *dn_pp = (dn_p)vn_p->v_data;
-
- return(0);
-}
-
-/***************************************************************\
-* given a dev_node, find the appropriate vnode if one is already*
-* associated, or get a new one an associate it with the dev_node*
-* need to check about vnode references.. should we increment it?*
-\***************************************************************/
-/*proto*/
-int
-devfs_dntovn(dn_p dnp, struct vnode **vn_pp)
-{
- struct vnode *vn_p;
- int error = 0;
- struct proc *p = curproc; /* XXX */
-
- vn_p = dnp->vn;
-DBPRINT(("dntovn "));
- if( vn_p)
- {
- if(vn_p->v_id != dnp->vn_id)
- {
-#if 0
- /* XXX: This is `normal'... */
- printf("bad-id ");
-#endif
- goto skip;
- }
- if(vn_p->v_tag != VT_DEVFS)
- {
-#if 0
- /* XXX: This is `normal'... */
- printf("bad-tag ");
-#endif
- goto skip;
- }
- if(vn_p->v_op != *(dnp->ops))
- {
- printf("bad-ops ");
- goto skip;
- }
- if((dn_p)(vn_p->v_data) != dnp)
- {
- printf("bad-rev_link ");
- goto skip;
- }
- if(vn_p->v_type != VNON)
- {
- vget(vn_p, LK_EXCLUSIVE, p);
- *vn_pp = vn_p;
- return(0);
- }
- else
- {
- printf("bad-type");
- }
-skip:
- vn_p = (struct vnode *) 0;
- }
- if(!(error = getnewvnode(VT_DEVFS,
- dnp->dvm->mount,
- *(dnp->ops),
- &vn_p)))
- {
- dnp->vn = vn_p;
- dnp->vn_id = vn_p->v_id;
- *vn_pp = vn_p;
-DBPRINT(("(New vnode)"));
- switch(dnp->type)
- {
- case DEV_SLNK:
- vn_p->v_type = VLNK;
- break;
- case DEV_DIR:
- if(dnp->by.Dir.parent == dnp)
- {
- vn_p->v_flag |= VROOT;
- }
- vn_p->v_type = VDIR;
- break;
- case DEV_BDEV:
- vn_p->v_type = VBLK;
- addalias(vn_p, dnp->by.dev.dev);
- break;
- case DEV_CDEV:
- vn_p->v_type = VCHR;
- addalias(vn_p, dnp->by.dev.dev);
- break;
- case DEV_DDEV:
- break;
- }
- if ( vn_p)
- {
- vn_p->v_mount = dnp->dvm->mount;/* XXX Duplicated */
- *vn_pp = vn_p;
- vn_p->v_data = (void *)dnp;
- }
- else
- {
- error = EINVAL;
- }
- vn_lock(vn_p, LK_EXCLUSIVE | LK_RETRY, p);
- }
- return error;
-}
-
-/***********************************************************************\
-* add a whole device, with no prototype.. make name element and node *
-* Used for adding the original device entries *
-\***********************************************************************/
-/*proto*/
-int
-dev_add_entry(char *name, dn_p parent, int type, union typeinfo *by,
- dn_p proto, struct devfsmount *dvm, devnm_p *nm_pp)
-{
- dn_p dnp;
- int error = 0;
-
- DBPRINT((" devfs_add_entry\n"));
- if ((error = dev_add_node(type, by, proto, &dnp,
- (parent?parent->dvm:dvm))) != 0)
- {
- printf("Device %s: base node allocation failed (Errno=%d)\n",
- name,error);
- return error;
- }
- if ((error = dev_add_name(name ,parent ,NULL, dnp, nm_pp)) != 0)
- {
- devfs_dn_free(dnp); /* 1->0 for dir, 0->(-1) for other */
- printf("Device %s: name slot allocation failed (Errno=%d)\n",
- name,error);
-
- }
- return error;
-}
-
-static void
-devfs_add_to_tree(dev_t dev, uid_t uid, gid_t gid, int perms)
-{
-
- struct cdevsw *devsw = dev->si_devsw;
-
- dev->si_devfs = devfs_add_devswf(dev->si_devsw, minor(dev), DV_CHR,
- uid, gid, perms, "%s", dev->si_name );
-
- /* XXX HACK .. name may not start in 'r' */
- if ((devsw->d_bmaj != -1)
- && (dev->si_name[0] == 'r')
- && ((devsw->d_flags & D_TYPEMASK) == D_DISK)) {
- dev->si_bdevfs = devfs_add_devswf(devsw, minor(dev), DV_BLK,
- uid, gid, perms, dev->si_name + 1);
- }
-}
-/***********************************************************************\
-* Add the named device entry into the given directory, and make it *
-* The appropriate type... (called (sometimes indirectly) by drivers..) *
-* this function is exported.. see sys/devfsext.h *
-* Has the capacity to take printf type arguments to format the device *
-* names *
-\***********************************************************************/
-void *
-devfs_add_devswf(void *devsw, int minor, int chrblk, uid_t uid,
- gid_t gid, int perms, char *fmt, ...)
-{
- int major;
- devnm_p new_dev;
- dn_p dnp; /* devnode for parent directory */
- int retval;
- union typeinfo by;
- struct cdevsw *cd;
-
- va_list ap;
- char *name, *path, buf[256]; /* XXX */
- int i;
-
- va_start(ap, fmt);
- i = kvprintf(fmt, NULL, (void*)buf, 32, ap);
- va_end(ap);
- buf[i] = '\0';
- name = NULL;
-
- for(i=strlen(buf); i>0; i--)
- if(buf[i] == '/') {
- name=&buf[i];
- buf[i]=0;
- break;
- }
-
- if (name) {
- *name++ = '\0';
- path = buf;
- } else {
- name = buf;
- path = "/";
- }
-
- DBPRINT(("dev_add\n"));
- retval = dev_finddir(path,NULL,1,&dnp);
- if (retval) return 0;
- switch(chrblk)
- {
- case DV_CHR:
- cd = devsw;
- major = cd->d_maj;
- if ( major == -1 ) return NULL;
- by.dev.dev = makedev(major, minor);
- if( dev_add_entry(name, dnp, DEV_CDEV, &by, NULL, NULL, &new_dev))
- return NULL;
- break;
- case DV_BLK:
- cd = devsw;
- major = cd->d_bmaj;
- if ( major == -1 ) return NULL;
- by.dev.dev = makebdev(major, minor);
- if( dev_add_entry(name, dnp, DEV_BDEV, &by, NULL, NULL, &new_dev))
- return NULL;
- break;
- default:
- return NULL;
- }
- new_dev->dnp->gid = gid;
- new_dev->dnp->uid = uid;
- new_dev->dnp->mode |= perms;
- devfs_propogate(dnp->by.Dir.myname,new_dev);
- return new_dev;
-}
-
-/***********************************************************************\
-* Add the named device entry into the given directory, and make it *
-* a link to the already created device given as an arg.. *
-* this function is exported.. see sys/devfsext.h *
-\***********************************************************************/
-void *
-devfs_makelink(void *original, char *fmt, ...)
-{
- devnm_p new_dev;
- devnm_p orig = (devnm_p) original;
- dn_p dirnode; /* devnode for parent directory */
- int retval;
-
- va_list ap;
- char *p, buf[256]; /* XXX */
- int i;
-
- va_start(ap, fmt);
- i = kvprintf(fmt, NULL, (void*)buf, 32, ap);
- va_end(ap);
- buf[i] = '\0';
- p = NULL;
-
- for(i=strlen(buf); i>0; i--)
- if(buf[i] == '/') {
- p=&buf[i];
- buf[i]=0;
- break;
- }
-
- DBPRINT(("dev_add\n"));
-
- /*
- * The DEV_CDEV below is not used other than it must NOT be DEV_DIR
- * the correctness of original should be checked..
- */
-
- if (p) {
- *p++ = '\0';
- retval = dev_finddir(buf,NULL,1,&dirnode);
- if (retval) return 0;
- if( dev_add_name(p, dirnode, NULL, orig->dnp, &new_dev))
- return NULL;
- } else {
- retval = dev_finddir("/",NULL,1,&dirnode);
- if (retval) return 0;
- if( dev_add_name(buf, dirnode, NULL, orig->dnp, &new_dev))
- return NULL;
- }
- devfs_propogate(dirnode->by.Dir.myname,new_dev);
- return new_dev;
-}
-
-/*
- * internal kernel call to open a device. Return either 0 or an open vnode.
- */
-struct vnode *
-devfs_open_device(char *path, int type)
-{
- register char *lastslash;
- char *nextpart;
- devnm_p nm_p;
- dn_p dirnode;
- struct vnode *vn;
-
- /*
- * If the caller didn't supply a full path, ignore and be
- * noisy about it.
- */
- if (*path != '/') {
- printf (__FUNCTION__ ": caller supplied bad path\n");
- return (NULL);
- }
-
- /*
- * find the last '/'. Unfortunatly rindex() while being in
- * libkern source, is not being compiled.. do it by hand.
- * lastslash = strrchr(path,(int)'c');
- * There will be at LEAST one '/'.
- */
- {
- register char *p = path; /* don't destroy path */
-
- for (lastslash = NULL;*p; ++p) {
- if (*p == '/')
- lastslash = p;
- }
- }
- dirnode = dev_root->dnp;
- if(lastslash != path) {
- /* find the directory we need */
- *lastslash = '\0';
- if (dev_finddir(path, dirnode, NULL, &dirnode) != 0) {
- *lastslash = '/';
- return (NULL);
- }
- /* ok we found the directory, put the slash back */
- *lastslash = '/';
- }
- nextpart = ++lastslash;
- if (*nextpart == '\0')
- return (NULL);
- /*
- * Now only return true if it exists and is the right type.
- */
- if ((nm_p = dev_findname(dirnode, nextpart)) == NULL) {
- return (NULL);
- }
- switch(type) {
- case DV_BLK:
- if( nm_p->dnp->type != DEV_BDEV)
- return (NULL);
- break;
- case DV_CHR:
- if( nm_p->dnp->type != DEV_CDEV)
- return (NULL);
- break;
- }
-
- if ( devfs_dntovn(nm_p->dnp, &vn))
- return (NULL);
-
-#if 0
- if ( VOP_OPEN(vn, FREAD, proc0.p_ucred, &proc0)) {
- vput(vn);
- return (NULL);
- }
-#endif
- return (vn);
-}
-
-/*
- * internal kernel call to close a devfs device.
- * It should have been openned by th ecall above.
- * try not mix it with user-openned vnodes.
- * Frees the vnode.
- */
-void
-devfs_close_device(struct vnode *vn)
-{
-#if 0
- VOP_CLOSE(vn, 0, proc0.p_ucred, &proc0) ;
-#endif
- vput(vn);
-}
-
-#if 0
-/*
- * Little utility routine for compatibilty.
- * Returns the dev_t that a devfs vnode represents.
- * should go away after dev_t go away :).
- */
-dev_t
-devfs_vntodev(struct vnode *vn)
-{
- register dn_p dnp;
- dnp = (dn_p)vn->v_data;
- switch (dnp->type) {
- case DEV_BDEV:
- return (dnp->by.dev.dev);
- break;
- case DEV_CDEV:
- return (dnp->by.dev.dev);
- break;
- }
- panic ("bad devfs DEVICE vnode");
-}
-#endif
diff --git a/sys/miscfs/devfs/devfs_vfsops.c b/sys/miscfs/devfs/devfs_vfsops.c
deleted file mode 100644
index f440a83..0000000
--- a/sys/miscfs/devfs/devfs_vfsops.c
+++ /dev/null
@@ -1,313 +0,0 @@
-/*-
- * Copyright 1997,1998 Julian Elischer. All rights reserved.
- * julian@freebsd.org
- *
- * 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.
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``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 HOLDER OR CONTRIBUTORS 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/systm.h>
-#include <sys/kernel.h>
-#include <sys/vnode.h>
-#include <sys/mount.h>
-#include <sys/malloc.h>
-
-#include <miscfs/devfs/devfsdefs.h>
-
-static MALLOC_DEFINE(M_DEVFSMNT, "DEVFS mount", "DEVFS mount structure");
-
-static int devfs_statfs( struct mount *mp, struct statfs *sbp, struct proc *p);
-
-/*-
- * Called from the generic VFS startups.
- * This is the second stage of DEVFS initialisation.
- * The probed devices have already been loaded and the
- * basic structure of the DEVFS created.
- * We take the oportunity to mount the hidden DEVFS layer, so that
- * devices from devfs get sync'd.
- */
-static int
-devfs_init(struct vfsconf *vfsp)
-{
- struct mount *mp = dev_root->dnp->dvm->mount;
- /*-
- * fill in the missing members on the "hidden" mount
- * we could almost use vfs_rootmountalloc() to do this.
- */
- lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, 0);
- mp->mnt_op = vfsp->vfc_vfsops;
- mp->mnt_vfc = vfsp;
- mp->mnt_stat.f_type = vfsp->vfc_typenum;
- mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK;
- strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN);
- mp->mnt_vnodecovered = NULLVP;
-
- /* Mark a reference for the "invisible" blueprint mount */
- mp->mnt_vfc->vfc_refcount++;
- TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
-
- printf("DEVFS: ready to run\n");
- return 0; /*XXX*/
-}
-
-/*-
- * mp - pointer to 'mount' structure
- * path - addr in user space of mount point (ie /usr or whatever)
- * data - addr in user space of mount params including the
- * name of the block special file to treat as a filesystem.
- * ndp - namei data pointer
- * p - proc pointer
- * devfs is special in that it doesn't require any device to be mounted..
- * It makes up its data as it goes along.
- * it must be mounted during single user.. until it is, only std{in/out/err}
- * and the root filesystem are available.
- */
-/*proto*/
-int
-devfs_mount(struct mount *mp, char *path, caddr_t data,
- struct nameidata *ndp, struct proc *p)
-{
- struct devfsmount *devfs_mp_p; /* devfs specific mount info */
- int error;
- u_int size;
-
-DBPRINT(("mount "));
-
- /*-
- * If they just want to update, we don't need to do anything.
- */
- if (mp->mnt_flag & MNT_UPDATE)
- {
- return 0;
- }
-
- /*-
- * Well, it's not an update, it's a real mount request.
- * Time to get dirty.
- * HERE we should check to see if we are already mounted here.
- */
-
- devfs_mp_p = (struct devfsmount *)malloc(sizeof *devfs_mp_p,
- M_DEVFSMNT, M_WAITOK);
- if (devfs_mp_p == NULL)
- return (ENOMEM);
- bzero(devfs_mp_p,sizeof(*devfs_mp_p));
- devfs_mp_p->mount = mp;
-
- /*-
- * Fill out some fields
- */
- mp->mnt_data = (qaddr_t)devfs_mp_p;
- if (mp->mnt_vfc == NULL)
- mp->mnt_stat.f_type = -1; /* doing hidden mountpoint */
- else
- mp->mnt_stat.f_type = mp->mnt_vfc->vfc_typenum;
- mp->mnt_stat.f_fsid.val[0] = (intptr_t)(void *)devfs_mp_p;
- mp->mnt_stat.f_fsid.val[1] = mp->mnt_stat.f_type;
- mp->mnt_flag |= MNT_LOCAL;
-
- if((error = dev_dup_plane(devfs_mp_p)) != 0)
- {
- mp->mnt_data = (qaddr_t)0;
- free((caddr_t)devfs_mp_p, M_DEVFSMNT);
- return (error);
- }
-
- /*-
- * Copy in the name of the directory the filesystem
- * is to be mounted on.
- * And we clear the remainder of the character strings
- * to be tidy.
- * Then, we try to fill in the filesystem stats structure
- * as best we can with whatever we can think of at the time
- */
-
- if(devfs_up_and_going) {
- copyinstr(path, (caddr_t)mp->mnt_stat.f_mntonname,
- sizeof(mp->mnt_stat.f_mntonname)-1, &size);
- bzero(mp->mnt_stat.f_mntonname + size,
- sizeof(mp->mnt_stat.f_mntonname) - size);
- } else {
- bcopy("dummy_mount", (caddr_t)mp->mnt_stat.f_mntonname,12);
- }
- bzero(mp->mnt_stat.f_mntfromname , MNAMELEN );
- bcopy("devfs",mp->mnt_stat.f_mntfromname, 5);
- (void)devfs_statfs(mp, &mp->mnt_stat, p);
- return 0;
-}
-
-
-/*-
- * Unmount the filesystem described by mp.
- */
-static int
-devfs_unmount( struct mount *mp, int mntflags, struct proc *p)
-{
- struct devfsmount *devfs_mp_p = (struct devfsmount *)mp->mnt_data;
- int flags = 0;
- int error;
-
- if (mntflags & MNT_FORCE) {
- flags |= FORCECLOSE;
- }
- error = vflush(mp, NULLVP, flags);
- if (error)
- return error;
-
-DBPRINT(("unmount "));
- devfs_free_plane(devfs_mp_p);
- free((caddr_t)devfs_mp_p, M_DEVFSMNT);
- mp->mnt_data = (qaddr_t)0;
- mp->mnt_flag &= ~MNT_LOCAL;
-
- return 0;
-}
-
-/* return the address of the root vnode in *vpp */
-static int
-devfs_root(struct mount *mp, struct vnode **vpp)
-{
- struct devfsmount *devfs_mp_p = (struct devfsmount *)(mp->mnt_data);
-
-DBPRINT(("root "));
- devfs_dntovn(devfs_mp_p->plane_root->dnp,vpp);
- return 0;
-}
-
-static int
-devfs_statfs( struct mount *mp, struct statfs *sbp, struct proc *p)
-{
- struct devfsmount *devfs_mp_p = (struct devfsmount *)mp->mnt_data;
-
-/*-
- * Fill in the stat block.
- */
-DBPRINT(("statfs "));
- sbp->f_type = mp->mnt_stat.f_type;
- sbp->f_flags = 0; /* XXX */
- sbp->f_bsize = 128;
- sbp->f_iosize = 1024; /* XXX*/
- sbp->f_blocks = 128;
- sbp->f_bfree = 0;
- sbp->f_bavail = 0;
- sbp->f_files = 128;
- sbp->f_ffree = 0; /* what to put in here? */
- sbp->f_fsid.val[0] = (intptr_t)(void *)devfs_mp_p;
- sbp->f_fsid.val[1] = mp->mnt_stat.f_type;
-
-/*-
- * Copy the mounted on and mounted from names into
- * the passed in stat block, if it is not the one
- * in the mount structure.
- */
- if (sbp != &mp->mnt_stat) {
- bcopy((caddr_t)mp->mnt_stat.f_mntonname,
- (caddr_t)&sbp->f_mntonname[0], MNAMELEN);
- bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
- (caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
- }
- return 0;
-}
-
-/*-
- * Go through the disk queues to initiate sandbagged IO;
- * go through the inodes to write those that have been modified;
- * initiate the writing of the super block if it has been modified.
- *
- * Note: we are always called with the filesystem marked `MPBUSY'.
- */
-static int
-devfs_sync(struct mount *mp, int waitfor,struct ucred *cred,struct proc *p)
-{
- register struct vnode *vp, *nvp;
- int error, allerror = 0;
-
-DBPRINT(("sync "));
-
- /*-
- * Write back modified superblock.
- * Consistency check that the superblock
- * is still in the buffer cache.
- */
- /*-
- * Write back each (modified) inode.
- */
-loop:
- for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
- /*-
- * If the vnode that we are about to sync is no longer
- * associated with this mount point, start over.
- */
- if (vp->v_mount != mp)
- goto loop;
- nvp = vp->v_mntvnodes.le_next;
- if (VOP_ISLOCKED(vp, NULL))
- continue;
- if (TAILQ_EMPTY(&vp->v_dirtyblkhd))
- continue;
- if (vp->v_type == VBLK) {
- if (vget(vp, LK_EXCLUSIVE, p))
- goto loop;
- error = VOP_FSYNC(vp, cred, waitfor, p);
- if (error)
- allerror = error;
- vput(vp);
- }
-#ifdef NOTYET
- else {
- struct timeval tv;
-
- tv = time;
- /* VOP_UPDATE(vp, &tv, &tv, waitfor == MNT_WAIT); */
- VOP_UPDATE(vp, &tv, &tv, 0);
- }
-#endif
- }
- /*-
- * Force stale file system control information to be flushed.
- *( except that htat makes no sense with devfs
- */
- return (allerror);
-}
-
-static struct vfsops devfs_vfsops = {
- devfs_mount,
- vfs_stdstart,
- devfs_unmount,
- devfs_root,
- vfs_stdquotactl,
- devfs_statfs,
- devfs_sync,
- vfs_stdvget,
- vfs_stdfhtovp,
- vfs_stdcheckexp,
- vfs_stdvptofh,
- devfs_init,
- vfs_stduninit,
- vfs_stdextattrctl,
-};
-
-VFS_SET(devfs_vfsops, devfs, 0);
diff --git a/sys/miscfs/devfs/devfs_vnops.c b/sys/miscfs/devfs/devfs_vnops.c
deleted file mode 100644
index 9a9c120..0000000
--- a/sys/miscfs/devfs/devfs_vnops.c
+++ /dev/null
@@ -1,2014 +0,0 @@
-/*
- * Copyright 1997,1998 Julian Elischer. All rights reserved.
- * julian@freebsd.org
- *
- * 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.
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``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 HOLDER OR CONTRIBUTORS 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/systm.h>
-#include <sys/bio.h>
-#include <sys/buf.h>
-#include <sys/namei.h>
-#include <sys/kernel.h>
-#include <sys/fcntl.h>
-#include <sys/conf.h>
-#include <sys/lock.h>
-#include <sys/stat.h>
-#include <sys/mount.h>
-#include <sys/proc.h>
-#include <sys/time.h>
-#include <sys/vnode.h>
-#include <sys/dirent.h>
-#include <miscfs/devfs/devfsdefs.h>
-#include <sys/vmmeter.h>
-
-#include <vm/vm.h>
-#include <vm/vm_object.h>
-#include <vm/vm_page.h>
-#include <vm/vm_pager.h>
-
-
-/*
- * Insert description here
- */
-
-
-/*
- * Convert a component of a pathname into a pointer to a locked node.
- * This is a very central and rather complicated routine.
- * If the file system is not maintained in a strict tree hierarchy,
- * this can result in a deadlock situation (see comments in code below).
- *
- * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
- * whether the name is to be looked up, created, renamed, or deleted.
- * When CREATE, RENAME, or DELETE is specified, information usable in
- * creating, renaming, or deleting a directory entry may be calculated.
- * If flag has LOCKPARENT or'ed into it and the target of the pathname
- * exists, lookup returns both the target and its parent directory locked.
- * When creating or renaming and LOCKPARENT is specified, the target may
- * not be ".". When deleting and LOCKPARENT is specified, the target may
- * be "."., but the caller must check to ensure it does an vrele and DNUNLOCK
- * instead of two DNUNLOCKs.
- *
- * Overall outline of devfs_lookup:
- *
- * check accessibility of directory
- * null terminate the component (lookup leaves the whole string alone)
- * look for name in cache, if found, then if at end of path
- * and deleting or creating, drop it, else return name
- * search for name in directory, to found or notfound
- * notfound:
- * if creating, return locked directory,
- * else return error
- * found:
- * if at end of path and deleting, return information to allow delete
- * if at end of path and rewriting (RENAME and LOCKPARENT), lock target
- * node and return info to allow rewrite
- * if not at end, add name to cache; if at end and neither creating
- * nor deleting, add name to cache
- * On return to lookup, remove the null termination we put in at the start.
- *
- * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent node unlocked.
- */
-static int
-devfs_lookup(struct vop_lookup_args *ap)
- /*struct vop_lookup_args {
- struct vnode * a_dvp; directory vnode ptr
- struct vnode ** a_vpp; where to put the result
- struct componentname * a_cnp; the name we want
- };*/
-{
- struct componentname *cnp = ap->a_cnp;
- struct vnode *dir_vnode = ap->a_dvp;
- struct vnode **result_vnode = ap->a_vpp;
- dn_p dir_node; /* the directory we are searching */
- dn_p new_node; /* the node we are searching for */
- devnm_p new_nodename;
- int flags = cnp->cn_flags;
- int op = cnp->cn_nameiop; /* LOOKUP, CREATE, RENAME, or DELETE */
- int lockparent = flags & LOCKPARENT;
- int wantparent = flags & (LOCKPARENT|WANTPARENT);
- int error = 0;
- struct proc *p = cnp->cn_proc;
- char heldchar; /* the char at the end of the name componet */
-
- *result_vnode = NULL; /* safe not sorry */ /*XXX*/
-
-DBPRINT(("lookup\n"));
-
- if (dir_vnode->v_usecount == 0)
- printf("dir had no refs ");
- if (devfs_vntodn(dir_vnode,&dir_node))
- {
- printf("vnode has changed?\n");
- vprint("=",dir_vnode);
- return(EINVAL);
- }
-
- /*
- * Check accessiblity of directory.
- */
- if (dir_node->type != DEV_DIR) /* XXX or symlink? */
- {
- return (ENOTDIR);
- }
- if ((error = VOP_ACCESS(dir_vnode, VEXEC, cnp->cn_cred, p)) != 0)
- {
- return (error);
- }
-
- /*
- * We now have a segment name to search for, and a directory to search.
- *
- */
-
-/***********************************************************************\
-* SEARCH FOR NAME *
-* while making sure the component is null terminated for the strcmp *
-\***********************************************************************/
-
- heldchar = cnp->cn_nameptr[cnp->cn_namelen];
- cnp->cn_nameptr[cnp->cn_namelen] = '\0';
- new_nodename = dev_findname(dir_node,cnp->cn_nameptr);
- cnp->cn_nameptr[cnp->cn_namelen] = heldchar;
- if(!new_nodename) {
- /*******************************************************\
- * Failed to find it.. (That may be good) *
- \*******************************************************/
- new_node = NULL; /* to be safe */
- /*
- * If creating, and at end of pathname
- * then can consider
- * allowing file to be created.
- */
- if (!(flags & ISLASTCN) || !(op == CREATE || op == RENAME)) {
- return ENOENT;
- }
- /*
- * Access for write is interpreted as allowing
- * creation of files in the directory.
- */
- if ((error = VOP_ACCESS(dir_vnode, VWRITE,
- cnp->cn_cred, p)) != 0)
- {
-DBPRINT(("MKACCESS "));
- return (error);
- }
- /*
- * We return with the directory locked, so that
- * the parameters we set up above will still be
- * valid if we actually decide to add a new entry.
- * We return ni_vp == NULL to indicate that the entry
- * does not currently exist; we leave a pointer to
- * the (locked) directory vnode in namei_data->ni_dvp.
- * The pathname buffer is saved so that the name
- * can be obtained later.
- *
- * NB - if the directory is unlocked, then this
- * information cannot be used.
- */
- cnp->cn_flags |= SAVENAME; /*XXX why? */
- if (!lockparent)
- VOP_UNLOCK(dir_vnode, 0, p);
- return (EJUSTRETURN);
- }
-
- /***************************************************************\
- * Found it.. this is not always a good thing.. *
- \***************************************************************/
- new_node = new_nodename->dnp;
- new_node->last_lookup = new_nodename; /* for unlink */
- /*
- * If deleting, and at end of pathname, return
- * parameters which can be used to remove file.
- * If the wantparent flag isn't set, we return only
- * the directory (in namei_data->ni_dvp), otherwise we go
- * on and lock the node, being careful with ".".
- */
- if (op == DELETE && (flags & ISLASTCN)) {
- /*
- * Write access to directory required to delete files.
- */
- if ((error = VOP_ACCESS(dir_vnode, VWRITE,
- cnp->cn_cred, p)) != 0)
- return (error);
- /*
- * we are trying to delete '.'. What does this mean? XXX
- */
- if (dir_node == new_node) {
- VREF(dir_vnode);
- *result_vnode = dir_vnode;
- return (0);
- }
- /*
- * If directory is "sticky", then user must own
- * the directory, or the file in it, else she
- * may not delete it (unless she's root). This
- * implements append-only directories.
- */
- devfs_dntovn(new_node,result_vnode);
-#ifdef NOTYET
- if ((dir_node->mode & ISVTX) &&
- cnp->cn_cred->cr_uid != 0 &&
- cnp->cn_cred->cr_uid != dir_node->uid &&
- cnp->cn_cred->cr_uid != new_node->uid) {
- VOP_UNLOCK(*result_vnode, 0, p);
- return (EPERM);
- }
-#endif
- if (!lockparent)
- VOP_UNLOCK(dir_vnode, 0, p);
- return (0);
- }
-
- /*
- * If rewriting (RENAME), return the vnode and the
- * information required to rewrite the present directory
- * Must get node of directory entry to verify it's a
- * regular file, or empty directory.
- */
- if (op == RENAME && wantparent && (flags & ISLASTCN)) {
- /*
- * Are we allowed to change the holding directory?
- */
- if ((error = VOP_ACCESS(dir_vnode, VWRITE,
- cnp->cn_cred, p)) != 0)
- return (error);
- /*
- * Careful about locking second node.
- * This can only occur if the target is ".".
- */
- if (dir_node == new_node)
- return (EISDIR);
- devfs_dntovn(new_node,result_vnode);
- /* hmm save the 'from' name (we need to delete it) */
- cnp->cn_flags |= SAVENAME;
- if (!lockparent)
- VOP_UNLOCK(dir_vnode, 0, p);
- return (0);
- }
-
- /*
- * Step through the translation in the name. We do not unlock the
- * directory because we may need it again if a symbolic link
- * is relative to the current directory. Instead we save it
- * unlocked as "saved_dir_node" XXX. We must get the target
- * node before unlocking
- * the directory to insure that the node will not be removed
- * before we get it. We prevent deadlock by always fetching
- * nodes from the root, moving down the directory tree. Thus
- * when following backward pointers ".." we must unlock the
- * parent directory before getting the requested directory.
- * There is a potential race condition here if both the current
- * and parent directories are removed before the lock for the
- * node associated with ".." returns. We hope that this occurs
- * infrequently since we cannot avoid this race condition without
- * implementing a sophisticated deadlock detection algorithm.
- * Note also that this simple deadlock detection scheme will not
- * work if the file system has any hard links other than ".."
- * that point backwards in the directory structure.
- */
- if (flags & ISDOTDOT) {
- VOP_UNLOCK(dir_vnode, 0, p); /* race to get the node */
- devfs_dntovn(new_node,result_vnode);
- if (lockparent && (flags & ISLASTCN))
- vn_lock(dir_vnode, LK_EXCLUSIVE | LK_RETRY, p);
- } else if (dir_node == new_node) {
- VREF(dir_vnode); /* we want ourself, ie "." */
- *result_vnode = dir_vnode;
- } else {
- devfs_dntovn(new_node,result_vnode);
- if (!lockparent || (flags & ISLASTCN))
- VOP_UNLOCK(dir_vnode, 0, p);
- }
-
-DBPRINT(("GOT\n"));
- return (0);
-}
-
-/*
- */
-
-static int
-devfs_access(struct vop_access_args *ap)
- /*struct vop_access_args {
- struct vnode *a_vp;
- int a_mode;
- struct ucred *a_cred;
- struct proc *a_p;
- } */
-{
- /*
- * mode is filled with a combination of VREAD, VWRITE,
- * and/or VEXEC bits turned on. In an octal number these
- * are the Y in 0Y00.
- */
- struct vnode *vp = ap->a_vp;
- int mode = ap->a_mode;
- struct ucred *cred = ap->a_cred;
- dn_p dnp;
- int error;
- gid_t *gp;
- int i;
-
-DBPRINT(("access\n"));
- if ((error = devfs_vntodn(vp,&dnp)) != 0)
- {
- printf("devfs_vntodn returned %d ",error);
- return error;
- }
-
- /*
- * if we are not running as a process, we are in the
- * kernel and we DO have permission
- */
- if (ap->a_p == NULL)
- return 0;
-
- /*
- * Access check is based on only one of owner, group, public.
- * If not owner, then check group. If not a member of the
- * group, then check public access.
- */
- if (cred->cr_uid != dnp->uid)
- {
- /* failing that.. try groups */
- mode >>= 3;
- gp = cred->cr_groups;
- for (i = 0; i < cred->cr_ngroups; i++, gp++)
- {
- if (dnp->gid == *gp)
- {
- goto found;
- }
- }
- /* failing that.. try general access */
- mode >>= 3;
-found:
- ;
- }
- if ((dnp->mode & mode) == mode)
- return (0);
- /*
- * Root gets to do anything.
- * but only use suser_xxx prives as a last resort
- * (Use of super powers is recorded in ap->a_p->p_acflag)
- */
- if( suser_xxx(cred, ap->a_p, 0) == 0) /* XXX what if no proc? */
- return 0;
- return (EACCES);
-}
-
-static int
-devfs_getattr(struct vop_getattr_args *ap)
- /*struct vop_getattr_args {
- struct vnode *a_vp;
- struct vattr *a_vap;
- struct ucred *a_cred;
- struct proc *a_p;
- } */
-{
- struct vnode *vp = ap->a_vp;
- struct vattr *vap = ap->a_vap;
- dn_p dnp;
- int error;
-
-DBPRINT(("getattr\n"));
- if ((error = devfs_vntodn(vp,&dnp)) != 0)
- {
- printf("devfs_vntodn returned %d ",error);
- return error;
- }
- vap->va_rdev = 0;/* default value only */
- vap->va_mode = dnp->mode;
- switch (dnp->type)
- {
- case DEV_DIR:
- vap->va_rdev = (udev_t)dnp->dvm;
- vap->va_mode |= (S_IFDIR);
- break;
- case DEV_CDEV:
- vap->va_rdev = dev2udev(vp->v_rdev);
- vap->va_mode |= (S_IFCHR);
- break;
-#if nolonger
- case DEV_BDEV:
- vap->va_rdev = dev2budev(vp->v_rdev);
- vap->va_mode |= (S_IFBLK);
- break;
-#endif
- case DEV_SLNK:
- break;
- }
- vap->va_type = vp->v_type;
- vap->va_nlink = dnp->links;
- vap->va_uid = dnp->uid;
- vap->va_gid = dnp->gid;
- vap->va_fsid = (intptr_t)(void *)dnp->dvm;
- vap->va_fileid = (intptr_t)(void *)dnp;
- vap->va_size = dnp->len; /* now a u_quad_t */
- vap->va_blocksize = 512;
- /*
- * XXX If the node times are in Jan 1, 1970, then
- * update them to the boot time.
- * When we made the node, the date/time was not yet known.
- */
- if(dnp->ctime.tv_sec < (24 * 3600))
- {
- TIMEVAL_TO_TIMESPEC(&boottime,&(dnp->ctime));
- TIMEVAL_TO_TIMESPEC(&boottime,&(dnp->mtime));
- TIMEVAL_TO_TIMESPEC(&boottime,&(dnp->atime));
- }
- if (dnp->flags & IN_ACCESS) {
- nanotime(&dnp->atime);
- dnp->flags &= ~IN_ACCESS;
- }
- vap->va_ctime = dnp->ctime;
- vap->va_mtime = dnp->mtime;
- vap->va_atime = dnp->atime;
- vap->va_gen = 0;
- vap->va_flags = 0;
- vap->va_bytes = dnp->len; /* u_quad_t */
- vap->va_filerev = 0; /* XXX */ /* u_quad_t */
- vap->va_vaflags = 0; /* XXX */
- return 0;
-}
-
-static int
-devfs_setattr(struct vop_setattr_args *ap)
- /*struct vop_setattr_args {
- struct vnode *a_vp;
- struct vattr *a_vap;
- struct ucred *a_cred;
- struct proc *a_p;
- } */
-{
- struct vnode *vp = ap->a_vp;
- struct vattr *vap = ap->a_vap;
- struct ucred *cred = ap->a_cred;
- struct proc *p = ap->a_p;
- int error = 0;
- gid_t *gp;
- int i;
- dn_p dnp;
-
- if (vap->va_flags != VNOVAL) /* XXX needs to be implemented */
- return (EOPNOTSUPP);
-
- if ((error = devfs_vntodn(vp,&dnp)) != 0)
- {
- printf("devfs_vntodn returned %d ",error);
- return error;
- }
-DBPRINT(("setattr\n"));
- if ((vap->va_type != VNON) ||
- (vap->va_nlink != VNOVAL) ||
- (vap->va_fsid != VNOVAL) ||
- (vap->va_fileid != VNOVAL) ||
- (vap->va_blocksize != VNOVAL) ||
- (vap->va_rdev != VNOVAL) ||
- (vap->va_bytes != VNOVAL) ||
- (vap->va_gen != VNOVAL ))
- {
- return EINVAL;
- }
-
-
- /*
- * Anyone can touch the files in such a way that the times are set
- * to NOW (e.g. run 'touch') if they have write permissions
- * however only the owner or root can set "un-natural times.
- * They also don't need write permissions.
- */
- if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
-#if 0 /*
- * This next test is pointless under devfs for now..
- * as there is only one devfs hiding under potentially many
- * mountpoints and actual device node are really 'mounted' under
- * a FAKE mountpoint inside the kernel only, no matter where it
- * APPEARS they are mounted to the outside world..
- * A readonly devfs doesn't exist anyway.
- */
- if (vp->v_mount->mnt_flag & MNT_RDONLY)
- return (EROFS);
-#endif
- if (((vap->va_vaflags & VA_UTIMES_NULL) == 0) &&
- (cred->cr_uid != dnp->uid) &&
- suser_xxx(cred, p, 0))
- return (EPERM);
- if(VOP_ACCESS(vp, VWRITE, cred, p))
- return (EACCES);
- dnp->atime = vap->va_atime;
- dnp->mtime = vap->va_mtime;
- nanotime(&dnp->ctime);
- return (0);
- }
-
- /*
- * Change the permissions.. must be root or owner to do this.
- */
- if (vap->va_mode != (u_short)VNOVAL) {
- if ((cred->cr_uid != dnp->uid)
- && suser_xxx(cred, p, 0))
- return (EPERM);
- /* set drwxwxrwx stuff */
- dnp->mode &= ~07777;
- dnp->mode |= vap->va_mode & 07777;
- }
-
- /*
- * Change the owner.. must be root to do this.
- */
- if (vap->va_uid != (uid_t)VNOVAL) {
- if (suser_xxx(cred, p, 0))
- return (EPERM);
- dnp->uid = vap->va_uid;
- }
-
- /*
- * Change the group.. must be root or owner to do this.
- * If we are the owner, we must be in the target group too.
- * don't use suser_xxx() unless you have to as it reports
- * whether you needed suser_xxx powers or not.
- */
- if (vap->va_gid != (gid_t)VNOVAL) {
- if (cred->cr_uid == dnp->uid){
- gp = cred->cr_groups;
- for (i = 0; i < cred->cr_ngroups; i++, gp++) {
- if (vap->va_gid == *gp)
- goto cando;
- }
- }
- /*
- * we can't do it with normal privs,
- * do we have an ace up our sleeve?
- */
- if( suser_xxx(cred, p, 0))
- return (EPERM);
-cando:
- dnp->gid = vap->va_gid;
- }
-#if 0
- /*
- * Copied from somewhere else
- * but only kept as a marker and reminder of the fact that
- * flags should be handled some day
- */
- if (vap->va_flags != VNOVAL) {
- if (error = suser_xxx(cred, p, 0))
- return error;
- if (cred->cr_uid == 0)
- ;
- else {
- }
- }
-#endif
- return error;
-}
-
-
-static int
-devfs_xread(struct vop_read_args *ap)
- /*struct vop_read_args {
- struct vnode *a_vp;
- struct uio *a_uio;
- int a_ioflag;
- struct ucred *a_cred;
- } */
-{
- int error = 0;
- dn_p dnp;
- struct vnode *vp = ap->a_vp;
-
-DBPRINT(("read\n"));
- if ((error = devfs_vntodn(vp,&dnp)) != 0)
- {
- printf("devfs_vntodn returned %d ",error);
- return error;
- }
-
-
- switch (vp->v_type) {
- case VREG:
- return(EINVAL);
- case VDIR:
- return VOP_READDIR(vp,ap->a_uio,ap->a_cred,
- NULL,NULL,NULL);
- case VCHR:
- case VBLK:
- panic("devfs: vnode methods");
-
- default:
- panic("devfs_read(): bad file type");
- break;
- }
-}
-
-/*
- * Write data to a file or directory.
- */
-static int
-devfs_xwrite(struct vop_write_args *ap)
- /*struct vop_write_args {
- struct vnode *a_vp;
- struct uio *a_uio;
- int a_ioflag;
- struct ucred *a_cred;
- } */
-{
- struct vnode *vp = ap->a_vp;
-
- switch (vp->v_type) {
- case VREG:
- return(EINVAL);
- case VDIR:
- return(EISDIR);
- case VCHR:
- case VBLK:
- panic("devfs: vnode methods");
- default:
- panic("devfs_xwrite(): bad file type");
- }
-}
-
-
-static int
-devfs_remove(struct vop_remove_args *ap)
- /*struct vop_remove_args {
- struct vnode *a_dvp;
- struct vnode *a_vp;
- struct componentname *a_cnp;
- } */
-{
- struct vnode *vp = ap->a_vp;
- struct vnode *dvp = ap->a_dvp;
- struct componentname *cnp = ap->a_cnp;
- dn_p tp, tdp;
- devnm_p tnp;
- int doingdirectory = 0;
- int error = 0;
- uid_t ouruid = cnp->cn_cred->cr_uid;
-
-
-DBPRINT(("remove\n"));
- /*
- * Lock our directories and get our name pointers
- * assume that the names are null terminated as they
- * are the end of the path. Get pointers to all our
- * devfs structures.
- */
- if ((error = devfs_vntodn(dvp, &tdp)) != 0) {
-abortit:
- return (error);
- }
- if ((error = devfs_vntodn(vp, &tp)) != 0) goto abortit;
- /*
- * Assuming we are atomic, dev_lookup left this for us
- */
- tnp = tp->last_lookup;
-
-
- /*
- * Check we are doing legal things WRT the new flags
- */
- if ((tp->flags & (IMMUTABLE | APPEND))
- || (tdp->flags & APPEND) /*XXX eh?*/ ) {
- error = EPERM;
- goto abortit;
- }
-
- /*
- * Make sure that we don't try do something stupid
- */
- if ((tp->type) == DEV_DIR) {
- /*
- * Avoid ".", "..", and aliases of "." for obvious reasons.
- */
- if ( (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.')
- || (cnp->cn_flags&ISDOTDOT) ) {
- error = EINVAL;
- goto abortit;
- }
- doingdirectory++;
- }
-
- /***********************************
- * Start actually doing things.... *
- ***********************************/
- getnanotime(&(tdp->mtime));
-
-
- /*
- * own the parent directory, or the destination of the rename,
- * otherwise the destination may not be changed (except by
- * root). This implements append-only directories.
- * XXX shoudn't this be in generic code?
- */
- if ((tdp->mode & S_ISTXT)
- && ouruid != 0
- && ouruid != tdp->uid
- && ouruid != tp->uid ) {
- error = EPERM;
- goto abortit;
- }
- /*
- * Target must be empty if a directory and have no links
- * to it. Also, ensure source and target are compatible
- * (both directories, or both not directories).
- */
- if (( doingdirectory) && (tp->links > 2)) {
- printf("nlink = %d\n",tp->links); /*XXX*/
- error = ENOTEMPTY;
- goto abortit;
- }
- dev_free_name(tnp);
- tp = NULL;
- return (error);
-}
-
-/*
- */
-static int
-devfs_link(struct vop_link_args *ap)
- /*struct vop_link_args {
- struct vnode *a_tdvp;
- struct vnode *a_vp;
- struct componentname *a_cnp;
- } */
-{
- struct vnode *vp = ap->a_vp;
- struct vnode *tdvp = ap->a_tdvp;
- struct componentname *cnp = ap->a_cnp;
- dn_p fp, tdp;
- devnm_p tnp;
- int error = 0;
-
-DBPRINT(("link\n"));
- /*
- * First catch an arbitrary restriction for this FS
- */
- if(cnp->cn_namelen > DEVMAXNAMESIZE) {
- error = ENAMETOOLONG;
- goto abortit;
- }
-
- /*
- * Lock our directories and get our name pointers
- * assume that the names are null terminated as they
- * are the end of the path. Get pointers to all our
- * devfs structures.
- */
- if ((error = devfs_vntodn(tdvp,&tdp)) != 0) goto abortit;
- if ((error = devfs_vntodn(vp,&fp)) != 0) goto abortit;
-
- /*
- * trying to move it out of devfs? (v_tag == VT_DEVFS)
- */
- if ( (vp->v_tag != VT_DEVFS)
- || (vp->v_tag != tdvp->v_tag) ) {
- error = EXDEV;
-abortit:
- goto out;
- }
-
- /*
- * Check we are doing legal things WRT the new flags
- */
- if (fp->flags & (IMMUTABLE | APPEND)) {
- error = EPERM;
- goto abortit;
- }
-
- /***********************************
- * Start actually doing things.... *
- ***********************************/
- getnanotime(&(tdp->atime));
- error = dev_add_name(cnp->cn_nameptr,
- tdp,
- NULL,
- fp,
- &tnp);
-out:
- return (error);
-
-}
-
-/*
- * Rename system call. Seems overly complicated to me...
- * rename("foo", "bar");
- * is essentially
- * unlink("bar");
- * link("foo", "bar");
- * unlink("foo");
- * but ``atomically''.
- *
- * When the target exists, both the directory
- * and target vnodes are locked.
- * the source and source-parent vnodes are referenced
- *
- *
- * Basic algorithm is:
- *
- * 1) Bump link count on source while we're linking it to the
- * target. This also ensure the inode won't be deleted out
- * from underneath us while we work (it may be truncated by
- * a concurrent `trunc' or `open' for creation).
- * 2) Link source to destination. If destination already exists,
- * delete it first.
- * 3) Unlink source reference to node if still around. If a
- * directory was moved and the parent of the destination
- * is different from the source, patch the ".." entry in the
- * directory.
- */
-static int
-devfs_rename(struct vop_rename_args *ap)
- /*struct vop_rename_args {
- struct vnode *a_fdvp;
- struct vnode *a_fvp;
- struct componentname *a_fcnp;
- struct vnode *a_tdvp;
- struct vnode *a_tvp;
- struct componentname *a_tcnp;
- } */
-{
- struct vnode *tvp = ap->a_tvp;
- struct vnode *tdvp = ap->a_tdvp;
- struct vnode *fvp = ap->a_fvp;
- struct vnode *fdvp = ap->a_fdvp;
- struct componentname *tcnp = ap->a_tcnp;
- struct componentname *fcnp = ap->a_fcnp;
- struct proc *p = fcnp->cn_proc;
- dn_p fp, fdp, tp, tdp;
- devnm_p fnp,tnp;
- int doingdirectory = 0;
- int error = 0;
-
- /*
- * First catch an arbitrary restriction for this FS
- */
- if(tcnp->cn_namelen > DEVMAXNAMESIZE) {
- error = ENAMETOOLONG;
- goto abortit;
- }
-
- /*
- * Lock our directories and get our name pointers
- * assume that the names are null terminated as they
- * are the end of the path. Get pointers to all our
- * devfs structures.
- */
- if ((error = devfs_vntodn(tdvp,&tdp)) != 0) goto abortit;
- if ((error = devfs_vntodn(fdvp,&fdp)) != 0) goto abortit;
- if ((error = devfs_vntodn(fvp,&fp)) != 0) goto abortit;
- fnp = fp->last_lookup;
- if (tvp) {
- if ((error = devfs_vntodn(tvp,&tp)) != 0) goto abortit;
- tnp = tp->last_lookup;
- } else {
- tp = NULL;
- tnp = NULL;
- }
-
- /*
- * trying to move it out of devfs? (v_tag == VT_DEVFS)
- * if we move a dir across mnt points. we need to fix all
- * the mountpoint pointers! XXX
- * so for now keep dirs within the same mount
- */
- if ( (fvp->v_tag != VT_DEVFS)
- || (fvp->v_tag != tdvp->v_tag)
- || (tvp && (fvp->v_tag != tvp->v_tag))
- || ((fp->type == DEV_DIR) && (fp->dvm != tdp->dvm ))) {
- error = EXDEV;
-abortit:
- if (tdvp == tvp) /* eh? */
- vrele(tdvp);
- else
- vput(tdvp);
- if (tvp)
- vput(tvp);
- vrele(fdvp);
- vrele(fvp);
- return (error);
- }
-
- /*
- * Check we are doing legal things WRT the new flags
- */
- if ((tp && (tp->flags & (IMMUTABLE | APPEND)))
- || (fp->flags & (IMMUTABLE | APPEND))
- || (fdp->flags & APPEND)) {
- error = EPERM;
- goto abortit;
- }
-
- /*
- * Make sure that we don't try do something stupid
- */
- if ((fp->type) == DEV_DIR) {
- /*
- * Avoid ".", "..", and aliases of "." for obvious reasons.
- */
- if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.')
- || (fcnp->cn_flags&ISDOTDOT)
- || (tcnp->cn_namelen == 1 && tcnp->cn_nameptr[0] == '.')
- || (tcnp->cn_flags&ISDOTDOT)
- || (tdp == fp )) {
- error = EINVAL;
- goto abortit;
- }
- doingdirectory++;
- }
-
- /*
- * If ".." must be changed (ie the directory gets a new
- * parent) then the source directory must not be in the
- * directory heirarchy above the target, as this would
- * orphan everything below the source directory. Also
- * the user must have write permission in the source so
- * as to be able to change "..".
- */
- if (doingdirectory && (tdp != fdp)) {
- dn_p tmp,ntmp;
- error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
- tmp = tdp;
- do {
- if(tmp == fp) {
- /* XXX unlock stuff here probably */
- error = EINVAL;
- goto out;
- }
- ntmp = tmp;
- } while ((tmp = tmp->by.Dir.parent) != ntmp);
- }
-
- /***********************************
- * Start actually doing things.... *
- ***********************************/
- getnanotime(&(fp->atime));
- /*
- * Check if just deleting a link name.
- */
- if (fvp == tvp) {
- if (fvp->v_type == VDIR) {
- error = EINVAL;
- goto abortit;
- }
-
- /* Release destination completely. */
- vput(tdvp);
- vput(tvp);
-
- /* Delete source. */
- vrele(fdvp);
- vrele(fvp);
- dev_free_name(fnp);
- return 0;
- }
-
-
- /*
- * 1) Bump link count while we're moving stuff
- * around. If we crash somewhere before
- * completing our work, too bad :)
- */
- fp->links++;
- /*
- * If the target exists zap it (unless it's a non-empty directory)
- * We could do that as well but won't
- */
- if (tp) {
- int ouruid = tcnp->cn_cred->cr_uid;
- /*
- * If the parent directory is "sticky", then the user must
- * own the parent directory, or the destination of the rename,
- * otherwise the destination may not be changed (except by
- * root). This implements append-only directories.
- * XXX shoudn't this be in generic code?
- */
- if ((tdp->mode & S_ISTXT)
- && ouruid != 0
- && ouruid != tdp->uid
- && ouruid != tp->uid ) {
- error = EPERM;
- goto bad;
- }
- /*
- * Target must be empty if a directory and have no links
- * to it. Also, ensure source and target are compatible
- * (both directories, or both not directories).
- */
- if (( doingdirectory) && (tp->links > 2)) {
- printf("nlink = %d\n",tp->links); /*XXX*/
- error = ENOTEMPTY;
- goto bad;
- }
- dev_free_name(tnp);
- tp = NULL;
- }
- dev_add_name(tcnp->cn_nameptr,tdp,fnp->as.front.realthing,fp,&tnp);
- fnp->dnp = NULL;
- fp->links--; /* one less link to it.. */
- dev_free_name(fnp);
- fp->links--; /* we added one earlier*/
- if (tdp)
- vput(tdvp);
- if (tp)
- vput(fvp);
- vrele(ap->a_fvp);
- return (error);
-
-bad:
- if (tp)
- vput(tvp);
- vput(tdvp);
-out:
- if (vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p) == 0) {
- fp->links--; /* we added one earlier*/
- vput(fvp);
- } else
- vrele(fvp);
- return (error);
-}
-
-static int
-devfs_symlink(struct vop_symlink_args *ap)
- /*struct vop_symlink_args {
- struct vnode *a_dvp;
- struct vnode **a_vpp;
- struct componentname *a_cnp;
- struct vattr *a_vap;
- char *a_target;
- } */
-{
- int error;
- dn_p dnp;
- union typeinfo by;
- devnm_p nm_p;
-
-DBPRINT(("symlink\n"));
- if((error = devfs_vntodn(ap->a_dvp, &dnp)) != 0) {
- return (error);
- }
-
- by.Slnk.name = ap->a_target;
- by.Slnk.namelen = strlen(ap->a_target);
- dev_add_entry(ap->a_cnp->cn_nameptr, dnp, DEV_SLNK, &by,
- NULL, NULL, &nm_p);
- if((error = devfs_dntovn(nm_p->dnp, ap->a_vpp)) != 0) {
- return (error);
- }
- VOP_SETATTR(*ap->a_vpp, ap->a_vap, ap->a_cnp->cn_cred,
- ap->a_cnp->cn_proc);
- return 0;
-}
-
-/*
- * Vnode op for readdir
- */
-static int
-devfs_readdir(struct vop_readdir_args *ap)
- /*struct vop_readdir_args {
- struct vnode *a_vp;
- struct uio *a_uio;
- struct ucred *a_cred;
- int *eofflag;
- int *ncookies;
- u_int **cookies;
- } */
-{
- struct vnode *vp = ap->a_vp;
- struct uio *uio = ap->a_uio;
- struct dirent dirent;
- dn_p dir_node;
- devnm_p name_node;
- char *name;
- int error = 0;
- int reclen;
- int nodenumber;
- int startpos,pos;
-
-DBPRINT(("readdir\n"));
-
-/* set up refs to dir */
- if ((error = devfs_vntodn(vp,&dir_node)) != 0)
- return error;
- if(dir_node->type != DEV_DIR)
- return(ENOTDIR);
-
- pos = 0;
- startpos = uio->uio_offset;
- name_node = dir_node->by.Dir.dirlist;
- nodenumber = 0;
- getnanotime(&(dir_node->atime));
-
- while ((name_node || (nodenumber < 2)) && (uio->uio_resid > 0))
- {
- switch(nodenumber)
- {
- case 0:
- dirent.d_fileno = (uintptr_t)(void *)dir_node;
- name = ".";
- dirent.d_namlen = 1;
- dirent.d_type = DT_DIR;
- break;
- case 1:
- if(dir_node->by.Dir.parent)
- dirent.d_fileno
- = (uintptr_t)(void *)dir_node->by.Dir.parent;
- else
- dirent.d_fileno = (uintptr_t)(void *)dir_node;
- name = "..";
- dirent.d_namlen = 2;
- dirent.d_type = DT_DIR;
- break;
- default:
- dirent.d_fileno = (uintptr_t)(void *)name_node->dnp;
- dirent.d_namlen = strlen(name_node->name);
- name = name_node->name;
- switch(name_node->dnp->type) {
- case DEV_BDEV:
- dirent.d_type = DT_BLK;
- break;
- case DEV_CDEV:
- dirent.d_type = DT_CHR;
- break;
- case DEV_DDEV:
- dirent.d_type = DT_SOCK; /*XXX*/
- break;
- case DEV_DIR:
- dirent.d_type = DT_DIR;
- break;
- case DEV_SLNK:
- dirent.d_type = DT_LNK;
- break;
- default:
- dirent.d_type = DT_UNKNOWN;
- }
- }
-
- reclen = dirent.d_reclen = GENERIC_DIRSIZ(&dirent);
-
- if(pos >= startpos) /* made it to the offset yet? */
- {
- if (uio->uio_resid < reclen) /* will it fit? */
- break;
- strcpy( dirent.d_name,name);
- if ((error = uiomove ((caddr_t)&dirent,
- dirent.d_reclen, uio)) != 0)
- break;
- }
- pos += reclen;
- if((nodenumber >1) && name_node)
- name_node = name_node->next;
- nodenumber++;
- }
- uio->uio_offset = pos;
-
- return (error);
-}
-
-
-/*
- */
-static int
-devfs_readlink(struct vop_readlink_args *ap)
- /*struct vop_readlink_args {
- struct vnode *a_vp;
- struct uio *a_uio;
- struct ucred *a_cred;
- } */
-{
- struct vnode *vp = ap->a_vp;
- struct uio *uio = ap->a_uio;
- dn_p lnk_node;
- int error = 0;
-
-
-DBPRINT(("readlink\n"));
-/* set up refs to dir */
- if ((error = devfs_vntodn(vp,&lnk_node)) != 0)
- return error;
- if(lnk_node->type != DEV_SLNK)
- return(EINVAL);
- if ((error = VOP_ACCESS(vp, VREAD, ap->a_cred, NULL)) != 0) { /* XXX */
- return error;
- }
- error = uiomove(lnk_node->by.Slnk.name, lnk_node->by.Slnk.namelen, uio);
- return error;
-}
-
-static int
-devfs_reclaim(struct vop_reclaim_args *ap)
- /*struct vop_reclaim_args {
- struct vnode *a_vp;
- } */
-{
- dn_p dnp = NULL;
- int error;
- struct vnode *vp = ap->a_vp;
-
-DBPRINT(("reclaim\n"));
- if ((error = devfs_vntodn(vp,&dnp)) != 0)
- {
- printf("devfs_vntodn returned %d ",error);
- return error;
- }
-
- vp->v_data = NULL;
- if (dnp) {
- dnp->vn = 0;
- dnp->vn_id = 0;
- }
- return(0);
-}
-
-/*
- * Print out the contents of a /devfs vnode.
- */
-static int
-devfs_print(struct vop_print_args *ap)
- /*struct vop_print_args {
- struct vnode *a_vp;
- } */
-{
-
- printf("tag VT_DEVFS, devfs vnode\n");
- return (0);
-}
-
-/**************************************************************************\
-* pseudo ops *
-\**************************************************************************/
-
-/*proto*/
-void
-devfs_dropvnode(dn_p dnp)
-{
- struct vnode *vn_p;
-
-#ifdef PARANOID
- if(!dnp)
- {
- printf("devfs: dn count dropped too early\n");
- }
-#endif
- vn_p = dnp->vn;
- /*
- * check if we have a vnode.......
- */
- if((vn_p) && ( dnp->vn_id == vn_p->v_id) && (dnp == (dn_p)vn_p->v_data))
- {
- VOP_REVOKE(vn_p, REVOKEALL);
- }
- dnp->vn = NULL; /* be pedantic about this */
-}
-
-/* struct vnode *speclisth[SPECHSZ];*/ /* till specfs goes away */
-
-/*
- * Open a special file.
- struct vop_open_args {
- struct vnode *a_vp;
- int a_mode;
- struct ucred *a_cred;
- struct proc *a_p;
- } *ap;
- */
-/* ARGSUSED */
-static int
-devfs_open( struct vop_open_args *ap)
-{
- struct proc *p = ap->a_p;
- struct vnode *vp = ap->a_vp;
- int error;
- dn_p dnp;
- struct cdevsw *dsw;
- dev_t dev = vp->v_rdev;
-
- if ((error = devfs_vntodn(vp,&dnp)) != 0)
- return error;
-
- switch (vp->v_type) {
- case VCHR:
- dsw = devsw(dev);
- if ( (dsw == NULL) || (dsw->d_open == NULL))
- return ENXIO;
- if (ap->a_cred != FSCRED && (ap->a_mode & FWRITE) &&
- vn_isdisk(vp, NULL)) {
- /*
- * When running in very secure mode, do not allow
- * opens for writing of any disk devices.
- */
- if (securelevel >= 2)
- return (EPERM);
- /*
- * When running in secure mode, do not allow opens
- * for writing if the device is mounted.
- */
- if (securelevel >= 1 && vp->v_specmountpoint != NULL)
- return (EPERM);
- }
- if ((dsw->d_flags & D_TYPEMASK) == D_TTY)
- vp->v_flag |= VISTTY;
- VOP_UNLOCK(vp, 0, p);
- error = (*vp->v_rdev->si_devsw->d_open)(
- vp->v_rdev,
- ap->a_mode,
- S_IFCHR,
- p);
- vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
- return (error);
- /* NOT REACHED */
- case VBLK:
- dsw = devsw(dev);
- if ( (dsw == NULL) || (dsw->d_open == NULL))
- return ENXIO;
- /*
- * When running in very secure mode, do not allow
- * opens for writing of any disk block devices.
- */
- if (securelevel >= 2 && ap->a_cred != FSCRED &&
- (ap->a_mode & FWRITE) &&
- (dsw->d_flags & D_TYPEMASK) == D_DISK)
- return (EPERM);
-
- /*
- * Do not allow opens of block devices that are
- * currently mounted.
- */
- error = vfs_mountedon(vp);
- if (error)
- return (error);
- error = (*vp->v_rdev->si_devsw->d_open)(
- vp->v_rdev,
- ap->a_mode,
- S_IFBLK,
- p);
- break;
- default:
- break;
- }
- return (error);
-}
-
-/* ARGSUSED */
-static int
-devfs_read( struct vop_read_args *ap)
-{
- int error;
-
- error = VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap);
- return (error);
-}
-
-/* ARGSUSED */
-static int
-devfs_write( struct vop_write_args *ap)
-{
- int error;
-
- error = VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap);
- return (error);
-}
-
-/*
- * Device ioctl operation.
- struct vop_ioctl_args {
- struct vnode *a_vp;
- int a_command;
- caddr_t a_data;
- int a_fflag;
- struct ucred *a_cred;
- struct proc *a_p;
- }
- */
-/* ARGSUSED */
-static int
-devfs_ioctl(struct vop_ioctl_args *ap)
-{
- dn_p dnp;
- int error;
- struct vnode *vp = ap->a_vp;
-
- if ((error = devfs_vntodn(vp,&dnp)) != 0)
- return error;
-
-
- switch (vp->v_type) {
-
- case VCHR:
- return ((*vp->v_rdev->si_devsw->d_ioctl)(vp->v_rdev,
- ap->a_command,
- ap->a_data,
- ap->a_fflag,
- ap->a_p));
- case VBLK:
- return ((*vp->v_rdev->si_devsw->d_ioctl)(vp->v_rdev,
- ap->a_command,
- ap->a_data,
- ap->a_fflag,
- ap->a_p));
- default:
- panic("devfs_ioctl");
- /* NOTREACHED */
- }
-}
-
-/*
- struct vop_poll_args {
- struct vnode *a_vp;
- int a_events;
- struct ucred *a_cred;
- struct proc *a_p;
- } *ap;
-*/
-/* ARGSUSED */
-static int
-devfs_poll(struct vop_poll_args *ap)
-{
- dn_p dnp;
- int error;
- struct vnode *vp = ap->a_vp;
-
- if ((error = devfs_vntodn(vp,&dnp)) != 0)
- return error;
-
-
- switch (vp->v_type) {
-
- case VCHR:
- return (*vp->v_rdev->si_devsw->d_poll)(vp->v_rdev,
- ap->a_events,
- ap->a_p);
- default:
- return (vop_defaultop((struct vop_generic_args *)ap));
-
- }
-}
-/*
- * Synch buffers associated with a block device
- struct vop_fsync_args {
- struct vnode *a_vp;
- struct ucred *a_cred;
- int a_waitfor;
- struct proc *a_p;
- }
- */
-/* ARGSUSED */
-static int
-devfs_fsync(struct vop_fsync_args *ap)
-{
- struct vnode *vp = ap->a_vp;
- struct buf *bp;
- struct buf *nbp;
- int s;
- dn_p dnp;
- int error;
-
- if ((error = devfs_vntodn(vp,&dnp)) != 0)
- return error;
-
-
- if (vp->v_type == VCHR)
- return (0);
- /*
- * Flush all dirty buffers associated with a block device.
- */
-loop:
- s = splbio();
- for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
- nbp = TAILQ_NEXT(bp, b_vnbufs);
- if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT))
- continue;
- if ((bp->b_flags & B_DELWRI) == 0)
- panic("devfs_fsync: not dirty");
- if ((vp->v_flag & VOBJBUF) && (bp->b_flags & B_CLUSTEROK)) {
- BUF_UNLOCK(bp);
- vfs_bio_awrite(bp);
- splx(s);
- } else {
- bremfree(bp);
- splx(s);
- bawrite(bp);
- }
- goto loop;
- }
- if (ap->a_waitfor == MNT_WAIT) {
- while (vp->v_numoutput) {
- vp->v_flag |= VBWAIT;
- (void) tsleep((caddr_t)&vp->v_numoutput, PRIBIO + 1, "spfsyn", 0);
- }
-#ifdef DIAGNOSTIC
- if (!TAILQ_EMPTY(&vp->v_dirtyblkhd)) {
- vprint("devfs_fsync: dirty", vp);
- splx(s);
- goto loop;
- }
-#endif
- }
- splx(s);
- return (0);
-}
-
-/*
- * Just call the device strategy routine
- struct vop_strategy_args {
- struct vnode *a_vp;
- struct bio *a_bp;
- }
- */
-static int
-devfs_strategy(struct vop_strategy_args *ap)
-{
- struct buf *bp = ap->a_bp;
- dn_p dnp;
- int error;
- struct vnode *vp = ap->a_vp;
-
- if ((vp->v_type != VCHR)
- && (vp->v_type != VBLK))
- panic ("devfs_strat:badvnode type");
- if ((error = devfs_vntodn(vp,&dnp)) != 0)
- return error;
-
-
- if ((bp->b_iocmd == BIO_WRITE) && (LIST_FIRST(&bp->b_dep)) != NULL)
- buf_start(bp);
- switch (vp->v_type) {
- case VCHR:
- (*vp->v_rdev->si_devsw->d_strategy)(&bp->b_io);
- break;
- case VBLK:
- (*vp->v_rdev->si_devsw->d_strategy)(&bp->b_io);
- break;
- default:
- /* XXX set error code? */
- break;
- }
- return (0);
-}
-
-/*
- * I can't say I'm completely sure what this one is for.
- * it's copied from specfs.
- struct vop_freeblks_args {
- struct vnode *a_vp;
- daddr_t a_addr;
- daddr_t a_length;
- };
- */
-static int
-devfs_freeblks(struct vop_freeblks_args *ap)
-{
- struct cdevsw *bsw;
- struct buf *bp;
- struct vnode *vp = ap->a_vp;
-
- bsw = devsw(vp->v_rdev);
- if ((bsw->d_flags & D_CANFREE) == 0)
- return (0);
- bp = geteblk(ap->a_length);
- bp->b_iocmd = BIO_DELETE;
- bp->b_dev = vp->v_rdev;
- bp->b_blkno = ap->a_addr;
- bp->b_offset = dbtob(ap->a_addr);
- bp->b_bcount = ap->a_length;
- DEV_STRATEGY(bp, 0);
- return (0);
-}
-
-
-/*
- * This is a noop, simply returning what one has been given.
- struct vop_bmap_args {
- struct vnode *a_vp;
- daddr_t a_bn;
- struct vnode **a_vpp;
- daddr_t *a_bnp;
- int *a_runp;
- int *a_runb;
- }
- */
-static int
-devfs_bmap(struct vop_bmap_args *ap)
-{
-
- if (ap->a_vpp != NULL)
- *ap->a_vpp = ap->a_vp;
- if (ap->a_bnp != NULL)
- *ap->a_bnp = ap->a_bn;
- if (ap->a_runp != NULL)
- *ap->a_runp = 0;
- if (ap->a_runb != NULL)
- *ap->a_runb = 0;
- return (0);
-}
-
-/*
- * Device close routine
- struct vop_close_args {
- struct vnode *a_vp;
- int a_fflag;
- struct ucred *a_cred;
- struct proc *a_p;
- }
- */
-/* ARGSUSED */
-static int
-devfs_close(struct vop_close_args *ap)
-{
- struct vnode *vp = ap->a_vp;
- dn_p dnp;
- struct cdevsw *devswp;
- dev_t dev;
- int mode, error;
-
- if ((error = devfs_vntodn(vp,&dnp)) != 0)
- return error;
-
-
- switch (vp->v_type) {
-
- case VCHR:
- devswp = vp->v_rdev->si_devsw;
- dev = vp->v_rdev;
- mode = S_IFCHR;
- /*
- * Hack: a tty device that is a controlling terminal
- * has a reference from the session structure.
- * We cannot easily tell that a character device is
- * a controlling terminal, unless it is the closing
- * process' controlling terminal. In that case,
- * if the reference count is 2 (this last descriptor
- * plus the session), release the reference from the session.
- */
- if (vcount(vp) == 2 && ap->a_p &&
- (vp->v_flag & VXLOCK) == 0 &&
- vp == ap->a_p->p_session->s_ttyvp) {
- vrele(vp);
- ap->a_p->p_session->s_ttyvp = NULL;
- }
- if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
- return (0);
-
- break;
-
- case VBLK:
- devswp = vp->v_rdev->si_devsw;
- dev = vp->v_rdev;
- mode = S_IFBLK;
- /*
- * On last close of a block device (that isn't mounted)
- * we must invalidate any in core blocks, so that
- * we can, for instance, change floppy disks.
- */
- vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, ap->a_p);
- error = vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 0, 0);
- VOP_UNLOCK(vp, 0, ap->a_p);
- if (error)
- return (error);
-
- break;
- default:
- panic("devfs_close: not special");
- }
- /*
- * If the vnode is locked, then we are in the midst
- * of forcably closing the device, otherwise we would normally
- * only close on last reference.
- * We do not want to really close the device if it
- * is still in use unless we are trying to close it
- * forcibly. Since every use (buffer, vnode, swap, cmap)
- * holds a reference to the vnode, and because we mark
- * any other vnodes that alias this device, when the
- * sum of the reference counts on all the aliased
- * vnodes descends to one, we are on last close.
- * defeat this however if the device wants to be told of every
- * close.
- */
- if ((vp->v_flag & VXLOCK)
- || (devswp->d_flags & D_TRACKCLOSE)
- || (vcount(vp) <= 1)) {
- return ((*devswp->d_close)(dev, ap->a_fflag, mode, ap->a_p));
- }
- return (0);
-}
-
-/*
- * Special device advisory byte-level locks.
- struct vop_advlock_args {
- struct vnode *a_vp;
- caddr_t a_id;
- int a_op;
- struct flock *a_fl;
- int a_flags;
- }
- */
-/* ARGSUSED */
-static int
-devfs_advlock(struct vop_advlock_args *ap)
-{
-
- return (ap->a_flags & F_FLOCK ? EOPNOTSUPP : EINVAL);
-}
-
-/*
- * Special device bad operation
- */
-static int
-devfs_badop(void)
-{
-
- panic("devfs_badop called");
- /* NOTREACHED */
-}
-
-static void
-devfs_getpages_iodone(struct buf *bp)
-{
-
- bp->b_flags |= B_DONE;
- wakeup(bp);
-}
-
-static int
-devfs_getpages(struct vop_getpages_args *ap)
-{
- vm_offset_t kva;
- int error;
- int i, pcount, size, s;
- daddr_t blkno;
- struct buf *bp;
- vm_page_t m;
- vm_ooffset_t offset;
- int toff, nextoff, nread;
- struct vnode *vp = ap->a_vp;
- int blksiz;
- int gotreqpage;
-
- error = 0;
- pcount = round_page(ap->a_count) / PAGE_SIZE;
-
- /*
- * Calculate the offset of the transfer and do sanity check.
- * FreeBSD currently only supports an 8 TB range due to b_blkno
- * being in DEV_BSIZE ( usually 512 ) byte chunks on call to
- * VOP_STRATEGY. XXX
- */
- offset = IDX_TO_OFF(ap->a_m[0]->pindex) + ap->a_offset;
-
-#define DADDR_T_BIT (sizeof(daddr_t)*8)
-#define OFFSET_MAX ((1LL << (DADDR_T_BIT + DEV_BSHIFT)) - 1)
-
- if (offset < 0 || offset > OFFSET_MAX) {
- /* XXX still no %q in kernel. */
- printf("devfs_getpages: preposterous offset 0x%x%08x\n",
- (u_int)((u_quad_t)offset >> 32),
- (u_int)(offset & 0xffffffff));
- return (VM_PAGER_ERROR);
- }
-
- blkno = btodb(offset);
-
- /*
- * Round up physical size for real devices. We cannot round using
- * v_mount's block size data because v_mount has nothing to do with
- * the device. i.e. it's usually '/dev'. We need the physical block
- * size for the device itself.
- *
- * We can't use v_specmountpoint because it only exists when the
- * block device is mounted. However, we can use v_rdev.
- */
-
- if (vp->v_type == VBLK)
- blksiz = vp->v_rdev->si_bsize_phys;
- else
- blksiz = DEV_BSIZE;
-
- size = (ap->a_count + blksiz - 1) & ~(blksiz - 1);
-
- bp = getpbuf(NULL);
- kva = (vm_offset_t)bp->b_data;
-
- /*
- * Map the pages to be read into the kva.
- */
- pmap_qenter(kva, ap->a_m, pcount);
-
- /* Build a minimal buffer header. */
- bp->b_iocmd = BIO_READ;
- bp->b_iodone = devfs_getpages_iodone;
-
- /* B_PHYS is not set, but it is nice to fill this in. */
- bp->b_rcred = bp->b_wcred = curproc->p_ucred;
- if (bp->b_rcred != NOCRED)
- crhold(bp->b_rcred);
- if (bp->b_wcred != NOCRED)
- crhold(bp->b_wcred);
- bp->b_blkno = blkno;
- bp->b_lblkno = blkno;
- pbgetvp(vp, bp);
- bp->b_bcount = size;
- bp->b_bufsize = size;
- bp->b_resid = 0;
-
- cnt.v_vnodein++;
- cnt.v_vnodepgsin += pcount;
-
- /* Do the input. */
- BUF_STRATEGY(bp);
-
- s = splbio();
-
- /* We definitely need to be at splbio here. */
- while ((bp->b_flags & B_DONE) == 0)
- tsleep(bp, PVM, "spread", 0);
-
- splx(s);
-
- if ((bp->b_ioflags & BIO_ERROR) != 0) {
- if (bp->b_error)
- error = bp->b_error;
- else
- error = EIO;
- }
-
- nread = size - bp->b_resid;
-
- if (nread < ap->a_count) {
- bzero((caddr_t)kva + nread,
- ap->a_count - nread);
- }
- pmap_qremove(kva, pcount);
-
-
- gotreqpage = 0;
- for (i = 0, toff = 0; i < pcount; i++, toff = nextoff) {
- nextoff = toff + PAGE_SIZE;
- m = ap->a_m[i];
-
- m->flags &= ~PG_ZERO;
-
- if (nextoff <= nread) {
- m->valid = VM_PAGE_BITS_ALL;
- vm_page_undirty(m);
- } else if (toff < nread) {
- /*
- * Since this is a VM request, we have to supply the
- * unaligned offset to allow vm_page_set_validclean()
- * to zero sub-DEV_BSIZE'd portions of the page.
- */
- vm_page_set_validclean(m, 0, nread - toff);
- } else {
- m->valid = 0;
- vm_page_undirty(m);
- }
-
- if (i != ap->a_reqpage) {
- /*
- * Just in case someone was asking for this page we
- * now tell them that it is ok to use.
- */
- if (!error || (m->valid == VM_PAGE_BITS_ALL)) {
- if (m->valid) {
- if (m->flags & PG_WANTED) {
- vm_page_activate(m);
- } else {
- vm_page_deactivate(m);
- }
- vm_page_wakeup(m);
- } else {
- vm_page_free(m);
- }
- } else {
- vm_page_free(m);
- }
- } else if (m->valid) {
- gotreqpage = 1;
- /*
- * Since this is a VM request, we need to make the
- * entire page presentable by zeroing invalid sections.
- */
- if (m->valid != VM_PAGE_BITS_ALL)
- vm_page_zero_invalid(m, FALSE);
- }
- }
- if (!gotreqpage) {
- m = ap->a_m[ap->a_reqpage];
- printf("devfs_getpages: I/O read failure: (error code=%d)\n",
- error);
- printf(" size: %d, resid:"
- " %ld, a_count: %d, valid: 0x%x\n",
- size, bp->b_resid, ap->a_count, m->valid);
- printf(" nread: %d, reqpage:"
- " %d, pindex: %d, pcount: %d\n",
- nread, ap->a_reqpage, m->pindex, pcount);
- /*
- * Free the buffer header back to the swap buffer pool.
- */
- relpbuf(bp, NULL);
- return VM_PAGER_ERROR;
- }
- /*
- * Free the buffer header back to the swap buffer pool.
- */
- relpbuf(bp, NULL);
- return VM_PAGER_OK;
-}
-
-
-
-/* These are the operations used by directories etc in a devfs */
-
-vop_t **devfs_vnodeop_p;
-static struct vnodeopv_entry_desc devfs_vnodeop_entries[] = {
- { &vop_default_desc, (vop_t *) vop_defaultop },
- { &vop_access_desc, (vop_t *) devfs_access },
- { &vop_bmap_desc, (vop_t *) devfs_badop },
- { &vop_getattr_desc, (vop_t *) devfs_getattr },
- { &vop_link_desc, (vop_t *) devfs_link },
- { &vop_lookup_desc, (vop_t *) devfs_lookup },
- { &vop_pathconf_desc, (vop_t *) vop_stdpathconf },
- { &vop_print_desc, (vop_t *) devfs_print },
- { &vop_read_desc, (vop_t *) devfs_xread },
- { &vop_readdir_desc, (vop_t *) devfs_readdir },
- { &vop_readlink_desc, (vop_t *) devfs_readlink },
- { &vop_reclaim_desc, (vop_t *) devfs_reclaim },
- { &vop_remove_desc, (vop_t *) devfs_remove },
- { &vop_rename_desc, (vop_t *) devfs_rename },
- { &vop_setattr_desc, (vop_t *) devfs_setattr },
- { &vop_symlink_desc, (vop_t *) devfs_symlink },
- { &vop_write_desc, (vop_t *) devfs_xwrite },
- { NULL, NULL }
-};
-static struct vnodeopv_desc devfs_vnodeop_opv_desc =
- { &devfs_vnodeop_p, devfs_vnodeop_entries };
-
-VNODEOP_SET(devfs_vnodeop_opv_desc);
-
-
-
-vop_t **devfs_spec_vnodeop_p;
-static struct vnodeopv_entry_desc devfs_spec_vnodeop_entries[] = {
- { &vop_default_desc, (vop_t *) vop_defaultop },
- { &vop_access_desc, (vop_t *) devfs_access },
- { &vop_advlock_desc, (vop_t *) devfs_advlock },
- { &vop_bmap_desc, (vop_t *) devfs_bmap },
- { &vop_close_desc, (vop_t *) devfs_close },
- { &vop_create_desc, (vop_t *) devfs_badop },
- { &vop_freeblks_desc, (vop_t *) devfs_freeblks },
- { &vop_fsync_desc, (vop_t *) devfs_fsync },
- { &vop_getattr_desc, (vop_t *) devfs_getattr },
- { &vop_getpages_desc, (vop_t *) devfs_getpages },
- { &vop_ioctl_desc, (vop_t *) devfs_ioctl },
- { &vop_lease_desc, (vop_t *) vop_null },
- { &vop_link_desc, (vop_t *) devfs_badop },
- { &vop_lookup_desc, (vop_t *) devfs_lookup },
- { &vop_mkdir_desc, (vop_t *) devfs_badop },
- { &vop_mknod_desc, (vop_t *) devfs_badop },
- { &vop_open_desc, (vop_t *) devfs_open },
- { &vop_pathconf_desc, (vop_t *) vop_stdpathconf },
- { &vop_poll_desc, (vop_t *) devfs_poll },
- { &vop_print_desc, (vop_t *) devfs_print },
- { &vop_read_desc, (vop_t *) devfs_read },
- { &vop_readdir_desc, (vop_t *) devfs_badop },
- { &vop_readlink_desc, (vop_t *) devfs_badop },
- { &vop_reallocblks_desc, (vop_t *) devfs_badop },
- { &vop_reclaim_desc, (vop_t *) devfs_reclaim },
- { &vop_remove_desc, (vop_t *) devfs_badop },
- { &vop_rename_desc, (vop_t *) devfs_badop },
- { &vop_rmdir_desc, (vop_t *) devfs_badop },
- { &vop_setattr_desc, (vop_t *) devfs_setattr },
- { &vop_strategy_desc, (vop_t *) devfs_strategy },
- { &vop_symlink_desc, (vop_t *) devfs_symlink },
- { &vop_write_desc, (vop_t *) devfs_write },
- { NULL, NULL }
-};
-static struct vnodeopv_desc devfs_spec_vnodeop_opv_desc =
- { &devfs_spec_vnodeop_p, devfs_spec_vnodeop_entries };
-
-VNODEOP_SET(devfs_spec_vnodeop_opv_desc);
-
diff --git a/sys/miscfs/devfs/devfsdefs.h b/sys/miscfs/devfs/devfsdefs.h
deleted file mode 100644
index 7df378c..0000000
--- a/sys/miscfs/devfs/devfsdefs.h
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright 1997,1998 Julian Elischer. All rights reserved.
- * julian@freebsd.org
- *
- * 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.
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``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 HOLDER OR CONTRIBUTORS 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$
- */
-#ifdef DEVFS_DEBUG
-#define DBPRINT(A) printf(A)
-#else
-#define DBPRINT(A)
-#endif
-
-/* first a couple of defines for compatibility with inodes */
-
-#define ISUID 04000 /* set user identifier when exec'ing */
-#define ISGID 02000 /* set group identifier when exec'ing */
-#define ISVTX 01000 /* save execution information on exit */
-#define IREAD 0400 /* read permission */
-#define IWRITE 0200 /* write permission */
-#define IEXEC 0100 /* execute permission */
-
-
-#define ILOCKED 0x0001 /* inode is locked */
-#define IWANT 0x0002 /* some process waiting on lock */
-#define IRENAME 0x0004 /* inode is being renamed */
-#define IUPD 0x0010 /* file has been modified */
-#define IACC 0x0020 /* inode access time to be updated */
-#define ICHG 0x0040 /* inode has been changed */
-#define IMOD 0x0080 /* inode has been modified */
-#define ISHLOCK 0x0100 /* file has shared lock */
-#define IEXLOCK 0x0200 /* file has exclusive lock */
-#define ILWAIT 0x0400 /* someone waiting on file lock */
-
-/*
- * Lock and unlock inodes.
- */
-#ifdef notdef
-#define DNLOCK(ip) { \
- while ((ip)->i_flag & ILOCKED) { \
- (ip)->i_flag |= IWANT; \
- (void) sleep((caddr_t)(ip), PINOD); \
- } \
- (ip)->i_flag |= ILOCKED; \
-}
-
-#define DNUNLOCK(ip) { \
- (ip)->i_flag &= ~ILOCKED; \
- if ((ip)->i_flag&IWANT) { \
- (ip)->i_flag &= ~IWANT; \
- wakeup((caddr_t)(ip)); \
- } \
-}
-#else
-#define DNLOCK(ip)
-#define DNUNLOCK(ip)
-#endif
-
-
-#define DEVMAXNAMESIZE 32
-#define DEVMAXPATHSIZE 128
-#define DEV_DIR 1
-#define DEV_BDEV 2
-#define DEV_CDEV 3
-#define DEV_DDEV 4
-#define DEV_ALIAS 5
-#define DEV_SLNK 6
-#define DEV_PIPE 7
-
-
-extern vop_t **devfs_vnodeop_p; /* our own vector array for dirs */
-extern vop_t **devfs_spec_vnodeop_p; /* our own vector array for devs */
-
-typedef struct dev_name *devnm_p;
-typedef struct devnode *dn_p;
-
-struct devnode /* the equivalent of an INODE */
-{
- u_short type;
- int flags; /* more inode compatible for now *//*XXXkill*/
-#define IN_ACCESS 0x0001
- u_short mode; /* basically inode compatible (drwxrwxrwx) */
- u_short uid; /* basically inode compatible */
- u_short gid; /* basically inode compatible */
- struct timespec atime; /* time of last access */
- struct timespec mtime; /* time of last modification */
- struct timespec ctime; /* time file changed */
- int links; /* how many file links does this node have? */
- struct devfsmount *dvm; /* the mount structure for this 'plane' */
- struct vnode *vn; /* address of last vnode that represented us */
- u_long vn_id; /* make sure we have the right vnode */
- int (***ops)(void *); /* yuk... pointer to pointer(s) to funcs */
- int len; /* of any associated info (e.g. dir data) */
- devnm_p linklist; /* circular list of hardlinks to this node */
- devnm_p last_lookup; /* name I was last looked up from */
- dn_p nextsibling; /* the list of equivelent nodes */
- dn_p *prevsiblingp; /* backpointer for the above */
- union typeinfo {
- struct {
- dev_t dev;
- }dev;
- struct {
- int (***ops)(void *); /* duplicate, used in dev_add_node */
- int arg;
- }Ddev;
- struct {
- devnm_p dirlist;
- devnm_p *dirlast;
- dn_p parent;
- devnm_p myname; /* my entry in .. */
- int entrycount;
- }Dir;
- struct {
- char *name; /* must be allocated separately */
- int namelen;
- }Slnk;
- struct {
- devnm_p realthing;
- devnm_p next;
- }Alias;
- struct {
- struct socket *sock;
- }Pipe;
- }by;
-};
-typedef struct devnode devnode_t;
-
-struct dev_name
-{
- /*-----------------------directory entry fields-------------*/
- char name[DEVMAXNAMESIZE];
- dn_p dnp; /* the "inode" (devnode) pointer */
- dn_p parent; /* backpointer to the directory itself */
- devnm_p next; /* next object in this directory */
- devnm_p *prevp; /* previous pointer in directory linked list */
- devnm_p nextlink; /* next hardlink to this node */
- devnm_p *prevlinkp; /* previous hardlink pointer for this node */
- /*-----------------------aliases or backing nodes----------*/
- union {
- struct {
- devnm_p aliases; /* aliase chain (kill with us)*/
- } back;
- struct {
- devnm_p realthing; /* ptr to the backing node */
- } front;
- } as;
-};
-
-typedef struct dev_name devnm_t;
-extern int devfs_up_and_going;
-extern devnm_p dev_root;
-
-
-/*
- * Rules for front nodes:
- * Dirs hava a strict 1:1 relationship with their OWN devnode
- * Symlinks similarly
- * Device Nodes ALWAYS point to the devnode that is linked
- * to the Backing node. (with a ref count)
- */
-
-/*
- * DEVFS specific per/mount information, used to link a monted fs to a
- * particular 'plane' of front nodes.
- */
-struct devfsmount
-{
- struct mount *mount; /* vfs mount struct for this fs */
- devnm_p plane_root; /* the root of this 'plane' */
- int flags; /* usefule some day 8-) */
-};
-
-struct dev_vn_data
-{
- char magic[6]; /* = "devfs" if correct */
- devnm_p front;
- devnm_p back;
-};
-
-/*
- * Prototypes for DEVFS virtual filesystem operations
- */
-#include <miscfs/devfs/devfs_proto.h>
diff --git a/sys/miscfs/devfs/reproto.sh b/sys/miscfs/devfs/reproto.sh
deleted file mode 100644
index 1b67116..0000000
--- a/sys/miscfs/devfs/reproto.sh
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/bin/sh
-#
-# This used to be a shell script, but had to become more sophisticated
-# to allow for KNF function definitions. So rewrote in perl, but wrapped
-# as a shell script.
-#
-# $FreeBSD$
-#
-exec /usr/bin/perl << *EOF*
-open(PROTO, ">devfs_proto.h") || die "Cannot open devfs_proto.h\n";
-
-print PROTO "/* \\\$FreeBSD\\\$ */\n";
-print PROTO "/* THIS FILE HAS BEEN PRODUCED AUTOMATICALLY */\n";
-
-while (\$file = <*.c>) {
- if(open(F, \$file) == 0) {
- warn "Cannot open \$file.\n";
- next;
- }
-
- while(<F>) {
- chop;
- if (m|/\*proto\*/|) {
- \$collecting = 1;
- \$idx = 0;
- } elsif (\$collecting) {
- if (/^{/) {
- \$text[\$idx - 1] .= ';';
- for (\$i = 0; \$i < \$idx; \$i++) {
- print PROTO "\$text[\$i]";
- print PROTO \$i == 0? "\t": "\n";
- }
- \$collecting = 0;
- next;
- }
- \$text[\$idx++] = \$_;
- }
- }
- close F;
-}
-
-print PROTO "/* THIS FILE PRODUCED AUTOMATICALLY */\n" .
- "/* DO NOT EDIT (see reproto.sh) */\n";
-
-*EOF*
diff --git a/sys/net/bpf.c b/sys/net/bpf.c
index 5fc8262..ecccbcf 100644
--- a/sys/net/bpf.c
+++ b/sys/net/bpf.c
@@ -41,6 +41,7 @@
*/
#include "bpf.h"
+#include "opt_devfs.h"
#ifndef __GNUC__
#define inline
@@ -78,6 +79,11 @@
#include <sys/kernel.h>
#include <sys/sysctl.h>
+#ifdef DEVFS
+#include <sys/eventhandler.h>
+#include <fs/devfs/devfs.h>
+#endif
+
MALLOC_DEFINE(M_BPF, "BPF", "BPF data");
#if NBPF > 0
@@ -1357,12 +1363,38 @@ bpfdetach(ifp)
static void bpf_drvinit __P((void *unused));
+#ifdef DEVFS
+static void bpf_clone __P((void *arg, char *name, int namelen, dev_t *dev));
+
+static void
+bpf_clone(arg, name, namelen, dev)
+ void *arg;
+ char *name;
+ int namelen;
+ dev_t *dev;
+{
+ int u;
+
+ if (*dev != NODEV)
+ return;
+ if (devfs_stdclone(name, NULL, "bpf", &u) != 1)
+ return;
+ /* XXX: minor encoding if u > 255 */
+ *dev = make_dev(&bpf_cdevsw, u, 0, 0, 0600, "bpf%d", u);
+ return;
+}
+#endif
+
static void
bpf_drvinit(unused)
void *unused;
{
+#ifdef DEVFS
+ EVENTHANDLER_REGISTER(devfs_clone, bpf_clone, 0, 1000);
+#else
cdevsw_add(&bpf_cdevsw);
+#endif
}
SYSINIT(bpfdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,bpf_drvinit,NULL)
diff --git a/sys/net/if_tun.c b/sys/net/if_tun.c
index b544f75..da865f0 100644
--- a/sys/net/if_tun.c
+++ b/sys/net/if_tun.c
@@ -17,6 +17,7 @@
*/
#include "opt_inet.h"
+#include "opt_devfs.h"
#include <sys/param.h>
#include <sys/proc.h>
@@ -50,6 +51,11 @@
#include <net/if_tunvar.h>
#include <net/if_tun.h>
+#ifdef DEVFS
+#include <sys/eventhandler.h>
+#include <fs/devfs/devfs.h>
+#endif
+
static MALLOC_DEFINE(M_TUN, "tun", "Tunnel Interface");
static void tunattach __P((void *));
@@ -91,12 +97,40 @@ static struct cdevsw tun_cdevsw = {
/* bmaj */ -1
};
+#ifdef DEVFS
+static void tun_clone __P((void *arg, char *name, int namelen, dev_t *dev));
+
+static void
+tun_clone(arg, name, namelen, dev)
+ void *arg;
+ char *name;
+ int namelen;
+ dev_t *dev;
+{
+ int u;
+
+ if (*dev != NODEV)
+ return;
+ if (devfs_stdclone(name, NULL, "tun", &u) != 1)
+ return;
+ /* XXX: minor encoding if u > 255 */
+ *dev = make_dev(&tun_cdevsw, u,
+ UID_UUCP, GID_DIALER, 0600, "tun%d", u);
+
+}
+#endif
+
+
static void
tunattach(dummy)
void *dummy;
{
+#ifdef DEVFS
+ EVENTHANDLER_REGISTER(devfs_clone, tun_clone, 0, 1000);
+#else
cdevsw_add(&tun_cdevsw);
+#endif
}
static void
diff --git a/sys/sys/conf.h b/sys/sys/conf.h
index affc646..b5d9c5a 100644
--- a/sys/sys/conf.h
+++ b/sys/sys/conf.h
@@ -1,6 +1,8 @@
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2000
+ * Poul-Henning Kamp. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
@@ -53,15 +55,19 @@ struct vnode;
struct specinfo {
u_int si_flags;
#define SI_STASHED 0x0001 /* created in stashed storage */
+#define SI_ALIAS 0x0002 /* carrier of alias name */
udev_t si_udev;
LIST_ENTRY(specinfo) si_hash;
- SLIST_HEAD(, vnode) si_hlist;
+ SLIST_HEAD(, vnode) si_hlist;
+ LIST_HEAD(, specinfo) si_names;
+ u_int si_inode;
char si_name[SPECNAMELEN + 1];
void *si_drv1, *si_drv2;
struct cdevsw *si_devsw;
- void *si_devfs; /* save cookie for devfs operations */
- void *si_bdevfs; /* XXX block device (should go away) */
int si_iosize_max; /* maximum I/O size (for physio &al) */
+ uid_t si_uid;
+ gid_t si_gid;
+ mode_t si_mode;
union {
struct {
struct tty *__sit_tty;
@@ -127,7 +133,7 @@ typedef int l_start_t __P((struct tty *tp));
typedef int l_modem_t __P((struct tty *tp, int flag));
/* This is type of the function DEVFS uses to hook into the kernel with */
-typedef void devfs_create_t __P((dev_t dev, uid_t uid, gid_t gid, int perms));
+typedef void devfs_create_t __P((dev_t dev));
typedef void devfs_remove_t __P((dev_t dev));
/*
@@ -285,6 +291,7 @@ void freedev __P((dev_t dev));
int iszerodev __P((dev_t dev));
dev_t makebdev __P((int maj, int min));
dev_t make_dev __P((struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms, char *fmt, ...)) __printflike(6, 7);
+dev_t make_dev_alias __P((dev_t pdev, char *fmt, ...)) __printflike(2, 3);
int lminor __P((dev_t dev));
void setconf __P((void));
dev_t getdiskbyname(char *name);
diff --git a/sys/sys/devfsext.h b/sys/sys/devfsext.h
deleted file mode 100644
index 478adc0..0000000
--- a/sys/sys/devfsext.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 1997,1998 Julian Elischer. All rights reserved.
- * julian@freebsd.org
- *
- * 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.
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``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 HOLDER OR CONTRIBUTORS 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 _SYS_DEVFSEXT_H_
-#define _SYS_DEVFSEXT_H_
-
-#warning "Using obsolete <sys/devfsext.h>"
-/*
- * The old DEVFS API is obsolete and should be discontinued ASAP
- * Please use the make_dev() function instead. Plenty of examples
- * to look at all over the place, contact phk@FreeBSD.org if in
- * doubt.
- */
-
-/*
- * Make a device at a path, and get a cookie for it in return.
- * Specify the type, the minor number and the devsw entry to use,
- * and the initial default perms/ownerships.
- */
-void *devfs_add_devswf __P((void *devsw, int minor, int chrblk, uid_t uid,
- gid_t gid, int perms, char *fmt, ...))
- __printflike(7, 8);
-/*
- * Make a link to a device you already made, and have the cookie for
- * We get another cookie, but for now, it can be discarded, as
- * at the moment there is nothing you can do with it that you couldn't do
- * with the original cookie. ( XXX this might be something I should change )
- */
-void *devfs_makelink __P((void *original, char *fmt, ...)) __printflike(2, 3);
-
-/*
- * Remove all instances of a device you have made. INCLUDING LINKS.
- * I.e. either the cookie from the original device or the cookie
- * from a link will have the effect of removing both entries.
- * Removing with BOTH an original cookie and one from a link is
- * likely to cause a panic.
- */
-void devfs_remove_dev __P((void *devnmp));
-
-/*
- * Check if a device exists and is the type you need. Returns NULL or a
- * cookie that can be used to try 'open' the device. XXX This is a bit
- * of a duplication of devfs_lookup(). I might one day try merge them a bit.
- * Used for mountroot under DEVFS. Path is relative to the base of the devfs.
- */
-struct vnode *devfs_open_device __P((char *path, int devtype));
-void devfs_close_device __P((struct vnode *vn));
-
-dev_t devfs_vntodev __P((struct vnode *vn)); /* extract dev_t from devfs vn */
-
-#define DV_CHR 0
-#define DV_BLK 1
-#define DV_DEV 2
-
-#endif /* !_SYS_DEVFSEXT_H_ */
diff --git a/sys/sys/kernel.h b/sys/sys/kernel.h
index ac69721..f87630d 100644
--- a/sys/sys/kernel.h
+++ b/sys/sys/kernel.h
@@ -119,7 +119,6 @@ enum sysinit_sub_id {
SI_SUB_VM_CONF = 0x2300000, /* config VM, set limits*/
SI_SUB_RUN_QUEUE = 0x2400000, /* set up run queue*/
SI_SUB_CREATE_INIT = 0x2500000, /* create init process*/
- SI_SUB_DEVFS = 0x3000000, /* get DEVFS ready */
SI_SUB_DRIVERS = 0x3100000, /* Let Drivers initialize */
SI_SUB_CONFIGURE = 0x3800000, /* Configure devices */
SI_SUB_VFS = 0x4000000, /* virtual file system*/
diff --git a/sys/sys/linedisc.h b/sys/sys/linedisc.h
index affc646..b5d9c5a 100644
--- a/sys/sys/linedisc.h
+++ b/sys/sys/linedisc.h
@@ -1,6 +1,8 @@
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2000
+ * Poul-Henning Kamp. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
@@ -53,15 +55,19 @@ struct vnode;
struct specinfo {
u_int si_flags;
#define SI_STASHED 0x0001 /* created in stashed storage */
+#define SI_ALIAS 0x0002 /* carrier of alias name */
udev_t si_udev;
LIST_ENTRY(specinfo) si_hash;
- SLIST_HEAD(, vnode) si_hlist;
+ SLIST_HEAD(, vnode) si_hlist;
+ LIST_HEAD(, specinfo) si_names;
+ u_int si_inode;
char si_name[SPECNAMELEN + 1];
void *si_drv1, *si_drv2;
struct cdevsw *si_devsw;
- void *si_devfs; /* save cookie for devfs operations */
- void *si_bdevfs; /* XXX block device (should go away) */
int si_iosize_max; /* maximum I/O size (for physio &al) */
+ uid_t si_uid;
+ gid_t si_gid;
+ mode_t si_mode;
union {
struct {
struct tty *__sit_tty;
@@ -127,7 +133,7 @@ typedef int l_start_t __P((struct tty *tp));
typedef int l_modem_t __P((struct tty *tp, int flag));
/* This is type of the function DEVFS uses to hook into the kernel with */
-typedef void devfs_create_t __P((dev_t dev, uid_t uid, gid_t gid, int perms));
+typedef void devfs_create_t __P((dev_t dev));
typedef void devfs_remove_t __P((dev_t dev));
/*
@@ -285,6 +291,7 @@ void freedev __P((dev_t dev));
int iszerodev __P((dev_t dev));
dev_t makebdev __P((int maj, int min));
dev_t make_dev __P((struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms, char *fmt, ...)) __printflike(6, 7);
+dev_t make_dev_alias __P((dev_t pdev, char *fmt, ...)) __printflike(2, 3);
int lminor __P((dev_t dev));
void setconf __P((void));
dev_t getdiskbyname(char *name);
diff --git a/sys/ufs/mfs/mfs_vfsops.c b/sys/ufs/mfs/mfs_vfsops.c
index 429f029..fb15f4d 100644
--- a/sys/ufs/mfs/mfs_vfsops.c
+++ b/sys/ufs/mfs/mfs_vfsops.c
@@ -244,7 +244,8 @@ mfs_mount(mp, path, data, ndp, p)
goto error_1;
}
devvp->v_type = VCHR;
- dev = make_dev(&mfs_cdevsw, mfs_minor, 0, 0, 0, "MFS%d", mfs_minor);
+ dev = makedev(mfs_cdevsw.d_maj, mfs_minor);
+ dev->si_devsw = &mfs_cdevsw;
/* It is not clear that these will get initialized otherwise */
dev->si_bsize_phys = DEV_BSIZE;
dev->si_iosize_max = DFLTPHYS;
OpenPOWER on IntegriCloud