Page MenuHomeFreeBSD

D6825.id17538.diff
No OneTemporary

D6825.id17538.diff

Index: sys/kern/kern_ntptime.c
===================================================================
--- sys/kern/kern_ntptime.c
+++ sys/kern/kern_ntptime.c
@@ -162,6 +162,30 @@
static int64_t time_adjtime; /* correction from adjtime(2) (usec) */
+static struct mtx ntpadj_lock;
+MTX_SYSINIT(ntpadj, &ntpadj_lock, "ntpadj",
+#ifdef PPS_SYNC
+ MTX_SPIN
+#else
+ MTX_DEF
+#endif
+);
+
+/*
+ * When PPS_SYNC is defined, hardpps() function is provided which can
+ * be legitimately called from interrupt filters. Due to this, use
+ * spinlock for ntptime state protection, otherwise sleepable mutex is
+ * adequate.
+ */
+#ifdef PPS_SYNC
+#define NTPADJ_LOCK() mtx_lock_spin(&ntpadj_lock)
+#define NTPADJ_UNLOCK() mtx_unlock_spin(&ntpadj_lock)
+#else
+#define NTPADJ_LOCK() mtx_lock(&ntpadj_lock)
+#define NTPADJ_UNLOCK() mtx_unlock(&ntpadj_lock)
+#endif
+#define NTPADJ_ASSERT_LOCKED() mtx_assert(&ntpadj_lock, MA_OWNED)
+
#ifdef PPS_SYNC
/*
* The following variables are used when a pulse-per-second (PPS) signal
@@ -203,11 +227,12 @@
static void ntp_init(void);
static void hardupdate(long offset);
static void ntp_gettime1(struct ntptimeval *ntvp);
-static int ntp_is_time_error(void);
+static bool ntp_is_time_error(int time_status);
-static int
-ntp_is_time_error(void)
+static bool
+ntp_is_time_error(int time_status)
{
+
/*
* Status word error decode. If any of these conditions occur,
* an error is returned, instead of the status word. Most
@@ -237,9 +262,9 @@
*/
(time_status & STA_PPSFREQ &&
time_status & (STA_PPSWANDER | STA_PPSERROR)))
- return (1);
+ return (true);
- return (0);
+ return (false);
}
static void
@@ -247,7 +272,7 @@
{
struct timespec atv; /* nanosecond time */
- GIANT_REQUIRED;
+ NTPADJ_ASSERT_LOCKED();
nanotime(&atv);
ntvp->time.tv_sec = atv.tv_sec;
@@ -257,7 +282,7 @@
ntvp->tai = time_tai;
ntvp->time_state = time_state;
- if (ntp_is_time_error())
+ if (ntp_is_time_error(time_status))
ntvp->time_state = TIME_ERROR;
}
@@ -278,9 +303,9 @@
{
struct ntptimeval ntv;
- mtx_lock(&Giant);
+ NTPADJ_LOCK();
ntp_gettime1(&ntv);
- mtx_unlock(&Giant);
+ NTPADJ_UNLOCK();
td->td_retval[0] = ntv.time_state;
return (copyout(&ntv, uap->ntvp, sizeof(ntv)));
@@ -291,14 +316,17 @@
{
struct ntptimeval ntv; /* temporary structure */
+ NTPADJ_LOCK();
ntp_gettime1(&ntv);
+ NTPADJ_UNLOCK();
return (sysctl_handle_opaque(oidp, &ntv, sizeof(ntv), req));
}
SYSCTL_NODE(_kern, OID_AUTO, ntp_pll, CTLFLAG_RW, 0, "");
-SYSCTL_PROC(_kern_ntp_pll, OID_AUTO, gettime, CTLTYPE_OPAQUE|CTLFLAG_RD,
- 0, sizeof(struct ntptimeval) , ntp_sysctl, "S,ntptimeval", "");
+SYSCTL_PROC(_kern_ntp_pll, OID_AUTO, gettime, CTLTYPE_OPAQUE | CTLFLAG_RD |
+ CTLFLAG_MPSAFE, 0, sizeof(struct ntptimeval) , ntp_sysctl, "S,ntptimeval",
+ "");
#ifdef PPS_SYNC
SYSCTL_INT(_kern_ntp_pll, OID_AUTO, pps_shiftmax, CTLFLAG_RW,
@@ -308,10 +336,12 @@
SYSCTL_LONG(_kern_ntp_pll, OID_AUTO, time_monitor, CTLFLAG_RD,
&time_monitor, 0, "Last time offset scaled (ns)");
-SYSCTL_OPAQUE(_kern_ntp_pll, OID_AUTO, pps_freq, CTLFLAG_RD,
- &pps_freq, sizeof(pps_freq), "I", "Scaled frequency offset (ns/sec)");
-SYSCTL_OPAQUE(_kern_ntp_pll, OID_AUTO, time_freq, CTLFLAG_RD,
- &time_freq, sizeof(time_freq), "I", "Frequency offset (ns/sec)");
+SYSCTL_S64(_kern_ntp_pll, OID_AUTO, pps_freq, CTLFLAG_RD | CTLFLAG_MPSAFE,
+ &pps_freq, 0,
+ "Scaled frequency offset (ns/sec)");
+SYSCTL_S64(_kern_ntp_pll, OID_AUTO, time_freq, CTLFLAG_RD | CTLFLAG_MPSAFE,
+ &time_freq, 0,
+ "Frequency offset (ns/sec)");
#endif
/*
@@ -333,12 +363,12 @@
struct timex ntv; /* temporary structure */
long freq; /* frequency ns/s) */
int modes; /* mode bits from structure */
- int s; /* caller priority */
int error;
+ bool terror;
error = copyin((caddr_t)uap->tp, (caddr_t)&ntv, sizeof(ntv));
if (error)
- return(error);
+ return (error);
/*
* Update selected clock variables - only the superuser can
@@ -349,13 +379,12 @@
* the STA_PLL bit in the status word is cleared, the state and
* status words are reset to the initial values at boot.
*/
- mtx_lock(&Giant);
modes = ntv.modes;
if (modes)
error = priv_check(td, PRIV_NTP_ADJTIME);
- if (error)
- goto done2;
- s = splclock();
+ if (error != 0)
+ return (error);
+ NTPADJ_LOCK();
if (modes & MOD_MAXERROR)
time_maxerror = ntv.maxerror;
if (modes & MOD_ESTERROR)
@@ -456,19 +485,12 @@
ntv.jitcnt = pps_jitcnt;
ntv.stbcnt = pps_stbcnt;
#endif /* PPS_SYNC */
- splx(s);
+ terror = ntp_is_time_error(time_status);
+ NTPADJ_UNLOCK();
error = copyout((caddr_t)&ntv, (caddr_t)uap->tp, sizeof(ntv));
- if (error)
- goto done2;
-
- if (ntp_is_time_error())
- td->td_retval[0] = TIME_ERROR;
- else
- td->td_retval[0] = time_state;
-
-done2:
- mtx_unlock(&Giant);
+ if (error == 0)
+ td->td_retval[0] = terror ? TIME_ERROR : time_state;
return (error);
}
@@ -620,7 +642,7 @@
* probably be integrated with the code that does that.
*/
static void
-ntp_init()
+ntp_init(void)
{
/*
@@ -670,6 +692,8 @@
long mtemp;
l_fp ftemp;
+ NTPADJ_ASSERT_LOCKED();
+
/*
* Select how the phase is to be controlled and from which
* source. If the PPS signal is present and enabled to
@@ -750,6 +774,8 @@
long u_sec, u_nsec, v_nsec; /* temps */
l_fp ftemp;
+ NTPADJ_LOCK();
+
/*
* The signal is first processed by a range gate and frequency
* discriminator. The range gate rejects noise spikes outside
@@ -770,9 +796,10 @@
u_sec++;
}
v_nsec = u_nsec - pps_tf[0].tv_nsec;
- if (u_sec == pps_tf[0].tv_sec && v_nsec < NANOSECOND -
- MAXFREQ)
+ if (u_sec == pps_tf[0].tv_sec && v_nsec < NANOSECOND - MAXFREQ) {
+ NTPADJ_UNLOCK();
return;
+ }
pps_tf[2] = pps_tf[1];
pps_tf[1] = pps_tf[0];
pps_tf[0].tv_sec = u_sec;
@@ -792,8 +819,10 @@
else if (u_nsec < -(NANOSECOND >> 1))
u_nsec += NANOSECOND;
pps_fcount += u_nsec;
- if (v_nsec > MAXFREQ || v_nsec < -MAXFREQ)
+ if (v_nsec > MAXFREQ || v_nsec < -MAXFREQ) {
+ NTPADJ_UNLOCK();
return;
+ }
time_status &= ~STA_PPSJITTER;
/*
@@ -839,7 +868,7 @@
* timecounter running faster than 1 GHz the lower bound is 2ns, just
* to avoid a nonsensical threshold of zero.
*/
- if (u_nsec > lmax(pps_jitter << PPS_POPCORN,
+ if (u_nsec > lmax(pps_jitter << PPS_POPCORN,
2 * (NANOSECOND / (long)qmin(NANOSECOND, tc_getfrequency())))) {
time_status |= STA_PPSJITTER;
pps_jitcnt++;
@@ -849,8 +878,10 @@
}
pps_jitter += (u_nsec - pps_jitter) >> PPS_FAVG;
u_sec = pps_tf[0].tv_sec - pps_lastsec;
- if (u_sec < (1 << pps_shift))
+ if (u_sec < (1 << pps_shift)) {
+ NTPADJ_UNLOCK();
return;
+ }
/*
* At the end of the calibration interval the difference between
@@ -867,10 +898,10 @@
pps_lastsec = pps_tf[0].tv_sec;
pps_fcount = 0;
u_nsec = MAXFREQ << pps_shift;
- if (v_nsec > u_nsec || v_nsec < -u_nsec || u_sec != (1 <<
- pps_shift)) {
+ if (v_nsec > u_nsec || v_nsec < -u_nsec || u_sec != (1 << pps_shift)) {
time_status |= STA_PPSERROR;
pps_errcnt++;
+ NTPADJ_UNLOCK();
return;
}
@@ -932,6 +963,8 @@
L_LINT(pps_freq, -MAXFREQ);
if (time_status & STA_PPSFREQ)
time_freq = pps_freq;
+
+ NTPADJ_UNLOCK();
}
#endif /* PPS_SYNC */
@@ -965,27 +998,29 @@
kern_adjtime(struct thread *td, struct timeval *delta, struct timeval *olddelta)
{
struct timeval atv;
+ int64_t ltr, ltw;
int error;
- mtx_lock(&Giant);
- if (olddelta) {
- atv.tv_sec = time_adjtime / 1000000;
- atv.tv_usec = time_adjtime % 1000000;
+ if (delta != NULL) {
+ error = priv_check(td, PRIV_ADJTIME);
+ if (error != 0)
+ return (error);
+ ltw = (int64_t)delta->tv_sec * 1000000 + delta->tv_usec;
+ }
+ NTPADJ_LOCK();
+ ltr = time_adjtime;
+ if (delta != NULL)
+ time_adjtime = ltw;
+ NTPADJ_UNLOCK();
+ if (olddelta != NULL) {
+ atv.tv_sec = ltr / 1000000;
+ atv.tv_usec = ltr % 1000000;
if (atv.tv_usec < 0) {
atv.tv_usec += 1000000;
atv.tv_sec--;
}
*olddelta = atv;
}
- if (delta) {
- if ((error = priv_check(td, PRIV_ADJTIME))) {
- mtx_unlock(&Giant);
- return (error);
- }
- time_adjtime = (int64_t)delta->tv_sec * 1000000 +
- delta->tv_usec;
- }
- mtx_unlock(&Giant);
return (0);
}
@@ -996,11 +1031,8 @@
periodic_resettodr(void *arg __unused)
{
- if (!ntp_is_time_error()) {
- mtx_lock(&Giant);
+ if (!ntp_is_time_error(time_status))
resettodr();
- mtx_unlock(&Giant);
- }
if (resettodr_period > 0)
callout_schedule(&resettodr_callout, resettodr_period * hz);
}
@@ -1010,11 +1042,8 @@
{
callout_drain(&resettodr_callout);
- if (resettodr_period > 0 && !ntp_is_time_error()) {
- mtx_lock(&Giant);
+ if (resettodr_period > 0 && !ntp_is_time_error(time_status))
resettodr();
- mtx_unlock(&Giant);
- }
}
static int
@@ -1036,9 +1065,9 @@
return (0);
}
-SYSCTL_PROC(_machdep, OID_AUTO, rtc_save_period, CTLTYPE_INT|CTLFLAG_RWTUN,
- &resettodr_period, 1800, sysctl_resettodr_period, "I",
- "Save system time to RTC with this period (in seconds)");
+SYSCTL_PROC(_machdep, OID_AUTO, rtc_save_period, CTLTYPE_INT | CTLFLAG_RWTUN |
+ CTLFLAG_MPSAFE, &resettodr_period, 1800, sysctl_resettodr_period, "I",
+ "Save system time to RTC with this period (in seconds)");
static void
start_periodic_resettodr(void *arg __unused)
Index: sys/kern/subr_clock.c
===================================================================
--- sys/kern/subr_clock.c
+++ sys/kern/subr_clock.c
@@ -67,8 +67,8 @@
resettodr();
return (error);
}
-SYSCTL_PROC(_machdep, OID_AUTO, adjkerntz, CTLTYPE_INT|CTLFLAG_RW,
- &adjkerntz, 0, sysctl_machdep_adjkerntz, "I",
+SYSCTL_PROC(_machdep, OID_AUTO, adjkerntz, CTLTYPE_INT | CTLFLAG_RW |
+ CTLFLAG_MPSAFE, &adjkerntz, 0, sysctl_machdep_adjkerntz, "I",
"Local offset from UTC in seconds");
static int ct_debug;
Index: sys/kern/subr_rtc.c
===================================================================
--- sys/kern/subr_rtc.c
+++ sys/kern/subr_rtc.c
@@ -62,6 +62,8 @@
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/clock.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
#include <sys/sysctl.h>
#ifdef FFCLOCK
#include <sys/timeffc.h>
@@ -73,6 +75,8 @@
static device_t clock_dev = NULL;
static long clock_res;
static struct timespec clock_adj;
+static struct mtx resettodr_lock;
+MTX_SYSINIT(resettodr_init, &resettodr_lock, "tod2rl", MTX_DEF);
/* XXX: should be kern. now, it's no longer machdep. */
static int disable_rtc_set;
@@ -168,11 +172,14 @@
if (disable_rtc_set || clock_dev == NULL)
return;
+ mtx_lock(&resettodr_lock);
getnanotime(&ts);
timespecadd(&ts, &clock_adj);
ts.tv_sec -= utc_offset();
/* XXX: We should really set all registered RTCs */
- if ((error = CLOCK_SETTIME(clock_dev, &ts)) != 0)
+ error = CLOCK_SETTIME(clock_dev, &ts);
+ mtx_unlock(&resettodr_lock);
+ if (error != 0)
printf("warning: clock_settime failed (%d), time-of-day clock "
"not adjusted to system time\n", error);
}

File Metadata

Mime Type
text/plain
Expires
Tue, Aug 25, 4:55 PM (3 h, 11 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
37198715
Default Alt Text
D6825.id17538.diff (10 KB)

Event Timeline