mirror of
https://github.com/torvalds/linux.git
synced 2026-06-02 11:33:28 +02:00
bcachefs: Add a fallback when journal_keys doesn't fit in ram
We may end up in a situation where allocating the buffer for the sorted journal_keys fails - but it would likely succeed, post compaction where we drop duplicates. We've had reports of this allocation failing, so this adds a slowpath to do the compaction incrementally. This is only a band-aid fix; we need to look at limiting the number of keys in the journal based on the amount of system RAM. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
2f0815840c
commit
26559553e4
|
|
@ -476,6 +476,26 @@ void bch2_journal_keys_free(struct journal_keys *keys)
|
|||
keys->nr = keys->gap = keys->size = 0;
|
||||
}
|
||||
|
||||
static void __journal_keys_sort(struct journal_keys *keys)
|
||||
{
|
||||
struct journal_key *src, *dst;
|
||||
|
||||
sort(keys->d, keys->nr, sizeof(keys->d[0]), journal_sort_key_cmp, NULL);
|
||||
|
||||
src = dst = keys->d;
|
||||
while (src < keys->d + keys->nr) {
|
||||
while (src + 1 < keys->d + keys->nr &&
|
||||
src[0].btree_id == src[1].btree_id &&
|
||||
src[0].level == src[1].level &&
|
||||
bpos_eq(src[0].k->k.p, src[1].k->k.p))
|
||||
src++;
|
||||
|
||||
*dst++ = *src++;
|
||||
}
|
||||
|
||||
keys->nr = dst - keys->d;
|
||||
}
|
||||
|
||||
static int journal_keys_sort(struct bch_fs *c)
|
||||
{
|
||||
struct genradix_iter iter;
|
||||
|
|
@ -483,8 +503,7 @@ static int journal_keys_sort(struct bch_fs *c)
|
|||
struct jset_entry *entry;
|
||||
struct bkey_i *k;
|
||||
struct journal_keys *keys = &c->journal_keys;
|
||||
struct journal_key *src, *dst;
|
||||
size_t nr_keys = 0;
|
||||
size_t nr_keys = 0, nr_read = 0;
|
||||
|
||||
genradix_for_each(&c->journal_entries, iter, _i) {
|
||||
i = *_i;
|
||||
|
|
@ -503,9 +522,19 @@ static int journal_keys_sort(struct bch_fs *c)
|
|||
|
||||
keys->d = kvmalloc_array(keys->size, sizeof(keys->d[0]), GFP_KERNEL);
|
||||
if (!keys->d) {
|
||||
bch_err(c, "Failed to allocate buffer for sorted journal keys (%zu keys)",
|
||||
bch_err(c, "Failed to allocate buffer for sorted journal keys (%zu keys); trying slowpath",
|
||||
nr_keys);
|
||||
return -BCH_ERR_ENOMEM_journal_keys_sort;
|
||||
|
||||
do {
|
||||
keys->size >>= 1;
|
||||
keys->d = kvmalloc_array(keys->size, sizeof(keys->d[0]), GFP_KERNEL);
|
||||
} while (!keys->d && keys->size > nr_keys / 8);
|
||||
|
||||
if (!keys->d) {
|
||||
bch_err(c, "Failed to allocate %zu size buffer for sorted journal keys; exiting",
|
||||
keys->size);
|
||||
return -BCH_ERR_ENOMEM_journal_keys_sort;
|
||||
}
|
||||
}
|
||||
|
||||
genradix_for_each(&c->journal_entries, iter, _i) {
|
||||
|
|
@ -514,7 +543,17 @@ static int journal_keys_sort(struct bch_fs *c)
|
|||
if (!i || i->ignore)
|
||||
continue;
|
||||
|
||||
for_each_jset_key(k, entry, &i->j)
|
||||
for_each_jset_key(k, entry, &i->j) {
|
||||
if (keys->nr == keys->size) {
|
||||
__journal_keys_sort(keys);
|
||||
|
||||
if (keys->nr > keys->size * 7 / 8) {
|
||||
bch_err(c, "Too many journal keys for slowpath; have %zu compacted, buf size %zu, processed %zu/%zu",
|
||||
keys->nr, keys->size, nr_read, nr_keys);
|
||||
return -BCH_ERR_ENOMEM_journal_keys_sort;
|
||||
}
|
||||
}
|
||||
|
||||
keys->d[keys->nr++] = (struct journal_key) {
|
||||
.btree_id = entry->btree_id,
|
||||
.level = entry->level,
|
||||
|
|
@ -522,23 +561,15 @@ static int journal_keys_sort(struct bch_fs *c)
|
|||
.journal_seq = le64_to_cpu(i->j.seq),
|
||||
.journal_offset = k->_data - i->j._data,
|
||||
};
|
||||
|
||||
nr_read++;
|
||||
}
|
||||
}
|
||||
|
||||
sort(keys->d, keys->nr, sizeof(keys->d[0]), journal_sort_key_cmp, NULL);
|
||||
|
||||
src = dst = keys->d;
|
||||
while (src < keys->d + keys->nr) {
|
||||
while (src + 1 < keys->d + keys->nr &&
|
||||
src[0].btree_id == src[1].btree_id &&
|
||||
src[0].level == src[1].level &&
|
||||
bpos_eq(src[0].k->k.p, src[1].k->k.p))
|
||||
src++;
|
||||
|
||||
*dst++ = *src++;
|
||||
}
|
||||
|
||||
keys->nr = dst - keys->d;
|
||||
__journal_keys_sort(keys);
|
||||
keys->gap = keys->nr;
|
||||
|
||||
bch_verbose(c, "Journal keys: %zu read, %zu after sorting and compacting", nr_keys, keys->nr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user