diff options
-rw-r--r-- | fs/bcachefs/btree_iter.c | 65 | ||||
-rw-r--r-- | fs/bcachefs/btree_iter.h | 14 |
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 *); |