Skip to content

fix(savedata): leave the mount result untouched when sceSaveDataMount3 fails - #4876

Merged
oneandonlydean merged 2 commits into
boykopovar:mainfrom
EagleBearerYS:fix/savedata-failed-mount-keeps-result
Oct 14, 2026
Merged

oneandonlydean merged 2 commits into
boykopovar:mainfrom
EagleBearerYS:fix/savedata-failed-mount-keeps-result

Conversation

@EagleBearerYS

@EagleBearerYS EagleBearerYS commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

What

Animal Well (PPSA22520, content 01.000.011) saves its progress outside its save directory, and a save placed in the save directory is never loaded. sceSaveDataMount3 cleared the caller's result before its checks, and the title depends on the result surviving a failed mount:

  • Its "save exists" check mounts SAVEDATA (CREATE2), stats <mount point>/save and never unmounts.
  • The load and save routines then mount SAVEDATA again into the same global result. They ignore every error except NO_SPACE (0x809F000A) and use the result's mount point for sceSaveDataPrepare, open("<mount point>/save", O_RDWR | O_CREAT ...) and the final sceSaveDataUmount2.
  • On main, that second mount returns BUSY with the mount point cleared. The title then opens /save (the game folder) and calls sceSaveDataUmount2 with an empty mount point (NOT_MOUNTED), so the first mount is never released:
[SAVEDATA:native] mount3 user=268435456 dir=SAVEDATA mode=0x20 blocks=48 -> 0x00000000 point=/savedata0 status=0
[SAVEDATA:native] mount3 user=268435456 dir=SAVEDATA mode=0x20 blocks=48 -> 0x809f0003 point= status=0
[SAVEDATA:native] umount2 mode=0x0 point= -> 0x809f0004

The result is now cleared and written only when the mount succeeds, as shadPS4's saveDataMount does (it returns BUSY for an already mounted directory before writing mount_result). Every error return (BUSY, EXISTS, NOT_FOUND, MOUNT_FULL) leaves it as it was. The title ships with this save flow and saves on the console, so the console's sceSaveDataMount3 evidently leaves the mount point in place on BUSY as well. A technical debt entry records that this follows shadPS4 and the title, not a hardware run.

Tested

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Unblocks: PPSA22520 Animal Well (PPSA22520) #966
  • AI-assisted: yes

…3 fails

Animal Well (PPSA22520) checks for its save with a CREATE2 mount it never
unmounts, then saves with a second mount of the same directory. That
mount returns BUSY, and the title keeps using the first mount point for
sceSaveDataPrepare, its save file and sceSaveDataUmount2.
sceSaveDataMount3 cleared the result before its checks, so the save was
written to "/save" in the game folder instead of the save directory, and
the first mount was never released. The result is now written only when
the mount succeeds, as shadPS4 does.
@xXPBSXx

xXPBSXx commented Oct 13, 2026

Copy link
Copy Markdown
Contributor

Windows test: head 4ccf88829 merged onto current main 5d50886ee, together with 9 other open pull requests in one build (the merges were conflict-free); a failure would have been bisected per PR. Windows 10, MinGW GCC (WinLibs), Ninja Release, -j2: full build 0 errors; ctest for the tests this change adds or touches: guest_savedata_mount_status passed; python tools/check_conventions.py --base upstream/main passed for the combined tree. I did not run the new tests against main without the change.

AI-assisted (Claude Code).

boykopovar#5173 changes the create condition right after the last error check, and boykopovar#3950 removes the comment after the create block, so clearing the result in either place made the pull requests conflict. The result is still cleared only after every error return and before anything is written to it.
@oneandonlydean
oneandonlydean merged commit 8a43794 into boykopovar:main Oct 14, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants