Skip to content

FileStream.Lock(Int64, Int64) always fails on FreeBSD #65831

@wfurt

Description

@wfurt

wrapping discussion from #65059, related to #14537.
Let's consider example as

using FileStream fs1 = File.Open(path, FileMode.Open, fileAccess, FileShare.ReadWrite);
fs1.Lock(0, 100);
fs1.Unlock(0, 100);
fs1.Lock(0, 100);

This will always fail with something like
System.IO.IOException: The process cannot access the file /tmp/FileStream_LockUnlock_nm3knbvl.5ix/OverlappingRegionsFromOtherProcess_With_WriteLock_ThrowsException_237_603d100b because it is being used by another process.
The sequence above would translate to following kernel calls:

16618: openat(AT_FDCWD,"/tmp/foo",O_RDWR|O_CLOEXEC,00) = 34 (0x22)
16618: flock(34,LOCK_SH|LOCK_NB)         = 0 (0x0)
16618: lseek(34,0x0,SEEK_CUR)            = 0 (0x0)
16618: lseek(34,0x0,SEEK_SET)            = 0 (0x0)
16618: fcntl(34,F_SETLK,0x7fffffffd928)      ERR#35 'Resource temporarily unavailable'

and

     [EAGAIN]           The argument cmd is F_SETLK, the type of lock (l_type)
                        is a shared lock (F_RDLCK) or exclusive lock
                        (F_WRLCK), and the segment of a file to be locked is
                        already exclusive-locked by another process; or the
                        type is an exclusive lock and some portion of the
                        segment of a file to be locked is already shared-
                        locked or exclusive-locked by another process.

small C repro of the same calls:

#include <sys/file.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

int main(int argc, char** argv)
{
    struct flock fl;

    int fd= open("/tmp/foo", O_RDWR|O_CLOEXEC);
    int ret  = lseek(fd, 0, SEEK_SET);
    printf("Opened as %d\n", fd);
    if (argc > 1) {
        ret = flock(fd, LOCK_SH|LOCK_NB);
        printf("flock finished with %d\n", ret);
    }

    fl.l_start = 0;
    fl.l_len = 100;
    fl.l_type = F_WRLCK;
    fl.l_whence = SEEK_SET;

    ret = fcntl(fd, F_SETLK, &fl);
    printf("fcntl finished with %d and errno %d (%s)\n", ret, errno, strerror(errno));

    return 0;
}

It fails if we follow the FileStream sequence.
But if we skip the flock then the fcntl works as expect. e.g. partial locking works but it seems like we cannot use both at the same time.
On Linux, it works fine in both cases.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions