From 4e9afa7885b07b6281e2ed7ee821f2511bde7743 Mon Sep 17 00:00:00 2001 From: Roman Tarasov Date: Sat, 4 Apr 2026 21:27:10 +0300 Subject: [PATCH] Fast shutdown --- src/main.c | 11 ++++++++++- src/sm_filesystem.c | 4 ++++ src/sm_image.c | 6 ++++++ src/sm_install.c | 9 +++++++++ src/sm_scan.c | 6 ++++++ src/sm_scanner.c | 30 +++++++++++++++++++++++++++++- 6 files changed, 64 insertions(+), 2 deletions(-) diff --git a/src/main.c b/src/main.c index 9a141c7..1446194 100644 --- a/src/main.c +++ b/src/main.c @@ -375,10 +375,19 @@ int main(void) { goto shutdown; } + log_debug("[STARTUP] post-LVD cleanup begin"); + log_debug("[STARTUP] cleanup_staged_mount_links begin"); cleanup_staged_mount_links(); + log_debug("[STARTUP] cleanup_staged_mount_links done"); + log_debug("[STARTUP] cleanup_duplicate_title_mounts begin"); cleanup_duplicate_title_mounts(); - if (!sm_scanner_run_startup_sync()) + log_debug("[STARTUP] cleanup_duplicate_title_mounts done"); + log_debug("[STARTUP] scanner startup sync begin"); + if (!sm_scanner_run_startup_sync()) { + log_debug("[STARTUP] scanner startup sync aborted"); goto shutdown; + } + log_debug("[STARTUP] scanner startup sync done"); sm_scanner_run_loop(); shutdown: diff --git a/src/sm_filesystem.c b/src/sm_filesystem.c index 21621de..61c2453 100644 --- a/src/sm_filesystem.c +++ b/src/sm_filesystem.c @@ -646,6 +646,8 @@ static int copy_param_json_rewrite(const char *src, const char *dst) { if (ret == 0 && hit) log_debug(" [COPY] param.json patched: %s", dst); + if (ret != 0) + (void)unlink(dst); free(buf); return ret; @@ -684,6 +686,8 @@ int copy_file(const char *src, const char *dst) { ret = -1; if (fclose(fs) != 0) ret = -1; + if (ret != 0) + (void)unlink(dst); return ret; } diff --git a/src/sm_image.c b/src/sm_image.c index 731f3f6..1d80aea 100644 --- a/src/sm_image.c +++ b/src/sm_image.c @@ -889,6 +889,7 @@ void cleanup_stale_image_mounts(void) { if (should_stop_requested()) return; + log_debug(" [IMG] stale image cleanup begin"); for (int k = 0; k < MAX_IMAGE_MOUNTS; k++) { image_cache_entry_t cached_entry; if (should_stop_requested()) @@ -896,6 +897,10 @@ void cleanup_stale_image_mounts(void) { if (!get_image_cache_entry(k, &cached_entry)) continue; + log_debug(" [IMG][%s] stale cleanup check: slot=%d source=%s mount=%s", + attach_backend_name(cached_entry.backend), k, cached_entry.path, + cached_entry.mount_point); + if (!path_exists(cached_entry.path)) { log_debug(" [IMG][%s] Source removed, unmounting: %s", attach_backend_name(cached_entry.backend), cached_entry.path); @@ -922,6 +927,7 @@ void cleanup_stale_image_mounts(void) { notify_image_mount_failed(source_path, mount_err); } } + log_debug(" [IMG] stale image cleanup done"); } void cleanup_stale_image_mounts_for_root(const char *root) { diff --git a/src/sm_install.c b/src/sm_install.c index d624801..42ab579 100644 --- a/src/sm_install.c +++ b/src/sm_install.c @@ -120,6 +120,9 @@ static bool mount_and_install(const char *src_path, const char *title_id, restage_staging = (!is_remount || should_register); restage_appmeta = (!is_remount || appmeta_missing); + if (should_stop_requested()) + return false; + // COPY FILES if (restage_staging || restage_appmeta) { snprintf(src_sce_sys, sizeof(src_sce_sys), "%s/sce_sys", src_path); @@ -162,6 +165,9 @@ static bool mount_and_install(const char *src_path, const char *title_id, metadata_restaged = true; } + if (should_stop_requested()) + return false; + if (!mount_title_nullfs(title_id, src_path)) { log_debug(" [LINK] nullfs mount failed: title=%s src=%s", title_id, src_path); @@ -265,6 +271,9 @@ void process_scan_candidates(const scan_candidate_t *candidates, clear_failed_mount_attempts(c->title_id); cache_game_entry(c->path, c->title_id, c->title_name); } else { + if (should_stop_requested()) + return; + uint8_t failed_attempts = bump_failed_mount_attempts(c->title_id); if (failed_attempts == MAX_FAILED_MOUNT_ATTEMPTS) { log_debug(" [RETRY] limit reached (%u/%u): %s (%s)", diff --git a/src/sm_scan.c b/src/sm_scan.c index 85a0c4a..aca71be 100644 --- a/src/sm_scan.c +++ b/src/sm_scan.c @@ -434,14 +434,20 @@ void mount_backport_overlays_for_scan_root(const char *scan_root, // --- Unified Scan Pass (images + game candidates) --- void cleanup_lost_sources_before_scan(void) { + log_debug(" [SCAN] pre-scan cleanup begin"); // 1) Drop stale game cache entries for deleted sources. + log_debug(" [SCAN] pre-scan cleanup: prune_game_cache"); prune_game_cache(); // 2) Drop stale/broken mount links and unmount stale /system_ex stacks. + log_debug(" [SCAN] pre-scan cleanup: cleanup_mount_links"); cleanup_mount_links(NULL, true); // 3) Unmount stale image mounts for deleted image files. + log_debug(" [SCAN] pre-scan cleanup: cleanup_stale_image_mounts"); cleanup_stale_image_mounts(); // 4) Drop stale path-state entries. + log_debug(" [SCAN] pre-scan cleanup: prune_path_state"); prune_path_state(); + log_debug(" [SCAN] pre-scan cleanup done"); } void cleanup_lost_sources_for_scan_root(const char *scan_root) { diff --git a/src/sm_scanner.c b/src/sm_scanner.c index 335cc76..7a508cc 100644 --- a/src/sm_scanner.c +++ b/src/sm_scanner.c @@ -781,20 +781,32 @@ static void apply_runtime_config_reload_effects(const runtime_config_t *old_cfg, } } +static bool should_abort_scan_cycle(void) { + return should_stop_requested(); +} + static bool run_full_scan_cycle(bool startup_sync, const char *reason, bool *unstable_found_out) { scan_candidate_t *candidates = g_scanner_scan_candidates; log_immediate_scan_reason(reason); + if (should_abort_scan_cycle()) + return false; + bool unstable_found = false; cleanup_lost_sources_before_scan(); + if (should_abort_scan_cycle()) + return false; int total_found_games = 0; int *total_found_ptr = startup_sync ? &total_found_games : NULL; int candidate_count = collect_scan_candidates(candidates, MAX_PENDING, total_found_ptr, &unstable_found); + if (should_abort_scan_cycle()) + return false; + if (candidate_count > 0) { if (startup_sync) { int new_games = 0; @@ -807,14 +819,18 @@ static bool run_full_scan_cycle(bool startup_sync, const char *reason, } process_scan_candidates(candidates, candidate_count); + if (should_abort_scan_cycle()) + return false; } mount_backport_overlays(&unstable_found); + if (should_abort_scan_cycle()) + return false; if (unstable_found_out) *unstable_found_out = unstable_found; - if (startup_sync) { + if (startup_sync && !should_abort_scan_cycle()) { notify_system_rich(true, "Library Synchronized.\nFound %d games.", total_found_games); } @@ -829,15 +845,27 @@ static bool run_targeted_scan_cycle(int scan_root_index, log_debug("[SCAN] running targeted scan for %s", scan_root); + if (should_abort_scan_cycle()) + return false; + bool unstable_found = false; cleanup_lost_sources_for_scan_root(scan_root); + if (should_abort_scan_cycle()) + return false; int candidate_count = collect_scan_candidates_for_scan_root( scan_root, candidates, MAX_PENDING, NULL, &unstable_found); + if (should_abort_scan_cycle()) + return false; + if (candidate_count > 0) process_scan_candidates(candidates, candidate_count); + if (should_abort_scan_cycle()) + return false; mount_backport_overlays_for_scan_root(scan_root, &unstable_found); + if (should_abort_scan_cycle()) + return false; if (unstable_found_out) *unstable_found_out = unstable_found;