diff options
author | Chris Mason <chris.mason@oracle.com> | 2011-04-11 20:46:03 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2011-04-11 20:46:03 -0400 |
commit | 874d0d2633e0f3fe955607c6b04d5fc5325781c4 (patch) | |
tree | a96165f1f13501419af1c88dae146bc1061f8664 /fs/btrfs/inode.c | |
parent | 507903b81840a70cc6a179d4eb03584ad50e8c5b (diff) | |
parent | 13c5a93e7005d7dae0b6d070d25203593e692d13 (diff) |
Merge branch 'for-chris' of git://git.kernel.org/pub/scm/linux/kernel/git/josef/btrfs-work into for-linus
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r-- | fs/btrfs/inode.c | 107 |
1 files changed, 82 insertions, 25 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 5a993e0ec865..55a6a0b416d7 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -1769,9 +1769,12 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end) | |||
1769 | add_pending_csums(trans, inode, ordered_extent->file_offset, | 1769 | add_pending_csums(trans, inode, ordered_extent->file_offset, |
1770 | &ordered_extent->list); | 1770 | &ordered_extent->list); |
1771 | 1771 | ||
1772 | btrfs_ordered_update_i_size(inode, 0, ordered_extent); | 1772 | ret = btrfs_ordered_update_i_size(inode, 0, ordered_extent); |
1773 | ret = btrfs_update_inode(trans, root, inode); | 1773 | if (!ret) { |
1774 | BUG_ON(ret); | 1774 | ret = btrfs_update_inode(trans, root, inode); |
1775 | BUG_ON(ret); | ||
1776 | } | ||
1777 | ret = 0; | ||
1775 | out: | 1778 | out: |
1776 | if (nolock) { | 1779 | if (nolock) { |
1777 | if (trans) | 1780 | if (trans) |
@@ -2589,6 +2592,13 @@ static void fill_inode_item(struct btrfs_trans_handle *trans, | |||
2589 | struct btrfs_inode_item *item, | 2592 | struct btrfs_inode_item *item, |
2590 | struct inode *inode) | 2593 | struct inode *inode) |
2591 | { | 2594 | { |
2595 | if (!leaf->map_token) | ||
2596 | map_private_extent_buffer(leaf, (unsigned long)item, | ||
2597 | sizeof(struct btrfs_inode_item), | ||
2598 | &leaf->map_token, &leaf->kaddr, | ||
2599 | &leaf->map_start, &leaf->map_len, | ||
2600 | KM_USER1); | ||
2601 | |||
2592 | btrfs_set_inode_uid(leaf, item, inode->i_uid); | 2602 | btrfs_set_inode_uid(leaf, item, inode->i_uid); |
2593 | btrfs_set_inode_gid(leaf, item, inode->i_gid); | 2603 | btrfs_set_inode_gid(leaf, item, inode->i_gid); |
2594 | btrfs_set_inode_size(leaf, item, BTRFS_I(inode)->disk_i_size); | 2604 | btrfs_set_inode_size(leaf, item, BTRFS_I(inode)->disk_i_size); |
@@ -2617,6 +2627,11 @@ static void fill_inode_item(struct btrfs_trans_handle *trans, | |||
2617 | btrfs_set_inode_rdev(leaf, item, inode->i_rdev); | 2627 | btrfs_set_inode_rdev(leaf, item, inode->i_rdev); |
2618 | btrfs_set_inode_flags(leaf, item, BTRFS_I(inode)->flags); | 2628 | btrfs_set_inode_flags(leaf, item, BTRFS_I(inode)->flags); |
2619 | btrfs_set_inode_block_group(leaf, item, BTRFS_I(inode)->block_group); | 2629 | btrfs_set_inode_block_group(leaf, item, BTRFS_I(inode)->block_group); |
2630 | |||
2631 | if (leaf->map_token) { | ||
2632 | unmap_extent_buffer(leaf, leaf->map_token, KM_USER1); | ||
2633 | leaf->map_token = NULL; | ||
2634 | } | ||
2620 | } | 2635 | } |
2621 | 2636 | ||
2622 | /* | 2637 | /* |
@@ -5433,17 +5448,30 @@ out: | |||
5433 | } | 5448 | } |
5434 | 5449 | ||
5435 | static struct extent_map *btrfs_new_extent_direct(struct inode *inode, | 5450 | static struct extent_map *btrfs_new_extent_direct(struct inode *inode, |
5451 | struct extent_map *em, | ||
5436 | u64 start, u64 len) | 5452 | u64 start, u64 len) |
5437 | { | 5453 | { |
5438 | struct btrfs_root *root = BTRFS_I(inode)->root; | 5454 | struct btrfs_root *root = BTRFS_I(inode)->root; |
5439 | struct btrfs_trans_handle *trans; | 5455 | struct btrfs_trans_handle *trans; |
5440 | struct extent_map *em; | ||
5441 | struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; | 5456 | struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; |
5442 | struct btrfs_key ins; | 5457 | struct btrfs_key ins; |
5443 | u64 alloc_hint; | 5458 | u64 alloc_hint; |
5444 | int ret; | 5459 | int ret; |
5460 | bool insert = false; | ||
5445 | 5461 | ||
5446 | btrfs_drop_extent_cache(inode, start, start + len - 1, 0); | 5462 | /* |
5463 | * Ok if the extent map we looked up is a hole and is for the exact | ||
5464 | * range we want, there is no reason to allocate a new one, however if | ||
5465 | * it is not right then we need to free this one and drop the cache for | ||
5466 | * our range. | ||
5467 | */ | ||
5468 | if (em->block_start != EXTENT_MAP_HOLE || em->start != start || | ||
5469 | em->len != len) { | ||
5470 | free_extent_map(em); | ||
5471 | em = NULL; | ||
5472 | insert = true; | ||
5473 | btrfs_drop_extent_cache(inode, start, start + len - 1, 0); | ||
5474 | } | ||
5447 | 5475 | ||
5448 | trans = btrfs_join_transaction(root, 0); | 5476 | trans = btrfs_join_transaction(root, 0); |
5449 | if (IS_ERR(trans)) | 5477 | if (IS_ERR(trans)) |
@@ -5459,10 +5487,12 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode, | |||
5459 | goto out; | 5487 | goto out; |
5460 | } | 5488 | } |
5461 | 5489 | ||
5462 | em = alloc_extent_map(GFP_NOFS); | ||
5463 | if (!em) { | 5490 | if (!em) { |
5464 | em = ERR_PTR(-ENOMEM); | 5491 | em = alloc_extent_map(GFP_NOFS); |
5465 | goto out; | 5492 | if (!em) { |
5493 | em = ERR_PTR(-ENOMEM); | ||
5494 | goto out; | ||
5495 | } | ||
5466 | } | 5496 | } |
5467 | 5497 | ||
5468 | em->start = start; | 5498 | em->start = start; |
@@ -5472,9 +5502,15 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode, | |||
5472 | em->block_start = ins.objectid; | 5502 | em->block_start = ins.objectid; |
5473 | em->block_len = ins.offset; | 5503 | em->block_len = ins.offset; |
5474 | em->bdev = root->fs_info->fs_devices->latest_bdev; | 5504 | em->bdev = root->fs_info->fs_devices->latest_bdev; |
5505 | |||
5506 | /* | ||
5507 | * We need to do this because if we're using the original em we searched | ||
5508 | * for, we could have EXTENT_FLAG_VACANCY set, and we don't want that. | ||
5509 | */ | ||
5510 | em->flags = 0; | ||
5475 | set_bit(EXTENT_FLAG_PINNED, &em->flags); | 5511 | set_bit(EXTENT_FLAG_PINNED, &em->flags); |
5476 | 5512 | ||
5477 | while (1) { | 5513 | while (insert) { |
5478 | write_lock(&em_tree->lock); | 5514 | write_lock(&em_tree->lock); |
5479 | ret = add_extent_mapping(em_tree, em); | 5515 | ret = add_extent_mapping(em_tree, em); |
5480 | write_unlock(&em_tree->lock); | 5516 | write_unlock(&em_tree->lock); |
@@ -5692,8 +5728,7 @@ must_cow: | |||
5692 | * it above | 5728 | * it above |
5693 | */ | 5729 | */ |
5694 | len = bh_result->b_size; | 5730 | len = bh_result->b_size; |
5695 | free_extent_map(em); | 5731 | em = btrfs_new_extent_direct(inode, em, start, len); |
5696 | em = btrfs_new_extent_direct(inode, start, len); | ||
5697 | if (IS_ERR(em)) | 5732 | if (IS_ERR(em)) |
5698 | return PTR_ERR(em); | 5733 | return PTR_ERR(em); |
5699 | len = min(len, em->len - (start - em->start)); | 5734 | len = min(len, em->len - (start - em->start)); |
@@ -5856,8 +5891,10 @@ again: | |||
5856 | } | 5891 | } |
5857 | 5892 | ||
5858 | add_pending_csums(trans, inode, ordered->file_offset, &ordered->list); | 5893 | add_pending_csums(trans, inode, ordered->file_offset, &ordered->list); |
5859 | btrfs_ordered_update_i_size(inode, 0, ordered); | 5894 | ret = btrfs_ordered_update_i_size(inode, 0, ordered); |
5860 | btrfs_update_inode(trans, root, inode); | 5895 | if (!ret) |
5896 | btrfs_update_inode(trans, root, inode); | ||
5897 | ret = 0; | ||
5861 | out_unlock: | 5898 | out_unlock: |
5862 | unlock_extent_cached(&BTRFS_I(inode)->io_tree, ordered->file_offset, | 5899 | unlock_extent_cached(&BTRFS_I(inode)->io_tree, ordered->file_offset, |
5863 | ordered->file_offset + ordered->len - 1, | 5900 | ordered->file_offset + ordered->len - 1, |
@@ -5943,7 +5980,7 @@ static struct bio *btrfs_dio_bio_alloc(struct block_device *bdev, | |||
5943 | 5980 | ||
5944 | static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode, | 5981 | static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode, |
5945 | int rw, u64 file_offset, int skip_sum, | 5982 | int rw, u64 file_offset, int skip_sum, |
5946 | u32 *csums) | 5983 | u32 *csums, int async_submit) |
5947 | { | 5984 | { |
5948 | int write = rw & REQ_WRITE; | 5985 | int write = rw & REQ_WRITE; |
5949 | struct btrfs_root *root = BTRFS_I(inode)->root; | 5986 | struct btrfs_root *root = BTRFS_I(inode)->root; |
@@ -5954,13 +5991,24 @@ static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode, | |||
5954 | if (ret) | 5991 | if (ret) |
5955 | goto err; | 5992 | goto err; |
5956 | 5993 | ||
5957 | if (write && !skip_sum) { | 5994 | if (skip_sum) |
5995 | goto map; | ||
5996 | |||
5997 | if (write && async_submit) { | ||
5958 | ret = btrfs_wq_submit_bio(root->fs_info, | 5998 | ret = btrfs_wq_submit_bio(root->fs_info, |
5959 | inode, rw, bio, 0, 0, | 5999 | inode, rw, bio, 0, 0, |
5960 | file_offset, | 6000 | file_offset, |
5961 | __btrfs_submit_bio_start_direct_io, | 6001 | __btrfs_submit_bio_start_direct_io, |
5962 | __btrfs_submit_bio_done); | 6002 | __btrfs_submit_bio_done); |
5963 | goto err; | 6003 | goto err; |
6004 | } else if (write) { | ||
6005 | /* | ||
6006 | * If we aren't doing async submit, calculate the csum of the | ||
6007 | * bio now. | ||
6008 | */ | ||
6009 | ret = btrfs_csum_one_bio(root, inode, bio, file_offset, 1); | ||
6010 | if (ret) | ||
6011 | goto err; | ||
5964 | } else if (!skip_sum) { | 6012 | } else if (!skip_sum) { |
5965 | ret = btrfs_lookup_bio_sums_dio(root, inode, bio, | 6013 | ret = btrfs_lookup_bio_sums_dio(root, inode, bio, |
5966 | file_offset, csums); | 6014 | file_offset, csums); |
@@ -5968,7 +6016,8 @@ static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode, | |||
5968 | goto err; | 6016 | goto err; |
5969 | } | 6017 | } |
5970 | 6018 | ||
5971 | ret = btrfs_map_bio(root, rw, bio, 0, 1); | 6019 | map: |
6020 | ret = btrfs_map_bio(root, rw, bio, 0, async_submit); | ||
5972 | err: | 6021 | err: |
5973 | bio_put(bio); | 6022 | bio_put(bio); |
5974 | return ret; | 6023 | return ret; |
@@ -5990,15 +6039,9 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, | |||
5990 | int nr_pages = 0; | 6039 | int nr_pages = 0; |
5991 | u32 *csums = dip->csums; | 6040 | u32 *csums = dip->csums; |
5992 | int ret = 0; | 6041 | int ret = 0; |
6042 | int async_submit = 0; | ||
5993 | int write = rw & REQ_WRITE; | 6043 | int write = rw & REQ_WRITE; |
5994 | 6044 | ||
5995 | bio = btrfs_dio_bio_alloc(orig_bio->bi_bdev, start_sector, GFP_NOFS); | ||
5996 | if (!bio) | ||
5997 | return -ENOMEM; | ||
5998 | bio->bi_private = dip; | ||
5999 | bio->bi_end_io = btrfs_end_dio_bio; | ||
6000 | atomic_inc(&dip->pending_bios); | ||
6001 | |||
6002 | map_length = orig_bio->bi_size; | 6045 | map_length = orig_bio->bi_size; |
6003 | ret = btrfs_map_block(map_tree, READ, start_sector << 9, | 6046 | ret = btrfs_map_block(map_tree, READ, start_sector << 9, |
6004 | &map_length, NULL, 0); | 6047 | &map_length, NULL, 0); |
@@ -6007,6 +6050,19 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, | |||
6007 | return -EIO; | 6050 | return -EIO; |
6008 | } | 6051 | } |
6009 | 6052 | ||
6053 | if (map_length >= orig_bio->bi_size) { | ||
6054 | bio = orig_bio; | ||
6055 | goto submit; | ||
6056 | } | ||
6057 | |||
6058 | async_submit = 1; | ||
6059 | bio = btrfs_dio_bio_alloc(orig_bio->bi_bdev, start_sector, GFP_NOFS); | ||
6060 | if (!bio) | ||
6061 | return -ENOMEM; | ||
6062 | bio->bi_private = dip; | ||
6063 | bio->bi_end_io = btrfs_end_dio_bio; | ||
6064 | atomic_inc(&dip->pending_bios); | ||
6065 | |||
6010 | while (bvec <= (orig_bio->bi_io_vec + orig_bio->bi_vcnt - 1)) { | 6066 | while (bvec <= (orig_bio->bi_io_vec + orig_bio->bi_vcnt - 1)) { |
6011 | if (unlikely(map_length < submit_len + bvec->bv_len || | 6067 | if (unlikely(map_length < submit_len + bvec->bv_len || |
6012 | bio_add_page(bio, bvec->bv_page, bvec->bv_len, | 6068 | bio_add_page(bio, bvec->bv_page, bvec->bv_len, |
@@ -6020,7 +6076,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, | |||
6020 | atomic_inc(&dip->pending_bios); | 6076 | atomic_inc(&dip->pending_bios); |
6021 | ret = __btrfs_submit_dio_bio(bio, inode, rw, | 6077 | ret = __btrfs_submit_dio_bio(bio, inode, rw, |
6022 | file_offset, skip_sum, | 6078 | file_offset, skip_sum, |
6023 | csums); | 6079 | csums, async_submit); |
6024 | if (ret) { | 6080 | if (ret) { |
6025 | bio_put(bio); | 6081 | bio_put(bio); |
6026 | atomic_dec(&dip->pending_bios); | 6082 | atomic_dec(&dip->pending_bios); |
@@ -6057,8 +6113,9 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, | |||
6057 | } | 6113 | } |
6058 | } | 6114 | } |
6059 | 6115 | ||
6116 | submit: | ||
6060 | ret = __btrfs_submit_dio_bio(bio, inode, rw, file_offset, skip_sum, | 6117 | ret = __btrfs_submit_dio_bio(bio, inode, rw, file_offset, skip_sum, |
6061 | csums); | 6118 | csums, async_submit); |
6062 | if (!ret) | 6119 | if (!ret) |
6063 | return 0; | 6120 | return 0; |
6064 | 6121 | ||