diff options
-rw-r--r-- | fs/btrfs/extent-tree.c | 47 |
1 files changed, 41 insertions, 6 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index a8ff25aedca1..a22b5cc921ad 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -4815,14 +4815,49 @@ out_fail: | |||
4815 | * If the inodes csum_bytes is the same as the original | 4815 | * If the inodes csum_bytes is the same as the original |
4816 | * csum_bytes then we know we haven't raced with any free()ers | 4816 | * csum_bytes then we know we haven't raced with any free()ers |
4817 | * so we can just reduce our inodes csum bytes and carry on. | 4817 | * so we can just reduce our inodes csum bytes and carry on. |
4818 | * Otherwise we have to do the normal free thing to account for | ||
4819 | * the case that the free side didn't free up its reserve | ||
4820 | * because of this outstanding reservation. | ||
4821 | */ | 4818 | */ |
4822 | if (BTRFS_I(inode)->csum_bytes == csum_bytes) | 4819 | if (BTRFS_I(inode)->csum_bytes == csum_bytes) { |
4823 | calc_csum_metadata_size(inode, num_bytes, 0); | 4820 | calc_csum_metadata_size(inode, num_bytes, 0); |
4824 | else | 4821 | } else { |
4825 | to_free = calc_csum_metadata_size(inode, num_bytes, 0); | 4822 | u64 orig_csum_bytes = BTRFS_I(inode)->csum_bytes; |
4823 | u64 bytes; | ||
4824 | |||
4825 | /* | ||
4826 | * This is tricky, but first we need to figure out how much we | ||
4827 | * free'd from any free-ers that occured during this | ||
4828 | * reservation, so we reset ->csum_bytes to the csum_bytes | ||
4829 | * before we dropped our lock, and then call the free for the | ||
4830 | * number of bytes that were freed while we were trying our | ||
4831 | * reservation. | ||
4832 | */ | ||
4833 | bytes = csum_bytes - BTRFS_I(inode)->csum_bytes; | ||
4834 | BTRFS_I(inode)->csum_bytes = csum_bytes; | ||
4835 | to_free = calc_csum_metadata_size(inode, bytes, 0); | ||
4836 | |||
4837 | |||
4838 | /* | ||
4839 | * Now we need to see how much we would have freed had we not | ||
4840 | * been making this reservation and our ->csum_bytes were not | ||
4841 | * artificially inflated. | ||
4842 | */ | ||
4843 | BTRFS_I(inode)->csum_bytes = csum_bytes - num_bytes; | ||
4844 | bytes = csum_bytes - orig_csum_bytes; | ||
4845 | bytes = calc_csum_metadata_size(inode, bytes, 0); | ||
4846 | |||
4847 | /* | ||
4848 | * Now reset ->csum_bytes to what it should be. If bytes is | ||
4849 | * more than to_free then we would have free'd more space had we | ||
4850 | * not had an artificially high ->csum_bytes, so we need to free | ||
4851 | * the remainder. If bytes is the same or less then we don't | ||
4852 | * need to do anything, the other free-ers did the correct | ||
4853 | * thing. | ||
4854 | */ | ||
4855 | BTRFS_I(inode)->csum_bytes = orig_csum_bytes - num_bytes; | ||
4856 | if (bytes > to_free) | ||
4857 | to_free = bytes - to_free; | ||
4858 | else | ||
4859 | to_free = 0; | ||
4860 | } | ||
4826 | spin_unlock(&BTRFS_I(inode)->lock); | 4861 | spin_unlock(&BTRFS_I(inode)->lock); |
4827 | if (dropped) | 4862 | if (dropped) |
4828 | to_free += btrfs_calc_trans_metadata_size(root, dropped); | 4863 | to_free += btrfs_calc_trans_metadata_size(root, dropped); |