Skip to content

Commit

Permalink
util: add file locking for PCIe access.
Browse files Browse the repository at this point in the history
This way, only one application using the library can access a given
device at a time.

We use the file descriptor pointing to BAR0 (via the resource0 file)
because it's the first one to be opened (i.e. we fail early), and
because it makes the most sense semantically: the issue with sharing a
device between processes is that they will need to access different page
indexes, which are controlled by BAR0.

We chose to use Open File Description (OFD) locking because it has more
predictable behavior [1] and is POSIX.1-2024 [2], unlike the flock(2)
API. Furthermore, we rely on mmap keeping a reference to the file
descriptor, therefore holding the lock while the mapping is active [3]
[4]:

    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.

No locking is added for the serial mode because the kernel will report
the device as busy when another process has already opened it.

[1] https://lwn.net/Articles/586904/
[2] https://pubs.opengroup.org/onlinepubs/9799919799/functions/fcntl.html
[3] https://pubs.opengroup.org/onlinepubs/9799919799/functions/mmap.html
[4] https://unix.stackexchange.com/q/784020/437538
  • Loading branch information
ericonr committed Oct 4, 2024
1 parent 16804dc commit b70d15a
Showing 1 changed file with 23 additions and 0 deletions.
23 changes: 23 additions & 0 deletions util/pcie-open.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,27 @@ void configure_mutexes(struct pcie_bars &bars)
throw std::runtime_error("couldn't initialize mutex");
}

void lock_file(int fd)
{
struct flock arg = {
/* exclusive lock */
.l_type = F_WRLCK,
/* lock the whole file */
.l_whence = SEEK_SET,
.l_start = 0,
.l_len = 0,
/* application is responsible for setting to 0 for OFD locks */
.l_pid = 0,
};
if (fcntl(fd, F_OFD_SETLK, &arg) < 0) {
/* allow program to work when F_OFD_SETLK isn't implemented */
if (errno == EINVAL)
fputs("WARNING: F_OFD_SETLK not supported!\n", stderr);
else
throw std::runtime_error(std::string("couldn't lock file"));
}
}

}

void dev_open_slot(struct pcie_bars &bars, int slot)
Expand Down Expand Up @@ -69,6 +90,8 @@ void dev_open(struct pcie_bars &bars, const char *pci_address)
if (fd < 0)
throw std::runtime_error(std::string("couldn't open resource file: ") + pci_address);
}
if (bar == 0)
lock_file(fd);
struct stat st;
fstat(fd, &st);
bars.sizes[i] = st.st_size;
Expand Down

0 comments on commit b70d15a

Please sign in to comment.