aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYan, Zheng <zheng.yan@oracle.com>2009-11-12 04:34:52 -0500
committerChris Mason <chris.mason@oracle.com>2009-12-17 12:33:33 -0500
commit5a303d5d4b8055d2e5a03e92d04745bfc5881a22 (patch)
treeb3a46e3ebc9ac2618e295b94658ddb1402577b6c
parent2e4bfab97055aa6acdd0637913bd705c2d6506d6 (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>
-rw-r--r--fs/btrfs/inode.c65
1 files changed, 32 insertions, 33 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index eb2db3bde23..8d8baaa6150 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
5667static int prealloc_file_range(struct btrfs_trans_handle *trans, 5667static 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 }
5705out:
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,
5824out_free: 5824 alloc_end - alloc_start);
5825 btrfs_free_reserved_data_space(root, inode, alloc_end - alloc_start);
5826out: 5825out:
5827 mutex_unlock(&inode->i_mutex); 5826 mutex_unlock(&inode->i_mutex);
5828 return ret; 5827 return ret;