From a324d4d6a342ad6847697c32f127c31ea76f6e61 Mon Sep 17 00:00:00 2001 From: Brian Gianforcaro Date: Fri, 14 May 2021 05:06:29 -0700 Subject: [PATCH] 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. --- Kernel/Devices/SB16.cpp | 2 ++ Kernel/Storage/AHCIPort.cpp | 4 +++- Kernel/VM/AnonymousVMObject.cpp | 8 ++++---- Kernel/VM/AnonymousVMObject.h | 4 ++-- Kernel/VM/ScatterGatherList.cpp | 11 +++++++---- Kernel/VM/ScatterGatherList.h | 4 ++-- 6 files changed, 20 insertions(+), 13 deletions(-) diff --git a/Kernel/Devices/SB16.cpp b/Kernel/Devices/SB16.cpp index fa48d20db8..2ae61c8ad2 100644 --- a/Kernel/Devices/SB16.cpp +++ b/Kernel/Devices/SB16.cpp @@ -230,6 +230,8 @@ KResultOr SB16::write(FileDescription&, u64, const UserOrKernelBuffer& d if (!page) return ENOMEM; auto vmobject = AnonymousVMObject::create_with_physical_page(*page); + if (!vmobject) + return ENOMEM; m_dma_region = MM.allocate_kernel_region_with_vmobject(*vmobject, PAGE_SIZE, "SB16 DMA buffer", Region::Access::Write); if (!m_dma_region) return ENOMEM; diff --git a/Kernel/Storage/AHCIPort.cpp b/Kernel/Storage/AHCIPort.cpp index cec7c4f3e7..0f7bfec115 100644 --- a/Kernel/Storage/AHCIPort.cpp +++ b/Kernel/Storage/AHCIPort.cpp @@ -433,7 +433,9 @@ Optional AHCIPort::prepare_and_set_scatter_li allocated_dma_regions.append(m_dma_buffers.at(index)); } - m_current_scatter_list = ScatterGatherList::create(request, allocated_dma_regions, m_connected_device->block_size()); + m_current_scatter_list = ScatterGatherList::create(request, move(allocated_dma_regions), m_connected_device->block_size()); + if (!m_current_scatter_list) + return AsyncDeviceRequest::Failure; if (request.request_type() == AsyncBlockDeviceRequest::Write) { if (!request.read_from_buffer(request.buffer(), m_current_scatter_list->dma_region().as_ptr(), m_connected_device->block_size() * request.block_count())) { return AsyncDeviceRequest::MemoryFault; diff --git a/Kernel/VM/AnonymousVMObject.cpp b/Kernel/VM/AnonymousVMObject.cpp index 038bae41a5..912e4cb275 100644 --- a/Kernel/VM/AnonymousVMObject.cpp +++ b/Kernel/VM/AnonymousVMObject.cpp @@ -60,14 +60,14 @@ RefPtr AnonymousVMObject::create_with_size(size_t size, Alloc return adopt_ref_if_nonnull(new AnonymousVMObject(size, commit)); } -NonnullRefPtr AnonymousVMObject::create_with_physical_pages(NonnullRefPtrVector physical_pages) +RefPtr AnonymousVMObject::create_with_physical_pages(NonnullRefPtrVector physical_pages) { - return adopt_ref(*new AnonymousVMObject(physical_pages)); + return adopt_ref_if_nonnull(new AnonymousVMObject(physical_pages)); } -NonnullRefPtr AnonymousVMObject::create_with_physical_page(PhysicalPage& page) +RefPtr AnonymousVMObject::create_with_physical_page(PhysicalPage& page) { - return adopt_ref(*new AnonymousVMObject(page)); + return adopt_ref_if_nonnull(new AnonymousVMObject(page)); } RefPtr AnonymousVMObject::create_for_physical_range(PhysicalAddress paddr, size_t size) diff --git a/Kernel/VM/AnonymousVMObject.h b/Kernel/VM/AnonymousVMObject.h index a2c990fa59..bdca7c0336 100644 --- a/Kernel/VM/AnonymousVMObject.h +++ b/Kernel/VM/AnonymousVMObject.h @@ -22,8 +22,8 @@ public: static RefPtr create_with_size(size_t, AllocationStrategy); static RefPtr create_for_physical_range(PhysicalAddress paddr, size_t size); - static NonnullRefPtr create_with_physical_page(PhysicalPage& page); - static NonnullRefPtr create_with_physical_pages(NonnullRefPtrVector); + static RefPtr create_with_physical_page(PhysicalPage& page); + static RefPtr create_with_physical_pages(NonnullRefPtrVector); virtual RefPtr clone() override; RefPtr allocate_committed_page(size_t); diff --git a/Kernel/VM/ScatterGatherList.cpp b/Kernel/VM/ScatterGatherList.cpp index 6ebbfece2d..a8452de263 100644 --- a/Kernel/VM/ScatterGatherList.cpp +++ b/Kernel/VM/ScatterGatherList.cpp @@ -8,13 +8,16 @@ namespace Kernel { -NonnullRefPtr ScatterGatherList::create(AsyncBlockDeviceRequest& request, NonnullRefPtrVector allocated_pages, size_t device_block_size) +RefPtr ScatterGatherList::create(AsyncBlockDeviceRequest& request, NonnullRefPtrVector allocated_pages, size_t device_block_size) { - return adopt_ref(*new ScatterGatherList(request, allocated_pages, device_block_size)); + auto vm_object = AnonymousVMObject::create_with_physical_pages(allocated_pages); + if (!vm_object) + return {}; + return adopt_ref_if_nonnull(new ScatterGatherList(vm_object.release_nonnull(), request, device_block_size)); } -ScatterGatherList::ScatterGatherList(AsyncBlockDeviceRequest& request, NonnullRefPtrVector allocated_pages, size_t device_block_size) - : m_vm_object(AnonymousVMObject::create_with_physical_pages(allocated_pages)) +ScatterGatherList::ScatterGatherList(NonnullRefPtr vm_object, AsyncBlockDeviceRequest& request, size_t device_block_size) + : m_vm_object(move(vm_object)) { m_dma_region = MM.allocate_kernel_region_with_vmobject(m_vm_object, page_round_up((request.block_count() * device_block_size)), "AHCI Scattered DMA", Region::Access::Read | Region::Access::Write, Region::Cacheable::Yes); } diff --git a/Kernel/VM/ScatterGatherList.h b/Kernel/VM/ScatterGatherList.h index 0d94cbcfa2..9998d677d4 100644 --- a/Kernel/VM/ScatterGatherList.h +++ b/Kernel/VM/ScatterGatherList.h @@ -18,13 +18,13 @@ namespace Kernel { class ScatterGatherList : public RefCounted { public: - static NonnullRefPtr create(AsyncBlockDeviceRequest&, NonnullRefPtrVector allocated_pages, size_t device_block_size); + static RefPtr create(AsyncBlockDeviceRequest&, NonnullRefPtrVector allocated_pages, size_t device_block_size); const VMObject& vmobject() const { return m_vm_object; } VirtualAddress dma_region() const { return m_dma_region->vaddr(); } size_t scatters_count() const { return m_vm_object->physical_pages().size(); } private: - ScatterGatherList(AsyncBlockDeviceRequest&, NonnullRefPtrVector allocated_pages, size_t device_block_size); + ScatterGatherList(NonnullRefPtr, AsyncBlockDeviceRequest&, size_t device_block_size); NonnullRefPtr m_vm_object; OwnPtr m_dma_region; };