Skip to content

Commit

Permalink
mm: Add swapping
Browse files Browse the repository at this point in the history
Add swapping of anon pages to disk. Also, while we're at it, perform _a
lot_ of miscellaneous refactoring and moving around of code, including
adding proper GFP flags in a bunch of places, some CHECKs, a bunch of
page fault work. This is not perfect but I'm working on it.

Also fix the UART8250 ACPI and DT builds.
This disables the ARM64 builds in CI because they're broken.

Signed-off-by: Pedro Falcato <[email protected]>
  • Loading branch information
heatd committed Aug 19, 2024
1 parent 0b7d2c5 commit 2dfdb4d
Show file tree
Hide file tree
Showing 41 changed files with 1,786 additions and 196 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,7 @@ jobs:
path: ${{ env.toolchain_id }}.tar.zst

build-arm64:
if: ${{ false }} # TODO: Fix the arm64 kernel build
runs-on: ubuntu-latest
needs: build-toolchains

Expand Down Expand Up @@ -471,6 +472,7 @@ jobs:
path: arm64-onyx-image.tar.zst

build-llvm-arm64:
if: ${{ false }}
# The type of runner that the job will run on
runs-on: ubuntu-latest
needs: build-toolchains
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,7 @@ jobs:
name: ${{ env.toolchain_id }}
path: ${{ env.toolchain_id }}.tar.zst
build-arm64:
if: ${{ false }}
runs-on: ubuntu-22.04
needs: build-toolchains

Expand Down Expand Up @@ -467,6 +468,7 @@ jobs:
path: arm64-onyx-image.tar.zst

build-llvm-arm64:
if: ${{ false }}
# The type of runner that the job will run on
runs-on: ubuntu-22.04
needs: build-toolchains
Expand Down
23 changes: 23 additions & 0 deletions kernel/arch/riscv64/mmu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -539,3 +539,26 @@ void mmu_verify_address_space_accounting(mm_address_space *as)
assert(acct.page_table_size == as->page_tables_size);
assert(acct.resident_set_size == as->resident_set_size);
}

/**
* @brief Invalidate the TLB after upgrading PTE protection
* Invalidates the TLB when upgrading PTE permissions. It isn't required to sync this invalidation
* with other cores.
* @param mm Address space
* @param virt Virtual address to invalidate
*/
void tlbi_upgrade_pte_prots(struct mm_address_space *mm, unsigned long virt)
{
__native_tlb_invalidate_page((void *) virt);
}

/**
* @brief Handle a seemingly spurious fault locally
* Make sure we sync the TLB when we find a spurious fault.
* @param mm Address space
* @param virt Virtual address to invalidate
*/
void tlbi_handle_spurious_fault_pte(struct mm_address_space *mm, unsigned long virt)
{
__native_tlb_invalidate_page((void *) virt);
}
7 changes: 7 additions & 0 deletions kernel/arch/x86_64/isr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,13 @@ void page_fault_handler(struct registers *ctx)
vm_do_fatal_page_fault(&info);
dumpstack(ctx->rip, (const void *) ctx->rsp);
}

if (WARN_ON(sched_is_preemption_disabled()))
{
pr_err("Trying to return from a page fault with preemption disabled (%lx)! Fixing up...\n",
sched_get_preempt_counter());
write_per_cpu(preemption_counter, 0);
}
}

void x87_fpu_exception(struct registers *ctx)
Expand Down
29 changes: 28 additions & 1 deletion kernel/arch/x86_64/mmu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <onyx/page.h>
#include <onyx/paging.h>
#include <onyx/panic.h>
#include <onyx/pgtable.h>
#include <onyx/process.h>
#include <onyx/smp.h>
#include <onyx/vm.h>
Expand Down Expand Up @@ -281,7 +282,7 @@ void x86_setup_placement_mappings(void)

extern "C"
{
unsigned int pgd_shift = 39, p4d_ptrs = 1;
int pgd_shift = 39, p4d_ptrs = 1;
}

NO_ASAN
Expand Down Expand Up @@ -688,6 +689,32 @@ void x86_invalidate_tlb(void *context)
}
}

/**
* @brief Invalidate the TLB after upgrading PTE protection
* Invalidates the TLB when upgrading PTE permissions. It isn't required to sync this invalidation
* with other cores.
* @param mm Address space
* @param virt Virtual address to invalidate
*/
void tlbi_upgrade_pte_prots(struct mm_address_space *mm, unsigned long virt)
{
/* Dodge the IPIs and just paging_invalidate */
paging_invalidate((void *) virt, 1);
add_per_cpu(tlb_nr_invals, 1);
}

/**
* @brief Handle a seemingly spurious fault locally
* Make sure we sync the TLB when we find a spurious fault.
* @param mm Address space
* @param virt Virtual address to invalidate
*/
void tlbi_handle_spurious_fault_pte(struct mm_address_space *mm, unsigned long virt)
{
paging_invalidate((void *) virt, 1);
add_per_cpu(tlb_nr_invals, 1);
}

/**
* @brief Invalidates a memory range.
*
Expand Down
4 changes: 2 additions & 2 deletions kernel/drivers/serial/uart8250/Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
uart8250-y:= drivers/serial/uart8250/uart8250.o
uart8250-$(SERIAL_UART8250_ACPI)+= drivers/serial/uart8250/acpi.o
uart8250-$(SERIAL_UART8250_DEVTREE)+= drivers/serial/uart8250/devtree.o
uart8250-$(CONFIG_SERIAL_UART8250_ACPI)+= drivers/serial/uart8250/acpi.o
uart8250-$(CONFIG_SERIAL_UART8250_DEVTREE)+= drivers/serial/uart8250/devtree.o

obj-$(CONFIG_SERIAL_UART8250)+= $(uart8250-y)
1 change: 1 addition & 0 deletions kernel/include/onyx/block.h
Original file line number Diff line number Diff line change
Expand Up @@ -211,5 +211,6 @@ int block_set_bsize(struct blockdev *bdev, unsigned int block_size);

int bdev_do_open(struct blockdev *bdev, bool exclusive);
void bdev_release(struct blockdev *bdev);
unsigned int bdev_sector_size(struct blockdev *bdev);
__END_CDECLS
#endif
5 changes: 5 additions & 0 deletions kernel/include/onyx/crc32.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@
#include <stddef.h>
#include <stdint.h>

#include <onyx/compiler.h>

__BEGIN_CDECLS

uint32_t crc32_calculate(uint8_t *ptr, size_t len);
uint32_t crc32_calculate_eth(uint8_t *ptr, size_t len);

__END_CDECLS
#endif
9 changes: 4 additions & 5 deletions kernel/include/onyx/filemap.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,19 +55,18 @@ ssize_t filemap_write_iter(struct file *filp, size_t off, struct iovec_iter *ite
int filemap_find_page(struct inode *ino, size_t pgoff, unsigned int flags, struct page **outp,
struct readahead_state *ra_state);

void page_start_writeback(struct page *page, struct inode *inode) REQUIRES(page);
void page_start_writeback(struct page *page) REQUIRES(page);

void page_end_writeback(struct page *page, struct inode *inode);
void page_end_writeback(struct page *page);

/**
* @brief Marks a page dirty in the filemap
*
* @param ino Inode to mark dirty
* @param page Page to mark dirty
* @param pgoff Page offset
* @invariant page is locked
*/
void filemap_mark_dirty(struct inode *ino, struct page *page, size_t pgoff) REQUIRES(page);
void filemap_mark_dirty(struct page *page, size_t pgoff) REQUIRES(page);

struct writepages_info;

Expand All @@ -94,7 +93,7 @@ struct readpages_state
*/
struct page *readpages_next_page(struct readpages_state *state);

void page_clear_dirty(struct page *page) REQUIRES(page);
void filemap_clear_dirty(struct page *page) REQUIRES(page);

__END_CDECLS

Expand Down
1 change: 1 addition & 0 deletions kernel/include/onyx/iovec_iter.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#define _ONYX_IOVEC_ITER_H

#include <errno.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

Expand Down
13 changes: 9 additions & 4 deletions kernel/include/onyx/mm/page_lru.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,16 @@

struct page;

#define NR_LRU_LISTS 2

#define LRU_ANON_OFF 2
enum lru_state
{
LRU_INACTIVE = 0,
LRU_ACTIVE
LRU_INACTIVE_BASE = 0,
LRU_INACTIVE_FILE = 0,
LRU_ACTIVE_BASE,
LRU_ACTIVE_FILE = LRU_ACTIVE_BASE,
LRU_INACTIVE_ANON,
LRU_ACTIVE_ANON,
NR_LRU_LISTS
};

struct page_lru
Expand All @@ -40,6 +44,7 @@ __BEGIN_CDECLS

void page_add_lru(struct page *page);
void page_remove_lru(struct page *page);
void page_lru_demote_reclaim(struct page *page);

__END_CDECLS

Expand Down
11 changes: 11 additions & 0 deletions kernel/include/onyx/mm/pool.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,7 @@ class memory_pool
NO_ASAN bool expand_pool(unsigned int gfp_flags)
{
// std::cout << "Expanding pool.\n";
spin_unlock(&lock);
auto allocation_size = memory_pool_segment<T, using_vm>::memory_pool_size();

memory_pool_segment<T, using_vm> seg{allocation_size};
Expand All @@ -325,7 +326,11 @@ class memory_pool
void *vmalloc_seg = vmalloc(allocation_size >> PAGE_SHIFT, VM_TYPE_REGULAR,
VM_READ | VM_WRITE, gfp_flags);
if (!vmalloc_seg)
{
spin_lock(&lock);
return false;
}

seg.set_vmalloc_seg(vmalloc_seg);
address = vmalloc_seg;
}
Expand All @@ -335,7 +340,11 @@ class memory_pool
alloc_pages(pages2order(allocation_size >> PAGE_SHIFT),
PAGE_ALLOC_NO_ZERO | PAGE_ALLOC_CONTIGUOUS | gfp_flags);
if (!pages)
{
spin_lock(&lock);
return false;
}

seg.set_pages(pages);
address = PAGE_TO_VIRT(pages);
}
Expand All @@ -347,6 +356,8 @@ class memory_pool
auto &mmap_seg = *static_cast<memory_pool_segment<T, using_vm> *>(address);
mmap_seg = cul::move(seg);

spin_lock(&lock);

auto pair = mmap_seg.setup_chunks();
free_chunk_head = pair.first;
free_chunk_tail = pair.second;
Expand Down
1 change: 1 addition & 0 deletions kernel/include/onyx/mm/vm_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ struct vm_object_ops
{
void (*free_page)(struct vm_object *vmo, struct page *page);
void (*truncate_partial)(struct vm_object *vmobj, struct page *page, size_t offset, size_t len);
ssize_t (*writepage)(struct vm_object *vm_obj, struct page *page, size_t off);
};

#define VMO_FLAG_LOCK_FUTURE_PAGES (1 << 0)
Expand Down
56 changes: 52 additions & 4 deletions kernel/include/onyx/page.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,31 @@ __BEGIN_CDECLS
#define PAGE_FLAG_LRU (1 << 11)
#define PAGE_FLAG_REFERENCED (1 << 12)
#define PAGE_FLAG_ACTIVE (1 << 13)
#define PAGE_FLAG_SWAP (1 << 14)
#define PAGE_FLAG_RECLAIM (1 << 15)

#define PAGEFLAG_OPS(lowercase, uppercase) \
static inline void page_clear_##lowercase(struct page *page) \
{ \
__atomic_and_fetch(&page->flags, ~PAGE_FLAG_##uppercase, __ATOMIC_RELEASE); \
} \
static inline void page_set_##lowercase(struct page *page) \
{ \
__atomic_or_fetch(&page->flags, PAGE_FLAG_##uppercase, __ATOMIC_RELEASE); \
} \
static inline bool page_test_set_##lowercase(struct page *page) \
{ \
return page_test_set_flag(page, PAGE_FLAG_##uppercase); \
} \
static inline bool page_test_clear_##lowercase(struct page *page) \
{ \
return page_test_clear_flag(page, PAGE_FLAG_##uppercase); \
} \
\
static inline bool page_test_##lowercase(const struct page *page) \
{ \
return page_flag_set(page, PAGE_FLAG_##uppercase); \
}

struct vm_object;

Expand Down Expand Up @@ -172,7 +197,7 @@ struct page *page_add_page_late(void *paddr);
#define __GFP_NOWARN (1 << 14)
#define __GFP_NOWAIT (1 << 15)
#define __GFP_MAY_RECLAIM (__GFP_DIRECT_RECLAIM | __GFP_WAKE_PAGEDAEMON)
#define GFP_KERNEL (__GFP_MAY_RECLAIM | __GFP_IO)
#define GFP_KERNEL (__GFP_MAY_RECLAIM | __GFP_IO | __GFP_FS)
#define GFP_ATOMIC (__GFP_ATOMIC | __GFP_WAKE_PAGEDAEMON)
#define GFP_NOIO (__GFP_MAY_RECLAIM)
#define GFP_NOFS (__GFP_MAY_RECLAIM | __GFP_IO)
Expand Down Expand Up @@ -328,12 +353,25 @@ __always_inline bool page_test_set_flag(struct page *p, unsigned long flag)
return true;
}

__always_inline bool page_flag_set(struct page *p, unsigned long flag)
__always_inline bool page_test_clear_flag(struct page *p, unsigned long flag)
{
unsigned long word;
do
{
word = __atomic_load_n(&p->flags, __ATOMIC_ACQUIRE);
if (!(word & flag))
return false;
} while (!__atomic_compare_exchange_n(&p->flags, &word, word & ~flag, false, __ATOMIC_RELEASE,
__ATOMIC_RELAXED));
return true;
}

__always_inline bool page_flag_set(const struct page *p, unsigned long flag)
{
return READ_ONCE(p->flags) & flag;
}

__always_inline bool page_locked(struct page *p)
__always_inline bool page_locked(const struct page *p)
{
return page_flag_set(p, PAGE_FLAG_LOCKED);
}
Expand Down Expand Up @@ -511,7 +549,6 @@ enum page_stat
NR_WRITEBACK,
NR_SLAB_RECLAIMABLE,
NR_SLAB_UNRECLAIMABLE,
/* LRU currently not implemented */
NR_INACTIVE_FILE,
NR_ACTIVE_FILE,
NR_INACTIVE_ANON,
Expand Down Expand Up @@ -569,6 +606,17 @@ static inline void page_set_anon(struct page *page)
inc_page_stat(page, NR_ANON);
}

PAGEFLAG_OPS(reclaim, RECLAIM);
PAGEFLAG_OPS(referenced, REFERENCED);
PAGEFLAG_OPS(swap, SWAP);
PAGEFLAG_OPS(active, ACTIVE);
PAGEFLAG_OPS(lru, LRU);
PAGEFLAG_OPS(uptodate, UPTODATE);
PAGEFLAG_OPS(dirty, DIRTY);

struct vm_object *page_vmobj(struct page *page);
unsigned long page_pgoff(struct page *page);

__END_CDECLS

#endif
3 changes: 3 additions & 0 deletions kernel/include/onyx/paging.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,11 @@ int mmu_fork_tables(struct vm_area_struct *old_region, struct mm_address_space *
unsigned long get_mapping_info(void *addr);
unsigned long __get_mapping_info(void *addr, struct mm_address_space *as);

struct vm_pf_context;
struct page;
unsigned int mmu_get_clear_referenced(struct mm_address_space *mm, void *addr, struct page *page);
int try_to_unmap_one(struct page *page, struct vm_area_struct *vma, unsigned long addr);
int do_wp_page(struct vm_pf_context *context);

__END_CDECLS

Expand Down
Loading

0 comments on commit 2dfdb4d

Please sign in to comment.