mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-17 18:56:24 +00:00
bcachefs: Finish writing journal after journal error
After emergency shutdown, all journal entries will be written as noflush entries, meaning they will never be used - but they'll still exist for debugging tools to examine. Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
This commit is contained in:
parent
24a3d53b28
commit
e0c014e7e4
@ -62,35 +62,6 @@ static void journal_pin_list_init(struct journal_entry_pin_list *p, int count)
|
|||||||
p->devs.nr = 0;
|
p->devs.nr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bch2_journal_halt(struct journal *j)
|
|
||||||
{
|
|
||||||
union journal_res_state old, new;
|
|
||||||
u64 v;
|
|
||||||
|
|
||||||
spin_lock(&j->lock);
|
|
||||||
|
|
||||||
v = atomic64_read(&j->reservations.counter);
|
|
||||||
do {
|
|
||||||
old.v = new.v = v;
|
|
||||||
if (old.cur_entry_offset == JOURNAL_ENTRY_ERROR_VAL)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
new.cur_entry_offset = JOURNAL_ENTRY_ERROR_VAL;
|
|
||||||
} while ((v = atomic64_cmpxchg(&j->reservations.counter,
|
|
||||||
old.v, new.v)) != old.v);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* XXX: we're not using j->lock here because this can be called from
|
|
||||||
* interrupt context, this can race with journal_write_done()
|
|
||||||
*/
|
|
||||||
if (!j->err_seq)
|
|
||||||
j->err_seq = journal_cur_seq(j);
|
|
||||||
journal_wake(j);
|
|
||||||
closure_wake_up(&journal_cur_buf(j)->wait);
|
|
||||||
out:
|
|
||||||
spin_unlock(&j->lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* journal entry close/open: */
|
/* journal entry close/open: */
|
||||||
|
|
||||||
void __bch2_journal_buf_put(struct journal *j)
|
void __bch2_journal_buf_put(struct journal *j)
|
||||||
@ -106,7 +77,7 @@ void __bch2_journal_buf_put(struct journal *j)
|
|||||||
* We don't close a journal_buf until the next journal_buf is finished writing,
|
* We don't close a journal_buf until the next journal_buf is finished writing,
|
||||||
* and can be opened again - this also initializes the next journal_buf:
|
* and can be opened again - this also initializes the next journal_buf:
|
||||||
*/
|
*/
|
||||||
static void __journal_entry_close(struct journal *j)
|
static void __journal_entry_close(struct journal *j, unsigned closed_val)
|
||||||
{
|
{
|
||||||
struct bch_fs *c = container_of(j, struct bch_fs, journal);
|
struct bch_fs *c = container_of(j, struct bch_fs, journal);
|
||||||
struct journal_buf *buf = journal_cur_buf(j);
|
struct journal_buf *buf = journal_cur_buf(j);
|
||||||
@ -114,23 +85,24 @@ static void __journal_entry_close(struct journal *j)
|
|||||||
u64 v = atomic64_read(&j->reservations.counter);
|
u64 v = atomic64_read(&j->reservations.counter);
|
||||||
unsigned sectors;
|
unsigned sectors;
|
||||||
|
|
||||||
|
BUG_ON(closed_val != JOURNAL_ENTRY_CLOSED_VAL &&
|
||||||
|
closed_val != JOURNAL_ENTRY_ERROR_VAL);
|
||||||
|
|
||||||
lockdep_assert_held(&j->lock);
|
lockdep_assert_held(&j->lock);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
old.v = new.v = v;
|
old.v = new.v = v;
|
||||||
if (old.cur_entry_offset == JOURNAL_ENTRY_CLOSED_VAL)
|
new.cur_entry_offset = closed_val;
|
||||||
return;
|
|
||||||
|
|
||||||
if (old.cur_entry_offset == JOURNAL_ENTRY_ERROR_VAL) {
|
if (old.cur_entry_offset == JOURNAL_ENTRY_ERROR_VAL ||
|
||||||
/* this entry will never be written: */
|
old.cur_entry_offset == new.cur_entry_offset)
|
||||||
closure_wake_up(&buf->wait);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
new.cur_entry_offset = JOURNAL_ENTRY_CLOSED_VAL;
|
|
||||||
} while ((v = atomic64_cmpxchg(&j->reservations.counter,
|
} while ((v = atomic64_cmpxchg(&j->reservations.counter,
|
||||||
old.v, new.v)) != old.v);
|
old.v, new.v)) != old.v);
|
||||||
|
|
||||||
|
if (!__journal_entry_is_open(old))
|
||||||
|
return;
|
||||||
|
|
||||||
/* Close out old buffer: */
|
/* Close out old buffer: */
|
||||||
buf->data->u64s = cpu_to_le32(old.cur_entry_offset);
|
buf->data->u64s = cpu_to_le32(old.cur_entry_offset);
|
||||||
|
|
||||||
@ -171,6 +143,15 @@ static void __journal_entry_close(struct journal *j)
|
|||||||
bch2_journal_buf_put(j, old.idx);
|
bch2_journal_buf_put(j, old.idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void bch2_journal_halt(struct journal *j)
|
||||||
|
{
|
||||||
|
spin_lock(&j->lock);
|
||||||
|
__journal_entry_close(j, JOURNAL_ENTRY_ERROR_VAL);
|
||||||
|
if (!j->err_seq)
|
||||||
|
j->err_seq = journal_cur_seq(j);
|
||||||
|
spin_unlock(&j->lock);
|
||||||
|
}
|
||||||
|
|
||||||
static bool journal_entry_want_write(struct journal *j)
|
static bool journal_entry_want_write(struct journal *j)
|
||||||
{
|
{
|
||||||
bool ret = !journal_entry_is_open(j) ||
|
bool ret = !journal_entry_is_open(j) ||
|
||||||
@ -178,7 +159,7 @@ static bool journal_entry_want_write(struct journal *j)
|
|||||||
|
|
||||||
/* Don't close it yet if we already have a write in flight: */
|
/* Don't close it yet if we already have a write in flight: */
|
||||||
if (ret)
|
if (ret)
|
||||||
__journal_entry_close(j);
|
__journal_entry_close(j, JOURNAL_ENTRY_CLOSED_VAL);
|
||||||
else if (nr_unwritten_journal_entries(j)) {
|
else if (nr_unwritten_journal_entries(j)) {
|
||||||
struct journal_buf *buf = journal_cur_buf(j);
|
struct journal_buf *buf = journal_cur_buf(j);
|
||||||
|
|
||||||
@ -312,8 +293,7 @@ static int journal_entry_open(struct journal *j)
|
|||||||
|
|
||||||
static bool journal_quiesced(struct journal *j)
|
static bool journal_quiesced(struct journal *j)
|
||||||
{
|
{
|
||||||
bool ret = atomic64_read(&j->seq) == j->seq_ondisk ||
|
bool ret = atomic64_read(&j->seq) == j->seq_ondisk;
|
||||||
bch2_journal_error(j);
|
|
||||||
|
|
||||||
if (!ret)
|
if (!ret)
|
||||||
journal_entry_close(j);
|
journal_entry_close(j);
|
||||||
@ -339,7 +319,7 @@ static void journal_write_work(struct work_struct *work)
|
|||||||
if (delta > 0)
|
if (delta > 0)
|
||||||
mod_delayed_work(c->io_complete_wq, &j->write_work, delta);
|
mod_delayed_work(c->io_complete_wq, &j->write_work, delta);
|
||||||
else
|
else
|
||||||
__journal_entry_close(j);
|
__journal_entry_close(j, JOURNAL_ENTRY_CLOSED_VAL);
|
||||||
spin_unlock(&j->lock);
|
spin_unlock(&j->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -390,7 +370,7 @@ retry:
|
|||||||
buf->buf_size < JOURNAL_ENTRY_SIZE_MAX)
|
buf->buf_size < JOURNAL_ENTRY_SIZE_MAX)
|
||||||
j->buf_size_want = max(j->buf_size_want, buf->buf_size << 1);
|
j->buf_size_want = max(j->buf_size_want, buf->buf_size << 1);
|
||||||
|
|
||||||
__journal_entry_close(j);
|
__journal_entry_close(j, JOURNAL_ENTRY_CLOSED_VAL);
|
||||||
ret = journal_entry_open(j);
|
ret = journal_entry_open(j);
|
||||||
|
|
||||||
if (ret == cur_entry_max_in_flight)
|
if (ret == cur_entry_max_in_flight)
|
||||||
@ -526,7 +506,7 @@ void bch2_journal_entry_res_resize(struct journal *j,
|
|||||||
/*
|
/*
|
||||||
* Not enough room in current journal entry, have to flush it:
|
* Not enough room in current journal entry, have to flush it:
|
||||||
*/
|
*/
|
||||||
__journal_entry_close(j);
|
__journal_entry_close(j, JOURNAL_ENTRY_CLOSED_VAL);
|
||||||
} else {
|
} else {
|
||||||
journal_cur_buf(j)->u64s_reserved += d;
|
journal_cur_buf(j)->u64s_reserved += d;
|
||||||
}
|
}
|
||||||
@ -578,7 +558,7 @@ recheck_need_open:
|
|||||||
struct journal_res res = { 0 };
|
struct journal_res res = { 0 };
|
||||||
|
|
||||||
if (journal_entry_is_open(j))
|
if (journal_entry_is_open(j))
|
||||||
__journal_entry_close(j);
|
__journal_entry_close(j, JOURNAL_ENTRY_CLOSED_VAL);
|
||||||
|
|
||||||
spin_unlock(&j->lock);
|
spin_unlock(&j->lock);
|
||||||
|
|
||||||
|
@ -1513,11 +1513,11 @@ void bch2_journal_write(struct closure *cl)
|
|||||||
j->write_start_time = local_clock();
|
j->write_start_time = local_clock();
|
||||||
|
|
||||||
spin_lock(&j->lock);
|
spin_lock(&j->lock);
|
||||||
if (c->sb.features & (1ULL << BCH_FEATURE_journal_no_flush) &&
|
if (bch2_journal_error(j) ||
|
||||||
(w->noflush ||
|
w->noflush ||
|
||||||
(!w->must_flush &&
|
(!w->must_flush &&
|
||||||
(jiffies - j->last_flush_write) < msecs_to_jiffies(c->opts.journal_flush_delay) &&
|
(jiffies - j->last_flush_write) < msecs_to_jiffies(c->opts.journal_flush_delay) &&
|
||||||
test_bit(JOURNAL_MAY_SKIP_FLUSH, &j->flags)))) {
|
test_bit(JOURNAL_MAY_SKIP_FLUSH, &j->flags))) {
|
||||||
w->noflush = true;
|
w->noflush = true;
|
||||||
SET_JSET_NO_FLUSH(jset, true);
|
SET_JSET_NO_FLUSH(jset, true);
|
||||||
jset->last_seq = 0;
|
jset->last_seq = 0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user