diff options
author | Yan, Zheng <zheng.yan@oracle.com> | 2009-11-12 04:34:52 -0500 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2009-12-17 12:33:33 -0500 |
commit | 5a303d5d4b8055d2e5a03e92d04745bfc5881a22 (patch) | |
tree | b3a46e3ebc9ac2618e295b94658ddb1402577b6c /fs/btrfs | |
parent | 2e4bfab97055aa6acdd0637913bd705c2d6506d6 (diff) |
Btrfs: Make fallocate(2) more ENOSPC friendly
fallocate(2) may allocate large number of file extents, so it's not
good to do it in a single transaction. This patch make fallocate(2)
start a new transaction for each file extents it allocates.
Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/inode.c | 65 |
1 files changed, 32 insertions, 33 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index eb2db3bde236..8d8baaa61504 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -5664,10 +5664,10 @@ out_fail: | |||
5664 | return err; | 5664 | return err; |
5665 | } | 5665 | } |
5666 | 5666 | ||
5667 | static int prealloc_file_range(struct btrfs_trans_handle *trans, | 5667 | static int prealloc_file_range(struct inode *inode, u64 start, u64 end, |
5668 | struct inode *inode, u64 start, u64 end, | ||
5669 | u64 alloc_hint, int mode) | 5668 | u64 alloc_hint, int mode) |
5670 | { | 5669 | { |
5670 | struct btrfs_trans_handle *trans; | ||
5671 | struct btrfs_root *root = BTRFS_I(inode)->root; | 5671 | struct btrfs_root *root = BTRFS_I(inode)->root; |
5672 | struct btrfs_key ins; | 5672 | struct btrfs_key ins; |
5673 | u64 alloc_size; | 5673 | u64 alloc_size; |
@@ -5678,17 +5678,23 @@ static int prealloc_file_range(struct btrfs_trans_handle *trans, | |||
5678 | while (num_bytes > 0) { | 5678 | while (num_bytes > 0) { |
5679 | alloc_size = min(num_bytes, root->fs_info->max_extent); | 5679 | alloc_size = min(num_bytes, root->fs_info->max_extent); |
5680 | 5680 | ||
5681 | ret = btrfs_reserve_metadata_space(root, 1); | ||
5682 | if (ret) | ||
5683 | goto out; | ||
5684 | |||
5685 | ret = btrfs_reserve_extent(trans, root, alloc_size, | 5681 | ret = btrfs_reserve_extent(trans, root, alloc_size, |
5686 | root->sectorsize, 0, alloc_hint, | 5682 | root->sectorsize, 0, alloc_hint, |
5687 | (u64)-1, &ins, 1); | 5683 | (u64)-1, &ins, 1); |
5688 | if (ret) { | 5684 | if (ret) { |
5689 | WARN_ON(1); | 5685 | WARN_ON(1); |
5690 | goto out; | 5686 | break; |
5687 | } | ||
5688 | |||
5689 | ret = btrfs_reserve_metadata_space(root, 3); | ||
5690 | if (ret) { | ||
5691 | btrfs_free_reserved_extent(root, ins.objectid, | ||
5692 | ins.offset); | ||
5693 | break; | ||
5691 | } | 5694 | } |
5695 | |||
5696 | trans = btrfs_start_transaction(root, 1); | ||
5697 | |||
5692 | ret = insert_reserved_file_extent(trans, inode, | 5698 | ret = insert_reserved_file_extent(trans, inode, |
5693 | cur_offset, ins.objectid, | 5699 | cur_offset, ins.objectid, |
5694 | ins.offset, ins.offset, | 5700 | ins.offset, ins.offset, |
@@ -5697,22 +5703,25 @@ static int prealloc_file_range(struct btrfs_trans_handle *trans, | |||
5697 | BUG_ON(ret); | 5703 | BUG_ON(ret); |
5698 | btrfs_drop_extent_cache(inode, cur_offset, | 5704 | btrfs_drop_extent_cache(inode, cur_offset, |
5699 | cur_offset + ins.offset -1, 0); | 5705 | cur_offset + ins.offset -1, 0); |
5706 | |||
5700 | num_bytes -= ins.offset; | 5707 | num_bytes -= ins.offset; |
5701 | cur_offset += ins.offset; | 5708 | cur_offset += ins.offset; |
5702 | alloc_hint = ins.objectid + ins.offset; | 5709 | alloc_hint = ins.objectid + ins.offset; |
5703 | btrfs_unreserve_metadata_space(root, 1); | 5710 | |
5704 | } | ||
5705 | out: | ||
5706 | if (cur_offset > start) { | ||
5707 | inode->i_ctime = CURRENT_TIME; | 5711 | inode->i_ctime = CURRENT_TIME; |
5708 | BTRFS_I(inode)->flags |= BTRFS_INODE_PREALLOC; | 5712 | BTRFS_I(inode)->flags |= BTRFS_INODE_PREALLOC; |
5709 | if (!(mode & FALLOC_FL_KEEP_SIZE) && | 5713 | if (!(mode & FALLOC_FL_KEEP_SIZE) && |
5710 | cur_offset > i_size_read(inode)) | 5714 | cur_offset > inode->i_size) { |
5711 | btrfs_i_size_write(inode, cur_offset); | 5715 | i_size_write(inode, cur_offset); |
5716 | btrfs_ordered_update_i_size(inode, cur_offset, NULL); | ||
5717 | } | ||
5718 | |||
5712 | ret = btrfs_update_inode(trans, root, inode); | 5719 | ret = btrfs_update_inode(trans, root, inode); |
5713 | BUG_ON(ret); | 5720 | BUG_ON(ret); |
5714 | } | ||
5715 | 5721 | ||
5722 | btrfs_end_transaction(trans, root); | ||
5723 | btrfs_unreserve_metadata_space(root, 3); | ||
5724 | } | ||
5716 | return ret; | 5725 | return ret; |
5717 | } | 5726 | } |
5718 | 5727 | ||
@@ -5727,8 +5736,6 @@ static long btrfs_fallocate(struct inode *inode, int mode, | |||
5727 | u64 locked_end; | 5736 | u64 locked_end; |
5728 | u64 mask = BTRFS_I(inode)->root->sectorsize - 1; | 5737 | u64 mask = BTRFS_I(inode)->root->sectorsize - 1; |
5729 | struct extent_map *em; | 5738 | struct extent_map *em; |
5730 | struct btrfs_trans_handle *trans; | ||
5731 | struct btrfs_root *root; | ||
5732 | int ret; | 5739 | int ret; |
5733 | 5740 | ||
5734 | alloc_start = offset & ~mask; | 5741 | alloc_start = offset & ~mask; |
@@ -5747,9 +5754,7 @@ static long btrfs_fallocate(struct inode *inode, int mode, | |||
5747 | goto out; | 5754 | goto out; |
5748 | } | 5755 | } |
5749 | 5756 | ||
5750 | root = BTRFS_I(inode)->root; | 5757 | ret = btrfs_check_data_free_space(BTRFS_I(inode)->root, inode, |
5751 | |||
5752 | ret = btrfs_check_data_free_space(root, inode, | ||
5753 | alloc_end - alloc_start); | 5758 | alloc_end - alloc_start); |
5754 | if (ret) | 5759 | if (ret) |
5755 | goto out; | 5760 | goto out; |
@@ -5758,12 +5763,6 @@ static long btrfs_fallocate(struct inode *inode, int mode, | |||
5758 | while (1) { | 5763 | while (1) { |
5759 | struct btrfs_ordered_extent *ordered; | 5764 | struct btrfs_ordered_extent *ordered; |
5760 | 5765 | ||
5761 | trans = btrfs_start_transaction(BTRFS_I(inode)->root, 1); | ||
5762 | if (!trans) { | ||
5763 | ret = -EIO; | ||
5764 | goto out_free; | ||
5765 | } | ||
5766 | |||
5767 | /* the extent lock is ordered inside the running | 5766 | /* the extent lock is ordered inside the running |
5768 | * transaction | 5767 | * transaction |
5769 | */ | 5768 | */ |
@@ -5777,8 +5776,6 @@ static long btrfs_fallocate(struct inode *inode, int mode, | |||
5777 | btrfs_put_ordered_extent(ordered); | 5776 | btrfs_put_ordered_extent(ordered); |
5778 | unlock_extent(&BTRFS_I(inode)->io_tree, | 5777 | unlock_extent(&BTRFS_I(inode)->io_tree, |
5779 | alloc_start, locked_end, GFP_NOFS); | 5778 | alloc_start, locked_end, GFP_NOFS); |
5780 | btrfs_end_transaction(trans, BTRFS_I(inode)->root); | ||
5781 | |||
5782 | /* | 5779 | /* |
5783 | * we can't wait on the range with the transaction | 5780 | * we can't wait on the range with the transaction |
5784 | * running or with the extent lock held | 5781 | * running or with the extent lock held |
@@ -5799,9 +5796,12 @@ static long btrfs_fallocate(struct inode *inode, int mode, | |||
5799 | BUG_ON(IS_ERR(em) || !em); | 5796 | BUG_ON(IS_ERR(em) || !em); |
5800 | last_byte = min(extent_map_end(em), alloc_end); | 5797 | last_byte = min(extent_map_end(em), alloc_end); |
5801 | last_byte = (last_byte + mask) & ~mask; | 5798 | last_byte = (last_byte + mask) & ~mask; |
5802 | if (em->block_start == EXTENT_MAP_HOLE) { | 5799 | if (em->block_start == EXTENT_MAP_HOLE || |
5803 | ret = prealloc_file_range(trans, inode, cur_offset, | 5800 | (cur_offset >= inode->i_size && |
5804 | last_byte, alloc_hint, mode); | 5801 | !test_bit(EXTENT_FLAG_PREALLOC, &em->flags))) { |
5802 | ret = prealloc_file_range(inode, | ||
5803 | cur_offset, last_byte, | ||
5804 | alloc_hint, mode); | ||
5805 | if (ret < 0) { | 5805 | if (ret < 0) { |
5806 | free_extent_map(em); | 5806 | free_extent_map(em); |
5807 | break; | 5807 | break; |
@@ -5820,9 +5820,8 @@ static long btrfs_fallocate(struct inode *inode, int mode, | |||
5820 | unlock_extent(&BTRFS_I(inode)->io_tree, alloc_start, locked_end, | 5820 | unlock_extent(&BTRFS_I(inode)->io_tree, alloc_start, locked_end, |
5821 | GFP_NOFS); | 5821 | GFP_NOFS); |
5822 | 5822 | ||
5823 | btrfs_end_transaction(trans, BTRFS_I(inode)->root); | 5823 | btrfs_free_reserved_data_space(BTRFS_I(inode)->root, inode, |
5824 | out_free: | 5824 | alloc_end - alloc_start); |
5825 | btrfs_free_reserved_data_space(root, inode, alloc_end - alloc_start); | ||
5826 | out: | 5825 | out: |
5827 | mutex_unlock(&inode->i_mutex); | 5826 | mutex_unlock(&inode->i_mutex); |
5828 | return ret; | 5827 | return ret; |