Created
January 1, 2025 15:58
-
-
Save joanbm/159759c075b04a679593ee5473456da0 to your computer and use it in GitHub Desktop.
Shows that on an unclean shutdown of ext4 (default settings, kernel 6.12.7), files may get a suffix of NUL bytes - see https://github.com/fish-shell/fish-shell/issues/10300
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <fcntl.h> | |
#include <unistd.h> | |
#include <string.h> | |
#include <sys/syscall.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <errno.h> | |
#include <linux/reboot.h> | |
#define NUM_FILES 200000 | |
#define BUFFER_SIZE 100 | |
void quit_on_error(const char *message) { | |
perror(message); | |
exit(EXIT_FAILURE); | |
} | |
void create_file_with_content(const char *filename, char c, size_t size) { | |
int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644); | |
if (fd < 0) quit_on_error("Failed to create file"); | |
char buffer[BUFFER_SIZE]; | |
memset(buffer, c, BUFFER_SIZE); | |
size_t remaining = size; | |
while (remaining > 0) { | |
size_t to_write = remaining > BUFFER_SIZE ? BUFFER_SIZE : remaining; | |
if (write(fd, buffer, to_write) != to_write) quit_on_error("Failed to write to file"); | |
remaining -= to_write; | |
} | |
close(fd); | |
} | |
int main() { | |
char filename[64]; | |
for (int i = 0; i < NUM_FILES; i++) { | |
snprintf(filename, sizeof(filename), "file_%06d", i); | |
create_file_with_content(filename, 'A', 5000); | |
} | |
int fd = open(".", O_RDONLY); | |
if (fd < 0) quit_on_error("Failed to open directory for sync"); | |
if (syscall(SYS_syncfs, fd) < 0) quit_on_error("Failed to sync filesystem"); | |
close(fd); | |
for (int i = 0; i < NUM_FILES; i++) { | |
snprintf(filename, sizeof(filename), "file_%06d", i); | |
int fd = open(filename, O_WRONLY | O_APPEND, 0644); | |
if (fd < 0) quit_on_error("Failed to open file"); | |
for (int i = 0; i < 100; i++) { | |
if (write(fd, "xyzzyxyzzyxyzzyxyzzy", 20) != 20) quit_on_error("Failed to append to file"); | |
} | |
close(fd); | |
} | |
if (syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART) < 0) | |
quit_on_error("Failed to uncleanly reboot system. Please run as root in a VM."); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
My qemu command line:
qemu-system-x86_64 -nodefaults -enable-kvm -cpu host -smp 2 -m 4096 -vga virtio -nic user -serial mon:stdio -drive file=ArchFsCrash.qcow2,if=virtio,cache=directsync
This creates a lot of files and then uncleanly restarts the system. After the system comes up, take a look at the file sizes to locate which files were being written when the system was restarted and then look for signs of corruption. If all files are in the 'old' or 'new' state, then you need to tune the number and size of the files.