1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 00:58:12 +00:00

Fix some paging related bugs exposed by the spawn stress test.

- Process::exec() needs to restore the original paging scope when called
  on a non-current process.
- Add missing InterruptDisabler guards around g_processes access.
- Only flush the TLB when modifying the active page tables.
This commit is contained in:
Andreas Kling 2018-11-09 01:25:31 +01:00
parent 7b96218389
commit e71cb1c56b
13 changed files with 110 additions and 67 deletions

View file

@ -3,7 +3,7 @@
#define PACKED __attribute__ ((packed)) #define PACKED __attribute__ ((packed))
#define NORETURN __attribute__ ((noreturn)) #define NORETURN __attribute__ ((noreturn))
#undef ALWAYS_INLINE #undef ALWAYS_INLINE
#define ALWAYS_INLINE __attribute__ ((always_inline)) #define ALWAYS_INLINE inline __attribute__ ((always_inline))
#define NEVER_INLINE __attribute__ ((noinline)) #define NEVER_INLINE __attribute__ ((noinline))
#define MALLOC_ATTR __attribute__ ((malloc)) #define MALLOC_ATTR __attribute__ ((malloc))
#define PURE __attribute__ ((pure)) #define PURE __attribute__ ((pure))

View file

@ -1,5 +1,3 @@
#define ALWAYS_INLINE inline __attribute__ ((always_inline))
typedef unsigned char byte; typedef unsigned char byte;
typedef unsigned short word; typedef unsigned short word;
typedef unsigned int dword; typedef unsigned int dword;

View file

@ -444,7 +444,8 @@ void MemoryManager::remap_region_page(PageDirectory* page_directory, Region& reg
else else
pte.setWritable(region.is_writable); pte.setWritable(region.is_writable);
pte.setUserAllowed(user_allowed); pte.setUserAllowed(user_allowed);
flushTLB(page_laddr); if (page_directory->is_active())
flushTLB(page_laddr);
#ifdef MM_DEBUG #ifdef MM_DEBUG
dbgprintf("MM: >> remap_region_page (PD=%x) '%s' L%x => P%x (@%p)\n", page_directory, region.name.characters(), page_laddr.get(), physical_page->paddr().get(), physical_page.ptr()); dbgprintf("MM: >> remap_region_page (PD=%x) '%s' L%x => P%x (@%p)\n", page_directory, region.name.characters(), page_laddr.get(), physical_page->paddr().get(), physical_page.ptr());
#endif #endif
@ -478,7 +479,8 @@ void MemoryManager::map_region_at_address(PageDirectory* page_directory, Region&
pte.setWritable(region.is_writable); pte.setWritable(region.is_writable);
} }
pte.setUserAllowed(user_allowed); pte.setUserAllowed(user_allowed);
flushTLB(page_laddr); if (page_directory->is_active())
flushTLB(page_laddr);
#ifdef MM_DEBUG #ifdef MM_DEBUG
dbgprintf("MM: >> map_region_at_address (PD=%x) '%s' L%x => P%x (@%p)\n", page_directory, region.name.characters(), page_laddr, physical_page ? physical_page->paddr().get() : 0, physical_page.ptr()); dbgprintf("MM: >> map_region_at_address (PD=%x) '%s' L%x => P%x (@%p)\n", page_directory, region.name.characters(), page_laddr, physical_page ? physical_page->paddr().get() : 0, physical_page.ptr());
#endif #endif
@ -498,7 +500,8 @@ void MemoryManager::unmap_range(PageDirectory* page_directory, LinearAddress lad
pte.setPresent(false); pte.setPresent(false);
pte.setWritable(false); pte.setWritable(false);
pte.setUserAllowed(false); pte.setUserAllowed(false);
flushTLB(page_laddr); if (page_directory->is_active())
flushTLB(page_laddr);
#ifdef MM_DEBUG #ifdef MM_DEBUG
dbgprintf("MM: << unmap_range L%x =/> 0\n", page_laddr); dbgprintf("MM: << unmap_range L%x =/> 0\n", page_laddr);
#endif #endif
@ -547,7 +550,8 @@ bool MemoryManager::unmapRegion(Process& process, Region& region)
pte.setPresent(false); pte.setPresent(false);
pte.setWritable(false); pte.setWritable(false);
pte.setUserAllowed(false); pte.setUserAllowed(false);
flushTLB(laddr); if (process.m_page_directory->is_active())
flushTLB(laddr);
#ifdef MM_DEBUG #ifdef MM_DEBUG
auto& physical_page = region.vmo().physical_pages()[region.first_page_index() + i]; auto& physical_page = region.vmo().physical_pages()[region.first_page_index() + i];
dbgprintf("MM: >> Unmapped L%x => P%x <<\n", laddr, physical_page ? physical_page->paddr().get() : 0); dbgprintf("MM: >> Unmapped L%x => P%x <<\n", laddr, physical_page ? physical_page->paddr().get() : 0);
@ -764,3 +768,8 @@ void MemoryManager::unregister_region(Region& region)
InterruptDisabler disabler; InterruptDisabler disabler;
m_regions.remove(&region); m_regions.remove(&region);
} }
inline bool PageDirectory::is_active() const
{
return &current->page_directory() == this;
}

View file

@ -55,6 +55,8 @@ private:
struct PageDirectory { struct PageDirectory {
dword entries[1024]; dword entries[1024];
RetainPtr<PhysicalPage> physical_pages[1024]; RetainPtr<PhysicalPage> physical_pages[1024];
bool is_active() const;
}; };
class VMObject : public Retainable<VMObject> { class VMObject : public Retainable<VMObject> {

View file

@ -271,8 +271,11 @@ Process* Process::fork(RegisterDump& regs)
ProcFileSystem::the().addProcess(*child); ProcFileSystem::the().addProcess(*child);
g_processes->prepend(child); {
system.nprocess++; InterruptDisabler disabler;
g_processes->prepend(child);
system.nprocess++;
}
#ifdef TASK_DEBUG #ifdef TASK_DEBUG
kprintf("Process %u (%s) forked from %u @ %p\n", child->pid(), child->name().characters(), m_pid, child->m_tss.eip); kprintf("Process %u (%s) forked from %u @ %p\n", child->pid(), child->name().characters(), m_pid, child->m_tss.eip);
#endif #endif
@ -315,10 +318,12 @@ int Process::exec(const String& path, Vector<String>&& arguments, Vector<String>
dword entry_eip = 0; dword entry_eip = 0;
PageDirectory* old_page_directory = m_page_directory; PageDirectory* old_page_directory = m_page_directory;
PageDirectory* new_page_directory = reinterpret_cast<PageDirectory*>(kmalloc_page_aligned(sizeof(PageDirectory))); PageDirectory* new_page_directory = reinterpret_cast<PageDirectory*>(kmalloc_page_aligned(sizeof(PageDirectory)));
dbgprintf("Process exec: PD=%x created\n", new_page_directory); #ifdef MM_DEBUG
dbgprintf("Process %u exec: PD=%x created\n", pid(), new_page_directory);
#endif
MM.populate_page_directory(*new_page_directory); MM.populate_page_directory(*new_page_directory);
m_page_directory = new_page_directory; m_page_directory = new_page_directory;
MM.enter_process_paging_scope(*this); ProcessPagingScope paging_scope(*this);
// FIXME: Should we consider doing on-demand paging here? Is it actually useful? // FIXME: Should we consider doing on-demand paging here? Is it actually useful?
bool success = region->page_in(*new_page_directory); bool success = region->page_in(*new_page_directory);
@ -400,10 +405,9 @@ int Process::exec(const String& path, Vector<String>&& arguments, Vector<String>
} // Ready to yield-teleport! } // Ready to yield-teleport!
if (current == this) { if (current == this) {
bool success = Scheduler::yield(); Scheduler::yield();
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
return 0; return 0;
} }
@ -509,8 +513,11 @@ Process* Process::create_user_process(const String& path, uid_t uid, gid_t gid,
ProcFileSystem::the().addProcess(*process); ProcFileSystem::the().addProcess(*process);
g_processes->prepend(process); {
system.nprocess++; InterruptDisabler disabler;
g_processes->prepend(process);
system.nprocess++;
}
#ifdef TASK_DEBUG #ifdef TASK_DEBUG
kprintf("Process %u (%s) spawned @ %p\n", process->pid(), process->name().characters(), process->m_tss.eip); kprintf("Process %u (%s) spawned @ %p\n", process->pid(), process->name().characters(), process->m_tss.eip);
#endif #endif
@ -562,9 +569,11 @@ Process* Process::create_kernel_process(void (*e)(), String&& name)
process->m_tss.eip = (dword)e; process->m_tss.eip = (dword)e;
if (process->pid() != 0) { if (process->pid() != 0) {
InterruptDisabler disabler; {
g_processes->prepend(process); InterruptDisabler disabler;
system.nprocess++; g_processes->prepend(process);
system.nprocess++;
}
ProcFileSystem::the().addProcess(*process); ProcFileSystem::the().addProcess(*process);
#ifdef TASK_DEBUG #ifdef TASK_DEBUG
kprintf("Kernel process %u (%s) spawned @ %p\n", process->pid(), process->name().characters(), process->m_tss.eip); kprintf("Kernel process %u (%s) spawned @ %p\n", process->pid(), process->name().characters(), process->m_tss.eip);
@ -603,7 +612,9 @@ Process::Process(String&& name, uid_t uid, gid_t gid, pid_t ppid, RingLevel ring
} }
m_page_directory = (PageDirectory*)kmalloc_page_aligned(sizeof(PageDirectory)); m_page_directory = (PageDirectory*)kmalloc_page_aligned(sizeof(PageDirectory));
dbgprintf("Process ctor: PD=%x created\n", m_page_directory); #ifdef MM_DEBUG
dbgprintf("Process %u ctor: PD=%x created\n", pid(), m_page_directory);
#endif
MM.populate_page_directory(*m_page_directory); MM.populate_page_directory(*m_page_directory);
if (fork_parent) { if (fork_parent) {
@ -1246,15 +1257,13 @@ mode_t Process::sys$umask(mode_t mask)
return old_mask; return old_mask;
} }
void Process::reap(pid_t pid) void Process::reap(Process& process)
{ {
InterruptDisabler disabler; InterruptDisabler disabler;
auto* process = Process::from_pid(pid); dbgprintf("reap: %s(%u) {%s}\n", process.name().characters(), process.pid(), toString(process.state()));
ASSERT(process); ASSERT(process.state() == Dead);
dbgprintf("reap: %s(%u) {%s}\n", process->name().characters(), process->pid(), toString(process->state())); g_processes->remove(&process);
ASSERT(process->state() == Dead); delete &process;
g_processes->remove(process);
delete process;
} }
pid_t Process::sys$waitpid(pid_t waitee, int* wstatus, int options) pid_t Process::sys$waitpid(pid_t waitee, int* wstatus, int options)
@ -1273,7 +1282,13 @@ pid_t Process::sys$waitpid(pid_t waitee, int* wstatus, int options)
sched_yield(); sched_yield();
if (m_was_interrupted_while_blocked) if (m_was_interrupted_while_blocked)
return -EINTR; return -EINTR;
reap(waitee); Process* waitee_process;
{
InterruptDisabler disabler;
waitee_process = Process::from_pid(waitee);
}
ASSERT(waitee_process);
reap(*waitee_process);
if (wstatus) if (wstatus)
*wstatus = m_waitee_status; *wstatus = m_waitee_status;
return m_waitee; return m_waitee;

View file

@ -67,6 +67,9 @@ public:
return m_state == BlockedSleep || m_state == BlockedWait || m_state == BlockedRead; return m_state == BlockedSleep || m_state == BlockedWait || m_state == BlockedRead;
} }
PageDirectory& page_directory() { return *m_page_directory; }
const PageDirectory& page_directory() const { return *m_page_directory; }
bool in_kernel() const { return (m_tss.cs & 0x03) == 0; } bool in_kernel() const { return (m_tss.cs & 0x03) == 0; }
static Process* from_pid(pid_t); static Process* from_pid(pid_t);
@ -162,7 +165,7 @@ public:
static void initialize(); static void initialize();
void crash() NORETURN; void crash() NORETURN;
static void reap(pid_t); static void reap(Process&);
const TTY* tty() const { return m_tty; } const TTY* tty() const { return m_tty; }

View file

@ -67,7 +67,7 @@ bool Scheduler::pick_next()
if (process.state() == Process::Dead) { if (process.state() == Process::Dead) {
if (current != &process && !Process::from_pid(process.ppid())) if (current != &process && !Process::from_pid(process.ppid()))
Process::reap(process.pid()); Process::reap(process);
return true; return true;
} }

View file

@ -149,8 +149,8 @@ static void spawn_stress()
for (unsigned i = 0; i < 10000; ++i) { for (unsigned i = 0; i < 10000; ++i) {
int error; int error;
Process::create_user_process("/bin/id", (uid_t)100, (gid_t)100, (pid_t)0, error, Vector<String>(), Vector<String>(), tty0); Process::create_user_process("/bin/id", (uid_t)100, (gid_t)100, (pid_t)0, error, Vector<String>(), Vector<String>(), tty0);
// kprintf("malloc stats: alloc:%u free:%u page_aligned:%u eternal:%u\n", sum_alloc, sum_free, kmalloc_page_aligned, kmalloc_sum_eternal); kprintf("malloc stats: alloc:%u free:%u page_aligned:%u eternal:%u\n", sum_alloc, sum_free, kmalloc_page_aligned, kmalloc_sum_eternal);
// kprintf("delta:%u\n", sum_alloc - lastAlloc); kprintf("delta:%u\n", sum_alloc - lastAlloc);
lastAlloc = sum_alloc; lastAlloc = sum_alloc;
sleep(60); sleep(60);
} }

View file

@ -28,7 +28,7 @@ typedef struct
#define RANGE_SIZE 0x100000 #define RANGE_SIZE 0x100000
PRIVATE BYTE alloc_map[POOL_SIZE / CHUNK_SIZE / 8]; static byte alloc_map[POOL_SIZE / CHUNK_SIZE / 8];
volatile DWORD sum_alloc = 0; volatile DWORD sum_alloc = 0;
volatile DWORD sum_free = POOL_SIZE; volatile DWORD sum_free = POOL_SIZE;
@ -50,8 +50,7 @@ bool is_kmalloc_address(void* ptr)
return ptr >= (void*)BASE_PHYS && ptr <= ((void*)BASE_PHYS + POOL_SIZE); return ptr >= (void*)BASE_PHYS && ptr <= ((void*)BASE_PHYS + POOL_SIZE);
} }
PUBLIC void void kmalloc_init()
kmalloc_init()
{ {
memset( &alloc_map, 0, sizeof(alloc_map) ); memset( &alloc_map, 0, sizeof(alloc_map) );
memset( (void *)BASE_PHYS, 0, POOL_SIZE ); memset( (void *)BASE_PHYS, 0, POOL_SIZE );
@ -88,8 +87,7 @@ void* kmalloc_page_aligned(size_t size)
} }
PUBLIC void * void* kmalloc(dword size)
kmalloc( DWORD size )
{ {
InterruptDisabler disabler; InterruptDisabler disabler;
@ -162,8 +160,7 @@ kmalloc( DWORD size )
return nullptr; return nullptr;
} }
PUBLIC void void kfree(void *ptr)
kfree( void *ptr )
{ {
if( !ptr ) if( !ptr )
return; return;

12
Kernel/makeall.sh Executable file
View file

@ -0,0 +1,12 @@
#!/bin/bash
sudo id
make -C ../LibC clean && \
make -C ../LibC && \
make -C ../Userland clean && \
make -C ../Userland && \
make clean &&\
make && \
sudo ./sync.sh

10
Kernel/makeuserland.sh Executable file
View file

@ -0,0 +1,10 @@
#!/bin/bash
sudo id
make -C ../LibC clean && \
make -C ../LibC && \
make -C ../Userland clean && \
make -C ../Userland && \
sudo ./sync.sh

View file

@ -1,30 +1,30 @@
rm -f _fs_contents.lock rm -vf _fs_contents.lock
rm -f _fs_contents rm -vf _fs_contents
cp -p _fs_contents.stock _fs_contents cp -vp _fs_contents.stock _fs_contents
mkdir -p mnt mkdir -vp mnt
mount -o loop _fs_contents mnt/ mount -o loop _fs_contents mnt/
cp -R ../Base/* mnt/ cp -R ../Base/* mnt/
cp ../Userland/sh mnt/bin/sh cp -v ../Userland/sh mnt/bin/sh
cp ../Userland/id mnt/bin/id cp -v ../Userland/id mnt/bin/id
cp ../Userland/ps mnt/bin/ps cp -v ../Userland/ps mnt/bin/ps
cp ../Userland/ls mnt/bin/ls cp -v ../Userland/ls mnt/bin/ls
cp ../Userland/pwd mnt/bin/pwd cp -v ../Userland/pwd mnt/bin/pwd
cp ../Userland/sleep mnt/bin/sleep cp -v ../Userland/sleep mnt/bin/sleep
cp ../Userland/date mnt/bin/date cp -v ../Userland/date mnt/bin/date
cp ../Userland/true mnt/bin/true cp -v ../Userland/true mnt/bin/true
cp ../Userland/false mnt/bin/false cp -v ../Userland/false mnt/bin/false
cp ../Userland/hostname mnt/bin/hostname cp -v ../Userland/hostname mnt/bin/hostname
cp ../Userland/cat mnt/bin/cat cp -v ../Userland/cat mnt/bin/cat
cp ../Userland/uname mnt/bin/uname cp -v ../Userland/uname mnt/bin/uname
cp ../Userland/clear mnt/bin/clear cp -v ../Userland/clear mnt/bin/clear
cp ../Userland/tst mnt/bin/tst cp -v ../Userland/tst mnt/bin/tst
cp ../Userland/ft mnt/bin/ft cp -v ../Userland/ft mnt/bin/ft
cp ../Userland/ft2 mnt/bin/ft2 cp -v ../Userland/ft2 mnt/bin/ft2
cp ../Userland/mm mnt/bin/mm cp -v ../Userland/mm mnt/bin/mm
cp ../Userland/kill mnt/bin/kill cp -v ../Userland/kill mnt/bin/kill
cp ../Userland/tty mnt/bin/tty cp -v ../Userland/tty mnt/bin/tty
cp ../Userland/strsignal mnt/bin/strsignal cp -v ../Userland/strsignal mnt/bin/strsignal
sh sync-local.sh sh sync-local.sh
cp kernel.map mnt/ cp -v kernel.map mnt/
umount mnt umount mnt
sync sync

View file

@ -1,13 +1,10 @@
#pragma once #pragma once
#include <AK/Compiler.h>
#include <AK/Types.h> #include <AK/Types.h>
#define PACKED __attribute__ ((packed)) #define PACKED __attribute__ ((packed))
#define NORETURN __attribute__ ((noreturn))
#define ALWAYS_INLINE __attribute__ ((always_inline))
#define PURE __attribute__ ((pure)) #define PURE __attribute__ ((pure))
#define PUBLIC
#define PRIVATE static
typedef unsigned char BYTE; typedef unsigned char BYTE;
typedef unsigned short WORD; typedef unsigned short WORD;