summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/md/bcache/alloc.c4
-rw-r--r--drivers/md/bcache/bcache.h1
-rw-r--r--drivers/md/bcache/btree_gc.c2
-rw-r--r--drivers/md/bcache/btree_io.c3
-rw-r--r--drivers/md/bcache/btree_update.c8
-rw-r--r--drivers/md/bcache/fs-io.c6
-rw-r--r--drivers/md/bcache/io.c3
-rw-r--r--drivers/md/bcache/journal.c46
-rw-r--r--drivers/md/bcache/move.c3
-rw-r--r--drivers/md/bcache/movinggc.c2
-rw-r--r--drivers/md/bcache/super.c4
-rw-r--r--drivers/md/bcache/tier.c2
-rw-r--r--drivers/md/bcache/util.c6
-rw-r--r--drivers/md/bcache/writeback.c4
14 files changed, 62 insertions, 32 deletions
diff --git a/drivers/md/bcache/alloc.c b/drivers/md/bcache/alloc.c
index c779bd9071d9..e33eb373ed4a 100644
--- a/drivers/md/bcache/alloc.c
+++ b/drivers/md/bcache/alloc.c
@@ -428,6 +428,7 @@ static int wait_buckets_available(struct cache *ca)
up_read(&ca->set->gc_lock);
schedule();
+ try_to_freeze();
down_read(&ca->set->gc_lock);
}
@@ -770,6 +771,8 @@ static int bch_allocator_thread(void *arg)
struct cache_set *c = ca->set;
int ret;
+ set_freezable();
+
while (1) {
/*
* First, we pull buckets off of the free_inc list, possibly
@@ -802,6 +805,7 @@ static int bch_allocator_thread(void *arg)
goto out;
}
schedule();
+ try_to_freeze();
}
__set_current_state(TASK_RUNNING);
diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h
index e1b3eea39395..ae1d31029943 100644
--- a/drivers/md/bcache/bcache.h
+++ b/drivers/md/bcache/bcache.h
@@ -435,7 +435,6 @@ struct cache {
/* Moving GC: */
struct task_struct *moving_gc_read;
- struct workqueue_struct *moving_gc_write;
struct moving_queue moving_gc_queue;
struct bch_pd_controller moving_gc_pd;
diff --git a/drivers/md/bcache/btree_gc.c b/drivers/md/bcache/btree_gc.c
index 975293880358..1d8d8133a038 100644
--- a/drivers/md/bcache/btree_gc.c
+++ b/drivers/md/bcache/btree_gc.c
@@ -769,6 +769,8 @@ static int bch_gc_thread(void *arg)
struct cache *ca;
unsigned i;
+ set_freezable();
+
while (1) {
unsigned long next = last + c->capacity / 16;
diff --git a/drivers/md/bcache/btree_io.c b/drivers/md/bcache/btree_io.c
index 4f3a7a2cdb76..0b09b1aa4417 100644
--- a/drivers/md/bcache/btree_io.c
+++ b/drivers/md/bcache/btree_io.c
@@ -502,7 +502,8 @@ static void btree_node_write_done(struct closure *cl)
bch_btree_complete_write(c, b, w);
if (btree_node_dirty(b) && c->btree_flush_delay)
- schedule_delayed_work(&b->work, c->btree_flush_delay * HZ);
+ queue_delayed_work(system_freezable_wq, &b->work,
+ c->btree_flush_delay * HZ);
closure_return_with_destructor(cl, btree_node_write_unlock);
}
diff --git a/drivers/md/bcache/btree_update.c b/drivers/md/bcache/btree_update.c
index cef1f7bb8d28..bc6d610871bb 100644
--- a/drivers/md/bcache/btree_update.c
+++ b/drivers/md/bcache/btree_update.c
@@ -746,8 +746,8 @@ void bch_btree_insert_and_journal(struct btree_iter *iter,
set_btree_node_dirty(b);
if (c->btree_flush_delay)
- schedule_delayed_work(&b->work,
- c->btree_flush_delay * HZ);
+ queue_delayed_work(system_freezable_wq, &b->work,
+ c->btree_flush_delay * HZ);
}
if (res->ref ||
@@ -1090,7 +1090,7 @@ static void async_split_updated_btree(struct async_split *as,
mutex_unlock(&as->c->async_split_lock);
- continue_at(&as->cl, async_split_nodes_written, system_wq);
+ continue_at(&as->cl, async_split_nodes_written, system_freezable_wq);
}
static void async_split_updated_root(struct async_split *as,
@@ -1121,7 +1121,7 @@ static void async_split_updated_root(struct async_split *as,
mutex_unlock(&as->c->async_split_lock);
- continue_at(&as->cl, async_split_nodes_written, system_wq);
+ continue_at(&as->cl, async_split_nodes_written, system_freezable_wq);
}
/*
diff --git a/drivers/md/bcache/fs-io.c b/drivers/md/bcache/fs-io.c
index 360bec8ae25c..89504f6f7186 100644
--- a/drivers/md/bcache/fs-io.c
+++ b/drivers/md/bcache/fs-io.c
@@ -1436,7 +1436,7 @@ static void bch_dio_write_loop_async(struct closure *cl)
continue_at(&dio->cl,
bch_dio_write_loop_async,
- dio->iter.count ? system_wq : NULL);
+ dio->iter.count ? system_freezable_wq : NULL);
} else {
#if 0
closure_return_with_destructor(cl, bch_dio_write_complete);
@@ -1566,8 +1566,8 @@ static int bch_direct_IO_write(struct cache_set *c, struct kiocb *req,
}
continue_at_noreturn(&dio->cl,
- bch_dio_write_loop_async,
- dio->iter.count ? system_wq : NULL);
+ bch_dio_write_loop_async,
+ dio->iter.count ? system_freezable_wq : NULL);
return -EIOCBQUEUED;
}
err_put_sectors_dirty:
diff --git a/drivers/md/bcache/io.c b/drivers/md/bcache/io.c
index 9dad04182c35..31555fd92c19 100644
--- a/drivers/md/bcache/io.c
+++ b/drivers/md/bcache/io.c
@@ -1047,6 +1047,9 @@ static void __bch_write(struct closure *cl)
* Otherwise, we do want to block the caller on alloc
* failure instead of letting it queue up more and more
* writes:
+ * XXX: this technically needs a try_to_freeze() -
+ * except that that's not safe because caller may have
+ * issued other IO... hmm..
*/
closure_sync(cl);
continue;
diff --git a/drivers/md/bcache/journal.c b/drivers/md/bcache/journal.c
index 5994c08c48ae..3fdc27bdcbe5 100644
--- a/drivers/md/bcache/journal.c
+++ b/drivers/md/bcache/journal.c
@@ -958,7 +958,7 @@ void bch_journal_start(struct cache_set *c)
journal_entry_open(j);
spin_unlock(&j->lock);
- queue_work(system_long_wq, &j->reclaim_work);
+ queue_work(system_freezable_wq, &j->reclaim_work);
}
int bch_journal_replay(struct cache_set *c, struct list_head *list)
@@ -1155,12 +1155,22 @@ static void journal_reclaim_work(struct work_struct *work)
while (ja->last_idx != cur_idx &&
ja->bucket_seq[ja->last_idx] < last_seq) {
if (ca->mi.discard &&
- blk_queue_discard(bdev_get_queue(ca->disk_sb.bdev)))
+ blk_queue_discard(bdev_get_queue(ca->disk_sb.bdev))) {
+ /*
+ * ugh:
+ * might be called from __journal_res_get()
+ * under wait_event() - have to go back to
+ * TASK_RUNNING before doing something that
+ * would block, but only if we're doing work:
+ */
+ __set_current_state(TASK_RUNNING);
+
blkdev_issue_discard(ca->disk_sb.bdev,
bucket_to_sector(ca,
journal_bucket(ca,
ja->last_idx)),
ca->mi.bucket_size, GFP_NOIO, 0);
+ }
spin_lock(&j->lock);
ja->last_idx = (ja->last_idx + 1) % nr;
@@ -1204,6 +1214,7 @@ restart_flush:
list_del_init(&pin->list);
spin_unlock_irq(&j->pin_lock);
+ __set_current_state(TASK_RUNNING);
pin->flush(pin);
spin_lock_irq(&j->pin_lock);
@@ -1341,7 +1352,7 @@ static int journal_next_bucket(struct cache_set *c)
rcu_read_unlock();
- queue_work(system_long_wq, &j->reclaim_work);
+ queue_work(system_freezable_wq, &j->reclaim_work);
return ret;
}
@@ -1425,13 +1436,13 @@ static void journal_write_done(struct closure *cl)
wake_up(&j->wait);
if (test_bit(JOURNAL_NEED_WRITE, &j->flags))
- mod_delayed_work(system_wq, &j->write_work, 0);
+ mod_delayed_work(system_freezable_wq, &j->write_work, 0);
/*
* Updating last_seq_ondisk may let journal_reclaim_work() discard more
* buckets:
*/
- queue_work(system_long_wq, &j->reclaim_work);
+ queue_work(system_freezable_wq, &j->reclaim_work);
}
static void journal_write_compact(struct jset *jset)
@@ -1730,8 +1741,9 @@ void bch_journal_res_put(struct journal *j, struct journal_res *res,
if (!test_bit(JOURNAL_DIRTY, &j->flags)) {
set_bit(JOURNAL_DIRTY, &j->flags);
- schedule_delayed_work(&j->write_work,
- msecs_to_jiffies(j->delay_ms));
+ queue_delayed_work(system_freezable_wq,
+ &j->write_work,
+ msecs_to_jiffies(j->delay_ms));
/* between set_bit() and *journal_seq = j->seq */
smp_wmb();
@@ -1820,7 +1832,7 @@ static int __journal_res_get(struct journal *j, struct journal_res *res,
*/
spin_lock(&j->lock);
-
+get:
/*
* Recheck after taking the lock, so we don't race with another
* thread that just did journal_entry_open() and call
@@ -1871,14 +1883,20 @@ static int __journal_res_get(struct journal *j, struct journal_res *res,
return ret;
}
- if (!journal_bucket_has_room(j)) {
- /* Still no room, we have to wait */
- spin_unlock(&j->lock);
- trace_bcache_journal_full(c);
- return 0;
- }
+ if (journal_bucket_has_room(j))
+ goto get;
+
+ /* Still no room, we have to wait */
spin_unlock(&j->lock);
+ trace_bcache_journal_full(c);
+
+ /*
+ * Direct reclaim - can't rely on reclaim from work item
+ * due to freezing..
+ */
+ journal_reclaim_work(&j->reclaim_work);
+ return 0;
}
}
}
diff --git a/drivers/md/bcache/move.c b/drivers/md/bcache/move.c
index 8333e35e51f0..35dc555b442e 100644
--- a/drivers/md/bcache/move.c
+++ b/drivers/md/bcache/move.c
@@ -291,7 +291,8 @@ int bch_queue_start(struct moving_queue *q,
/* Re-use workqueue if already started */
if (!q->wq)
- q->wq = alloc_workqueue(name, WQ_UNBOUND|WQ_MEM_RECLAIM, 1);
+ q->wq = alloc_workqueue(name,
+ WQ_UNBOUND|WQ_FREEZABLE|WQ_MEM_RECLAIM, 1);
if (!q->wq)
return -ENOMEM;
diff --git a/drivers/md/bcache/movinggc.c b/drivers/md/bcache/movinggc.c
index 3aeebeba7b97..cdee43d4f316 100644
--- a/drivers/md/bcache/movinggc.c
+++ b/drivers/md/bcache/movinggc.c
@@ -280,6 +280,8 @@ static int bch_moving_gc_thread(void *arg)
unsigned long last;
bool moved;
+ set_freezable();
+
while (!kthread_should_stop()) {
if (kthread_wait_freezable(c->copy_gc_enabled))
break;
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index 5eae7eadf678..6c75d67da7f6 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -794,7 +794,7 @@ bool bch_cache_set_read_only(struct cache_set *c)
*/
percpu_ref_kill(&c->writes);
- queue_work(system_unbound_wq, &c->read_only_work);
+ queue_work(system_freezable_wq, &c->read_only_work);
return true;
}
@@ -2412,7 +2412,7 @@ static int __init bcache_init(void)
if (IS_ERR(bch_chardev))
goto err;
- if (!(bcache_io_wq = alloc_workqueue("bcache_io", WQ_MEM_RECLAIM, 0)) ||
+ if (!(bcache_io_wq = create_freezable_workqueue("bcache_io")) ||
!(bcache_kset = kset_create_and_add("bcache", NULL, fs_kobj)) ||
sysfs_create_files(&bcache_kset->kobj, files) ||
bch_blockdev_init() ||
diff --git a/drivers/md/bcache/tier.c b/drivers/md/bcache/tier.c
index 07a1456814dd..53653f6ea478 100644
--- a/drivers/md/bcache/tier.c
+++ b/drivers/md/bcache/tier.c
@@ -371,6 +371,8 @@ static int bch_tiering_thread(void *arg)
unsigned long last;
unsigned i;
+ set_freezable();
+
while (!kthread_should_stop()) {
if (kthread_wait_freezable(c->tiering_enabled &&
c->cache_tiers[1].nr_devices))
diff --git a/drivers/md/bcache/util.c b/drivers/md/bcache/util.c
index b0ae1a4c6a7a..a9111aa3c426 100644
--- a/drivers/md/bcache/util.c
+++ b/drivers/md/bcache/util.c
@@ -253,11 +253,7 @@ int bch_ratelimit_wait_freezable_stoppable(struct bch_ratelimit *d,
return 0;
schedule_timeout(delay);
-
- if (freezing(current)) {
- closure_sync(cl);
- try_to_freeze();
- }
+ try_to_freeze();
}
}
diff --git a/drivers/md/bcache/writeback.c b/drivers/md/bcache/writeback.c
index 53ceb56a6a38..01650b86da0c 100644
--- a/drivers/md/bcache/writeback.c
+++ b/drivers/md/bcache/writeback.c
@@ -186,7 +186,7 @@ static void read_dirty_submit(struct closure *cl)
closure_bio_submit(&io->bio, cl);
- continue_at(cl, write_dirty, system_wq);
+ continue_at(cl, write_dirty, system_freezable_wq);
}
static u64 read_dirty(struct cached_dev *dc)
@@ -477,6 +477,8 @@ static int bch_writeback_thread(void *arg)
unsigned long last;
u64 sectors_written;
+ set_freezable();
+
while (!kthread_should_stop()) {
if (kthread_wait_freezable(dc->writeback_running ||
test_bit(BCACHE_DEV_DETACHING,