diff options
author | phk <phk@FreeBSD.org> | 2005-03-10 18:21:34 +0000 |
---|---|---|
committer | phk <phk@FreeBSD.org> | 2005-03-10 18:21:34 +0000 |
commit | 75bcf4d381dea96e2c41fb2edafacd6e06dd1f43 (patch) | |
tree | f972184c76526c477d18e70db28e2908e1edd6f5 /sys/fs/devfs | |
parent | d0ffad32b585c4e46b0814f34d9469d7bbb374b3 (diff) | |
download | FreeBSD-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.c | 9 | ||||
-rw-r--r-- | sys/fs/devfs/devfs_vnops.c | 60 |
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_ |