fix: eliminate desktop stall when deleting large files
Deleting a big file froze the desktop for seconds: ext2 FreeBlock did 4 synchronous disk I/Os per data block (bitmap + BGDT read/write), and the file manager deleted single files inline on the desktop main thread. - Ext2: batch block frees per block group; keep the bitmap resident, clear bits in memory, flush bitmap + BGDT once per group transition. Also covers the truncate-on-overwrite path. - Ext2: refuse to mount volumes with block size > 4096; temp buffers throughout the driver are single 4 KiB pages, so larger blocks would overflow them (our mkfs always uses 4K). - Files: route single-file deletes past 4 MiB to the background worker + progress dialog; refuse (instead of stalling inline) when another file operation already owns the worker. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -154,10 +154,33 @@ void filemanager_delete_selected(FileManagerState* fm) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Single plain file: delete immediately.
|
||||
// Single plain file. Freeing a large file's blocks is a slow syscall
|
||||
// (the fs driver rewrites allocation bitmaps per block), so deleting it
|
||||
// inline would stall the desktop -- Files runs inside desktop.elf, so a
|
||||
// blocked main thread freezes the compositor and cursor. Hand anything
|
||||
// past the inline threshold to the background worker + progress dialog;
|
||||
// small files still delete inline so there's no dialog flash.
|
||||
int only = filtered[0];
|
||||
char fullpath[512];
|
||||
filemanager_build_fullpath(fullpath, 512,
|
||||
fm->current_path, fm->entry_names[filtered[0]]);
|
||||
fm->current_path, fm->entry_names[only]);
|
||||
|
||||
if (fm->entry_sizes[only] > FILEMANAGER_DELETE_INLINE_MAX_BYTES) {
|
||||
const char* one = fullpath;
|
||||
if (filemanager_start_delete_job(fm, &one, 1)) {
|
||||
montauk::mfree(filtered);
|
||||
return;
|
||||
}
|
||||
if (fm->active_fileop) {
|
||||
// Another operation owns the worker. Deleting a big file inline
|
||||
// here would stall the desktop (the exact bug this path avoids),
|
||||
// so refuse; its progress dialog tells the user we're busy.
|
||||
montauk::mfree(filtered);
|
||||
return;
|
||||
}
|
||||
// Job allocation failed (OOM): fall through to the inline delete.
|
||||
}
|
||||
|
||||
montauk::mfree(filtered);
|
||||
montauk::fdelete(fullpath);
|
||||
filemanager_clear_multi_selection(fm);
|
||||
|
||||
@@ -54,6 +54,12 @@ struct FileManagerVirtualEntry {
|
||||
// misbehaving driver and bounds memory. Far above any realistic directory.
|
||||
inline constexpr int FM_ENTRY_HARD_CAP = 8192;
|
||||
|
||||
// Single-file deletes at or below this size are freed inline; larger files go
|
||||
// to the background worker + progress dialog. Freeing a big file rewrites the
|
||||
// filesystem allocation bitmaps and can take seconds on real disks, which would
|
||||
// otherwise stall the desktop (Files runs inside desktop.elf).
|
||||
inline constexpr uint64_t FILEMANAGER_DELETE_INLINE_MAX_BYTES = 4ull * 1024 * 1024;
|
||||
|
||||
struct FileManagerState {
|
||||
char current_path[256];
|
||||
FileManagerLocation history[16];
|
||||
|
||||
Reference in New Issue
Block a user