dsched_fq - properly drain all queues on teardown
authorAlex Hornung <ahornung@gmail.com>
Wed, 31 Mar 2010 10:19:38 +0000 (10:19 +0000)
committerAlex Hornung <ahornung@gmail.com>
Thu, 15 Apr 2010 20:24:48 +0000 (20:24 +0000)
* Properly drain all fqp queues on teardown to ensure that no bios and
  especially fqps are left dangling around.

* This should fix the occasional panic during policy switches.

sys/dsched/fq/dsched_fq_core.c
sys/dsched/fq/dsched_fq_diskops.c

index d490af7..1425202 100644 (file)
@@ -368,7 +368,25 @@ fq_dispatcher(struct dsched_fq_dpriv *dpriv)
                         * supposed to die away nicely or that the disk is idle.
                         */
 
-                       if (dpriv->die == 1) {
+                       if (__predict_false(dpriv->die == 1)) {
+                               /* If we are supposed to die, drain all queues */
+                               TAILQ_FOREACH_MUTABLE(fqp, &dpriv->fq_priv_list,
+                                   dlink, fqp2) {
+                                       if (fqp->qlength == 0)
+                                               continue;
+
+                                       FQ_FQP_LOCK(fqp);
+                                       TAILQ_FOREACH_MUTABLE(bio, &fqp->queue,
+                                           link, bio2) {
+                                               TAILQ_REMOVE(&fqp->queue, bio,
+                                                   link);
+                                               --fqp->qlength;
+                                               fq_dispatch(dpriv, bio, fqp);
+                                       }
+                                       FQ_FQP_UNLOCK(fqp);
+                               }
+
+                               /* Now we can safely unlock and exit */
                                FQ_DPRIV_UNLOCK(dpriv);
                                kprintf("fq_dispatcher is peacefully dying\n");
                                lwkt_exit();
@@ -404,7 +422,6 @@ fq_dispatcher(struct dsched_fq_dpriv *dpriv)
                        if ((fqp->max_tp > 0) && idle &&
                            (fqp->issued >= fqp->max_tp)) {
                                fqp->max_tp += 5;
-                               ++fqp->idle_generation;
                        }
 
                        TAILQ_FOREACH_MUTABLE(bio, &fqp->queue, link, bio2) {
index 44edcfe..ef2badc 100644 (file)
@@ -163,7 +163,7 @@ fq_teardown(struct disk *dp)
         *      but how do we get rid of all loose fqps?
         *    --> possibly same solution as devfs; tracking a list of
         *        orphans.
-        *    but for now we don't care much about this yet
+        * XXX XXX: this XXX is probably irrelevant by now :)
         */
 }
 
@@ -192,16 +192,17 @@ fq_cancel(struct disk *dp)
         */
        FQ_DPRIV_LOCK(dpriv);
        TAILQ_FOREACH_MUTABLE(fqp, &dpriv->fq_priv_list, dlink, fqp2) {
-               if (fqp->qlength > 0) {
-                       FQ_FQP_LOCK(fqp);
-                       TAILQ_FOREACH_MUTABLE(bio, &fqp->queue, link, bio2) {
-                               TAILQ_REMOVE(&fqp->queue, bio, link);
-                               --fqp->qlength;
-                               dsched_cancel_bio(bio);
-                               atomic_add_int(&fq_stats.cancelled, 1);
-                       }
-                       FQ_FQP_UNLOCK(fqp);
+               if (fqp->qlength == 0)
+                       continue;
+
+               FQ_FQP_LOCK(fqp);
+               TAILQ_FOREACH_MUTABLE(bio, &fqp->queue, link, bio2) {
+                       TAILQ_REMOVE(&fqp->queue, bio, link);
+                       --fqp->qlength;
+                       dsched_cancel_bio(bio);
+                       atomic_add_int(&fq_stats.cancelled, 1);
                }
+               FQ_FQP_UNLOCK(fqp);
        }
        FQ_DPRIV_UNLOCK(dpriv);
 }