History

kdb: use __ktime_get_real_seconds instead of __current_kernel_time

kdb is the only user of the __current_kernel_time() interface, which is not y2038 safe and should be removed at some point. The kdb code also goes to great lengths to print the time in a human-readable format from 'struct timespec', again using a non-y2038-safe re-implementation of the generic time_to_tm() code. Using __current_kernel_time() here is necessary since the regular accessors that require a sequence lock might hang when called during the xtime update. However, this is safe in the particular case since kdb is only interested in the tv_sec field that is updated atomically. In order to make this y2038-safe, I'm converting the code to the generic time64_to_tm helper, but that introduces the problem that we have no interface like __current_kernel_time() that provides a 64-bit timestamp in a lockless, safe and architecture-independent way. I have multiple ideas for how to solve that: - __ktime_get_real_seconds() is lockless, but can return incorrect results on 32-bit architectures in the special case that we are in the process of changing the time across the epoch, either during the timer tick that overflows the seconds in 2038, or while calling settimeofday. - ktime_get_real_fast_ns() would work in this context, but does require a call into the clocksource driver to return a high-resolution timestamp. This may have undesired side-effects in the debugger, since we want to limit the interactions with the rest of the kernel. - Adding a ktime_get_real_fast_seconds() based on tk_fast_mono plus tkr->base_real without the tk_clock_read() delta. Not sure about the value of adding yet another interface here. - Changing the existing ktime_get_real_seconds() to use tk_fast_mono on 32-bit architectures rather than xtime_sec. I think this could work, but am not entirely sure if this is an improvement. I picked the first of those for simplicity here. It's technically not correct but probably good enough as the time is only used for the debugging output and the race will likely never be hit in practice. Another downside is having to move the declaration into a public header file. Let me know if anyone has a different preference.

Arnd Bergmann committed 9 years ago

Commit 6909e291 parent 0296c243 files · +6 −42Browse files

Showing the changes to kernel/debug (1 of 3 files). Show all

Unified · Split

kernel/debug/kdb/kdb_main.c+5−40
@@ -2479,41 +2479,6 @@ static int kdb_kill(int argc, const char **argv) · 2478 unmodified lines
24792479 return 0;
24802480 }
24812481
2482−struct kdb_tm {
2483− int tm_sec; /* seconds */
2484− int tm_min; /* minutes */
2485− int tm_hour; /* hours */
2486− int tm_mday; /* day of the month */
2487− int tm_mon; /* month */
2488− int tm_year; /* year */
2489−};
2490−
2491−static void kdb_gmtime(struct timespec *tv, struct kdb_tm *tm)
2492−{
2493− /* This will work from 1970-2099, 2100 is not a leap year */
2494− static int mon_day[] = { 31, 29, 31, 30, 31, 30, 31,
2495− 31, 30, 31, 30, 31 };
2496− memset(tm, 0, sizeof(*tm));
2497− tm->tm_sec = tv->tv_sec % (24 * 60 * 60);
2498− tm->tm_mday = tv->tv_sec / (24 * 60 * 60) +
2499− (2 * 365 + 1); /* shift base from 1970 to 1968 */
2500− tm->tm_min = tm->tm_sec / 60 % 60;
2501− tm->tm_hour = tm->tm_sec / 60 / 60;
2502− tm->tm_sec = tm->tm_sec % 60;
2503− tm->tm_year = 68 + 4*(tm->tm_mday / (4*365+1));
2504− tm->tm_mday %= (4*365+1);
2505− mon_day[1] = 29;
2506− while (tm->tm_mday >= mon_day[tm->tm_mon]) {
2507− tm->tm_mday -= mon_day[tm->tm_mon];
2508− if (++tm->tm_mon == 12) {
2509− tm->tm_mon = 0;
2510− ++tm->tm_year;
2511− mon_day[1] = 28;
2512− }
2513− }
2514− ++tm->tm_mday;
2515−}
2516−
25172482 /*
25182483 * Most of this code has been lifted from kernel/timer.c::sys_sysinfo().
25192484 * I cannot call that code directly from kdb, it has an unconditional
@@ -2539,8 +2504,8 @@ static void kdb_sysinfo(struct sysinfo *val) · 19 unmodified lines
25392504 */
25402505 static int kdb_summary(int argc, const char **argv)
25412506 {
2542− struct timespec now;
2543− struct kdb_tm tm;
2507+ time64_t now;
2508+ struct tm tm;
25442509 struct sysinfo val;
25452510
25462511 if (argc)
@@ -2554,9 +2519,9 @@ static int kdb_summary(int argc, const char **argv) · 7 unmodified lines
25542519 kdb_printf("domainname %s\n", init_uts_ns.name.domainname);
25552520 kdb_printf("ccversion %s\n", __stringify(CCVERSION));
25562521
2557− now = __current_kernel_time();
2558− kdb_gmtime(&now, &tm);
2559− kdb_printf("date %04d-%02d-%02d %02d:%02d:%02d "
2522+ now = __ktime_get_real_seconds();
2523+ time64_to_tm(now, 0, &tm);
2524+ kdb_printf("date %04ld-%02d-%02d %02d:%02d:%02d "
25602525 "tz_minuteswest %d\n",
25612526 1900+tm.tm_year, tm.tm_mon+1, tm.tm_mday,
25622527 tm.tm_hour, tm.tm_min, tm.tm_sec,

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t