All of lore.kernel.org
 help / color / mirror / Atom feed
* [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(&current->sighand->siglock);
 		if (!fatal_signal_pending(current)) {
 			flush_sigqueue(&current->pending);
 			flush_sigqueue(&current->signal->shared_pending);
@@ -2594,7 +2594,7 @@ static void selinux_bprm_committed_creds(const struct linux_binprm *bprm)
 			sigemptyset(&current->blocked);
 			recalc_sigpending();
 		}
-		spin_unlock_irq(&unrcu_pointer(current->sighand)->siglock);
+		spin_unlock_irq(&current->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.