]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - block/cfq-iosched.c
Merge branch 'x86/urgent' into core/efi, to pick up a pending EFI fix
[karo-tx-linux.git] / block / cfq-iosched.c
index a948d4df3fc364dc5dc89b9601fcf813b4571f3b..04de88463a986384b54fa57593d2c89e7189e95c 100644 (file)
@@ -68,9 +68,9 @@ static struct kmem_cache *cfq_pool;
 #define rb_entry_cfqg(node)    rb_entry((node), struct cfq_group, rb_node)
 
 /* blkio-related constants */
-#define CFQ_WEIGHT_MIN          10
-#define CFQ_WEIGHT_MAX          1000
-#define CFQ_WEIGHT_DEFAULT      500
+#define CFQ_WEIGHT_LEGACY_MIN  10
+#define CFQ_WEIGHT_LEGACY_DFL  500
+#define CFQ_WEIGHT_LEGACY_MAX  1000
 
 struct cfq_ttime {
        unsigned long last_end_request;
@@ -185,8 +185,6 @@ struct cfqg_stats {
        struct blkg_rwstat              wait_time;
        /* number of IOs queued up */
        struct blkg_rwstat              queued;
-       /* total sectors transferred */
-       struct blkg_stat                sectors;
        /* total disk time and nr sectors dispatched by this group */
        struct blkg_stat                time;
 #ifdef CONFIG_DEBUG_BLK_CGROUP
@@ -688,12 +686,6 @@ static inline void cfqg_stats_update_io_merged(struct cfq_group *cfqg, int rw)
        blkg_rwstat_add(&cfqg->stats.merged, rw, 1);
 }
 
-static inline void cfqg_stats_update_dispatch(struct cfq_group *cfqg,
-                                             uint64_t bytes, int rw)
-{
-       blkg_stat_add(&cfqg->stats.sectors, bytes >> 9);
-}
-
 static inline void cfqg_stats_update_completion(struct cfq_group *cfqg,
                        uint64_t start_time, uint64_t io_start_time, int rw)
 {
@@ -782,8 +774,6 @@ static inline void cfqg_stats_update_timeslice_used(struct cfq_group *cfqg,
                        unsigned long time, unsigned long unaccounted_time) { }
 static inline void cfqg_stats_update_io_remove(struct cfq_group *cfqg, int rw) { }
 static inline void cfqg_stats_update_io_merged(struct cfq_group *cfqg, int rw) { }
-static inline void cfqg_stats_update_dispatch(struct cfq_group *cfqg,
-                                             uint64_t bytes, int rw) { }
 static inline void cfqg_stats_update_completion(struct cfq_group *cfqg,
                        uint64_t start_time, uint64_t io_start_time, int rw) { }
 
@@ -1532,14 +1522,15 @@ static void cfq_init_cfqg_base(struct cfq_group *cfqg)
 }
 
 #ifdef CONFIG_CFQ_GROUP_IOSCHED
+static int __cfq_set_weight(struct cgroup_subsys_state *css, u64 val,
+                           bool on_dfl, bool reset_dev, bool is_leaf_weight);
+
 static void cfqg_stats_exit(struct cfqg_stats *stats)
 {
        blkg_rwstat_exit(&stats->merged);
        blkg_rwstat_exit(&stats->service_time);
        blkg_rwstat_exit(&stats->wait_time);
        blkg_rwstat_exit(&stats->queued);
-
-       blkg_stat_exit(&stats->sectors);
        blkg_stat_exit(&stats->time);
 #ifdef CONFIG_DEBUG_BLK_CGROUP
        blkg_stat_exit(&stats->unaccounted_time);
@@ -1558,8 +1549,6 @@ static int cfqg_stats_init(struct cfqg_stats *stats, gfp_t gfp)
            blkg_rwstat_init(&stats->service_time, gfp) ||
            blkg_rwstat_init(&stats->wait_time, gfp) ||
            blkg_rwstat_init(&stats->queued, gfp) ||
-
-           blkg_stat_init(&stats->sectors, gfp) ||
            blkg_stat_init(&stats->time, gfp))
                goto err;
 
@@ -1592,14 +1581,14 @@ static struct blkcg_policy_data *cfq_cpd_alloc(gfp_t gfp)
 static void cfq_cpd_init(struct blkcg_policy_data *cpd)
 {
        struct cfq_group_data *cgd = cpd_to_cfqgd(cpd);
+       unsigned int weight = cgroup_on_dfl(blkcg_root.css.cgroup) ?
+                             CGROUP_WEIGHT_DFL : CFQ_WEIGHT_LEGACY_DFL;
 
-       if (cpd_to_blkcg(cpd) == &blkcg_root) {
-               cgd->weight = 2 * CFQ_WEIGHT_DEFAULT;
-               cgd->leaf_weight = 2 * CFQ_WEIGHT_DEFAULT;
-       } else {
-               cgd->weight = CFQ_WEIGHT_DEFAULT;
-               cgd->leaf_weight = CFQ_WEIGHT_DEFAULT;
-       }
+       if (cpd_to_blkcg(cpd) == &blkcg_root)
+               weight *= 2;
+
+       cgd->weight = weight;
+       cgd->leaf_weight = weight;
 }
 
 static void cfq_cpd_free(struct blkcg_policy_data *cpd)
@@ -1607,6 +1596,19 @@ static void cfq_cpd_free(struct blkcg_policy_data *cpd)
        kfree(cpd_to_cfqgd(cpd));
 }
 
+static void cfq_cpd_bind(struct blkcg_policy_data *cpd)
+{
+       struct blkcg *blkcg = cpd_to_blkcg(cpd);
+       bool on_dfl = cgroup_on_dfl(blkcg_root.css.cgroup);
+       unsigned int weight = on_dfl ? CGROUP_WEIGHT_DFL : CFQ_WEIGHT_LEGACY_DFL;
+
+       if (blkcg == &blkcg_root)
+               weight *= 2;
+
+       WARN_ON_ONCE(__cfq_set_weight(&blkcg->css, weight, on_dfl, true, false));
+       WARN_ON_ONCE(__cfq_set_weight(&blkcg->css, weight, on_dfl, true, true));
+}
+
 static struct blkg_policy_data *cfq_pd_alloc(gfp_t gfp, int node)
 {
        struct cfq_group *cfqg;
@@ -1754,36 +1756,48 @@ static int cfq_print_leaf_weight(struct seq_file *sf, void *v)
 
 static ssize_t __cfqg_set_weight_device(struct kernfs_open_file *of,
                                        char *buf, size_t nbytes, loff_t off,
-                                       bool is_leaf_weight)
+                                       bool on_dfl, bool is_leaf_weight)
 {
+       unsigned int min = on_dfl ? CGROUP_WEIGHT_MIN : CFQ_WEIGHT_LEGACY_MIN;
+       unsigned int max = on_dfl ? CGROUP_WEIGHT_MAX : CFQ_WEIGHT_LEGACY_MAX;
        struct blkcg *blkcg = css_to_blkcg(of_css(of));
        struct blkg_conf_ctx ctx;
        struct cfq_group *cfqg;
        struct cfq_group_data *cfqgd;
        int ret;
+       u64 v;
 
        ret = blkg_conf_prep(blkcg, &blkcg_policy_cfq, buf, &ctx);
        if (ret)
                return ret;
 
-       ret = -EINVAL;
+       if (sscanf(ctx.body, "%llu", &v) == 1) {
+               /* require "default" on dfl */
+               ret = -ERANGE;
+               if (!v && on_dfl)
+                       goto out_finish;
+       } else if (!strcmp(strim(ctx.body), "default")) {
+               v = 0;
+       } else {
+               ret = -EINVAL;
+               goto out_finish;
+       }
+
        cfqg = blkg_to_cfqg(ctx.blkg);
        cfqgd = blkcg_to_cfqgd(blkcg);
-       if (!cfqg || !cfqgd)
-               goto err;
 
-       if (!ctx.v || (ctx.v >= CFQ_WEIGHT_MIN && ctx.v <= CFQ_WEIGHT_MAX)) {
+       ret = -ERANGE;
+       if (!v || (v >= min && v <= max)) {
                if (!is_leaf_weight) {
-                       cfqg->dev_weight = ctx.v;
-                       cfqg->new_weight = ctx.v ?: cfqgd->weight;
+                       cfqg->dev_weight = v;
+                       cfqg->new_weight = v ?: cfqgd->weight;
                } else {
-                       cfqg->dev_leaf_weight = ctx.v;
-                       cfqg->new_leaf_weight = ctx.v ?: cfqgd->leaf_weight;
+                       cfqg->dev_leaf_weight = v;
+                       cfqg->new_leaf_weight = v ?: cfqgd->leaf_weight;
                }
                ret = 0;
        }
-
-err:
+out_finish:
        blkg_conf_finish(&ctx);
        return ret ?: nbytes;
 }
@@ -1791,25 +1805,27 @@ err:
 static ssize_t cfqg_set_weight_device(struct kernfs_open_file *of,
                                      char *buf, size_t nbytes, loff_t off)
 {
-       return __cfqg_set_weight_device(of, buf, nbytes, off, false);
+       return __cfqg_set_weight_device(of, buf, nbytes, off, false, false);
 }
 
 static ssize_t cfqg_set_leaf_weight_device(struct kernfs_open_file *of,
                                           char *buf, size_t nbytes, loff_t off)
 {
-       return __cfqg_set_weight_device(of, buf, nbytes, off, true);
+       return __cfqg_set_weight_device(of, buf, nbytes, off, false, true);
 }
 
-static int __cfq_set_weight(struct cgroup_subsys_state *css, struct cftype *cft,
-                           u64 val, bool is_leaf_weight)
+static int __cfq_set_weight(struct cgroup_subsys_state *css, u64 val,
+                           bool on_dfl, bool reset_dev, bool is_leaf_weight)
 {
+       unsigned int min = on_dfl ? CGROUP_WEIGHT_MIN : CFQ_WEIGHT_LEGACY_MIN;
+       unsigned int max = on_dfl ? CGROUP_WEIGHT_MAX : CFQ_WEIGHT_LEGACY_MAX;
        struct blkcg *blkcg = css_to_blkcg(css);
        struct blkcg_gq *blkg;
        struct cfq_group_data *cfqgd;
        int ret = 0;
 
-       if (val < CFQ_WEIGHT_MIN || val > CFQ_WEIGHT_MAX)
-               return -EINVAL;
+       if (val < min || val > max)
+               return -ERANGE;
 
        spin_lock_irq(&blkcg->lock);
        cfqgd = blkcg_to_cfqgd(blkcg);
@@ -1830,9 +1846,13 @@ static int __cfq_set_weight(struct cgroup_subsys_state *css, struct cftype *cft,
                        continue;
 
                if (!is_leaf_weight) {
+                       if (reset_dev)
+                               cfqg->dev_weight = 0;
                        if (!cfqg->dev_weight)
                                cfqg->new_weight = cfqgd->weight;
                } else {
+                       if (reset_dev)
+                               cfqg->dev_leaf_weight = 0;
                        if (!cfqg->dev_leaf_weight)
                                cfqg->new_leaf_weight = cfqgd->leaf_weight;
                }
@@ -1846,13 +1866,13 @@ out:
 static int cfq_set_weight(struct cgroup_subsys_state *css, struct cftype *cft,
                          u64 val)
 {
-       return __cfq_set_weight(css, cft, val, false);
+       return __cfq_set_weight(css, val, false, false, false);
 }
 
 static int cfq_set_leaf_weight(struct cgroup_subsys_state *css,
                               struct cftype *cft, u64 val)
 {
-       return __cfq_set_weight(css, cft, val, true);
+       return __cfq_set_weight(css, val, false, false, true);
 }
 
 static int cfqg_print_stat(struct seq_file *sf, void *v)
@@ -1901,6 +1921,40 @@ static int cfqg_print_rwstat_recursive(struct seq_file *sf, void *v)
        return 0;
 }
 
+static u64 cfqg_prfill_sectors(struct seq_file *sf, struct blkg_policy_data *pd,
+                              int off)
+{
+       u64 sum = blkg_rwstat_total(&pd->blkg->stat_bytes);
+
+       return __blkg_prfill_u64(sf, pd, sum >> 9);
+}
+
+static int cfqg_print_stat_sectors(struct seq_file *sf, void *v)
+{
+       blkcg_print_blkgs(sf, css_to_blkcg(seq_css(sf)),
+                         cfqg_prfill_sectors, &blkcg_policy_cfq, 0, false);
+       return 0;
+}
+
+static u64 cfqg_prfill_sectors_recursive(struct seq_file *sf,
+                                        struct blkg_policy_data *pd, int off)
+{
+       struct blkg_rwstat tmp = blkg_rwstat_recursive_sum(pd->blkg, NULL,
+                                       offsetof(struct blkcg_gq, stat_bytes));
+       u64 sum = atomic64_read(&tmp.aux_cnt[BLKG_RWSTAT_READ]) +
+               atomic64_read(&tmp.aux_cnt[BLKG_RWSTAT_WRITE]);
+
+       return __blkg_prfill_u64(sf, pd, sum >> 9);
+}
+
+static int cfqg_print_stat_sectors_recursive(struct seq_file *sf, void *v)
+{
+       blkcg_print_blkgs(sf, css_to_blkcg(seq_css(sf)),
+                         cfqg_prfill_sectors_recursive, &blkcg_policy_cfq, 0,
+                         false);
+       return 0;
+}
+
 #ifdef CONFIG_DEBUG_BLK_CGROUP
 static u64 cfqg_prfill_avg_queue_size(struct seq_file *sf,
                                      struct blkg_policy_data *pd, int off)
@@ -1927,7 +1981,7 @@ static int cfqg_print_avg_queue_size(struct seq_file *sf, void *v)
 }
 #endif /* CONFIG_DEBUG_BLK_CGROUP */
 
-static struct cftype cfq_blkcg_files[] = {
+static struct cftype cfq_blkcg_legacy_files[] = {
        /* on root, weight is mapped to leaf_weight */
        {
                .name = "weight_device",
@@ -1975,8 +2029,7 @@ static struct cftype cfq_blkcg_files[] = {
        },
        {
                .name = "sectors",
-               .private = offsetof(struct cfq_group, stats.sectors),
-               .seq_show = cfqg_print_stat,
+               .seq_show = cfqg_print_stat_sectors,
        },
        {
                .name = "io_service_bytes",
@@ -2017,8 +2070,7 @@ static struct cftype cfq_blkcg_files[] = {
        },
        {
                .name = "sectors_recursive",
-               .private = offsetof(struct cfq_group, stats.sectors),
-               .seq_show = cfqg_print_stat_recursive,
+               .seq_show = cfqg_print_stat_sectors_recursive,
        },
        {
                .name = "io_service_bytes_recursive",
@@ -2083,6 +2135,48 @@ static struct cftype cfq_blkcg_files[] = {
 #endif /* CONFIG_DEBUG_BLK_CGROUP */
        { }     /* terminate */
 };
+
+static int cfq_print_weight_on_dfl(struct seq_file *sf, void *v)
+{
+       struct blkcg *blkcg = css_to_blkcg(seq_css(sf));
+       struct cfq_group_data *cgd = blkcg_to_cfqgd(blkcg);
+
+       seq_printf(sf, "default %u\n", cgd->weight);
+       blkcg_print_blkgs(sf, blkcg, cfqg_prfill_weight_device,
+                         &blkcg_policy_cfq, 0, false);
+       return 0;
+}
+
+static ssize_t cfq_set_weight_on_dfl(struct kernfs_open_file *of,
+                                    char *buf, size_t nbytes, loff_t off)
+{
+       char *endp;
+       int ret;
+       u64 v;
+
+       buf = strim(buf);
+
+       /* "WEIGHT" or "default WEIGHT" sets the default weight */
+       v = simple_strtoull(buf, &endp, 0);
+       if (*endp == '\0' || sscanf(buf, "default %llu", &v) == 1) {
+               ret = __cfq_set_weight(of_css(of), v, true, false, false);
+               return ret ?: nbytes;
+       }
+
+       /* "MAJ:MIN WEIGHT" */
+       return __cfqg_set_weight_device(of, buf, nbytes, off, true, false);
+}
+
+static struct cftype cfq_blkcg_files[] = {
+       {
+               .name = "weight",
+               .flags = CFTYPE_NOT_ON_ROOT,
+               .seq_show = cfq_print_weight_on_dfl,
+               .write = cfq_set_weight_on_dfl,
+       },
+       { }     /* terminate */
+};
+
 #else /* GROUP_IOSCHED */
 static struct cfq_group *cfq_lookup_cfqg(struct cfq_data *cfqd,
                                         struct blkcg *blkcg)
@@ -2888,7 +2982,6 @@ static void cfq_dispatch_insert(struct request_queue *q, struct request *rq)
 
        cfqd->rq_in_flight[cfq_cfqq_sync(cfqq)]++;
        cfqq->nr_sectors += blk_rq_sectors(rq);
-       cfqg_stats_update_dispatch(cfqq->cfqg, blk_rq_bytes(rq), rq->cmd_flags);
 }
 
 /*
@@ -4443,9 +4536,9 @@ static int cfq_init_queue(struct request_queue *q, struct elevator_type *e)
                goto out_free;
 
        cfq_init_cfqg_base(cfqd->root_group);
+       cfqd->root_group->weight = 2 * CFQ_WEIGHT_LEGACY_DFL;
+       cfqd->root_group->leaf_weight = 2 * CFQ_WEIGHT_LEGACY_DFL;
 #endif
-       cfqd->root_group->weight = 2 * CFQ_WEIGHT_DEFAULT;
-       cfqd->root_group->leaf_weight = 2 * CFQ_WEIGHT_DEFAULT;
 
        /*
         * Not strictly needed (since RB_ROOT just clears the node and we
@@ -4640,11 +4733,13 @@ static struct elevator_type iosched_cfq = {
 
 #ifdef CONFIG_CFQ_GROUP_IOSCHED
 static struct blkcg_policy blkcg_policy_cfq = {
-       .cftypes                = cfq_blkcg_files,
+       .dfl_cftypes            = cfq_blkcg_files,
+       .legacy_cftypes         = cfq_blkcg_legacy_files,
 
        .cpd_alloc_fn           = cfq_cpd_alloc,
        .cpd_init_fn            = cfq_cpd_init,
        .cpd_free_fn            = cfq_cpd_free,
+       .cpd_bind_fn            = cfq_cpd_bind,
 
        .pd_alloc_fn            = cfq_pd_alloc,
        .pd_init_fn             = cfq_pd_init,