libceph: export osd_req_op_data() macro
[linux-2.6-microblaze.git] / block / bio.c
index 683cbb4..ce797d7 100644 (file)
@@ -636,7 +636,7 @@ EXPORT_SYMBOL(bio_clone_fast);
 
 static inline bool page_is_mergeable(const struct bio_vec *bv,
                struct page *page, unsigned int len, unsigned int off,
-               bool same_page)
+               bool *same_page)
 {
        phys_addr_t vec_end_addr = page_to_phys(bv->bv_page) +
                bv->bv_offset + bv->bv_len - 1;
@@ -647,15 +647,9 @@ static inline bool page_is_mergeable(const struct bio_vec *bv,
        if (xen_domain() && !xen_biovec_phys_mergeable(bv, page))
                return false;
 
-       if ((vec_end_addr & PAGE_MASK) != page_addr) {
-               if (same_page)
-                       return false;
-               if (pfn_to_page(PFN_DOWN(vec_end_addr)) + 1 != page)
-                       return false;
-       }
-
-       WARN_ON_ONCE(same_page && (len + off) > PAGE_SIZE);
-
+       *same_page = ((vec_end_addr & PAGE_MASK) == page_addr);
+       if (!*same_page && pfn_to_page(PFN_DOWN(vec_end_addr)) + 1 != page)
+               return false;
        return true;
 }
 
@@ -701,6 +695,7 @@ static int __bio_add_pc_page(struct request_queue *q, struct bio *bio,
                bool put_same_page)
 {
        struct bio_vec *bvec;
+       bool same_page = false;
 
        /*
         * cloned bio must not modify vec list
@@ -729,7 +724,7 @@ static int __bio_add_pc_page(struct request_queue *q, struct bio *bio,
                if (bvec_gap_to_prev(q, bvec, offset))
                        return 0;
 
-               if (page_is_mergeable(bvec, page, len, offset, false) &&
+               if (page_is_mergeable(bvec, page, len, offset, &same_page) &&
                    can_add_page_to_seg(q, bvec, page, len, offset)) {
                        bvec->bv_len += len;
                        goto done;
@@ -767,8 +762,7 @@ EXPORT_SYMBOL(bio_add_pc_page);
  * @page: start page to add
  * @len: length of the data to add
  * @off: offset of the data relative to @page
- * @same_page: if %true only merge if the new data is in the same physical
- *             page as the last segment of the bio.
+ * @same_page: return if the segment has been merged inside the same page
  *
  * Try to add the data at @page + @off to the last bvec of @bio.  This is a
  * a useful optimisation for file systems with a block size smaller than the
@@ -779,7 +773,7 @@ EXPORT_SYMBOL(bio_add_pc_page);
  * Return %true on success or %false on failure.
  */
 bool __bio_try_merge_page(struct bio *bio, struct page *page,
-               unsigned int len, unsigned int off, bool same_page)
+               unsigned int len, unsigned int off, bool *same_page)
 {
        if (WARN_ON_ONCE(bio_flagged(bio, BIO_CLONED)))
                return false;
@@ -837,7 +831,9 @@ EXPORT_SYMBOL_GPL(__bio_add_page);
 int bio_add_page(struct bio *bio, struct page *page,
                 unsigned int len, unsigned int offset)
 {
-       if (!__bio_try_merge_page(bio, page, len, offset, false)) {
+       bool same_page = false;
+
+       if (!__bio_try_merge_page(bio, page, len, offset, &same_page)) {
                if (bio_full(bio))
                        return 0;
                __bio_add_page(bio, page, len, offset);
@@ -900,6 +896,7 @@ static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
        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;
+       bool same_page = false;
        ssize_t size, left;
        unsigned len, i;
        size_t offset;
@@ -920,8 +917,15 @@ static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
                struct page *page = pages[i];
 
                len = min_t(size_t, PAGE_SIZE - offset, left);
-               if (WARN_ON_ONCE(bio_add_page(bio, page, len, offset) != len))
-                       return -EINVAL;
+
+               if (__bio_try_merge_page(bio, page, len, offset, &same_page)) {
+                       if (same_page)
+                               put_page(page);
+               } else {
+                       if (WARN_ON_ONCE(bio_full(bio)))
+                                return -EINVAL;
+                       __bio_add_page(bio, page, len, offset);
+               }
                offset = 0;
        }