diff options
-rw-r--r-- | sys/dev/hotplug.c | 99 |
1 files changed, 68 insertions, 31 deletions
diff --git a/sys/dev/hotplug.c b/sys/dev/hotplug.c index 1d33606df52..ae38f0fea55 100644 --- a/sys/dev/hotplug.c +++ b/sys/dev/hotplug.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hotplug.c,v 1.23 2023/09/08 20:00:27 mvs Exp $ */ +/* $OpenBSD: hotplug.c,v 1.24 2023/09/22 22:12:32 mvs Exp $ */ /* * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org> * @@ -22,27 +22,39 @@ #include <sys/param.h> #include <sys/systm.h> #include <sys/device.h> +#include <sys/event.h> #include <sys/fcntl.h> #include <sys/hotplug.h> #include <sys/ioctl.h> -#include <sys/selinfo.h> +#include <sys/mutex.h> #include <sys/vnode.h> #define HOTPLUG_MAXEVENTS 64 +/* + * Locks used to protect struct members and global data + * M hotplug_mtx + */ + +static struct mutex hotplug_mtx = MUTEX_INITIALIZER(IPL_MPFLOOR); + static int opened; static struct hotplug_event evqueue[HOTPLUG_MAXEVENTS]; -static int evqueue_head, evqueue_tail, evqueue_count; -static struct selinfo hotplug_sel; +static int evqueue_head, evqueue_tail, evqueue_count; /* [M] */ +static struct klist hotplug_klist; /* [M] */ void filt_hotplugrdetach(struct knote *); int filt_hotplugread(struct knote *, long); +int filt_hotplugmodify(struct kevent *, struct knote *); +int filt_hotplugprocess(struct knote *, struct kevent *); const struct filterops hotplugread_filtops = { - .f_flags = FILTEROP_ISFD, + .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE, .f_attach = NULL, .f_detach = filt_hotplugrdetach, .f_event = filt_hotplugread, + .f_modify = filt_hotplugmodify, + .f_process = filt_hotplugprocess, }; #define EVQUEUE_NEXT(p) (p == HOTPLUG_MAXEVENTS - 1 ? 0 : p + 1) @@ -60,6 +72,8 @@ hotplugattach(int count) evqueue_head = 0; evqueue_tail = 0; evqueue_count = 0; + + klist_init_mutex(&hotplug_klist, &hotplug_mtx); } void @@ -87,7 +101,9 @@ hotplug_device_detach(enum devclass class, char *name) int hotplug_put_event(struct hotplug_event *he) { + mtx_enter(&hotplug_mtx); if (evqueue_count == HOTPLUG_MAXEVENTS && opened) { + mtx_leave(&hotplug_mtx); printf("hotplug: event lost, queue full\n"); return (1); } @@ -98,24 +114,21 @@ hotplug_put_event(struct hotplug_event *he) evqueue_tail = EVQUEUE_NEXT(evqueue_tail); else evqueue_count++; + knote_locked(&hotplug_klist, 0); wakeup(&evqueue); - selwakeup(&hotplug_sel); + mtx_leave(&hotplug_mtx); return (0); } int hotplug_get_event(struct hotplug_event *he) { - int s; - if (evqueue_count == 0) return (1); - s = splbio(); *he = evqueue[evqueue_tail]; evqueue_tail = EVQUEUE_NEXT(evqueue_tail); evqueue_count--; - splx(s); return (0); } @@ -137,8 +150,11 @@ hotplugclose(dev_t dev, int flag, int mode, struct proc *p) { struct hotplug_event he; + mtx_enter(&hotplug_mtx); while (hotplug_get_event(&he) == 0) continue; + mtx_leave(&hotplug_mtx); + klist_invalidate(&hotplug_klist); opened = 0; return (0); } @@ -152,16 +168,23 @@ hotplugread(dev_t dev, struct uio *uio, int flags) if (uio->uio_resid != sizeof(he)) return (EINVAL); -again: - if (hotplug_get_event(&he) == 0) - return (uiomove(&he, sizeof(he), uio)); - if (flags & IO_NDELAY) - return (EAGAIN); + mtx_enter(&hotplug_mtx); + while (hotplug_get_event(&he)) { + if (flags & IO_NDELAY) { + mtx_leave(&hotplug_mtx); + return (EAGAIN); + } + + error = msleep_nsec(&evqueue, &hotplug_mtx, PRIBIO | PCATCH, + "htplev", INFSLP); + if (error) { + mtx_leave(&hotplug_mtx); + return (error); + } + } + mtx_leave(&hotplug_mtx); - error = tsleep_nsec(&evqueue, PRIBIO | PCATCH, "htplev", INFSLP); - if (error) - return (error); - goto again; + return (uiomove(&he, sizeof(he), uio)); } int @@ -183,32 +206,22 @@ hotplugioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) int hotplugkqfilter(dev_t dev, struct knote *kn) { - struct klist *klist; - int s; - switch (kn->kn_filter) { case EVFILT_READ: - klist = &hotplug_sel.si_note; kn->kn_fop = &hotplugread_filtops; break; default: return (EINVAL); } - s = splbio(); - klist_insert_locked(klist, kn); - splx(s); + klist_insert(&hotplug_klist, kn); return (0); } void filt_hotplugrdetach(struct knote *kn) { - int s; - - s = splbio(); - klist_remove_locked(&hotplug_sel.si_note, kn); - splx(s); + klist_remove(&hotplug_klist, kn); } int @@ -218,3 +231,27 @@ filt_hotplugread(struct knote *kn, long hint) return (evqueue_count > 0); } + +int +filt_hotplugmodify(struct kevent *kev, struct knote *kn) +{ + int active; + + mtx_enter(&hotplug_mtx); + active = knote_modify(kev, kn); + mtx_leave(&hotplug_mtx); + + return (active); +} + +int +filt_hotplugprocess(struct knote *kn, struct kevent *kev) +{ + int active; + + mtx_enter(&hotplug_mtx); + active = knote_process(kn, kev); + mtx_leave(&hotplug_mtx); + + return (active); +} |