Skip to content

Commit 06e23ee

Browse files
author
Francesco Lavra
committed
Kernel heaps: add vmem heap
Since commit 1462526 "Physical heap: switch from id heap to buddy memory allocator", the physical memory heap does not support allocation requests larger than 2 MB; this is done in order to keep the heap implementation efficient in terms of both runtime performance and memory overhead. However, there are rare cases where the kernel needs memory allocations that exceed this limit: for example, when booting images with large filesystems, the tuple staging buffer for the TFS log can grow in size to several MB, and if memory allocation fails, the kernel panics with "assertion buffer_write(tl->tuple_staging, buffer_ref(b, 0), length) failed". In order to allow the kernel to allocate large chunks of memory while keeping the physical memory allocator efficient, add a new kernel heap that supports arbitrarily large alloocations of contiguous virtual memory which is mapped to physical memory that can be non-contiguous. To allow booting images with large filesystems, make the tuple staging buffer for the TFS log use this new heap. Closes #2105.
1 parent f54e6aa commit 06e23ee

File tree

8 files changed

+89
-1
lines changed

8 files changed

+89
-1
lines changed

platform/pc/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ SRCS-kernel.elf= \
5050
$(SRCDIR)/kernel/storage.c \
5151
$(SRCDIR)/kernel/symtab.c \
5252
$(SRCDIR)/kernel/vdso-now.c \
53+
$(SRCDIR)/kernel/vmem_heap.c \
5354
$(SRCDIR)/net/direct.c \
5455
$(SRCDIR)/net/net.c \
5556
$(SRCDIR)/net/netsyscall.c \

platform/riscv-virt/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ SRCS-kernel.elf= \
4646
$(SRCDIR)/kernel/storage.c \
4747
$(SRCDIR)/kernel/symtab.c \
4848
$(SRCDIR)/kernel/vdso-now.c \
49+
$(SRCDIR)/kernel/vmem_heap.c \
4950
$(SRCDIR)/net/direct.c \
5051
$(SRCDIR)/net/net.c \
5152
$(SRCDIR)/net/netsyscall.c \

platform/virt/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ SRCS-kernel.elf= \
7272
$(SRCDIR)/kernel/storage.c \
7373
$(SRCDIR)/kernel/symtab.c \
7474
$(SRCDIR)/kernel/vdso-now.c \
75+
$(SRCDIR)/kernel/vmem_heap.c \
7576
$(SRCDIR)/net/direct.c \
7677
$(SRCDIR)/net/net.c \
7778
$(SRCDIR)/net/netsyscall.c \

src/fs/tlog.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,13 @@ static log log_new(heap h, tfs fs)
197197
tl->dictionary = allocate_table(h, identity_key, pointer_equal);
198198
if (tl->dictionary == INVALID_ADDRESS)
199199
goto fail_dealloc_log;
200-
tl->tuple_staging = allocate_buffer(h, PAGESIZE /* arbitrary */);
200+
heap staging_heap;
201+
#ifdef KERNEL
202+
staging_heap = get_kernel_heaps()->vmem;
203+
#else
204+
staging_heap = h;
205+
#endif
206+
tl->tuple_staging = allocate_buffer(staging_heap, PAGESIZE /* arbitrary */);
201207
if (tl->tuple_staging == INVALID_ADDRESS)
202208
goto fail_dealloc_dict;
203209
tl->encoding_lengths = allocate_vector(h, 512);

src/kernel/init.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,9 @@ void init_kernel_heaps(void)
206206
heaps.malloc = locking_heap_wrapper(heaps.general, heaps.malloc);
207207
assert(heaps.malloc != INVALID_ADDRESS);
208208

209+
heaps.vmem = create_vmem_heap();
210+
assert(heaps.vmem != INVALID_ADDRESS);
211+
209212
id_heap kas_ih = create_id_heap(heaps.general, heaps.locked,
210213
kas.start, range_span(kas), PAGESIZE, true);
211214
assert(kas_ih != INVALID_ADDRESS);

src/kernel/kernel.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,8 @@ static inline u64 phys_from_linear_backed_virt(u64 virt)
650650
return virt - kvmem.linear.start;
651651
}
652652

653+
heap create_vmem_heap(void);
654+
653655
void unmap_and_free_phys(u64 virtual, u64 length);
654656
void page_free_phys(u64 phys);
655657

src/kernel/vmem_heap.c

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#include <kernel.h>
2+
3+
typedef struct vmem_heap {
4+
struct heap h;
5+
heap physical;
6+
heap virtual;
7+
} *vmem_heap;
8+
9+
static void vmem_dealloc(heap h, u64 a, bytes len)
10+
{
11+
bytes pagesize = h->pagesize;
12+
len = pad(len, pagesize);
13+
for (u64 v = a; v < a + len; v += pagesize) {
14+
unmap(v, pagesize);
15+
}
16+
vmem_heap vmh = (vmem_heap)h;
17+
deallocate(vmh->virtual, a, len);
18+
}
19+
20+
static u64 vmem_alloc(heap h, bytes len)
21+
{
22+
vmem_heap vmh = (vmem_heap)h;
23+
bytes pagesize = h->pagesize;
24+
len = pad(len, pagesize);
25+
u64 v = allocate_u64(vmh->virtual, len);
26+
if (v != INVALID_PHYSICAL) {
27+
heap physical = vmh->physical;
28+
pageflags flags = pageflags_writable(pageflags_memory());
29+
u64 virt_offset = 0;
30+
do {
31+
u64 phys_len = len - virt_offset;
32+
u64 p;
33+
while (true) {
34+
p = allocate_u64(physical, phys_len);
35+
if ((p != INVALID_PHYSICAL) || (phys_len == pagesize))
36+
break;
37+
phys_len = pad(phys_len >> 1, pagesize);
38+
}
39+
if (p != INVALID_PHYSICAL) {
40+
map(v + virt_offset, p, phys_len, flags);
41+
virt_offset += phys_len;
42+
} else if (phys_len == pagesize) {
43+
break;
44+
}
45+
} while (virt_offset < len);
46+
if (virt_offset < len) { /* physical memory allocation failed */
47+
vmem_dealloc(h, v, virt_offset);
48+
v = INVALID_PHYSICAL;
49+
}
50+
}
51+
return v;
52+
}
53+
54+
heap create_vmem_heap(void)
55+
{
56+
kernel_heaps kh = get_kernel_heaps();
57+
vmem_heap vmh = allocate(kh->locked, sizeof(*vmh));
58+
if (vmh != INVALID_ADDRESS) {
59+
vmh->h.alloc = vmem_alloc;
60+
vmh->h.dealloc = vmem_dealloc;
61+
vmh->h.allocated = 0;
62+
vmh->h.total = 0;
63+
vmh->h.management = 0;
64+
vmh->physical = heap_physical(kh);
65+
vmh->virtual = &heap_virtual_page(kh)->h;
66+
vmh->h.pagesize = vmh->physical->pagesize;
67+
}
68+
return &vmh->h;
69+
}

src/runtime/kernel_heaps.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,11 @@ typedef struct kernel_heaps {
5858

5959
/* mcache for allocations of DMA memory. Protected by spinlock. */
6060
heap dma;
61+
62+
/* Heap for allocating large chunks of virtually contiguous memory that does not have to be
63+
* physically contiguous. Mapping and unmapping of virtual addresses is done during allocation
64+
* and deallocation. */
65+
heap vmem;
6166
} *kernel_heaps;
6267

6368
static inline heap heap_physical(kernel_heaps heaps)

0 commit comments

Comments
 (0)