summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/bcachefs/btree_iter.c65
-rw-r--r--fs/bcachefs/btree_iter.h14
2 files changed, 46 insertions, 33 deletions
diff --git a/fs/bcachefs/btree_iter.c b/fs/bcachefs/btree_iter.c
index 0b856c72389c..bdb69b4b406f 100644
--- a/fs/bcachefs/btree_iter.c
+++ b/fs/bcachefs/btree_iter.c
@@ -3241,32 +3241,30 @@ void *__bch2_trans_kmalloc(struct btree_trans *trans, size_t size, unsigned long
}
EBUG_ON(trans->mem);
+ EBUG_ON(trans->mem_bytes);
+ EBUG_ON(trans->mem_top);
+ EBUG_ON(new_bytes > BTREE_TRANS_MEM_MAX);
+
+ bool lock_dropped = false;
+ new_mem = allocate_dropping_locks_norelock(trans, lock_dropped, kmalloc(new_bytes, _gfp));
+ if (!new_mem) {
+ new_mem = mempool_alloc(&c->btree_trans_mem_pool, GFP_KERNEL);
+ new_bytes = BTREE_TRANS_MEM_MAX;
+ trans->used_mempool = true;
+ }
- new_mem = kmalloc(new_bytes, GFP_NOWAIT|__GFP_NOWARN);
- if (unlikely(!new_mem)) {
- bch2_trans_unlock(trans);
-
- new_mem = kmalloc(new_bytes, GFP_KERNEL);
- if (!new_mem && new_bytes <= BTREE_TRANS_MEM_MAX) {
- new_mem = mempool_alloc(&c->btree_trans_mem_pool, GFP_KERNEL);
- new_bytes = BTREE_TRANS_MEM_MAX;
- trans->used_mempool = true;
- }
-
- EBUG_ON(!new_mem);
+ EBUG_ON(!new_mem);
- trans->mem = new_mem;
- trans->mem_bytes = new_bytes;
+ trans->mem = new_mem;
+ trans->mem_bytes = new_bytes;
+ if (unlikely(lock_dropped)) {
ret = bch2_trans_relock(trans);
if (ret)
return ERR_PTR(ret);
}
- trans->mem = new_mem;
- trans->mem_bytes = new_bytes;
-
- p = trans->mem + trans->mem_top;
+ p = trans->mem;
trans->mem_top += size;
memset(p, 0, size);
return p;
@@ -3327,22 +3325,23 @@ u32 bch2_trans_begin(struct btree_trans *trans)
trans->mem_top = 0;
if (unlikely(trans->restarted == BCH_ERR_transaction_restart_mem_realloced)) {
- EBUG_ON(!trans->mem || !trans->mem_bytes);
unsigned new_bytes = trans->realloc_bytes_required;
- void *new_mem = krealloc(trans->mem, new_bytes, GFP_NOWAIT|__GFP_NOWARN);
- if (unlikely(!new_mem)) {
- bch2_trans_unlock(trans);
- new_mem = krealloc(trans->mem, new_bytes, GFP_KERNEL);
-
- EBUG_ON(new_bytes > BTREE_TRANS_MEM_MAX);
-
- if (!new_mem) {
- new_mem = mempool_alloc(&trans->c->btree_trans_mem_pool, GFP_KERNEL);
- new_bytes = BTREE_TRANS_MEM_MAX;
- trans->used_mempool = true;
- kfree(trans->mem);
- }
- }
+ EBUG_ON(new_bytes > BTREE_TRANS_MEM_MAX);
+ EBUG_ON(!trans->mem);
+ EBUG_ON(!trans->mem_bytes);
+
+ bool lock_dropped = false;
+ void *new_mem = allocate_dropping_locks_norelock(trans, lock_dropped,
+ krealloc(trans->mem, new_bytes, _gfp));
+ if (!new_mem) {
+ new_mem = mempool_alloc(&trans->c->btree_trans_mem_pool, GFP_KERNEL);
+ new_bytes = BTREE_TRANS_MEM_MAX;
+ trans->used_mempool = true;
+ kfree(trans->mem);
+ }
+
+ EBUG_ON(!new_mem);
+
trans->mem = new_mem;
trans->mem_bytes = new_bytes;
}
diff --git a/fs/bcachefs/btree_iter.h b/fs/bcachefs/btree_iter.h
index 09dd3e52622e..cc2c6bb6b6a8 100644
--- a/fs/bcachefs/btree_iter.h
+++ b/fs/bcachefs/btree_iter.h
@@ -963,6 +963,20 @@ struct bkey_s_c bch2_btree_iter_peek_and_restart_outlined(struct btree_trans *,
_p; \
})
+#define allocate_dropping_locks_norelock(_trans, _lock_dropped, _do) \
+({ \
+ gfp_t _gfp = GFP_NOWAIT|__GFP_NOWARN; \
+ typeof(_do) _p = _do; \
+ _lock_dropped = false; \
+ if (unlikely(!_p)) { \
+ bch2_trans_unlock(_trans); \
+ _lock_dropped = true; \
+ _gfp = GFP_KERNEL; \
+ _p = _do; \
+ } \
+ _p; \
+})
+
struct btree_trans *__bch2_trans_get(struct bch_fs *, unsigned);
void bch2_trans_put(struct btree_trans *);