Btrfs: add support for blkio controllers
authorChris Mason <clm@fb.com>
Thu, 2 Jul 2015 20:57:22 +0000 (13:57 -0700)
committerChris Mason <clm@fb.com>
Sun, 9 Aug 2015 14:35:06 +0000 (07:35 -0700)
This attaches accounting information to bios as we submit them so the
new blkio controllers can throttle on btrfs filesystems.

Not much is required, we're just associating bios with blkcgs during clone,
calling wbc_init_bio()/wbc_account_io() during writepages submission,
and attaching the bios to the current context during direct IO.

Finally if we are splitting bios during btrfs_map_bio, this attaches
accounting information to the split.

The end result is able to throttle nicely on single disk filesystems.  A
little more work is required for multi-device filesystems.

Signed-off-by: Chris Mason <clm@fb.com>
fs/btrfs/disk-io.c
fs/btrfs/extent_io.c
fs/btrfs/inode.c
fs/btrfs/super.c
fs/btrfs/volumes.c

index f7536bcf7ceec893c7ed9a3fcfe70752e9aedecf..230546b45474253a16e8db8f8f7b24c1659ad726 100644 (file)
@@ -1724,6 +1724,7 @@ static int setup_bdi(struct btrfs_fs_info *info, struct backing_dev_info *bdi)
        bdi->ra_pages = VM_MAX_READAHEAD * 1024 / PAGE_CACHE_SIZE;
        bdi->congested_fn       = btrfs_congested_fn;
        bdi->congested_data     = info;
+       bdi->capabilities |= BDI_CAP_CGROUP_WRITEBACK;
        return 0;
 }
 
index 02d05817cbdfe8330add4bbefd424ea1058cb09d..b9755ce982182469873eaf0bf77ed356b7e1a4da 100644 (file)
@@ -2730,6 +2730,9 @@ struct bio *btrfs_bio_clone(struct bio *bio, gfp_t gfp_mask)
                btrfs_bio->csum = NULL;
                btrfs_bio->csum_allocated = NULL;
                btrfs_bio->end_io = NULL;
+               /* FIXME, put this into bio_clone_bioset */
+               if (bio->bi_css)
+                       bio_associate_blkcg(new, bio->bi_css);
        }
        return new;
 }
@@ -2790,6 +2793,7 @@ static int merge_bio(int rw, struct extent_io_tree *tree, struct page *page,
 }
 
 static int submit_extent_page(int rw, struct extent_io_tree *tree,
+                             struct writeback_control *wbc,
                              struct page *page, sector_t sector,
                              size_t size, unsigned long offset,
                              struct block_device *bdev,
@@ -2826,6 +2830,8 @@ static int submit_extent_page(int rw, struct extent_io_tree *tree,
                        }
                        bio = NULL;
                } else {
+                       if (wbc)
+                               wbc_account_io(wbc, page, page_size);
                        return 0;
                }
        }
@@ -2841,6 +2847,10 @@ static int submit_extent_page(int rw, struct extent_io_tree *tree,
        bio_add_page(bio, page, page_size, offset);
        bio->bi_end_io = end_io_func;
        bio->bi_private = tree;
+       if (wbc) {
+               wbc_init_bio(wbc, bio);
+               wbc_account_io(wbc, page, page_size);
+       }
 
        if (bio_ret)
                *bio_ret = bio;
@@ -3051,7 +3061,7 @@ static int __do_readpage(struct extent_io_tree *tree,
                }
 
                pnr -= page->index;
-               ret = submit_extent_page(rw, tree, page,
+               ret = submit_extent_page(rw, tree, NULL, page,
                                         sector, disk_io_size, pg_offset,
                                         bdev, bio, pnr,
                                         end_bio_extent_readpage, mirror_num,
@@ -3446,7 +3456,7 @@ static noinline_for_stack int __extent_writepage_io(struct inode *inode,
                                       page->index, cur, end);
                        }
 
-                       ret = submit_extent_page(write_flags, tree, page,
+                       ret = submit_extent_page(write_flags, tree, wbc, page,
                                                 sector, iosize, pg_offset,
                                                 bdev, &epd->bio, max_nr,
                                                 end_bio_extent_writepage,
@@ -3749,7 +3759,7 @@ static noinline_for_stack int write_one_eb(struct extent_buffer *eb,
 
                clear_page_dirty_for_io(p);
                set_page_writeback(p);
-               ret = submit_extent_page(rw, tree, p, offset >> 9,
+               ret = submit_extent_page(rw, tree, wbc, p, offset >> 9,
                                         PAGE_CACHE_SIZE, 0, bdev, &epd->bio,
                                         -1, end_bio_extent_buffer_writepage,
                                         0, epd->bio_flags, bio_flags);
index 79a73645346e0e2cb59462f29acc980b1bbe31df..bda3c41dc9d5afa5912f35f2ec5543e81fdabde6 100644 (file)
@@ -7987,7 +7987,11 @@ static struct bio *btrfs_dio_bio_alloc(struct block_device *bdev,
                                       u64 first_sector, gfp_t gfp_flags)
 {
        int nr_vecs = bio_get_nr_vecs(bdev);
-       return btrfs_bio_alloc(bdev, first_sector, nr_vecs, gfp_flags);
+       struct bio *bio;
+       bio = btrfs_bio_alloc(bdev, first_sector, nr_vecs, gfp_flags);
+       if (bio)
+               bio_associate_current(bio);
+       return bio;
 }
 
 static inline int btrfs_lookup_and_bind_dio_csum(struct btrfs_root *root,
index cd7ef34d2dce99987fe87f3040ba20038bb3f041..d366dd4664d066269e9394403c060fece1a9100d 100644 (file)
@@ -1033,6 +1033,7 @@ static int btrfs_fill_super(struct super_block *sb,
        sb->s_flags |= MS_POSIXACL;
 #endif
        sb->s_flags |= MS_I_VERSION;
+       sb->s_iflags |= SB_I_CGROUPWB;
        err = open_ctree(sb, fs_devices, (char *)data);
        if (err) {
                printk(KERN_ERR "BTRFS: open_ctree failed\n");
index fb9abf1678d05e5016e5f8a8e1ba3e231f2363a8..88e2fe931bde2320b4df5a7e9310dff76e2a3bca 100644 (file)
@@ -5942,6 +5942,14 @@ again:
        if (!bio)
                return -ENOMEM;
 
+       if (first_bio->bi_ioc) {
+               get_io_context_active(first_bio->bi_ioc);
+               bio->bi_ioc = first_bio->bi_ioc;
+       }
+       if (first_bio->bi_css) {
+               css_get(first_bio->bi_css);
+               bio->bi_css = first_bio->bi_css;
+       }
        while (bvec <= (first_bio->bi_io_vec + first_bio->bi_vcnt - 1)) {
                if (bio_add_page(bio, bvec->bv_page, bvec->bv_len,
                                 bvec->bv_offset) < bvec->bv_len) {