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 workedn", 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 workedn", 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