-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
On Linux, FileShare.None doesn't seem to be taken into account when retrying to open a locked file #59995
Comments
Tagging subscribers to this area: @dotnet/area-system-io Issue DetailsDescriptionWe have 2 processes. The first one opens a file with an exclusive lock (using FileShare.None), and keeps this lock for some time. Another process starts and tries to open the same file with an exclusive lock (also using FileShare.None). And it retries to open it until it gets the exclusive lock. Here are two small programs. First, test1 is started, then, after the lock is acquired (but before it is released), test2 is started. using System;
using System.IO;
using System.Threading;
namespace test1
{
class Program
{
static void Main(string[] args)
{
var lockfilepath = Path.Combine(Path.GetTempPath(), "test-lock");
Console.WriteLine($"{DateTime.Now} test1 {lockfilepath}");
using(var exclusiveLock = new FileStream(lockfilepath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None, 1, FileOptions.DeleteOnClose)) {
Console.WriteLine($"{DateTime.Now} {lockfilepath} locked");
Thread.Sleep(10 * 1000);
Console.WriteLine($"{DateTime.Now} releasing lock");
}
Console.WriteLine($"{DateTime.Now} lock released");
}
}
} using System;
using System.IO;
using System.Threading;
namespace test2
{
class Program
{
static void Main(string[] args)
{
var lockfilepath = Path.Combine(Path.GetTempPath(), "test-lock");
Console.WriteLine($"{DateTime.Now} test2 - {lockfilepath}");
while(true) {
try {
var exclusiveLock = new FileStream(lockfilepath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None, 1, FileOptions.DeleteOnClose);
break;
} catch(Exception _) {
Console.WriteLine($"{DateTime.Now} retrying");
Thread.Sleep(1000);
}
}
Console.WriteLine($"{DateTime.Now} lock acquired");
}
}
} What we see: What we expect: Configuration.NET version: 6.0.100-rc.1.21463.6 Regression?This works as expected on Windows (.NET Framework 4.8, .NET Core 3.1, .NET 6 RC1) and Linux with .NET Core 3.1.
|
This is a 6.0 regression introduced by #55153.
runtime/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs Lines 274 to 283 in b320541
cc @stephentoub |
The fix is to assign
The reproducer describes a scenario where the first program has locked the file for the whole time that the second program is started/stopped. That worked in previous versions of .NET. #55327 makes it works when both programs are started/stopped at random times. That has never worked perfect on Unix so far due to races. |
Yes, this, and the races that occur on Unix when concurrently opening/closing a file with |
Thanks. What's the bare minimum src change required to fix just the regression? |
Moving I could imagine the reproducer is a simplified version of production code that would be subject to the races that are fixed in #55327 (but very unlikely to occur). If you like a minimal fix, I can make a PR for it against 6.0 branch. |
Please and thank you :) |
@nicolasl-rc thank you for a great bug report! |
@nicolasl-rc fyi, what happens in your reproducer: When the second program runs the first time, it ends up deleting the file from the first program. The fix is to not delete the file when we fail to lock. |
Thank you for looking at it so rapidly! Just to be sure: will the fix be included in the .NET 6 release? We are migrating our products from .NET Core 3.1 to .NET 6, and would like to be ready as soon as possible after the official release (we already have customers asking us about .NET 6 support). And as far as I can tell, this is the last issue we have. |
Yes, it will be fixed for .NET 6. |
Fixed by #60112 |
Description
We have 2 processes. The first one opens a file with an exclusive lock (using FileShare.None), and keeps this lock for some time. Another process starts and tries to open the same file with an exclusive lock (also using FileShare.None). And it retries to open it until it gets the exclusive lock.
Here are two small programs. First, test1 is started, then, after the lock is acquired (but before it is released), test2 is started.
What we see:
The first attempt by test2 to open the file fails as expected. However, the second attempt succeeds, even though test1 still has the lock.
What we expect:
test2 should loop until test1 releases the lock.
Configuration
.NET version: 6.0.100-rc.1.21463.6
OS: Linux (distro: rocky linux 8)
Architecture: x64
Regression?
This works as expected on Windows (.NET Framework 4.8, .NET Core 3.1, .NET 6 RC1) and Linux with .NET Core 3.1.
It seems to be linked to the use of FileOptions.DeleteOnClose. Using FileOptions.None gives the expected behavior.
The text was updated successfully, but these errors were encountered: