OSDN Git Service

power: supply: ltc2941-battery-gauge: fix use-after-free
[sagit-ice-cold/kernel_xiaomi_msm8998.git] / block / bio.c
index ad3f276..cf513f7 100644 (file)
@@ -211,7 +211,7 @@ fallback:
                bvl = mempool_alloc(pool, gfp_mask);
        } else {
                struct biovec_slab *bvs = bvec_slabs + *idx;
-               gfp_t __gfp_mask = gfp_mask & ~(__GFP_WAIT | __GFP_IO);
+               gfp_t __gfp_mask = gfp_mask & ~(__GFP_DIRECT_RECLAIM | __GFP_IO);
 
                /*
                 * Make this allocation restricted and don't dump info on
@@ -221,11 +221,11 @@ fallback:
                __gfp_mask |= __GFP_NOMEMALLOC | __GFP_NORETRY | __GFP_NOWARN;
 
                /*
-                * Try a slab allocation. If this fails and __GFP_WAIT
+                * Try a slab allocation. If this fails and __GFP_DIRECT_RECLAIM
                 * is set, retry with the 1-entry mempool
                 */
                bvl = kmem_cache_alloc(bvs->slab, __gfp_mask);
-               if (unlikely(!bvl && (gfp_mask & __GFP_WAIT))) {
+               if (unlikely(!bvl && (gfp_mask & __GFP_DIRECT_RECLAIM))) {
                        *idx = BIOVEC_MAX_IDX;
                        goto fallback;
                }
@@ -373,10 +373,14 @@ static void punt_bios_to_rescuer(struct bio_set *bs)
        bio_list_init(&punt);
        bio_list_init(&nopunt);
 
-       while ((bio = bio_list_pop(current->bio_list)))
+       while ((bio = bio_list_pop(&current->bio_list[0])))
                bio_list_add(bio->bi_pool == bs ? &punt : &nopunt, bio);
+       current->bio_list[0] = nopunt;
 
-       *current->bio_list = nopunt;
+       bio_list_init(&nopunt);
+       while ((bio = bio_list_pop(&current->bio_list[1])))
+               bio_list_add(bio->bi_pool == bs ? &punt : &nopunt, bio);
+       current->bio_list[1] = nopunt;
 
        spin_lock(&bs->rescue_lock);
        bio_list_merge(&bs->rescue_list, &punt);
@@ -395,12 +399,12 @@ static void punt_bios_to_rescuer(struct bio_set *bs)
  *   If @bs is NULL, uses kmalloc() to allocate the bio; else the allocation is
  *   backed by the @bs's mempool.
  *
- *   When @bs is not NULL, if %__GFP_WAIT is set then bio_alloc will always be
- *   able to allocate a bio. This is due to the mempool guarantees. To make this
- *   work, callers must never allocate more than 1 bio at a time from this pool.
- *   Callers that need to allocate more than 1 bio must always submit the
- *   previously allocated bio for IO before attempting to allocate a new one.
- *   Failure to do so can cause deadlocks under memory pressure.
+ *   When @bs is not NULL, if %__GFP_DIRECT_RECLAIM is set then bio_alloc will
+ *   always be able to allocate a bio. This is due to the mempool guarantees.
+ *   To make this work, callers must never allocate more than 1 bio at a time
+ *   from this pool. Callers that need to allocate more than 1 bio must always
+ *   submit the previously allocated bio for IO before attempting to allocate
+ *   a new one. Failure to do so can cause deadlocks under memory pressure.
  *
  *   Note that when running under generic_make_request() (i.e. any block
  *   driver), bios are not submitted until after you return - see the code in
@@ -459,13 +463,15 @@ struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs)
                 * We solve this, and guarantee forward progress, with a rescuer
                 * workqueue per bio_set. If we go to allocate and there are
                 * bios on current->bio_list, we first try the allocation
-                * without __GFP_WAIT; if that fails, we punt those bios we
-                * would be blocking to the rescuer workqueue before we retry
-                * with the original gfp_flags.
+                * without __GFP_DIRECT_RECLAIM; if that fails, we punt those
+                * bios we would be blocking to the rescuer workqueue before
+                * we retry with the original gfp_flags.
                 */
 
-               if (current->bio_list && !bio_list_empty(current->bio_list))
-                       gfp_mask &= ~__GFP_WAIT;
+               if (current->bio_list &&
+                   (!bio_list_empty(&current->bio_list[0]) ||
+                    !bio_list_empty(&current->bio_list[1])))
+                       gfp_mask &= ~__GFP_DIRECT_RECLAIM;
 
                p = mempool_alloc(bs->bio_pool, gfp_mask);
                if (!p && gfp_mask != saved_gfp) {
@@ -584,6 +590,8 @@ void __bio_clone_fast(struct bio *bio, struct bio *bio_src)
        bio->bi_rw = bio_src->bi_rw;
        bio->bi_iter = bio_src->bi_iter;
        bio->bi_io_vec = bio_src->bi_io_vec;
+
+       bio_clone_blkcg_association(bio, bio_src);
 }
 EXPORT_SYMBOL(__bio_clone_fast);
 
@@ -689,6 +697,8 @@ integrity_clone:
                }
        }
 
+       bio_clone_blkcg_association(bio, bio_src);
+
        return bio;
 }
 EXPORT_SYMBOL(bio_clone_bioset);
@@ -1090,9 +1100,12 @@ int bio_uncopy_user(struct bio *bio)
        if (!bio_flagged(bio, BIO_NULL_MAPPED)) {
                /*
                 * if we're in a workqueue, the request is orphaned, so
-                * don't copy into a random user address space, just free.
+                * don't copy into a random user address space, just free
+                * and return -EINTR so user space doesn't expect any data.
                 */
-               if (current->mm && bio_data_dir(bio) == READ)
+               if (!current->mm)
+                       ret = -EINTR;
+               else if (bio_data_dir(bio) == READ)
                        ret = bio_copy_to_iter(bio, bmd->iter);
                if (bmd->is_our_pages)
                        bio_free_pages(bio);
@@ -1203,8 +1216,11 @@ struct bio *bio_copy_user_iov(struct request_queue *q,
                        }
                }
 
-               if (bio_add_pc_page(q, bio, page, bytes, offset) < bytes)
+               if (bio_add_pc_page(q, bio, page, bytes, offset) < bytes) {
+                       if (!map_data)
+                               __free_page(page);
                        break;
+               }
 
                len -= bytes;
                offset = 0;
@@ -1255,6 +1271,7 @@ struct bio *bio_map_user_iov(struct request_queue *q,
        int ret, offset;
        struct iov_iter i;
        struct iovec iov;
+       struct bio_vec *bvec;
 
        iov_for_each(iov, i, *iter) {
                unsigned long uaddr = (unsigned long) iov.iov_base;
@@ -1299,7 +1316,12 @@ struct bio *bio_map_user_iov(struct request_queue *q,
                ret = get_user_pages_fast(uaddr, local_nr_pages,
                                (iter->type & WRITE) != WRITE,
                                &pages[cur_page]);
-               if (ret < local_nr_pages) {
+               if (unlikely(ret < local_nr_pages)) {
+                       for (j = cur_page; j < page_limit; j++) {
+                               if (!pages[j])
+                                       break;
+                               put_page(pages[j]);
+                       }
                        ret = -EFAULT;
                        goto out_unmap;
                }
@@ -1307,6 +1329,7 @@ struct bio *bio_map_user_iov(struct request_queue *q,
                offset = uaddr & ~PAGE_MASK;
                for (j = cur_page; j < page_limit; j++) {
                        unsigned int bytes = PAGE_SIZE - offset;
+                       unsigned short prev_bi_vcnt = bio->bi_vcnt;
 
                        if (len <= 0)
                                break;
@@ -1321,6 +1344,13 @@ struct bio *bio_map_user_iov(struct request_queue *q,
                                            bytes)
                                break;
 
+                       /*
+                        * check if vector was merged with previous
+                        * drop page reference if needed
+                        */
+                       if (bio->bi_vcnt == prev_bi_vcnt)
+                               put_page(pages[j]);
+
                        len -= bytes;
                        offset = 0;
                }
@@ -1353,10 +1383,8 @@ struct bio *bio_map_user_iov(struct request_queue *q,
        return bio;
 
  out_unmap:
-       for (j = 0; j < nr_pages; j++) {
-               if (!pages[j])
-                       break;
-               page_cache_release(pages[j]);
+       bio_for_each_segment_all(bvec, bio, j) {
+               put_page(bvec->bv_page);
        }
  out:
        kfree(pages);
@@ -2011,6 +2039,17 @@ void bio_disassociate_task(struct bio *bio)
        }
 }
 
+/**
+ * bio_clone_blkcg_association - clone blkcg association from src to dst bio
+ * @dst: destination bio
+ * @src: source bio
+ */
+void bio_clone_blkcg_association(struct bio *dst, struct bio *src)
+{
+       if (src->bi_css)
+               WARN_ON(bio_associate_blkcg(dst, src->bi_css));
+}
+
 #endif /* CONFIG_BLK_CGROUP */
 
 static void __init biovec_init_slabs(void)