blkcg: associate blkg when associating a device
[sfrench/cifs-2.6.git] / block / bio.c
index a50d59236b1976439e691bc0f22da002eedfd0a9..1e852ab904aaef6421644733d9b0619ad2780cc9 100644 (file)
@@ -605,6 +605,7 @@ void __bio_clone_fast(struct bio *bio, struct bio *bio_src)
        if (bio_flagged(bio_src, BIO_THROTTLED))
                bio_set_flag(bio, BIO_THROTTLED);
        bio->bi_opf = bio_src->bi_opf;
+       bio->bi_ioprio = bio_src->bi_ioprio;
        bio->bi_write_hint = bio_src->bi_write_hint;
        bio->bi_iter = bio_src->bi_iter;
        bio->bi_io_vec = bio_src->bi_io_vec;
@@ -1989,55 +1990,103 @@ int bio_associate_blkcg_from_page(struct bio *bio, struct page *page)
  *
  * This function takes an extra reference of @blkcg_css which will be put
  * when @bio is released.  The caller must own @bio and is responsible for
- * synchronizing calls to this function.
+ * synchronizing calls to this function.  If @blkcg_css is %NULL, a call to
+ * blkcg_get_css() finds the current css from the kthread or task.
  */
 int bio_associate_blkcg(struct bio *bio, struct cgroup_subsys_state *blkcg_css)
 {
        if (unlikely(bio->bi_css))
                return -EBUSY;
-       css_get(blkcg_css);
+
+       if (blkcg_css)
+               css_get(blkcg_css);
+       else
+               blkcg_css = blkcg_get_css();
+
        bio->bi_css = blkcg_css;
        return 0;
 }
 EXPORT_SYMBOL_GPL(bio_associate_blkcg);
 
 /**
- * bio_associate_blkg - associate a bio with the specified blkg
+ * bio_disassociate_blkg - puts back the blkg reference if associated
+ * @bio: target bio
+ *
+ * Helper to disassociate the blkg from @bio if a blkg is associated.
+ */
+void bio_disassociate_blkg(struct bio *bio)
+{
+       if (bio->bi_blkg) {
+               blkg_put(bio->bi_blkg);
+               bio->bi_blkg = NULL;
+       }
+}
+EXPORT_SYMBOL_GPL(bio_disassociate_blkg);
+
+/**
+ * __bio_associate_blkg - associate a bio with the a blkg
  * @bio: target bio
  * @blkg: the blkg to associate
  *
- * Associate @bio with the blkg specified by @blkg.  This is the queue specific
- * blkcg information associated with the @bio, a reference will be taken on the
- * @blkg and will be freed when the bio is freed.
+ * This tries to associate @bio with the specified @blkg.  Association failure
+ * is handled by walking up the blkg tree.  Therefore, the blkg associated can
+ * be anything between @blkg and the root_blkg.  This situation only happens
+ * when a cgroup is dying and then the remaining bios will spill to the closest
+ * alive blkg.
+ *
+ * A reference will be taken on the @blkg and will be released when @bio is
+ * freed.
  */
-int bio_associate_blkg(struct bio *bio, struct blkcg_gq *blkg)
+static void __bio_associate_blkg(struct bio *bio, struct blkcg_gq *blkg)
 {
-       if (unlikely(bio->bi_blkg))
-               return -EBUSY;
-       if (!blkg_try_get(blkg))
-               return -ENODEV;
-       bio->bi_blkg = blkg;
-       return 0;
+       bio_disassociate_blkg(bio);
+
+       bio->bi_blkg = blkg_try_get_closest(blkg);
 }
 
+/**
+ * bio_associate_blkg - associate a bio with a blkg
+ * @bio: target bio
+ *
+ * Associate @bio with the blkg found from the bio's css and request_queue.
+ * If one is not found, bio_lookup_blkg() creates the blkg.  If a blkg is
+ * already associated, the css is reused and association redone as the
+ * request_queue may have changed.
+ */
+void bio_associate_blkg(struct bio *bio)
+{
+       struct request_queue *q = bio->bi_disk->queue;
+       struct blkcg *blkcg;
+       struct blkcg_gq *blkg;
+
+       rcu_read_lock();
+
+       bio_associate_blkcg(bio, NULL);
+       blkcg = bio_blkcg(bio);
+
+       if (!blkcg->css.parent) {
+               __bio_associate_blkg(bio, q->root_blkg);
+       } else {
+               blkg = blkg_lookup_create(blkcg, q);
+
+               __bio_associate_blkg(bio, blkg);
+       }
+
+       rcu_read_unlock();
+}
+EXPORT_SYMBOL_GPL(bio_associate_blkg);
+
 /**
  * bio_disassociate_task - undo bio_associate_current()
  * @bio: target bio
  */
 void bio_disassociate_task(struct bio *bio)
 {
-       if (bio->bi_ioc) {
-               put_io_context(bio->bi_ioc);
-               bio->bi_ioc = NULL;
-       }
        if (bio->bi_css) {
                css_put(bio->bi_css);
                bio->bi_css = NULL;
        }
-       if (bio->bi_blkg) {
-               blkg_put(bio->bi_blkg);
-               bio->bi_blkg = NULL;
-       }
+       bio_disassociate_blkg(bio);
 }
 
 /**
@@ -2049,6 +2098,9 @@ void bio_clone_blkcg_association(struct bio *dst, struct bio *src)
 {
        if (src->bi_css)
                WARN_ON(bio_associate_blkcg(dst, src->bi_css));
+
+       if (src->bi_blkg)
+               __bio_associate_blkg(dst, src->bi_blkg);
 }
 EXPORT_SYMBOL_GPL(bio_clone_blkcg_association);
 #endif /* CONFIG_BLK_CGROUP */