Module Name:    src
Committed By:   thorpej
Date:           Wed Jan  1 21:09:12 UTC 2020

Modified Files:
        src/sys/dev: clock_subr.h
        src/sys/kern: init_main.c kern_todr.c

Log Message:
First steps towards properly serializing access to the TOD clock.
- Add a mutex around the TODR, and provide lock/unlock/lock-owned
  functions to manipulate it.
- Rename inittodr() to todr_set_systime() and resettodr() to
  todr_save_systime() to better reflect what they do.  These functions
  are intended to be called with the TODR lock held, which will allow
  for a pattern like:
        -> todr_lock()
        -> todr_save_systime()
        -> [do machine-dependent stuff to sleep/suspend]
        -> [magically awaken]
        -> todr_set_systime(...)
        -> todr_unlock()
- Provide historically-named wrappers inittodr() and resettodr() that
  do the dance of acquiring / releasing the lock around the actual
  substance.

NOTE: resettodr()'s use of the TODR lock is currently disabled (and
todr_save_systime() does not assert it's held) until such time as
issues around shutdown / reboot under duress can be addressed.


To generate a diff of this commit:
cvs rdiff -u -r1.28 -r1.29 src/sys/dev/clock_subr.h
cvs rdiff -u -r1.514 -r1.515 src/sys/kern/init_main.c
cvs rdiff -u -r1.43 -r1.44 src/sys/kern/kern_todr.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/clock_subr.h
diff -u src/sys/dev/clock_subr.h:1.28 src/sys/dev/clock_subr.h:1.29
--- src/sys/dev/clock_subr.h:1.28	Wed Jan  1 19:24:03 2020
+++ src/sys/dev/clock_subr.h	Wed Jan  1 21:09:11 2020
@@ -1,7 +1,7 @@
-/*	$NetBSD: clock_subr.h,v 1.28 2020/01/01 19:24:03 thorpej Exp $	*/
+/*	$NetBSD: clock_subr.h,v 1.29 2020/01/01 21:09:11 thorpej Exp $	*/
 
 /*-
- * Copyright (c) 1996 The NetBSD Foundation, Inc.
+ * Copyright (c) 1996, 2020 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -93,10 +93,13 @@ struct todr_chip_handle {
 };
 typedef struct todr_chip_handle *todr_chip_handle_t;
 
-/*
- * Machine-dependent function that machine-independent RTC drivers can
- * use to register their todr_chip_handle_t with inittodr()/resettodr().
- */
+void	todr_init(void);
 void	todr_attach(todr_chip_handle_t);
+void	todr_lock(void);
+void	todr_unlock(void);
+bool	todr_lock_owned(void);
+
+void	todr_set_systime(time_t base);
+void	todr_save_systime(void);
 
 #endif /* _DEV_CLOCK_SUBR_H_ */

Index: src/sys/kern/init_main.c
diff -u src/sys/kern/init_main.c:1.514 src/sys/kern/init_main.c:1.515
--- src/sys/kern/init_main.c:1.514	Tue Dec 31 13:07:13 2019
+++ src/sys/kern/init_main.c	Wed Jan  1 21:09:11 2020
@@ -1,7 +1,7 @@
-/*	$NetBSD: init_main.c,v 1.514 2019/12/31 13:07:13 ad Exp $	*/
+/*	$NetBSD: init_main.c,v 1.515 2020/01/01 21:09:11 thorpej Exp $	*/
 
 /*-
- * Copyright (c) 2008, 2009, 2019 The NetBSD Foundation, Inc.
+ * Copyright (c) 2008, 2009, 2019, The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -97,7 +97,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.514 2019/12/31 13:07:13 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.515 2020/01/01 21:09:11 thorpej Exp $");
 
 #include "opt_ddb.h"
 #include "opt_inet.h"
@@ -204,6 +204,8 @@ extern void *_binary_splash_image_end;
 
 #include <sys/pax.h>
 
+#include <dev/clock_subr.h>
+
 #include <secmodel/secmodel.h>
 
 #include <ufs/ufs/quota.h>
@@ -298,6 +300,7 @@ main(void)
 
 	kernel_lock_init();
 	once_init();
+	todr_init();
 
 	mi_cpu_init();
 	kernconfig_lock_init();

Index: src/sys/kern/kern_todr.c
diff -u src/sys/kern/kern_todr.c:1.43 src/sys/kern/kern_todr.c:1.44
--- src/sys/kern/kern_todr.c:1.43	Wed Jan  1 19:24:03 2020
+++ src/sys/kern/kern_todr.c	Wed Jan  1 21:09:11 2020
@@ -1,4 +1,33 @@
-/*	$NetBSD: kern_todr.c,v 1.43 2020/01/01 19:24:03 thorpej Exp $	*/
+/*	$NetBSD: kern_todr.c,v 1.44 2020/01/01 21:09:11 thorpej Exp $	*/
+
+/*-
+ * Copyright (c) 2020 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
 
 /*
  * Copyright (c) 1988 University of Utah.
@@ -41,7 +70,7 @@
 #include "opt_todr.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_todr.c,v 1.43 2020/01/01 19:24:03 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_todr.c,v 1.44 2020/01/01 21:09:11 thorpej Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -50,35 +79,98 @@ __KERNEL_RCSID(0, "$NetBSD: kern_todr.c,
 #include <sys/timetc.h>
 #include <sys/intr.h>
 #include <sys/rndsource.h>
+#include <sys/mutex.h>
 
 #include <dev/clock_subr.h>	/* hmm.. this should probably move to sys */
 
 static int todr_gettime(todr_chip_handle_t, struct timeval *);
 static int todr_settime(todr_chip_handle_t, struct timeval *);
 
-static todr_chip_handle_t todr_handle = NULL;
+static kmutex_t todr_mutex;
+static todr_chip_handle_t todr_handle;
+static bool todr_initialized;
+
+/*
+ * todr_init:
+ *	Initialize TOD clock data.
+ */
+void
+todr_init(void)
+{
+
+	mutex_init(&todr_mutex, MUTEX_DEFAULT, IPL_NONE);
+	todr_initialized = true;
+}
+
+/*
+ * todr_lock:
+ *	Acquire the TODR lock.
+ */
+void
+todr_lock(void)
+{
+
+	mutex_enter(&todr_mutex);
+}
+
+/*
+ * todr_unlock:
+ *	Release the TODR lock.
+ */
+void
+todr_unlock(void)
+{
+
+	mutex_exit(&todr_mutex);
+}
+
+/*
+ * todr_lock_owned:
+ *	Return true if the current thread owns the TODR lock.
+ *	This is to be used by diagnostic assertions only.
+ */
+bool
+todr_lock_owned(void)
+{
+
+	return mutex_owned(&todr_mutex) ? true : false;
+}
 
 /*
- * Attach the clock device to todr_handle.
+ * todr_attach:
+ *	Attach the clock device to todr_handle.
  */
 void
 todr_attach(todr_chip_handle_t todr)
 {
 
+	/*
+	 * todr_init() is called very early in main(), but this is
+	 * here to catch a case where todr_attach() is called before
+	 * main().
+	 */
+	KASSERT(todr_initialized);
+
+	todr_lock();
 	if (todr_handle) {
+		todr_unlock();
 		printf("todr_attach: TOD already configured\n");
 		return;
 	}
 	todr_handle = todr;
+	todr_unlock();
 }
 
 static bool timeset = false;
 
 /*
- * Set up the system's time, given a `reasonable' time value.
+ * todr_set_systime:
+ *	Set up the system's time.  The "base" argument is a best-guess
+ *	close-enough value to use if the TOD clock is unavailable or
+ *	contains garbage.  Must be called with the TODR lock held.
  */
 void
-inittodr(time_t base)
+todr_set_systime(time_t base)
 {
 	bool badbase = false;
 	bool waszero = (base == 0);
@@ -87,6 +179,8 @@ inittodr(time_t base)
 	struct timespec ts;
 	struct timeval tv;
 
+	KASSERT(todr_lock_owned());
+
 	rnd_add_data(NULL, &base, sizeof(base), 0);
 
 	if (base < 5 * SECS_PER_COMMON_YEAR) {
@@ -180,17 +274,19 @@ inittodr(time_t base)
 }
 
 /*
- * Reset the TODR based on the time value; used when the TODR
- * has a preposterous value and also when the time is reset
- * by the stime system call.  Also called when the TODR goes past
- * TODRZERO + 100*(SECS_PER_COMMON_YEAR+2*SECS_PER_DAY)
- * (e.g. on Jan 2 just after midnight) to wrap the TODR around.
+ * todr_save_systime:
+ *	Save the current system time back to the TOD clock.
+ *	Must be called with the TODR lock held.
  */
 void
-resettodr(void)
+todr_save_systime(void)
 {
 	struct timeval tv;
 
+#if notyet
+	KASSERT(todr_lock_owned());
+#endif
+
 	/*
 	 * We might have been called by boot() due to a crash early
 	 * on.  Don't reset the clock chip if we don't know what time
@@ -209,6 +305,47 @@ resettodr(void)
 			printf("Cannot set TOD clock time\n");
 }
 
+/*
+ * inittodr:
+ *	Legacy wrapper around todr_set_systime().
+ */
+void
+inittodr(time_t base)
+{
+
+	todr_lock();
+	todr_set_systime(base);
+	todr_unlock();
+}
+
+/*
+ * resettodr:
+ *	Legacy wrapper around todr_save_systime().
+ */
+void
+resettodr(void)
+{
+
+#if notyet
+	/*
+	 * If we're shutting down, we don't want to get stuck in case
+	 * someone was already fiddling with the TOD clock.
+	 */
+	if (shutting_down) {
+		if (mutex_tryenter(&todr_mutex) == 0) {
+			printf("WARNING: Cannot set TOD clock time (busy)\n");
+			return;
+		}
+	} else {
+		todr_lock();
+	}
+#endif
+	todr_save_systime();
+#if notyet
+	todr_unlock();
+#endif
+}
+
 #ifdef	TODR_DEBUG
 static void
 todr_debug(const char *prefix, int rv, struct clock_ymdhms *dt,

Reply via email to