]> git.ipfire.org Git - thirdparty/kernel/stable.git/blobdiff - block/bio.c
lkdtm: Add tests for NULL pointer dereference
[thirdparty/kernel/stable.git] / block / bio.c
index 101c2a9b548150cd3f7bb5b28a460ef82c9e4a75..d01ab919b31390c8f8b92618fe87d41cc0d0d2ca 100644 (file)
@@ -43,9 +43,9 @@
  * break badly! cannot be bigger than what you can fit into an
  * unsigned short
  */
-#define BV(x) { .nr_vecs = x, .name = "biovec-"__stringify(x) }
+#define BV(x, n) { .nr_vecs = x, .name = "biovec-"#n }
 static struct biovec_slab bvec_slabs[BVEC_POOL_NR] __read_mostly = {
-       BV(1), BV(4), BV(16), BV(64), BV(128), BV(BIO_MAX_PAGES),
+       BV(1, 1), BV(4, 4), BV(16, 16), BV(64, 64), BV(128, 128), BV(BIO_MAX_PAGES, max),
 };
 #undef BV
 
@@ -156,7 +156,7 @@ out:
 
 unsigned int bvec_nr_vecs(unsigned short idx)
 {
-       return bvec_slabs[idx].nr_vecs;
+       return bvec_slabs[--idx].nr_vecs;
 }
 
 void bvec_free(mempool_t *pool, struct bio_vec *bv, unsigned int idx)
@@ -597,7 +597,10 @@ void __bio_clone_fast(struct bio *bio, struct bio *bio_src)
         * so we don't set nor calculate new physical/hw segment counts here
         */
        bio->bi_disk = bio_src->bi_disk;
+       bio->bi_partno = bio_src->bi_partno;
        bio_set_flag(bio, BIO_CLONED);
+       if (bio_flagged(bio_src, BIO_THROTTLED))
+               bio_set_flag(bio, BIO_THROTTLED);
        bio->bi_opf = bio_src->bi_opf;
        bio->bi_write_hint = bio_src->bi_write_hint;
        bio->bi_iter = bio_src->bi_iter;
@@ -878,16 +881,16 @@ EXPORT_SYMBOL(bio_add_page);
  */
 int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
 {
-       unsigned short nr_pages = bio->bi_max_vecs - bio->bi_vcnt;
+       unsigned short nr_pages = bio->bi_max_vecs - bio->bi_vcnt, idx;
        struct bio_vec *bv = bio->bi_io_vec + bio->bi_vcnt;
        struct page **pages = (struct page **)bv;
-       size_t offset, diff;
+       size_t offset;
        ssize_t size;
 
        size = iov_iter_get_pages(iter, pages, LONG_MAX, nr_pages, &offset);
        if (unlikely(size <= 0))
                return size ? size : -EFAULT;
-       nr_pages = (size + offset + PAGE_SIZE - 1) / PAGE_SIZE;
+       idx = nr_pages = (size + offset + PAGE_SIZE - 1) / PAGE_SIZE;
 
        /*
         * Deep magic below:  We need to walk the pinned pages backwards
@@ -900,17 +903,15 @@ int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
        bio->bi_iter.bi_size += size;
        bio->bi_vcnt += nr_pages;
 
-       diff = (nr_pages * PAGE_SIZE - offset) - size;
-       while (nr_pages--) {
-               bv[nr_pages].bv_page = pages[nr_pages];
-               bv[nr_pages].bv_len = PAGE_SIZE;
-               bv[nr_pages].bv_offset = 0;
+       while (idx--) {
+               bv[idx].bv_page = pages[idx];
+               bv[idx].bv_len = PAGE_SIZE;
+               bv[idx].bv_offset = 0;
        }
 
        bv[0].bv_offset += offset;
        bv[0].bv_len -= offset;
-       if (diff)
-               bv[bio->bi_vcnt - 1].bv_len -= diff;
+       bv[nr_pages - 1].bv_len -= nr_pages * PAGE_SIZE - offset - size;
 
        iov_iter_advance(iter, size);
        return 0;
@@ -1279,8 +1280,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;
@@ -1888,9 +1892,10 @@ 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(bio, BIO_TRACE_COMPLETION);
+               bio_set_flag(split, BIO_TRACE_COMPLETION);
 
        return split;
 }