summaryrefslogtreecommitdiff
path: root/fs/bcachefs/btree_key_cache.c
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@linux.dev>2022-11-14 10:22:30 +0300
committerKent Overstreet <kent.overstreet@linux.dev>2023-10-23 00:09:46 +0300
commit061f7999a6322c639dd6616dc6d3785957de2bc3 (patch)
treefebba2966132f8a61e387bbded3a04441037848d /fs/bcachefs/btree_key_cache.c
parent961cbdef3c270266e17aa831cf22eb14b900af65 (diff)
downloadlinux-061f7999a6322c639dd6616dc6d3785957de2bc3.tar.xz
bcachefs: Fix a use after free
This fixes a regression from percpu freedlists in the btree key cache code: in a rare error path, we were immediately freeing a bkey_cached that had been used before and should've waited for an SRCU barrier. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
Diffstat (limited to 'fs/bcachefs/btree_key_cache.c')
-rw-r--r--fs/bcachefs/btree_key_cache.c9
1 files changed, 5 insertions, 4 deletions
diff --git a/fs/bcachefs/btree_key_cache.c b/fs/bcachefs/btree_key_cache.c
index 179669dbd688..1ac91221cc95 100644
--- a/fs/bcachefs/btree_key_cache.c
+++ b/fs/bcachefs/btree_key_cache.c
@@ -190,7 +190,8 @@ static void bkey_cached_free_fast(struct btree_key_cache *bc,
}
static struct bkey_cached *
-bkey_cached_alloc(struct btree_trans *trans, struct btree_path *path)
+bkey_cached_alloc(struct btree_trans *trans, struct btree_path *path,
+ bool *was_new)
{
struct bch_fs *c = trans->c;
struct btree_key_cache *bc = &c->btree_key_cache;
@@ -275,6 +276,7 @@ bkey_cached_alloc(struct btree_trans *trans, struct btree_path *path)
ck->c.cached = true;
BUG_ON(!six_trylock_intent(&ck->c.lock));
BUG_ON(!six_trylock_write(&ck->c.lock));
+ *was_new = true;
return ck;
}
@@ -313,9 +315,9 @@ btree_key_cache_create(struct btree_trans *trans, struct btree_path *path)
struct bch_fs *c = trans->c;
struct btree_key_cache *bc = &c->btree_key_cache;
struct bkey_cached *ck;
- bool was_new = true;
+ bool was_new = false;
- ck = bkey_cached_alloc(trans, path);
+ ck = bkey_cached_alloc(trans, path, &was_new);
if (IS_ERR(ck))
return ck;
@@ -328,7 +330,6 @@ btree_key_cache_create(struct btree_trans *trans, struct btree_path *path)
}
mark_btree_node_locked(trans, path, 0, SIX_LOCK_intent);
- was_new = false;
} else {
if (path->btree_id == BTREE_ID_subvolumes)
six_lock_pcpu_alloc(&ck->c.lock);