summaryrefslogtreecommitdiffstats
path: root/fs/btrfs/space-info.c
diff options
context:
space:
mode:
authorJosef Bacik <josef@toxicpanda.com>2020-07-21 10:22:25 -0400
committerDavid Sterba <dsterba@suse.com>2020-10-07 12:06:52 +0200
commit8698fc4eb7884eeba29adc4193f9d05fa2bed16b (patch)
treec3e34ecebb57efe722b67fa664a8bdc727f4f431 /fs/btrfs/space-info.c
parenta1ed0a8216f7c7305ccfaa2c93b498f10b340ede (diff)
downloadlinux-8698fc4eb7884eeba29adc4193f9d05fa2bed16b.tar.gz
linux-8698fc4eb7884eeba29adc4193f9d05fa2bed16b.tar.bz2
linux-8698fc4eb7884eeba29adc4193f9d05fa2bed16b.zip
btrfs: add btrfs_reserve_data_bytes and use it
Create a new function btrfs_reserve_data_bytes() in order to handle data reservations. This uses the new flush types and flush states to handle making data reservations. This patch specifically does not change any functionality, and is purposefully not cleaned up in order to make bisection easier for the future patches. The new helper is identical to the old helper in how it handles data reservations. We first try to force a chunk allocation, and then we run through the flush states all at once and in the same order that they were done with the old helper. Subsequent patches will clean this up and change the behavior of the flushing, and it is important to keep those changes separate so we can easily bisect down to the patch that caused the regression, rather than the patch that made us start using the new infrastructure. Reviewed-by: Nikolay Borisov <nborisov@suse.com> Tested-by: Nikolay Borisov <nborisov@suse.com> Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com> Signed-off-by: Josef Bacik <josef@toxicpanda.com> Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'fs/btrfs/space-info.c')
-rw-r--r--fs/btrfs/space-info.c92
1 files changed, 92 insertions, 0 deletions
diff --git a/fs/btrfs/space-info.c b/fs/btrfs/space-info.c
index abd2b8fb1833..ad1dcb37593d 100644
--- a/fs/btrfs/space-info.c
+++ b/fs/btrfs/space-info.c
@@ -1329,3 +1329,95 @@ int btrfs_reserve_metadata_bytes(struct btrfs_root *root,
}
return ret;
}
+
+/**
+ * btrfs_reserve_data_bytes - try to reserve data bytes for an allocation
+ * @fs_info - the filesystem
+ * @bytes - the number of bytes we need
+ * @flush - how we are allowed to flush
+ *
+ * This will reserve bytes from the data space info. If there is not enough
+ * space then we will attempt to flush space as specified by flush.
+ */
+int btrfs_reserve_data_bytes(struct btrfs_fs_info *fs_info, u64 bytes,
+ enum btrfs_reserve_flush_enum flush)
+{
+ struct btrfs_space_info *data_sinfo = fs_info->data_sinfo;
+ const enum btrfs_flush_state *states = NULL;
+ u64 used;
+ int states_nr = 0;
+ int commit_cycles = 2;
+ int ret = -ENOSPC;
+
+ ASSERT(!current->journal_info || flush != BTRFS_RESERVE_FLUSH_DATA);
+
+ if (flush == BTRFS_RESERVE_FLUSH_DATA) {
+ states = data_flush_states;
+ states_nr = ARRAY_SIZE(data_flush_states);
+ }
+
+ spin_lock(&data_sinfo->lock);
+again:
+ used = btrfs_space_info_used(data_sinfo, true);
+
+ if (used + bytes > data_sinfo->total_bytes) {
+ u64 prev_total_bytes = data_sinfo->total_bytes;
+ int flush_state = 0;
+
+ spin_unlock(&data_sinfo->lock);
+
+ /*
+ * Everybody can force chunk allocation, so try this first to
+ * see if we can just bail here and make our reservation.
+ */
+ flush_space(fs_info, data_sinfo, bytes, ALLOC_CHUNK_FORCE);
+ spin_lock(&data_sinfo->lock);
+ if (prev_total_bytes < data_sinfo->total_bytes)
+ goto again;
+ spin_unlock(&data_sinfo->lock);
+
+ /*
+ * Cycle through the rest of the flushing options for our flush
+ * type, then try again.
+ */
+ while (flush_state < states_nr) {
+ u64 flush_bytes = U64_MAX;
+
+ /*
+ * Previously we unconditionally committed the
+ * transaction twice before finally checking against
+ * pinned space before committing the final time. We
+ * also skipped flushing delalloc the final pass
+ * through.
+ */
+ if (!commit_cycles) {
+ if (states[flush_state] == FLUSH_DELALLOC_WAIT) {
+ flush_state++;
+ continue;
+ }
+ if (states[flush_state] == COMMIT_TRANS)
+ flush_bytes = bytes;
+ }
+
+ flush_space(fs_info, data_sinfo, flush_bytes,
+ states[flush_state]);
+ flush_state++;
+ }
+
+ if (!commit_cycles)
+ goto out;
+
+ commit_cycles--;
+ spin_lock(&data_sinfo->lock);
+ goto again;
+ }
+ btrfs_space_info_update_bytes_may_use(fs_info, data_sinfo, bytes);
+ ret = 0;
+ spin_unlock(&data_sinfo->lock);
+out:
+ if (ret)
+ trace_btrfs_space_reservation(fs_info,
+ "space_info:enospc",
+ data_sinfo->flags, bytes, 1);
+ return ret;
+}