Skip to content
42 changes: 35 additions & 7 deletions src/native/libs/System.Native/pal_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -783,21 +783,30 @@ int32_t SystemNative_FChMod(intptr_t fd, int32_t mode)
#endif /* HAVE_FCHMOD */
}

#ifdef TARGET_OSX
static int32_t IsNetworkFileSystem(int fileDescriptor);
#endif

int32_t SystemNative_FSync(intptr_t fd)
{
int fileDescriptor = ToFileDescriptor(fd);

int32_t result;
Comment thread
adamsitnik marked this conversation as resolved.
#ifdef TARGET_OSX
while ((result = fcntl(fileDescriptor, F_FULLFSYNC)) < 0 && errno == EINTR);
if (result >= 0)
// F_FULLFSYNC is not supported on network file systems (e.g., NFS, SMB, CIFS) and may cause
// pending writes to be discarded. See https://github.com/dotnet/runtime/issues/124722.
if (!IsNetworkFileSystem(fileDescriptor))
Comment thread
adamsitnik marked this conversation as resolved.
Outdated
{
return result;
}
while ((result = fcntl(fileDescriptor, F_FULLFSYNC)) < 0 && errno == EINTR);
if (result >= 0)
{
return result;
}
Comment thread
adamsitnik marked this conversation as resolved.

// F_FULLFSYNC is not supported on all file systems and handle types (e.g.,
// network file systems, read-only handles). Fall back to fsync.
// For genuine I/O errors (e.g., EIO), fsync will also fail and propagate the error.
// F_FULLFSYNC is not supported on all file systems and handle types (e.g.,
// network file systems, read-only handles). Fall back to fsync.
// For genuine I/O errors (e.g., EIO), fsync will also fail and propagate the error.
}
#endif
while ((result = fsync(fileDescriptor)) < 0 && errno == EINTR);
return result;
Expand Down Expand Up @@ -1708,6 +1717,25 @@ static uint32_t FileSystemNameSupportsLocking(const char* fileSystemName)
}
return 1;
}

#ifdef TARGET_OSX
// Returns 1 if the file descriptor is on a network file system (e.g., NFS, SMB, CIFS).
// These file systems don't reliably support F_FULLFSYNC and may discard pending writes.
// See https://github.com/dotnet/runtime/issues/124722.
static int32_t IsNetworkFileSystem(int fileDescriptor)
Comment thread
adamsitnik marked this conversation as resolved.
Outdated
{
struct statfs statfsArgs;
int statfsRes;
while ((statfsRes = fstatfs(fileDescriptor, &statfsArgs)) == -1 && errno == EINTR);
if (statfsRes == -1)
{
// Cannot determine the file system type; skip F_FULLFSYNC to avoid potential data loss.
return 1;
}
// FileSystemNameSupportsLocking returns 0 for network file systems (NFS, CIFS, SMB, SMB2).
return !FileSystemNameSupportsLocking(statfsArgs.f_fstypename);
}
#endif
#endif
#endif /* TARGET_WASI */

Expand Down
Loading