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); |
