[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20240722163111.4766-2-dakr@kernel.org>
Date: Mon, 22 Jul 2024 18:29:23 +0200
From: Danilo Krummrich <dakr@...nel.org>
To: cl@...ux.com,
penberg@...nel.org,
rientjes@...gle.com,
iamjoonsoo.kim@....com,
akpm@...ux-foundation.org,
vbabka@...e.cz,
roman.gushchin@...ux.dev,
42.hyeyoo@...il.com,
urezki@...il.com,
hch@...radead.org,
kees@...nel.org,
ojeda@...nel.org,
wedsonaf@...il.com,
mhocko@...nel.org,
mpe@...erman.id.au,
chandan.babu@...cle.com,
christian.koenig@....com,
maz@...nel.org,
oliver.upton@...ux.dev
Cc: linux-kernel@...r.kernel.org,
linux-mm@...ck.org,
rust-for-linux@...r.kernel.org,
Danilo Krummrich <dakr@...nel.org>
Subject: [PATCH v2 1/2] mm: vmalloc: implement vrealloc()
Implement vrealloc() analogous to krealloc().
Currently, krealloc() requires the caller to pass the size of the
previous memory allocation, which, instead, should be self-contained.
We attempt to fix this in a subsequent patch which, in order to do so,
requires vrealloc().
Besides that, we need realloc() functions for kernel allocators in Rust
too. With `Vec` or `KVec` respectively, potentially growing (and
shrinking) data structures are rather common.
Signed-off-by: Danilo Krummrich <dakr@...nel.org>
---
include/linux/vmalloc.h | 4 +++
mm/vmalloc.c | 59 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 63 insertions(+)
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index e4a631ec430b..ad2ce7a6ab7a 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -189,6 +189,10 @@ extern void *__vcalloc_noprof(size_t n, size_t size, gfp_t flags) __alloc_size(1
extern void *vcalloc_noprof(size_t n, size_t size) __alloc_size(1, 2);
#define vcalloc(...) alloc_hooks(vcalloc_noprof(__VA_ARGS__))
+void * __must_check vrealloc_noprof(const void *p, size_t size, gfp_t flags)
+ __realloc_size(2);
+#define vrealloc(...) alloc_hooks(vrealloc_noprof(__VA_ARGS__))
+
extern void vfree(const void *addr);
extern void vfree_atomic(const void *addr);
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 6b783baf12a1..caf032f0bd69 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -4037,6 +4037,65 @@ void *vzalloc_node_noprof(unsigned long size, int node)
}
EXPORT_SYMBOL(vzalloc_node_noprof);
+/**
+ * vrealloc - reallocate virtually contiguous memory; contents remain unchanged
+ * @p: object to reallocate memory for
+ * @size: the size to reallocate
+ * @flags: the flags for the page level allocator
+ *
+ * The contents of the object pointed to are preserved up to the lesser of the
+ * new and old size (__GFP_ZERO flag is effectively ignored).
+ *
+ * If @p is %NULL, vrealloc() behaves exactly like vmalloc(). If @size is 0 and
+ * @p is not a %NULL pointer, the object pointed to is freed.
+ *
+ * Return: pointer to the allocated memory; %NULL if @size is zero or in case of
+ * failure
+ */
+void *vrealloc_noprof(const void *p, size_t size, gfp_t flags)
+{
+ size_t old_size = 0;
+ void *n;
+
+ if (!size) {
+ vfree(p);
+ return NULL;
+ }
+
+ if (p) {
+ struct vm_struct *vm;
+
+ vm = find_vm_area(p);
+ if (unlikely(!vm)) {
+ WARN(1, "Trying to vrealloc() nonexistent vm area (%p)\n", p);
+ return NULL;
+ }
+
+ old_size = get_vm_area_size(vm);
+ }
+
+ if (size <= old_size) {
+ /*
+ * TODO: Shrink the vm_area, i.e. unmap and free unused pages.
+ * What would be a good heuristic for when to shrink the
+ * vm_area?
+ */
+ return (void *)p;
+ }
+
+ /* TODO: Grow the vm_area, i.e. allocate and map additional pages. */
+ n = __vmalloc_noprof(size, flags);
+ if (!n)
+ return NULL;
+
+ if (p) {
+ memcpy(n, p, old_size);
+ vfree(p);
+ }
+
+ return n;
+}
+
#if defined(CONFIG_64BIT) && defined(CONFIG_ZONE_DMA32)
#define GFP_VMALLOC32 (GFP_DMA32 | GFP_KERNEL)
#elif defined(CONFIG_64BIT) && defined(CONFIG_ZONE_DMA)
--
2.45.2
Powered by blists - more mailing lists