]> www.infradead.org Git - users/hch/dma-mapping.git/commitdiff
bcachefs: Workaround for kvmalloc() not supporting > INT_MAX allocations
authorKent Overstreet <kent.overstreet@linux.dev>
Sat, 19 Oct 2024 22:27:09 +0000 (18:27 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 20 Oct 2024 20:50:14 +0000 (16:50 -0400)
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: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/darray.c

index 4f06cd8bbbe15be2bb68d7c2187eea3eef5d8720..e86d36d23e9e309d4e6a21eaf8d243706b538daa 100644 (file)
@@ -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;