git: 516eb937b274 - stable/14 - LinuxKPI: implement krealloc() for memory being contiguous

From: Bjoern A. Zeeb <bz_at_FreeBSD.org>
Date: Fri, 18 Apr 2025 14:36:55 UTC
The branch stable/14 has been updated by bz:

URL: https://cgit.FreeBSD.org/src/commit/?id=516eb937b274c34793f9b640e547eee0dc185b2d

commit 516eb937b274c34793f9b640e547eee0dc185b2d
Author:     Bjoern A. Zeeb <bz@FreeBSD.org>
AuthorDate: 2025-03-29 17:05:58 +0000
Commit:     Bjoern A. Zeeb <bz@FreeBSD.org>
CommitDate: 2025-04-18 14:35:58 +0000

    LinuxKPI: implement krealloc() for memory being contiguous
    
    Implement krealloc_array() using krealloc().  Implement krealloc()
    doing the various size checks ourselves and use realloc() or kmalloc()
    depending on old and new allocation sizes.
    This way we can ensure that allocated memory stays physically contiguous.
    
    Sponsored by:   The FreeBSD Foundation
    Suggested by:   jhb (see D46657)
    Reviewed by:    jhb, markj
    Differential Revision: https://reviews.freebsd.org/D49571
    
    (cherry picked from commit 1c95d401ebe5075ebb38b57638830713a496f107)
---
 sys/compat/linuxkpi/common/include/linux/slab.h | 31 +++++++++++-----------
 sys/compat/linuxkpi/common/src/linux_slab.c     | 35 +++++++++++++++++++++++++
 2 files changed, 51 insertions(+), 15 deletions(-)

diff --git a/sys/compat/linuxkpi/common/include/linux/slab.h b/sys/compat/linuxkpi/common/include/linux/slab.h
index ddaabcef0b9c..a692ccb8b944 100644
--- a/sys/compat/linuxkpi/common/include/linux/slab.h
+++ b/sys/compat/linuxkpi/common/include/linux/slab.h
@@ -94,6 +94,7 @@ extern void *lkpi_kmalloc(size_t size, gfp_t flags);
 void *lkpi___kmalloc(size_t size, gfp_t flags);
 void *lkpi___kmalloc_node(size_t size, gfp_t flags, int node);
 #define	__kmalloc(_s, _f)	lkpi___kmalloc(_s, _f)
+void *lkpi_krealloc(void *, size_t, gfp_t);
 
 static inline gfp_t
 linux_check_m_flags(gfp_t flags)
@@ -148,6 +149,21 @@ kcalloc_node(size_t n, size_t size, gfp_t flags, int node)
 	return (kmalloc_array_node(n, size, flags, node));
 }
 
+static inline void *
+krealloc(void *ptr, size_t size, gfp_t flags)
+{
+	return (lkpi_krealloc(ptr, size, flags));
+}
+
+static inline void *
+krealloc_array(void *ptr, size_t n, size_t size, gfp_t flags)
+{
+	if (WOULD_OVERFLOW(n, size))
+		return NULL;
+
+	return (krealloc(ptr, n * size, flags));
+}
+
 static inline void *
 __vmalloc(size_t size, gfp_t flags, int other)
 {
@@ -183,21 +199,6 @@ kvmalloc_array(size_t n, size_t size, gfp_t flags)
 	return (kvmalloc(size * n, flags));
 }
 
-static inline void *
-krealloc(void *ptr, size_t size, gfp_t flags)
-{
-	return (realloc(ptr, size, M_KMALLOC, linux_check_m_flags(flags)));
-}
-
-static inline void *
-krealloc_array(void *ptr, size_t n, size_t size, gfp_t flags)
-{
-	if (WOULD_OVERFLOW(n, size))
-		return NULL;
-
-	return (realloc(ptr, n * size, M_KMALLOC, linux_check_m_flags(flags)));
-}
-
 extern void linux_kfree_async(void *);
 
 static inline void
diff --git a/sys/compat/linuxkpi/common/src/linux_slab.c b/sys/compat/linuxkpi/common/src/linux_slab.c
index 4b0b18178a5c..abcffdb094f5 100644
--- a/sys/compat/linuxkpi/common/src/linux_slab.c
+++ b/sys/compat/linuxkpi/common/src/linux_slab.c
@@ -234,6 +234,41 @@ lkpi___kmalloc(size_t size, gfp_t flags)
 		    0, -1UL, PAGE_SIZE, 0));
 }
 
+void *
+lkpi_krealloc(void *ptr, size_t size, gfp_t flags)
+{
+	void *nptr;
+	size_t osize;
+
+	/*
+	 * First handle invariants based on function arguments.
+	 */
+	if (ptr == NULL)
+		return (kmalloc(size, flags));
+
+	osize = ksize(ptr);
+	if (size <= osize)
+		return (ptr);
+
+	/*
+	 * We know the new size > original size.  realloc(9) does not (and cannot)
+	 * know about our requirements for physically contiguous memory, so we can
+	 * only call it for sizes up to and including PAGE_SIZE, and otherwise have
+	 * to replicate its functionality using kmalloc to get the contigmalloc(9)
+	 * backing.
+	 */
+	if (size <= PAGE_SIZE)
+		return (realloc(ptr, size, M_KMALLOC, linux_check_m_flags(flags)));
+
+	nptr = kmalloc(size, flags);
+	if (nptr == NULL)
+		return (NULL);
+
+	memcpy(nptr, ptr, osize);
+	kfree(ptr);
+	return (nptr);
+}
+
 struct lkpi_kmalloc_ctx {
 	size_t size;
 	gfp_t flags;