Commit c62b758b authored by Linus Torvalds's avatar Linus Torvalds Committed by Christian Brauner

fcntl: add F_DUPFD_QUERY fcntl()

Often userspace needs to know whether two file descriptors refer to the
same struct file. For example, systemd uses this to filter out duplicate
file descriptors in it's file descriptor store (cf. [1]) and vulkan uses
it to compare dma-buf fds (cf. [2]).

The only api we provided for this was kcmp() but that's not generally
available or might be disallowed because it is way more powerful (allows
ordering of file pointers, operates on non-current task) etc. So give
userspace a simple way of comparing two file descriptors for sameness
adding a new fcntl() F_DUDFD_QUERY.

Link: https://github.com/systemd/systemd/blob/a4f0e0da3573a10bc5404142be8799418760b1d1/src/basic/fd-util.c#L517 [1]
Link: https://gitlab.freedesktop.org/wlroots/wlroots/-/blob/master/render/vulkan/texture.c#L490 [2]
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
[brauner: commit message]
Signed-off-by: default avatarChristian Brauner <brauner@kernel.org>
parent a0fde7ed
...@@ -327,6 +327,22 @@ static long fcntl_set_rw_hint(struct file *file, unsigned int cmd, ...@@ -327,6 +327,22 @@ static long fcntl_set_rw_hint(struct file *file, unsigned int cmd,
return 0; return 0;
} }
/* Is the file descriptor a dup of the file? */
static long f_dupfd_query(int fd, struct file *filp)
{
CLASS(fd_raw, f)(fd);
/*
* We can do the 'fdput()' immediately, as the only thing that
* matters is the pointer value which isn't changed by the fdput.
*
* Technically we didn't need a ref at all, and 'fdget()' was
* overkill, but given our lockless file pointer lookup, the
* alternatives are complicated.
*/
return f.file == filp;
}
static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
struct file *filp) struct file *filp)
{ {
...@@ -342,6 +358,9 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, ...@@ -342,6 +358,9 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
case F_DUPFD_CLOEXEC: case F_DUPFD_CLOEXEC:
err = f_dupfd(argi, filp, O_CLOEXEC); err = f_dupfd(argi, filp, O_CLOEXEC);
break; break;
case F_DUPFD_QUERY:
err = f_dupfd_query(argi, filp);
break;
case F_GETFD: case F_GETFD:
err = get_close_on_exec(fd) ? FD_CLOEXEC : 0; err = get_close_on_exec(fd) ? FD_CLOEXEC : 0;
break; break;
...@@ -446,6 +465,7 @@ static int check_fcntl_cmd(unsigned cmd) ...@@ -446,6 +465,7 @@ static int check_fcntl_cmd(unsigned cmd)
switch (cmd) { switch (cmd) {
case F_DUPFD: case F_DUPFD:
case F_DUPFD_CLOEXEC: case F_DUPFD_CLOEXEC:
case F_DUPFD_QUERY:
case F_GETFD: case F_GETFD:
case F_SETFD: case F_SETFD:
case F_GETFL: case F_GETFL:
......
...@@ -8,6 +8,14 @@ ...@@ -8,6 +8,14 @@
#define F_SETLEASE (F_LINUX_SPECIFIC_BASE + 0) #define F_SETLEASE (F_LINUX_SPECIFIC_BASE + 0)
#define F_GETLEASE (F_LINUX_SPECIFIC_BASE + 1) #define F_GETLEASE (F_LINUX_SPECIFIC_BASE + 1)
/*
* Request nofications on a directory.
* See below for events that may be notified.
*/
#define F_NOTIFY (F_LINUX_SPECIFIC_BASE + 2)
#define F_DUPFD_QUERY (F_LINUX_SPECIFIC_BASE + 3)
/* /*
* Cancel a blocking posix lock; internal use only until we expose an * Cancel a blocking posix lock; internal use only until we expose an
* asynchronous lock api to userspace: * asynchronous lock api to userspace:
...@@ -17,12 +25,6 @@ ...@@ -17,12 +25,6 @@
/* Create a file descriptor with FD_CLOEXEC set. */ /* Create a file descriptor with FD_CLOEXEC set. */
#define F_DUPFD_CLOEXEC (F_LINUX_SPECIFIC_BASE + 6) #define F_DUPFD_CLOEXEC (F_LINUX_SPECIFIC_BASE + 6)
/*
* Request nofications on a directory.
* See below for events that may be notified.
*/
#define F_NOTIFY (F_LINUX_SPECIFIC_BASE+2)
/* /*
* Set and get of pipe page size array * Set and get of pipe page size array
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment