Commit f0d33020 authored by Kent Overstreet's avatar Kent Overstreet
Browse files

bcachefs: Workaround for kvmalloc() not supporting > INT_MAX allocations

kvmalloc() doesn't support allocations > INT_MAX, but vmalloc() does -
the limit should be lifted, but we can work around this for now.

A user with a 75 TB filesystem reported the following journal replay
error:
https://github.com/koverstreet/bcachefs/issues/769



In journal replay we have to sort and dedup all the keys from the
journal, which means we need a large contiguous allocation. Given that
the user has 128GB of ram, the 2GB limit on allocation size has become
far too small.

Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 3956ff8b
Loading
Loading
Loading
Loading
+14 −1
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@

#include <linux/log2.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include "darray.h"

int __bch2_darray_resize_noprof(darray_char *d, size_t element_size, size_t new_size, gfp_t gfp)
@@ -9,7 +10,19 @@ int __bch2_darray_resize_noprof(darray_char *d, size_t element_size, size_t new_
	if (new_size > d->size) {
		new_size = roundup_pow_of_two(new_size);

		void *data = kvmalloc_array_noprof(new_size, element_size, gfp);
		/*
		 * This is a workaround: kvmalloc() doesn't support > INT_MAX
		 * allocations, but vmalloc() does.
		 * The limit needs to be lifted from kvmalloc, and when it does
		 * we'll go back to just using that.
		 */
		size_t bytes;
		if (unlikely(check_mul_overflow(new_size, element_size, &bytes)))
			return -ENOMEM;

		void *data = likely(bytes < INT_MAX)
			? kvmalloc_noprof(bytes, gfp)
			: vmalloc_noprof(bytes);
		if (!data)
			return -ENOMEM;