Follow up to kern_conf.c 1.16. We can't just ignore the ops comparison, it
authorMatthew Dillon <dillon@dragonflybsd.org>
Tue, 26 Sep 2006 18:57:14 +0000 (18:57 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Tue, 26 Sep 2006 18:57:14 +0000 (18:57 +0000)
is needed to keep user-invisible devices user-invisible.  Add a flag so
hashdev() knows when it can ignore the comparison and when it can't ignore
the comparison.

sys/kern/kern_conf.c
sys/kern/kern_device.c
sys/sys/conf.h

index 5c5dce0..9fa02fe 100644 (file)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/kern/kern_conf.c,v 1.73.2.3 2003/03/10 02:18:25 imp Exp $
- * $DragonFly: src/sys/kern/kern_conf.c,v 1.16 2006/09/26 18:15:28 dillon Exp $
+ * $DragonFly: src/sys/kern/kern_conf.c,v 1.17 2006/09/26 18:57:13 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -111,10 +111,18 @@ lminor(cdev_t x)
  * set the device will be referenced (once) and SI_ADHOC will be set.
  * The caller must explicitly add additional references to the device if
  * the caller wishes to track additional references.
+ *
+ * NOTE: The passed ops vector must normally match the device.  This is
+ * because the kernel may create shadow devices that are INVISIBLE TO
+ * USERLAND.  For example, the block device backing a disk is created
+ * as a shadow underneath the user-visible disklabel management device.
+ * Sometimes a device ops vector can be overridden, such as by /dev/console.
+ * In this case and this case only we allow a match when the ops vector
+ * otherwise would not match.
  */
 static
 cdev_t
-hashdev(struct dev_ops *ops, int x, int y, int allow_override)
+hashdev(struct dev_ops *ops, int x, int y, int allow_intercept)
 {
        struct cdev *si;
        udev_t  udev;
@@ -124,9 +132,11 @@ hashdev(struct dev_ops *ops, int x, int y, int allow_override)
        udev = makeudev(x, y);
        hash = udev % DEVT_HASH;
        LIST_FOREACH(si, &dev_hash[hash], si_hash) {
-               if (si->si_udev == udev &&
-                   (allow_override || si->si_ops == ops)) {
-                       return (si);
+               if (si->si_udev == udev) {
+                       if (si->si_ops == ops)
+                               return (si);
+                       if (allow_intercept && (si->si_flags & SI_INTERCEPTED))
+                               return (si);
                }
        }
        if (stashed >= DEVT_STASH) {
index f8b0076..a4c2584 100644 (file)
@@ -27,7 +27,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $DragonFly: src/sys/kern/kern_device.c,v 1.20 2006/09/10 01:26:39 dillon Exp $
+ * $DragonFly: src/sys/kern/kern_device.c,v 1.21 2006/09/26 18:57:13 dillon Exp $
  */
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -567,6 +567,7 @@ dev_ops_intercept(cdev_t dev, struct dev_ops *iops)
        iops->head.data = oops->head.data;
        iops->head.flags = oops->head.flags;
        dev->si_ops = iops;
+       dev->si_flags |= SI_INTERCEPTED;
 
        return (oops);
 }
@@ -577,6 +578,7 @@ dev_ops_restore(cdev_t dev, struct dev_ops *oops)
        struct dev_ops *iops = dev->si_ops;
 
        dev->si_ops = oops;
+       dev->si_flags &= ~SI_INTERCEPTED;
        iops->head.maj = 0;
        iops->head.data = NULL;
        iops->head.flags = 0;
index 980c1f9..0ff4fdb 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)conf.h      8.5 (Berkeley) 1/9/95
  * $FreeBSD: src/sys/sys/conf.h,v 1.103.2.6 2002/03/11 01:14:55 dd Exp $
- * $DragonFly: src/sys/sys/conf.h,v 1.14 2006/09/10 01:26:40 dillon Exp $
+ * $DragonFly: src/sys/sys/conf.h,v 1.15 2006/09/26 18:57:14 dillon Exp $
  */
 
 #ifndef _SYS_CONF_H_
@@ -85,6 +85,7 @@ struct cdev {
 #define SI_STASHED     0x0001  /* created in stashed storage */
 #define SI_HASHED      0x0002  /* in (maj,min) hash table */
 #define SI_ADHOC       0x0004  /* created via make_adhoc_dev() or udev2dev() */
+#define SI_INTERCEPTED 0x0008  /* device ops was intercepted */
 
 #define si_tty         __si_u.__si_tty.__sit_tty
 #define si_disk                __si_u.__si_disk.__sid_disk