mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 15:27:35 +00:00
Kernel: Make Region::try_create_user_accessible() OOM-safe
Previously we would simply assume that Region allocation always succeeded. There is still one such assumption when splitting user regions inside a Space. That will be dealt with in a separate commit.
This commit is contained in:
parent
241bbce264
commit
cac557eee0
3 changed files with 33 additions and 14 deletions
|
@ -83,8 +83,12 @@ OwnPtr<Region> Region::clone(Process& new_owner)
|
||||||
VERIFY(vmobject().is_shared_inode());
|
VERIFY(vmobject().is_shared_inode());
|
||||||
|
|
||||||
// Create a new region backed by the same VMObject.
|
// Create a new region backed by the same VMObject.
|
||||||
auto region = Region::create_user_accessible(
|
auto region = Region::try_create_user_accessible(
|
||||||
&new_owner, m_range, m_vmobject, m_offset_in_vmobject, m_name ? m_name->try_clone() : OwnPtr<KString> {}, access(), m_cacheable ? Cacheable::Yes : Cacheable::No, m_shared);
|
&new_owner, m_range, m_vmobject, m_offset_in_vmobject, m_name ? m_name->try_clone() : OwnPtr<KString> {}, access(), m_cacheable ? Cacheable::Yes : Cacheable::No, m_shared);
|
||||||
|
if (!region) {
|
||||||
|
dbgln("Region::clone: Unable to allocate new Region");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
if (m_vmobject->is_anonymous())
|
if (m_vmobject->is_anonymous())
|
||||||
region->copy_purgeable_page_ranges(*this);
|
region->copy_purgeable_page_ranges(*this);
|
||||||
region->set_mmap(m_mmap);
|
region->set_mmap(m_mmap);
|
||||||
|
@ -102,8 +106,12 @@ OwnPtr<Region> Region::clone(Process& new_owner)
|
||||||
|
|
||||||
// Set up a COW region. The parent (this) region becomes COW as well!
|
// Set up a COW region. The parent (this) region becomes COW as well!
|
||||||
remap();
|
remap();
|
||||||
auto clone_region = Region::create_user_accessible(
|
auto clone_region = Region::try_create_user_accessible(
|
||||||
&new_owner, m_range, vmobject_clone.release_nonnull(), m_offset_in_vmobject, m_name ? m_name->try_clone() : OwnPtr<KString> {}, access(), m_cacheable ? Cacheable::Yes : Cacheable::No, m_shared);
|
&new_owner, m_range, vmobject_clone.release_nonnull(), m_offset_in_vmobject, m_name ? m_name->try_clone() : OwnPtr<KString> {}, access(), m_cacheable ? Cacheable::Yes : Cacheable::No, m_shared);
|
||||||
|
if (!clone_region) {
|
||||||
|
dbgln("Region::clone: Unable to allocate new Region for COW");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
if (m_vmobject->is_anonymous())
|
if (m_vmobject->is_anonymous())
|
||||||
clone_region->copy_purgeable_page_ranges(*this);
|
clone_region->copy_purgeable_page_ranges(*this);
|
||||||
if (m_stack) {
|
if (m_stack) {
|
||||||
|
@ -208,13 +216,14 @@ size_t Region::amount_shared() const
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
NonnullOwnPtr<Region> Region::create_user_accessible(Process* owner, const Range& range, NonnullRefPtr<VMObject> vmobject, size_t offset_in_vmobject, OwnPtr<KString> name, Region::Access access, Cacheable cacheable, bool shared)
|
OwnPtr<Region> Region::try_create_user_accessible(Process* owner, const Range& range, NonnullRefPtr<VMObject> vmobject, size_t offset_in_vmobject, OwnPtr<KString> name, Region::Access access, Cacheable cacheable, bool shared)
|
||||||
{
|
{
|
||||||
auto region = adopt_own_if_nonnull(new (nothrow) Region(range, move(vmobject), offset_in_vmobject, move(name), access, cacheable, shared));
|
auto region = adopt_own_if_nonnull(new (nothrow) Region(range, move(vmobject), offset_in_vmobject, move(name), access, cacheable, shared));
|
||||||
if (region && owner)
|
if (!region)
|
||||||
|
return nullptr;
|
||||||
|
if (owner)
|
||||||
region->m_owner = owner->make_weak_ptr();
|
region->m_owner = owner->make_weak_ptr();
|
||||||
// FIXME: Return OwnPtr and propagate failure, currently there are too many assumptions made by down stream callers.
|
return region;
|
||||||
return region.release_nonnull();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OwnPtr<Region> Region::create_kernel_only(const Range& range, NonnullRefPtr<VMObject> vmobject, size_t offset_in_vmobject, OwnPtr<KString> name, Region::Access access, Cacheable cacheable)
|
OwnPtr<Region> Region::create_kernel_only(const Range& range, NonnullRefPtr<VMObject> vmobject, size_t offset_in_vmobject, OwnPtr<KString> name, Region::Access access, Cacheable cacheable)
|
||||||
|
|
|
@ -49,7 +49,7 @@ public:
|
||||||
Yes,
|
Yes,
|
||||||
};
|
};
|
||||||
|
|
||||||
static NonnullOwnPtr<Region> create_user_accessible(Process*, const Range&, NonnullRefPtr<VMObject>, size_t offset_in_vmobject, OwnPtr<KString> name, Region::Access access, Cacheable, bool shared);
|
static OwnPtr<Region> try_create_user_accessible(Process*, const Range&, NonnullRefPtr<VMObject>, size_t offset_in_vmobject, OwnPtr<KString> name, Region::Access access, Cacheable, bool shared);
|
||||||
static OwnPtr<Region> create_kernel_only(const Range&, NonnullRefPtr<VMObject>, size_t offset_in_vmobject, OwnPtr<KString> name, Region::Access access, Cacheable = Cacheable::Yes);
|
static OwnPtr<Region> create_kernel_only(const Range&, NonnullRefPtr<VMObject>, size_t offset_in_vmobject, OwnPtr<KString> name, Region::Access access, Cacheable = Cacheable::Yes);
|
||||||
|
|
||||||
~Region();
|
~Region();
|
||||||
|
|
|
@ -145,8 +145,11 @@ Optional<Range> Space::allocate_range(VirtualAddress vaddr, size_t size, size_t
|
||||||
|
|
||||||
Region& Space::allocate_split_region(const Region& source_region, const Range& range, size_t offset_in_vmobject)
|
Region& Space::allocate_split_region(const Region& source_region, const Range& range, size_t offset_in_vmobject)
|
||||||
{
|
{
|
||||||
auto& region = add_region(Region::create_user_accessible(
|
auto new_region = Region::try_create_user_accessible(
|
||||||
m_process, range, source_region.vmobject(), offset_in_vmobject, KString::try_create(source_region.name()), source_region.access(), source_region.is_cacheable() ? Region::Cacheable::Yes : Region::Cacheable::No, source_region.is_shared()));
|
m_process, range, source_region.vmobject(), offset_in_vmobject, KString::try_create(source_region.name()), source_region.access(), source_region.is_cacheable() ? Region::Cacheable::Yes : Region::Cacheable::No, source_region.is_shared());
|
||||||
|
// FIXME: Handle !new_region (by propagating ENOMEM)
|
||||||
|
VERIFY(new_region);
|
||||||
|
auto& region = add_region(new_region.release_nonnull());
|
||||||
region.set_syscall_region(source_region.is_syscall_region());
|
region.set_syscall_region(source_region.is_syscall_region());
|
||||||
region.set_mmap(source_region.is_mmap());
|
region.set_mmap(source_region.is_mmap());
|
||||||
region.set_stack(source_region.is_stack());
|
region.set_stack(source_region.is_stack());
|
||||||
|
@ -164,10 +167,12 @@ KResultOr<Region*> Space::allocate_region(Range const& range, StringView name, i
|
||||||
auto vmobject = AnonymousVMObject::try_create_with_size(range.size(), strategy);
|
auto vmobject = AnonymousVMObject::try_create_with_size(range.size(), strategy);
|
||||||
if (!vmobject)
|
if (!vmobject)
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
auto region = Region::create_user_accessible(m_process, range, vmobject.release_nonnull(), 0, KString::try_create(name), prot_to_region_access_flags(prot), Region::Cacheable::Yes, false);
|
auto region = Region::try_create_user_accessible(m_process, range, vmobject.release_nonnull(), 0, KString::try_create(name), prot_to_region_access_flags(prot), Region::Cacheable::Yes, false);
|
||||||
|
if (!region)
|
||||||
|
return ENOMEM;
|
||||||
if (!region->map(page_directory()))
|
if (!region->map(page_directory()))
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
return &add_region(move(region));
|
return &add_region(region.release_nonnull());
|
||||||
}
|
}
|
||||||
|
|
||||||
KResultOr<Region*> Space::allocate_region_with_vmobject(Range const& range, NonnullRefPtr<VMObject> vmobject, size_t offset_in_vmobject, StringView name, int prot, bool shared)
|
KResultOr<Region*> Space::allocate_region_with_vmobject(Range const& range, NonnullRefPtr<VMObject> vmobject, size_t offset_in_vmobject, StringView name, int prot, bool shared)
|
||||||
|
@ -187,12 +192,17 @@ KResultOr<Region*> Space::allocate_region_with_vmobject(Range const& range, Nonn
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
offset_in_vmobject &= PAGE_MASK;
|
offset_in_vmobject &= PAGE_MASK;
|
||||||
auto& region = add_region(Region::create_user_accessible(m_process, range, move(vmobject), offset_in_vmobject, KString::try_create(name), prot_to_region_access_flags(prot), Region::Cacheable::Yes, shared));
|
auto region = Region::try_create_user_accessible(m_process, range, move(vmobject), offset_in_vmobject, KString::try_create(name), prot_to_region_access_flags(prot), Region::Cacheable::Yes, shared);
|
||||||
if (!region.map(page_directory())) {
|
if (!region) {
|
||||||
|
dbgln("allocate_region_with_vmobject: Unable to allocate Region");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
auto& region_ref = add_region(region.release_nonnull());
|
||||||
|
if (!region_ref.map(page_directory())) {
|
||||||
// FIXME: What is an appropriate error code here, really?
|
// FIXME: What is an appropriate error code here, really?
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
return ®ion;
|
return ®ion_ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Space::deallocate_region(Region& region)
|
bool Space::deallocate_region(Region& region)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue