1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-18 12:55:07 +00:00
Commit graph

61 commits

Author SHA1 Message Date
Andreas Kling
dd58d0f650 Kernel: Uncommit a shared COW page when discovering it was unshared
When we hit a COW fault and discover than no other process is sharing
the physical page, we simply remap it r/w and save ourselves the
trouble. When this happens, we can also give back (uncommit) one of our
shared committed COW pages, since we won't be needing it.

We had this optimization before, but I mistakenly removed it in
50472fd69f since I had misunderstood
it to be the reason for a panic.
2021-08-05 17:41:58 +02:00
Andreas Kling
843d0d0d15 Kernel: Detach AnonymousVMObject from shared COW pages set once emptied
We currently overcommit for COW when forking a process and cloning its
memory regions. Both the parent and child process share a set of.
committed COW pages.

If there's COW sharing across more than two processeses within a lineage
(e.g parent, child & grandchild), it's possible to exhaust these pages.
When the shared set is emptied, the next COW fault in each process must
detach from the shared set and fall back to on demand allocation.

This patch makes sure that we detach from the shared set once we
discover it to be empty (during COW fault handling). This fixes an issue
where we'd try to allocate from an exhausted shared set while building
GNU binutils inside SerenityOS.
2021-08-05 17:41:58 +02:00
Andreas Kling
89a9ae7d0c Kernel: Handle AnonymousVMObject allocation failure when forking
Thanks to all the RAII, AnonymousVMObject::try_clone() can now
gracefully handle allocation failure.
2021-08-05 17:41:58 +02:00
Andreas Kling
0672163840 Kernel: Simplify AnonymousVMObject copy constructor
It was doing a bunch of things it didn't need to do. I think we had
misunderstood the base class as having copied m_lock in its copy
constructor but it's actually default initialized.
2021-08-05 17:41:58 +02:00
Andreas Kling
fa627c1eb2 Kernel: Use RAII to manage committed physical pages
We had issues with committed physical pages getting miscounted in some
situations, and instead of figuring out what was going wrong and making
sure all the commits had matching uncommits, this patch makes the
problem go away by adding an RAII class to manage this instead. :^)

MemoryManager::commit_user_physical_pages() now returns an (optional)
CommittedPhysicalPageSet. You can then allocate pages from the page set
by calling take_one() on it. Any unallocated pages are uncommitted upon
destruction of the page set.
2021-08-05 17:41:58 +02:00
Andreas Kling
821a6e8b4c Kernel: Remap regions after changing purgeable VM object volatile flag
Otherwise we could end up with stale page table mappings that give us
erroneous Protection Violation faults when accessing valid addresses.
2021-08-03 10:23:36 +02:00
Andreas Kling
363a901603 Kernel: Copy the "purgeable" flag when cloning AnonymousVMObject 2021-07-31 11:22:53 +02:00
Andreas Kling
25b76462bf Revert "Kernel: Share committed COW pages between whole VMObject lineage"
This reverts commit 2c0df5e7e7.

This caused OOM on CI, so let's roll it back until we can figure it out.
2021-07-30 13:50:24 +02:00
Andreas Kling
2c0df5e7e7 Kernel: Share committed COW pages between whole VMObject lineage
When cloning an AnonymousVMObject, committed COW pages are shared
between the parent and child object. Whicever object COW's first will
take the shared committed page, and if the other object ends up doing
a COW as well, it will notice that the page is no longer shared by
two objects and simple remap it as read/write.

When a child is COW'ed again, while still having shared committed
pages with its own parent, the grandchild object will now join in the
sharing pool with its parent and grandparent. This means that the first
2 of 3 objects that COW will draw from the shared committed pages, and
3rd will remap read/write.

Previously, we would "fork" the shared committed pages when cloning,
which could lead to a situation where the grandparent held on to 1 of
the 3 needed shared committed pages. If both the child and grandchild
COW'ed, they wouldn't have enough pages, and since the grandparent
maintained an extra +1 ref count on the page, it wasn't possible to
to remap read/write.
2021-07-30 13:17:55 +02:00
Andreas Kling
50472fd69f Kernel: Don't try to return a committed page that we don't have
When we get a COW fault and discover that whoever we were COW'ing
together with has either COW'ed that page on their end (or they have
unmapped/exited) we simplify life for ourselves by clearing the COW
bit and keeping the page we already have. (No need to COW if the page
is not shared!)

The act of doing this does not return a committed page to the pool.
In fact, that committed page we had reserved for this purpose was used
up (allocated) by our COW buddy when they COW'ed the page.

This fixes a kernel panic when running TestLibCMkTemp. :^)
2021-07-26 00:39:10 +02:00
Andreas Kling
101486279f Kernel: Clear the COW bits when making an AnonymousVMObject volatile 2021-07-26 00:39:10 +02:00
Andreas Kling
6a537ceef1 Kernel: Remove ContiguousVMObject, let AnonymousVMObject do the job
We don't need an entirely separate VMObject subclass to influence the
location of the physical pages.

Instead, we simply allocate enough physically contiguous memory first,
and then pass it to the AnonymousVMObject constructor that takes a span
of physical pages.
2021-07-25 18:44:47 +02:00
Andreas Kling
9a701eafc4 Kernel: Run clang-format on AnonymousVMObject.cpp 2021-07-25 18:21:59 +02:00
Andreas Kling
5fb91e2e84 Kernel: Don't COW volatile VM objects
If a purgeable VM object is in the "volatile" state when we're asked
to make a COW clone of it, make life simpler by simply "purging"
the cloned object right away.

This effectively means that a fork()'ed child process will discover
its purgeable+volatile regions to be empty if/when it tries making
them non-volatile.
2021-07-25 17:28:05 +02:00
Andreas Kling
2d1a651e0a Kernel: Make purgeable memory a VMObject level concept (again)
This patch changes the semantics of purgeable memory.

- AnonymousVMObject now has a "purgeable" flag. It can only be set when
  constructing the object. (Previously, all anonymous memory was
  effectively purgeable.)

- AnonymousVMObject now has a "volatile" flag. It covers the entire
  range of physical pages. (Previously, we tracked ranges of volatile
  pages, effectively making it a page-level concept.)

- Non-volatile objects maintain a physical page reservation via the
  committed pages mechanism, to ensure full coverage for page faults.

- When an object is made volatile, it relinquishes any unused committed
  pages immediately. If later made non-volatile again, we then attempt
  to make a new committed pages reservation. If this fails, we return
  ENOMEM to userspace.

mmap() now creates purgeable objects if passed the MAP_PURGEABLE option
together with MAP_ANONYMOUS. anon_create() memory is always purgeable.
2021-07-25 17:28:05 +02:00
Andreas Kling
082ed6f417 Kernel: Simplify VMObject locking & page fault handlers
This patch greatly simplifies VMObject locking by doing two things:

1. Giving VMObject an IntrusiveList of all its mapping Region objects.
2. Removing VMObject::m_paging_lock in favor of VMObject::m_lock

Before (1), VMObject::for_each_region() was forced to acquire the
global MM lock (since it worked by walking MemoryManager's list of
all regions and checking for regions that pointed to itself.)

With each VMObject having its own list of Regions, VMObject's own
m_lock is all we need.

Before (2), page fault handlers used a separate mutex for preventing
overlapping work. This design required multiple temporary unlocks
and was generally extremely hard to reason about.

Instead, page fault handlers now use VMObject's own m_lock as well.
2021-07-23 03:24:44 +02:00
Andreas Kling
0642f8f2c6 Kernel: Make committed physical page allocation return NonnullRefPtr
Since we're taking from the committed set of pages, there should never
be a reason for this call to fail.

Also add a Badge to disallow taking committed pages from anywhere but
the Region class.
2021-07-22 14:20:05 +02:00
Andreas Kling
5217875f6a Kernel: Consolidate API for creating AnonymousVMObject with given pages
We don't need to have a dedicated API for creating a VMObject with a
single page, the multi-page API option works in all cases.

Also make the API take a Span<NonnullRefPtr<PhysicalPage>> instead of
a NonnullRefPtrVector<PhysicalPage>.
2021-07-22 09:17:02 +02:00
Andreas Kling
9e15708aa0 Kernel: Convert VMObject & subclasses to east-const style 2021-07-22 09:17:02 +02:00
Andreas Kling
9457d83986 Kernel: Rename Locker => MutexLocker 2021-07-18 01:53:04 +02:00
Brian Gianforcaro
d879709ec7 Kernel: Convert the PhysicalPage bool parameter to an enum 2021-07-17 18:38:28 +04:30
Andreas Kling
c2792212f4 Kernel: Remove "supervisor" bit from PhysicalPage
Instead of each PhysicalPage knowing whether it comes from the
supervisor pages or from the user pages, we can just check in both
sets when freeing a page.

It's just a handful of pointer range checks, nothing expensive.
2021-07-12 11:09:42 +02:00
Tom
9318d9f284 Kernel: Fix allocating VMObject from page array
The VMObject constructor takes the size in bytes.

Fixes #8670
2021-07-12 10:45:53 +02:00
Andreas Kling
f244a25f71 Kernel: Rename VMObject::clone() => try_clone()
And fix an unsafe dereference in SharedInodeVMObject::try_clone()
to make it OOM-safe.
2021-07-11 19:09:02 +02:00
Andreas Kling
88d490566f Kernel: Rename various *VMObject::create*() => try_create()
try_*() implies that it can fail (and they all return RefPtr with
nullptr signalling failure.)
2021-07-11 17:55:29 +02:00
Andreas Kling
59049ae4b7 Kernel: Store VMObject physical pages in a FixedArray
Let's enforce the invariant that VMObjects don't shrink or grow by
storing the pages in a FixedArray.
2021-07-11 17:42:31 +02:00
Daniel Bertalan
f820917a76 Everywhere: Use nothrow new with adopt_{ref,own}_if_nonnull
This commit converts naked `new`s to `AK::try_make` and `AK::try_create`
wherever possible. If the called constructor is private, this can not be
done, so we instead now use the standard-defined and compiler-agnostic
`new (nothrow)`.
2021-06-24 17:35:49 +04:30
Brian Gianforcaro
cb45b2c001 Kernel: Make AnonymousVMObject::clone() API OOM safe
Propagate allocation failure of m_shared_committed_cow_pages,
and uncommit previously committed COW pages on failure.

This method needs a closer look in terms of error handling, as we
will eventually need to rollback all changes on allocation failure.
Alternatively we could allocate the anonymous object much earlier
and only initialize it once the other steps have succeeded.
2021-05-29 09:04:05 +02:00
Nicholas Baron
aa4d41fe2c
AK+Kernel+LibELF: Remove the need for IteratorDecision::Continue
By constraining two implementations, the compiler will select the best
fitting one. All this will require is duplicating the implementation and
simplifying for the `void` case.

This constraining also informs both the caller and compiler by passing
the callback parameter types as part of the constraint
(e.g.: `IterationFunction<int>`).

Some `for_each` functions in LibELF only take functions which return
`void`. This is a minimal correctness check, as it removes one way for a
function to incompletely do something.

There seems to be a possible idiom where inside a lambda, a `return;` is
the same as `continue;` in a for-loop.
2021-05-16 10:36:52 +01:00
Brian Gianforcaro
a324d4d6a3 Kernel: Make AnonymousVMObject physical page APIs OOM safe
AnonymousVMObject::create_with_physical_page(s) can't be NonnullRefPtr
as it allocates internally. Fixing the API then surfaced an issue in
ScatterGatherList, where the code was attempting to create an
AnonymousVMObject in the constructor which will not be observable
during OOM.

Fix all of these issues and start propagating errors at the callers
of the AnonymousVMObject and ScatterGatherList APis.
2021-05-15 09:01:32 +02:00
Brian Gianforcaro
d45db06826 Kernel: Make AnonymousVMObject::clone/create APIs OOM safe 2021-05-15 09:01:32 +02:00
Gunnar Beutner
6cf59b6ae9 Everywhere: Turn #if *_DEBUG into dbgln_if/if constexpr 2021-05-01 21:25:06 +02:00
Brian Gianforcaro
8d6e9fad40 Kernel: Remove the now defunct LOCKER(..) macro. 2021-04-25 09:38:27 +02:00
Andreas Kling
b91c49364d AK: Rename adopt() to adopt_ref()
This makes it more symmetrical with adopt_own() (which is used to
create a NonnullOwnPtr from the result of a naked new.)
2021-04-23 16:46:57 +02:00
Brian Gianforcaro
1682f0b760 Everything: Move to SPDX license identifiers in all files.
SPDX License Identifiers are a more compact / standardized
way of representing file license information.

See: https://spdx.dev/resources/use/#identifiers

This was done with the `ambr` search and replace tool.

 ambr --no-parent-ignore --key-from-file --rep-from-file key.txt rep.txt *
2021-04-22 11:22:27 +02:00
Andreas Kling
07564577c0 Kernel: Convert klog() => dmesgln() in AnonymousVMObject 2021-03-09 22:10:41 +01:00
Liav A
ecb169b61e Kernel: Add AnonymousVMObject constructor for a Vector of physical pages
This will be used later on by the AHCI code to create a Region
that spans over scattered DMA pages.
2021-03-05 11:29:34 +01:00
Andreas Kling
adb2e6be5f Kernel: Make the kernel compile & link for x86_64
It's now possible to build the whole kernel with an x86_64 toolchain.
There's no bootstrap code so it doesn't work yet (obviously.)
2021-03-04 18:25:01 +01:00
Andreas Kling
4515652001 Kernel: Remove 1 level of indirection for AnonymousVMObject CoW bitmaps
Instead of keeping AnonymousVMObject::m_cow_map in an OwnPtr<Bitmap>,
just make the Bitmap a regular value member. This increases the size
of the VMObject by 8 bytes, but removes some of the kmalloc/kfree spam
incurred by sys$fork().
2021-03-04 10:11:37 +01:00
Andreas Kling
8129f3da52 Kernel: Move SMAP disabler RAII helper to its own file
Added this in a new directory called Kernel/Arch/x86/ where stuff
that applies to both i386 and x86_64 can live.
2021-02-25 17:25:34 +01:00
Andreas Kling
5d180d1f99 Everywhere: Rename ASSERT => VERIFY
(...and ASSERT_NOT_REACHED => VERIFY_NOT_REACHED)

Since all of these checks are done in release builds as well,
let's rename them to VERIFY to prevent confusion, as everyone is
used to assertions being compiled out in release.

We can introduce a new ASSERT macro that is specifically for debug
checks, but I'm doing this wholesale conversion first since we've
accumulated thousands of these already, and it's not immediately
obvious which ones are suitable for ASSERT.
2021-02-23 20:56:54 +01:00
AnotherTest
09a43969ba Everywhere: Replace dbgln<flag>(...) with dbgln_if(flag, ...)
Replacement made by `find Kernel Userland -name '*.h' -o -name '*.cpp' | sed -i -Ee 's/dbgln\b<(\w+)>\(/dbgln_if(\1, /g'`
2021-02-08 18:08:55 +01:00
asynts
7cf0c7cc0d Meta: Split debug defines into multiple headers.
The following script was used to make these changes:

    #!/bin/bash
    set -e

    tmp=$(mktemp -d)

    echo "tmp=$tmp"

    find Kernel \( -name '*.cpp' -o -name '*.h' \) | sort > $tmp/Kernel.files
    find . \( -path ./Toolchain -prune -o -path ./Build -prune -o -path ./Kernel -prune \) -o \( -name '*.cpp' -o -name '*.h' \) -print | sort > $tmp/EverythingExceptKernel.files

    cat $tmp/Kernel.files | xargs grep -Eho '[A-Z0-9_]+_DEBUG' | sort | uniq > $tmp/Kernel.macros
    cat $tmp/EverythingExceptKernel.files | xargs grep -Eho '[A-Z0-9_]+_DEBUG' | sort | uniq > $tmp/EverythingExceptKernel.macros

    comm -23 $tmp/Kernel.macros $tmp/EverythingExceptKernel.macros > $tmp/Kernel.unique
    comm -1 $tmp/Kernel.macros $tmp/EverythingExceptKernel.macros > $tmp/EverythingExceptKernel.unique

    cat $tmp/Kernel.unique | awk '{ print "#cmakedefine01 "$1 }' > $tmp/Kernel.header
    cat $tmp/EverythingExceptKernel.unique | awk '{ print "#cmakedefine01 "$1 }' > $tmp/EverythingExceptKernel.header

    for macro in $(cat $tmp/Kernel.unique)
    do
        cat $tmp/Kernel.files | xargs grep -l $macro >> $tmp/Kernel.new-includes ||:
    done
    cat $tmp/Kernel.new-includes | sort > $tmp/Kernel.new-includes.sorted

    for macro in $(cat $tmp/EverythingExceptKernel.unique)
    do
        cat $tmp/Kernel.files | xargs grep -l $macro >> $tmp/Kernel.old-includes ||:
    done
    cat $tmp/Kernel.old-includes | sort > $tmp/Kernel.old-includes.sorted

    comm -23 $tmp/Kernel.new-includes.sorted $tmp/Kernel.old-includes.sorted > $tmp/Kernel.includes.new
    comm -13 $tmp/Kernel.new-includes.sorted $tmp/Kernel.old-includes.sorted > $tmp/Kernel.includes.old
    comm -12 $tmp/Kernel.new-includes.sorted $tmp/Kernel.old-includes.sorted > $tmp/Kernel.includes.mixed

    for file in $(cat $tmp/Kernel.includes.new)
    do
        sed -i -E 's/#include <AK\/Debug\.h>/#include <Kernel\/Debug\.h>/' $file
    done

    for file in $(cat $tmp/Kernel.includes.mixed)
    do
        echo "mixed include in $file, requires manual editing."
    done
2021-01-26 21:20:00 +01:00
asynts
eea72b9b5c Everywhere: Hook up remaining debug macros to Debug.h. 2021-01-25 09:47:36 +01:00
asynts
8465683dcf Everywhere: Debug macros instead of constexpr.
This was done with the following script:

    find . \( -name '*.cpp' -o -name '*.h' -o -name '*.in' \) -not -path './Toolchain/*' -not -path './Build/*' -exec sed -i -E 's/dbgln<debug_([a-z_]+)>/dbgln<\U\1_DEBUG>/' {} \;

    find . \( -name '*.cpp' -o -name '*.h' -o -name '*.in' \) -not -path './Toolchain/*' -not -path './Build/*' -exec sed -i -E 's/if constexpr \(debug_([a-z0-9_]+)/if constexpr \(\U\1_DEBUG/' {} \;
2021-01-25 09:47:36 +01:00
asynts
1a3a0836c0 Everywhere: Use CMake to generate AK/Debug.h.
This was done with the help of several scripts, I dump them here to
easily find them later:

    awk '/#ifdef/ { print "#cmakedefine01 "$2 }' AK/Debug.h.in

    for debug_macro in $(awk '/#ifdef/ { print $2 }' AK/Debug.h.in)
    do
        find . \( -name '*.cpp' -o -name '*.h' -o -name '*.in' \) -not -path './Toolchain/*' -not -path './Build/*' -exec sed -i -E 's/#ifdef '$debug_macro'/#if '$debug_macro'/' {} \;
    done

    # Remember to remove WRAPPER_GERNERATOR_DEBUG from the list.
    awk '/#cmake/ { print "set("$2" ON)" }' AK/Debug.h.in
2021-01-25 09:47:36 +01:00
asynts
27bc48e06c Everywhere: Replace a bundle of dbg with dbgln.
These changes are arbitrarily divided into multiple commits to make it
easier to find potentially introduced bugs with git bisect.
2021-01-22 22:14:30 +01:00
Linus Groh
421587c15c Everywhere: Fix typos 2021-01-22 18:41:29 +01:00
asynts
723effd051 Everywhere: Replace a bundle of dbg with dbgln.
These changes are arbitrarily divided into multiple commits to make it
easier to find potentially introduced bugs with git bisect.Everything:
2021-01-11 11:55:47 +01:00
asynts
938e5c7719 Everywhere: Replace a bundle of dbg with dbgln.
These changes are arbitrarily divided into multiple commits to make it
easier to find potentially introduced bugs with git bisect.Everything:

The modifications in this commit were automatically made using the
following command:

    find . -name '*.cpp' -exec sed -i -E 's/dbg\(\) << ("[^"{]*");/dbgln\(\1\);/' {} \;
2021-01-09 21:11:09 +01:00