blkcg: shoot down blkio_groups on elevator switch
Elevator switch may involve changes to blkcg policies. Implement
shoot down of blkio_groups.
Combined with the previous bypass updates, the end goal is updating
blkcg core such that it can ensure that blkcg's being affected become
quiescent and don't have any per-blkg data hanging around before
commencing any policy updates. Until queues are made aware of the
policies that applies to them, as an interim step, all per-policy blkg
data will be shot down.
* blk-throtl doesn't need this change as it can't be disabled for a
live queue; however, update it anyway as the scheduled blkg
unification requires this behavior change. This means that
blk-throtl configuration will be unnecessarily lost over elevator
switch. This oddity will be removed after blkcg learns to associate
individual policies with request_queues.
* blk-throtl dosen't shoot down root_tg. This is to ease transition.
Unified blkg will always have persistent root group and not shooting
down root_tg for now eases transition to that point by avoiding
having to update td->root_tg and is safe as blk-throtl can never be
disabled
-v2: Vivek pointed out that group list is not guaranteed to be empty
on return from clear function if it raced cgroup removal and
lost. Fix it by waiting a bit and retrying. This kludge will
soon be removed once locking is updated such that blkg is never
in limbo state between blkcg and request_queue locks.
blk-throtl no longer shoots down root_tg to avoid breaking
td->root_tg.
Also, Nest queue_lock inside blkio_list_lock not the other way
around to avoid introduce possible deadlock via blkcg lock.
-v3: blkcg_clear_queue() repositioned and renamed to
blkg_destroy_all() to increase consistency with later changes.
cfq_clear_queue() updated to check q->elevator before
dereferencing it to avoid NULL dereference on not fully
initialized queues (used by later change).
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Vivek Goyal <vgoyal@redhat.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index 970a717..159aef5 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -17,8 +17,9 @@
#include <linux/err.h>
#include <linux/blkdev.h>
#include <linux/slab.h>
-#include "blk-cgroup.h"
#include <linux/genhd.h>
+#include <linux/delay.h>
+#include "blk-cgroup.h"
#define MAX_KEY_LEN 100
@@ -546,6 +547,37 @@
}
EXPORT_SYMBOL_GPL(blkiocg_lookup_group);
+void blkg_destroy_all(struct request_queue *q)
+{
+ struct blkio_policy_type *pol;
+
+ while (true) {
+ bool done = true;
+
+ spin_lock(&blkio_list_lock);
+ spin_lock_irq(q->queue_lock);
+
+ /*
+ * clear_queue_fn() might return with non-empty group list
+ * if it raced cgroup removal and lost. cgroup removal is
+ * guaranteed to make forward progress and retrying after a
+ * while is enough. This ugliness is scheduled to be
+ * removed after locking update.
+ */
+ list_for_each_entry(pol, &blkio_list, list)
+ if (!pol->ops.blkio_clear_queue_fn(q))
+ done = false;
+
+ spin_unlock_irq(q->queue_lock);
+ spin_unlock(&blkio_list_lock);
+
+ if (done)
+ break;
+
+ msleep(10); /* just some random duration I like */
+ }
+}
+
static void blkio_reset_stats_cpu(struct blkio_group *blkg)
{
struct blkio_group_stats_cpu *stats_cpu;