runtime: Write CIFS file 'permission denied' (Linux)

Dear guys,

I got an error when I use my application write to a CIFS file folder mounted on host machine.

I tried use same user with shell script echo 123 > /mnt/debug/a.txt success.

After application error, there is a 0kb file in the folder, means the file is created but application cannot flush binary content into the file.

Mount options mount -t cifs --verbose -o domain=***,username=***,password='***',dir_mode=0777,file_mode=0777,noperm,rw \ //somehost/folder /mnt

error log

Unhandled exception. System.UnauthorizedAccessException: Access to the path '/mnt/debug/5d256383-48b6-49f3-99b7-d964c4a964f6' is denied.
 ---> System.IO.IOException: Permission denied
   --- End of inner exception stack trace ---
   at System.IO.FileStream.WriteNative(ReadOnlySpan`1 source)
   at System.IO.FileStream.FlushWriteBuffer()
   at System.IO.FileStream.FlushInternalBuffer()
   at System.IO.FileStream.Flush(Boolean flushToDisk)
   at System.IO.FileStream.Flush()
   at System.IO.StreamWriter.Flush(Boolean flushStream, Boolean flushEncoder)
   at System.IO.StreamWriter.Dispose(Boolean disposing)
   at System.IO.TextWriter.Dispose()
   at System.IO.File.WriteAllText(String path, String contents)
   at NasDebugger.Program.Main(String[] args)
Aborted (core dumped)

sample code

static int Main(string[] args)
        {
            if (args.Length == 0 || string.IsNullOrEmpty(args[0]))
            {
                Console.WriteLine("please set dir");
                return -1;
            }
            var dir = args[0];
            if (!Directory.Exists(dir))
            {
                Console.WriteLine("please set right dir");
                return -1;
            }
            var id = Guid.NewGuid().ToString();
            File.WriteAllText(Path.Combine(dir, id), "123123");
            Console.WriteLine(id);
            return 0;
        }

Right now , I only can reproduce it in my datacenter😭.

OS Linux version 4.12.14-95.54-default (geeko@buildhost) (gcc version 4.8.5 (SUSE Linux) ) #1 SMP Thu Jun 4 12:49:28 UTC 2020 (892ef1f) dotnetcore version: 3.1.8

Does anyone have idea about it?

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 2
  • Comments: 23 (11 by maintainers)

Commits related to this issue

Most upvoted comments

I ran into this and wasn’t in a position to change all our code that writes files to CIFS shares. I investigated different kernel versions as it appeared to happen after we upgraded the OS on our hosts. It turned out to be introduced in kernel v5.5.1, in fact this commit: https://github.com/torvalds/linux/commit/d0677992d2af3d65f1c1c21de3323d09d4891537. I managed to work around it by mounting our cifs shares using the nobrl option. From https://linux.die.net/man/8/mount.cifs:

nobrl Do not send byte range lock requests to the server. This is necessary for certain applications that break with cifs style mandatory byte range locks (and most cifs servers do not yet support requesting advisory byte range locks).

After remounting shares including this option the problem went away.

I ran into this and wasn’t in a position to change all our code that writes files to CIFS shares. I investigated different kernel versions as it appeared to happen after we upgraded the OS on our hosts. It turned out to be introduced in kernel v5.5.1, in fact this commit: torvalds/linux@d067799. I managed to work around it by mounting our cifs shares using the nobrl option. From https://linux.die.net/man/8/mount.cifs:

nobrl Do not send byte range lock requests to the server. This is necessary for certain applications that break with cifs style mandatory byte range locks (and most cifs servers do not yet support requesting advisory byte range locks).

After remounting shares including this option the problem went away.

THANK YOU! THANK YOU! THANK YOU!

I have been struggling with DOTNET commands on CIFS shares for ages. This is the only thing that fixed it for me.

I also just rant into this after upgrading some linux hosts with a Azure File Share using the 3.1 runtime. Saved me a ton of additional time trying to track down the issue.

Update

thanks @wfurt, I will try as your suggestion, this result tested by single file application.

I tried use 4 ways to write file.

  1. File.WriteAllText
  2. new StreamWriter(path)
  3. new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None)
  4. new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read)

Only 3 works fine, so FileShare should impact the result.

Sample code

class Program
{
    static int Main(string[] args)
    {
        if (args.Length == 0 || string.IsNullOrEmpty(args[0]))
        {
            Console.WriteLine("please set dir");
            return -1;
        }
        var dir = args[0];

        if (!Directory.Exists(dir))
        {
            Console.WriteLine("please set and existing dir");
            return -1;
        }
        var id = Guid.NewGuid().ToString();
        var model = 1;
        if (args.Length > 1) {
            if (!int.TryParse(args[1], out model))
                model = 1;
        }
        var path = Path.Combine(dir, id);
        
        switch (model)
        {
            case 1:
                Write1(path);break;
            case 2:
                Write2(path); break;
            case 3:
                Write3(path); break;
            case 4:
                Write4(path); break;
            default:
                return -1;
        }           
        return 0;
    }

    static void Write1(string path)
    {
        File.WriteAllText(path, "123123");
        Console.WriteLine(path);
    }

    static void Write2(string path)
    {
        using var writer = new StreamWriter(path);
        writer.Write("123123");
        Console.WriteLine(path);
    }

    static void Write3(string path)
    {
        using var fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
        using var writer = new StreamWriter(fs);
        writer.Write("123123");
        Console.WriteLine(path);
    }

    static void Write4(string path)
    {
        using var fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read);
        using var writer = new StreamWriter(fs);
        writer.Write("123123");
        Console.WriteLine(path);
    }
}

sample log

the-host-name:/home/debugger # ./NasDebugger /mnt/debug/ 1
Unhandled exception. System.UnauthorizedAccessException: Access to the path '/mnt/debug/c5d0bccf-edc8-4b7b-8607-fab879d0da79' is denied.
 ---> System.IO.IOException: Permission denied
   --- End of inner exception stack trace ---
   at System.IO.FileStream.WriteNative(ReadOnlySpan`1 source)
   at System.IO.FileStream.FlushWriteBuffer()
   at System.IO.FileStream.FlushInternalBuffer()
   at System.IO.FileStream.Flush(Boolean flushToDisk)
   at System.IO.FileStream.Flush()
   at System.IO.StreamWriter.Flush(Boolean flushStream, Boolean flushEncoder)
   at System.IO.StreamWriter.Dispose(Boolean disposing)
   at System.IO.TextWriter.Dispose()
   at System.IO.File.WriteAllText(String path, String contents)
   at NasDebugger.Program.Write1(String path)
   at NasDebugger.Program.Main(String[] args)
Aborted (core dumped)
the-host-name:/home/debugger # ./NasDebugger /mnt/debug/ 2
/mnt/debug/5a973cdd-ce73-40ad-b483-507f3843cbce
Unhandled exception. System.UnauthorizedAccessException: Access to the path '/mnt/debug/5a973cdd-ce73-40ad-b483-507f3843cbce' is denied.
 ---> System.IO.IOException: Permission denied
   --- End of inner exception stack trace ---
   at System.IO.FileStream.WriteNative(ReadOnlySpan`1 source)
   at System.IO.FileStream.FlushWriteBuffer()
   at System.IO.FileStream.FlushInternalBuffer()
   at System.IO.FileStream.Flush(Boolean flushToDisk)
   at System.IO.FileStream.Flush()
   at System.IO.StreamWriter.Flush(Boolean flushStream, Boolean flushEncoder)
   at System.IO.StreamWriter.Dispose(Boolean disposing)
   at System.IO.TextWriter.Dispose()
   at NasDebugger.Program.Write2(String path)
   at NasDebugger.Program.Main(String[] args)
Aborted (core dumped)
the-host-name:/home/debugger # ./NasDebugger /mnt/debug/ 3
/mnt/debug/2e23f4c7-ae3d-488d-968a-a98830777305
the-host-name:/home/debugger # ./NasDebugger /mnt/debug/ 4
/mnt/debug/d82757c5-9b77-4ee0-93c5-c140a4c39f8f
Unhandled exception. System.UnauthorizedAccessException: Access to the path '/mnt/debug/d82757c5-9b77-4ee0-93c5-c140a4c39f8f' is denied.
 ---> System.IO.IOException: Permission denied
   --- End of inner exception stack trace ---
   at System.IO.FileStream.WriteNative(ReadOnlySpan`1 source)
   at System.IO.FileStream.FlushWriteBuffer()
   at System.IO.FileStream.FlushInternalBuffer()
   at System.IO.FileStream.Flush(Boolean flushToDisk)
   at System.IO.FileStream.Flush()
   at System.IO.StreamWriter.Flush(Boolean flushStream, Boolean flushEncoder)
   at System.IO.StreamWriter.Dispose(Boolean disposing)
   at System.IO.TextWriter.Dispose()
   at NasDebugger.Program.Write4(String path)
   at NasDebugger.Program.Main(String[] args)
Aborted (core dumped)