From da1b24b9b563e36f228a44480ee6d66b927d3820 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sat, 12 Mar 2022 23:01:01 -0800 Subject: [PATCH] fs: fix locking in FileSystemBufferManager --- .../fssystem_file_system_buffer_manager.hpp | 15 ++- .../fssystem_file_system_buffer_manager.cpp | 106 ++++++++++++++---- 2 files changed, 95 insertions(+), 26 deletions(-) diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/buffers/fssystem_file_system_buffer_manager.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/buffers/fssystem_file_system_buffer_manager.hpp index 0fc803ca6..c59259544 100644 --- a/libraries/libstratosphere/include/stratosphere/fssystem/buffers/fssystem_file_system_buffer_manager.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssystem/buffers/fssystem_file_system_buffer_manager.hpp @@ -269,13 +269,13 @@ namespace ams::fssystem { m_cache_handle_table.Finalize(); } private: - virtual const std::pair DoAllocateBuffer(size_t size, const BufferAttribute &attr) override; + virtual const fs::IBufferManager::MemoryRange DoAllocateBuffer(size_t size, const BufferAttribute &attr) override; virtual void DoDeallocateBuffer(uintptr_t address, size_t size) override; virtual CacheHandle DoRegisterCache(uintptr_t address, size_t size, const BufferAttribute &attr) override; - virtual const std::pair DoAcquireCache(CacheHandle handle) override; + virtual const fs::IBufferManager::MemoryRange DoAcquireCache(CacheHandle handle) override; virtual size_t DoGetTotalSize() const override; @@ -290,6 +290,17 @@ namespace ams::fssystem { virtual size_t DoGetRetriedCount() const override; virtual void DoClearPeak() override; + private: + const fs::IBufferManager::MemoryRange AllocateBufferImpl(size_t size, const BufferAttribute &attr); + void DeallocateBufferImpl(uintptr_t address, size_t size); + CacheHandle RegisterCacheImpl(uintptr_t address, size_t size, const BufferAttribute &attr); + const fs::IBufferManager::MemoryRange AcquireCacheImpl(CacheHandle handle); + size_t GetFreeSizeImpl() const; + size_t GetTotalAllocatableSizeImpl() const; + size_t GetFreeSizePeakImpl() const; + size_t GetTotalAllocatableSizePeakImpl() const; + size_t GetRetriedCountImpl() const; + void ClearPeakImpl(); }; } diff --git a/libraries/libstratosphere/source/fssystem/buffers/fssystem_file_system_buffer_manager.cpp b/libraries/libstratosphere/source/fssystem/buffers/fssystem_file_system_buffer_manager.cpp index 80ef95134..93b8683ef 100644 --- a/libraries/libstratosphere/source/fssystem/buffers/fssystem_file_system_buffer_manager.cpp +++ b/libraries/libstratosphere/source/fssystem/buffers/fssystem_file_system_buffer_manager.cpp @@ -239,21 +239,24 @@ namespace ams::fssystem { return it != m_attr_list.end() ? std::addressof(*it) : nullptr; } - const fs::IBufferManager::MemoryRange FileSystemBufferManager::DoAllocateBuffer(size_t size, const BufferAttribute &attr) { - std::scoped_lock lk(m_mutex); - + const fs::IBufferManager::MemoryRange FileSystemBufferManager::AllocateBufferImpl(size_t size, const BufferAttribute &attr) { + /* Get/sanity check the required order. */ fs::IBufferManager::MemoryRange range = {}; const auto order = m_buddy_heap.GetOrderFromBytes(size); AMS_ASSERT(order >= 0); while (true) { + /* Try to allocate a buffer at the desired order. */ if (auto address = m_buddy_heap.AllocateByOrder(order); address != 0) { + /* Check that we allocated enough. */ const auto allocated_size = m_buddy_heap.GetBytesFromOrder(order); AMS_ASSERT(size <= allocated_size); + /* Set up the range extents. */ range.first = reinterpret_cast(address); range.second = allocated_size; + /* Update our peak tracking variables. */ const size_t free_size = m_buddy_heap.GetTotalFreeSize(); m_peak_free_size = std::min(m_peak_free_size, free_size); @@ -262,32 +265,30 @@ namespace ams::fssystem { break; } + /* We failed, to we'll need to deallocate something and retry. */ + ++m_retried_count; + /* Deallocate a buffer. */ uintptr_t deallocate_address = 0; size_t deallocate_size = 0; - - ++m_retried_count; if (m_cache_handle_table.UnregisterOldest(std::addressof(deallocate_address), std::addressof(deallocate_size), attr, size)) { - this->DeallocateBuffer(deallocate_address, deallocate_size); + this->DeallocateBufferImpl(deallocate_address, deallocate_size); } else { break; } } + /* Return the range we allocated. */ return range; } - void FileSystemBufferManager::DoDeallocateBuffer(uintptr_t address, size_t size) { + void FileSystemBufferManager::DeallocateBufferImpl(uintptr_t address, size_t size) { AMS_ASSERT(util::IsPowerOfTwo(size)); - std::scoped_lock lk(m_mutex); - m_buddy_heap.Free(reinterpret_cast(address), m_buddy_heap.GetOrderFromBytes(size)); } - FileSystemBufferManager::CacheHandle FileSystemBufferManager::DoRegisterCache(uintptr_t address, size_t size, const BufferAttribute &attr) { - std::scoped_lock lk(m_mutex); - + FileSystemBufferManager::CacheHandle FileSystemBufferManager::RegisterCacheImpl(uintptr_t address, size_t size, const BufferAttribute &attr) { CacheHandle handle = 0; while (true) { /* Try to register the handle. */ @@ -301,9 +302,9 @@ namespace ams::fssystem { ++m_retried_count; if (m_cache_handle_table.UnregisterOldest(std::addressof(deallocate_address), std::addressof(deallocate_size), attr)) { - this->DeallocateBuffer(deallocate_address, deallocate_size); + this->DeallocateBufferImpl(deallocate_address, deallocate_size); } else { - this->DeallocateBuffer(address, size); + this->DeallocateBufferImpl(address, size); handle = m_cache_handle_table.PublishCacheHandle(); break; } @@ -312,9 +313,7 @@ namespace ams::fssystem { return handle; } - const fs::IBufferManager::MemoryRange FileSystemBufferManager::DoAcquireCache(CacheHandle handle) { - std::scoped_lock lk(m_mutex); - + const fs::IBufferManager::MemoryRange FileSystemBufferManager::AcquireCacheImpl(CacheHandle handle) { fs::IBufferManager::MemoryRange range = {}; if (m_cache_handle_table.Unregister(std::addressof(range.first), std::addressof(range.second), handle)) { const size_t total_allocatable_size = m_buddy_heap.GetTotalFreeSize() + m_cache_handle_table.GetTotalCacheSize(); @@ -327,6 +326,56 @@ namespace ams::fssystem { return range; } + size_t FileSystemBufferManager::GetFreeSizeImpl() const { + return m_buddy_heap.GetTotalFreeSize(); + } + + size_t FileSystemBufferManager::GetTotalAllocatableSizeImpl() const { + return this->GetFreeSizeImpl() + m_cache_handle_table.GetTotalCacheSize(); + } + + size_t FileSystemBufferManager::GetFreeSizePeakImpl() const { + return m_peak_free_size; + } + + size_t FileSystemBufferManager::GetTotalAllocatableSizePeakImpl() const { + return m_peak_total_allocatable_size; + } + + size_t FileSystemBufferManager::GetRetriedCountImpl() const { + return m_retried_count; + } + + void FileSystemBufferManager::ClearPeakImpl() { + m_peak_free_size = this->GetFreeSizeImpl(); + m_peak_total_allocatable_size = this->GetTotalAllocatableSizeImpl(); + m_retried_count = 0; + } + + const fs::IBufferManager::MemoryRange FileSystemBufferManager::DoAllocateBuffer(size_t size, const BufferAttribute &attr) { + std::scoped_lock lk(m_mutex); + + return this->AllocateBufferImpl(size, attr); + } + + void FileSystemBufferManager::DoDeallocateBuffer(uintptr_t address, size_t size) { + std::scoped_lock lk(m_mutex); + + return this->DeallocateBufferImpl(address, size); + } + + FileSystemBufferManager::CacheHandle FileSystemBufferManager::DoRegisterCache(uintptr_t address, size_t size, const BufferAttribute &attr) { + std::scoped_lock lk(m_mutex); + + return this->RegisterCacheImpl(address, size, attr); + } + + const fs::IBufferManager::MemoryRange FileSystemBufferManager::DoAcquireCache(CacheHandle handle) { + std::scoped_lock lk(m_mutex); + + return this->AcquireCacheImpl(handle); + } + size_t FileSystemBufferManager::DoGetTotalSize() const { return m_total_size; } @@ -334,28 +383,37 @@ namespace ams::fssystem { size_t FileSystemBufferManager::DoGetFreeSize() const { std::scoped_lock lk(m_mutex); - return m_buddy_heap.GetTotalFreeSize(); + return this->GetFreeSizeImpl(); } size_t FileSystemBufferManager::DoGetTotalAllocatableSize() const { - return this->GetFreeSize() + m_cache_handle_table.GetTotalCacheSize(); + std::scoped_lock lk(m_mutex); + + return this->GetTotalAllocatableSizeImpl(); } size_t FileSystemBufferManager::DoGetFreeSizePeak() const { - return m_peak_free_size; + std::scoped_lock lk(m_mutex); + + return this->GetFreeSizePeakImpl(); } size_t FileSystemBufferManager::DoGetTotalAllocatableSizePeak() const { - return m_peak_total_allocatable_size; + std::scoped_lock lk(m_mutex); + + return this->GetTotalAllocatableSizePeakImpl(); } size_t FileSystemBufferManager::DoGetRetriedCount() const { - return m_retried_count; + std::scoped_lock lk(m_mutex); + + return this->GetRetriedCountImpl(); } void FileSystemBufferManager::DoClearPeak() { - m_peak_free_size = this->GetFreeSize(); - m_retried_count = 0; + std::scoped_lock lk(m_mutex); + + return this->ClearPeakImpl(); } }