summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRadek Podgorny <radek@podgorny.cz>2022-07-04 12:13:01 +0200
committerRadek Podgorny <radek@podgorny.cz>2022-07-04 12:13:01 +0200
commitce5efb2a4504f2d78e6542fe94d0192630ad2bf1 (patch)
treeed7fb89367d0e4fc2b3856a91e134e34ef243e4d
parent678a9aa6a1ad047f3f340eda4d0e7c17a90f6234 (diff)
downloadunionfs-fuse-git-ce5efb2a4504f2d78e6542fe94d0192630ad2bf1.tar.gz
fix for nfs (and local) race condition
-rw-r--r--src/general.c19
1 files changed, 16 insertions, 3 deletions
diff --git a/src/general.c b/src/general.c
index 5611bca..81a8799 100644
--- a/src/general.c
+++ b/src/general.c
@@ -240,15 +240,28 @@ static int do_create(const char *path, int nbranch_ro, int nbranch_rw) {
if (res == -1) RETURN(1); // lower level branch removed in the mean time?
}
+ bool _call_setfile = true;
res = mkdir(dirp, buf.st_mode);
if (res == -1) {
- USYSLOG(LOG_ERR, "Creating %s failed: \n", dirp);
- RETURN(1);
+ if (errno == EEXIST) {
+ // In an NFS environment with many clients trying to write to the same directory tree
+ // and if that tree does not exist on the read write mount, there's a race between them.
+ // The directory may have been created by another client. It's not a fatal error.
+ // TODO: actually, this may also happen locally. anyway, it would probably be better to just
+ // some internal locking instead of relying on return error (!) codes
+ USYSLOG(LOG_INFO, "Directory %s already existed - probably another client made it", dirp);
+ _call_setfile = false; // leave the call to the thread which had a successful mkdir
+ } else {
+ USYSLOG(LOG_ERR, "Creating %s failed: \n", dirp);
+ RETURN(1);
+ }
}
if (nbranch_ro == nbranch_rw) RETURN(0); // the special case again
- if (setfile(dirp, &buf)) RETURN(1); // directory already removed by another process?
+ if (_call_setfile) {
+ if (setfile(dirp, &buf)) RETURN(1); // directory already removed by another process?
+ }
// TODO: time, but its values are modified by the next dir/file creation steps?