eventfd: Add refcounting

An eventfd file descriptor can be used by drivers such as DRM drivers
through linuxkpi. A driver can hold a reference to such a file
regardless of the fact it is used by userland or not.

This patch introduces a refcount in `struct eventfd`, plus the
`eventfd_get()` and `eventfd_put()` functions to acquire and release
references. These functions will be used by DRM drivers for instance.

This structure is internal to `sys/kern/sys_eventfd.c` and not used
anywhere else. Thus it is safe to add a field without breaking anything.

Reviewed by:	markj
Sponsored by:	The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D50849
This commit is contained in:
Jean-Sébastien Pédron
2025-05-26 19:18:24 +02:00
parent e878df0d3b
commit 5931649751
2 changed files with 34 additions and 4 deletions
+30 -4
View File
@@ -40,6 +40,7 @@
#include <sys/mutex.h>
#include <sys/poll.h>
#include <sys/proc.h>
#include <sys/refcount.h>
#include <sys/selinfo.h>
#include <sys/stat.h>
#include <sys/uio.h>
@@ -102,6 +103,7 @@ struct eventfd {
uint32_t efd_flags;
struct selinfo efd_sel;
struct mtx efd_lock;
unsigned int efd_refcount;
};
int
@@ -119,6 +121,7 @@ eventfd_create_file(struct thread *td, struct file *fp, uint32_t initval,
efd->efd_count = initval;
mtx_init(&efd->efd_lock, "eventfd", NULL, MTX_DEF);
knlist_init_mtx(&efd->efd_sel.si_note, &efd->efd_lock);
refcount_init(&efd->efd_refcount, 1);
fflags = FREAD | FWRITE;
if ((flags & EFD_NONBLOCK) != 0)
@@ -128,16 +131,39 @@ eventfd_create_file(struct thread *td, struct file *fp, uint32_t initval,
return (0);
}
struct eventfd *
eventfd_get(struct file *fp)
{
struct eventfd *efd;
if (fp->f_data == NULL || fp->f_ops != &eventfdops)
return (NULL);
efd = fp->f_data;
refcount_acquire(&efd->efd_refcount);
return (efd);
}
void
eventfd_put(struct eventfd *efd)
{
if (!refcount_release(&efd->efd_refcount))
return;
seldrain(&efd->efd_sel);
knlist_destroy(&efd->efd_sel.si_note);
mtx_destroy(&efd->efd_lock);
free(efd, M_EVENTFD);
}
static int
eventfd_close(struct file *fp, struct thread *td)
{
struct eventfd *efd;
efd = fp->f_data;
seldrain(&efd->efd_sel);
knlist_destroy(&efd->efd_sel.si_note);
mtx_destroy(&efd->efd_lock);
free(efd, M_EVENTFD);
eventfd_put(efd);
return (0);
}
+4
View File
@@ -38,8 +38,12 @@ typedef uint64_t eventfd_t;
#ifdef _KERNEL
struct eventfd;
int eventfd_create_file(struct thread *td, struct file *fp, uint32_t initval,
int flags);
struct eventfd *eventfd_get(struct file *fp);
void eventfd_put(struct eventfd *efd);
#else