ams.mitm: fix deadlock when building multiple romfs simultaneously (closes #1972)

This commit is contained in:
Michael Scire 2025-09-02 18:35:42 -07:00
parent 081e76a2b5
commit 98bc030b37

View File

@ -215,43 +215,47 @@ namespace ams::mitm::fs {
using namespace ams::fs; using namespace ams::fs;
std::shared_ptr<ams::fs::IStorage> GetLayeredRomfsStorage(ncm::ProgramId program_id, ::FsStorage &data_storage, bool is_process_romfs) { std::shared_ptr<ams::fs::IStorage> GetLayeredRomfsStorage(ncm::ProgramId program_id, ::FsStorage &data_storage, bool is_process_romfs) {
std::scoped_lock lk(g_storage_set_mutex); /*Prepare to find or create a new storage. */
LayeredRomfsStorageImpl *impl = nullptr;
{
std::scoped_lock lk(g_storage_set_mutex);
/* Find an existing storage. */ /* Find an existing storage. */
if (auto it = g_storage_set.find_key(program_id.value); it != g_storage_set.end()) { if (auto it = g_storage_set.find_key(program_id.value); it != g_storage_set.end()) {
return std::make_shared<LayeredRomfsStorage>(it->GetImpl()); return std::make_shared<LayeredRomfsStorage>(it->GetImpl());
} }
/* We don't have an existing storage. If we're creating process romfs, free any unreferenced process romfs. */ /* We don't have an existing storage. If we're creating process romfs, free any unreferenced process romfs. */
/* This should help prevent too much memory in use at any time. */ /* This should help prevent too much memory in use at any time. */
if (is_process_romfs) { if (is_process_romfs) {
auto it = g_storage_set.begin(); auto it = g_storage_set.begin();
while (it != g_storage_set.end()) { while (it != g_storage_set.end()) {
if (it->GetReferenceCount() > 0 || !it->IsProcessRomfs()) { if (it->GetReferenceCount() > 0 || !it->IsProcessRomfs()) {
++it; ++it;
} else { } else {
auto *holder = std::addressof(*it); auto *holder = std::addressof(*it);
it = g_storage_set.erase(it); it = g_storage_set.erase(it);
delete holder; delete holder;
}
} }
} }
}
/* Create a new storage. */ /* Create a new storage. */
LayeredRomfsStorageImpl *impl; {
{ ::FsFile data_file;
::FsFile data_file; if (R_SUCCEEDED(OpenAtmosphereSdFile(std::addressof(data_file), program_id, "romfs.bin", OpenMode_Read))) {
if (R_SUCCEEDED(OpenAtmosphereSdFile(std::addressof(data_file), program_id, "romfs.bin", OpenMode_Read))) { impl = new LayeredRomfsStorageImpl(std::make_unique<ReadOnlyStorageAdapter>(new RemoteStorage(data_storage)), std::make_unique<ReadOnlyStorageAdapter>(new FileStorage(new RemoteFile(data_file))), program_id);
impl = new LayeredRomfsStorageImpl(std::make_unique<ReadOnlyStorageAdapter>(new RemoteStorage(data_storage)), std::make_unique<ReadOnlyStorageAdapter>(new FileStorage(new RemoteFile(data_file))), program_id); } else {
} else { impl = new LayeredRomfsStorageImpl(std::make_unique<ReadOnlyStorageAdapter>(new RemoteStorage(data_storage)), nullptr, program_id);
impl = new LayeredRomfsStorageImpl(std::make_unique<ReadOnlyStorageAdapter>(new RemoteStorage(data_storage)), nullptr, program_id); }
} }
}
/* Insert holder. Reference count will now be one. */ /* Insert holder. Reference count will now be one. */
g_storage_set.insert(*(new LayeredRomfsStorageHolder(impl, is_process_romfs))); g_storage_set.insert(*(new LayeredRomfsStorageHolder(impl, is_process_romfs)));
}
/* Begin initialization. When this finishes, a decref will occur. */ /* Begin initialization. When this finishes, a decref will occur. */
AMS_ABORT_UNLESS(impl != nullptr);
impl->BeginInitialize(); impl->BeginInitialize();
/* Return a new shared storage for the impl. */ /* Return a new shared storage for the impl. */