* [tip:timers/core 2/58] kernel/time/posix-cpu-timers.c:1307:9: sparse: sparse: incorrect type in argument 1 (different address spaces)
@ 2026-08-12 19:40 kernel test robot
2026-08-12 19:42 ` Bradley Morgan
0 siblings, 1 reply; 3+ messages in thread
From: kernel test robot @ 2026-08-12 19:40 UTC (permalink / raw)
To: Oleg Nesterov
Cc: oe-kbuild-all, linux-kernel, x86, Thomas Gleixner, Bradley Morgan
tree: https://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
head: 4fa377c19e111c539a530a8200996b911ceff9ff
commit: a73d7f98e41a96d6e1bcb0e731ab185d9d67878e [2/58] posix-cpu-timers: Don't abuse lock_task_sighand() in handle_posix_cpu_timers()
config: microblaze-randconfig-r122-20260812 (https://download.01.org/0day-ci/archive/20260813/202608130320.o3cNs7Lr-lkp@intel.com/config)
compiler: microblaze-linux-gcc (GCC) 11.5.0
sparse: v0.6.5-rc1
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260813/202608130320.o3cNs7Lr-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202608130320.o3cNs7Lr-lkp@intel.com/
sparse warnings: (new ones prefixed by >>)
>> kernel/time/posix-cpu-timers.c:1307:9: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct spinlock [usertype] *lock @@ got struct spinlock [noderef] __rcu * @@
kernel/time/posix-cpu-timers.c:1307:9: sparse: expected struct spinlock [usertype] *lock
kernel/time/posix-cpu-timers.c:1307:9: sparse: got struct spinlock [noderef] __rcu *
kernel/time/posix-cpu-timers.c:1367:36: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct spinlock [usertype] *lock @@ got struct spinlock [noderef] __rcu * @@
kernel/time/posix-cpu-timers.c:1367:36: sparse: expected struct spinlock [usertype] *lock
kernel/time/posix-cpu-timers.c:1367:36: sparse: got struct spinlock [noderef] __rcu *
kernel/time/posix-cpu-timers.c: note: in included file:
include/linux/sched/signal.h:749:37: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct spinlock [usertype] *lock @@ got struct spinlock [noderef] __rcu * @@
include/linux/sched/signal.h:749:37: sparse: expected struct spinlock [usertype] *lock
include/linux/sched/signal.h:749:37: sparse: got struct spinlock [noderef] __rcu *
include/linux/sched/signal.h:749:37: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct spinlock [usertype] *lock @@ got struct spinlock [noderef] __rcu * @@
include/linux/sched/signal.h:749:37: sparse: expected struct spinlock [usertype] *lock
include/linux/sched/signal.h:749:37: sparse: got struct spinlock [noderef] __rcu *
include/linux/sched/signal.h:749:37: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct spinlock [usertype] *lock @@ got struct spinlock [noderef] __rcu * @@
include/linux/sched/signal.h:749:37: sparse: expected struct spinlock [usertype] *lock
include/linux/sched/signal.h:749:37: sparse: got struct spinlock [noderef] __rcu *
include/linux/sched/signal.h:749:37: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct spinlock [usertype] *lock @@ got struct spinlock [noderef] __rcu * @@
include/linux/sched/signal.h:749:37: sparse: expected struct spinlock [usertype] *lock
include/linux/sched/signal.h:749:37: sparse: got struct spinlock [noderef] __rcu *
include/linux/sched/signal.h:749:37: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct spinlock [usertype] *lock @@ got struct spinlock [noderef] __rcu * @@
include/linux/sched/signal.h:749:37: sparse: expected struct spinlock [usertype] *lock
include/linux/sched/signal.h:749:37: sparse: got struct spinlock [noderef] __rcu *
vim +1307 kernel/time/posix-cpu-timers.c
1296
1297 static void handle_posix_cpu_timers(struct task_struct *tsk)
1298 {
1299 struct k_itimer *timer, *next;
1300 unsigned long flags, start;
1301 LIST_HEAD(firing);
1302
1303 /*
1304 * tsk is current and ->sighand is stable, see the
1305 * tsk->exit_state check in run_posix_cpu_timers()
1306 */
> 1307 spin_lock_irqsave(&tsk->sighand->siglock, flags);
1308
1309 do {
1310 /*
1311 * On RT locking sighand lock does not disable interrupts,
1312 * so this needs to be careful vs. ticks. Store the current
1313 * jiffies value.
1314 */
1315 start = READ_ONCE(jiffies);
1316 barrier();
1317
1318 /*
1319 * Here we take off tsk->signal->cpu_timers[N] and
1320 * tsk->cpu_timers[N] all the timers that are firing, and
1321 * put them on the firing list.
1322 */
1323 check_thread_timers(tsk, &firing);
1324
1325 check_process_timers(tsk, &firing);
1326
1327 /*
1328 * The above timer checks have updated the expiry cache and
1329 * because nothing can have queued or modified timers after
1330 * sighand lock was taken above it is guaranteed to be
1331 * consistent. So the next timer interrupt fastpath check
1332 * will find valid data.
1333 *
1334 * If timer expiry runs in the timer interrupt context then
1335 * the loop is not relevant as timers will be directly
1336 * expired in interrupt context. The stub function below
1337 * returns always true which allows the compiler to
1338 * optimize the loop out.
1339 *
1340 * If timer expiry is deferred to task work context then
1341 * the following rules apply:
1342 *
1343 * - On !RT kernels no tick can have happened on this CPU
1344 * after sighand lock was acquired because interrupts are
1345 * disabled. So reenabling task work before dropping
1346 * sighand lock and reenabling interrupts is race free.
1347 *
1348 * - On RT kernels ticks might have happened but the tick
1349 * work ignored posix CPU timer handling because the
1350 * CPUTIMERS_WORK_SCHEDULED bit is set. Reenabling work
1351 * must be done very carefully including a check whether
1352 * ticks have happened since the start of the timer
1353 * expiry checks. posix_cpu_timers_enable_work() takes
1354 * care of that and eventually lets the expiry checks
1355 * run again.
1356 */
1357 } while (!posix_cpu_timers_enable_work(tsk, start));
1358
1359 /*
1360 * We must release sighand lock before taking any timer's lock.
1361 * There is a potential race with timer deletion here, as the
1362 * siglock now protects our private firing list. We have set
1363 * the firing flag in each timer, so that a deletion attempt
1364 * that gets the timer lock before we do will give it up and
1365 * spin until we've taken care of that timer below.
1366 */
1367 spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
1368
1369 /*
1370 * Now that all the timers on our list have the firing flag,
1371 * no one will touch their list entries but us. We'll take
1372 * each timer's lock before clearing its firing flag, so no
1373 * timer call will interfere.
1374 */
1375 list_for_each_entry_safe(timer, next, &firing, it.cpu.elist) {
1376 bool cpu_firing;
1377
1378 /*
1379 * spin_lock() is sufficient here even independent of the
1380 * expiry context. If expiry happens in hard interrupt
1381 * context it's obvious. For task work context it's safe
1382 * because all other operations on timer::it_lock happen in
1383 * task context (syscall or exit).
1384 */
1385 spin_lock(&timer->it_lock);
1386 list_del_init(&timer->it.cpu.elist);
1387 cpu_firing = timer->it.cpu.firing;
1388 timer->it.cpu.firing = false;
1389 /*
1390 * If the firing flag is cleared then this raced with a
1391 * timer rearm/delete operation. So don't generate an
1392 * event.
1393 */
1394 if (likely(cpu_firing))
1395 cpu_timer_fire(timer);
1396 /* See posix_cpu_timer_wait_running() */
1397 rcu_assign_pointer(timer->it.cpu.handling, NULL);
1398 spin_unlock(&timer->it_lock);
1399 }
1400 }
1401
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [tip:timers/core 2/58] kernel/time/posix-cpu-timers.c:1307:9: sparse: sparse: incorrect type in argument 1 (different address spaces)
2026-08-12 19:40 [tip:timers/core 2/58] kernel/time/posix-cpu-timers.c:1307:9: sparse: sparse: incorrect type in argument 1 (different address spaces) kernel test robot
@ 2026-08-12 19:42 ` Bradley Morgan
2026-08-13 4:55 ` Bradley Morgan
0 siblings, 1 reply; 3+ messages in thread
From: Bradley Morgan @ 2026-08-12 19:42 UTC (permalink / raw)
To: kernel test robot, Oleg Nesterov
Cc: oe-kbuild-all, linux-kernel, x86, Thomas Gleixner
On 12 August 2026 20:40:00 BST, kernel test robot <lkp@intel.com> wrote:
>tree: https://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
>head: 4fa377c19e111c539a530a8200996b911ceff9ff
>commit: a73d7f98e41a96d6e1bcb0e731ab185d9d67878e [2/58] posix-cpu-timers: Don't abuse lock_task_sighand() in handle_posix_cpu_timers()
>config: microblaze-randconfig-r122-20260812 (https://download.01.org/0day-ci/archive/20260813/202608130320.o3cNs7Lr-lkp@intel.com/config)
>compiler: microblaze-linux-gcc (GCC) 11.5.0
>sparse: v0.6.5-rc1
>reproduce (this is a W=1 build):
>(https://download.01.org/0day-ci/archive/20260813/202608130320.o3cNs7Lr-lkp@intel.com/reproduce)
>
>If you fix the issue in a separate patch/commit (i.e. not just a new
>version of
>the same patch/commit), kindly add following tags
>| Reported-by: kernel test robot <lkp@intel.com>
>| Closes:
>https://lore.kernel.org/oe-kbuild-all/202608130320.o3cNs7Lr-lkp@intel.com/
>
>sparse warnings: (new ones prefixed by >>)
>>> kernel/time/posix-cpu-timers.c:1307:9: sparse: sparse: incorrect type
>in argument 1 (different address spaces) @@ expected struct spinlock
>[usertype] *lock @@ got struct spinlock [noderef] __rcu * @@
> kernel/time/posix-cpu-timers.c:1307:9: sparse: expected struct spinlock [usertype] *lock
> kernel/time/posix-cpu-timers.c:1307:9: sparse: got struct spinlock [noderef] __rcu *
> kernel/time/posix-cpu-timers.c:1367:36: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct spinlock [usertype] *lock @@ got struct spinlock [noderef] __rcu * @@
> kernel/time/posix-cpu-timers.c:1367:36: sparse: expected struct spinlock [usertype] *lock
> kernel/time/posix-cpu-timers.c:1367:36: sparse: got struct spinlock [noderef] __rcu *
> kernel/time/posix-cpu-timers.c: note: in included file:
> include/linux/sched/signal.h:749:37: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct spinlock [usertype] *lock @@ got struct spinlock [noderef] __rcu * @@
> include/linux/sched/signal.h:749:37: sparse: expected struct spinlock [usertype] *lock
> include/linux/sched/signal.h:749:37: sparse: got struct spinlock [noderef] __rcu *
> include/linux/sched/signal.h:749:37: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct spinlock [usertype] *lock @@ got struct spinlock [noderef] __rcu * @@
> include/linux/sched/signal.h:749:37: sparse: expected struct spinlock [usertype] *lock
> include/linux/sched/signal.h:749:37: sparse: got struct spinlock [noderef] __rcu *
> include/linux/sched/signal.h:749:37: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct spinlock [usertype] *lock @@ got struct spinlock [noderef] __rcu * @@
> include/linux/sched/signal.h:749:37: sparse: expected struct spinlock [usertype] *lock
> include/linux/sched/signal.h:749:37: sparse: got struct spinlock [noderef] __rcu *
> include/linux/sched/signal.h:749:37: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct spinlock [usertype] *lock @@ got struct spinlock [noderef] __rcu * @@
> include/linux/sched/signal.h:749:37: sparse: expected struct spinlock [usertype] *lock
> include/linux/sched/signal.h:749:37: sparse: got struct spinlock [noderef] __rcu *
> include/linux/sched/signal.h:749:37: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct spinlock [usertype] *lock @@ got struct spinlock [noderef] __rcu * @@
> include/linux/sched/signal.h:749:37: sparse: expected struct spinlock [usertype] *lock
> include/linux/sched/signal.h:749:37: sparse: got struct spinlock [noderef] __rcu *
>
>vim +1307 kernel/time/posix-cpu-timers.c
>
> 1296
> 1297 static void handle_posix_cpu_timers(struct task_struct *tsk)
> 1298 {
> 1299 struct k_itimer *timer, *next;
> 1300 unsigned long flags, start;
> 1301 LIST_HEAD(firing);
> 1302
> 1303 /*
> 1304 * tsk is current and ->sighand is stable, see the
> 1305 * tsk->exit_state check in run_posix_cpu_timers()
> 1306 */
>> 1307 spin_lock_irqsave(&tsk->sighand->siglock, flags);
> 1308
> 1309 do {
> 1310 /*
> 1311 * On RT locking sighand lock does not disable interrupts,
> 1312 * so this needs to be careful vs. ticks. Store the current
> 1313 * jiffies value.
> 1314 */
> 1315 start = READ_ONCE(jiffies);
> 1316 barrier();
> 1317
> 1318 /*
> 1319 * Here we take off tsk->signal->cpu_timers[N] and
> 1320 * tsk->cpu_timers[N] all the timers that are firing, and
> 1321 * put them on the firing list.
> 1322 */
> 1323 check_thread_timers(tsk, &firing);
> 1324
> 1325 check_process_timers(tsk, &firing);
> 1326
> 1327 /*
> 1328 * The above timer checks have updated the expiry cache and
> 1329 * because nothing can have queued or modified timers after
> 1330 * sighand lock was taken above it is guaranteed to be
> 1331 * consistent. So the next timer interrupt fastpath check
> 1332 * will find valid data.
> 1333 *
> 1334 * If timer expiry runs in the timer interrupt context then
> 1335 * the loop is not relevant as timers will be directly
> 1336 * expired in interrupt context. The stub function below
> 1337 * returns always true which allows the compiler to
> 1338 * optimize the loop out.
> 1339 *
> 1340 * If timer expiry is deferred to task work context then
> 1341 * the following rules apply:
> 1342 *
> 1343 * - On !RT kernels no tick can have happened on this CPU
> 1344 * after sighand lock was acquired because interrupts are
> 1345 * disabled. So reenabling task work before dropping
> 1346 * sighand lock and reenabling interrupts is race free.
> 1347 *
> 1348 * - On RT kernels ticks might have happened but the tick
> 1349 * work ignored posix CPU timer handling because the
> 1350 * CPUTIMERS_WORK_SCHEDULED bit is set. Reenabling work
> 1351 * must be done very carefully including a check whether
> 1352 * ticks have happened since the start of the timer
> 1353 * expiry checks. posix_cpu_timers_enable_work() takes
> 1354 * care of that and eventually lets the expiry checks
> 1355 * run again.
> 1356 */
> 1357 } while (!posix_cpu_timers_enable_work(tsk, start));
> 1358
> 1359 /*
> 1360 * We must release sighand lock before taking any timer's lock.
> 1361 * There is a potential race with timer deletion here, as the
> 1362 * siglock now protects our private firing list. We have set
> 1363 * the firing flag in each timer, so that a deletion attempt
> 1364 * that gets the timer lock before we do will give it up and
> 1365 * spin until we've taken care of that timer below.
> 1366 */
> 1367 spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
> 1368
> 1369 /*
> 1370 * Now that all the timers on our list have the firing flag,
> 1371 * no one will touch their list entries but us. We'll take
> 1372 * each timer's lock before clearing its firing flag, so no
> 1373 * timer call will interfere.
> 1374 */
> 1375 list_for_each_entry_safe(timer, next, &firing, it.cpu.elist) {
> 1376 bool cpu_firing;
> 1377
> 1378 /*
> 1379 * spin_lock() is sufficient here even independent of the
> 1380 * expiry context. If expiry happens in hard interrupt
> 1381 * context it's obvious. For task work context it's safe
> 1382 * because all other operations on timer::it_lock happen in
> 1383 * task context (syscall or exit).
> 1384 */
> 1385 spin_lock(&timer->it_lock);
> 1386 list_del_init(&timer->it.cpu.elist);
> 1387 cpu_firing = timer->it.cpu.firing;
> 1388 timer->it.cpu.firing = false;
> 1389 /*
> 1390 * If the firing flag is cleared then this raced with a
> 1391 * timer rearm/delete operation. So don't generate an
> 1392 * event.
> 1393 */
> 1394 if (likely(cpu_firing))
> 1395 cpu_timer_fire(timer);
> 1396 /* See posix_cpu_timer_wait_running() */
> 1397 rcu_assign_pointer(timer->it.cpu.handling, NULL);
> 1398 spin_unlock(&timer->it_lock);
> 1399 }
> 1400 }
> 1401
>
>--
>0-DAY CI Kernel Test Service
>https://github.com/intel/lkp-tests/wiki
>
Oleg already addressed to something like this, I think he said to nuke
__rcu, which idm looking at and submitting.
Thanks!
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [tip:timers/core 2/58] kernel/time/posix-cpu-timers.c:1307:9: sparse: sparse: incorrect type in argument 1 (different address spaces)
2026-08-12 19:42 ` Bradley Morgan
@ 2026-08-13 4:55 ` Bradley Morgan
0 siblings, 0 replies; 3+ messages in thread
From: Bradley Morgan @ 2026-08-13 4:55 UTC (permalink / raw)
To: kernel test robot, Oleg Nesterov
Cc: oe-kbuild-all, linux-kernel, x86, Thomas Gleixner
On 12 August 2026 20:42:03 BST, Bradley Morgan <include@grrlz.net> wrote:
>On 12 August 2026 20:40:00 BST, kernel test robot <lkp@intel.com> wrote:
>>tree: https://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git
>timers/core
>>head: 4fa377c19e111c539a530a8200996b911ceff9ff
>>commit: a73d7f98e41a96d6e1bcb0e731ab185d9d67878e [2/58] posix-cpu-timers:
>Don't abuse lock_task_sighand() in handle_posix_cpu_timers()
>>config: microblaze-randconfig-r122-20260812
>(https://download.01.org/0day-ci/archive/20260813/202608130320.o3cNs7Lr-lkp@intel.com/config)
>>compiler: microblaze-linux-gcc (GCC) 11.5.0
>>sparse: v0.6.5-rc1
>>reproduce (this is a W=1 build):
>>(https://download.01.org/0day-ci/archive/20260813/202608130320.o3cNs7Lr-lkp@intel.com/reproduce)
>>
>>If you fix the issue in a separate patch/commit (i.e. not just a new
>>version of
>>the same patch/commit), kindly add following tags
>>| Reported-by: kernel test robot <lkp@intel.com>
>>| Closes:
>>https://lore.kernel.org/oe-kbuild-all/202608130320.o3cNs7Lr-lkp@intel.com/
>>
>>sparse warnings: (new ones prefixed by >>)
>>>> kernel/time/posix-cpu-timers.c:1307:9: sparse: sparse: incorrect type
>>in argument 1 (different address spaces) @@ expected struct spinlock
>>[usertype] *lock @@ got struct spinlock [noderef] __rcu * @@
>> kernel/time/posix-cpu-timers.c:1307:9: sparse: expected struct
>spinlock [usertype] *lock
>> kernel/time/posix-cpu-timers.c:1307:9: sparse: got struct spinlock
>[noderef] __rcu *
>> kernel/time/posix-cpu-timers.c:1367:36: sparse: sparse: incorrect type
>in argument 1 (different address spaces) @@ expected struct spinlock
>[usertype] *lock @@ got struct spinlock [noderef] __rcu * @@
>> kernel/time/posix-cpu-timers.c:1367:36: sparse: expected struct
>spinlock [usertype] *lock
>> kernel/time/posix-cpu-timers.c:1367:36: sparse: got struct
>spinlock [noderef] __rcu *
>> kernel/time/posix-cpu-timers.c: note: in included file:
>> include/linux/sched/signal.h:749:37: sparse: sparse: incorrect type in
>argument 1 (different address spaces) @@ expected struct spinlock
>[usertype] *lock @@ got struct spinlock [noderef] __rcu * @@
>> include/linux/sched/signal.h:749:37: sparse: expected struct
>spinlock [usertype] *lock
>> include/linux/sched/signal.h:749:37: sparse: got struct spinlock
>[noderef] __rcu *
>> include/linux/sched/signal.h:749:37: sparse: sparse: incorrect type in
>argument 1 (different address spaces) @@ expected struct spinlock
>[usertype] *lock @@ got struct spinlock [noderef] __rcu * @@
>> include/linux/sched/signal.h:749:37: sparse: expected struct
>spinlock [usertype] *lock
>> include/linux/sched/signal.h:749:37: sparse: got struct spinlock
>[noderef] __rcu *
>> include/linux/sched/signal.h:749:37: sparse: sparse: incorrect type in
>argument 1 (different address spaces) @@ expected struct spinlock
>[usertype] *lock @@ got struct spinlock [noderef] __rcu * @@
>> include/linux/sched/signal.h:749:37: sparse: expected struct
>spinlock [usertype] *lock
>> include/linux/sched/signal.h:749:37: sparse: got struct spinlock
>[noderef] __rcu *
>> include/linux/sched/signal.h:749:37: sparse: sparse: incorrect type in
>argument 1 (different address spaces) @@ expected struct spinlock
>[usertype] *lock @@ got struct spinlock [noderef] __rcu * @@
>> include/linux/sched/signal.h:749:37: sparse: expected struct
>spinlock [usertype] *lock
>> include/linux/sched/signal.h:749:37: sparse: got struct spinlock
>[noderef] __rcu *
>> include/linux/sched/signal.h:749:37: sparse: sparse: incorrect type in
>argument 1 (different address spaces) @@ expected struct spinlock
>[usertype] *lock @@ got struct spinlock [noderef] __rcu * @@
>> include/linux/sched/signal.h:749:37: sparse: expected struct
>spinlock [usertype] *lock
>> include/linux/sched/signal.h:749:37: sparse: got struct spinlock
>[noderef] __rcu *
>>
>>vim +1307 kernel/time/posix-cpu-timers.c
>>
>> 1296
>> 1297 static void handle_posix_cpu_timers(struct task_struct *tsk)
>> 1298 {
>> 1299 struct k_itimer *timer, *next;
>> 1300 unsigned long flags, start;
>> 1301 LIST_HEAD(firing);
>> 1302
>> 1303 /*
>> 1304 * tsk is current and ->sighand is stable, see the
>> 1305 * tsk->exit_state check in run_posix_cpu_timers()
>> 1306 */
>>> 1307 spin_lock_irqsave(&tsk->sighand->siglock, flags);
>> 1308
>> 1309 do {
>> 1310 /*
>> 1311 * On RT locking sighand lock does not disable interrupts,
>> 1312 * so this needs to be careful vs. ticks. Store the current
>> 1313 * jiffies value.
>> 1314 */
>> 1315 start = READ_ONCE(jiffies);
>> 1316 barrier();
>> 1317
>> 1318 /*
>> 1319 * Here we take off tsk->signal->cpu_timers[N] and
>> 1320 * tsk->cpu_timers[N] all the timers that are firing, and
>> 1321 * put them on the firing list.
>> 1322 */
>> 1323 check_thread_timers(tsk, &firing);
>> 1324
>> 1325 check_process_timers(tsk, &firing);
>> 1326
>> 1327 /*
>> 1328 * The above timer checks have updated the expiry cache and
>> 1329 * because nothing can have queued or modified timers after
>> 1330 * sighand lock was taken above it is guaranteed to be
>> 1331 * consistent. So the next timer interrupt fastpath check
>> 1332 * will find valid data.
>> 1333 *
>> 1334 * If timer expiry runs in the timer interrupt context then
>> 1335 * the loop is not relevant as timers will be directly
>> 1336 * expired in interrupt context. The stub function below
>> 1337 * returns always true which allows the compiler to
>> 1338 * optimize the loop out.
>> 1339 *
>> 1340 * If timer expiry is deferred to task work context then
>> 1341 * the following rules apply:
>> 1342 *
>> 1343 * - On !RT kernels no tick can have happened on this CPU
>> 1344 * after sighand lock was acquired because interrupts are
>> 1345 * disabled. So reenabling task work before dropping
>> 1346 * sighand lock and reenabling interrupts is race free.
>> 1347 *
>> 1348 * - On RT kernels ticks might have happened but the tick
>> 1349 * work ignored posix CPU timer handling because the
>> 1350 * CPUTIMERS_WORK_SCHEDULED bit is set. Reenabling work
>> 1351 * must be done very carefully including a check whether
>> 1352 * ticks have happened since the start of the timer
>> 1353 * expiry checks. posix_cpu_timers_enable_work() takes
>> 1354 * care of that and eventually lets the expiry checks
>> 1355 * run again.
>> 1356 */
>> 1357 } while (!posix_cpu_timers_enable_work(tsk, start));
>> 1358
>> 1359 /*
>> 1360 * We must release sighand lock before taking any timer's lock.
>> 1361 * There is a potential race with timer deletion here, as the
>> 1362 * siglock now protects our private firing list. We have set
>> 1363 * the firing flag in each timer, so that a deletion attempt
>> 1364 * that gets the timer lock before we do will give it up and
>> 1365 * spin until we've taken care of that timer below.
>> 1366 */
>> 1367 spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
>> 1368
>> 1369 /*
>> 1370 * Now that all the timers on our list have the firing flag,
>> 1371 * no one will touch their list entries but us. We'll take
>> 1372 * each timer's lock before clearing its firing flag, so no
>> 1373 * timer call will interfere.
>> 1374 */
>> 1375 list_for_each_entry_safe(timer, next, &firing, it.cpu.elist) {
>> 1376 bool cpu_firing;
>> 1377
>> 1378 /*
>> 1379 * spin_lock() is sufficient here even independent of the
>> 1380 * expiry context. If expiry happens in hard interrupt
>> 1381 * context it's obvious. For task work context it's safe
>> 1382 * because all other operations on timer::it_lock happen in
>> 1383 * task context (syscall or exit).
>> 1384 */
>> 1385 spin_lock(&timer->it_lock);
>> 1386 list_del_init(&timer->it.cpu.elist);
>> 1387 cpu_firing = timer->it.cpu.firing;
>> 1388 timer->it.cpu.firing = false;
>> 1389 /*
>> 1390 * If the firing flag is cleared then this raced with a
>> 1391 * timer rearm/delete operation. So don't generate an
>> 1392 * event.
>> 1393 */
>> 1394 if (likely(cpu_firing))
>> 1395 cpu_timer_fire(timer);
>> 1396 /* See posix_cpu_timer_wait_running() */
>> 1397 rcu_assign_pointer(timer->it.cpu.handling, NULL);
>> 1398 spin_unlock(&timer->it_lock);
>> 1399 }
>> 1400 }
>> 1401
>>
>>--
>>0-DAY CI Kernel Test Service
>>https://github.com/intel/lkp-tests/wiki
>>
>
>
>Oleg already addressed to something like this, I think he said to nuke
>__rcu, which idm looking at and submitting.
>
>Thanks!
Suggested patch, Oleg, what do you think?
From 5e22f00b181c79202bef233d9266a18a4b7abaf9 Mon Sep 17 00:00:00 2001
From: Bradley Morgan <include@grrlz.net>
Date: Wed, 12 Aug 2026 23:52:12 +0000
Subject: [PATCH] signal: Remove the __rcu annotation from task_struct->sighand
sighand is not protected by RCU. It is protected by sighand->siglock,
and by tasklist_lock on the exit path, so the __rcu annotation on
task_struct->sighand describes neither, and sparse complains about
every direct ->siglock use because of it. That is exactly what the
kbuild robot is reporting now for posix-cpu-timers.
What actually keeps lock_task_sighand() safe is SLAB_TYPESAFE_BY_RCU
plus the siglock recheck, not this annotation. Oleg suggested just
dropping the annotation, so that is what this does, and the few rcu_*
accessors
get switched over to the READ_ONCE/WRITE_ONCE/smp_store_release they
already expand to.
This cannot really be split... with the annotation gone the leftover
rcu_* sites are sparse errors, and converting them first while the
annotation stays leaves warnings, so there is no file by file split
that keeps every commit clean. With CONFIG_PROVE_LOCKING off the
generated code is identical, with it on the only difference is the RCU
lockdep assertions that came with the removed accessors.
Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202608130320.o3cNs7Lr-lkp@intel.com/
Suggested-by: Oleg Nesterov <oleg@redhat.com>
Link: https://lore.kernel.org/r/ak5wjJSOyqpXKBdj@redhat.com
Fixes: 913292c97d75 ("sched.h: Annotate sighand_struct with __rcu")
Signed-off-by: Bradley Morgan <include@grrlz.net>
---
fs/exec.c | 7 ++++ +-
include/linux/sched.h | 2 +-
kernel/exit.c | 3 +--
kernel/fork.c | 2 +-
kernel/signal.c | 6 +++---
net/sunrpc/svc.c | 2 +-
security/selinux/hooks.c | 4 ++--
7 files changed, 15 insertions(+), 11 deletions(-)
diff --git a/fs/exec.c b/fs/exec.c
index a14f28b15607..9e3d703329ab 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1078,7 +1078,12 @@ static int unshare_sighand(struct task_struct *me)
spin_lock(&oldsighand->siglock);
memcpy(newsighand->action, oldsighand->action,
sizeof(newsighand->action));
- rcu_assign_pointer(me->sighand, newsighand);
+ /*
+ * Pairs with the READ_ONCE() in lock_task_sighand(): the
+ * ->action copy above has to be visible before anyone can
+ * see the new ->sighand.
+ */
+ smp_store_release(&me->sighand, newsighand);
spin_unlock(&oldsighand->siglock);
write_unlock_irq(&tasklist_lock);
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 499943987c1a..ef5bcc8caf74 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1216,7 +1216,7 @@ struct task_struct {
/* Signal handlers: */
struct signal_struct *signal;
- struct sighand_struct __rcu *sighand;
+ struct sighand_struct *sighand;
sigset_t blocked;
sigset_t real_blocked;
/* Restored if set_restore_sigmask() was used: */
diff --git a/kernel/exit.c b/kernel/exit.c
index 182c06671c78..45a9354a6a77 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -163,8 +163,7 @@ static void __exit_signal(struct release_task_post *post, struct task_struct *ts
struct tty_struct *tty;
u64 utime, stime;
- sighand = rcu_dereference_check(tsk->sighand,
- lockdep_tasklist_lock_is_held());
+ sighand = READ_ONCE(tsk->sighand);
spin_lock(&sighand->siglock);
#ifdef CONFIG_POSIX_TIMERS
diff --git a/kernel/fork.c b/kernel/fork.c
index 86b6351ed120..202915e85b4e 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1702,7 +1702,7 @@ static int copy_sighand(u64 clone_flags, struct task_struct *tsk)
return 0;
}
sig = kmem_cache_alloc(sighand_cachep, GFP_KERNEL);
- RCU_INIT_POINTER(tsk->sighand, sig);
+ WRITE_ONCE(tsk->sighand, sig);
if (!sig)
return -ENOMEM;
diff --git a/kernel/signal.c b/kernel/signal.c
index a5e15bf09d31..04cfefe86208 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1354,7 +1354,7 @@ struct sighand_struct *lock_task_sighand(struct task_struct *tsk,
rcu_read_lock();
for (;;) {
- sighand = rcu_dereference(tsk->sighand);
+ sighand = READ_ONCE(tsk->sighand);
if (unlikely(sighand == NULL)) {
/*
* Pairs with the smp_store_release() in
@@ -1378,7 +1378,7 @@ struct sighand_struct *lock_task_sighand(struct task_struct *tsk,
* must see ->sighand == NULL.
*/
spin_lock_irqsave(&sighand->siglock, *flags);
- if (likely(sighand == rcu_access_pointer(tsk->sighand)))
+ if (likely(sighand == READ_ONCE(tsk->sighand)))
break;
spin_unlock_irqrestore(&sighand->siglock, *flags);
}
@@ -1393,7 +1393,7 @@ void lockdep_assert_task_sighand_held(struct task_struct *task)
struct sighand_struct *sighand;
rcu_read_lock();
- sighand = rcu_dereference(task->sighand);
+ sighand = READ_ONCE(task->sighand);
if (sighand)
lockdep_assert_held(&sighand->siglock);
else
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 05c3e6e2f659..7c681b9f829b 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -1276,7 +1276,7 @@ static void svc_unregister(const struct svc_serv *serv, struct net *net)
}
rcu_read_lock();
- sighand = rcu_dereference(current->sighand);
+ sighand = READ_ONCE(current->sighand);
spin_lock_irqsave(&sighand->siglock, flags);
recalc_sigpending();
spin_unlock_irqrestore(&sighand->siglock, flags);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 035aaf113d1d..d6423a05ca6c 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2586,7 +2586,7 @@ static void selinux_bprm_committed_creds(const struct linux_binprm *bprm)
if (rc) {
clear_itimer();
- spin_lock_irq(&unrcu_pointer(current->sighand)->siglock);
+ spin_lock_irq(¤t->sighand->siglock);
if (!fatal_signal_pending(current)) {
flush_sigqueue(¤t->pending);
flush_sigqueue(¤t->signal->shared_pending);
@@ -2594,7 +2594,7 @@ static void selinux_bprm_committed_creds(const struct linux_binprm *bprm)
sigemptyset(¤t->blocked);
recalc_sigpending();
}
- spin_unlock_irq(&unrcu_pointer(current->sighand)->siglock);
+ spin_unlock_irq(¤t->sighand->siglock);
}
/* Wake up the parent if it is waiting so that it can recheck
--
2.47.3
I'm feeling it's a bit, broad, but sparse still cries if I just remove the
annotation from sched.h.. honestly this is odd.
Thanks!
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-08-13 4:55 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-12 19:40 [tip:timers/core 2/58] kernel/time/posix-cpu-timers.c:1307:9: sparse: sparse: incorrect type in argument 1 (different address spaces) kernel test robot
2026-08-12 19:42 ` Bradley Morgan
2026-08-13 4:55 ` Bradley Morgan
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.