Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/sysmon Improve tracking of the state of an event's c...



details:   https://anonhg.NetBSD.org/src/rev/d21f1c838c3c
branches:  trunk
changeset: 826536:d21f1c838c3c
user:      pgoyette <pgoyette%NetBSD.org@localhost>
date:      Mon Sep 11 06:02:09 2017 +0000

description:
Improve tracking of the state of an event's callout, and protect all
queries or modifications of the state with the sme_mtx mutex.

Detach the rndsrc before re-attaching it (with potentially new values).

Clean up some lock-ordering issues.

And a couple of KNF issues for good measure!

Should address PR kern/52533

XXX Pullup-8 along with the previous fixes from msaitoh@
XXX http://mail-index.netbsd.org/source-changes/2017/09/06/msg088028.html
~
~

diffstat:

 sys/dev/sysmon/sysmon_envsys.c        |  45 +++++++++++++++++++++++++------
 sys/dev/sysmon/sysmon_envsys_events.c |  49 ++++++++++++++++++++---------------
 sys/dev/sysmon/sysmonvar.h            |   9 +++++-
 3 files changed, 71 insertions(+), 32 deletions(-)

diffs (285 lines):

diff -r d6897caa1b90 -r d21f1c838c3c sys/dev/sysmon/sysmon_envsys.c
--- a/sys/dev/sysmon/sysmon_envsys.c    Mon Sep 11 05:25:53 2017 +0000
+++ b/sys/dev/sysmon/sysmon_envsys.c    Mon Sep 11 06:02:09 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: sysmon_envsys.c,v 1.140 2017/09/06 11:08:53 msaitoh Exp $      */
+/*     $NetBSD: sysmon_envsys.c,v 1.141 2017/09/11 06:02:09 pgoyette Exp $     */
 
 /*-
  * Copyright (c) 2007, 2008 Juan Romero Pardines.
@@ -64,7 +64,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sysmon_envsys.c,v 1.140 2017/09/06 11:08:53 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sysmon_envsys.c,v 1.141 2017/09/11 06:02:09 pgoyette Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -525,6 +525,8 @@
 {
        struct sysmon_envsys *sme;
 
+       CTASSERT(SME_CALLOUT_INVALID == 0);
+
        sme = kmem_zalloc(sizeof(*sme), KM_SLEEP);
        TAILQ_INIT(&sme->sme_sensors_list);
        LIST_INIT(&sme->sme_events_list);
@@ -654,7 +656,8 @@
                rnd_detach_source(&oedata->rnd_src);
        sme_event_unregister_sensor(sme, edata);
        if (LIST_EMPTY(&sme->sme_events_list)) {
-               sme_events_halt_callout(sme);
+               if (sme->sme_callout_state == SME_CALLOUT_READY)
+                       sme_events_halt_callout(sme);
                destroy = true;
        }
        TAILQ_REMOVE(&sme->sme_sensors_list, edata, sensors_head);
@@ -1269,15 +1272,23 @@
                        }
 
                        /*
-                        * Finally, remove any old limits event, then
-                        * install a new event (which will update the
-                        * dictionary)
+                        * If the sensor is providing entropy data,
+                        * get rid of the rndsrc;  we'll provide a new
+                        * one shortly.
+                        */
+                       if (edata->flags & ENVSYS_FHAS_ENTROPY)
+                               rnd_detach_source(&edata->rnd_src);
+
+                       /*
+                        * Remove the old limits event, if any
                         */
                        sme_event_unregister(sme, edata->desc,
                            PENVSYS_EVENT_LIMITS);
 
                        /*
-                        * Find the correct units for this sensor.
+                        * Create and install a new event (which will
+                        * update the dictionary) with the correct
+                        * units.
                         */
                        sdt_units = sme_find_table_entry(SME_DESC_UNITS,
                            edata->units);
@@ -1290,6 +1301,11 @@
                                    &lims, props, PENVSYS_EVENT_LIMITS,
                                    sdt_units->crittype);
                        }
+
+                       /* Finally, if the sensor provides entropy,
+                        * create an additional event entry and attach
+                        * the rndsrc
+                        */
                        if (edata->flags & ENVSYS_FHAS_ENTROPY) {
                                sme_event_register(sdict, edata, sme,
                                    &lims, props, PENVSYS_EVENT_NULL,
@@ -1308,8 +1324,17 @@
                 * Restore default timeout value.
                 */
                sme->sme_events_timeout = SME_EVENTS_DEFTIMEOUT;
+
+               /*
+                * Note that we need to hold the sme_mtx while calling
+                * sme_schedule_callout().  Thus to avoid dropping,
+                * reacquiring, and dropping it again, we just tell
+                * sme_envsys_release() that the mutex is already owned.
+                */
+               mutex_enter(&sme->sme_mtx);
                sme_schedule_callout(sme);
-               sysmon_envsys_release(sme, false);
+               sysmon_envsys_release(sme, true);
+               mutex_exit(&sme->sme_mtx);
        }
        mutex_exit(&sme_global_mtx);
 }
@@ -1350,7 +1375,9 @@
         */
        if (sme->sme_events_timeout == 0) {
                sme->sme_events_timeout = SME_EVENTS_DEFTIMEOUT;
+               mutex_enter(&sme->sme_mtx);
                sme_schedule_callout(sme);
+               mutex_exit(&sme->sme_mtx);
        }
 
        if (!prop_dictionary_set_uint64(pdict, "refresh-timeout",
@@ -1824,7 +1851,7 @@
                                        sme_schedule_callout(sme);
                                }
                                mutex_exit(&sme->sme_mtx);
-               }
+                       }
                }
                return error;
 
diff -r d6897caa1b90 -r d21f1c838c3c sys/dev/sysmon/sysmon_envsys_events.c
--- a/sys/dev/sysmon/sysmon_envsys_events.c     Mon Sep 11 05:25:53 2017 +0000
+++ b/sys/dev/sysmon/sysmon_envsys_events.c     Mon Sep 11 06:02:09 2017 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: sysmon_envsys_events.c,v 1.120 2017/09/06 11:08:53 msaitoh Exp $ */
+/* $NetBSD: sysmon_envsys_events.c,v 1.121 2017/09/11 06:02:09 pgoyette Exp $ */
 
 /*-
  * Copyright (c) 2007, 2008 Juan Romero Pardines.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sysmon_envsys_events.c,v 1.120 2017/09/06 11:08:53 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sysmon_envsys_events.c,v 1.121 2017/09/11 06:02:09 pgoyette Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -313,7 +313,7 @@
        /*
         * Initialize the events framework if it wasn't initialized before.
         */
-       if ((sme->sme_flags & SME_CALLOUT_INITIALIZED) == 0)
+       if (sme->sme_callout_state == SME_CALLOUT_INVALID)
                error = sme_events_init(sme);
 
        /*
@@ -374,7 +374,7 @@
        }
 
        if (LIST_EMPTY(&sme->sme_events_list) &&
-           sme->sme_flags & SME_CALLOUT_INITIALIZED) {
+           sme->sme_callout_state == SME_CALLOUT_READY) {
                sme_events_halt_callout(sme);
                destroy = true;
        }
@@ -570,7 +570,7 @@
 
        callout_init(&sme->sme_callout, CALLOUT_MPSAFE);
        callout_setfunc(&sme->sme_callout, sme_events_check, sme);
-       sme->sme_flags |= SME_CALLOUT_INITIALIZED;
+       sme->sme_callout_state = SME_CALLOUT_READY;
        sme_schedule_callout(sme);
        DPRINTF(("%s: events framework initialized for '%s'\n",
            __func__, sme->sme_name));
@@ -589,8 +589,9 @@
        uint64_t timo;
 
        KASSERT(sme != NULL);
+       KASSERT(mutex_owned(&sme->sme_mtx));
 
-       if ((sme->sme_flags & SME_CALLOUT_INITIALIZED) == 0)
+       if (sme->sme_callout_state != SME_CALLOUT_READY)
                return;
 
        if (sme->sme_events_timeout)
@@ -610,14 +611,18 @@
 void
 sme_events_halt_callout(struct sysmon_envsys *sme)
 {
+
        KASSERT(mutex_owned(&sme->sme_mtx));
+       KASSERT(sme->sme_callout_state == SME_CALLOUT_READY);
 
        /*
-        * Unset before callout_halt to ensure callout is not scheduled again
-        * during callout_halt.
+        * Set HALTED before callout_halt to ensure callout is not
+        * scheduled again during callout_halt.  (callout_halt()
+        * can potentially release the mutex, so an active callout
+        * could reschedule itself if it grabs the mutex.)
         */
-       sme->sme_flags &= ~SME_CALLOUT_INITIALIZED;
 
+       sme->sme_callout_state = SME_CALLOUT_HALTED;
        callout_halt(&sme->sme_callout, &sme->sme_mtx);
 }
 
@@ -630,11 +635,15 @@
 void
 sme_events_destroy(struct sysmon_envsys *sme)
 {
+
        KASSERT(!mutex_owned(&sme->sme_mtx));
-       KASSERT((sme->sme_flags & SME_CALLOUT_INITIALIZED) == 0);
 
-       callout_destroy(&sme->sme_callout);
-       workqueue_destroy(sme->sme_wq);
+       if (sme->sme_callout_state == SME_CALLOUT_HALTED) {
+               callout_destroy(&sme->sme_callout);
+               sme->sme_callout_state = SME_CALLOUT_INVALID;
+               workqueue_destroy(sme->sme_wq);
+       }
+       KASSERT(sme->sme_callout_state == SME_CALLOUT_INVALID);
 
        DPRINTF(("%s: events framework destroyed for '%s'\n",
            __func__, sme->sme_name));
@@ -734,13 +743,7 @@
                mutex_exit(&sme->sme_work_mtx);
                return;
        }
-       if (!mutex_tryenter(&sme->sme_mtx)) {
-               /* can't get lock - try again later */
-               if (!sysmon_low_power)
-                       sme_schedule_callout(sme);
-               mutex_exit(&sme->sme_work_mtx);
-               return;
-       }
+       mutex_enter(&sme->sme_mtx);
        LIST_FOREACH(see, &sme->sme_events_list, see_list) {
                workqueue_enqueue(sme->sme_wq, &see->see_wk, NULL);
                see->see_edata->flags |= ENVSYS_FNEED_REFRESH;
@@ -748,8 +751,8 @@
        }
        if (!sysmon_low_power)
                sme_schedule_callout(sme);
+       mutex_exit(&sme->sme_mtx);
        mutex_exit(&sme->sme_work_mtx);
-       mutex_exit(&sme->sme_mtx);
 }
 
 /*
@@ -1003,12 +1006,16 @@
                 */
                if (!sysmon_low_power && sme_event_check_low_power()) {
                        struct penvsys_state pes;
+                       struct sysmon_envsys *sme = see->see_sme;
 
                        /*
                         * Stop the callout and send the 'low-power' event.
                         */
                        sysmon_low_power = true;
-                       callout_stop(&see->see_sme->sme_callout);
+                       KASSERT(mutex_owned(&sme->sme_mtx));
+                       KASSERT(sme->sme_callout_state == SME_CALLOUT_READY);
+                       callout_stop(&sme->sme_callout);
+                       sme->sme_callout_state = SME_CALLOUT_HALTED;
                        pes.pes_type = PENVSYS_TYPE_BATTERY;
                        sysmon_penvsys_event(&pes, PENVSYS_EVENT_LOW_POWER);
                }
diff -r d6897caa1b90 -r d21f1c838c3c sys/dev/sysmon/sysmonvar.h
--- a/sys/dev/sysmon/sysmonvar.h        Mon Sep 11 05:25:53 2017 +0000
+++ b/sys/dev/sysmon/sysmonvar.h        Mon Sep 11 06:02:09 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: sysmonvar.h,v 1.49 2015/04/23 23:22:03 pgoyette Exp $  */
+/*     $NetBSD: sysmonvar.h,v 1.50 2017/09/11 06:02:09 pgoyette Exp $  */
 
 /*-
  * Copyright (c) 2000 Zembu Labs, Inc.
@@ -163,7 +163,6 @@
        int sme_flags;                  /* additional flags */
 #define SME_FLAG_BUSY          0x00000001      /* device busy */
 #define SME_DISABLE_REFRESH    0x00000002      /* disable sme_refresh */
-#define SME_CALLOUT_INITIALIZED        0x00000004      /* callout was initialized */
 #define SME_INIT_REFRESH        0x00000008      /* call sme_refresh() after
                                                   interrupts are enabled in
                                                   the autoconf(9) process. */
@@ -187,6 +186,12 @@
 
        struct workqueue *sme_wq;       /* the workqueue for the events */
        struct callout sme_callout;     /* for the events */
+       int sme_callout_state;          /* state of the event's callout */
+
+#define        SME_CALLOUT_INVALID     0x0     /* callout is not initialized */
+#define        SME_CALLOUT_READY       0x1     /* callout is ready for use */
+#define        SME_CALLOUT_HALTED      0x2     /* callout can be destroyed */
+
        uint64_t sme_events_timeout;    /* the timeout used in the callout */
 
        /* 



Home | Main Index | Thread Index | Old Index