diff options
| author | xtraeme <xtraeme@NetBSD.org> | 2007-11-10 09:32:24 +0000 |
|---|---|---|
| committer | xtraeme <xtraeme@NetBSD.org> | 2007-11-10 09:32:24 +0000 |
| commit | 91551751e7fa1e882ce8224c90d49a83a971c97c (patch) | |
| tree | cda917b152293f7e901da2bbc4417027cb1a46f1 /sys/dev/sysmon | |
| parent | 110566cad5a8c3a18a553966d0f4564b776d786d (diff) | |
Add another flag that is set only when the event was enqueued
(and its dictionary created) successfully and use it in the
POWER_EVENT_RECVDICT ioctl to check if the dictionary is ready before
calling prop_dictionary_copyout_ioctl().
This fixes a rare condition when too many events are enqueued and
there wasn't time to create the dictionary, so prop_dictionary_copyout_ioctl()
fails with a NULL pointer dereference.
Diffstat (limited to 'sys/dev/sysmon')
| -rw-r--r-- | sys/dev/sysmon/sysmon_power.c | 27 |
1 files changed, 16 insertions, 11 deletions
diff --git a/sys/dev/sysmon/sysmon_power.c b/sys/dev/sysmon/sysmon_power.c index a75d0b586d0..167c6398aaa 100644 --- a/sys/dev/sysmon/sysmon_power.c +++ b/sys/dev/sysmon/sysmon_power.c @@ -1,4 +1,4 @@ -/* $NetBSD: sysmon_power.c,v 1.29 2007/10/10 23:25:40 xtraeme Exp $ */ +/* $NetBSD: sysmon_power.c,v 1.30 2007/11/10 09:32:24 xtraeme Exp $ */ /*- * Copyright (c) 2007 Juan Romero Pardines. @@ -69,7 +69,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sysmon_power.c,v 1.29 2007/10/10 23:25:40 xtraeme Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sysmon_power.c,v 1.30 2007/11/10 09:32:24 xtraeme Exp $"); #include "opt_compat_netbsd.h" #include <sys/param.h> @@ -156,6 +156,7 @@ static const struct power_event_description penvsys_type_desc[] = { #define SYSMON_MAX_POWER_EVENTS 32 #define SYSMON_POWER_DICTIONARY_BUSY 0x01 +#define SYSMON_POWER_DICTIONARY_READY 0x02 static power_event_t sysmon_power_event_queue[SYSMON_MAX_POWER_EVENTS]; static int sysmon_power_event_queue_head; @@ -265,7 +266,7 @@ sysmon_power_daemon_task(struct power_event_dictionary *ped, power_event_t pev; int rv, error = 0; - if (!pev_data) + if (!ped || !ped->dict || !pev_data) return EINVAL; mutex_enter(&sysmon_power_event_queue_mtx); @@ -342,12 +343,6 @@ sysmon_power_daemon_task(struct power_event_dictionary *ped, } /* - * The dictionary for the event was created successfully - * at this point, time to add it into the list. - */ - SLIST_INSERT_HEAD(&pev_dict_list, ped, pev_dict_head); - - /* * Enqueue the event. */ rv = sysmon_queue_power_event(&pev); @@ -359,8 +354,11 @@ sysmon_power_daemon_task(struct power_event_dictionary *ped, goto out; } else { /* - * Notify the daemon that an event is ready. + * Notify the daemon that an event is ready and its + * dictionary is ready to be fetched. */ + ped->flags |= SYSMON_POWER_DICTIONARY_READY; + SLIST_INSERT_HEAD(&pev_dict_list, ped, pev_dict_head); cv_broadcast(&sysmon_power_event_queue_cv); mutex_exit(&sysmon_power_event_queue_mtx); selnotify(&sysmon_power_event_queue_selinfo, 0); @@ -563,12 +561,18 @@ sysmonioctl_power(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) */ mutex_enter(&sysmon_power_event_queue_mtx); ped = SLIST_FIRST(&pev_dict_list); - if (!ped) { + if (!ped || !ped->dict) { mutex_exit(&sysmon_power_event_queue_mtx); error = ENOTSUP; break; } + if ((ped->flags & SYSMON_POWER_DICTIONARY_READY) == 0) { + mutex_exit(&sysmon_power_event_queue_mtx); + error = EINVAL; + break; + } + if (ped->flags & SYSMON_POWER_DICTIONARY_BUSY) { mutex_exit(&sysmon_power_event_queue_mtx); error = EBUSY; @@ -590,6 +594,7 @@ sysmonioctl_power(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) */ mutex_enter(&sysmon_power_event_queue_mtx); ped->flags &= ~SYSMON_POWER_DICTIONARY_BUSY; + ped->flags &= ~SYSMON_POWER_DICTIONARY_READY; SLIST_REMOVE_HEAD(&pev_dict_list, pev_dict_head); mutex_exit(&sysmon_power_event_queue_mtx); sysmon_power_destroy_dictionary(ped); |
