aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent-tree.c
diff options
context:
space:
mode:
authorJosef Bacik <josef@redhat.com>2011-08-04 10:25:02 -0400
committerJosef Bacik <josef@redhat.com>2011-10-19 15:12:31 -0400
commit7709cde33f12db71efb377fae4ae7aab6c94ebc6 (patch)
treef60b4ff7dafa0fcf64e0d9e9445d6984739cbfe6 /fs/btrfs/extent-tree.c
parent9e4871070b5f070cacf26525389d56e0345ba156 (diff)
Btrfs: calculate checksum space correctly
We have not been reserving enough space for checksums. We were just reserving bytes for the checksum items themselves, we were not taking into account having to cow the tree and such. This patch adds a csum_bytes counter to the inode for keeping track of the number of bytes outstanding we have for checksums. Then we calculate how many leaves would be required for the checksums we are given and use that to reserve space. This adds a significant amount of bytes to our reservations, but we will handle this later. Thanks, Signed-off-by: Josef Bacik <josef@redhat.com>
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r--fs/btrfs/extent-tree.c117
1 files changed, 109 insertions, 8 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index fbe6278f466b..4add1ac2dda0 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -3984,11 +3984,19 @@ int btrfs_snap_reserve_metadata(struct btrfs_trans_handle *trans,
3984 return block_rsv_migrate_bytes(src_rsv, dst_rsv, num_bytes); 3984 return block_rsv_migrate_bytes(src_rsv, dst_rsv, num_bytes);
3985} 3985}
3986 3986
3987/**
3988 * drop_outstanding_extent - drop an outstanding extent
3989 * @inode: the inode we're dropping the extent for
3990 *
3991 * This is called when we are freeing up an outstanding extent, either called
3992 * after an error or after an extent is written. This will return the number of
3993 * reserved extents that need to be freed. This must be called with
3994 * BTRFS_I(inode)->lock held.
3995 */
3987static unsigned drop_outstanding_extent(struct inode *inode) 3996static unsigned drop_outstanding_extent(struct inode *inode)
3988{ 3997{
3989 unsigned dropped_extents = 0; 3998 unsigned dropped_extents = 0;
3990 3999
3991 spin_lock(&BTRFS_I(inode)->lock);
3992 BUG_ON(!BTRFS_I(inode)->outstanding_extents); 4000 BUG_ON(!BTRFS_I(inode)->outstanding_extents);
3993 BTRFS_I(inode)->outstanding_extents--; 4001 BTRFS_I(inode)->outstanding_extents--;
3994 4002
@@ -3998,19 +4006,70 @@ static unsigned drop_outstanding_extent(struct inode *inode)
3998 */ 4006 */
3999 if (BTRFS_I(inode)->outstanding_extents >= 4007 if (BTRFS_I(inode)->outstanding_extents >=
4000 BTRFS_I(inode)->reserved_extents) 4008 BTRFS_I(inode)->reserved_extents)
4001 goto out; 4009 return 0;
4002 4010
4003 dropped_extents = BTRFS_I(inode)->reserved_extents - 4011 dropped_extents = BTRFS_I(inode)->reserved_extents -
4004 BTRFS_I(inode)->outstanding_extents; 4012 BTRFS_I(inode)->outstanding_extents;
4005 BTRFS_I(inode)->reserved_extents -= dropped_extents; 4013 BTRFS_I(inode)->reserved_extents -= dropped_extents;
4006out:
4007 spin_unlock(&BTRFS_I(inode)->lock);
4008 return dropped_extents; 4014 return dropped_extents;
4009} 4015}
4010 4016
4011static u64 calc_csum_metadata_size(struct inode *inode, u64 num_bytes) 4017/**
4018 * calc_csum_metadata_size - return the amount of metada space that must be
4019 * reserved/free'd for the given bytes.
4020 * @inode: the inode we're manipulating
4021 * @num_bytes: the number of bytes in question
4022 * @reserve: 1 if we are reserving space, 0 if we are freeing space
4023 *
4024 * This adjusts the number of csum_bytes in the inode and then returns the
4025 * correct amount of metadata that must either be reserved or freed. We
4026 * calculate how many checksums we can fit into one leaf and then divide the
4027 * number of bytes that will need to be checksumed by this value to figure out
4028 * how many checksums will be required. If we are adding bytes then the number
4029 * may go up and we will return the number of additional bytes that must be
4030 * reserved. If it is going down we will return the number of bytes that must
4031 * be freed.
4032 *
4033 * This must be called with BTRFS_I(inode)->lock held.
4034 */
4035static u64 calc_csum_metadata_size(struct inode *inode, u64 num_bytes,
4036 int reserve)
4012{ 4037{
4013 return num_bytes >>= 3; 4038 struct btrfs_root *root = BTRFS_I(inode)->root;
4039 u64 csum_size;
4040 int num_csums_per_leaf;
4041 int num_csums;
4042 int old_csums;
4043
4044 if (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM &&
4045 BTRFS_I(inode)->csum_bytes == 0)
4046 return 0;
4047
4048 old_csums = (int)div64_u64(BTRFS_I(inode)->csum_bytes, root->sectorsize);
4049 if (reserve)
4050 BTRFS_I(inode)->csum_bytes += num_bytes;
4051 else
4052 BTRFS_I(inode)->csum_bytes -= num_bytes;
4053 csum_size = BTRFS_LEAF_DATA_SIZE(root) - sizeof(struct btrfs_item);
4054 num_csums_per_leaf = (int)div64_u64(csum_size,
4055 sizeof(struct btrfs_csum_item) +
4056 sizeof(struct btrfs_disk_key));
4057 num_csums = (int)div64_u64(BTRFS_I(inode)->csum_bytes, root->sectorsize);
4058 num_csums = num_csums + num_csums_per_leaf - 1;
4059 num_csums = num_csums / num_csums_per_leaf;
4060
4061 old_csums = old_csums + num_csums_per_leaf - 1;
4062 old_csums = old_csums / num_csums_per_leaf;
4063
4064 /* No change, no need to reserve more */
4065 if (old_csums == num_csums)
4066 return 0;
4067
4068 if (reserve)
4069 return btrfs_calc_trans_metadata_size(root,
4070 num_csums - old_csums);
4071
4072 return btrfs_calc_trans_metadata_size(root, old_csums - num_csums);
4014} 4073}
4015 4074
4016int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes) 4075int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
@@ -4037,9 +4096,9 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
4037 4096
4038 to_reserve = btrfs_calc_trans_metadata_size(root, nr_extents); 4097 to_reserve = btrfs_calc_trans_metadata_size(root, nr_extents);
4039 } 4098 }
4099 to_reserve += calc_csum_metadata_size(inode, num_bytes, 1);
4040 spin_unlock(&BTRFS_I(inode)->lock); 4100 spin_unlock(&BTRFS_I(inode)->lock);
4041 4101
4042 to_reserve += calc_csum_metadata_size(inode, num_bytes);
4043 ret = reserve_metadata_bytes(NULL, root, block_rsv, to_reserve, 1); 4102 ret = reserve_metadata_bytes(NULL, root, block_rsv, to_reserve, 1);
4044 if (ret) { 4103 if (ret) {
4045 unsigned dropped; 4104 unsigned dropped;
@@ -4047,8 +4106,11 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
4047 * We don't need the return value since our reservation failed, 4106 * We don't need the return value since our reservation failed,
4048 * we just need to clean up our counter. 4107 * we just need to clean up our counter.
4049 */ 4108 */
4109 spin_lock(&BTRFS_I(inode)->lock);
4050 dropped = drop_outstanding_extent(inode); 4110 dropped = drop_outstanding_extent(inode);
4051 WARN_ON(dropped > 1); 4111 WARN_ON(dropped > 1);
4112 BTRFS_I(inode)->csum_bytes -= num_bytes;
4113 spin_unlock(&BTRFS_I(inode)->lock);
4052 return ret; 4114 return ret;
4053 } 4115 }
4054 4116
@@ -4057,6 +4119,15 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
4057 return 0; 4119 return 0;
4058} 4120}
4059 4121
4122/**
4123 * btrfs_delalloc_release_metadata - release a metadata reservation for an inode
4124 * @inode: the inode to release the reservation for
4125 * @num_bytes: the number of bytes we're releasing
4126 *
4127 * This will release the metadata reservation for an inode. This can be called
4128 * once we complete IO for a given set of bytes to release their metadata
4129 * reservations.
4130 */
4060void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes) 4131void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes)
4061{ 4132{
4062 struct btrfs_root *root = BTRFS_I(inode)->root; 4133 struct btrfs_root *root = BTRFS_I(inode)->root;
@@ -4064,9 +4135,11 @@ void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes)
4064 unsigned dropped; 4135 unsigned dropped;
4065 4136
4066 num_bytes = ALIGN(num_bytes, root->sectorsize); 4137 num_bytes = ALIGN(num_bytes, root->sectorsize);
4138 spin_lock(&BTRFS_I(inode)->lock);
4067 dropped = drop_outstanding_extent(inode); 4139 dropped = drop_outstanding_extent(inode);
4068 4140
4069 to_free = calc_csum_metadata_size(inode, num_bytes); 4141 to_free = calc_csum_metadata_size(inode, num_bytes, 0);
4142 spin_unlock(&BTRFS_I(inode)->lock);
4070 if (dropped > 0) 4143 if (dropped > 0)
4071 to_free += btrfs_calc_trans_metadata_size(root, dropped); 4144 to_free += btrfs_calc_trans_metadata_size(root, dropped);
4072 4145
@@ -4074,6 +4147,21 @@ void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes)
4074 to_free); 4147 to_free);
4075} 4148}
4076 4149
4150/**
4151 * btrfs_delalloc_reserve_space - reserve data and metadata space for delalloc
4152 * @inode: inode we're writing to
4153 * @num_bytes: the number of bytes we want to allocate
4154 *
4155 * This will do the following things
4156 *
4157 * o reserve space in the data space info for num_bytes
4158 * o reserve space in the metadata space info based on number of outstanding
4159 * extents and how much csums will be needed
4160 * o add to the inodes ->delalloc_bytes
4161 * o add it to the fs_info's delalloc inodes list.
4162 *
4163 * This will return 0 for success and -ENOSPC if there is no space left.
4164 */
4077int btrfs_delalloc_reserve_space(struct inode *inode, u64 num_bytes) 4165int btrfs_delalloc_reserve_space(struct inode *inode, u64 num_bytes)
4078{ 4166{
4079 int ret; 4167 int ret;
@@ -4091,6 +4179,19 @@ int btrfs_delalloc_reserve_space(struct inode *inode, u64 num_bytes)
4091 return 0; 4179 return 0;
4092} 4180}
4093 4181
4182/**
4183 * btrfs_delalloc_release_space - release data and metadata space for delalloc
4184 * @inode: inode we're releasing space for
4185 * @num_bytes: the number of bytes we want to free up
4186 *
4187 * This must be matched with a call to btrfs_delalloc_reserve_space. This is
4188 * called in the case that we don't need the metadata AND data reservations
4189 * anymore. So if there is an error or we insert an inline extent.
4190 *
4191 * This function will release the metadata space that was not used and will
4192 * decrement ->delalloc_bytes and remove it from the fs_info delalloc_inodes
4193 * list if there are no delalloc bytes left.
4194 */
4094void btrfs_delalloc_release_space(struct inode *inode, u64 num_bytes) 4195void btrfs_delalloc_release_space(struct inode *inode, u64 num_bytes)
4095{ 4196{
4096 btrfs_delalloc_release_metadata(inode, num_bytes); 4197 btrfs_delalloc_release_metadata(inode, num_bytes);