Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F167806609
D6825.id17538.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
10 KB
Referenced Files
None
Subscribers
None
D6825.id17538.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D6825: Fix several races in ntptime code and provide fine-grained locking for ntptime and resettodr().
Attached
Detach File
Event Timeline
Log In to Comment