Commit de0022b9 authored by Josef Bacik's avatar Josef Bacik Committed by Chris Mason

Btrfs: do not async metadata csumming in certain situations

There are a coule scenarios where farming metadata csumming off to an async
thread doesn't help.  The first is if our processor supports crc32c, in
which case the csumming will be fast and so the overhead of the async model
is not worth the cost.  The other case is for our tree log.  We will be
making that stuff dirty and writing it out and waiting for it immediately.
Even with software crc32c this gives me a ~15% increase in speed with O_SYNC
workloads.  Thanks,
Signed-off-by: default avatarJosef Bacik <jbacik@fusionio.com>
parent 221b8318
...@@ -46,6 +46,10 @@ ...@@ -46,6 +46,10 @@
#include "check-integrity.h" #include "check-integrity.h"
#include "rcu-string.h" #include "rcu-string.h"
#ifdef CONFIG_X86
#include <asm/cpufeature.h>
#endif
static struct extent_io_ops btree_extent_io_ops; static struct extent_io_ops btree_extent_io_ops;
static void end_workqueue_fn(struct btrfs_work *work); static void end_workqueue_fn(struct btrfs_work *work);
static void free_fs_root(struct btrfs_root *root); static void free_fs_root(struct btrfs_root *root);
...@@ -859,10 +863,22 @@ static int __btree_submit_bio_done(struct inode *inode, int rw, struct bio *bio, ...@@ -859,10 +863,22 @@ static int __btree_submit_bio_done(struct inode *inode, int rw, struct bio *bio,
return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio, mirror_num, 1); return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio, mirror_num, 1);
} }
static int check_async_write(struct inode *inode, unsigned long bio_flags)
{
if (bio_flags & EXTENT_BIO_TREE_LOG)
return 0;
#ifdef CONFIG_X86
if (cpu_has_xmm4_2)
return 0;
#endif
return 1;
}
static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio, static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
int mirror_num, unsigned long bio_flags, int mirror_num, unsigned long bio_flags,
u64 bio_offset) u64 bio_offset)
{ {
int async = check_async_write(inode, bio_flags);
int ret; int ret;
if (!(rw & REQ_WRITE)) { if (!(rw & REQ_WRITE)) {
...@@ -877,6 +893,12 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio, ...@@ -877,6 +893,12 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
return ret; return ret;
return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio, return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio,
mirror_num, 0); mirror_num, 0);
} else if (!async) {
ret = btree_csum_one_bio(bio);
if (ret)
return ret;
return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio,
mirror_num, 0);
} }
/* /*
......
...@@ -45,6 +45,7 @@ struct extent_page_data { ...@@ -45,6 +45,7 @@ struct extent_page_data {
struct bio *bio; struct bio *bio;
struct extent_io_tree *tree; struct extent_io_tree *tree;
get_extent_t *get_extent; get_extent_t *get_extent;
unsigned long bio_flags;
/* tells writepage not to lock the state bits for this range /* tells writepage not to lock the state bits for this range
* it still does the unlocking * it still does the unlocking
...@@ -3163,12 +3164,16 @@ static int write_one_eb(struct extent_buffer *eb, ...@@ -3163,12 +3164,16 @@ static int write_one_eb(struct extent_buffer *eb,
struct block_device *bdev = fs_info->fs_devices->latest_bdev; struct block_device *bdev = fs_info->fs_devices->latest_bdev;
u64 offset = eb->start; u64 offset = eb->start;
unsigned long i, num_pages; unsigned long i, num_pages;
unsigned long bio_flags = 0;
int rw = (epd->sync_io ? WRITE_SYNC : WRITE); int rw = (epd->sync_io ? WRITE_SYNC : WRITE);
int ret = 0; int ret = 0;
clear_bit(EXTENT_BUFFER_IOERR, &eb->bflags); clear_bit(EXTENT_BUFFER_IOERR, &eb->bflags);
num_pages = num_extent_pages(eb->start, eb->len); num_pages = num_extent_pages(eb->start, eb->len);
atomic_set(&eb->io_pages, num_pages); atomic_set(&eb->io_pages, num_pages);
if (btrfs_header_owner(eb) == BTRFS_TREE_LOG_OBJECTID)
bio_flags = EXTENT_BIO_TREE_LOG;
for (i = 0; i < num_pages; i++) { for (i = 0; i < num_pages; i++) {
struct page *p = extent_buffer_page(eb, i); struct page *p = extent_buffer_page(eb, i);
...@@ -3177,7 +3182,8 @@ static int write_one_eb(struct extent_buffer *eb, ...@@ -3177,7 +3182,8 @@ static int write_one_eb(struct extent_buffer *eb,
ret = submit_extent_page(rw, eb->tree, p, offset >> 9, ret = submit_extent_page(rw, eb->tree, p, offset >> 9,
PAGE_CACHE_SIZE, 0, bdev, &epd->bio, PAGE_CACHE_SIZE, 0, bdev, &epd->bio,
-1, end_bio_extent_buffer_writepage, -1, end_bio_extent_buffer_writepage,
0, 0, 0); 0, epd->bio_flags, bio_flags);
epd->bio_flags = bio_flags;
if (ret) { if (ret) {
set_bit(EXTENT_BUFFER_IOERR, &eb->bflags); set_bit(EXTENT_BUFFER_IOERR, &eb->bflags);
SetPageError(p); SetPageError(p);
...@@ -3212,6 +3218,7 @@ int btree_write_cache_pages(struct address_space *mapping, ...@@ -3212,6 +3218,7 @@ int btree_write_cache_pages(struct address_space *mapping,
.tree = tree, .tree = tree,
.extent_locked = 0, .extent_locked = 0,
.sync_io = wbc->sync_mode == WB_SYNC_ALL, .sync_io = wbc->sync_mode == WB_SYNC_ALL,
.bio_flags = 0,
}; };
int ret = 0; int ret = 0;
int done = 0; int done = 0;
...@@ -3474,7 +3481,7 @@ static void flush_epd_write_bio(struct extent_page_data *epd) ...@@ -3474,7 +3481,7 @@ static void flush_epd_write_bio(struct extent_page_data *epd)
if (epd->sync_io) if (epd->sync_io)
rw = WRITE_SYNC; rw = WRITE_SYNC;
ret = submit_one_bio(rw, epd->bio, 0, 0); ret = submit_one_bio(rw, epd->bio, 0, epd->bio_flags);
BUG_ON(ret < 0); /* -ENOMEM */ BUG_ON(ret < 0); /* -ENOMEM */
epd->bio = NULL; epd->bio = NULL;
} }
...@@ -3497,6 +3504,7 @@ int extent_write_full_page(struct extent_io_tree *tree, struct page *page, ...@@ -3497,6 +3504,7 @@ int extent_write_full_page(struct extent_io_tree *tree, struct page *page,
.get_extent = get_extent, .get_extent = get_extent,
.extent_locked = 0, .extent_locked = 0,
.sync_io = wbc->sync_mode == WB_SYNC_ALL, .sync_io = wbc->sync_mode == WB_SYNC_ALL,
.bio_flags = 0,
}; };
ret = __extent_writepage(page, wbc, &epd); ret = __extent_writepage(page, wbc, &epd);
...@@ -3521,6 +3529,7 @@ int extent_write_locked_range(struct extent_io_tree *tree, struct inode *inode, ...@@ -3521,6 +3529,7 @@ int extent_write_locked_range(struct extent_io_tree *tree, struct inode *inode,
.get_extent = get_extent, .get_extent = get_extent,
.extent_locked = 1, .extent_locked = 1,
.sync_io = mode == WB_SYNC_ALL, .sync_io = mode == WB_SYNC_ALL,
.bio_flags = 0,
}; };
struct writeback_control wbc_writepages = { struct writeback_control wbc_writepages = {
.sync_mode = mode, .sync_mode = mode,
...@@ -3560,6 +3569,7 @@ int extent_writepages(struct extent_io_tree *tree, ...@@ -3560,6 +3569,7 @@ int extent_writepages(struct extent_io_tree *tree,
.get_extent = get_extent, .get_extent = get_extent,
.extent_locked = 0, .extent_locked = 0,
.sync_io = wbc->sync_mode == WB_SYNC_ALL, .sync_io = wbc->sync_mode == WB_SYNC_ALL,
.bio_flags = 0,
}; };
ret = extent_write_cache_pages(tree, mapping, wbc, ret = extent_write_cache_pages(tree, mapping, wbc,
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
* type for this bio * type for this bio
*/ */
#define EXTENT_BIO_COMPRESSED 1 #define EXTENT_BIO_COMPRESSED 1
#define EXTENT_BIO_TREE_LOG 2
#define EXTENT_BIO_FLAG_SHIFT 16 #define EXTENT_BIO_FLAG_SHIFT 16
/* these are bit numbers for test/set bit */ /* these are bit numbers for test/set bit */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment