diff options
author | Radek Podgorny <radek@podgorny.cz> | 2022-07-04 12:13:01 +0200 |
---|---|---|
committer | Radek Podgorny <radek@podgorny.cz> | 2022-07-04 12:13:01 +0200 |
commit | ce5efb2a4504f2d78e6542fe94d0192630ad2bf1 (patch) | |
tree | ed7fb89367d0e4fc2b3856a91e134e34ef243e4d | |
parent | 678a9aa6a1ad047f3f340eda4d0e7c17a90f6234 (diff) | |
download | unionfs-fuse-git-ce5efb2a4504f2d78e6542fe94d0192630ad2bf1.tar.gz |
fix for nfs (and local) race condition
-rw-r--r-- | src/general.c | 19 |
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? |