btrfs: determine stripe boundary at bio allocation time in btrfs_submit_compressed_read
[sfrench/cifs-2.6.git] / fs / btrfs / compression.c
index 13814737420cd66111ac0e258ba634ee6037e38d..f3cb18afec209ad0dce0fce9b741cf4d5d9a8975 100644 (file)
@@ -435,12 +435,31 @@ static blk_status_t submit_compressed_bio(struct btrfs_fs_info *fs_info,
 }
 
 /*
- * Allocate a compressed_bio, which will be used to read/write on-disk data.
+ * Allocate a compressed_bio, which will be used to read/write on-disk
+ * (aka, compressed) * data.
+ *
+ * @cb:                 The compressed_bio structure, which records all the needed
+ *                      information to bind the compressed data to the uncompressed
+ *                      page cache.
+ * @disk_byten:         The logical bytenr where the compressed data will be read
+ *                      from or written to.
+ * @endio_func:         The endio function to call after the IO for compressed data
+ *                      is finished.
+ * @next_stripe_start:  Return value of logical bytenr of where next stripe starts.
+ *                      Let the caller know to only fill the bio up to the stripe
+ *                      boundary.
  */
+
+
 static struct bio *alloc_compressed_bio(struct compressed_bio *cb, u64 disk_bytenr,
-                                       unsigned int opf, bio_end_io_t endio_func)
+                                       unsigned int opf, bio_end_io_t endio_func,
+                                       u64 *next_stripe_start)
 {
+       struct btrfs_fs_info *fs_info = btrfs_sb(cb->inode->i_sb);
+       struct btrfs_io_geometry geom;
+       struct extent_map *em;
        struct bio *bio;
+       int ret;
 
        bio = btrfs_bio_alloc(BIO_MAX_VECS);
 
@@ -449,18 +468,23 @@ static struct bio *alloc_compressed_bio(struct compressed_bio *cb, u64 disk_byte
        bio->bi_private = cb;
        bio->bi_end_io = endio_func;
 
-       if (bio_op(bio) == REQ_OP_ZONE_APPEND) {
-               struct btrfs_fs_info *fs_info = btrfs_sb(cb->inode->i_sb);
-               struct btrfs_device *device;
+       em = btrfs_get_chunk_map(fs_info, disk_bytenr, fs_info->sectorsize);
+       if (IS_ERR(em)) {
+               bio_put(bio);
+               return ERR_CAST(em);
+       }
 
-               device = btrfs_zoned_get_device(fs_info, disk_bytenr,
-                                               fs_info->sectorsize);
-               if (IS_ERR(device)) {
-                       bio_put(bio);
-                       return ERR_CAST(device);
-               }
-               bio_set_dev(bio, device->bdev);
+       if (bio_op(bio) == REQ_OP_ZONE_APPEND)
+               bio_set_dev(bio, em->map_lookup->stripes[0].dev->bdev);
+
+       ret = btrfs_get_io_geometry(fs_info, em, btrfs_op(bio), disk_bytenr, &geom);
+       free_extent_map(em);
+       if (ret < 0) {
+               bio_put(bio);
+               return ERR_PTR(ret);
        }
+       *next_stripe_start = disk_bytenr + geom.len;
+
        return bio;
 }
 
@@ -488,6 +512,7 @@ blk_status_t btrfs_submit_compressed_write(struct btrfs_inode *inode, u64 start,
        int pg_index = 0;
        struct page *page;
        u64 first_byte = disk_start;
+       u64 next_stripe_start;
        blk_status_t ret;
        int skip_sum = inode->flags & BTRFS_INODE_NODATASUM;
        const bool use_append = btrfs_use_zone_append(inode, disk_start);
@@ -510,7 +535,7 @@ blk_status_t btrfs_submit_compressed_write(struct btrfs_inode *inode, u64 start,
        cb->nr_pages = nr_pages;
 
        bio = alloc_compressed_bio(cb, first_byte, bio_op | write_flags,
-                                  end_compressed_bio_write);
+                                  end_compressed_bio_write, &next_stripe_start);
        if (IS_ERR(bio)) {
                kfree(cb);
                return errno_to_blk_status(PTR_ERR(bio));
@@ -559,7 +584,8 @@ blk_status_t btrfs_submit_compressed_write(struct btrfs_inode *inode, u64 start,
 
                        bio = alloc_compressed_bio(cb, first_byte,
                                        bio_op | write_flags,
-                                       end_compressed_bio_write);
+                                       end_compressed_bio_write,
+                                       &next_stripe_start);
                        if (IS_ERR(bio)) {
                                ret = errno_to_blk_status(PTR_ERR(bio));
                                bio = NULL;
@@ -790,9 +816,10 @@ blk_status_t btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
        unsigned int compressed_len;
        unsigned int nr_pages;
        unsigned int pg_index;
-       struct page *page;
-       struct bio *comp_bio;
-       u64 cur_disk_byte = bio->bi_iter.bi_sector << 9;
+       struct bio *comp_bio = NULL;
+       const u64 disk_bytenr = bio->bi_iter.bi_sector << SECTOR_SHIFT;
+       u64 cur_disk_byte = disk_bytenr;
+       u64 next_stripe_start;
        u64 file_offset;
        u64 em_len;
        u64 em_start;
@@ -860,39 +887,58 @@ blk_status_t btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
        /* include any pages we added in add_ra-bio_pages */
        cb->len = bio->bi_iter.bi_size;
 
-       comp_bio = alloc_compressed_bio(cb, cur_disk_byte, REQ_OP_READ,
-                                       end_compressed_bio_read);
-       if (IS_ERR(comp_bio)) {
-               ret = errno_to_blk_status(PTR_ERR(comp_bio));
-               comp_bio = NULL;
-               goto fail2;
-       }
+       while (cur_disk_byte < disk_bytenr + compressed_len) {
+               u64 offset = cur_disk_byte - disk_bytenr;
+               unsigned int index = offset >> PAGE_SHIFT;
+               unsigned int real_size;
+               unsigned int added;
+               struct page *page = cb->compressed_pages[index];
+               bool submit = false;
 
-       for (pg_index = 0; pg_index < nr_pages; pg_index++) {
-               u32 pg_len = PAGE_SIZE;
-               int submit = 0;
+               /* Allocate new bio if submitted or not yet allocated */
+               if (!comp_bio) {
+                       comp_bio = alloc_compressed_bio(cb, cur_disk_byte,
+                                       REQ_OP_READ, end_compressed_bio_read,
+                                       &next_stripe_start);
+                       if (IS_ERR(comp_bio)) {
+                               ret = errno_to_blk_status(PTR_ERR(comp_bio));
+                               comp_bio = NULL;
+                               goto finish_cb;
+                       }
+               }
+               /*
+                * We should never reach next_stripe_start start as we will
+                * submit comp_bio when reach the boundary immediately.
+                */
+               ASSERT(cur_disk_byte != next_stripe_start);
+               /*
+                * We have various limit on the real read size:
+                * - stripe boundary
+                * - page boundary
+                * - compressed length boundary
+                */
+               real_size = min_t(u64, U32_MAX, next_stripe_start - cur_disk_byte);
+               real_size = min_t(u64, real_size, PAGE_SIZE - offset_in_page(offset));
+               real_size = min_t(u64, real_size, compressed_len - offset);
+               ASSERT(IS_ALIGNED(real_size, fs_info->sectorsize));
 
+               added = bio_add_page(comp_bio, page, real_size, offset_in_page(offset));
                /*
-                * To handle subpage case, we need to make sure the bio only
-                * covers the range we need.
-                *
-                * If we're at the last page, truncate the length to only cover
-                * the remaining part.
+                * Maximum compressed extent is smaller than bio size limit,
+                * thus bio_add_page() should always success.
                 */
-               if (pg_index == nr_pages - 1)
-                       pg_len = min_t(u32, PAGE_SIZE,
-                                       compressed_len - pg_index * PAGE_SIZE);
+               ASSERT(added == real_size);
+               cur_disk_byte += added;
 
-               page = cb->compressed_pages[pg_index];
-               page->mapping = inode->i_mapping;
-               page->index = em_start >> PAGE_SHIFT;
+               /* Reached stripe boundary, need to submit */
+               if (cur_disk_byte == next_stripe_start)
+                       submit = true;
 
-               if (comp_bio->bi_iter.bi_size)
-                       submit = btrfs_bio_fits_in_stripe(page, pg_len,
-                                                         comp_bio, 0);
+               /* Has finished the range, need to submit */
+               if (cur_disk_byte == disk_bytenr + compressed_len)
+                       submit = true;
 
-               page->mapping = NULL;
-               if (submit || bio_add_page(comp_bio, page, pg_len, 0) < pg_len) {
+               if (submit) {
                        unsigned int nr_sectors;
 
                        ret = btrfs_lookup_bio_sums(inode, comp_bio, sums);
@@ -906,29 +952,9 @@ blk_status_t btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
                        ret = submit_compressed_bio(fs_info, cb, comp_bio, mirror_num);
                        if (ret)
                                goto finish_cb;
-
-                       comp_bio = alloc_compressed_bio(cb, cur_disk_byte,
-                                       REQ_OP_READ,
-                                       end_compressed_bio_read);
-                       if (IS_ERR(comp_bio)) {
-                               ret = errno_to_blk_status(PTR_ERR(comp_bio));
-                               comp_bio = NULL;
-                               goto finish_cb;
-                       }
-
-                       bio_add_page(comp_bio, page, pg_len, 0);
+                       comp_bio = NULL;
                }
-               cur_disk_byte += pg_len;
        }
-
-       ret = btrfs_lookup_bio_sums(inode, comp_bio, sums);
-       if (ret)
-               goto last_bio;
-
-       ret = submit_compressed_bio(fs_info, cb, comp_bio, mirror_num);
-       if (ret)
-               goto last_bio;
-
        return 0;
 
 fail2:
@@ -943,18 +969,18 @@ fail1:
 out:
        free_extent_map(em);
        return ret;
-last_bio:
-       comp_bio->bi_status = ret;
-       /* This is the last bio, endio functions will free @cb */
-       bio_endio(comp_bio);
-       return ret;
-
 finish_cb:
        if (comp_bio) {
                comp_bio->bi_status = ret;
                bio_endio(comp_bio);
        }
-       wait_var_event(cb, atomic_read(&cb->pending_bios) == 0);
+       /* All bytes of @cb is submitted, endio will free @cb */
+       if (cur_disk_byte == disk_bytenr + compressed_len)
+               return ret;
+
+       wait_var_event(cb, refcount_read(&cb->pending_sectors) ==
+                          (disk_bytenr + compressed_len - cur_disk_byte) >>
+                          fs_info->sectorsize_bits);
        /*
         * Even with previous bio ended, we should still have io not yet
         * submitted, thus need to finish @cb manually.