fs.mitm: Cache IStorageInterfaces, store meta on SD instead of memory.

This commit is contained in:
Michael Scire 2018-11-04 13:56:07 -08:00
parent 5d0aabaa44
commit 78a47dba6d
7 changed files with 176 additions and 39 deletions

View file

@ -14,7 +14,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <map>
#include <memory>
#include <mutex>
#include <switch.h>
#include <stratosphere.hpp>
#include "fsmitm_service.hpp"
#include "fs_shim.h"
@ -24,6 +29,37 @@
#include "debug.hpp"
static HosMutex g_StorageCacheLock;
static std::unordered_map<u64, std::weak_ptr<IStorageInterface>> g_StorageCache;
static bool StorageCacheGetEntry(u64 title_id, std::shared_ptr<IStorageInterface> *out) {
std::scoped_lock<HosMutex> lock(g_StorageCacheLock);
if (g_StorageCache.find(title_id) == g_StorageCache.end()) {
return false;
}
auto intf = g_StorageCache[title_id].lock();
if (intf != nullptr) {
*out = intf;
return true;
}
return false;
}
static void StorageCacheSetEntry(u64 title_id, std::shared_ptr<IStorageInterface> *ptr) {
std::scoped_lock<HosMutex> lock(g_StorageCacheLock);
/* Ensure we always use the cached copy if present. */
if (g_StorageCache.find(title_id) != g_StorageCache.end()) {
auto intf = g_StorageCache[title_id].lock();
if (intf != nullptr) {
*ptr = intf;
}
}
g_StorageCache[title_id] = *ptr;
}
void FsMitmService::PostProcess(IMitmServiceObject *obj, IpcResponseContext *ctx) {
auto this_ptr = static_cast<FsMitmService *>(obj);
switch ((FspSrvCmd)ctx->cmd_id) {
@ -49,16 +85,23 @@ Result FsMitmService::OpenDataStorageByCurrentProcess(Out<std::shared_ptr<IStora
u32 out_domain_id = 0;
Result rc = 0;
bool has_cache = StorageCacheGetEntry(this->title_id, &storage);
ON_SCOPE_EXIT {
if (R_SUCCEEDED(rc)) {
if (!has_cache) {
StorageCacheSetEntry(this->title_id, &storage);
}
out_storage.SetValue(std::move(storage));
if (out_storage.IsDomain()) {
out_storage.ChangeObjectId(out_domain_id);
}
}
};
if (this->romfs_storage != nullptr) {
if (has_cache) {
if (out_storage.IsDomain()) {
FsStorage s = {0};
rc = fsOpenDataStorageByCurrentProcessFwd(this->forward_service.get(), &s);
@ -68,8 +111,8 @@ Result FsMitmService::OpenDataStorageByCurrentProcess(Out<std::shared_ptr<IStora
} else {
rc = 0;
}
if (R_SUCCEEDED(rc)) {
storage = this->romfs_storage;
if (R_FAILED(rc)) {
storage.reset();
}
} else {
FsStorage data_storage;
@ -86,7 +129,6 @@ Result FsMitmService::OpenDataStorageByCurrentProcess(Out<std::shared_ptr<IStora
} else {
storage = std::make_shared<IStorageInterface>(new LayeredRomFS(std::make_shared<RomInterfaceStorage>(data_storage), nullptr, this->title_id));
}
this->romfs_storage = storage;
if (out_storage.IsDomain()) {
out_domain_id = data_storage.s.object_id;
}
@ -106,13 +148,19 @@ Result FsMitmService::OpenDataStorageByDataId(Out<std::shared_ptr<IStorageInterf
FsStorageId storage_id = (FsStorageId)sid;
FsStorage data_storage;
FsFile data_file;
std::shared_ptr<IStorageInterface> storage = nullptr;
u32 out_domain_id = 0;
Result rc = 0;
bool has_cache = StorageCacheGetEntry(data_id, &storage);
ON_SCOPE_EXIT {
if (R_SUCCEEDED(rc)) {
if (!has_cache) {
StorageCacheSetEntry(data_id, &storage);
}
out_storage.SetValue(std::move(storage));
if (out_storage.IsDomain()) {
out_storage.ChangeObjectId(out_domain_id);
@ -120,23 +168,38 @@ Result FsMitmService::OpenDataStorageByDataId(Out<std::shared_ptr<IStorageInterf
}
};
rc = fsOpenDataStorageByDataIdFwd(this->forward_service.get(), storage_id, data_id, &data_storage);
if (R_SUCCEEDED(rc)) {
if (Utils::HasSdRomfsContent(data_id)) {
/* TODO: Is there a sensible path that ends in ".romfs" we can use?" */
if (R_SUCCEEDED(Utils::OpenSdFileForAtmosphere(data_id, "romfs.bin", FS_OPEN_READ, &data_file))) {
storage = std::make_shared<IStorageInterface>(new LayeredRomFS(std::make_shared<RomInterfaceStorage>(data_storage), std::make_shared<RomFileStorage>(data_file), data_id));
} else {
storage = std::make_shared<IStorageInterface>(new LayeredRomFS(std::make_shared<RomInterfaceStorage>(data_storage), nullptr, data_id));
}
if (out_storage.IsDomain()) {
out_domain_id = data_storage.s.object_id;
if (has_cache) {
if (out_storage.IsDomain()) {
FsStorage s = {0};
rc = fsOpenDataStorageByDataIdFwd(this->forward_service.get(), storage_id, data_id, &s);
if (R_SUCCEEDED(rc)) {
out_domain_id = s.s.object_id;
}
} else {
/* If we don't have anything to modify, there's no sense in maintaining a copy of the metadata tables. */
fsStorageClose(&data_storage);
rc = RESULT_FORWARD_TO_SESSION;
rc = 0;
}
if (R_FAILED(rc)) {
storage.reset();
}
} else {
rc = fsOpenDataStorageByDataIdFwd(this->forward_service.get(), storage_id, data_id, &data_storage);
if (R_SUCCEEDED(rc)) {
if (Utils::HasSdRomfsContent(data_id)) {
/* TODO: Is there a sensible path that ends in ".romfs" we can use?" */
if (R_SUCCEEDED(Utils::OpenSdFileForAtmosphere(data_id, "romfs.bin", FS_OPEN_READ, &data_file))) {
storage = std::make_shared<IStorageInterface>(new LayeredRomFS(std::make_shared<RomInterfaceStorage>(data_storage), std::make_shared<RomFileStorage>(data_file), data_id));
} else {
storage = std::make_shared<IStorageInterface>(new LayeredRomFS(std::make_shared<RomInterfaceStorage>(data_storage), nullptr, data_id));
}
if (out_storage.IsDomain()) {
out_domain_id = data_storage.s.object_id;
}
} else {
/* If we don't have anything to modify, there's no sense in maintaining a copy of the metadata tables. */
fsStorageClose(&data_storage);
rc = RESULT_FORWARD_TO_SESSION;
}
}
}