summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2018-01-27 20:46:40 -0500
committerKent Overstreet <kent.overstreet@gmail.com>2018-01-30 20:41:35 -0500
commitc2c02d3afbf6ecf400eb9c71d366de0e710682c3 (patch)
tree7d29aa2dfa129d1a282a35d44963cb0577568da5
parentbe06b3e44c36cac596a8e2193c8e5772c653a901 (diff)
bcachefs: fix another deadlock
-rw-r--r--fs/bcachefs/btree_update_interior.c34
-rw-r--r--fs/bcachefs/journal.c57
-rw-r--r--fs/bcachefs/journal.h3
-rw-r--r--fs/bcachefs/journal_types.h1
4 files changed, 77 insertions, 18 deletions
diff --git a/fs/bcachefs/btree_update_interior.c b/fs/bcachefs/btree_update_interior.c
index 4a75b2e8705c..2ce45bcecbbb 100644
--- a/fs/bcachefs/btree_update_interior.c
+++ b/fs/bcachefs/btree_update_interior.c
@@ -601,8 +601,7 @@ static void bch2_btree_update_free(struct btree_update *as)
static void btree_update_nodes_reachable(struct closure *cl)
{
- struct btree_update *as =
- container_of(cl, struct btree_update, cl);
+ struct btree_update *as = container_of(cl, struct btree_update, cl);
struct bch_fs *c = as->c;
bch2_journal_pin_drop(&c->journal, &as->journal);
@@ -636,10 +635,26 @@ static void btree_update_nodes_reachable(struct closure *cl)
bch2_btree_update_free(as);
}
+static void btree_update_wait_on_journal(struct closure *cl)
+{
+ struct btree_update *as = container_of(cl, struct btree_update, cl);
+ struct bch_fs *c = as->c;
+ int ret;
+
+ ret = bch2_journal_open_seq_async(&c->journal, as->journal_seq, cl);
+ if (ret < 0)
+ goto err;
+ if (!ret)
+ continue_at(cl, btree_update_wait_on_journal, system_wq);
+
+ bch2_journal_flush_seq_async(&c->journal, as->journal_seq, cl);
+err:
+ continue_at(cl, btree_update_nodes_reachable, system_wq);
+}
+
static void btree_update_nodes_written(struct closure *cl)
{
- struct btree_update *as =
- container_of(cl, struct btree_update, cl);
+ struct btree_update *as = container_of(cl, struct btree_update, cl);
struct bch_fs *c = as->c;
struct btree *b;
@@ -736,13 +751,10 @@ retry:
*/
bch2_journal_pin_drop(&c->journal, &as->journal);
- /*
- * And, do a journal write to write the pointer to the new root,
- * then wait for it to complete before freeing the nodes we
- * replaced:
- */
- bch2_journal_meta_async(&c->journal, cl);
- break;
+ as->journal_seq = bch2_journal_last_unwritten_seq(&c->journal);
+
+ btree_update_wait_on_journal(cl);
+ return;
}
continue_at(cl, btree_update_nodes_reachable, system_wq);
diff --git a/fs/bcachefs/journal.c b/fs/bcachefs/journal.c
index 5bfa7cd0ca4b..1870534df6d0 100644
--- a/fs/bcachefs/journal.c
+++ b/fs/bcachefs/journal.c
@@ -31,6 +31,12 @@ static void journal_pin_add_entry(struct journal *,
struct journal_entry_pin *,
journal_pin_flush_fn);
+static inline void journal_wake(struct journal *j)
+{
+ wake_up(&j->wait);
+ closure_wake_up(&j->async_wait);
+}
+
static inline struct journal_buf *journal_cur_buf(struct journal *j)
{
return j->buf + j->reservations.idx;
@@ -1280,7 +1286,7 @@ void bch2_journal_halt(struct journal *j)
} while ((v = atomic64_cmpxchg(&j->reservations.counter,
old.v, new.v)) != old.v);
- wake_up(&j->wait);
+ journal_wake(j);
closure_wake_up(&journal_cur_buf(j)->wait);
closure_wake_up(&journal_prev_buf(j)->wait);
}
@@ -1449,7 +1455,7 @@ static int journal_entry_open(struct journal *j)
mod_delayed_work(system_freezable_wq,
&j->write_work,
msecs_to_jiffies(j->write_delay_ms));
- wake_up(&j->wait);
+ journal_wake(j);
return 1;
}
@@ -1545,7 +1551,7 @@ int bch2_journal_replay(struct bch_fs *c, struct list_head *list)
}
if (atomic_dec_and_test(&j->replay_pin_list->count))
- wake_up(&j->wait);
+ journal_wake(j);
}
j->replay_pin_list = NULL;
@@ -1712,7 +1718,7 @@ static void journal_reclaim_fast(struct journal *j)
}
if (popped)
- wake_up(&j->wait);
+ journal_wake(j);
}
/*
@@ -1741,7 +1747,7 @@ static inline void __journal_pin_add(struct journal *j,
* If the journal is currently full, we might want to call flush_fn
* immediately:
*/
- wake_up(&j->wait);
+ journal_wake(j);
}
static void journal_pin_add_entry(struct journal *j,
@@ -1991,7 +1997,7 @@ static void journal_reclaim_work(struct work_struct *work)
ja->last_idx = (ja->last_idx + 1) % ja->nr;
spin_unlock(&j->lock);
- wake_up(&j->wait);
+ journal_wake(j);
}
/*
@@ -2231,7 +2237,7 @@ out:
&j->reservations.counter);
closure_wake_up(&w->wait);
- wake_up(&j->wait);
+ journal_wake(j);
if (test_bit(JOURNAL_NEED_WRITE, &j->flags))
mod_delayed_work(system_freezable_wq, &j->write_work, 0);
@@ -2536,6 +2542,43 @@ int bch2_journal_res_get_slowpath(struct journal *j, struct journal_res *res,
return ret < 0 ? ret : 0;
}
+u64 bch2_journal_last_unwritten_seq(struct journal *j)
+{
+ u64 seq;
+
+ spin_lock(&j->lock);
+ seq = atomic64_read(&j->seq);
+ if (j->reservations.prev_buf_unwritten)
+ seq--;
+ spin_unlock(&j->lock);
+
+ return seq;
+}
+
+int bch2_journal_open_seq_async(struct journal *j, u64 seq, struct closure *parent)
+{
+ int ret;
+
+ spin_lock(&j->lock);
+ BUG_ON(seq > atomic64_read(&j->seq));
+
+ if (seq < atomic64_read(&j->seq) ||
+ journal_entry_is_open(j)) {
+ spin_unlock(&j->lock);
+ return 1;
+ }
+
+ ret = journal_entry_open(j);
+ if (!ret)
+ closure_wait(&j->async_wait, parent);
+ spin_unlock(&j->lock);
+
+ if (!ret)
+ journal_reclaim_work(&j->reclaim_work.work);
+
+ return ret;
+}
+
void bch2_journal_wait_on_seq(struct journal *j, u64 seq, struct closure *parent)
{
spin_lock(&j->lock);
diff --git a/fs/bcachefs/journal.h b/fs/bcachefs/journal.h
index ebb846438915..9461d2d8a23e 100644
--- a/fs/bcachefs/journal.h
+++ b/fs/bcachefs/journal.h
@@ -354,6 +354,9 @@ out:
return 0;
}
+u64 bch2_journal_last_unwritten_seq(struct journal *);
+int bch2_journal_open_seq_async(struct journal *, u64, struct closure *);
+
void bch2_journal_wait_on_seq(struct journal *, u64, struct closure *);
void bch2_journal_flush_seq_async(struct journal *, u64, struct closure *);
void bch2_journal_flush_async(struct journal *, struct closure *);
diff --git a/fs/bcachefs/journal_types.h b/fs/bcachefs/journal_types.h
index 52fc7a6ca27d..e39b18f27058 100644
--- a/fs/bcachefs/journal_types.h
+++ b/fs/bcachefs/journal_types.h
@@ -140,6 +140,7 @@ struct journal {
/* Used when waiting because the journal was full */
wait_queue_head_t wait;
+ struct closure_waitlist async_wait;
struct closure io;
struct delayed_work write_work;