Commit fbec3b88 authored by Kent Overstreet's avatar Kent Overstreet Committed by Kent Overstreet

bcachefs: Kill JOURNAL_NEED_WRITE

This replaces the journal flag JOURNAL_NEED_WRITE with per-journal buf
state - more explicit, and solving a race in the old code that would
lead to entries being opened and written unnecessarily.
Signed-off-by: default avatarKent Overstreet <kent.overstreet@gmail.com>
parent 506bac7e
...@@ -86,6 +86,7 @@ static void bch2_journal_buf_init(struct journal *j) ...@@ -86,6 +86,7 @@ static void bch2_journal_buf_init(struct journal *j)
buf->noflush = false; buf->noflush = false;
buf->must_flush = false; buf->must_flush = false;
buf->separate_flush = false; buf->separate_flush = false;
buf->flush_time = 0;
memset(buf->data, 0, sizeof(*buf->data)); memset(buf->data, 0, sizeof(*buf->data));
buf->data->seq = cpu_to_le64(journal_cur_seq(j)); buf->data->seq = cpu_to_le64(journal_cur_seq(j));
...@@ -152,11 +153,6 @@ static bool __journal_entry_close(struct journal *j) ...@@ -152,11 +153,6 @@ static bool __journal_entry_close(struct journal *j)
return true; return true;
} }
if (!test_bit(JOURNAL_NEED_WRITE, &j->flags)) {
set_bit(JOURNAL_NEED_WRITE, &j->flags);
j->need_write_time = local_clock();
}
new.cur_entry_offset = JOURNAL_ENTRY_CLOSED_VAL; new.cur_entry_offset = JOURNAL_ENTRY_CLOSED_VAL;
new.idx++; new.idx++;
...@@ -205,7 +201,6 @@ static bool __journal_entry_close(struct journal *j) ...@@ -205,7 +201,6 @@ static bool __journal_entry_close(struct journal *j)
bch2_journal_buf_init(j); bch2_journal_buf_init(j);
cancel_delayed_work(&j->write_work); cancel_delayed_work(&j->write_work);
clear_bit(JOURNAL_NEED_WRITE, &j->flags);
bch2_journal_space_available(j); bch2_journal_space_available(j);
...@@ -216,15 +211,16 @@ static bool __journal_entry_close(struct journal *j) ...@@ -216,15 +211,16 @@ static bool __journal_entry_close(struct journal *j)
static bool journal_entry_want_write(struct journal *j) static bool journal_entry_want_write(struct journal *j)
{ {
union journal_res_state s = READ_ONCE(j->reservations); union journal_res_state s = READ_ONCE(j->reservations);
struct journal_buf *buf = journal_cur_buf(j);
bool ret = false; bool ret = false;
/* if (!buf->flush_time) {
* Don't close it yet if we already have a write in flight, but do set buf->flush_time = local_clock() ?: 1;
* NEED_WRITE: buf->expires = jiffies;
*/ }
if (s.idx != s.unwritten_idx)
set_bit(JOURNAL_NEED_WRITE, &j->flags); /* Don't close it yet if we already have a write in flight: */
else if (s.idx == s.unwritten_idx)
ret = __journal_entry_close(j); ret = __journal_entry_close(j);
return ret; return ret;
...@@ -278,6 +274,8 @@ static int journal_entry_open(struct journal *j) ...@@ -278,6 +274,8 @@ static int journal_entry_open(struct journal *j)
*/ */
BUG_ON(buf->data->u64s); BUG_ON(buf->data->u64s);
buf->expires = jiffies +
msecs_to_jiffies(c->opts.journal_flush_delay);
buf->u64s_reserved = j->entry_u64s_reserved; buf->u64s_reserved = j->entry_u64s_reserved;
buf->disk_sectors = j->cur_entry_sectors; buf->disk_sectors = j->cur_entry_sectors;
buf->sectors = min(buf->disk_sectors, buf->buf_size >> 9); buf->sectors = min(buf->disk_sectors, buf->buf_size >> 9);
...@@ -337,8 +335,19 @@ static void journal_quiesce(struct journal *j) ...@@ -337,8 +335,19 @@ static void journal_quiesce(struct journal *j)
static void journal_write_work(struct work_struct *work) static void journal_write_work(struct work_struct *work)
{ {
struct journal *j = container_of(work, struct journal, write_work.work); struct journal *j = container_of(work, struct journal, write_work.work);
struct bch_fs *c = container_of(j, struct bch_fs, journal);
struct journal_buf *buf;
long delta;
journal_entry_close(j); spin_lock(&j->lock);
buf = journal_cur_buf(j);
delta = buf->expires - jiffies;
if (delta > 0)
mod_delayed_work(c->io_complete_wq, &j->write_work, delta);
else
__journal_entry_close(j);
spin_unlock(&j->lock);
} }
static int __journal_res_get(struct journal *j, struct journal_res *res, static int __journal_res_get(struct journal *j, struct journal_res *res,
...@@ -591,7 +600,11 @@ int bch2_journal_flush_seq_async(struct journal *j, u64 seq, ...@@ -591,7 +600,11 @@ int bch2_journal_flush_seq_async(struct journal *j, u64 seq,
seq = res.seq; seq = res.seq;
buf = j->buf + (seq & JOURNAL_BUF_MASK); buf = j->buf + (seq & JOURNAL_BUF_MASK);
buf->must_flush = true; buf->must_flush = true;
set_bit(JOURNAL_NEED_WRITE, &j->flags);
if (!buf->flush_time) {
buf->flush_time = local_clock() ?: 1;
buf->expires = jiffies;
}
if (parent && !closure_wait(&buf->wait, parent)) if (parent && !closure_wait(&buf->wait, parent))
BUG(); BUG();
...@@ -657,7 +670,11 @@ int bch2_journal_meta(struct journal *j) ...@@ -657,7 +670,11 @@ int bch2_journal_meta(struct journal *j)
buf = j->buf + (res.seq & JOURNAL_BUF_MASK); buf = j->buf + (res.seq & JOURNAL_BUF_MASK);
buf->must_flush = true; buf->must_flush = true;
set_bit(JOURNAL_NEED_WRITE, &j->flags);
if (!buf->flush_time) {
buf->flush_time = local_clock() ?: 1;
buf->expires = jiffies;
}
bch2_journal_res_put(j, &res); bch2_journal_res_put(j, &res);
...@@ -1233,12 +1250,22 @@ void __bch2_journal_debug_to_text(struct printbuf *out, struct journal *j) ...@@ -1233,12 +1250,22 @@ void __bch2_journal_debug_to_text(struct printbuf *out, struct journal *j)
pr_buf(out, "unwritten entry:\tidx %u refcount %u sectors %u\n", pr_buf(out, "unwritten entry:\tidx %u refcount %u sectors %u\n",
i, journal_state_count(s, i), j->buf[i].sectors); i, journal_state_count(s, i), j->buf[i].sectors);
pr_indent_push(out, 2);
pr_buf(out, "refcount %u", journal_state_count(s, i));
pr_newline(out);
pr_buf(out, "sectors %u", j->buf[i].sectors);
pr_newline(out);
pr_buf(out, "expires %li ms", jiffies_to_msecs(j->buf[i].expires - jiffies));
pr_newline(out);
pr_indent_pop(out, 2);
} }
pr_buf(out, pr_buf(out,
"need write:\t\t%i\n"
"replay done:\t\t%i\n", "replay done:\t\t%i\n",
test_bit(JOURNAL_NEED_WRITE, &j->flags),
test_bit(JOURNAL_REPLAY_DONE, &j->flags)); test_bit(JOURNAL_REPLAY_DONE, &j->flags));
pr_buf(out, "space:\n"); pr_buf(out, "space:\n");
......
...@@ -1403,13 +1403,15 @@ static void journal_write_done(struct closure *cl) ...@@ -1403,13 +1403,15 @@ static void journal_write_done(struct closure *cl)
closure_wake_up(&w->wait); closure_wake_up(&w->wait);
journal_wake(j); journal_wake(j);
if (test_bit(JOURNAL_NEED_WRITE, &j->flags)) if (new.unwritten_idx == new.idx) {
mod_delayed_work(c->io_complete_wq, &j->write_work, 0); struct journal_buf *buf = journal_cur_buf(j);
spin_unlock(&j->lock); long delta = buf->expires - jiffies;
if (new.unwritten_idx != new.idx && mod_delayed_work(c->io_complete_wq, &j->write_work, max(0L, delta));
!journal_state_count(new, new.unwritten_idx)) } else if (!journal_state_count(new, new.unwritten_idx))
closure_call(&j->io, bch2_journal_write, c->io_complete_wq, NULL); closure_call(&j->io, bch2_journal_write, c->io_complete_wq, NULL);
spin_unlock(&j->lock);
} }
static void journal_write_endio(struct bio *bio) static void journal_write_endio(struct bio *bio)
......
...@@ -25,6 +25,8 @@ struct journal_buf { ...@@ -25,6 +25,8 @@ struct journal_buf {
struct closure_waitlist wait; struct closure_waitlist wait;
u64 last_seq; /* copy of data->last_seq */ u64 last_seq; /* copy of data->last_seq */
unsigned long expires;
u64 flush_time;
unsigned buf_size; /* size in bytes of @data */ unsigned buf_size; /* size in bytes of @data */
unsigned sectors; /* maximum size for current entry */ unsigned sectors; /* maximum size for current entry */
...@@ -139,16 +141,9 @@ enum journal_space_from { ...@@ -139,16 +141,9 @@ enum journal_space_from {
journal_space_nr, journal_space_nr,
}; };
/*
* JOURNAL_NEED_WRITE - current (pending) journal entry should be written ASAP,
* either because something's waiting on the write to complete or because it's
* been dirty too long and the timer's expired.
*/
enum { enum {
JOURNAL_REPLAY_DONE, JOURNAL_REPLAY_DONE,
JOURNAL_STARTED, JOURNAL_STARTED,
JOURNAL_NEED_WRITE,
JOURNAL_MAY_GET_UNRESERVED, JOURNAL_MAY_GET_UNRESERVED,
JOURNAL_MAY_SKIP_FLUSH, JOURNAL_MAY_SKIP_FLUSH,
}; };
...@@ -266,7 +261,6 @@ struct journal { ...@@ -266,7 +261,6 @@ struct journal {
unsigned long last_flush_write; unsigned long last_flush_write;
u64 res_get_blocked_start; u64 res_get_blocked_start;
u64 need_write_time;
u64 write_start_time; u64 write_start_time;
u64 nr_flush_writes; u64 nr_flush_writes;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment