|
@@ -0,0 +1,129 @@
|
|
|
+/*
|
|
|
+ * Common Block IO controller cgroup interface
|
|
|
+ *
|
|
|
+ * Based on ideas and code from CFQ, CFS and BFQ:
|
|
|
+ * Copyright (C) 2003 Jens Axboe <axboe@kernel.dk>
|
|
|
+ *
|
|
|
+ * Copyright (C) 2008 Fabio Checconi <fabio@gandalf.sssup.it>
|
|
|
+ * Paolo Valente <paolo.valente@unimore.it>
|
|
|
+ *
|
|
|
+ * Copyright (C) 2009 Vivek Goyal <vgoyal@redhat.com>
|
|
|
+ * Nauman Rafique <nauman@google.com>
|
|
|
+ */
|
|
|
+#include <linux/ioprio.h>
|
|
|
+#include <linux/kdev_t.h>
|
|
|
+#include <linux/module.h>
|
|
|
+#include <linux/err.h>
|
|
|
+#include <linux/blkdev.h>
|
|
|
+#include <linux/slab.h>
|
|
|
+#include <linux/genhd.h>
|
|
|
+#include <linux/delay.h>
|
|
|
+#include <linux/atomic.h>
|
|
|
+#include "blk-cgroup.h"
|
|
|
+#include "blk.h"
|
|
|
+
|
|
|
+#define MAX_KEY_LEN 100
|
|
|
+
|
|
|
+static DEFINE_MUTEX(blkcg_pol_mutex);
|
|
|
+
|
|
|
+struct blkcg blkcg_root = { .cfq_weight = 2 * CFQ_WEIGHT_DEFAULT };
|
|
|
+EXPORT_SYMBOL_GPL(blkcg_root);
|
|
|
+
|
|
|
+static struct blkcg_policy *blkcg_policy[BLKCG_MAX_POLS];
|
|
|
+
|
|
|
+static bool blkcg_policy_enabled(struct request_queue *q,
|
|
|
+ const struct blkcg_policy *pol)
|
|
|
+{
|
|
|
+ return pol && test_bit(pol->plid, q->blkcg_pols);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * blkg_free - free a blkg
|
|
|
+ * @blkg: blkg to free
|
|
|
+ *
|
|
|
+ * Free @blkg which may be partially allocated.
|
|
|
+ */
|
|
|
+static void blkg_free(struct blkcg_gq *blkg)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ if (!blkg)
|
|
|
+ return;
|
|
|
+
|
|
|
+ for (i = 0; i < BLKCG_MAX_POLS; i++) {
|
|
|
+ struct blkcg_policy *pol = blkcg_policy[i];
|
|
|
+ struct blkg_policy_data *pd = blkg->pd[i];
|
|
|
+
|
|
|
+ if (!pd)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if (pol && pol->pd_exit_fn)
|
|
|
+ pol->pd_exit_fn(blkg);
|
|
|
+
|
|
|
+ kfree(pd);
|
|
|
+ }
|
|
|
+
|
|
|
+ blk_exit_rl(&blkg->rl);
|
|
|
+ kfree(blkg);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * blkg_alloc - allocate a blkg
|
|
|
+ * @blkcg: block cgroup the new blkg is associated with
|
|
|
+ * @q: request_queue the new blkg is associated with
|
|
|
+ * @gfp_mask: allocation mask to use
|
|
|
+ *
|
|
|
+ * Allocate a new blkg assocating @blkcg and @q.
|
|
|
+ */
|
|
|
+static struct blkcg_gq *blkg_alloc(struct blkcg *blkcg, struct request_queue *q,
|
|
|
+ gfp_t gfp_mask)
|
|
|
+{
|
|
|
+ struct blkcg_gq *blkg;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ /* alloc and init base part */
|
|
|
+ blkg = kzalloc_node(sizeof(*blkg), gfp_mask, q->node);
|
|
|
+ if (!blkg)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ blkg->q = q;
|
|
|
+ INIT_LIST_HEAD(&blkg->q_node);
|
|
|
+ blkg->blkcg = blkcg;
|
|
|
+ blkg->refcnt = 1;
|
|
|
+
|
|
|
+ /* root blkg uses @q->root_rl, init rl only for !root blkgs */
|
|
|
+ if (blkcg != &blkcg_root) {
|
|
|
+ if (blk_init_rl(&blkg->rl, q, gfp_mask))
|
|
|
+ goto err_free;
|
|
|
+ blkg->rl.blkg = blkg;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = 0; i < BLKCG_MAX_POLS; i++) {
|
|
|
+ struct blkcg_policy *pol = blkcg_policy[i];
|
|
|
+ struct blkg_policy_data *pd;
|
|
|
+
|
|
|
+ if (!blkcg_policy_enabled(q, pol))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ /* alloc per-policy data and attach it to blkg */
|
|
|
+ pd = kzalloc_node(pol->pd_size, gfp_mask, q->node);
|
|
|
+ if (!pd)
|
|
|
+ goto err_free;
|
|
|
+
|
|
|
+ blkg->pd[i] = pd;
|
|
|
+ pd->blkg = blkg;
|
|
|
+
|
|
|
+ /* invoke per-policy init */
|
|
|
+ if (blkcg_policy_enabled(blkg->q, pol))
|
|
|
+ pol->pd_init_fn(blkg);
|
|
|
+ }
|
|
|
+
|
|
|
+ return blkg;
|
|
|
+
|
|
|
+err_free:
|
|
|
+ blkg_free(blkg);
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+static struct blkcg_gq *__blkg_lookup(struct blkcg *blkcg,
|
|
|
+ struct request_queue *q)
|