diff options
-rw-r--r-- | drivers/md/bcache/btree_types.h | 1 | ||||
-rw-r--r-- | drivers/md/bcache/btree_update.c | 15 | ||||
-rw-r--r-- | drivers/md/bcache/buckets.c | 14 | ||||
-rw-r--r-- | drivers/md/bcache/buckets.h | 5 | ||||
-rw-r--r-- | drivers/md/bcache/extents.c | 23 |
5 files changed, 46 insertions, 12 deletions
diff --git a/drivers/md/bcache/btree_types.h b/drivers/md/bcache/btree_types.h index f294aa2965c9..2472fdce10af 100644 --- a/drivers/md/bcache/btree_types.h +++ b/drivers/md/bcache/btree_types.h @@ -167,6 +167,7 @@ enum btree_insert_ret { BTREE_INSERT_BTREE_NODE_FULL, BTREE_INSERT_JOURNAL_RES_FULL, BTREE_INSERT_ENOSPC, + BTREE_INSERT_NEED_GC_LOCK, }; #endif /* _BCACHE_BTREE_TYPES_H */ diff --git a/drivers/md/bcache/btree_update.c b/drivers/md/bcache/btree_update.c index 5b4a743a1f8f..ad7e3d9790d4 100644 --- a/drivers/md/bcache/btree_update.c +++ b/drivers/md/bcache/btree_update.c @@ -1561,8 +1561,9 @@ int __bch_btree_insert_at(struct btree_insert *trans, u64 *journal_seq) struct cache_set *c = trans->c; struct journal_res res = { 0, 0 }; struct btree_insert_entry *i; - struct btree_iter *split; + struct btree_iter *split = NULL; struct closure cl; + bool cycle_gc_lock = false; unsigned u64s; int ret; @@ -1619,6 +1620,7 @@ retry: ret = 0; split = NULL; + cycle_gc_lock = false; trans_for_each_entry(trans, i) { if (i->done) @@ -1641,6 +1643,12 @@ retry: case BTREE_INSERT_ENOSPC: ret = -ENOSPC; break; + case BTREE_INSERT_NEED_GC_LOCK: + cycle_gc_lock = true; + ret = -EINTR; + break; + default: + BUG(); } if (!trans->did_work && (ret || split)) @@ -1689,6 +1697,11 @@ err: ret = -EINTR; } + if (cycle_gc_lock) { + down_read(&c->gc_lock); + up_read(&c->gc_lock); + } + /* * Main rule is, BTREE_INSERT_ATOMIC means we can't call * bch_btree_iter_traverse(), because if we have to we either dropped diff --git a/drivers/md/bcache/buckets.c b/drivers/md/bcache/buckets.c index 9d66b537e3d2..8e62ce236851 100644 --- a/drivers/md/bcache/buckets.c +++ b/drivers/md/bcache/buckets.c @@ -667,8 +667,18 @@ recalculate: * GC recalculates sectors_available when it starts, so that hopefully * we don't normally end up blocking here: */ - if (!(flags & BCH_DISK_RESERVATION_GC_LOCK_HELD)) - down_read(&c->gc_lock); + + /* + * Piss fuck, we can be called from extent_insert_fixup() with btree + * locks held: + */ + + if (!(flags & BCH_DISK_RESERVATION_GC_LOCK_HELD)) { + if (!(flags & BCH_DISK_RESERVATION_BTREE_LOCKS_HELD)) + down_read(&c->gc_lock); + else if (!down_read_trylock(&c->gc_lock)) + return -EINTR; + } lg_global_lock(&c->bucket_stats_lock); sectors_available = __recalc_sectors_available(c); diff --git a/drivers/md/bcache/buckets.h b/drivers/md/bcache/buckets.h index 2617ed38b3dc..0219c5c07487 100644 --- a/drivers/md/bcache/buckets.h +++ b/drivers/md/bcache/buckets.h @@ -248,8 +248,9 @@ void bch_disk_reservation_put(struct cache_set *, struct disk_reservation *); #define BCH_DISK_RESERVATION_NOFAIL (1 << 0) -#define BCH_DISK_RESERVATION_GC_LOCK_HELD (1 << 1) -#define BCH_DISK_RESERVATION_METADATA (1 << 2) +#define BCH_DISK_RESERVATION_METADATA (1 << 1) +#define BCH_DISK_RESERVATION_GC_LOCK_HELD (1 << 2) +#define BCH_DISK_RESERVATION_BTREE_LOCKS_HELD (1 << 3) int bch_disk_reservation_add(struct cache_set *, struct disk_reservation *, diff --git a/drivers/md/bcache/extents.c b/drivers/md/bcache/extents.c index e3de4463f5b4..5b6cb8c1ca93 100644 --- a/drivers/md/bcache/extents.c +++ b/drivers/md/bcache/extents.c @@ -1337,17 +1337,26 @@ bch_insert_fixup_extent(struct btree_insert *trans, if (k.k->size && overlap == BCH_EXTENT_OVERLAP_MIDDLE) { unsigned sectors = bkey_extent_is_compressed(c, k.s_c); - int flags = 0; + int flags = BCH_DISK_RESERVATION_BTREE_LOCKS_HELD; if (trans->flags & BTREE_INSERT_NOFAIL) flags |= BCH_DISK_RESERVATION_NOFAIL; - if (sectors && - bch_disk_reservation_add(c, trans->disk_res, - sectors, flags)) { - ret = BTREE_INSERT_ENOSPC; - goto stop; - } + if (sectors) + switch (bch_disk_reservation_add(c, + trans->disk_res, + sectors, flags)) { + case 0: + break; + case -ENOSPC: + ret = BTREE_INSERT_ENOSPC; + goto stop; + case -EINTR: + ret = BTREE_INSERT_NEED_GC_LOCK; + goto stop; + default: + BUG(); + } } /* |