git: b89104dfd5cf - main - null: support EVFILT_READ/EVFILT_WRITE kevent filters

From: Pietro Cerutti <gahr_at_FreeBSD.org>
Date: Mon, 11 Aug 2025 20:31:35 UTC
The branch main has been updated by gahr:

URL: https://cgit.FreeBSD.org/src/commit/?id=b89104dfd5cf001b34963b9e02083027f9d215d5

commit b89104dfd5cf001b34963b9e02083027f9d215d5
Author:     Pietro Cerutti <gahr@FreeBSD.org>
AuthorDate: 2025-08-07 20:24:06 +0000
Commit:     Pietro Cerutti <gahr@FreeBSD.org>
CommitDate: 2025-08-11 20:31:01 +0000

    null: support EVFILT_READ/EVFILT_WRITE kevent filters
    
    This enhances the full, null, and zero devices to support read and write kevent filters.
    
    A read event is immediately triggered for full and null, and never for zero.
    A write event is immediately triggered for zero and null, and never for full.
    
    Reviewed by:            cognet
    MFC after:              1 week
    Differential Revision:  https://reviews.freebsd.org/D51807
---
 sys/dev/null/null.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)

diff --git a/sys/dev/null/null.c b/sys/dev/null/null.c
index 7ffc618e63ee..8525eb9543c3 100644
--- a/sys/dev/null/null.c
+++ b/sys/dev/null/null.c
@@ -4,6 +4,7 @@
  * Copyright (c) 2000 Mark R. V. Murray & Jeroen C. van Gelderen
  * Copyright (c) 2001-2004 Mark R. V. Murray
  * Copyright (c) 2014 Eitan Adler
+ * Copyright (c) 2025 Pietro Cerutti
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -39,6 +40,7 @@
 #include <sys/disk.h>
 #include <sys/bus.h>
 #include <sys/filio.h>
+#include <sys/event.h>
 
 #include <machine/bus.h>
 #include <machine/vmparam.h>
@@ -53,12 +55,26 @@ static d_write_t null_write;
 static d_ioctl_t null_ioctl;
 static d_ioctl_t zero_ioctl;
 static d_read_t zero_read;
+static d_kqfilter_t kqfilter;
+static int one_ev(struct knote *kn, long hint);
+static int zero_ev(struct knote *kn, long hint);
+
+static const struct filterops one_fop = {
+	.f_isfd =	1,
+	.f_event =	one_ev
+};
+
+static const struct filterops zero_fop = {
+	.f_isfd =	1,
+	.f_event =	zero_ev
+};
 
 static struct cdevsw full_cdevsw = {
 	.d_version =	D_VERSION,
 	.d_read =	zero_read,
 	.d_write =	full_write,
 	.d_ioctl =	zero_ioctl,
+	.d_kqfilter =	kqfilter,
 	.d_name =	"full",
 };
 
@@ -67,6 +83,7 @@ static struct cdevsw null_cdevsw = {
 	.d_read =	(d_read_t *)nullop,
 	.d_write =	null_write,
 	.d_ioctl =	null_ioctl,
+	.d_kqfilter =	kqfilter,
 	.d_name =	"null",
 };
 
@@ -75,6 +92,7 @@ static struct cdevsw zero_cdevsw = {
 	.d_read =	zero_read,
 	.d_write =	null_write,
 	.d_ioctl =	zero_ioctl,
+	.d_kqfilter =	kqfilter,
 	.d_name =	"zero",
 	.d_flags =	D_MMAP_ANON,
 };
@@ -197,5 +215,35 @@ null_modevent(module_t mod __unused, int type, void *data __unused)
 	return (0);
 }
 
+static int
+one_ev(struct knote *kn, long hint)
+{
+
+	return (1);
+}
+
+static int
+zero_ev(struct knote *kn, long hint)
+{
+
+	return (0);
+}
+
+static int
+kqfilter(struct cdev *dev, struct knote *kn)
+{
+
+	switch (kn->kn_filter) {
+	case EVFILT_READ:
+	    kn->kn_fop = dev->si_devsw == &null_cdevsw ? &zero_fop : &one_fop;
+	    return (0);
+	case EVFILT_WRITE:
+	    kn->kn_fop = dev->si_devsw == &full_cdevsw ? &zero_fop : &one_fop;
+	    return (0);
+	default:
+	    return (EOPNOTSUPP);
+	}
+}
+
 DEV_MODULE(null, null_modevent, NULL);
 MODULE_VERSION(null, 1);