Closed
Description
Description
We discovered a race condition when trying to poll fs events using uv_fs_poll_start.
The race condition happens when the fs poll watch is started for a newly created directory and directly afterwards a file is written to that directory. That file does most of the times not get recognized by the file watch.
If we add a sleep of approx. 1s between the watch start and file creation, the file gets recognized.
We first encountered this issue while debugging a failing test in nodejs:
(async () => {
const root = '/tmp/debug-test';
await fs.rm(root, {recursive: true, force: true});
await fs.mkdir(root, {recursive: true});
//await wait(duration({milliseconds: 500}));
fscb.watchFile(root, {
interval: 2000,
}, (curr) => {
console.log('watchFile', curr);
});
await fs.writeFile(path.join(root, 'test.txt'), 'foo');
console.log('Printed file');
})()
Bug occurs on the following systems and cloudproviders:
- Provider: Azure on Flatcar stable (kernel 5.15.111), beta (kernel 5.15.113) and alpha.
- Provider Equinix on Flatcar stable (kernel 5.15.94)
- Provider PlusServer (German Hoster with Openstack) on Flatcar stable (kernel 5.15.111).
The bug does not occur on:
- Provider PlusServer on Ubuntu 20.04
- Azure Ubuntu 20.04
- Laptop with ArchLinux (Kernel 6.3.3)
Impact
- We always need a sleep second before we can be sure the watch recognizes all files.
- This bug is a blocker for us using Flatcar.
Environment and steps to reproduce
- Create a machine with Flatcar (tested on stable, beta and alpha)
- start a ubuntu container
sudo docker run -it --entrypoint bash --rm ubuntu:20.04
- compile the following c program with
gcc main.c -o main -luv
#include <stdio.h>
#include <uv.h>
void cb (uv_fs_poll_t* handle,
int status,
const uv_stat_t* prev,
const uv_stat_t* curr) {
printf("Received %ld\n", curr->st_ino);
}
void writeToFile () {
FILE *f = fopen("/tmp/debug-test/test6.txt", "w");
fprintf(f, "foo");
fclose(f);
}
void writeToFileCb (uv_work_t *req) {
writeToFile();
}
void after(uv_work_t *req, int status) {
printf("Finished\n");
}
static uv_fs_poll_t handle;
static uv_work_t req;
static char root[] = "/tmp/debug-test";
int main()
{
setbuf(stdout, NULL);
uv_loop_t *loop = uv_default_loop();
uv_fs_poll_init(loop, &handle);
const int err = uv_fs_poll_start(&handle, cb, root, 2000);
if (err != 0) {
printf("Error %d", err);
return 42;
}
printf("--ready\n");
uv_queue_work(loop, &req, writeToFileCb, after);
return uv_run(uv_default_loop(), UV_RUN_DEFAULT);
}
- Setup the tmp dir:
mkdir /tmp/debug-test
- run
rm /tmp/dir/* && ./main
multiple times -> the poll does not notice the file.
Expected behavior
The written file should always be reported by the poll as it does on other distros.