Skip to content

Commit

Permalink
Btrfs: Avoid unplug storms during commit
Browse files Browse the repository at this point in the history
While doing a commit, btrfs makes sure all the metadata blocks
were properly written to disk, calling wait_on_page_writeback for
each page.  This writeback happens after allowing another transaction
to start, so it competes for the disk with other processes in the FS.

If the page writeback bit is still set, each wait_on_page_writeback might
trigger an unplug, even though the page might be waiting for checksumming
to finish or might be waiting for the async work queue to submit the
bio.

This trades wait_on_page_writeback for waiting on the extent writeback
bits.  It won't trigger any unplugs and substantially improves performance
in a number of workloads.

This also changes the async bio submission to avoid requeueing if there
is only one device.  The requeue just wastes CPU time because there are
no other devices to service.

Signed-off-by: Chris Mason <chris.mason@oracle.com>
  • Loading branch information
Chris Mason committed Nov 7, 2008
1 parent 42e70e7 commit 5f2cc08
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 2 deletions.
30 changes: 29 additions & 1 deletion fs/btrfs/transaction.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <linux/sched.h>
#include <linux/writeback.h>
#include <linux/pagemap.h>
#include <linux/blkdev.h>
#include "ctree.h"
#include "disk-io.h"
#include "transaction.h"
Expand Down Expand Up @@ -331,6 +332,7 @@ int btrfs_write_and_wait_marked_extents(struct btrfs_root *root,
int werr = 0;
struct page *page;
struct inode *btree_inode = root->fs_info->btree_inode;
struct extent_io_tree *io_tree = &BTRFS_I(btree_inode)->io_tree;
u64 start = 0;
u64 end;
unsigned long index;
Expand Down Expand Up @@ -371,6 +373,11 @@ int btrfs_write_and_wait_marked_extents(struct btrfs_root *root,
page_cache_release(page);
}
}
/*
* we unplug once and then use the wait_on_extent_bit for
* everything else
*/
blk_run_address_space(btree_inode->i_mapping);
while(1) {
ret = find_first_extent_bit(dirty_pages, 0, &start, &end,
EXTENT_DIRTY);
Expand All @@ -391,7 +398,28 @@ int btrfs_write_and_wait_marked_extents(struct btrfs_root *root,
if (err)
werr = err;
}
wait_on_page_writeback(page);
if (PageWriteback(page)) {
/*
* we don't wait on the page writeback bit
* because that triggers a lot of unplugs.
* The extent bits are much nicer to
* the disks, but come with a slightly
* higher latency because we aren't forcing
* unplugs.
*/
wait_on_extent_writeback(io_tree,
page_offset(page),
page_offset(page) +
PAGE_CACHE_SIZE - 1);
}
if (PageWriteback(page)) {
/*
* the state bits get cleared before the
* page bits, lets add some extra
* paranoia here
*/
wait_on_page_writeback(page);
}
page_cache_release(page);
cond_resched();
}
Expand Down
3 changes: 2 additions & 1 deletion fs/btrfs/volumes.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,8 @@ static int noinline run_scheduled_bios(struct btrfs_device *device)
* is now congested. Back off and let other work structs
* run instead
*/
if (pending && bdi_write_congested(bdi)) {
if (pending && bdi_write_congested(bdi) &&
fs_info->fs_devices->open_devices > 1) {
struct bio *old_head;

spin_lock(&device->io_lock);
Expand Down

0 comments on commit 5f2cc08

Please sign in to comment.