blkio: Drop the reference to queue once the task changes cgroup
authorVivek Goyal <vgoyal@redhat.com>
Thu, 3 Dec 2009 17:59:51 +0000 (12:59 -0500)
committerJens Axboe <jens.axboe@oracle.com>
Thu, 3 Dec 2009 18:28:52 +0000 (19:28 +0100)
o If a task changes cgroup, drop reference to the cfqq associated with io
  context and set cfqq pointer stored in ioc to NULL so that upon next request
  arrival we will allocate a  new queue in new group.

Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
block/cfq-iosched.c

index 3a62ce95daec353a89babc11fb19805f886aef5c..3d99e45789bd0176e0af0ee85223ed5a2c04934a 100644 (file)
@@ -2608,6 +2608,41 @@ static void cfq_init_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq,
        cfqq->pid = pid;
 }
 
+#ifdef CONFIG_CFQ_GROUP_IOSCHED
+static void changed_cgroup(struct io_context *ioc, struct cfq_io_context *cic)
+{
+       struct cfq_queue *sync_cfqq = cic_to_cfqq(cic, 1);
+       struct cfq_data *cfqd = cic->key;
+       unsigned long flags;
+       struct request_queue *q;
+
+       if (unlikely(!cfqd))
+               return;
+
+       q = cfqd->queue;
+
+       spin_lock_irqsave(q->queue_lock, flags);
+
+       if (sync_cfqq) {
+               /*
+                * Drop reference to sync queue. A new sync queue will be
+                * assigned in new group upon arrival of a fresh request.
+                */
+               cfq_log_cfqq(cfqd, sync_cfqq, "changed cgroup");
+               cic_set_cfqq(cic, NULL, 1);
+               cfq_put_queue(sync_cfqq);
+       }
+
+       spin_unlock_irqrestore(q->queue_lock, flags);
+}
+
+static void cfq_ioc_set_cgroup(struct io_context *ioc)
+{
+       call_for_each_cic(ioc, changed_cgroup);
+       ioc->cgroup_changed = 0;
+}
+#endif  /* CONFIG_CFQ_GROUP_IOSCHED */
+
 static struct cfq_queue *
 cfq_find_alloc_queue(struct cfq_data *cfqd, bool is_sync,
                     struct io_context *ioc, gfp_t gfp_mask)
@@ -2840,6 +2875,10 @@ out:
        if (unlikely(ioc->ioprio_changed))
                cfq_ioc_set_ioprio(ioc);
 
+#ifdef CONFIG_CFQ_GROUP_IOSCHED
+       if (unlikely(ioc->cgroup_changed))
+               cfq_ioc_set_cgroup(ioc);
+#endif
        return cic;
 err_free:
        cfq_cic_free(cic);