Skip to content

Cannot use fs.mitm on overlayDisp #1972

Description

@Ereza

Bug Report

What's the issue you encountered?

When an attempt is made to use fs.mitm on overlayDisp (title id 010000000000100C), the system hangs at startup.

I use fs.mitm to provide a Catalan language translation to the Switch interface (https://github.com/Ereza/switch-cat). This is done by replacing some .szs files on each system title via fs.mitm. I was using firmware 13.0.0 and Atmosphère 1.1.1 until now, but now I upgraded to firmware 15.0.0 and Atmosphère 1.4.0.

When on firmware 13.0.0 and Atmosphère 1.1.1 it was possible to use fs.mitm on overlayDisp with no problems. However, under the current versions, adding any file to atmosphere/contents/010000000000100C/romfs/ completely hangs the system at startup. Just a guess, but could this be related to the optimizations made to fs.mitm in 1.2.4?

How can the issue be reproduced?

  • Create the directory atmosphere/contents/010000000000100C/romfs/ on your SD card, and place an empty dummy.txt file inside the directory.
  • Power on the console.
  • The system hangs on a black screen after the Nintendo Switch logo.

If you place no files inside the atmosphere/contents/010000000000100C/romfs/ directory, the console boots just fine.

Crash Report

N/A

System Firmware Version

15.0.0

Environment?

  • What bootloader (fusèe, hekate, etc) was Atmosphère launched by: fusee
  • Official release or unofficial build:
    • Official, 1.4.0
  • Do you have additional kips or sysmodules you're loading: No.
  • Homebrew software installed: Just Daybreak, Goldleaf and nxdumptool.
  • EmuMMC or SysNAND: SysNAND.

Additional context?

  • Additional info about your environment:
    • Switch console from 2017 (first model).
    • nogc = 0.

Activity

  1. SciresM commented on Oct 20, 2022

    @SciresM
    Collaborator

    You report the issue doesn't occur on 1.1.1/13.0.0, and that it does occur on 1.4.0/15.0.0.

    Does it occur on 1.4.0/13.0.0?

  2. Ereza commented on Oct 20, 2022

    @Ereza
    Author

    Unfortunately I did not try it on 1.4.0/13.0.0, I updated the firmware and Atmosphère at the same time...

  3. SciresM commented on Oct 20, 2022

    @SciresM
    Collaborator

    Could you make an emummc, downgrade it to 13.0.0, and test it? If not, it is not the end of the world, but it may take me longer to test and reproduce locally.

  4. Ereza commented on Oct 20, 2022

    @Ereza
    Author

    Hmm, I have never done anything with emuMMC and never downgraded either, so I don't feel very confident on doing that. I'm sorry...

  5. SciresM commented on Oct 20, 2022

    @SciresM
    Collaborator

    No worries, I will investigate myself.

  6. Ereza commented on Oct 20, 2022

    @Ereza
    Author

    Oh, I didn't mention that, but just in case: other system titles work as expected when using fs.mitm on them. It seems to happen only with overlayDisp.

    Also, possible related issue with what could be the same problem: #1698.

  7. JarleSoelie commented on Oct 31, 2022

    @JarleSoelie

    Hi,
    I believe I'm getting the same error message after updating atomsphere, hekate, and then the firmware to 15.0. Everything was working great before, and I have also updated everything several times before without any problems. I never installed any themes, and I don't have the 010000000000100C folder in my atmosphere/contents folder.

    I am using emummc, (that I have left be on the sd card since I really don't want to delete 350 gb of data), but I tried to delete absolutely everything else regarding atmosphere and hekate and do as fresh of an install as possible, but I still get the exact same error message no matter what I do... I have attached the fatal error log below. Is there something inside the emummc that can cause this? Is there anything that can be done you think, or is perhaps the SD card itself on the fritz?
    01640995215_010000000000100c.log

  8. JarleSoelie commented on Nov 1, 2022

    @JarleSoelie

    Hi, I believe I'm getting the same error message after updating atomsphere, hekate, and then the firmware to 15.0. Everything was working great before, and I have also updated everything several times before without any problems. I never installed any themes, and I don't have the 010000000000100C folder in my atmosphere/contents folder.

    I am using emummc, (that I have left be on the sd card since I really don't want to delete 350 gb of data), but I tried to delete absolutely everything else regarding atmosphere and hekate and do as fresh of an install as possible, but I still get the exact same error message no matter what I do... I have attached the fatal error log below. Is there something inside the emummc that can cause this? Is there anything that can be done you think, or is perhaps the SD card itself on the fritz? 01640995215_010000000000100c.log

    Wait! I fixed it, but I'm not entirely sure how. I made sure no overlays were active, I reinstalled atmosphere and hekate (making sure I extracted them from their archives before copying the files to the SD card). Then I used the latest TegraRCMgui instead of my phone to load the hekate payload. And suddenly I was in! I apologize for posting this here, I was at my wits end last night trying to figure this error out. Thanks for everything

  9. changed the title [-]Cannot use fs.midm on overlayDisp[/-] [+]Cannot use fs.mitm on overlayDisp[/+] on Dec 29, 2022
  10. Ereza commented on May 10, 2023

    @Ereza
    Author

    I just wanted to confirm that this still happens in Atmosphère 1.5.3 with firmware 16.0.3. Creating any file inside the romfs directory for title id 010000000000100C hangs the system on startup.

  11. sodasoba1 commented on Jun 19, 2023

    @sodasoba1

    Just to note I tried a similar mitm but patching a szs the switch black screens but Tesla will still work.

  12. SciresM commented on Apr 3, 2025

    @SciresM
    Collaborator

    Not closing this issue of the various overlayDisp redirection stuff, but noting that I have no idea how to fix this or why the problem occurs.

  13. Ereza commented on Aug 4, 2025

    @Ereza
    Author

    I am planning to release an updated Switch OS translation and this issue was making me unhappy because I could not apply the translation to overlayDisp, but I finally had some time to debug it and I think I found what was causing this issue and a possible solution. However, be aware that I am not a C++ developer and therefore, my changes could cause other issues.

    I started by reverting the fs.mitm implementation to that of Atmosphère 1.2.3 (reverting commit 47218f0 and fixing some minor things to make it work with the 1.9.3 codebase). And... fs.mitm on overlayDisp worked again! So it had to be some kind of issue with the changes made in that commit. I suspected some kind of problem with the reference counting or some kind of deadlock between threads.

    After adding quite a bit of logging, I found out that there appears to be a deadlock if both qlaunch and overlayDisp are using fs.mitm. I tried using fs.mitm only for overlayDisp but not for qlaunch... and it worked in the official 1.9.3!

    Here is a rough explanation of the deadlock:

    Thread A (2nd GetLayeredRomfsStorage call, called for overlayDisp):

    1. Acquires a lock for g_storage_set_mutex.
    2. Then executes BeginInitialize, which calls RequestInitializeStorage.
    3. RequestInitializeStorage calls g_req_mq.Send(...), then waits g_ack_mq.Receive(...)... and the thread becomes blocked there.

    Thread B (1st RomfsInitializerThreadFunction call, called for qlaunch):

    1. Receives a message with g_req_mq.Receive(...) and sends an ACK with g_ack_mq.Send(...).
    2. Ends up calling CloseReference, with acquires a lock for g_storage_set_mutex... and the thread becomes blocked there.

    The solution appears to be to move the g_storage_set_mutex lock to a scope block, instead of locking it for the entire GetLayeredRomfsStorage function. This means that the lock is released before calling BeginInitialize.

    These are my changes:

        std::shared_ptr<ams::fs::IStorage> GetLayeredRomfsStorage(ncm::ProgramId program_id, ::FsStorage &data_storage, bool is_process_romfs) {
    
            LayeredRomfsStorageImpl *impl;
    
            //<--- This is the original code, but put inside a scope block:
            {
                std::scoped_lock lk(g_storage_set_mutex);
    
                /* Find an existing storage. */
                if (auto it = g_storage_set.find_key(program_id.value); it != g_storage_set.end()) {
                    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. */
                /* This should help prevent too much memory in use at any time. */
                if (is_process_romfs) {
                    auto it = g_storage_set.begin();
                    while (it != g_storage_set.end()) {
                        if (it->GetReferenceCount() > 0 || !it->IsProcessRomfs()) {
                            ++it;
                        } else {
                            auto *holder = std::addressof(*it);
                            it = g_storage_set.erase(it);
                            delete holder;
                        }
                    }
                }
    
                /* Create a new storage. */
                {
                    ::FsFile data_file;
                    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);
                    } else {
                    impl = new LayeredRomfsStorageImpl(std::make_unique<ReadOnlyStorageAdapter>(new RemoteStorage(data_storage)), nullptr, program_id);
                    }
                }
    
                /* Insert holder. Reference count will now be one. */
                g_storage_set.insert(*(new LayeredRomfsStorageHolder(impl, is_process_romfs)));
            }
            //<--- The scope block ends here, so the g_storage_set_mutex lock is released here
    
            /* Begin initialization. When this finishes, a decref will occur. */
            impl->BeginInitialize();
    
            /* Return a new shared storage for the impl. */
            return std::make_shared<LayeredRomfsStorage>(impl);
        }

    Since I am not that familiar with C++ and locks (not to say with the Atmosphère codebase), maybe this code is wrong or introduces new concurrency issues, but this change appears to fix the problem in my case, and I can now happily use fs.mitm for both qlaunch and overlayDisp!

    Regardless, the cause of the problem appears to be the changes made in commit 47218f0, so if my solution is not valid, you can hopefully look at it now that we identified the cause.

    Let me know if you need any more info. Thanks for not closing this issue and for all your time developing Atmosphère! I hope you can include a fix for this issue in a future release!

  14. SciresM commented on Aug 29, 2025

    @SciresM
    Collaborator

    @Ereza sorry I missed this. Thank you for your work and your diagnosis!

    By any chance are you available for discussion on discord about getting this solved upstream?

  15. added a commit that references this issue on Sep 3, 2025
    98bc030
  16. added a commit that references this issue on Sep 12, 2025
    8ab0ac2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions