block: ensure bio_iov_add_page can't fail
[linux-2.6-block.git] / block / bio.c
index 6f9f883f9a65ab76fb368997be0122324835d417..4740ba3cb9df352b526af33b7154d97de8ab91f2 100644 (file)
@@ -965,7 +965,7 @@ int bio_add_hw_page(struct request_queue *q, struct bio *bio,
                 * would create a gap, disallow it.
                 */
                bvec = &bio->bi_io_vec[bio->bi_vcnt - 1];
-               if (bvec_gap_to_prev(q, bvec, offset))
+               if (bvec_gap_to_prev(&q->limits, bvec, offset))
                        return 0;
        }
 
@@ -1165,8 +1165,6 @@ static int bio_iov_add_page(struct bio *bio, struct page *page,
        bool same_page = false;
 
        if (!__bio_try_merge_page(bio, page, len, offset, &same_page)) {
-               if (WARN_ON_ONCE(bio_full(bio, len)))
-                       return -EINVAL;
                __bio_add_page(bio, page, len, offset);
                return 0;
        }
@@ -1211,6 +1209,7 @@ static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
        ssize_t size, left;
        unsigned len, i;
        size_t offset;
+       int ret = 0;
 
        /*
         * Move page array up in the allocated memory for the bio vecs as far as
@@ -1227,7 +1226,8 @@ static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
         * result to ensure the bio's total size is correct. The remainder of
         * the iov data will be picked up in the next bio iteration.
         */
-       size = iov_iter_get_pages(iter, pages, LONG_MAX, nr_pages, &offset);
+       size = iov_iter_get_pages(iter, pages, UINT_MAX - bio->bi_iter.bi_size,
+                                 nr_pages, &offset);
        if (size > 0)
                size = ALIGN_DOWN(size, bdev_logical_block_size(bio->bi_bdev));
        if (unlikely(size <= 0))
@@ -1235,24 +1235,23 @@ static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
 
        for (left = size, i = 0; left > 0; left -= len, i++) {
                struct page *page = pages[i];
-               int ret;
 
                len = min_t(size_t, PAGE_SIZE - offset, left);
-               if (bio_op(bio) == REQ_OP_ZONE_APPEND)
+               if (bio_op(bio) == REQ_OP_ZONE_APPEND) {
                        ret = bio_iov_add_zone_append_page(bio, page, len,
                                        offset);
-               else
-                       ret = bio_iov_add_page(bio, page, len, offset);
+                       if (ret) {
+                               bio_put_pages(pages + i, left, offset);
+                               break;
+                       }
+               } else
+                       bio_iov_add_page(bio, page, len, offset);
 
-               if (ret) {
-                       bio_put_pages(pages + i, left, offset);
-                       return ret;
-               }
                offset = 0;
        }
 
-       iov_iter_advance(iter, size);
-       return 0;
+       iov_iter_advance(iter, size - left);
+       return ret;
 }
 
 /**