summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/md/bcache/btree_types.h1
-rw-r--r--drivers/md/bcache/btree_update.c15
-rw-r--r--drivers/md/bcache/buckets.c14
-rw-r--r--drivers/md/bcache/buckets.h5
-rw-r--r--drivers/md/bcache/extents.c23
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();
+ }
}
/*