Skip to content

Commit c62b758

Browse files
torvaldsbrauner
authored andcommitted
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: Linus Torvalds <torvalds@linux-foundation.org> [brauner: commit message] Signed-off-by: Christian Brauner <brauner@kernel.org>
1 parent a0fde7e commit c62b758

File tree

2 files changed

+28
-6
lines changed

2 files changed

+28
-6
lines changed

fs/fcntl.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,22 @@ static long fcntl_set_rw_hint(struct file *file, unsigned int cmd,
327327
return 0;
328328
}
329329

330+
/* Is the file descriptor a dup of the file? */
331+
static long f_dupfd_query(int fd, struct file *filp)
332+
{
333+
CLASS(fd_raw, f)(fd);
334+
335+
/*
336+
* We can do the 'fdput()' immediately, as the only thing that
337+
* matters is the pointer value which isn't changed by the fdput.
338+
*
339+
* Technically we didn't need a ref at all, and 'fdget()' was
340+
* overkill, but given our lockless file pointer lookup, the
341+
* alternatives are complicated.
342+
*/
343+
return f.file == filp;
344+
}
345+
330346
static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
331347
struct file *filp)
332348
{
@@ -342,6 +358,9 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
342358
case F_DUPFD_CLOEXEC:
343359
err = f_dupfd(argi, filp, O_CLOEXEC);
344360
break;
361+
case F_DUPFD_QUERY:
362+
err = f_dupfd_query(argi, filp);
363+
break;
345364
case F_GETFD:
346365
err = get_close_on_exec(fd) ? FD_CLOEXEC : 0;
347366
break;
@@ -446,6 +465,7 @@ static int check_fcntl_cmd(unsigned cmd)
446465
switch (cmd) {
447466
case F_DUPFD:
448467
case F_DUPFD_CLOEXEC:
468+
case F_DUPFD_QUERY:
449469
case F_GETFD:
450470
case F_SETFD:
451471
case F_GETFL:

include/uapi/linux/fcntl.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,14 @@
88
#define F_SETLEASE (F_LINUX_SPECIFIC_BASE + 0)
99
#define F_GETLEASE (F_LINUX_SPECIFIC_BASE + 1)
1010

11+
/*
12+
* Request nofications on a directory.
13+
* See below for events that may be notified.
14+
*/
15+
#define F_NOTIFY (F_LINUX_SPECIFIC_BASE + 2)
16+
17+
#define F_DUPFD_QUERY (F_LINUX_SPECIFIC_BASE + 3)
18+
1119
/*
1220
* Cancel a blocking posix lock; internal use only until we expose an
1321
* asynchronous lock api to userspace:
@@ -17,12 +25,6 @@
1725
/* Create a file descriptor with FD_CLOEXEC set. */
1826
#define F_DUPFD_CLOEXEC (F_LINUX_SPECIFIC_BASE + 6)
1927

20-
/*
21-
* Request nofications on a directory.
22-
* See below for events that may be notified.
23-
*/
24-
#define F_NOTIFY (F_LINUX_SPECIFIC_BASE+2)
25-
2628
/*
2729
* Set and get of pipe page size array
2830
*/

0 commit comments

Comments
 (0)