lightnvm: pblk: encapsulate rqd dma allocations
[sfrench/cifs-2.6.git] / block / bio.c
index b12966e415d3f807d0ac27bab9b5e010f771d0b0..17a8b0aa70506e094b8da3a07eca7a2c71e00826 100644 (file)
@@ -609,7 +609,9 @@ void __bio_clone_fast(struct bio *bio, struct bio *bio_src)
        bio->bi_iter = bio_src->bi_iter;
        bio->bi_io_vec = bio_src->bi_io_vec;
 
-       bio_clone_blkcg_association(bio, bio_src);
+       bio_clone_blkg_association(bio, bio_src);
+
+       blkcg_bio_issue_init(bio);
 }
 EXPORT_SYMBOL(__bio_clone_fast);
 
@@ -729,7 +731,7 @@ int bio_add_pc_page(struct request_queue *q, struct bio *bio, struct page
        }
 
        /* If we may be able to merge these biovecs, force a recount */
-       if (bio->bi_vcnt > 1 && (BIOVEC_PHYS_MERGEABLE(bvec-1, bvec)))
+       if (bio->bi_vcnt > 1 && biovec_phys_mergeable(q, bvec - 1, bvec))
                bio_clear_flag(bio, BIO_SEG_VALID);
 
  done:
@@ -827,6 +829,8 @@ int bio_add_page(struct bio *bio, struct page *page,
 }
 EXPORT_SYMBOL(bio_add_page);
 
+#define PAGE_PTRS_PER_BVEC     (sizeof(struct bio_vec) / sizeof(struct page *))
+
 /**
  * __bio_iov_iter_get_pages - pin user or kernel pages and add them to a bio
  * @bio: bio to add pages to
@@ -839,38 +843,35 @@ EXPORT_SYMBOL(bio_add_page);
  */
 static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
 {
-       unsigned short nr_pages = bio->bi_max_vecs - bio->bi_vcnt, idx;
+       unsigned short nr_pages = bio->bi_max_vecs - bio->bi_vcnt;
+       unsigned short entries_left = bio->bi_max_vecs - bio->bi_vcnt;
        struct bio_vec *bv = bio->bi_io_vec + bio->bi_vcnt;
        struct page **pages = (struct page **)bv;
+       ssize_t size, left;
+       unsigned len, i;
        size_t offset;
-       ssize_t size;
+
+       /*
+        * Move page array up in the allocated memory for the bio vecs as far as
+        * possible so that we can start filling biovecs from the beginning
+        * without overwriting the temporary page array.
+       */
+       BUILD_BUG_ON(PAGE_PTRS_PER_BVEC < 2);
+       pages += entries_left * (PAGE_PTRS_PER_BVEC - 1);
 
        size = iov_iter_get_pages(iter, pages, LONG_MAX, nr_pages, &offset);
        if (unlikely(size <= 0))
                return size ? size : -EFAULT;
-       idx = nr_pages = (size + offset + PAGE_SIZE - 1) / PAGE_SIZE;
 
-       /*
-        * Deep magic below:  We need to walk the pinned pages backwards
-        * because we are abusing the space allocated for the bio_vecs
-        * for the page array.  Because the bio_vecs are larger than the
-        * page pointers by definition this will always work.  But it also
-        * means we can't use bio_add_page, so any changes to it's semantics
-        * need to be reflected here as well.
-        */
-       bio->bi_iter.bi_size += size;
-       bio->bi_vcnt += nr_pages;
+       for (left = size, i = 0; left > 0; left -= len, i++) {
+               struct page *page = pages[i];
 
-       while (idx--) {
-               bv[idx].bv_page = pages[idx];
-               bv[idx].bv_len = PAGE_SIZE;
-               bv[idx].bv_offset = 0;
+               len = min_t(size_t, PAGE_SIZE - offset, left);
+               if (WARN_ON_ONCE(bio_add_page(bio, page, len, offset) != len))
+                       return -EINVAL;
+               offset = 0;
        }
 
-       bv[0].bv_offset += offset;
-       bv[0].bv_len -= offset;
-       bv[nr_pages - 1].bv_len -= nr_pages * PAGE_SIZE - offset - size;
-
        iov_iter_advance(iter, size);
        return 0;
 }
@@ -1684,7 +1685,7 @@ void generic_end_io_acct(struct request_queue *q, int req_op,
        const int sgrp = op_stat_group(req_op);
        int cpu = part_stat_lock();
 
-       part_stat_add(cpu, part, ticks[sgrp], duration);
+       part_stat_add(cpu, part, nsecs[sgrp], jiffies_to_nsecs(duration));
        part_round_stats(q, cpu, part);
        part_dec_in_flight(q, part, op_is_write(req_op));
 
@@ -1807,7 +1808,6 @@ struct bio *bio_split(struct bio *bio, int sectors,
                bio_integrity_trim(split);
 
        bio_advance(bio, split->bi_iter.bi_size);
-       bio->bi_iter.bi_done = 0;
 
        if (bio_flagged(bio, BIO_TRACE_COMPLETION))
                bio_set_flag(split, BIO_TRACE_COMPLETION);
@@ -1956,68 +1956,131 @@ EXPORT_SYMBOL(bioset_init_from_src);
 
 #ifdef CONFIG_BLK_CGROUP
 
-#ifdef CONFIG_MEMCG
 /**
- * bio_associate_blkcg_from_page - associate a bio with the page's blkcg
+ * bio_associate_blkg - associate a bio with the a blkg
  * @bio: target bio
- * @page: the page to lookup the blkcg from
+ * @blkg: the blkg to associate
+ *
+ * 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.
  *
- * Associate @bio with the blkcg from @page's owning memcg.  This works like
- * every other associate function wrt references.
+ * A reference will be taken on the @blkg and will be released when @bio is
+ * freed.
  */
-int bio_associate_blkcg_from_page(struct bio *bio, struct page *page)
+int bio_associate_blkg(struct bio *bio, struct blkcg_gq *blkg)
 {
-       struct cgroup_subsys_state *blkcg_css;
-
-       if (unlikely(bio->bi_css))
+       if (unlikely(bio->bi_blkg))
                return -EBUSY;
-       if (!page->mem_cgroup)
-               return 0;
-       blkcg_css = cgroup_get_e_css(page->mem_cgroup->css.cgroup,
-                                    &io_cgrp_subsys);
-       bio->bi_css = blkcg_css;
+       bio->bi_blkg = blkg_tryget_closest(blkg);
        return 0;
 }
-#endif /* CONFIG_MEMCG */
 
 /**
- * bio_associate_blkcg - associate a bio with the specified blkcg
- * @bio: target bio
- * @blkcg_css: css of the blkcg to associate
+ * __bio_associate_blkg_from_css - internal blkg association function
  *
- * Associate @bio with the blkcg specified by @blkcg_css.  Block layer will
- * treat @bio as if it were issued by a task which belongs to the blkcg.
+ * This in the core association function that all association paths rely on.
+ * A blkg reference is taken which is released upon freeing of the bio.
+ */
+static int __bio_associate_blkg_from_css(struct bio *bio,
+                                        struct cgroup_subsys_state *css)
+{
+       struct request_queue *q = bio->bi_disk->queue;
+       struct blkcg_gq *blkg;
+       int ret;
+
+       rcu_read_lock();
+
+       if (!css || !css->parent)
+               blkg = q->root_blkg;
+       else
+               blkg = blkg_lookup_create(css_to_blkcg(css), q);
+
+       ret = bio_associate_blkg(bio, blkg);
+
+       rcu_read_unlock();
+       return ret;
+}
+
+/**
+ * bio_associate_blkg_from_css - associate a bio with a specified css
+ * @bio: target bio
+ * @css: target css
  *
- * 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.
+ * Associate @bio with the blkg found by combining the css's blkg and the
+ * request_queue of the @bio.  This falls back to the queue's root_blkg if
+ * the association fails with the css.
  */
-int bio_associate_blkcg(struct bio *bio, struct cgroup_subsys_state *blkcg_css)
+int bio_associate_blkg_from_css(struct bio *bio,
+                               struct cgroup_subsys_state *css)
 {
-       if (unlikely(bio->bi_css))
+       if (unlikely(bio->bi_blkg))
                return -EBUSY;
-       css_get(blkcg_css);
-       bio->bi_css = blkcg_css;
-       return 0;
+       return __bio_associate_blkg_from_css(bio, css);
 }
-EXPORT_SYMBOL_GPL(bio_associate_blkcg);
+EXPORT_SYMBOL_GPL(bio_associate_blkg_from_css);
 
+#ifdef CONFIG_MEMCG
 /**
- * bio_associate_blkg - associate a bio with the specified blkg
+ * bio_associate_blkg_from_page - associate a bio with the page's blkg
  * @bio: target bio
- * @blkg: the blkg to associate
+ * @page: the page to lookup the blkcg from
  *
- * 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.
+ * Associate @bio with the blkg from @page's owning memcg and the respective
+ * request_queue.  If cgroup_e_css returns NULL, fall back to the queue's
+ * root_blkg.
+ *
+ * Note: this must be called after bio has an associated device.
  */
-int bio_associate_blkg(struct bio *bio, struct blkcg_gq *blkg)
+int bio_associate_blkg_from_page(struct bio *bio, struct page *page)
 {
+       struct cgroup_subsys_state *css;
+       int ret;
+
        if (unlikely(bio->bi_blkg))
                return -EBUSY;
-       blkg_get(blkg);
-       bio->bi_blkg = blkg;
-       return 0;
+       if (!page->mem_cgroup)
+               return 0;
+
+       rcu_read_lock();
+
+       css = cgroup_e_css(page->mem_cgroup->css.cgroup, &io_cgrp_subsys);
+
+       ret = __bio_associate_blkg_from_css(bio, css);
+
+       rcu_read_unlock();
+       return ret;
+}
+#endif /* CONFIG_MEMCG */
+
+/**
+ * bio_associate_create_blkg - associate a bio with a blkg from q
+ * @q: request_queue where bio is going
+ * @bio: target bio
+ *
+ * Associate @bio with the blkg found from the bio's css and the request_queue.
+ * If one is not found, bio_lookup_blkg creates the blkg.  This falls back to
+ * the queue's root_blkg if association fails.
+ */
+int bio_associate_create_blkg(struct request_queue *q, struct bio *bio)
+{
+       struct cgroup_subsys_state *css;
+       int ret = 0;
+
+       /* someone has already associated this bio with a blkg */
+       if (bio->bi_blkg)
+               return ret;
+
+       rcu_read_lock();
+
+       css = blkcg_css();
+
+       ret = __bio_associate_blkg_from_css(bio, css);
+
+       rcu_read_unlock();
+       return ret;
 }
 
 /**
@@ -2030,10 +2093,6 @@ void bio_disassociate_task(struct bio *bio)
                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;
@@ -2041,16 +2100,16 @@ void bio_disassociate_task(struct bio *bio)
 }
 
 /**
- * bio_clone_blkcg_association - clone blkcg association from src to dst bio
+ * bio_clone_blkg_association - clone blkg association from src to dst bio
  * @dst: destination bio
  * @src: source bio
  */
-void bio_clone_blkcg_association(struct bio *dst, struct bio *src)
+void bio_clone_blkg_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);
+EXPORT_SYMBOL_GPL(bio_clone_blkg_association);
 #endif /* CONFIG_BLK_CGROUP */
 
 static void __init biovec_init_slabs(void)