summaryrefslogtreecommitdiffstats
path: root/sys/fs/devfs
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>2005-03-10 18:21:34 +0000
committerphk <phk@FreeBSD.org>2005-03-10 18:21:34 +0000
commit75bcf4d381dea96e2c41fb2edafacd6e06dd1f43 (patch)
treef972184c76526c477d18e70db28e2908e1edd6f5 /sys/fs/devfs
parentd0ffad32b585c4e46b0814f34d9469d7bbb374b3 (diff)
downloadFreeBSD-src-75bcf4d381dea96e2c41fb2edafacd6e06dd1f43.zip
FreeBSD-src-75bcf4d381dea96e2c41fb2edafacd6e06dd1f43.tar.gz
Try to fix the mess I made of devname, with the minimal subset of the
larger minor/major patch which was posted for testing.
Diffstat (limited to 'sys/fs/devfs')
-rw-r--r--sys/fs/devfs/devfs_devs.c9
-rw-r--r--sys/fs/devfs/devfs_vnops.c60
2 files changed, 64 insertions, 5 deletions
diff --git a/sys/fs/devfs/devfs_devs.c b/sys/fs/devfs/devfs_devs.c
index e9c2a55..761caa5 100644
--- a/sys/fs/devfs/devfs_devs.c
+++ b/sys/fs/devfs/devfs_devs.c
@@ -114,6 +114,8 @@ struct devfs_dirent **
devfs_itode (struct devfs_mount *dm, int inode)
{
+ if (inode < 0)
+ return (NULL);
if (inode < NDEVFSINO)
return (&dm->dm_dirent[inode]);
if (devfs_overflow == NULL)
@@ -127,6 +129,8 @@ struct cdev **
devfs_itod (int inode)
{
+ if (inode < 0)
+ return (NULL);
if (inode < NDEVFSINO)
return (&devfs_inot[inode]);
if (devfs_overflow == NULL)
@@ -270,10 +274,7 @@ devfs_populate(struct devfs_mount *dm)
if (dev == NULL && de != NULL) {
dd = de->de_dir;
*dep = NULL;
- TAILQ_REMOVE(&dd->de_dlist, de, de_list);
- if (de->de_vnode)
- de->de_vnode->v_data = NULL;
- FREE(de, M_DEVFS);
+ devfs_delete(dd, de);
devfs_dropref(i);
continue;
}
diff --git a/sys/fs/devfs/devfs_vnops.c b/sys/fs/devfs/devfs_vnops.c
index 09a978a..dbce518 100644
--- a/sys/fs/devfs/devfs_vnops.c
+++ b/sys/fs/devfs/devfs_vnops.c
@@ -61,6 +61,7 @@
#include <sys/proc.h>
#include <sys/stat.h>
#include <sys/sx.h>
+#include <sys/sysctl.h>
#include <sys/time.h>
#include <sys/ttycom.h>
#include <sys/unistd.h>
@@ -113,6 +114,25 @@ static vop_symlink_t devfs_symlink;
extern struct vop_vector devfs_vnodeops;
extern struct vop_vector devfs_specops;
+static u_int
+devfs_random(void)
+{
+ static u_int devfs_seed;
+
+ while (devfs_seed == 0) {
+ /*
+ * Make sure people don't make stupid assumptions
+ * about device major/minor numbers in userspace.
+ * We do this late to get entropy and for the same
+ * reason we force a reseed, but it may not be
+ * late enough for entropy to be available.
+ */
+ arc4rand(&devfs_seed, sizeof devfs_seed, 1);
+ devfs_seed &= 0xf0f;
+ }
+ return (devfs_seed);
+}
+
static int
devfs_fp_check(struct file *fp, struct cdev **devp, struct cdevsw **dswp)
{
@@ -441,7 +461,8 @@ devfs_getattr(ap)
vap->va_mtime = dev->si_mtime;
fix(dev->si_ctime);
vap->va_ctime = dev->si_ctime;
- vap->va_rdev = dev->si_udev;
+
+ vap->va_rdev = de->de_inode ^ devfs_random();
}
vap->va_gen = 0;
vap->va_flags = 0;
@@ -1432,6 +1453,43 @@ static struct vop_vector devfs_specops = {
.vop_write = VOP_PANIC,
};
+dev_t
+dev2udev(struct cdev *x)
+{
+ if (x == NULL)
+ return (NODEV);
+ return (x->si_inode ^ devfs_random());
+}
+
+/*
+ * Helper sysctl for devname(3). We're given a struct cdev * and return
+ * the name, if any, registered by the device driver.
+ */
+static int
+sysctl_devname(SYSCTL_HANDLER_ARGS)
+{
+ int error;
+ dev_t ud;
+ struct cdev *dev, **dp;
+
+ error = SYSCTL_IN(req, &ud, sizeof (ud));
+ if (error)
+ return (error);
+ if (ud == NODEV)
+ return(EINVAL);
+ dp = devfs_itod(ud ^ devfs_random());
+ if (dp == NULL)
+ return(ENOENT);
+ dev = *dp;
+ if (dev == NULL)
+ return(ENOENT);
+ return(SYSCTL_OUT(req, dev->si_name, strlen(dev->si_name) + 1));
+ return (error);
+}
+
+SYSCTL_PROC(_kern, OID_AUTO, devname, CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_ANYBODY,
+ NULL, 0, sysctl_devname, "", "devname(3) handler");
+
/*
* Our calling convention to the device drivers used to be that we passed
* vnode.h IO_* flags to read()/write(), but we're moving to fcntl.h O_
OpenPOWER on IntegriCloud