|
@@ -4815,14 +4815,49 @@ out_fail:
|
|
|
* If the inodes csum_bytes is the same as the original
|
|
|
* csum_bytes then we know we haven't raced with any free()ers
|
|
|
* so we can just reduce our inodes csum bytes and carry on.
|
|
|
- * Otherwise we have to do the normal free thing to account for
|
|
|
- * the case that the free side didn't free up its reserve
|
|
|
- * because of this outstanding reservation.
|
|
|
*/
|
|
|
- if (BTRFS_I(inode)->csum_bytes == csum_bytes)
|
|
|
+ if (BTRFS_I(inode)->csum_bytes == csum_bytes) {
|
|
|
calc_csum_metadata_size(inode, num_bytes, 0);
|
|
|
- else
|
|
|
- to_free = calc_csum_metadata_size(inode, num_bytes, 0);
|
|
|
+ } else {
|
|
|
+ u64 orig_csum_bytes = BTRFS_I(inode)->csum_bytes;
|
|
|
+ u64 bytes;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * This is tricky, but first we need to figure out how much we
|
|
|
+ * free'd from any free-ers that occured during this
|
|
|
+ * reservation, so we reset ->csum_bytes to the csum_bytes
|
|
|
+ * before we dropped our lock, and then call the free for the
|
|
|
+ * number of bytes that were freed while we were trying our
|
|
|
+ * reservation.
|
|
|
+ */
|
|
|
+ bytes = csum_bytes - BTRFS_I(inode)->csum_bytes;
|
|
|
+ BTRFS_I(inode)->csum_bytes = csum_bytes;
|
|
|
+ to_free = calc_csum_metadata_size(inode, bytes, 0);
|
|
|
+
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Now we need to see how much we would have freed had we not
|
|
|
+ * been making this reservation and our ->csum_bytes were not
|
|
|
+ * artificially inflated.
|
|
|
+ */
|
|
|
+ BTRFS_I(inode)->csum_bytes = csum_bytes - num_bytes;
|
|
|
+ bytes = csum_bytes - orig_csum_bytes;
|
|
|
+ bytes = calc_csum_metadata_size(inode, bytes, 0);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Now reset ->csum_bytes to what it should be. If bytes is
|
|
|
+ * more than to_free then we would have free'd more space had we
|
|
|
+ * not had an artificially high ->csum_bytes, so we need to free
|
|
|
+ * the remainder. If bytes is the same or less then we don't
|
|
|
+ * need to do anything, the other free-ers did the correct
|
|
|
+ * thing.
|
|
|
+ */
|
|
|
+ BTRFS_I(inode)->csum_bytes = orig_csum_bytes - num_bytes;
|
|
|
+ if (bytes > to_free)
|
|
|
+ to_free = bytes - to_free;
|
|
|
+ else
|
|
|
+ to_free = 0;
|
|
|
+ }
|
|
|
spin_unlock(&BTRFS_I(inode)->lock);
|
|
|
if (dropped)
|
|
|
to_free += btrfs_calc_trans_metadata_size(root, dropped);
|