Skip to content

Commit 4d31865

Browse files
Danilo Krummrichfbq
authored andcommitted
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 <[email protected]> Acked-by: Vlastimil Babka <[email protected]> Acked-by: Michal Hocko <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 83c14c8 commit 4d31865

File tree

2 files changed

+63
-0
lines changed

2 files changed

+63
-0
lines changed

include/linux/vmalloc.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,10 @@ extern void *__vcalloc_noprof(size_t n, size_t size, gfp_t flags) __alloc_size(1
189189
extern void *vcalloc_noprof(size_t n, size_t size) __alloc_size(1, 2);
190190
#define vcalloc(...) alloc_hooks(vcalloc_noprof(__VA_ARGS__))
191191

192+
void * __must_check vrealloc_noprof(const void *p, size_t size, gfp_t flags)
193+
__realloc_size(2);
194+
#define vrealloc(...) alloc_hooks(vrealloc_noprof(__VA_ARGS__))
195+
192196
extern void vfree(const void *addr);
193197
extern void vfree_atomic(const void *addr);
194198

mm/vmalloc.c

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4030,6 +4030,65 @@ void *vzalloc_node_noprof(unsigned long size, int node)
40304030
}
40314031
EXPORT_SYMBOL(vzalloc_node_noprof);
40324032

4033+
/**
4034+
* vrealloc - reallocate virtually contiguous memory; contents remain unchanged
4035+
* @p: object to reallocate memory for
4036+
* @size: the size to reallocate
4037+
* @flags: the flags for the page level allocator
4038+
*
4039+
* The contents of the object pointed to are preserved up to the lesser of the
4040+
* new and old size (__GFP_ZERO flag is effectively ignored).
4041+
*
4042+
* If @p is %NULL, vrealloc() behaves exactly like vmalloc(). If @size is 0 and
4043+
* @p is not a %NULL pointer, the object pointed to is freed.
4044+
*
4045+
* Return: pointer to the allocated memory; %NULL if @size is zero or in case of
4046+
* failure
4047+
*/
4048+
void *vrealloc_noprof(const void *p, size_t size, gfp_t flags)
4049+
{
4050+
size_t old_size = 0;
4051+
void *n;
4052+
4053+
if (!size) {
4054+
vfree(p);
4055+
return NULL;
4056+
}
4057+
4058+
if (p) {
4059+
struct vm_struct *vm;
4060+
4061+
vm = find_vm_area(p);
4062+
if (unlikely(!vm)) {
4063+
WARN(1, "Trying to vrealloc() nonexistent vm area (%p)\n", p);
4064+
return NULL;
4065+
}
4066+
4067+
old_size = get_vm_area_size(vm);
4068+
}
4069+
4070+
if (size <= old_size) {
4071+
/*
4072+
* TODO: Shrink the vm_area, i.e. unmap and free unused pages.
4073+
* What would be a good heuristic for when to shrink the
4074+
* vm_area?
4075+
*/
4076+
return (void *)p;
4077+
}
4078+
4079+
/* TODO: Grow the vm_area, i.e. allocate and map additional pages. */
4080+
n = __vmalloc_noprof(size, flags);
4081+
if (!n)
4082+
return NULL;
4083+
4084+
if (p) {
4085+
memcpy(n, p, old_size);
4086+
vfree(p);
4087+
}
4088+
4089+
return n;
4090+
}
4091+
40334092
#if defined(CONFIG_64BIT) && defined(CONFIG_ZONE_DMA32)
40344093
#define GFP_VMALLOC32 (GFP_DMA32 | GFP_KERNEL)
40354094
#elif defined(CONFIG_64BIT) && defined(CONFIG_ZONE_DMA)

0 commit comments

Comments
 (0)