diff options
author | phk <phk@FreeBSD.org> | 2000-08-20 21:34:39 +0000 |
---|---|---|
committer | phk <phk@FreeBSD.org> | 2000-08-20 21:34:39 +0000 |
commit | b648921accec69a7e5c83e915ded3037cbca7f3d (patch) | |
tree | fa2e43c05e3c1d31732408f806d72db091c03d14 | |
parent | 1c624ac57c791b6df4b51eb86e04dc404052c700 (diff) | |
download | FreeBSD-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
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; |