diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2016-03-24 05:00:53 -0800 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@gmail.com> | 2016-10-07 12:35:53 -0800 |
commit | e2fc8d4ea450cfe1a3d94d6e563b581c92fbc1a8 (patch) | |
tree | c317704f3fcdeff1723d921a704e787aa3df3eb4 | |
parent | 7bbe9f06877204eedc52eeb206ed7bf9ac89a0cd (diff) |
bcache: Suspend fixes
ugh, hate freezing - ought to be able to suspend correctly now though..
-rw-r--r-- | drivers/md/bcache/alloc.c | 4 | ||||
-rw-r--r-- | drivers/md/bcache/bcache.h | 1 | ||||
-rw-r--r-- | drivers/md/bcache/btree_gc.c | 2 | ||||
-rw-r--r-- | drivers/md/bcache/btree_io.c | 3 | ||||
-rw-r--r-- | drivers/md/bcache/btree_update.c | 8 | ||||
-rw-r--r-- | drivers/md/bcache/fs-io.c | 6 | ||||
-rw-r--r-- | drivers/md/bcache/io.c | 3 | ||||
-rw-r--r-- | drivers/md/bcache/journal.c | 46 | ||||
-rw-r--r-- | drivers/md/bcache/move.c | 3 | ||||
-rw-r--r-- | drivers/md/bcache/movinggc.c | 2 | ||||
-rw-r--r-- | drivers/md/bcache/super.c | 4 | ||||
-rw-r--r-- | drivers/md/bcache/tier.c | 2 | ||||
-rw-r--r-- | drivers/md/bcache/util.c | 6 | ||||
-rw-r--r-- | drivers/md/bcache/writeback.c | 4 |
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, |