diff options
-rw-r--r-- | fs/btrfs/ctree.h | 3 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 2 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 59 | ||||
-rw-r--r-- | fs/btrfs/extent_io.c | 2 | ||||
-rw-r--r-- | fs/btrfs/extent_io.h | 2 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 29 | ||||
-rw-r--r-- | fs/btrfs/volumes.c | 5 | ||||
-rw-r--r-- | fs/btrfs/volumes.h | 3 |
8 files changed, 103 insertions, 2 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 96a493217860..acf22ad6115c 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -1405,6 +1405,9 @@ int btrfs_csum_truncate(struct btrfs_trans_handle *trans, | |||
1405 | struct btrfs_root *root, struct btrfs_path *path, | 1405 | struct btrfs_root *root, struct btrfs_path *path, |
1406 | u64 isize); | 1406 | u64 isize); |
1407 | /* inode.c */ | 1407 | /* inode.c */ |
1408 | int btrfs_merge_bio_hook(struct page *page, unsigned long offset, | ||
1409 | size_t size, struct bio *bio); | ||
1410 | |||
1408 | static inline void dec_i_blocks(struct inode *inode, u64 dec) | 1411 | static inline void dec_i_blocks(struct inode *inode, u64 dec) |
1409 | { | 1412 | { |
1410 | dec = dec >> 9; | 1413 | dec = dec >> 9; |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 26185d46712c..4890151cd68d 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -1103,4 +1103,6 @@ int btrfs_read_buffer(struct extent_buffer *buf) | |||
1103 | static struct extent_io_ops btree_extent_io_ops = { | 1103 | static struct extent_io_ops btree_extent_io_ops = { |
1104 | .writepage_io_hook = btree_writepage_io_hook, | 1104 | .writepage_io_hook = btree_writepage_io_hook, |
1105 | .submit_bio_hook = btree_submit_bio_hook, | 1105 | .submit_bio_hook = btree_submit_bio_hook, |
1106 | /* note we're sharing with inode.c for the merge bio hook */ | ||
1107 | .merge_bio_hook = btrfs_merge_bio_hook, | ||
1106 | }; | 1108 | }; |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 14eb8fc87015..e9ef644ff56f 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -1473,13 +1473,31 @@ static int noinline find_free_extent(struct btrfs_trans_handle *trans, | |||
1473 | struct btrfs_root * root = orig_root->fs_info->extent_root; | 1473 | struct btrfs_root * root = orig_root->fs_info->extent_root; |
1474 | struct btrfs_fs_info *info = root->fs_info; | 1474 | struct btrfs_fs_info *info = root->fs_info; |
1475 | u64 total_needed = num_bytes; | 1475 | u64 total_needed = num_bytes; |
1476 | u64 *last_ptr = NULL; | ||
1476 | struct btrfs_block_group_cache *block_group; | 1477 | struct btrfs_block_group_cache *block_group; |
1477 | int full_scan = 0; | 1478 | int full_scan = 0; |
1478 | int wrapped = 0; | 1479 | int wrapped = 0; |
1480 | int empty_cluster = 2 * 1024 * 1024; | ||
1479 | 1481 | ||
1480 | WARN_ON(num_bytes < root->sectorsize); | 1482 | WARN_ON(num_bytes < root->sectorsize); |
1481 | btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY); | 1483 | btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY); |
1482 | 1484 | ||
1485 | if (data & BTRFS_BLOCK_GROUP_METADATA) { | ||
1486 | last_ptr = &root->fs_info->last_alloc; | ||
1487 | } | ||
1488 | |||
1489 | if ((data & BTRFS_BLOCK_GROUP_DATA) && btrfs_test_opt(root, SSD)) { | ||
1490 | last_ptr = &root->fs_info->last_data_alloc; | ||
1491 | } | ||
1492 | |||
1493 | if (last_ptr) { | ||
1494 | if (*last_ptr) | ||
1495 | hint_byte = *last_ptr; | ||
1496 | else { | ||
1497 | empty_size += empty_cluster; | ||
1498 | } | ||
1499 | } | ||
1500 | |||
1483 | if (search_end == (u64)-1) | 1501 | if (search_end == (u64)-1) |
1484 | search_end = btrfs_super_total_bytes(&info->super_copy); | 1502 | search_end = btrfs_super_total_bytes(&info->super_copy); |
1485 | 1503 | ||
@@ -1489,11 +1507,14 @@ static int noinline find_free_extent(struct btrfs_trans_handle *trans, | |||
1489 | hint_byte = search_start; | 1507 | hint_byte = search_start; |
1490 | block_group = btrfs_find_block_group(root, block_group, | 1508 | block_group = btrfs_find_block_group(root, block_group, |
1491 | hint_byte, data, 1); | 1509 | hint_byte, data, 1); |
1510 | if (last_ptr && *last_ptr == 0 && block_group) | ||
1511 | hint_byte = block_group->key.objectid; | ||
1492 | } else { | 1512 | } else { |
1493 | block_group = btrfs_find_block_group(root, | 1513 | block_group = btrfs_find_block_group(root, |
1494 | trans->block_group, | 1514 | trans->block_group, |
1495 | search_start, data, 1); | 1515 | search_start, data, 1); |
1496 | } | 1516 | } |
1517 | search_start = max(search_start, hint_byte); | ||
1497 | 1518 | ||
1498 | total_needed += empty_size; | 1519 | total_needed += empty_size; |
1499 | 1520 | ||
@@ -1506,9 +1527,36 @@ check_failed: | |||
1506 | } | 1527 | } |
1507 | ret = find_search_start(root, &block_group, &search_start, | 1528 | ret = find_search_start(root, &block_group, &search_start, |
1508 | total_needed, data); | 1529 | total_needed, data); |
1530 | if (ret == -ENOSPC && last_ptr && *last_ptr) { | ||
1531 | *last_ptr = 0; | ||
1532 | block_group = btrfs_lookup_block_group(info, | ||
1533 | orig_search_start); | ||
1534 | search_start = orig_search_start; | ||
1535 | ret = find_search_start(root, &block_group, &search_start, | ||
1536 | total_needed, data); | ||
1537 | } | ||
1538 | if (ret == -ENOSPC) | ||
1539 | goto enospc; | ||
1509 | if (ret) | 1540 | if (ret) |
1510 | goto error; | 1541 | goto error; |
1511 | 1542 | ||
1543 | if (last_ptr && *last_ptr && search_start != *last_ptr) { | ||
1544 | *last_ptr = 0; | ||
1545 | if (!empty_size) { | ||
1546 | empty_size += empty_cluster; | ||
1547 | total_needed += empty_size; | ||
1548 | } | ||
1549 | block_group = btrfs_lookup_block_group(info, | ||
1550 | orig_search_start); | ||
1551 | search_start = orig_search_start; | ||
1552 | ret = find_search_start(root, &block_group, | ||
1553 | &search_start, total_needed, data); | ||
1554 | if (ret == -ENOSPC) | ||
1555 | goto enospc; | ||
1556 | if (ret) | ||
1557 | goto error; | ||
1558 | } | ||
1559 | |||
1512 | search_start = stripe_align(root, search_start); | 1560 | search_start = stripe_align(root, search_start); |
1513 | ins->objectid = search_start; | 1561 | ins->objectid = search_start; |
1514 | ins->offset = num_bytes; | 1562 | ins->offset = num_bytes; |
@@ -1547,6 +1595,13 @@ check_failed: | |||
1547 | trans->block_group = block_group; | 1595 | trans->block_group = block_group; |
1548 | } | 1596 | } |
1549 | ins->offset = num_bytes; | 1597 | ins->offset = num_bytes; |
1598 | if (last_ptr) { | ||
1599 | *last_ptr = ins->objectid + ins->offset; | ||
1600 | if (*last_ptr == | ||
1601 | btrfs_super_total_bytes(&root->fs_info->super_copy)) { | ||
1602 | *last_ptr = 0; | ||
1603 | } | ||
1604 | } | ||
1550 | return 0; | 1605 | return 0; |
1551 | 1606 | ||
1552 | new_group: | 1607 | new_group: |
@@ -1612,12 +1667,12 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, | |||
1612 | if (root->ref_cows) { | 1667 | if (root->ref_cows) { |
1613 | if (data != BTRFS_BLOCK_GROUP_METADATA) { | 1668 | if (data != BTRFS_BLOCK_GROUP_METADATA) { |
1614 | ret = do_chunk_alloc(trans, root->fs_info->extent_root, | 1669 | ret = do_chunk_alloc(trans, root->fs_info->extent_root, |
1615 | num_bytes, | 1670 | 2 * 1024 * 1024, |
1616 | BTRFS_BLOCK_GROUP_METADATA); | 1671 | BTRFS_BLOCK_GROUP_METADATA); |
1617 | BUG_ON(ret); | 1672 | BUG_ON(ret); |
1618 | } | 1673 | } |
1619 | ret = do_chunk_alloc(trans, root->fs_info->extent_root, | 1674 | ret = do_chunk_alloc(trans, root->fs_info->extent_root, |
1620 | num_bytes, data); | 1675 | num_bytes + 2 * 1024 * 1024, data); |
1621 | BUG_ON(ret); | 1676 | BUG_ON(ret); |
1622 | } | 1677 | } |
1623 | 1678 | ||
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 7e3a1ebde9fc..6dab664529c1 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
@@ -1730,6 +1730,8 @@ static int submit_extent_page(int rw, struct extent_io_tree *tree, | |||
1730 | if (bio_ret && *bio_ret) { | 1730 | if (bio_ret && *bio_ret) { |
1731 | bio = *bio_ret; | 1731 | bio = *bio_ret; |
1732 | if (bio->bi_sector + (bio->bi_size >> 9) != sector || | 1732 | if (bio->bi_sector + (bio->bi_size >> 9) != sector || |
1733 | (tree->ops && tree->ops->merge_bio_hook && | ||
1734 | tree->ops->merge_bio_hook(page, offset, size, bio)) || | ||
1733 | bio_add_page(bio, page, size, offset) < size) { | 1735 | bio_add_page(bio, page, size, offset) < size) { |
1734 | ret = submit_one_bio(rw, bio); | 1736 | ret = submit_one_bio(rw, bio); |
1735 | bio = NULL; | 1737 | bio = NULL; |
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 0dca89328f98..8b5319db2516 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h | |||
@@ -29,6 +29,8 @@ struct extent_io_ops { | |||
29 | int (*fill_delalloc)(struct inode *inode, u64 start, u64 end); | 29 | int (*fill_delalloc)(struct inode *inode, u64 start, u64 end); |
30 | int (*writepage_io_hook)(struct page *page, u64 start, u64 end); | 30 | int (*writepage_io_hook)(struct page *page, u64 start, u64 end); |
31 | int (*submit_bio_hook)(struct inode *inode, int rw, struct bio *bio); | 31 | int (*submit_bio_hook)(struct inode *inode, int rw, struct bio *bio); |
32 | int (*merge_bio_hook)(struct page *page, unsigned long offset, | ||
33 | size_t size, struct bio *bio); | ||
32 | int (*readpage_io_hook)(struct page *page, u64 start, u64 end); | 34 | int (*readpage_io_hook)(struct page *page, u64 start, u64 end); |
33 | int (*readpage_end_io_hook)(struct page *page, u64 start, u64 end, | 35 | int (*readpage_end_io_hook)(struct page *page, u64 start, u64 end, |
34 | struct extent_state *state); | 36 | struct extent_state *state); |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 109576b57f69..5140d6801846 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -296,6 +296,34 @@ int btrfs_clear_bit_hook(struct inode *inode, u64 start, u64 end, | |||
296 | return 0; | 296 | return 0; |
297 | } | 297 | } |
298 | 298 | ||
299 | int btrfs_merge_bio_hook(struct page *page, unsigned long offset, | ||
300 | size_t size, struct bio *bio) | ||
301 | { | ||
302 | struct btrfs_root *root = BTRFS_I(page->mapping->host)->root; | ||
303 | struct btrfs_mapping_tree *map_tree; | ||
304 | struct btrfs_device *dev; | ||
305 | u64 logical = bio->bi_sector << 9; | ||
306 | u64 physical; | ||
307 | u64 length = 0; | ||
308 | u64 map_length; | ||
309 | struct bio_vec *bvec; | ||
310 | int i; | ||
311 | int ret; | ||
312 | |||
313 | bio_for_each_segment(bvec, bio, i) { | ||
314 | length += bvec->bv_len; | ||
315 | } | ||
316 | map_tree = &root->fs_info->mapping_tree; | ||
317 | map_length = length; | ||
318 | ret = btrfs_map_block(map_tree, logical, &physical, &map_length, &dev); | ||
319 | if (map_length < length + size) { | ||
320 | printk("merge bio hook logical %Lu bio len %Lu physical %Lu " | ||
321 | "len %Lu\n", logical, length, physical, map_length); | ||
322 | return 1; | ||
323 | } | ||
324 | return 0; | ||
325 | } | ||
326 | |||
299 | int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio) | 327 | int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio) |
300 | { | 328 | { |
301 | struct btrfs_root *root = BTRFS_I(inode)->root; | 329 | struct btrfs_root *root = BTRFS_I(inode)->root; |
@@ -3033,6 +3061,7 @@ static struct file_operations btrfs_dir_file_operations = { | |||
3033 | static struct extent_io_ops btrfs_extent_io_ops = { | 3061 | static struct extent_io_ops btrfs_extent_io_ops = { |
3034 | .fill_delalloc = run_delalloc_range, | 3062 | .fill_delalloc = run_delalloc_range, |
3035 | .submit_bio_hook = btrfs_submit_bio_hook, | 3063 | .submit_bio_hook = btrfs_submit_bio_hook, |
3064 | .merge_bio_hook = btrfs_merge_bio_hook, | ||
3036 | .readpage_io_hook = btrfs_readpage_io_hook, | 3065 | .readpage_io_hook = btrfs_readpage_io_hook, |
3037 | .readpage_end_io_hook = btrfs_readpage_end_io_hook, | 3066 | .readpage_end_io_hook = btrfs_readpage_end_io_hook, |
3038 | .set_bit_hook = btrfs_set_bit_hook, | 3067 | .set_bit_hook = btrfs_set_bit_hook, |
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index ae22d01ecf54..16fb6bbe6e28 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -578,6 +578,11 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio) | |||
578 | map_tree = &root->fs_info->mapping_tree; | 578 | map_tree = &root->fs_info->mapping_tree; |
579 | map_length = length; | 579 | map_length = length; |
580 | ret = btrfs_map_block(map_tree, logical, &physical, &map_length, &dev); | 580 | ret = btrfs_map_block(map_tree, logical, &physical, &map_length, &dev); |
581 | if (map_length < length) { | ||
582 | printk("mapping failed logical %Lu bio len %Lu physical %Lu " | ||
583 | "len %Lu\n", logical, length, physical, map_length); | ||
584 | BUG(); | ||
585 | } | ||
581 | BUG_ON(map_length < length); | 586 | BUG_ON(map_length < length); |
582 | bio->bi_sector = physical >> 9; | 587 | bio->bi_sector = physical >> 9; |
583 | bio->bi_bdev = dev->bdev; | 588 | bio->bi_bdev = dev->bdev; |
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 77fa6efd79cf..20259128152e 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h | |||
@@ -64,4 +64,7 @@ void btrfs_mapping_init(struct btrfs_mapping_tree *tree); | |||
64 | void btrfs_mapping_tree_free(struct btrfs_mapping_tree *tree); | 64 | void btrfs_mapping_tree_free(struct btrfs_mapping_tree *tree); |
65 | int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio); | 65 | int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio); |
66 | int btrfs_read_super_device(struct btrfs_root *root, struct extent_buffer *buf); | 66 | int btrfs_read_super_device(struct btrfs_root *root, struct extent_buffer *buf); |
67 | int btrfs_map_block(struct btrfs_mapping_tree *map_tree, | ||
68 | u64 logical, u64 *phys, u64 *length, | ||
69 | struct btrfs_device **dev); | ||
67 | #endif | 70 | #endif |