0

I am using Open File Description (OFD) owned locks on Linux (fcntl with command F_OFD_SETLK). After locking a file, I memory mapped it, and closed the file descriptor. Another process tried to lock the same file, and was unable to do so until the first process unmapped the memory. It seems Linux, at least, keeps a reference to the open file description when a mapping is still active.

POSIX.1-2024 documents that mmap adds a reference to the "file associated with the file descriptor".

The mmap() function shall add an extra reference to the file associated with the file descriptor fildes which is not removed by a subsequent close() on that file descriptor. This reference shall be removed when there are no more mappings to the file.

A literal interpretation here would mean that the reference is to the file itself, but I don't know if that was the intent when the documentation was written.

I would like to be able to rely on this behavior. Is there somewhere in POSIX where it's specified that I am missing? Could this be a defect report? If it's Linux exclusive, is there a reference anywhere that this was their intended behavior (and, possibly, their interpretation of the POSIX standard)?

Test program (might require different feature test macros on other platforms):

#define _GNU_SOURCE #include <fcntl.h> #include <sys/mman.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> int main() { char filename[] = "/tmp/ofd-test.XXXXXX"; int fd = mkstemp(filename); if (fd < 0) { perror("mkstemp"); return 1; } fprintf(stderr, "created file '%s'\n", filename); struct flock lock = { .l_len = 0, .l_pid = 0, .l_whence = SEEK_SET, .l_start = 0, .l_type = F_WRLCK, }; if (fcntl(fd, F_OFD_SETLK, &lock) < 0) { perror("first lock"); return 1; } void *ptr = mmap(0, 1024, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (ptr == MAP_FAILED) { perror("mmap"); return 1; } close(fd); int newfd = open(filename, O_RDWR); if (newfd < 0) { perror("re-open"); return 1; } lock.l_pid = 0; if (fcntl(newfd, F_OFD_SETLK, &lock) == 0) { fputs("locking after mmap worked\n", stderr); return 1; } perror("locking after mmap"); munmap(ptr, 1024); lock.l_pid = 0; if (fcntl(newfd, F_OFD_SETLK, &lock) < 0) { perror("locking after munmap"); return 1; } fputs("locking after munmap worked\n", stderr); if (unlink(filename) < 0) { perror("unlink"); return 1; } return 0; } 

For me, this outputs:

created file '/tmp/ofd-test.Pyf3oj' locking after mmap: Resource temporarily unavailable locking after munmap worked 

1 Answer 1

1

A file descriptor is a reference to an open file.

The reference count is maintained on the file itself, not on the descriptors.

The mmap generates another reference, but that doesn't need to be attached to a descriptor -- pretty much the only state a descriptor has is its number, and the close-on-exec flag, and neither is required for a mapped area.

The dup(2) manpage says

After a successful return, the old and new file descriptors may be used interchangeably. Since the two file descriptors refer to the same open file description, they share file offset and file status flags; for example, if the file offset is modified by using lseek(2) on one of the file descriptors, the offset is also changed for the other file descriptor.

So yes, that behaviour is expected.

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.