diff --git a/stratosphere/ncm/source/impl/ncm_content_manager.cpp b/stratosphere/ncm/source/impl/ncm_content_manager.cpp index 01ec3f94e..27b5e0b7a 100644 --- a/stratosphere/ncm/source/impl/ncm_content_manager.cpp +++ b/stratosphere/ncm/source/impl/ncm_content_manager.cpp @@ -25,6 +25,7 @@ #include "../ncm_make_path.hpp" #include "../ncm_readonlycontentstorage.hpp" #include "ncm_content_manager.hpp" +#include "ncm_rights_cache.hpp" namespace sts::ncm::impl { @@ -115,6 +116,7 @@ namespace sts::ncm::impl { ContentMetaDBEntry g_content_meta_entries[MaxContentMetaDBEntries]; u32 g_num_content_storage_entries; u32 g_num_content_meta_entries; + RightsIdCache g_rights_id_cache; ContentStorageEntry* FindContentStorageEntry(StorageId storage_id) { for (size_t i = 0; i < MaxContentStorageEntries; i++) { @@ -449,7 +451,7 @@ namespace sts::ncm::impl { break; } - R_TRY(content_storage->Initialize(entry->root_path, content_path_func, placeholder_path_func, delay_flush)); + R_TRY(content_storage->Initialize(entry->root_path, content_path_func, placeholder_path_func, delay_flush, &g_rights_id_cache)); entry->content_storage = std::move(content_storage); mount_guard.Cancel(); } @@ -706,4 +708,10 @@ namespace sts::ncm::impl { return ResultSuccess; } + + Result InvalidateRightsIdCache() { + g_rights_id_cache.Invalidate(); + return ResultSuccess; + } + } diff --git a/stratosphere/ncm/source/impl/ncm_content_manager.hpp b/stratosphere/ncm/source/impl/ncm_content_manager.hpp index 7cfe4254e..3fdaf9d99 100644 --- a/stratosphere/ncm/source/impl/ncm_content_manager.hpp +++ b/stratosphere/ncm/source/impl/ncm_content_manager.hpp @@ -43,5 +43,6 @@ namespace sts::ncm::impl { Result CleanupContentMetaDatabase(StorageId storage_id); Result ActivateContentMetaDatabase(StorageId storage_id); Result InactivateContentMetaDatabase(StorageId storage_id); + Result InvalidateRightsIdCache(); } diff --git a/stratosphere/ncm/source/impl/ncm_rights_cache.cpp b/stratosphere/ncm/source/impl/ncm_rights_cache.cpp deleted file mode 100644 index 42b57da7c..000000000 --- a/stratosphere/ncm/source/impl/ncm_rights_cache.cpp +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2019 Adubbz - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "ncm_rights_cache.hpp" - -namespace sts::ncm::impl { - - namespace { - - RightsIdCache g_rights_id_cache; - - } - - RightsIdCache* GetRightsIdCache() { - return &g_rights_id_cache; - } - -} diff --git a/stratosphere/ncm/source/impl/ncm_rights_cache.hpp b/stratosphere/ncm/source/impl/ncm_rights_cache.hpp index 1f1d74332..1e17437e4 100644 --- a/stratosphere/ncm/source/impl/ncm_rights_cache.hpp +++ b/stratosphere/ncm/source/impl/ncm_rights_cache.hpp @@ -29,14 +29,23 @@ namespace sts::ncm::impl { util::Uuid uuid; FsRightsId rights_id; u64 key_generation; - u64 last_accessed = 1; + u64 last_accessed; }; Entry entries[MaxEntries]; - u64 counter = 2; + u64 counter; HosMutex mutex; + + RightsIdCache() { + this->Invalidate(); + } + + void Invalidate() { + this->counter = 2; + for (size_t i = 0; i < MaxEntries; i++) { + this->entries[i].last_accessed = 1; + } + } }; - RightsIdCache* GetRightsIdCache(); - } diff --git a/stratosphere/ncm/source/ncm_content_manager_service.cpp b/stratosphere/ncm/source/ncm_content_manager_service.cpp index 5a2d3c550..d0bcdffa6 100644 --- a/stratosphere/ncm/source/ncm_content_manager_service.cpp +++ b/stratosphere/ncm/source/ncm_content_manager_service.cpp @@ -77,4 +77,8 @@ namespace sts::ncm { return impl::InactivateContentMetaDatabase(storage_id); } + Result ContentManagerService::InvalidateRightsIdCache() { + return impl::InvalidateRightsIdCache(); + } + } diff --git a/stratosphere/ncm/source/ncm_content_manager_service.hpp b/stratosphere/ncm/source/ncm_content_manager_service.hpp index 1d2c2fe31..48ddd1c65 100644 --- a/stratosphere/ncm/source/ncm_content_manager_service.hpp +++ b/stratosphere/ncm/source/ncm_content_manager_service.hpp @@ -39,6 +39,7 @@ namespace sts::ncm { InactivateContentStorage = 10, ActivateContentMetaDatabase = 11, InactivateContentMetaDatabase = 12, + InvalidateRightsIdCache = 13, }; public: virtual Result CreateContentStorage(StorageId storage_id); @@ -54,6 +55,7 @@ namespace sts::ncm { virtual Result InactivateContentStorage(StorageId storage_id); virtual Result ActivateContentMetaDatabase(StorageId storage_id); virtual Result InactivateContentMetaDatabase(StorageId storage_id); + virtual Result InvalidateRightsIdCache(); public: DEFINE_SERVICE_DISPATCH_TABLE { MAKE_SERVICE_COMMAND_META(ContentManagerService, CreateContentStorage), @@ -69,6 +71,7 @@ namespace sts::ncm { MAKE_SERVICE_COMMAND_META(ContentManagerService, InactivateContentStorage, FirmwareVersion_200), MAKE_SERVICE_COMMAND_META(ContentManagerService, ActivateContentMetaDatabase, FirmwareVersion_200), MAKE_SERVICE_COMMAND_META(ContentManagerService, InactivateContentMetaDatabase, FirmwareVersion_200), + MAKE_SERVICE_COMMAND_META(ContentManagerService, InvalidateRightsIdCache, FirmwareVersion_900), }; }; diff --git a/stratosphere/ncm/source/ncm_contentstorage.cpp b/stratosphere/ncm/source/ncm_contentstorage.cpp index 01f177124..75e44ed4d 100644 --- a/stratosphere/ncm/source/ncm_contentstorage.cpp +++ b/stratosphere/ncm/source/ncm_contentstorage.cpp @@ -14,7 +14,6 @@ * along with this program. If not, see . */ -#include "impl/ncm_rights_cache.hpp" #include "ncm_contentstorage.hpp" #include "ncm_fs.hpp" #include "ncm_make_path.hpp" @@ -26,7 +25,7 @@ namespace sts::ncm { this->Finalize(); } - Result ContentStorageInterface::Initialize(const char* root_path, MakeContentPathFunc content_path_func, MakePlaceHolderPathFunc placeholder_path_func, bool delay_flush) { + Result ContentStorageInterface::Initialize(const char* root_path, MakeContentPathFunc content_path_func, MakePlaceHolderPathFunc placeholder_path_func, bool delay_flush, impl::RightsIdCache* rights_id_cache) { R_TRY(this->EnsureEnabled()); R_TRY(fs::CheckContentStorageDirectoriesExist(root_path)); const size_t root_path_len = strnlen(root_path, FS_MAX_PATH-1); @@ -38,6 +37,7 @@ namespace sts::ncm { strncpy(this->root_path, root_path, FS_MAX_PATH-2); this->make_content_path_func = *content_path_func; this->placeholder_accessor.Initialize(this->root_path, *placeholder_path_func, delay_flush); + this->rights_id_cache = rights_id_cache; return ResultSuccess; } @@ -428,18 +428,16 @@ namespace sts::ncm { Result ContentStorageInterface::GetRightsIdFromContentId(Out out_rights_id, Out out_key_generation, ContentId content_id) { R_TRY(this->EnsureEnabled()); - impl::RightsIdCache* rights_id_cache = impl::GetRightsIdCache(); - { - std::scoped_lock lk(rights_id_cache->mutex); + std::scoped_lock lk(this->rights_id_cache->mutex); /* Attempt to locate the content id in the cache. */ for (size_t i = 0; i < impl::RightsIdCache::MaxEntries; i++) { - impl::RightsIdCache::Entry* entry = &rights_id_cache->entries[i]; + impl::RightsIdCache::Entry* entry = &this->rights_id_cache->entries[i]; if (entry->last_accessed != 1 && content_id == entry->uuid) { - entry->last_accessed = rights_id_cache->counter; - rights_id_cache->counter++; + entry->last_accessed = this->rights_id_cache->counter; + this->rights_id_cache->counter++; out_rights_id.SetValue(entry->rights_id); out_key_generation.SetValue(entry->key_generation); return ResultSuccess; @@ -456,12 +454,12 @@ namespace sts::ncm { R_TRY(fsGetRightsIdAndKeyGenerationByPath(common_path, &key_generation, &rights_id)); { - std::scoped_lock lk(rights_id_cache->mutex); - impl::RightsIdCache::Entry* eviction_candidate = &rights_id_cache->entries[0]; + std::scoped_lock lk(this->rights_id_cache->mutex); + impl::RightsIdCache::Entry* eviction_candidate = &this->rights_id_cache->entries[0]; /* Find a suitable existing entry to store our new one at. */ for (size_t i = 1; i < impl::RightsIdCache::MaxEntries; i++) { - impl::RightsIdCache::Entry* entry = &rights_id_cache->entries[i]; + impl::RightsIdCache::Entry* entry = &this->rights_id_cache->entries[i]; /* Change eviction candidates if the uuid already matches ours, or if the uuid doesn't already match and the last_accessed count is lower */ if (content_id == entry->uuid || (content_id != eviction_candidate->uuid && entry->last_accessed < eviction_candidate->last_accessed)) { @@ -473,8 +471,8 @@ namespace sts::ncm { eviction_candidate->uuid = content_id.uuid; eviction_candidate->rights_id = rights_id; eviction_candidate->key_generation = key_generation; - eviction_candidate->last_accessed = rights_id_cache->counter; - rights_id_cache->counter++; + eviction_candidate->last_accessed = this->rights_id_cache->counter; + this->rights_id_cache->counter++; /* Set output. */ out_rights_id.SetValue(rights_id); @@ -599,18 +597,16 @@ namespace sts::ncm { Result ContentStorageInterface::GetRightsIdFromPlaceHolderIdWithCache(Out out_rights_id, Out out_key_generation, PlaceHolderId placeholder_id, ContentId cache_content_id) { R_TRY(this->EnsureEnabled()); - impl::RightsIdCache* rights_id_cache = impl::GetRightsIdCache(); - { - std::scoped_lock lk(rights_id_cache->mutex); + std::scoped_lock lk(this->rights_id_cache->mutex); /* Attempt to locate the content id in the cache. */ for (size_t i = 0; i < impl::RightsIdCache::MaxEntries; i++) { - impl::RightsIdCache::Entry* entry = &rights_id_cache->entries[i]; + impl::RightsIdCache::Entry* entry = &this->rights_id_cache->entries[i]; if (entry->last_accessed != 1 && cache_content_id == entry->uuid) { - entry->last_accessed = rights_id_cache->counter; - rights_id_cache->counter++; + entry->last_accessed = this->rights_id_cache->counter; + this->rights_id_cache->counter++; out_rights_id.SetValue(entry->rights_id); out_key_generation.SetValue(entry->key_generation); return ResultSuccess; @@ -627,12 +623,12 @@ namespace sts::ncm { R_TRY(fsGetRightsIdAndKeyGenerationByPath(common_path, &key_generation, &rights_id)); { - std::scoped_lock lk(rights_id_cache->mutex); - impl::RightsIdCache::Entry* eviction_candidate = &rights_id_cache->entries[0]; + std::scoped_lock lk(this->rights_id_cache->mutex); + impl::RightsIdCache::Entry* eviction_candidate = &this->rights_id_cache->entries[0]; /* Find a suitable existing entry to store our new one at. */ for (size_t i = 1; i < impl::RightsIdCache::MaxEntries; i++) { - impl::RightsIdCache::Entry* entry = &rights_id_cache->entries[i]; + impl::RightsIdCache::Entry* entry = &this->rights_id_cache->entries[i]; /* Change eviction candidates if the uuid already matches ours, or if the uuid doesn't already match and the last_accessed count is lower */ if (cache_content_id == entry->uuid || (cache_content_id != eviction_candidate->uuid && entry->last_accessed < eviction_candidate->last_accessed)) { @@ -644,8 +640,8 @@ namespace sts::ncm { eviction_candidate->uuid = cache_content_id.uuid; eviction_candidate->rights_id = rights_id; eviction_candidate->key_generation = key_generation; - eviction_candidate->last_accessed = rights_id_cache->counter; - rights_id_cache->counter++; + eviction_candidate->last_accessed = this->rights_id_cache->counter; + this->rights_id_cache->counter++; /* Set output. */ out_rights_id.SetValue(rights_id); diff --git a/stratosphere/ncm/source/ncm_contentstorage.hpp b/stratosphere/ncm/source/ncm_contentstorage.hpp index 7f9f8b7de..bd0939187 100644 --- a/stratosphere/ncm/source/ncm_contentstorage.hpp +++ b/stratosphere/ncm/source/ncm_contentstorage.hpp @@ -19,6 +19,7 @@ #include #include "impl/ncm_placeholder_accessor.hpp" +#include "impl/ncm_rights_cache.hpp" #include "ncm_icontentstorage.hpp" #include "ncm_path_utils.hpp" @@ -29,10 +30,11 @@ namespace sts::ncm { impl::PlaceHolderAccessor placeholder_accessor; ContentId cached_content_id; FILE* content_cache_file_handle; + impl::RightsIdCache* rights_id_cache; public: ~ContentStorageInterface(); - Result Initialize(const char* root_path, MakeContentPathFunc content_path_func, MakePlaceHolderPathFunc placeholder_path_func, bool delay_flush); + Result Initialize(const char* root_path, MakeContentPathFunc content_path_func, MakePlaceHolderPathFunc placeholder_path_func, bool delay_flush, impl::RightsIdCache* rights_id_cache); void Finalize(); private: void ClearContentCache();