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:
+30
-4
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user