[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <CAL3q7H4e8JPggKYasQA9Cm2UA=iCNuuchEjB0GzYKxPvf4f-FA@mail.gmail.com>
Date: Wed, 3 Dec 2025 17:42:31 +0000
From: Filipe Manana <fdmanana@...nel.org>
To: Vyacheslav Kovalevsky <slava.kovalevskiy.2014@...il.com>
Cc: clm@...com, dsterba@...e.com, linux-btrfs@...r.kernel.org,
linux-kernel@...r.kernel.org
Subject: Re: Directory is not persisted after creating 100s of files inside,
writing to another file and renaming it if system crashes.
On Wed, Dec 3, 2025 at 11:26 AM Vyacheslav Kovalevsky
<slava.kovalevskiy.2014@...il.com> wrote:
>
> Directory entry is not persisted after creating 100s (hundreds) of files inside, writing to another file (with `O_SYNC` flag) and renaming it if system crashes.
There's no need to create hundreds of files, 1 is enough. There's also
no need to open the file with O_SYNC or write data to it, more details
below.
>
>
> Detailed description
> ====================
>
> Hello, we have found another issue with btrfs crash behavior.
>
> In short:
>
> 1. Create and sync an empty file in root directory.
> 2. Make new directory in root directory.
> 3. Open the file with `O_SYNC` flag and write some data (of specific size).
There's no need to O_SYNC, write data of any specific size or even write data.
Just change the file in some way (writing something to it of any size,
or changing uid, gid, or add a xattr, etc) and then fsync it.
> 4. Fill directory with specific number of empty files.
One file is enough.
Fixed by: https://lore.kernel.org/linux-btrfs/a1b70971f8b73d44695ab6af56b69e0ae1010179.1764783284.git.fdmanana@suse.com/
Thanks.
> 5. Rename the previously written file.
> 6. Sync root directory.
>
> After system crash directory will be missing, although it was synced in the last step.
>
>
> System info
> ===========
>
> Linux version 6.18, also tested on 6.14.11.
>
>
> How to reproduce
> ================
>
> ```
> #include <errno.h>
> #include <fcntl.h>
> #include <stdio.h>
> #include <string.h>
> #include <sys/stat.h>
> #include <sys/types.h>
> #include <unistd.h>
>
> #define BUFFER_LEN 1024 // should be at least ~ 528
> #define FILE_N 256 // should be at least ~ 128
>
> int main() {
> int status;
> int file_fd;
> int root_fd;
>
> int buffer[BUFFER_LEN + 1] = {};
> for (int i = 0; i < BUFFER_LEN; ++i) {
> buffer[i] = i;
> }
>
> status = creat("file1", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
> printf("CREAT: %d\n", status);
> close(status);
>
> // persist `file1`
> sync();
>
> status = mkdir("dir", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
> printf("MKDIR: %d\n", status);
>
> // `O_SYNC` is important
> status = open("file1", O_WRONLY | O_SYNC);
> printf("OPEN: %d\n", status);
> file_fd = status;
>
> status = write(file_fd, buffer, BUFFER_LEN);
> printf("WRITE: %d\n", status);
>
> char path[100];
> // fill directory with a lot of empty files
> for (int i = 0; i < FILE_N; ++i) {
> sprintf(path, "dir/%d", i);
> status = creat(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
> close(status);
> }
>
> status = rename("file1", "file2");
> printf("RENAME: %d\n", status);
>
> status = open(".", O_RDONLY | O_DIRECTORY);
> printf("OPEN: %d\n", status);
> root_fd = status;
>
> // persist `dir`
> status = fsync(root_fd);
> printf("FSYNC: %d\n", status);
> }
> // after the crash `dir` is missing
> ```
>
> Steps:
>
> 1. Create and mount new btrfs file system in default configuration.
> 2. Change directory to root of the file system and run the compiled test.
> 3. Cause hard system crash (e.g. QEMU `system_reset` command).
> 4. Remount file system after crash.
> 5. Observe that `dir` directory is missing.
>
>
Powered by blists - more mailing lists