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,