Merge branch 'work.namei' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[linux-2.6-block.git] / block / blk-cgroup.c
index 55a7dc227dfbd6af883a2832d09c8abf2c16d3d0..b6f20be0fc78c16a2984294386a25b2893f677fc 100644 (file)
@@ -175,7 +175,7 @@ static struct blkcg_gq *blkg_alloc(struct blkcg *blkcg, struct request_queue *q,
                        continue;
 
                /* alloc per-policy data and attach it to blkg */
-               pd = pol->pd_alloc_fn(gfp_mask, q->node);
+               pd = pol->pd_alloc_fn(gfp_mask, q, blkcg);
                if (!pd)
                        goto err_free;
 
@@ -753,6 +753,44 @@ static struct blkcg_gq *blkg_lookup_check(struct blkcg *blkcg,
        return __blkg_lookup(blkcg, q, true /* update_hint */);
 }
 
+/**
+ * blkg_conf_prep - parse and prepare for per-blkg config update
+ * @inputp: input string pointer
+ *
+ * Parse the device node prefix part, MAJ:MIN, of per-blkg config update
+ * from @input and get and return the matching gendisk.  *@inputp is
+ * updated to point past the device node prefix.  Returns an ERR_PTR()
+ * value on error.
+ *
+ * Use this function iff blkg_conf_prep() can't be used for some reason.
+ */
+struct gendisk *blkcg_conf_get_disk(char **inputp)
+{
+       char *input = *inputp;
+       unsigned int major, minor;
+       struct gendisk *disk;
+       int key_len, part;
+
+       if (sscanf(input, "%u:%u%n", &major, &minor, &key_len) != 2)
+               return ERR_PTR(-EINVAL);
+
+       input += key_len;
+       if (!isspace(*input))
+               return ERR_PTR(-EINVAL);
+       input = skip_spaces(input);
+
+       disk = get_gendisk(MKDEV(major, minor), &part);
+       if (!disk)
+               return ERR_PTR(-ENODEV);
+       if (part) {
+               put_disk_and_module(disk);
+               return ERR_PTR(-ENODEV);
+       }
+
+       *inputp = input;
+       return disk;
+}
+
 /**
  * blkg_conf_prep - parse and prepare for per-blkg config update
  * @blkcg: target block cgroup
@@ -772,25 +810,11 @@ int blkg_conf_prep(struct blkcg *blkcg, const struct blkcg_policy *pol,
        struct gendisk *disk;
        struct request_queue *q;
        struct blkcg_gq *blkg;
-       unsigned int major, minor;
-       int key_len, part, ret;
-       char *body;
-
-       if (sscanf(input, "%u:%u%n", &major, &minor, &key_len) != 2)
-               return -EINVAL;
-
-       body = input + key_len;
-       if (!isspace(*body))
-               return -EINVAL;
-       body = skip_spaces(body);
+       int ret;
 
-       disk = get_gendisk(MKDEV(major, minor), &part);
-       if (!disk)
-               return -ENODEV;
-       if (part) {
-               ret = -ENODEV;
-               goto fail;
-       }
+       disk = blkcg_conf_get_disk(&input);
+       if (IS_ERR(disk))
+               return PTR_ERR(disk);
 
        q = disk->queue;
 
@@ -856,7 +880,7 @@ int blkg_conf_prep(struct blkcg *blkcg, const struct blkcg_policy *pol,
 success:
        ctx->disk = disk;
        ctx->blkg = blkg;
-       ctx->body = body;
+       ctx->body = input;
        return 0;
 
 fail_unlock:
@@ -876,6 +900,7 @@ fail:
        }
        return ret;
 }
+EXPORT_SYMBOL_GPL(blkg_conf_prep);
 
 /**
  * blkg_conf_finish - finish up per-blkg config update
@@ -891,6 +916,7 @@ void blkg_conf_finish(struct blkg_conf_ctx *ctx)
        rcu_read_unlock();
        put_disk_and_module(ctx->disk);
 }
+EXPORT_SYMBOL_GPL(blkg_conf_finish);
 
 static int blkcg_print_stat(struct seq_file *sf, void *v)
 {
@@ -1346,7 +1372,7 @@ int blkcg_activate_policy(struct request_queue *q,
                blk_mq_freeze_queue(q);
 pd_prealloc:
        if (!pd_prealloc) {
-               pd_prealloc = pol->pd_alloc_fn(GFP_KERNEL, q->node);
+               pd_prealloc = pol->pd_alloc_fn(GFP_KERNEL, q, &blkcg_root);
                if (!pd_prealloc) {
                        ret = -ENOMEM;
                        goto out_bypass_end;
@@ -1362,7 +1388,7 @@ pd_prealloc:
                if (blkg->pd[pol->plid])
                        continue;
 
-               pd = pol->pd_alloc_fn(GFP_NOWAIT | __GFP_NOWARN, q->node);
+               pd = pol->pd_alloc_fn(GFP_NOWAIT | __GFP_NOWARN, q, &blkcg_root);
                if (!pd)
                        swap(pd, pd_prealloc);
                if (!pd) {
@@ -1475,7 +1501,8 @@ int blkcg_policy_register(struct blkcg_policy *pol)
                        blkcg->cpd[pol->plid] = cpd;
                        cpd->blkcg = blkcg;
                        cpd->plid = pol->plid;
-                       pol->cpd_init_fn(cpd);
+                       if (pol->cpd_init_fn)
+                               pol->cpd_init_fn(cpd);
                }
        }