Commit 6c36318c authored by Kent Overstreet's avatar Kent Overstreet

bcachefs: key cache: Don't hold btree locks while using GFP_RECLAIM

This is something we need to do more widely: instead of bothering with
GFP_NOIO/GFP_NOFS, if we need to allocate memory while holding locks:

 - first attempt the allocation with GFP_NOWAIT
 - if that fails, drop btree locks with bch2_trans_unlock(), then
   retry with GFP_KERNEL.
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 7af365eb
...@@ -2827,7 +2827,7 @@ u32 bch2_trans_begin(struct btree_trans *trans) ...@@ -2827,7 +2827,7 @@ u32 bch2_trans_begin(struct btree_trans *trans)
bch2_trans_relock(trans); bch2_trans_relock(trans);
} }
if (unlikely(time_after(jiffies, trans->srcu_lock_time + HZ))) if (unlikely(time_after(jiffies, trans->srcu_lock_time + msecs_to_jiffies(10))))
bch2_trans_reset_srcu_lock(trans); bch2_trans_reset_srcu_lock(trans);
trans->last_restarted_ip = _RET_IP_; trans->last_restarted_ip = _RET_IP_;
......
...@@ -196,6 +196,7 @@ bkey_cached_alloc(struct btree_trans *trans, struct btree_path *path, ...@@ -196,6 +196,7 @@ bkey_cached_alloc(struct btree_trans *trans, struct btree_path *path,
struct btree_key_cache *bc = &c->btree_key_cache; struct btree_key_cache *bc = &c->btree_key_cache;
struct bkey_cached *ck = NULL; struct bkey_cached *ck = NULL;
bool pcpu_readers = btree_uses_pcpu_readers(path->btree_id); bool pcpu_readers = btree_uses_pcpu_readers(path->btree_id);
int ret;
if (!pcpu_readers) { if (!pcpu_readers) {
#ifdef __KERNEL__ #ifdef __KERNEL__
...@@ -263,9 +264,23 @@ bkey_cached_alloc(struct btree_trans *trans, struct btree_path *path, ...@@ -263,9 +264,23 @@ bkey_cached_alloc(struct btree_trans *trans, struct btree_path *path,
return ck; return ck;
} }
/* GFP_NOFS because we're holding btree locks: */ ck = kmem_cache_zalloc(bch2_key_cache, GFP_NOWAIT|__GFP_NOWARN);
ck = kmem_cache_alloc(bch2_key_cache, GFP_NOFS|__GFP_ZERO); if (likely(ck))
if (likely(ck)) { goto init;
bch2_trans_unlock(trans);
ck = kmem_cache_zalloc(bch2_key_cache, GFP_KERNEL);
ret = bch2_trans_relock(trans);
if (ret) {
kmem_cache_free(bch2_key_cache, ck);
return ERR_PTR(ret);
}
if (!ck)
return NULL;
init:
INIT_LIST_HEAD(&ck->list); INIT_LIST_HEAD(&ck->list);
__six_lock_init(&ck->c.lock, "b->c.lock", &bch2_btree_node_lock_key); __six_lock_init(&ck->c.lock, "b->c.lock", &bch2_btree_node_lock_key);
lockdep_set_novalidate_class(&ck->c.lock); lockdep_set_novalidate_class(&ck->c.lock);
...@@ -277,9 +292,6 @@ bkey_cached_alloc(struct btree_trans *trans, struct btree_path *path, ...@@ -277,9 +292,6 @@ bkey_cached_alloc(struct btree_trans *trans, struct btree_path *path,
BUG_ON(!six_trylock_write(&ck->c.lock)); BUG_ON(!six_trylock_write(&ck->c.lock));
*was_new = true; *was_new = true;
return ck; return ck;
}
return NULL;
} }
static struct bkey_cached * static struct bkey_cached *
...@@ -385,7 +397,7 @@ static int btree_key_cache_fill(struct btree_trans *trans, ...@@ -385,7 +397,7 @@ static int btree_key_cache_fill(struct btree_trans *trans,
if (!bch2_btree_node_relock(trans, ck_path, 0)) { if (!bch2_btree_node_relock(trans, ck_path, 0)) {
trace_and_count(trans->c, trans_restart_relock_key_cache_fill, trans, _THIS_IP_, ck_path); trace_and_count(trans->c, trans_restart_relock_key_cache_fill, trans, _THIS_IP_, ck_path);
ret = btree_trans_restart(trans, BCH_ERR_transaction_restart_key_cache_raced); ret = btree_trans_restart(trans, BCH_ERR_transaction_restart_key_cache_fill);
goto err; goto err;
} }
...@@ -404,13 +416,31 @@ static int btree_key_cache_fill(struct btree_trans *trans, ...@@ -404,13 +416,31 @@ static int btree_key_cache_fill(struct btree_trans *trans,
if (new_u64s > ck->u64s) { if (new_u64s > ck->u64s) {
new_u64s = roundup_pow_of_two(new_u64s); new_u64s = roundup_pow_of_two(new_u64s);
new_k = kmalloc(new_u64s * sizeof(u64), GFP_NOFS); new_k = kmalloc(new_u64s * sizeof(u64), GFP_NOWAIT|__GFP_NOWARN);
if (!new_k) {
bch2_trans_unlock(trans);
new_k = kmalloc(new_u64s * sizeof(u64), GFP_KERNEL);
if (!new_k) { if (!new_k) {
bch_err(trans->c, "error allocating memory for key cache key, btree %s u64s %u", bch_err(trans->c, "error allocating memory for key cache key, btree %s u64s %u",
bch2_btree_ids[ck->key.btree_id], new_u64s); bch2_btree_ids[ck->key.btree_id], new_u64s);
ret = -ENOMEM; ret = -ENOMEM;
goto err; goto err;
} }
if (!bch2_btree_node_relock(trans, ck_path, 0)) {
kfree(new_k);
trace_and_count(trans->c, trans_restart_relock_key_cache_fill, trans, _THIS_IP_, ck_path);
ret = btree_trans_restart(trans, BCH_ERR_transaction_restart_key_cache_fill);
goto err;
}
ret = bch2_trans_relock(trans);
if (ret) {
kfree(new_k);
goto err;
}
}
} }
ret = bch2_btree_node_lock_write(trans, ck_path, &ck_path->l[0].b->c); ret = bch2_btree_node_lock_write(trans, ck_path, &ck_path->l[0].b->c);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment