@@ -4357,6 +4357,15 @@ int write_all_supers(struct btrfs_fs_info *fs_info, int max_mirrors)
}
}
+ ret = btrfs_write_intent_writeback(fs_info, 0);
+ if (ret < 0) {
+ mutex_unlock(
+ &fs_info->fs_devices->device_list_mutex);
+ btrfs_handle_fs_error(fs_info, ret,
+ "errors while writing back write intent bitmaps.");
+ return ret;
+ }
+
list_for_each_entry(dev, head, dev_list) {
if (!dev->bdev) {
total_errors++;
@@ -133,8 +133,17 @@ static int write_intent_writeback(struct btrfs_fs_info *fs_info)
shash->tfm = fs_info->csum_shash;
spin_lock(&ctrl->lock);
- wis = page_address(ctrl->page);
+ /* No update on the bitmap, just skip this writeback. */
+ if (!memcmp(page_address(ctrl->page), page_address(ctrl->commit_page),
+ WRITE_INTENT_BITMAPS_SIZE)) {
+ ctrl->writing_event = 0;
+ spin_unlock(&ctrl->lock);
+ wake_up(&ctrl->write_wait);
+ return 0;
+ }
+
+ wis = page_address(ctrl->page);
/*
* Bump up the event counter each time this bitmap is going to be
* written.
@@ -148,7 +157,6 @@ static int write_intent_writeback(struct btrfs_fs_info *fs_info)
WRITE_INTENT_BITMAPS_SIZE);
spin_unlock(&ctrl->lock);
- mutex_lock(&fs_info->fs_devices->device_list_mutex);
/*
* Go through all the writeable devices, copy the bitmap page into the
* page cache, and submit them (without waiting).
@@ -170,7 +178,13 @@ static int write_intent_writeback(struct btrfs_fs_info *fs_info)
if (ret < 0)
total_errors++;
}
- mutex_unlock(&fs_info->fs_devices->device_list_mutex);
+
+ spin_lock(&ctrl->lock);
+ if (ctrl->writing_event > ctrl->committed_event)
+ ctrl->committed_event = ctrl->writing_event;
+ ctrl->writing_event = 0;
+ spin_unlock(&ctrl->lock);
+ wake_up(&ctrl->write_wait);
if (total_errors > btrfs_super_num_devices(fs_info->super_copy) - 1) {
btrfs_err(fs_info, "failed to writeback write-intent bitmaps");
@@ -685,6 +699,63 @@ static void write_intent_clear_bits(struct write_intent_ctrl *ctrl, u64 bytenr,
}
}
+int btrfs_write_intent_writeback(struct btrfs_fs_info *fs_info, u64 event)
+{
+ struct write_intent_ctrl *ctrl = fs_info->wi_ctrl;
+
+ if (!btrfs_fs_compat_ro(fs_info, WRITE_INTENT_BITMAP))
+ return 0;
+
+ ASSERT(ctrl);
+
+again:
+ spin_lock(&ctrl->lock);
+
+ /*
+ * The bitmap has already been written to disk at least once. Our update
+ * has already reached disk.
+ */
+ if (event && ctrl->committed_event > event) {
+ spin_unlock(&ctrl->lock);
+ return 0;
+ }
+
+ /* Previous writing hasn't finished, wait for it and retry. */
+ if (ctrl->writing_event && ctrl->writing_event <= event) {
+ DEFINE_WAIT(__wait);
+
+ prepare_to_wait_event(&ctrl->write_wait, &__wait,
+ TASK_UNINTERRUPTIBLE);
+ spin_unlock(&ctrl->lock);
+ schedule();
+ finish_wait(&ctrl->write_wait, &__wait);
+ goto again;
+ }
+
+ /* Someone is already writing back the bitmap. */
+ if (ctrl->writing_event) {
+ DEFINE_WAIT(__wait);
+
+ ASSERT(ctrl->writing_event > event);
+ prepare_to_wait_event(&ctrl->write_wait, &__wait,
+ TASK_UNINTERRUPTIBLE);
+ spin_unlock(&ctrl->lock);
+ schedule();
+ finish_wait(&ctrl->write_wait, &__wait);
+ return 0;
+ }
+
+ /*
+ * We're the one to write back the bitmap, update @writing_event so
+ * all the other caller will just wait for us.
+ */
+ ctrl->writing_event = atomic64_read(&ctrl->event) + 1;
+ spin_unlock(&ctrl->lock);
+
+ /* Slow path, do the submission and wait. */
+ return write_intent_writeback(fs_info);
+}
+
int btrfs_write_intent_init(struct btrfs_fs_info *fs_info)
{
struct btrfs_device *highest_dev = NULL;
@@ -709,6 +780,8 @@ int btrfs_write_intent_init(struct btrfs_fs_info *fs_info)
}
spin_lock_init(&fs_info->wi_ctrl->lock);
+ init_waitqueue_head(&fs_info->wi_ctrl->overflow_wait);
+ init_waitqueue_head(&fs_info->wi_ctrl->write_wait);
/*
* Go through every writeable device to find the highest event.
@@ -749,6 +822,8 @@ int btrfs_write_intent_init(struct btrfs_fs_info *fs_info)
dev->devid, ret);
goto cleanup;
}
+ memcpy_page(fs_info->wi_ctrl->commit_page, 0,
+ fs_info->wi_ctrl->page, 0, WRITE_INTENT_BITMAPS_SIZE);
wis = page_address(fs_info->wi_ctrl->page);
atomic64_set(&fs_info->wi_ctrl->event, wi_super_events(wis));
fs_info->wi_ctrl->blocksize = wi_super_blocksize(wis);
@@ -123,12 +123,30 @@ struct write_intent_ctrl {
/* A copy for writeback. */
struct page *commit_page;
+ /*
+ * For callers who has updated their bitmap, wait for the bitmap to be
+ * flushed to disk.
+ */
+ wait_queue_head_t write_wait;
+
+ /*
+ * For callers whose bits can not be updated as no enough space left
+ * int the bitmap.
+ */
+ wait_queue_head_t overflow_wait;
+
/* Cached event counter.*/
atomic64_t event;
/* Lock for reading/writing above @page. */
spinlock_t lock;
+ /* Event number for the bitmap being written. */
+ u64 writing_event;
+
+ /* Event number for the last committed bitmap. */
+ u64 committed_event;
+
/* Cached blocksize from write intent super. */
u32 blocksize;
};
@@ -233,4 +251,11 @@ static inline void wie_set_bitmap(struct write_intent_entry *entry,
int btrfs_write_intent_init(struct btrfs_fs_info *fs_info);
void btrfs_write_intent_free(struct btrfs_fs_info *fs_info);
+/*
+ * Ensure the bitmap for @event is already written to disk.
+ *
+ * If @event is 0, it means to write current bitmap to disk.
+ */
+int btrfs_write_intent_writeback(struct btrfs_fs_info *fs_info, u64 event);
+
#endif
The new function, btrfs_write_intent_writeback(), will also accept a u64 parameter, @event, to do extra fastpath check to avoid unnecessary writeback. For now we just pass 0 to write the current bitmap to disk. Signed-off-by: Qu Wenruo <wqu@suse.com> --- fs/btrfs/disk-io.c | 9 +++++ fs/btrfs/write-intent.c | 81 +++++++++++++++++++++++++++++++++++++++-- fs/btrfs/write-intent.h | 25 +++++++++++++ 3 files changed, 112 insertions(+), 3 deletions(-)