devfs - Fix FREEBLKS
authorAlex Hornung <ahornung@gmail.com>
Fri, 19 Nov 2010 14:49:17 +0000 (14:49 +0000)
committerAlex Hornung <ahornung@gmail.com>
Fri, 19 Nov 2010 15:09:49 +0000 (15:09 +0000)
* Since vn and md were changed to use the disk subsystem they
  essentially haven't been able to receive any BUF_CMD_FREEBLKS since
  their D_CANFREE flag was not propagated through the disk subsystem.

* Fix this by making the flag specific to the device via SI_CANFREE and
  propagating the D_CANFREE of even *underlying*/covered devices to the
  top-level device's SI_CANFREE.

sys/sys/conf.h
sys/vfs/devfs/devfs_core.c
sys/vfs/devfs/devfs_vnops.c

index b437f7e..444d4d0 100644 (file)
@@ -114,6 +114,7 @@ struct cdev {
 #define SI_INTERCEPTED 0x0008  /* device ops was intercepted */
 #define SI_DEVFS_LINKED        0x0010
 #define        SI_REPROBE_TEST 0x0020
+#define SI_CANFREE     0x0040  /* basically just a propagated D_CANFREE */
 
 #define si_tty         __si_u.__si_tty.__sit_tty
 #define si_disk                __si_u.__si_disk.__sid_disk
index eaa1dba..1779750 100644 (file)
@@ -2228,6 +2228,18 @@ devfs_new_cdev(struct dev_ops *ops, int minor, struct dev_ops *bops)
        dev->si_umajor = 0;
        dev->si_uminor = minor;
        dev->si_bops = bops;
+
+       /*
+        * Since the disk subsystem is in the way, we need to
+        * propagate the D_CANFREE from bops (and ops) to
+        * si_flags.
+        */
+       if (bops && (bops->head.flags & D_CANFREE)) {
+               dev->si_flags |= SI_CANFREE;
+       } else if (ops->head.flags & D_CANFREE) {
+               dev->si_flags |= SI_CANFREE;
+       }
+
        /* If there is a backing device, we reference its ops */
        dev->si_inode = makeudev(
                    devfs_reference_ops((bops)?(bops):(ops)),
index 013e06f..c88cef2 100644 (file)
@@ -1843,7 +1843,7 @@ devfs_spec_freeblks(struct vop_freeblks_args *ap)
         * XXX: this may not be TRTTD.
         */
        KKASSERT(ap->a_vp->v_rdev != NULL);
-       if ((dev_dflags(ap->a_vp->v_rdev) & D_CANFREE) == 0)
+       if ((ap->a_vp->v_rdev->si_flags & SI_CANFREE) == 0)
                return (0);
        bp = geteblk(ap->a_length);
        bp->b_cmd = BUF_CMD_FREEBLKS;