pinctrl: uniphier: Add 5th LD20 MPEG2-TS input pin-mux setting
[linux-2.6-microblaze.git] / block / blk-cgroup.c
index 53b7bd4..24ed269 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/ctype.h>
 #include <linux/blk-cgroup.h>
 #include <linux/tracehook.h>
+#include <linux/psi.h>
 #include "blk.h"
 
 #define MAX_KEY_LEN 100
@@ -47,12 +48,14 @@ struct blkcg blkcg_root;
 EXPORT_SYMBOL_GPL(blkcg_root);
 
 struct cgroup_subsys_state * const blkcg_root_css = &blkcg_root.css;
+EXPORT_SYMBOL_GPL(blkcg_root_css);
 
 static struct blkcg_policy *blkcg_policy[BLKCG_MAX_POLS];
 
 static LIST_HEAD(all_blkcgs);          /* protected by blkcg_pol_mutex */
 
 static bool blkcg_debug_stats = false;
+static struct workqueue_struct *blkcg_punt_bio_wq;
 
 static bool blkcg_policy_enabled(struct request_queue *q,
                                 const struct blkcg_policy *pol)
@@ -87,6 +90,8 @@ static void __blkg_release(struct rcu_head *rcu)
 {
        struct blkcg_gq *blkg = container_of(rcu, struct blkcg_gq, rcu_head);
 
+       WARN_ON(!bio_list_empty(&blkg->async_bios));
+
        /* release the blkcg and parent blkg refs this blkg has been holding */
        css_put(&blkg->blkcg->css);
        if (blkg->parent)
@@ -112,6 +117,23 @@ static void blkg_release(struct percpu_ref *ref)
        call_rcu(&blkg->rcu_head, __blkg_release);
 }
 
+static void blkg_async_bio_workfn(struct work_struct *work)
+{
+       struct blkcg_gq *blkg = container_of(work, struct blkcg_gq,
+                                            async_bio_work);
+       struct bio_list bios = BIO_EMPTY_LIST;
+       struct bio *bio;
+
+       /* as long as there are pending bios, @blkg can't go away */
+       spin_lock_bh(&blkg->async_bio_lock);
+       bio_list_merge(&bios, &blkg->async_bios);
+       bio_list_init(&blkg->async_bios);
+       spin_unlock_bh(&blkg->async_bio_lock);
+
+       while ((bio = bio_list_pop(&bios)))
+               submit_bio(bio);
+}
+
 /**
  * blkg_alloc - allocate a blkg
  * @blkcg: block cgroup the new blkg is associated with
@@ -140,6 +162,9 @@ static struct blkcg_gq *blkg_alloc(struct blkcg *blkcg, struct request_queue *q,
 
        blkg->q = q;
        INIT_LIST_HEAD(&blkg->q_node);
+       spin_lock_init(&blkg->async_bio_lock);
+       bio_list_init(&blkg->async_bios);
+       INIT_WORK(&blkg->async_bio_work, blkg_async_bio_workfn);
        blkg->blkcg = blkcg;
 
        for (i = 0; i < BLKCG_MAX_POLS; i++) {
@@ -1526,6 +1551,25 @@ out_unlock:
 }
 EXPORT_SYMBOL_GPL(blkcg_policy_unregister);
 
+bool __blkcg_punt_bio_submit(struct bio *bio)
+{
+       struct blkcg_gq *blkg = bio->bi_blkg;
+
+       /* consume the flag first */
+       bio->bi_opf &= ~REQ_CGROUP_PUNT;
+
+       /* never bounce for the root cgroup */
+       if (!blkg->parent)
+               return false;
+
+       spin_lock_bh(&blkg->async_bio_lock);
+       bio_list_add(&blkg->async_bios, bio);
+       spin_unlock_bh(&blkg->async_bio_lock);
+
+       queue_work(blkcg_punt_bio_wq, &blkg->async_bio_work);
+       return true;
+}
+
 /*
  * Scale the accumulated delay based on how long it has been since we updated
  * the delay.  We only call this when we are adding delay, in case it's been a
@@ -1587,6 +1631,7 @@ static void blkcg_scale_delay(struct blkcg_gq *blkg, u64 now)
  */
 static void blkcg_maybe_throttle_blkg(struct blkcg_gq *blkg, bool use_memdelay)
 {
+       unsigned long pflags;
        u64 now = ktime_to_ns(ktime_get());
        u64 exp;
        u64 delay_nsec = 0;
@@ -1613,11 +1658,8 @@ static void blkcg_maybe_throttle_blkg(struct blkcg_gq *blkg, bool use_memdelay)
         */
        delay_nsec = min_t(u64, delay_nsec, 250 * NSEC_PER_MSEC);
 
-       /*
-        * TODO: the use_memdelay flag is going to be for the upcoming psi stuff
-        * that hasn't landed upstream yet.  Once that stuff is in place we need
-        * to do a psi_memstall_enter/leave if memdelay is set.
-        */
+       if (use_memdelay)
+               psi_memstall_enter(&pflags);
 
        exp = ktime_add_ns(now, delay_nsec);
        tok = io_schedule_prepare();
@@ -1627,6 +1669,9 @@ static void blkcg_maybe_throttle_blkg(struct blkcg_gq *blkg, bool use_memdelay)
                        break;
        } while (!fatal_signal_pending(current));
        io_schedule_finish(tok);
+
+       if (use_memdelay)
+               psi_memstall_leave(&pflags);
 }
 
 /**
@@ -1726,5 +1771,16 @@ void blkcg_add_delay(struct blkcg_gq *blkg, u64 now, u64 delta)
        atomic64_add(delta, &blkg->delay_nsec);
 }
 
+static int __init blkcg_init(void)
+{
+       blkcg_punt_bio_wq = alloc_workqueue("blkcg_punt_bio",
+                                           WQ_MEM_RECLAIM | WQ_FREEZABLE |
+                                           WQ_UNBOUND | WQ_SYSFS, 0);
+       if (!blkcg_punt_bio_wq)
+               return -ENOMEM;
+       return 0;
+}
+subsys_initcall(blkcg_init);
+
 module_param(blkcg_debug_stats, bool, 0644);
 MODULE_PARM_DESC(blkcg_debug_stats, "True if you want debug stats, false if not");