Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/coreclr/vm/wasm/browser/callhelpers-pinvoke.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ extern "C" {
int32_t SystemNative_FChflags (void *, uint32_t);
int32_t SystemNative_FLock (void *, int32_t);
int32_t SystemNative_FStat (void *, void *);
int32_t SystemNative_FSync (void *);
int32_t SystemNative_FSync (void *, int32_t);
int32_t SystemNative_FTruncate (void *, int64_t);
int32_t SystemNative_FUTimens (void *, void *);
int32_t SystemNative_FcntlGetIsNonBlocking (void *, void *);
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/wasm/wasi/callhelpers-pinvoke.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ extern "C" {
int32_t SystemNative_FChflags (void *, uint32_t);
int32_t SystemNative_FLock (void *, int32_t);
int32_t SystemNative_FStat (void *, void *);
int32_t SystemNative_FSync (void *);
int32_t SystemNative_FSync (void *, int32_t);
int32_t SystemNative_FTruncate (void *, int64_t);
int32_t SystemNative_FUTimens (void *, void *);
int32_t SystemNative_FcntlGetFD (void *);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ internal static partial class Interop
internal static partial class Sys
{
[LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_FSync", SetLastError = true)]
internal static partial int FSync(SafeFileHandle fd);
internal static partial int FSync(SafeFileHandle fd, [MarshalAs(UnmanagedType.Bool)] bool useFullFSync);
Comment thread
adamsitnik marked this conversation as resolved.
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,35 @@ public sealed partial class SafeFileHandle : SafeHandleZeroOrMinusOneIsInvalid
private NullableBool _canSeek /* = NullableBool.Undefined */;
private NullableBool _supportsRandomAccess /* = NullableBool.Undefined */;
private NullableBool _isAsync /* = NullableBool.Undefined */;
// Lazily initialized on Apple platforms (macOS, iOS, tvOS, Mac Catalyst).
// True = use F_FULLFSYNC.
// False = skip F_FULLFSYNC because the probe indicates the file system should avoid it
// (e.g., NFS/SMB/CIFS/SMB2, or when the probe fails).
// Stays Undefined until first queried; UseFullFSync treats Undefined as True.
// See https://github.com/dotnet/runtime/issues/124722.
private NullableBool _useFullFsync /* = NullableBool.Undefined */;
private bool _deleteOnClose;
private bool _isLocked;

// Returns true when F_FULLFSYNC should be attempted. Returns false when
// FileSystemSupportsLocking(LOCK_SH, accessWrite: true) reports the file system as unsupported
// for this probe, which includes known network file systems and probe failures.
// The value is only used on Apple platforms; native code ignores it on other platforms.
// Lazily computed and cached on first access to avoid a syscall for callers that never flush to disk.
internal bool UseFullFSync
{
get
{
NullableBool useFullFsync = _useFullFsync;
if (useFullFsync == NullableBool.Undefined && !IsClosed && OperatingSystem.IsApplePlatform())

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SystemNative_FSync uses TARGET_OSX only.

Suggested change
if (useFullFsync == NullableBool.Undefined && !IsClosed && OperatingSystem.IsApplePlatform())
if (useFullFsync == NullableBool.Undefined && !IsClosed && OperatingSystem.IsMacOS())

{
_useFullFsync = useFullFsync = Interop.Sys.FileSystemSupportsLocking(this, Interop.Sys.LockOperations.LOCK_SH, accessWrite: true)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR reuses SystemNative_FileSystemSupportsLocking as a proxy for "is this a network FS," but that function's contract is about locking and its result depends on lockOperation/accessWrite, so it can't simply be renamed to IsNetworkFileSystem. Consider extracting the shared network-FS detection (the FileSystemNameSupportsLocking nfs/cifs/smb/smb2 check) into a dedicated helper.

? NullableBool.True : NullableBool.False;
}
return useFullFsync != NullableBool.False;
}
}

public SafeFileHandle() : this(ownsHandle: true)
{
}
Expand Down Expand Up @@ -461,6 +487,7 @@ private bool Init(string path, FileMode mode, FileAccess access, FileShare share
return false;
}
}

// Enable DeleteOnClose when we've successfully locked the file.
// On Windows, the locking happens atomically as part of opening the file.
_deleteOnClose = (options & FileOptions.DeleteOnClose) != 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ internal static void ThrowInvalidArgument(SafeFileHandle handle) =>
/// <summary>Flushes the file's OS buffer.</summary>
internal static void FlushToDisk(SafeFileHandle handle)
{
if (Interop.Sys.FSync(handle) < 0)
if (Interop.Sys.FSync(handle, handle.UseFullFSync) < 0)
{
Interop.ErrorInfo errorInfo = Interop.Sys.GetLastErrorInfo();
switch (errorInfo.Error)
Expand Down
21 changes: 13 additions & 8 deletions src/native/libs/System.Native/pal_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -783,21 +783,26 @@ int32_t SystemNative_FChMod(intptr_t fd, int32_t mode)
#endif /* HAVE_FCHMOD */
}

int32_t SystemNative_FSync(intptr_t fd)
int32_t SystemNative_FSync(intptr_t fd, int32_t useFullFSync)
{
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)
if (useFullFSync)
{
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.
}
#else
(void)useFullFSync;
#endif
while ((result = fsync(fileDescriptor)) < 0 && errno == EINTR);
return result;
Expand Down
5 changes: 3 additions & 2 deletions src/native/libs/System.Native/pal_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -535,11 +535,12 @@ PALEXPORT int32_t SystemNative_ChMod(const char* path, int32_t mode);
PALEXPORT int32_t SystemNative_FChMod(intptr_t fd, int32_t mode);

/**
* Flushes all modified data and attribtues of the specified File Descriptor to the storage medium.
* Flushes all modified data and attributes of the specified File Descriptor to the storage medium.
* On macOS, attempts F_FULLFSYNC when useFullFSync is non-zero, falling back to fsync on failure.
*
* Returns 0 for success; on fail, -1 is returned and errno is set.
*/
PALEXPORT int32_t SystemNative_FSync(intptr_t fd);
PALEXPORT int32_t SystemNative_FSync(intptr_t fd, int32_t useFullFSync);

/**
* Changes the advisory lock status on a given File Descriptor
Expand Down
Loading