tree: https://git.kernel.org/pub/scm/linux/kernel/git/tglx/devel.git hrtimer head: 16c372aeaca31d5d9d998466e75e845a2926685f commit: 6161421a8190f07b3c0a52c0b62c8b3f51de6ddf [8/12] hrtimer: Avoid reprogramming when callback is running config: um-x86_64_defconfig (attached as .config) compiler: gcc-9 (Debian 9.3.0-22) 9.3.0 reproduce (this is a W=1 build): # https://git.kernel.org/pub/scm/linux/kernel/git/tglx/devel.git/commit/?id=6161421a8190f07b3c0a52c0b62c8b3f51de6ddf git remote add tglx-devel https://git.kernel.org/pub/scm/linux/kernel/git/tglx/devel.git git fetch --no-tags tglx-devel hrtimer git checkout 6161421a8190f07b3c0a52c0b62c8b3f51de6ddf # save the attached .config to linux build tree make W=1 ARCH=um SUBARCH=x86_64 If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot All warnings (new ones prefixed by >>): kernel/time/hrtimer.c:120:21: warning: initialized field overwritten [-Woverride-init] 120 | [CLOCK_REALTIME] = HRTIMER_BASE_REALTIME, | ^~~~~~~~~~~~~~~~~~~~~ kernel/time/hrtimer.c:120:21: note: (near initialization for 'hrtimer_clock_to_base_table[0]') kernel/time/hrtimer.c:121:22: warning: initialized field overwritten [-Woverride-init] 121 | [CLOCK_MONOTONIC] = HRTIMER_BASE_MONOTONIC, | ^~~~~~~~~~~~~~~~~~~~~~ kernel/time/hrtimer.c:121:22: note: (near initialization for 'hrtimer_clock_to_base_table[1]') kernel/time/hrtimer.c:122:21: warning: initialized field overwritten [-Woverride-init] 122 | [CLOCK_BOOTTIME] = HRTIMER_BASE_BOOTTIME, | ^~~~~~~~~~~~~~~~~~~~~ kernel/time/hrtimer.c:122:21: note: (near initialization for 'hrtimer_clock_to_base_table[7]') kernel/time/hrtimer.c:123:17: warning: initialized field overwritten [-Woverride-init] 123 | [CLOCK_TAI] = HRTIMER_BASE_TAI, | ^~~~~~~~~~~~~~~~ kernel/time/hrtimer.c:123:17: note: (near initialization for 'hrtimer_clock_to_base_table[11]') kernel/time/hrtimer.c: In function '__hrtimer_start_range_ns': >> kernel/time/hrtimer.c:1232:44: warning: suggest parentheses around comparison in operand of '|' [-Wparentheses] 1232 | force_local &= base->cpu_base->next_timer == timer | in_callback; | ~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~ kernel/time/hrtimer.c: In function '__run_hrtimer': kernel/time/hrtimer.c:1652:7: warning: variable 'expires_in_hardirq' set but not used [-Wunused-but-set-variable] 1652 | bool expires_in_hardirq; | ^~~~~~~~~~~~~~~~~~ vim +1232 kernel/time/hrtimer.c 1211 1212 static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, 1213 u64 delta_ns, const enum hrtimer_mode mode, 1214 struct hrtimer_clock_base *base) 1215 { 1216 struct hrtimer_clock_base *new_base; 1217 bool in_callback, force_local, first; 1218 1219 /* 1220 * If the timer is on the local cpu base and is the first expiring 1221 * timer then this might end up reprogramming the hardware twice 1222 * (on removal and on enqueue). To avoid that by prevent the 1223 * reprogram on removal, keep the timer local to the current CPU 1224 * and enforce reprogramming after it is queued no matter whether 1225 * it is the new first expiring timer again or not. 1226 * 1227 * Also avoid reprogramming if the timer callback is currently 1228 * running. 1229 */ 1230 in_callback = base->running == timer; 1231 force_local = base->cpu_base == this_cpu_ptr(&hrtimer_bases); > 1232 force_local &= base->cpu_base->next_timer == timer | in_callback; 1233 1234 /* 1235 * Remove an active timer from the queue. In case it is not queued 1236 * on the current CPU, make sure that remove_hrtimer() updates the 1237 * remote data correctly. 1238 * 1239 * If it's on the current CPU and the first expiring timer, then 1240 * skip reprogramming, keep the timer local and enforce 1241 * reprogramming later if it was the first expiring timer. This 1242 * avoids programming the underlying clock event twice (once at 1243 * removal and once after enqueue). 1244 */ 1245 remove_hrtimer(timer, base, true, force_local); 1246 1247 if (mode & HRTIMER_MODE_REL) 1248 tim = ktime_add_safe(tim, base->get_time()); 1249 1250 tim = hrtimer_update_lowres(timer, tim, mode); 1251 1252 hrtimer_set_expires_range_ns(timer, tim, delta_ns); 1253 1254 /* Switch the timer base, if necessary: */ 1255 if (!force_local) { 1256 new_base = switch_hrtimer_base(timer, base, 1257 mode & HRTIMER_MODE_PINNED); 1258 } else { 1259 new_base = base; 1260 } 1261 1262 first = enqueue_hrtimer(timer, new_base, mode); 1263 if (!force_local || in_callback) 1264 return first; 1265 1266 /* 1267 * Timer was forced to stay on the current CPU to avoid 1268 * reprogramming on removal and enqueue. Force reprogram the 1269 * hardware by evaluating the new first expiring timer. 1270 */ 1271 hrtimer_force_reprogram(new_base->cpu_base, 1); 1272 return 0; 1273 } 1274 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org