]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - block/blk-sysfs.c
block: hook up writeback throttling
[mirror_ubuntu-artful-kernel.git] / block / blk-sysfs.c
index 9cdb7247727a5504b9f1964b514b82e783938d62..9262d2d60a0916281a5e1c09759985922e3349d7 100644 (file)
@@ -13,6 +13,7 @@
 
 #include "blk.h"
 #include "blk-mq.h"
+#include "blk-wbt.h"
 
 struct queue_sysfs_entry {
        struct attribute attr;
@@ -41,6 +42,19 @@ queue_var_store(unsigned long *var, const char *page, size_t count)
        return count;
 }
 
+static ssize_t queue_var_store64(u64 *var, const char *page)
+{
+       int err;
+       u64 v;
+
+       err = kstrtou64(page, 10, &v);
+       if (err < 0)
+               return err;
+
+       *var = v;
+       return 0;
+}
+
 static ssize_t queue_requests_show(struct request_queue *q, char *page)
 {
        return queue_var_show(q->nr_requests, (page));
@@ -364,6 +378,32 @@ static ssize_t queue_poll_store(struct request_queue *q, const char *page,
        return ret;
 }
 
+static ssize_t queue_wb_lat_show(struct request_queue *q, char *page)
+{
+       if (!q->rq_wb)
+               return -EINVAL;
+
+       return sprintf(page, "%llu\n", div_u64(q->rq_wb->min_lat_nsec, 1000));
+}
+
+static ssize_t queue_wb_lat_store(struct request_queue *q, const char *page,
+                                 size_t count)
+{
+       ssize_t ret;
+       u64 val;
+
+       if (!q->rq_wb)
+               return -EINVAL;
+
+       ret = queue_var_store64(&val, page);
+       if (ret < 0)
+               return ret;
+
+       q->rq_wb->min_lat_nsec = val * 1000ULL;
+       wbt_update_limits(q->rq_wb);
+       return count;
+}
+
 static ssize_t queue_wc_show(struct request_queue *q, char *page)
 {
        if (test_bit(QUEUE_FLAG_WC, &q->queue_flags))
@@ -578,6 +618,12 @@ static struct queue_sysfs_entry queue_stats_entry = {
        .show = queue_stats_show,
 };
 
+static struct queue_sysfs_entry queue_wb_lat_entry = {
+       .attr = {.name = "wbt_lat_usec", .mode = S_IRUGO | S_IWUSR },
+       .show = queue_wb_lat_show,
+       .store = queue_wb_lat_store,
+};
+
 static struct attribute *default_attrs[] = {
        &queue_requests_entry.attr,
        &queue_ra_entry.attr,
@@ -608,6 +654,7 @@ static struct attribute *default_attrs[] = {
        &queue_wc_entry.attr,
        &queue_dax_entry.attr,
        &queue_stats_entry.attr,
+       &queue_wb_lat_entry.attr,
        NULL,
 };
 
@@ -682,6 +729,7 @@ static void blk_release_queue(struct kobject *kobj)
        struct request_queue *q =
                container_of(kobj, struct request_queue, kobj);
 
+       wbt_exit(q);
        bdi_exit(&q->backing_dev_info);
        blkcg_exit_queue(q);
 
@@ -722,6 +770,44 @@ struct kobj_type blk_queue_ktype = {
        .release        = blk_release_queue,
 };
 
+static void blk_wb_stat_get(void *data, struct blk_rq_stat *stat)
+{
+       blk_queue_stat_get(data, stat);
+}
+
+static void blk_wb_stat_clear(void *data)
+{
+       blk_stat_clear(data);
+}
+
+static bool blk_wb_stat_is_current(struct blk_rq_stat *stat)
+{
+       return blk_stat_is_current(stat);
+}
+
+static struct wb_stat_ops wb_stat_ops = {
+       .get            = blk_wb_stat_get,
+       .is_current     = blk_wb_stat_is_current,
+       .clear          = blk_wb_stat_clear,
+};
+
+static void blk_wb_init(struct request_queue *q)
+{
+#ifndef CONFIG_BLK_WBT_MQ
+       if (q->mq_ops)
+               return;
+#endif
+#ifndef CONFIG_BLK_WBT_SQ
+       if (q->request_fn)
+               return;
+#endif
+
+       /*
+        * If this fails, we don't get throttling
+        */
+       wbt_init(q, &wb_stat_ops);
+}
+
 int blk_register_queue(struct gendisk *disk)
 {
        int ret;
@@ -761,6 +847,8 @@ int blk_register_queue(struct gendisk *disk)
        if (q->mq_ops)
                blk_mq_register_dev(dev, q);
 
+       blk_wb_init(q);
+
        if (!q->request_fn)
                return 0;