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

bcachefs: Fix hang while shutting down

If the allocator thread exited before bch2_dev_allocator_stop() was
called (because of an error), bch2_dev_allocator_quiesce() could hang.
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 53beb841
...@@ -598,6 +598,9 @@ static int wait_buckets_available(struct bch_fs *c, struct bch_dev *ca) ...@@ -598,6 +598,9 @@ static int wait_buckets_available(struct bch_fs *c, struct bch_dev *ca)
unsigned long gc_count = c->gc_count; unsigned long gc_count = c->gc_count;
int ret = 0; int ret = 0;
ca->allocator_state = ALLOCATOR_BLOCKED;
closure_wake_up(&c->freelist_wait);
while (1) { while (1) {
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
if (kthread_should_stop()) { if (kthread_should_stop()) {
...@@ -620,6 +623,9 @@ static int wait_buckets_available(struct bch_fs *c, struct bch_dev *ca) ...@@ -620,6 +623,9 @@ static int wait_buckets_available(struct bch_fs *c, struct bch_dev *ca)
} }
__set_current_state(TASK_RUNNING); __set_current_state(TASK_RUNNING);
ca->allocator_state = ALLOCATOR_RUNNING;
closure_wake_up(&c->freelist_wait);
return ret; return ret;
} }
...@@ -1119,14 +1125,14 @@ static int push_invalidated_bucket(struct bch_fs *c, struct bch_dev *ca, size_t ...@@ -1119,14 +1125,14 @@ static int push_invalidated_bucket(struct bch_fs *c, struct bch_dev *ca, size_t
fifo_pop(&ca->free_inc, bucket); fifo_pop(&ca->free_inc, bucket);
closure_wake_up(&c->freelist_wait); closure_wake_up(&c->freelist_wait);
ca->allocator_blocked_full = false; ca->allocator_state = ALLOCATOR_RUNNING;
spin_unlock(&c->freelist_lock); spin_unlock(&c->freelist_lock);
goto out; goto out;
} }
if (!ca->allocator_blocked_full) { if (ca->allocator_state != ALLOCATOR_BLOCKED_FULL) {
ca->allocator_blocked_full = true; ca->allocator_state = ALLOCATOR_BLOCKED_FULL;
closure_wake_up(&c->freelist_wait); closure_wake_up(&c->freelist_wait);
} }
...@@ -1184,6 +1190,7 @@ static int bch2_allocator_thread(void *arg) ...@@ -1184,6 +1190,7 @@ static int bch2_allocator_thread(void *arg)
int ret; int ret;
set_freezable(); set_freezable();
ca->allocator_state = ALLOCATOR_RUNNING;
while (1) { while (1) {
cond_resched(); cond_resched();
...@@ -1242,9 +1249,6 @@ static int bch2_allocator_thread(void *arg) ...@@ -1242,9 +1249,6 @@ static int bch2_allocator_thread(void *arg)
if (!nr || if (!nr ||
(nr < ALLOC_SCAN_BATCH(ca) && (nr < ALLOC_SCAN_BATCH(ca) &&
!fifo_full(&ca->free[RESERVE_MOVINGGC]))) { !fifo_full(&ca->free[RESERVE_MOVINGGC]))) {
ca->allocator_blocked = true;
closure_wake_up(&c->freelist_wait);
ret = wait_buckets_available(c, ca); ret = wait_buckets_available(c, ca);
if (ret) { if (ret) {
up_read(&c->gc_lock); up_read(&c->gc_lock);
...@@ -1253,7 +1257,6 @@ static int bch2_allocator_thread(void *arg) ...@@ -1253,7 +1257,6 @@ static int bch2_allocator_thread(void *arg)
} }
} while (!nr); } while (!nr);
ca->allocator_blocked = false;
up_read(&c->gc_lock); up_read(&c->gc_lock);
pr_debug("%zu buckets to invalidate", nr); pr_debug("%zu buckets to invalidate", nr);
...@@ -1266,6 +1269,8 @@ static int bch2_allocator_thread(void *arg) ...@@ -1266,6 +1269,8 @@ static int bch2_allocator_thread(void *arg)
stop: stop:
pr_debug("alloc thread stopping (ret %i)", ret); pr_debug("alloc thread stopping (ret %i)", ret);
ca->allocator_state = ALLOCATOR_STOPPED;
closure_wake_up(&c->freelist_wait);
return 0; return 0;
} }
...@@ -1457,7 +1462,8 @@ void bch2_dev_allocator_add(struct bch_fs *c, struct bch_dev *ca) ...@@ -1457,7 +1462,8 @@ void bch2_dev_allocator_add(struct bch_fs *c, struct bch_dev *ca)
void bch2_dev_allocator_quiesce(struct bch_fs *c, struct bch_dev *ca) void bch2_dev_allocator_quiesce(struct bch_fs *c, struct bch_dev *ca)
{ {
if (ca->alloc_thread) if (ca->alloc_thread)
closure_wait_event(&c->freelist_wait, ca->allocator_blocked_full); closure_wait_event(&c->freelist_wait,
ca->allocator_state != ALLOCATOR_RUNNING);
} }
/* stop allocator thread: */ /* stop allocator thread: */
......
...@@ -447,8 +447,12 @@ struct bch_dev { ...@@ -447,8 +447,12 @@ struct bch_dev {
* XXX: this should be an enum for allocator state, so as to include * XXX: this should be an enum for allocator state, so as to include
* error state * error state
*/ */
bool allocator_blocked; enum {
bool allocator_blocked_full; ALLOCATOR_STOPPED,
ALLOCATOR_RUNNING,
ALLOCATOR_BLOCKED,
ALLOCATOR_BLOCKED_FULL,
} allocator_state;
alloc_heap alloc_heap; alloc_heap alloc_heap;
......
...@@ -116,7 +116,7 @@ static bool have_copygc_reserve(struct bch_dev *ca) ...@@ -116,7 +116,7 @@ static bool have_copygc_reserve(struct bch_dev *ca)
spin_lock(&ca->freelist_lock); spin_lock(&ca->freelist_lock);
ret = fifo_full(&ca->free[RESERVE_MOVINGGC]) || ret = fifo_full(&ca->free[RESERVE_MOVINGGC]) ||
ca->allocator_blocked; ca->allocator_state != ALLOCATOR_RUNNING;
spin_unlock(&ca->freelist_lock); spin_unlock(&ca->freelist_lock);
return ret; return ret;
......
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