summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/bcachefs/bcachefs.h1
-rw-r--r--fs/bcachefs/fs-io-buffered.c56
2 files changed, 45 insertions, 12 deletions
diff --git a/fs/bcachefs/bcachefs.h b/fs/bcachefs/bcachefs.h
index 553031a3b06a..c62d2e4ab50b 100644
--- a/fs/bcachefs/bcachefs.h
+++ b/fs/bcachefs/bcachefs.h
@@ -483,6 +483,7 @@ BCH_DEBUG_PARAMS_ALL()
x(blocked_allocate) \
x(blocked_allocate_open_bucket) \
x(blocked_write_buffer_full) \
+ x(blocked_writeback_throttle) \
x(nocow_lock_contended)
enum bch_time_stats {
diff --git a/fs/bcachefs/fs-io-buffered.c b/fs/bcachefs/fs-io-buffered.c
index aab30571b056..d9db9f1082d3 100644
--- a/fs/bcachefs/fs-io-buffered.c
+++ b/fs/bcachefs/fs-io-buffered.c
@@ -532,6 +532,39 @@ static void bch2_writepage_io_alloc(struct bch_fs *c,
op->wbio.bio.bi_opf = wbc_to_write_flags(wbc);
}
+static bool can_write_now(struct bch_fs *c, unsigned replicas_want, struct closure *cl)
+{
+ unsigned reserved = OPEN_BUCKETS_COUNT -
+ (OPEN_BUCKETS_COUNT - bch2_open_buckets_reserved(BCH_WATERMARK_normal)) / 2;
+
+ if (unlikely(c->open_buckets_nr_free <= reserved)) {
+ closure_wait(&c->open_buckets_wait, cl);
+ return false;
+ }
+
+ if (BCH_WATERMARK_normal < c->journal.watermark) {
+ closure_wait(&c->journal.async_wait, cl);
+ return false;
+ }
+
+ return true;
+}
+
+static void throttle_writes(struct bch_fs *c, unsigned replicas_want, struct closure *cl)
+{
+ u64 start = 0;
+ while (!can_write_now(c, replicas_want, cl)) {
+ if (!start)
+ start = local_clock();
+ closure_sync(cl);
+ }
+
+ BUG_ON(closure_nr_remaining(cl) > 1);
+
+ if (start)
+ bch2_time_stats_update(&c->times[BCH_TIME_blocked_writeback_throttle], start);
+}
+
static int __bch2_writepage(struct folio *folio,
struct writeback_control *wbc,
void *data)
@@ -667,17 +700,6 @@ do_io:
return 0;
}
-static int bch2_write_cache_pages(struct address_space *mapping,
- struct writeback_control *wbc, void *data)
-{
- struct folio *folio = NULL;
- int error;
-
- while ((folio = writeback_iter(mapping, wbc, folio, &error)))
- error = __bch2_writepage(folio, wbc, data);
- return error;
-}
-
int bch2_writepages(struct address_space *mapping, struct writeback_control *wbc)
{
struct bch_fs *c = mapping->host->i_sb->s_fs_info;
@@ -686,7 +708,17 @@ int bch2_writepages(struct address_space *mapping, struct writeback_control *wbc
bch2_inode_opts_get_inode(c, &to_bch_ei(mapping->host)->ei_inode, &w->opts);
blk_start_plug(&w->plug);
- int ret = bch2_write_cache_pages(mapping, wbc, w);
+
+ struct closure cl;
+ closure_init_stack(&cl);
+
+ struct folio *folio = NULL;
+ int ret = 0;
+
+ while (throttle_writes(c, w->opts.data_replicas, &cl),
+ (folio = writeback_iter(mapping, wbc, folio, &ret)))
+ ret = __bch2_writepage(folio, wbc, w);
+
if (w->io)
bch2_writepage_do_io(w);
blk_finish_plug(&w->plug);