On Wed, Feb 16, 2022 at 11:28:18AM +0100, Miklos Szeredi wrote: > Something like this: > diff --git a/fs/namei.c b/fs/namei.c > index 3f1829b3ab5b..dd6908cee49d 100644 Tested-by: Xavier Roche <xavier.roche@xxxxxxxxxxx> I confirm this completely fixes at least the specific race. Tested on a unpatched and then patched 5.16.5, with the trivial bash test, and then with a C++ torture test. Before: ------- $ time ./linkbug Failed after 4 with No such file or directory real 0m0,004s user 0m0,000s sys 0m0,004s After: ------ (no error after ten minutes of running the program) Torture test program: --------------------- /* Linux rename vs. linkat race condition. * Rationale: both (1) moving a file to a target and (2) linking the target to a file in parallel leads to a race * on Linux kernel. * Sample file courtesy of Xavier Grand at Algolia * g++ -pthread linkbug.c -o linkbug */ #include <thread> #include <unistd.h> #include <assert.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <iostream> #include <string.h> static const char* producedDir = "/tmp"; static const char* producedFile = "/tmp/file.txt"; static const char* producedTmpFile = "/tmp/file.txt.tmp"; static const char* producedThreadDir = "/tmp/tmp"; static const char* producedThreadFile = "/tmp/file.txt.tmp.2"; bool createFile(const char* path) { const int fdOut = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); assert(fdOut != -1); assert(write(fdOut, "Foo", 4) == 4); assert(close(fdOut) == 0); return true; } void func() { int nbSuccess = 0; // Loop producedThread a hardlink of the file while (true) { if (link(producedFile, producedThreadFile) != 0) { std::cout << "Failed after " << nbSuccess << " with " << strerror(errno) << std::endl; exit(EXIT_FAILURE); } else { nbSuccess++; } assert(unlink(producedThreadFile) == 0); } } int main() { // Setup env unlink(producedTmpFile); unlink(producedFile); unlink(producedThreadFile); createFile(producedFile); mkdir(producedThreadDir, 0777); // Async thread doing a hardlink and moving it std::thread t(func); // Loop creating a .tmp and moving it while (true) { assert(createFile(producedTmpFile)); assert(rename(producedTmpFile, producedFile) == 0); } return 0; }