Commit 83ec519a authored by Kent Overstreet's avatar Kent Overstreet

bcachefs: When shutting down, flush btree node writes last

Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent adac06fa
...@@ -13,6 +13,9 @@ void bch2_btree_node_prep_for_write(struct btree_trans *, ...@@ -13,6 +13,9 @@ void bch2_btree_node_prep_for_write(struct btree_trans *,
bool bch2_btree_bset_insert_key(struct btree_trans *, struct btree_path *, bool bch2_btree_bset_insert_key(struct btree_trans *, struct btree_path *,
struct btree *, struct btree_node_iter *, struct btree *, struct btree_node_iter *,
struct bkey_i *); struct bkey_i *);
int bch2_btree_node_flush0(struct journal *, struct journal_entry_pin *, u64);
int bch2_btree_node_flush1(struct journal *, struct journal_entry_pin *, u64);
void bch2_btree_add_journal_pin(struct bch_fs *, struct btree *, u64); void bch2_btree_add_journal_pin(struct bch_fs *, struct btree *, u64);
void bch2_btree_insert_key_leaf(struct btree_trans *, struct btree_path *, void bch2_btree_insert_key_leaf(struct btree_trans *, struct btree_path *,
......
...@@ -227,12 +227,12 @@ static int __btree_node_flush(struct journal *j, struct journal_entry_pin *pin, ...@@ -227,12 +227,12 @@ static int __btree_node_flush(struct journal *j, struct journal_entry_pin *pin,
return 0; return 0;
} }
static int btree_node_flush0(struct journal *j, struct journal_entry_pin *pin, u64 seq) int bch2_btree_node_flush0(struct journal *j, struct journal_entry_pin *pin, u64 seq)
{ {
return __btree_node_flush(j, pin, 0, seq); return __btree_node_flush(j, pin, 0, seq);
} }
static int btree_node_flush1(struct journal *j, struct journal_entry_pin *pin, u64 seq) int bch2_btree_node_flush1(struct journal *j, struct journal_entry_pin *pin, u64 seq)
{ {
return __btree_node_flush(j, pin, 1, seq); return __btree_node_flush(j, pin, 1, seq);
} }
...@@ -244,8 +244,8 @@ inline void bch2_btree_add_journal_pin(struct bch_fs *c, ...@@ -244,8 +244,8 @@ inline void bch2_btree_add_journal_pin(struct bch_fs *c,
bch2_journal_pin_add(&c->journal, seq, &w->journal, bch2_journal_pin_add(&c->journal, seq, &w->journal,
btree_node_write_idx(b) == 0 btree_node_write_idx(b) == 0
? btree_node_flush0 ? bch2_btree_node_flush0
: btree_node_flush1); : bch2_btree_node_flush1);
} }
/** /**
......
...@@ -67,8 +67,9 @@ journal_seq_to_buf(struct journal *j, u64 seq) ...@@ -67,8 +67,9 @@ journal_seq_to_buf(struct journal *j, u64 seq)
static void journal_pin_list_init(struct journal_entry_pin_list *p, int count) static void journal_pin_list_init(struct journal_entry_pin_list *p, int count)
{ {
INIT_LIST_HEAD(&p->list); unsigned i;
INIT_LIST_HEAD(&p->key_cache_list); for (i = 0; i < ARRAY_SIZE(p->list); i++)
INIT_LIST_HEAD(&p->list[i]);
INIT_LIST_HEAD(&p->flushed); INIT_LIST_HEAD(&p->flushed);
atomic_set(&p->count, count); atomic_set(&p->count, count);
p->devs.nr = 0; p->devs.nr = 0;
...@@ -1347,6 +1348,7 @@ bool bch2_journal_seq_pins_to_text(struct printbuf *out, struct journal *j, u64 ...@@ -1347,6 +1348,7 @@ bool bch2_journal_seq_pins_to_text(struct printbuf *out, struct journal *j, u64
{ {
struct journal_entry_pin_list *pin_list; struct journal_entry_pin_list *pin_list;
struct journal_entry_pin *pin; struct journal_entry_pin *pin;
unsigned i;
spin_lock(&j->lock); spin_lock(&j->lock);
*seq = max(*seq, j->pin.front); *seq = max(*seq, j->pin.front);
...@@ -1364,15 +1366,11 @@ bool bch2_journal_seq_pins_to_text(struct printbuf *out, struct journal *j, u64 ...@@ -1364,15 +1366,11 @@ bool bch2_journal_seq_pins_to_text(struct printbuf *out, struct journal *j, u64
prt_newline(out); prt_newline(out);
printbuf_indent_add(out, 2); printbuf_indent_add(out, 2);
list_for_each_entry(pin, &pin_list->list, list) { for (i = 0; i < ARRAY_SIZE(pin_list->list); i++)
prt_printf(out, "\t%px %ps", pin, pin->flush); list_for_each_entry(pin, &pin_list->list[i], list) {
prt_newline(out); prt_printf(out, "\t%px %ps", pin, pin->flush);
} prt_newline(out);
}
list_for_each_entry(pin, &pin_list->key_cache_list, list) {
prt_printf(out, "\t%px %ps", pin, pin->flush);
prt_newline(out);
}
if (!list_empty(&pin_list->flushed)) { if (!list_empty(&pin_list->flushed)) {
prt_printf(out, "flushed:"); prt_printf(out, "flushed:");
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#include "bcachefs.h" #include "bcachefs.h"
#include "btree_key_cache.h" #include "btree_key_cache.h"
#include "btree_update.h"
#include "errcode.h" #include "errcode.h"
#include "error.h" #include "error.h"
#include "journal.h" #include "journal.h"
...@@ -318,9 +319,7 @@ static void bch2_journal_reclaim_fast(struct journal *j) ...@@ -318,9 +319,7 @@ static void bch2_journal_reclaim_fast(struct journal *j)
*/ */
while (!fifo_empty(&j->pin) && while (!fifo_empty(&j->pin) &&
!atomic_read(&fifo_peek_front(&j->pin).count)) { !atomic_read(&fifo_peek_front(&j->pin).count)) {
BUG_ON(!list_empty(&fifo_peek_front(&j->pin).list)); fifo_pop(&j->pin, temp);
BUG_ON(!list_empty(&fifo_peek_front(&j->pin).flushed));
BUG_ON(!fifo_pop(&j->pin, temp));
popped = true; popped = true;
} }
...@@ -379,6 +378,17 @@ void bch2_journal_pin_drop(struct journal *j, ...@@ -379,6 +378,17 @@ void bch2_journal_pin_drop(struct journal *j,
spin_unlock(&j->lock); spin_unlock(&j->lock);
} }
enum journal_pin_type journal_pin_type(journal_pin_flush_fn fn)
{
if (fn == bch2_btree_node_flush0 ||
fn == bch2_btree_node_flush1)
return JOURNAL_PIN_btree;
else if (fn == bch2_btree_key_cache_journal_flush)
return JOURNAL_PIN_key_cache;
else
return JOURNAL_PIN_other;
}
void bch2_journal_pin_set(struct journal *j, u64 seq, void bch2_journal_pin_set(struct journal *j, u64 seq,
struct journal_entry_pin *pin, struct journal_entry_pin *pin,
journal_pin_flush_fn flush_fn) journal_pin_flush_fn flush_fn)
...@@ -407,10 +417,8 @@ void bch2_journal_pin_set(struct journal *j, u64 seq, ...@@ -407,10 +417,8 @@ void bch2_journal_pin_set(struct journal *j, u64 seq,
pin->seq = seq; pin->seq = seq;
pin->flush = flush_fn; pin->flush = flush_fn;
if (flush_fn == bch2_btree_key_cache_journal_flush) if (flush_fn)
list_add(&pin->list, &pin_list->key_cache_list); list_add(&pin->list, &pin_list->list[journal_pin_type(flush_fn)]);
else if (flush_fn)
list_add(&pin->list, &pin_list->list);
else else
list_add(&pin->list, &pin_list->flushed); list_add(&pin->list, &pin_list->flushed);
...@@ -446,37 +454,37 @@ void bch2_journal_pin_flush(struct journal *j, struct journal_entry_pin *pin) ...@@ -446,37 +454,37 @@ void bch2_journal_pin_flush(struct journal *j, struct journal_entry_pin *pin)
static struct journal_entry_pin * static struct journal_entry_pin *
journal_get_next_pin(struct journal *j, journal_get_next_pin(struct journal *j,
bool get_any, u64 seq_to_flush,
bool get_key_cache, unsigned allowed_below_seq,
u64 max_seq, u64 *seq) unsigned allowed_above_seq,
u64 *seq)
{ {
struct journal_entry_pin_list *pin_list; struct journal_entry_pin_list *pin_list;
struct journal_entry_pin *ret = NULL; struct journal_entry_pin *ret = NULL;
unsigned i;
fifo_for_each_entry_ptr(pin_list, &j->pin, *seq) { fifo_for_each_entry_ptr(pin_list, &j->pin, *seq) {
if (*seq > max_seq && !get_any && !get_key_cache) if (*seq > seq_to_flush && !allowed_above_seq)
break; break;
if (*seq <= max_seq || get_any) { for (i = 0; i < JOURNAL_PIN_NR; i++)
ret = list_first_entry_or_null(&pin_list->list, if ((((1U << i) & allowed_below_seq) && *seq <= seq_to_flush) ||
struct journal_entry_pin, list); ((1U << i) & allowed_above_seq)) {
if (ret) ret = list_first_entry_or_null(&pin_list->list[i],
return ret; struct journal_entry_pin, list);
} if (ret)
return ret;
if (*seq <= max_seq || get_any || get_key_cache) { }
ret = list_first_entry_or_null(&pin_list->key_cache_list,
struct journal_entry_pin, list);
if (ret)
return ret;
}
} }
return NULL; return NULL;
} }
/* returns true if we did work */ /* returns true if we did work */
static size_t journal_flush_pins(struct journal *j, u64 seq_to_flush, static size_t journal_flush_pins(struct journal *j,
u64 seq_to_flush,
unsigned allowed_below_seq,
unsigned allowed_above_seq,
unsigned min_any, unsigned min_any,
unsigned min_key_cache) unsigned min_key_cache)
{ {
...@@ -489,15 +497,25 @@ static size_t journal_flush_pins(struct journal *j, u64 seq_to_flush, ...@@ -489,15 +497,25 @@ static size_t journal_flush_pins(struct journal *j, u64 seq_to_flush,
lockdep_assert_held(&j->reclaim_lock); lockdep_assert_held(&j->reclaim_lock);
while (1) { while (1) {
unsigned allowed_above = allowed_above_seq;
unsigned allowed_below = allowed_below_seq;
if (min_any) {
allowed_above |= ~0;
allowed_below |= ~0;
}
if (min_key_cache) {
allowed_above |= 1U << JOURNAL_PIN_key_cache;
allowed_below |= 1U << JOURNAL_PIN_key_cache;
}
cond_resched(); cond_resched();
j->last_flushed = jiffies; j->last_flushed = jiffies;
spin_lock(&j->lock); spin_lock(&j->lock);
pin = journal_get_next_pin(j, pin = journal_get_next_pin(j, seq_to_flush, allowed_below, allowed_above, &seq);
min_any != 0,
min_key_cache != 0,
seq_to_flush, &seq);
if (pin) { if (pin) {
BUG_ON(j->flush_in_progress); BUG_ON(j->flush_in_progress);
j->flush_in_progress = pin; j->flush_in_progress = pin;
...@@ -656,6 +674,7 @@ static int __bch2_journal_reclaim(struct journal *j, bool direct, bool kicked) ...@@ -656,6 +674,7 @@ static int __bch2_journal_reclaim(struct journal *j, bool direct, bool kicked)
atomic_long_read(&c->btree_key_cache.nr_keys)); atomic_long_read(&c->btree_key_cache.nr_keys));
nr_flushed = journal_flush_pins(j, seq_to_flush, nr_flushed = journal_flush_pins(j, seq_to_flush,
~0, 0,
min_nr, min_key_cache); min_nr, min_key_cache);
if (direct) if (direct)
...@@ -776,7 +795,11 @@ static int journal_flush_done(struct journal *j, u64 seq_to_flush, ...@@ -776,7 +795,11 @@ static int journal_flush_done(struct journal *j, u64 seq_to_flush,
mutex_lock(&j->reclaim_lock); mutex_lock(&j->reclaim_lock);
if (journal_flush_pins(j, seq_to_flush, 0, 0)) if (journal_flush_pins(j, seq_to_flush,
(1U << JOURNAL_PIN_key_cache)|
(1U << JOURNAL_PIN_other), 0, 0, 0) ||
journal_flush_pins(j, seq_to_flush,
(1U << JOURNAL_PIN_btree), 0, 0, 0))
*did_work = true; *did_work = true;
spin_lock(&j->lock); spin_lock(&j->lock);
......
...@@ -43,9 +43,15 @@ struct journal_buf { ...@@ -43,9 +43,15 @@ struct journal_buf {
* flushed: * flushed:
*/ */
enum journal_pin_type {
JOURNAL_PIN_btree,
JOURNAL_PIN_key_cache,
JOURNAL_PIN_other,
JOURNAL_PIN_NR,
};
struct journal_entry_pin_list { struct journal_entry_pin_list {
struct list_head list; struct list_head list[JOURNAL_PIN_NR];
struct list_head key_cache_list;
struct list_head flushed; struct list_head flushed;
atomic_t count; atomic_t count;
struct bch_devs_list devs; struct bch_devs_list devs;
......
...@@ -209,7 +209,8 @@ static void __bch2_fs_read_only(struct bch_fs *c) ...@@ -209,7 +209,8 @@ static void __bch2_fs_read_only(struct bch_fs *c)
bch2_copygc_stop(c); bch2_copygc_stop(c);
bch2_gc_thread_stop(c); bch2_gc_thread_stop(c);
bch_verbose(c, "flushing journal and stopping allocators"); bch_verbose(c, "flushing journal and stopping allocators, journal seq %llu",
journal_cur_seq(&c->journal));
do { do {
clean_passes++; clean_passes++;
...@@ -223,7 +224,8 @@ static void __bch2_fs_read_only(struct bch_fs *c) ...@@ -223,7 +224,8 @@ static void __bch2_fs_read_only(struct bch_fs *c)
} }
} while (clean_passes < 2); } while (clean_passes < 2);
bch_verbose(c, "flushing journal and stopping allocators complete"); bch_verbose(c, "flushing journal and stopping allocators complete, journal seq %llu",
journal_cur_seq(&c->journal));
if (test_bit(JOURNAL_REPLAY_DONE, &c->journal.flags) && if (test_bit(JOURNAL_REPLAY_DONE, &c->journal.flags) &&
!test_bit(BCH_FS_EMERGENCY_RO, &c->flags)) !test_bit(BCH_FS_EMERGENCY_RO, &c->flags))
......
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