Re: Read `ps_single' once

2021-03-09 Thread Martin Pieuchot
On 08/03/21(Mon) 12:37, Claudio Jeker wrote:
> On Mon, Mar 08, 2021 at 12:11:54PM +0100, Martin Pieuchot wrote:
> [...]  
> > This diff targets a specific problem which is to make sure `ps_single'
> > dereferences are coherent if this value is being modified w/o KERNEL_LOCK().
> > It doesn't revisit/clarify the relation between the uses of `ps_single'
> > in ptrace and parking code.  This can, IMHO, be done in a later step.
> 
> It only ensures that ps_single is coherent but not that data read from
> that pointer is coherent.

Yes, that's exactly the point of this diff.

> > > > > @@ -541,10 +543,11 @@ loop:
> > > > >   proc_finish_wait(q, p);
> > > > >   return (0);
> > > > >   }
> > > > > +
> > > > > + st = READ_ONCE(pr->ps_single);
> > > > >   if (pr->ps_flags & PS_TRACED &&
> > > > > - (pr->ps_flags & PS_WAITED) == 0 && pr->ps_single &&
> > > > > - pr->ps_single->p_stat == SSTOP &&
> > > > > - (pr->ps_single->p_flag & P_SUSPSINGLE) == 0) {
> > > > > + (pr->ps_flags & PS_WAITED) == 0 && st != NULL &&
> > > > > + st->p_stat == SSTOP && (st->p_flag & P_SUSPSINGLE) 
> > > > > == 0) {
> > > > >   if (single_thread_wait(pr, 0))
> > > > >   goto loop;
> > > > >  
> > > 
> > > Here you access p_stat and p_flag, as far as I remember p_stat is also
> > > protected by SCHED_LOCK. p_flag is atomic and maybe the check should be
> > > turned. So this decision may not be stable.
> > 
> > This is an incoherency which is fine as long as this code is executed
> > with the KERNEL_LOCK().
> 
> It is not if the signal handling is no longer using the KERNEL_LOCK.

But it is currently ;)

> Then the thread could be in the process of being stopped and the race
> to enter single_thread_wait() could be lost. The KERNEL_LOCK() alone does
> not prevent single_thread_set() from running.

Sure, there's plenty of races in the existing code if the KERNEL)_LOCK()
is removed.  I'm trying to move forward step by step.  I sent a simple diff
that fixes a simple problem.  Are you suggesting I should send a huge diff?



Re: Read `ps_single' once

2021-03-08 Thread Claudio Jeker
On Mon, Mar 08, 2021 at 12:11:54PM +0100, Martin Pieuchot wrote:
> On 08/03/21(Mon) 11:57, Claudio Jeker wrote:
> > On Mon, Mar 08, 2021 at 11:06:44AM +0100, Martin Pieuchot wrote:
> > > On 05/03/21(Fri) 11:30, Martin Pieuchot wrote:
> > > > On 04/03/21(Thu) 11:45, Mark Kettenis wrote:
> > > > > > Date: Thu, 4 Mar 2021 11:19:23 +0100
> > > > > > From: Martin Pieuchot 
> > > > > > 
> > > > > > On 04/03/21(Thu) 11:01, Mark Kettenis wrote:
> > > > > > > > Date: Thu, 4 Mar 2021 10:54:48 +0100
> > > > > > > > From: Patrick Wildt 
> > > > > > > > 
> > > > > > > > Am Thu, Mar 04, 2021 at 10:42:24AM +0100 schrieb Mark Kettenis:
> > > > > > > > > > Date: Thu, 4 Mar 2021 10:34:24 +0100
> > > > > > > > > > From: Martin Pieuchot 
> > > > > > > > > > 
> > > > > > > > > > Running t/rw/msleep(9) w/o KERNEL_LOCK() implies that a 
> > > > > > > > > > thread can
> > > > > > > > > > change the value of `ps_single' while one of its siblings 
> > > > > > > > > > might be
> > > > > > > > > > dereferencing it.  
> > > > > > > > > > 
> > > > > > > > > > To prevent inconsistencies in the code executed by sibling 
> > > > > > > > > > thread, the
> > > > > > > > > > diff below makes sure `ps_single' is dereferenced only once 
> > > > > > > > > > in various
> > > > > > > > > > parts of the kernel.
> > > > > > > > > > 
> > > > > > > > > > ok?
> > > > > > > > > 
> > > > > > > > > I think that means that ps_single has to be declared 
> > > > > > > > > "volatile".
> > > > > > > > 
> > > > > > > > Isn't there the READ_ONCE(x) macro, that does exactly that?
> > > > > > > 
> > > > > > > Not a big fan of READ_ONCE() and WRITE_ONCE(), but apparently 
> > > > > > > those
> > > > > > > are needed to comply with the alpha memory model.  At least in 
> > > > > > > some
> > > > > > > cases...
> > > > > > 
> > > > > > Updated diff using READ_ONCE(), ok?
> > > > > 
> > > > > If you use READ_ONCE() you shoul also use WRITE_ONCE() everywhere
> > > > > where you modify ps_single isn't it?
> > > > 
> > > > I don't know, I'm learning how to do it.  I'd appreciate if somebody 
> > > > could
> > > > come with a READ_ONCE(9) manual explaining how this API should be used.
> > > > 
> > > > Updated diff including the WRITE_ONCE().
> > > 
> > > Any ok?
> > 
> > The one thing that bothers me is that we decided that ps_single needs the
> > SCHED_LOCK but now this becomes a bit of a mishmash.
> 
> I hear what you're saying.
> 
> I'm currently concentrating on moving cursig() out of the KERNEL_LOCK()
> and I'd appreciate not be blocked on discussions on which locking/lock-free
> solution is the best for making the parking code mp-safe.

The problem is that you may introduce hard to debug issues in the parking
code. Been there done that.
 
> This diff targets a specific problem which is to make sure `ps_single'
> dereferences are coherent if this value is being modified w/o KERNEL_LOCK().
> It doesn't revisit/clarify the relation between the uses of `ps_single'
> in ptrace and parking code.  This can, IMHO, be done in a later step.

It only ensures that ps_single is coherent but not that data read from
that pointer is coherent.
 
> > > > @@ -510,7 +512,7 @@ dowait4(struct proc *q, pid_t pid, int *
> > > >  {
> > > > int nfound;
> > > > struct process *pr;
> > > > -   struct proc *p;
> > > > +   struct proc *p, *st;
> > > > int error;
> > > >  
> > > > if (pid == 0)
> > > > @@ -541,10 +543,11 @@ loop:
> > > > proc_finish_wait(q, p);
> > > > return (0);
> > > > }
> > > > +
> > > > +   st = READ_ONCE(pr->ps_single);
> > > > if (pr->ps_flags & PS_TRACED &&
> > > > -   (pr->ps_flags & PS_WAITED) == 0 && pr->ps_single &&
> > > > -   pr->ps_single->p_stat == SSTOP &&
> > > > -   (pr->ps_single->p_flag & P_SUSPSINGLE) == 0) {
> > > > +   (pr->ps_flags & PS_WAITED) == 0 && st != NULL &&
> > > > +   st->p_stat == SSTOP && (st->p_flag & P_SUSPSINGLE) 
> > > > == 0) {
> > > > if (single_thread_wait(pr, 0))
> > > > goto loop;
> > > >  
> > 
> > Here you access p_stat and p_flag, as far as I remember p_stat is also
> > protected by SCHED_LOCK. p_flag is atomic and maybe the check should be
> > turned. So this decision may not be stable.
> 
> This is an incoherency which is fine as long as this code is executed
> with the KERNEL_LOCK().

It is not if the signal handling is no longer using the KERNEL_LOCK.
Then the thread could be in the process of being stopped and the race
to enter single_thread_wait() could be lost. The KERNEL_LOCK() alone does
not prevent single_thread_set() from running.
 
> > > > Index: kern/sys_process.c
> > > > ===
> > > > RCS file: /cvs/src/sys/kern/sys_process.c,v
> > > > retrieving revision 1.86
> > > > diff -u -p -r1.86 

Re: Read `ps_single' once

2021-03-08 Thread Martin Pieuchot
On 08/03/21(Mon) 11:57, Claudio Jeker wrote:
> On Mon, Mar 08, 2021 at 11:06:44AM +0100, Martin Pieuchot wrote:
> > On 05/03/21(Fri) 11:30, Martin Pieuchot wrote:
> > > On 04/03/21(Thu) 11:45, Mark Kettenis wrote:
> > > > > Date: Thu, 4 Mar 2021 11:19:23 +0100
> > > > > From: Martin Pieuchot 
> > > > > 
> > > > > On 04/03/21(Thu) 11:01, Mark Kettenis wrote:
> > > > > > > Date: Thu, 4 Mar 2021 10:54:48 +0100
> > > > > > > From: Patrick Wildt 
> > > > > > > 
> > > > > > > Am Thu, Mar 04, 2021 at 10:42:24AM +0100 schrieb Mark Kettenis:
> > > > > > > > > Date: Thu, 4 Mar 2021 10:34:24 +0100
> > > > > > > > > From: Martin Pieuchot 
> > > > > > > > > 
> > > > > > > > > Running t/rw/msleep(9) w/o KERNEL_LOCK() implies that a 
> > > > > > > > > thread can
> > > > > > > > > change the value of `ps_single' while one of its siblings 
> > > > > > > > > might be
> > > > > > > > > dereferencing it.  
> > > > > > > > > 
> > > > > > > > > To prevent inconsistencies in the code executed by sibling 
> > > > > > > > > thread, the
> > > > > > > > > diff below makes sure `ps_single' is dereferenced only once 
> > > > > > > > > in various
> > > > > > > > > parts of the kernel.
> > > > > > > > > 
> > > > > > > > > ok?
> > > > > > > > 
> > > > > > > > I think that means that ps_single has to be declared "volatile".
> > > > > > > 
> > > > > > > Isn't there the READ_ONCE(x) macro, that does exactly that?
> > > > > > 
> > > > > > Not a big fan of READ_ONCE() and WRITE_ONCE(), but apparently those
> > > > > > are needed to comply with the alpha memory model.  At least in some
> > > > > > cases...
> > > > > 
> > > > > Updated diff using READ_ONCE(), ok?
> > > > 
> > > > If you use READ_ONCE() you shoul also use WRITE_ONCE() everywhere
> > > > where you modify ps_single isn't it?
> > > 
> > > I don't know, I'm learning how to do it.  I'd appreciate if somebody could
> > > come with a READ_ONCE(9) manual explaining how this API should be used.
> > > 
> > > Updated diff including the WRITE_ONCE().
> > 
> > Any ok?
> 
> The one thing that bothers me is that we decided that ps_single needs the
> SCHED_LOCK but now this becomes a bit of a mishmash.

I hear what you're saying.

I'm currently concentrating on moving cursig() out of the KERNEL_LOCK()
and I'd appreciate not be blocked on discussions on which locking/lock-free
solution is the best for making the parking code mp-safe.

This diff targets a specific problem which is to make sure `ps_single'
dereferences are coherent if this value is being modified w/o KERNEL_LOCK().
It doesn't revisit/clarify the relation between the uses of `ps_single'
in ptrace and parking code.  This can, IMHO, be done in a later step.

> > > @@ -510,7 +512,7 @@ dowait4(struct proc *q, pid_t pid, int *
> > >  {
> > >   int nfound;
> > >   struct process *pr;
> > > - struct proc *p;
> > > + struct proc *p, *st;
> > >   int error;
> > >  
> > >   if (pid == 0)
> > > @@ -541,10 +543,11 @@ loop:
> > >   proc_finish_wait(q, p);
> > >   return (0);
> > >   }
> > > +
> > > + st = READ_ONCE(pr->ps_single);
> > >   if (pr->ps_flags & PS_TRACED &&
> > > - (pr->ps_flags & PS_WAITED) == 0 && pr->ps_single &&
> > > - pr->ps_single->p_stat == SSTOP &&
> > > - (pr->ps_single->p_flag & P_SUSPSINGLE) == 0) {
> > > + (pr->ps_flags & PS_WAITED) == 0 && st != NULL &&
> > > + st->p_stat == SSTOP && (st->p_flag & P_SUSPSINGLE) == 0) {
> > >   if (single_thread_wait(pr, 0))
> > >   goto loop;
> > >  
> 
> Here you access p_stat and p_flag, as far as I remember p_stat is also
> protected by SCHED_LOCK. p_flag is atomic and maybe the check should be
> turned. So this decision may not be stable.

This is an incoherency which is fine as long as this code is executed
with the KERNEL_LOCK().

> > > Index: kern/sys_process.c
> > > ===
> > > RCS file: /cvs/src/sys/kern/sys_process.c,v
> > > retrieving revision 1.86
> > > diff -u -p -r1.86 sys_process.c
> > > --- kern/sys_process.c8 Feb 2021 10:51:02 -   1.86
> > > +++ kern/sys_process.c5 Mar 2021 10:28:06 -
> > > @@ -273,7 +273,7 @@ sys_ptrace(struct proc *p, void *v, regi
> > >  int
> > >  ptrace_ctrl(struct proc *p, int req, pid_t pid, caddr_t addr, int data)
> > >  {
> > > - struct proc *t; /* target thread */
> > > + struct proc *st, *t;/* target thread */
> > >   struct process *tr; /* target process */
> > >   int error = 0;
> > >   int s;
> > > @@ -433,8 +433,9 @@ ptrace_ctrl(struct proc *p, int req, pid
> > >* from where it stopped."
> > >*/
> > >  
> > > - if (pid < THREAD_PID_OFFSET && tr->ps_single)
> > > - t = tr->ps_single;
> > > + st = READ_ONCE(tr->ps_single);
> > > + if (pid < THREAD_PID_OFFSET && st != NULL)
> > > 

Re: Read `ps_single' once

2021-03-08 Thread Claudio Jeker
On Mon, Mar 08, 2021 at 11:06:44AM +0100, Martin Pieuchot wrote:
> On 05/03/21(Fri) 11:30, Martin Pieuchot wrote:
> > On 04/03/21(Thu) 11:45, Mark Kettenis wrote:
> > > > Date: Thu, 4 Mar 2021 11:19:23 +0100
> > > > From: Martin Pieuchot 
> > > > 
> > > > On 04/03/21(Thu) 11:01, Mark Kettenis wrote:
> > > > > > Date: Thu, 4 Mar 2021 10:54:48 +0100
> > > > > > From: Patrick Wildt 
> > > > > > 
> > > > > > Am Thu, Mar 04, 2021 at 10:42:24AM +0100 schrieb Mark Kettenis:
> > > > > > > > Date: Thu, 4 Mar 2021 10:34:24 +0100
> > > > > > > > From: Martin Pieuchot 
> > > > > > > > 
> > > > > > > > Running t/rw/msleep(9) w/o KERNEL_LOCK() implies that a thread 
> > > > > > > > can
> > > > > > > > change the value of `ps_single' while one of its siblings might 
> > > > > > > > be
> > > > > > > > dereferencing it.  
> > > > > > > > 
> > > > > > > > To prevent inconsistencies in the code executed by sibling 
> > > > > > > > thread, the
> > > > > > > > diff below makes sure `ps_single' is dereferenced only once in 
> > > > > > > > various
> > > > > > > > parts of the kernel.
> > > > > > > > 
> > > > > > > > ok?
> > > > > > > 
> > > > > > > I think that means that ps_single has to be declared "volatile".
> > > > > > 
> > > > > > Isn't there the READ_ONCE(x) macro, that does exactly that?
> > > > > 
> > > > > Not a big fan of READ_ONCE() and WRITE_ONCE(), but apparently those
> > > > > are needed to comply with the alpha memory model.  At least in some
> > > > > cases...
> > > > 
> > > > Updated diff using READ_ONCE(), ok?
> > > 
> > > If you use READ_ONCE() you shoul also use WRITE_ONCE() everywhere
> > > where you modify ps_single isn't it?
> > 
> > I don't know, I'm learning how to do it.  I'd appreciate if somebody could
> > come with a READ_ONCE(9) manual explaining how this API should be used.
> > 
> > Updated diff including the WRITE_ONCE().
> 
> Any ok?

The one thing that bothers me is that we decided that ps_single needs the
SCHED_LOCK but now this becomes a bit of a mishmash.
 
> > Index: kern/kern_exit.c
> > ===
> > RCS file: /cvs/src/sys/kern/kern_exit.c,v
> > retrieving revision 1.196
> > diff -u -p -r1.196 kern_exit.c
> > --- kern/kern_exit.c15 Feb 2021 09:35:59 -  1.196
> > +++ kern/kern_exit.c5 Mar 2021 10:28:05 -
> > @@ -274,6 +274,8 @@ exit1(struct proc *p, int xexit, int xsi
> >  */
> > if (qr->ps_flags & PS_TRACED &&
> > !(qr->ps_flags & PS_EXITING)) {
> > +   struct proc *st;
> > +
> > process_untrace(qr);
> >  
> > /*
> > @@ -281,9 +283,9 @@ exit1(struct proc *p, int xexit, int xsi
> >  * direct the signal to the active
> >  * thread to avoid deadlock.
> >  */
> > -   if (qr->ps_single)
> > -   ptsignal(qr->ps_single, SIGKILL,
> > -   STHREAD);
> > +   st = READ_ONCE(qr->ps_single);
> > +   if (st != NULL)
> > +   ptsignal(st, SIGKILL, STHREAD);
> > else
> > prsignal(qr, SIGKILL);
> > } else {

I seriously wonder if that should not be moved into prsignal() but this
should be ok.

> > @@ -510,7 +512,7 @@ dowait4(struct proc *q, pid_t pid, int *
> >  {
> > int nfound;
> > struct process *pr;
> > -   struct proc *p;
> > +   struct proc *p, *st;
> > int error;
> >  
> > if (pid == 0)
> > @@ -541,10 +543,11 @@ loop:
> > proc_finish_wait(q, p);
> > return (0);
> > }
> > +
> > +   st = READ_ONCE(pr->ps_single);
> > if (pr->ps_flags & PS_TRACED &&
> > -   (pr->ps_flags & PS_WAITED) == 0 && pr->ps_single &&
> > -   pr->ps_single->p_stat == SSTOP &&
> > -   (pr->ps_single->p_flag & P_SUSPSINGLE) == 0) {
> > +   (pr->ps_flags & PS_WAITED) == 0 && st != NULL &&
> > +   st->p_stat == SSTOP && (st->p_flag & P_SUSPSINGLE) == 0) {
> > if (single_thread_wait(pr, 0))
> > goto loop;
> >  

Here you access p_stat and p_flag, as far as I remember p_stat is also
protected by SCHED_LOCK. p_flag is atomic and maybe the check should be
turned. So this decision may not be stable.

> > Index: kern/kern_sig.c
> > ===
> > RCS file: /cvs/src/sys/kern/kern_sig.c,v
> > retrieving revision 1.274
> > diff -u -p -r1.274 kern_sig.c
> > --- kern/kern_sig.c 4 Mar 2021 09:02:37 -   1.274
> > +++ kern/kern_sig.c 5 Mar 2021 10:28:05 -
> > @@ -2040,7 +2040,7 @@ single_thread_set(struct proc *p, enum s
> >   

Re: Read `ps_single' once

2021-03-08 Thread Martin Pieuchot
On 05/03/21(Fri) 11:30, Martin Pieuchot wrote:
> On 04/03/21(Thu) 11:45, Mark Kettenis wrote:
> > > Date: Thu, 4 Mar 2021 11:19:23 +0100
> > > From: Martin Pieuchot 
> > > 
> > > On 04/03/21(Thu) 11:01, Mark Kettenis wrote:
> > > > > Date: Thu, 4 Mar 2021 10:54:48 +0100
> > > > > From: Patrick Wildt 
> > > > > 
> > > > > Am Thu, Mar 04, 2021 at 10:42:24AM +0100 schrieb Mark Kettenis:
> > > > > > > Date: Thu, 4 Mar 2021 10:34:24 +0100
> > > > > > > From: Martin Pieuchot 
> > > > > > > 
> > > > > > > Running t/rw/msleep(9) w/o KERNEL_LOCK() implies that a thread can
> > > > > > > change the value of `ps_single' while one of its siblings might be
> > > > > > > dereferencing it.  
> > > > > > > 
> > > > > > > To prevent inconsistencies in the code executed by sibling 
> > > > > > > thread, the
> > > > > > > diff below makes sure `ps_single' is dereferenced only once in 
> > > > > > > various
> > > > > > > parts of the kernel.
> > > > > > > 
> > > > > > > ok?
> > > > > > 
> > > > > > I think that means that ps_single has to be declared "volatile".
> > > > > 
> > > > > Isn't there the READ_ONCE(x) macro, that does exactly that?
> > > > 
> > > > Not a big fan of READ_ONCE() and WRITE_ONCE(), but apparently those
> > > > are needed to comply with the alpha memory model.  At least in some
> > > > cases...
> > > 
> > > Updated diff using READ_ONCE(), ok?
> > 
> > If you use READ_ONCE() you shoul also use WRITE_ONCE() everywhere
> > where you modify ps_single isn't it?
> 
> I don't know, I'm learning how to do it.  I'd appreciate if somebody could
> come with a READ_ONCE(9) manual explaining how this API should be used.
> 
> Updated diff including the WRITE_ONCE().

Any ok?

> Index: kern/kern_exit.c
> ===
> RCS file: /cvs/src/sys/kern/kern_exit.c,v
> retrieving revision 1.196
> diff -u -p -r1.196 kern_exit.c
> --- kern/kern_exit.c  15 Feb 2021 09:35:59 -  1.196
> +++ kern/kern_exit.c  5 Mar 2021 10:28:05 -
> @@ -274,6 +274,8 @@ exit1(struct proc *p, int xexit, int xsi
>*/
>   if (qr->ps_flags & PS_TRACED &&
>   !(qr->ps_flags & PS_EXITING)) {
> + struct proc *st;
> +
>   process_untrace(qr);
>  
>   /*
> @@ -281,9 +283,9 @@ exit1(struct proc *p, int xexit, int xsi
>* direct the signal to the active
>* thread to avoid deadlock.
>*/
> - if (qr->ps_single)
> - ptsignal(qr->ps_single, SIGKILL,
> - STHREAD);
> + st = READ_ONCE(qr->ps_single);
> + if (st != NULL)
> + ptsignal(st, SIGKILL, STHREAD);
>   else
>   prsignal(qr, SIGKILL);
>   } else {
> @@ -510,7 +512,7 @@ dowait4(struct proc *q, pid_t pid, int *
>  {
>   int nfound;
>   struct process *pr;
> - struct proc *p;
> + struct proc *p, *st;
>   int error;
>  
>   if (pid == 0)
> @@ -541,10 +543,11 @@ loop:
>   proc_finish_wait(q, p);
>   return (0);
>   }
> +
> + st = READ_ONCE(pr->ps_single);
>   if (pr->ps_flags & PS_TRACED &&
> - (pr->ps_flags & PS_WAITED) == 0 && pr->ps_single &&
> - pr->ps_single->p_stat == SSTOP &&
> - (pr->ps_single->p_flag & P_SUSPSINGLE) == 0) {
> + (pr->ps_flags & PS_WAITED) == 0 && st != NULL &&
> + st->p_stat == SSTOP && (st->p_flag & P_SUSPSINGLE) == 0) {
>   if (single_thread_wait(pr, 0))
>   goto loop;
>  
> Index: kern/kern_sig.c
> ===
> RCS file: /cvs/src/sys/kern/kern_sig.c,v
> retrieving revision 1.274
> diff -u -p -r1.274 kern_sig.c
> --- kern/kern_sig.c   4 Mar 2021 09:02:37 -   1.274
> +++ kern/kern_sig.c   5 Mar 2021 10:28:05 -
> @@ -2040,7 +2040,7 @@ single_thread_set(struct proc *p, enum s
>   }
>   pr->ps_singlecount = 0;
>   membar_producer();
> - pr->ps_single = p;
> + WRITE_ONCE(pr->ps_single, p);
>   TAILQ_FOREACH(q, >ps_threads, p_thr_link) {
>   if (q == p)
>   continue;
> @@ -2131,7 +2131,7 @@ single_thread_clear(struct proc *p, int 
>   KERNEL_ASSERT_LOCKED();
>  
>   SCHED_LOCK(s);
> - pr->ps_single = NULL;
> + WRITE_ONCE(pr->ps_single, NULL);
>   atomic_clearbits_int(>ps_flags, PS_SINGLEUNWIND | PS_SINGLEEXIT);
>   TAILQ_FOREACH(q, >ps_threads, p_thr_link) {
>   if (q == p || (q->p_flag & P_SUSPSINGLE) == 0)
> Index: 

Re: Read `ps_single' once

2021-03-05 Thread Martin Pieuchot
On 04/03/21(Thu) 11:45, Mark Kettenis wrote:
> > Date: Thu, 4 Mar 2021 11:19:23 +0100
> > From: Martin Pieuchot 
> > 
> > On 04/03/21(Thu) 11:01, Mark Kettenis wrote:
> > > > Date: Thu, 4 Mar 2021 10:54:48 +0100
> > > > From: Patrick Wildt 
> > > > 
> > > > Am Thu, Mar 04, 2021 at 10:42:24AM +0100 schrieb Mark Kettenis:
> > > > > > Date: Thu, 4 Mar 2021 10:34:24 +0100
> > > > > > From: Martin Pieuchot 
> > > > > > 
> > > > > > Running t/rw/msleep(9) w/o KERNEL_LOCK() implies that a thread can
> > > > > > change the value of `ps_single' while one of its siblings might be
> > > > > > dereferencing it.  
> > > > > > 
> > > > > > To prevent inconsistencies in the code executed by sibling thread, 
> > > > > > the
> > > > > > diff below makes sure `ps_single' is dereferenced only once in 
> > > > > > various
> > > > > > parts of the kernel.
> > > > > > 
> > > > > > ok?
> > > > > 
> > > > > I think that means that ps_single has to be declared "volatile".
> > > > 
> > > > Isn't there the READ_ONCE(x) macro, that does exactly that?
> > > 
> > > Not a big fan of READ_ONCE() and WRITE_ONCE(), but apparently those
> > > are needed to comply with the alpha memory model.  At least in some
> > > cases...
> > 
> > Updated diff using READ_ONCE(), ok?
> 
> If you use READ_ONCE() you shoul also use WRITE_ONCE() everywhere
> where you modify ps_single isn't it?

I don't know, I'm learning how to do it.  I'd appreciate if somebody could
come with a READ_ONCE(9) manual explaining how this API should be used.

Updated diff including the WRITE_ONCE().

Index: kern/kern_exit.c
===
RCS file: /cvs/src/sys/kern/kern_exit.c,v
retrieving revision 1.196
diff -u -p -r1.196 kern_exit.c
--- kern/kern_exit.c15 Feb 2021 09:35:59 -  1.196
+++ kern/kern_exit.c5 Mar 2021 10:28:05 -
@@ -274,6 +274,8 @@ exit1(struct proc *p, int xexit, int xsi
 */
if (qr->ps_flags & PS_TRACED &&
!(qr->ps_flags & PS_EXITING)) {
+   struct proc *st;
+
process_untrace(qr);
 
/*
@@ -281,9 +283,9 @@ exit1(struct proc *p, int xexit, int xsi
 * direct the signal to the active
 * thread to avoid deadlock.
 */
-   if (qr->ps_single)
-   ptsignal(qr->ps_single, SIGKILL,
-   STHREAD);
+   st = READ_ONCE(qr->ps_single);
+   if (st != NULL)
+   ptsignal(st, SIGKILL, STHREAD);
else
prsignal(qr, SIGKILL);
} else {
@@ -510,7 +512,7 @@ dowait4(struct proc *q, pid_t pid, int *
 {
int nfound;
struct process *pr;
-   struct proc *p;
+   struct proc *p, *st;
int error;
 
if (pid == 0)
@@ -541,10 +543,11 @@ loop:
proc_finish_wait(q, p);
return (0);
}
+
+   st = READ_ONCE(pr->ps_single);
if (pr->ps_flags & PS_TRACED &&
-   (pr->ps_flags & PS_WAITED) == 0 && pr->ps_single &&
-   pr->ps_single->p_stat == SSTOP &&
-   (pr->ps_single->p_flag & P_SUSPSINGLE) == 0) {
+   (pr->ps_flags & PS_WAITED) == 0 && st != NULL &&
+   st->p_stat == SSTOP && (st->p_flag & P_SUSPSINGLE) == 0) {
if (single_thread_wait(pr, 0))
goto loop;
 
Index: kern/kern_sig.c
===
RCS file: /cvs/src/sys/kern/kern_sig.c,v
retrieving revision 1.274
diff -u -p -r1.274 kern_sig.c
--- kern/kern_sig.c 4 Mar 2021 09:02:37 -   1.274
+++ kern/kern_sig.c 5 Mar 2021 10:28:05 -
@@ -2040,7 +2040,7 @@ single_thread_set(struct proc *p, enum s
}
pr->ps_singlecount = 0;
membar_producer();
-   pr->ps_single = p;
+   WRITE_ONCE(pr->ps_single, p);
TAILQ_FOREACH(q, >ps_threads, p_thr_link) {
if (q == p)
continue;
@@ -2131,7 +2131,7 @@ single_thread_clear(struct proc *p, int 
KERNEL_ASSERT_LOCKED();
 
SCHED_LOCK(s);
-   pr->ps_single = NULL;
+   WRITE_ONCE(pr->ps_single, NULL);
atomic_clearbits_int(>ps_flags, PS_SINGLEUNWIND | PS_SINGLEEXIT);
TAILQ_FOREACH(q, >ps_threads, p_thr_link) {
if (q == p || (q->p_flag & P_SUSPSINGLE) == 0)
Index: kern/sys_process.c
===
RCS file: /cvs/src/sys/kern/sys_process.c,v
retrieving revision 1.86
diff -u -p -r1.86 sys_process.c
--- 

Re: Read `ps_single' once

2021-03-04 Thread Mark Kettenis
> Date: Thu, 4 Mar 2021 11:19:23 +0100
> From: Martin Pieuchot 
> 
> On 04/03/21(Thu) 11:01, Mark Kettenis wrote:
> > > Date: Thu, 4 Mar 2021 10:54:48 +0100
> > > From: Patrick Wildt 
> > > 
> > > Am Thu, Mar 04, 2021 at 10:42:24AM +0100 schrieb Mark Kettenis:
> > > > > Date: Thu, 4 Mar 2021 10:34:24 +0100
> > > > > From: Martin Pieuchot 
> > > > > 
> > > > > Running t/rw/msleep(9) w/o KERNEL_LOCK() implies that a thread can
> > > > > change the value of `ps_single' while one of its siblings might be
> > > > > dereferencing it.  
> > > > > 
> > > > > To prevent inconsistencies in the code executed by sibling thread, the
> > > > > diff below makes sure `ps_single' is dereferenced only once in various
> > > > > parts of the kernel.
> > > > > 
> > > > > ok?
> > > > 
> > > > I think that means that ps_single has to be declared "volatile".
> > > 
> > > Isn't there the READ_ONCE(x) macro, that does exactly that?
> > 
> > Not a big fan of READ_ONCE() and WRITE_ONCE(), but apparently those
> > are needed to comply with the alpha memory model.  At least in some
> > cases...
> 
> Updated diff using READ_ONCE(), ok?

If you use READ_ONCE() you shoul also use WRITE_ONCE() everywhere
where you modify ps_single isn't it?

That is one of the reasons I dislike these macros...

> Index: kern/kern_exit.c
> ===
> RCS file: /cvs/src/sys/kern/kern_exit.c,v
> retrieving revision 1.196
> diff -u -p -r1.196 kern_exit.c
> --- kern/kern_exit.c  15 Feb 2021 09:35:59 -  1.196
> +++ kern/kern_exit.c  4 Mar 2021 10:15:22 -
> @@ -274,6 +274,8 @@ exit1(struct proc *p, int xexit, int xsi
>*/
>   if (qr->ps_flags & PS_TRACED &&
>   !(qr->ps_flags & PS_EXITING)) {
> + struct proc *st;
> +
>   process_untrace(qr);
>  
>   /*
> @@ -281,9 +283,9 @@ exit1(struct proc *p, int xexit, int xsi
>* direct the signal to the active
>* thread to avoid deadlock.
>*/
> - if (qr->ps_single)
> - ptsignal(qr->ps_single, SIGKILL,
> - STHREAD);
> + st = READ_ONCE(qr->ps_single);
> + if (st != NULL)
> + ptsignal(st, SIGKILL, STHREAD);
>   else
>   prsignal(qr, SIGKILL);
>   } else {
> @@ -510,7 +512,7 @@ dowait4(struct proc *q, pid_t pid, int *
>  {
>   int nfound;
>   struct process *pr;
> - struct proc *p;
> + struct proc *p, *st;
>   int error;
>  
>   if (pid == 0)
> @@ -541,10 +543,11 @@ loop:
>   proc_finish_wait(q, p);
>   return (0);
>   }
> +
> + st = READ_ONCE(pr->ps_single);
>   if (pr->ps_flags & PS_TRACED &&
> - (pr->ps_flags & PS_WAITED) == 0 && pr->ps_single &&
> - pr->ps_single->p_stat == SSTOP &&
> - (pr->ps_single->p_flag & P_SUSPSINGLE) == 0) {
> + (pr->ps_flags & PS_WAITED) == 0 && st != NULL &&
> + st->p_stat == SSTOP && (st->p_flag & P_SUSPSINGLE) == 0) {
>   if (single_thread_wait(pr, 0))
>   goto loop;
>  
> Index: kern/sys_process.c
> ===
> RCS file: /cvs/src/sys/kern/sys_process.c,v
> retrieving revision 1.86
> diff -u -p -r1.86 sys_process.c
> --- kern/sys_process.c8 Feb 2021 10:51:02 -   1.86
> +++ kern/sys_process.c4 Mar 2021 10:15:57 -
> @@ -273,7 +273,7 @@ sys_ptrace(struct proc *p, void *v, regi
>  int
>  ptrace_ctrl(struct proc *p, int req, pid_t pid, caddr_t addr, int data)
>  {
> - struct proc *t; /* target thread */
> + struct proc *st, *t;/* target thread */
>   struct process *tr; /* target process */
>   int error = 0;
>   int s;
> @@ -433,8 +433,9 @@ ptrace_ctrl(struct proc *p, int req, pid
>* from where it stopped."
>*/
>  
> - if (pid < THREAD_PID_OFFSET && tr->ps_single)
> - t = tr->ps_single;
> + st = READ_ONCE(tr->ps_single);
> + if (pid < THREAD_PID_OFFSET && st != NULL)
> + t = st;
>  
>   /* If the address parameter is not (int *)1, set the pc. */
>   if ((int *)addr != (int *)1)
> @@ -464,8 +465,9 @@ ptrace_ctrl(struct proc *p, int req, pid
>* from where it stopped."
>*/
>  
> - if (pid < THREAD_PID_OFFSET && tr->ps_single)
> - t = 

Re: Read `ps_single' once

2021-03-04 Thread Martin Pieuchot
On 04/03/21(Thu) 11:01, Mark Kettenis wrote:
> > Date: Thu, 4 Mar 2021 10:54:48 +0100
> > From: Patrick Wildt 
> > 
> > Am Thu, Mar 04, 2021 at 10:42:24AM +0100 schrieb Mark Kettenis:
> > > > Date: Thu, 4 Mar 2021 10:34:24 +0100
> > > > From: Martin Pieuchot 
> > > > 
> > > > Running t/rw/msleep(9) w/o KERNEL_LOCK() implies that a thread can
> > > > change the value of `ps_single' while one of its siblings might be
> > > > dereferencing it.  
> > > > 
> > > > To prevent inconsistencies in the code executed by sibling thread, the
> > > > diff below makes sure `ps_single' is dereferenced only once in various
> > > > parts of the kernel.
> > > > 
> > > > ok?
> > > 
> > > I think that means that ps_single has to be declared "volatile".
> > 
> > Isn't there the READ_ONCE(x) macro, that does exactly that?
> 
> Not a big fan of READ_ONCE() and WRITE_ONCE(), but apparently those
> are needed to comply with the alpha memory model.  At least in some
> cases...

Updated diff using READ_ONCE(), ok?

Index: kern/kern_exit.c
===
RCS file: /cvs/src/sys/kern/kern_exit.c,v
retrieving revision 1.196
diff -u -p -r1.196 kern_exit.c
--- kern/kern_exit.c15 Feb 2021 09:35:59 -  1.196
+++ kern/kern_exit.c4 Mar 2021 10:15:22 -
@@ -274,6 +274,8 @@ exit1(struct proc *p, int xexit, int xsi
 */
if (qr->ps_flags & PS_TRACED &&
!(qr->ps_flags & PS_EXITING)) {
+   struct proc *st;
+
process_untrace(qr);
 
/*
@@ -281,9 +283,9 @@ exit1(struct proc *p, int xexit, int xsi
 * direct the signal to the active
 * thread to avoid deadlock.
 */
-   if (qr->ps_single)
-   ptsignal(qr->ps_single, SIGKILL,
-   STHREAD);
+   st = READ_ONCE(qr->ps_single);
+   if (st != NULL)
+   ptsignal(st, SIGKILL, STHREAD);
else
prsignal(qr, SIGKILL);
} else {
@@ -510,7 +512,7 @@ dowait4(struct proc *q, pid_t pid, int *
 {
int nfound;
struct process *pr;
-   struct proc *p;
+   struct proc *p, *st;
int error;
 
if (pid == 0)
@@ -541,10 +543,11 @@ loop:
proc_finish_wait(q, p);
return (0);
}
+
+   st = READ_ONCE(pr->ps_single);
if (pr->ps_flags & PS_TRACED &&
-   (pr->ps_flags & PS_WAITED) == 0 && pr->ps_single &&
-   pr->ps_single->p_stat == SSTOP &&
-   (pr->ps_single->p_flag & P_SUSPSINGLE) == 0) {
+   (pr->ps_flags & PS_WAITED) == 0 && st != NULL &&
+   st->p_stat == SSTOP && (st->p_flag & P_SUSPSINGLE) == 0) {
if (single_thread_wait(pr, 0))
goto loop;
 
Index: kern/sys_process.c
===
RCS file: /cvs/src/sys/kern/sys_process.c,v
retrieving revision 1.86
diff -u -p -r1.86 sys_process.c
--- kern/sys_process.c  8 Feb 2021 10:51:02 -   1.86
+++ kern/sys_process.c  4 Mar 2021 10:15:57 -
@@ -273,7 +273,7 @@ sys_ptrace(struct proc *p, void *v, regi
 int
 ptrace_ctrl(struct proc *p, int req, pid_t pid, caddr_t addr, int data)
 {
-   struct proc *t; /* target thread */
+   struct proc *st, *t;/* target thread */
struct process *tr; /* target process */
int error = 0;
int s;
@@ -433,8 +433,9 @@ ptrace_ctrl(struct proc *p, int req, pid
 * from where it stopped."
 */
 
-   if (pid < THREAD_PID_OFFSET && tr->ps_single)
-   t = tr->ps_single;
+   st = READ_ONCE(tr->ps_single);
+   if (pid < THREAD_PID_OFFSET && st != NULL)
+   t = st;
 
/* If the address parameter is not (int *)1, set the pc. */
if ((int *)addr != (int *)1)
@@ -464,8 +465,9 @@ ptrace_ctrl(struct proc *p, int req, pid
 * from where it stopped."
 */
 
-   if (pid < THREAD_PID_OFFSET && tr->ps_single)
-   t = tr->ps_single;
+   st = READ_ONCE(tr->ps_single);
+   if (pid < THREAD_PID_OFFSET && st != NULL)
+   t = st;
 
 #ifdef PT_STEP
/*
@@ -495,8 +497,9 @@ ptrace_ctrl(struct proc *p, int req, pid
break;
 
case PT_KILL:
-   if (pid < THREAD_PID_OFFSET && 

Re: Read `ps_single' once

2021-03-04 Thread Mark Kettenis
> Date: Thu, 4 Mar 2021 10:54:48 +0100
> From: Patrick Wildt 
> 
> Am Thu, Mar 04, 2021 at 10:42:24AM +0100 schrieb Mark Kettenis:
> > > Date: Thu, 4 Mar 2021 10:34:24 +0100
> > > From: Martin Pieuchot 
> > > 
> > > Running t/rw/msleep(9) w/o KERNEL_LOCK() implies that a thread can
> > > change the value of `ps_single' while one of its siblings might be
> > > dereferencing it.  
> > > 
> > > To prevent inconsistencies in the code executed by sibling thread, the
> > > diff below makes sure `ps_single' is dereferenced only once in various
> > > parts of the kernel.
> > > 
> > > ok?
> > 
> > I think that means that ps_single has to be declared "volatile".
> 
> Isn't there the READ_ONCE(x) macro, that does exactly that?

Not a big fan of READ_ONCE() and WRITE_ONCE(), but apparently those
are needed to comply with the alpha memory model.  At least in some
cases...

> > > Index: kern/kern_exit.c
> > > ===
> > > RCS file: /cvs/src/sys/kern/kern_exit.c,v
> > > retrieving revision 1.196
> > > diff -u -p -r1.196 kern_exit.c
> > > --- kern/kern_exit.c  15 Feb 2021 09:35:59 -  1.196
> > > +++ kern/kern_exit.c  4 Mar 2021 09:29:27 -
> > > @@ -274,6 +274,8 @@ exit1(struct proc *p, int xexit, int xsi
> > >*/
> > >   if (qr->ps_flags & PS_TRACED &&
> > >   !(qr->ps_flags & PS_EXITING)) {
> > > + struct proc *st;
> > > +
> > >   process_untrace(qr);
> > >  
> > >   /*
> > > @@ -281,9 +283,9 @@ exit1(struct proc *p, int xexit, int xsi
> > >* direct the signal to the active
> > >* thread to avoid deadlock.
> > >*/
> > > - if (qr->ps_single)
> > > - ptsignal(qr->ps_single, SIGKILL,
> > > - STHREAD);
> > > + st = qr->ps_single;
> > > + if (st != NULL)
> > > + ptsignal(st, SIGKILL, STHREAD);
> > >   else
> > >   prsignal(qr, SIGKILL);
> > >   } else {
> > > @@ -510,7 +512,7 @@ dowait4(struct proc *q, pid_t pid, int *
> > >  {
> > >   int nfound;
> > >   struct process *pr;
> > > - struct proc *p;
> > > + struct proc *p, *st;
> > >   int error;
> > >  
> > >   if (pid == 0)
> > > @@ -541,10 +543,11 @@ loop:
> > >   proc_finish_wait(q, p);
> > >   return (0);
> > >   }
> > > +
> > > + st = pr->ps_single;
> > >   if (pr->ps_flags & PS_TRACED &&
> > > - (pr->ps_flags & PS_WAITED) == 0 && pr->ps_single &&
> > > - pr->ps_single->p_stat == SSTOP &&
> > > - (pr->ps_single->p_flag & P_SUSPSINGLE) == 0) {
> > > + (pr->ps_flags & PS_WAITED) == 0 && st != NULL &&
> > > + st->p_stat == SSTOP && (st->p_flag & P_SUSPSINGLE) == 0) {
> > >   if (single_thread_wait(pr, 0))
> > >   goto loop;
> > >  
> > > Index: kern/sys_process.c
> > > ===
> > > RCS file: /cvs/src/sys/kern/sys_process.c,v
> > > retrieving revision 1.86
> > > diff -u -p -r1.86 sys_process.c
> > > --- kern/sys_process.c8 Feb 2021 10:51:02 -   1.86
> > > +++ kern/sys_process.c4 Mar 2021 09:29:27 -
> > > @@ -273,7 +273,7 @@ sys_ptrace(struct proc *p, void *v, regi
> > >  int
> > >  ptrace_ctrl(struct proc *p, int req, pid_t pid, caddr_t addr, int data)
> > >  {
> > > - struct proc *t; /* target thread */
> > > + struct proc *st, *t;/* target thread */
> > >   struct process *tr; /* target process */
> > >   int error = 0;
> > >   int s;
> > > @@ -433,8 +433,9 @@ ptrace_ctrl(struct proc *p, int req, pid
> > >* from where it stopped."
> > >*/
> > >  
> > > - if (pid < THREAD_PID_OFFSET && tr->ps_single)
> > > - t = tr->ps_single;
> > > + st = tr->ps_single;
> > > + if (pid < THREAD_PID_OFFSET && st != NULL)
> > > + t = st;
> > >  
> > >   /* If the address parameter is not (int *)1, set the pc. */
> > >   if ((int *)addr != (int *)1)
> > > @@ -464,8 +465,9 @@ ptrace_ctrl(struct proc *p, int req, pid
> > >* from where it stopped."
> > >*/
> > >  
> > > - if (pid < THREAD_PID_OFFSET && tr->ps_single)
> > > - t = tr->ps_single;
> > > + st = tr->ps_single;
> > > + if (pid < THREAD_PID_OFFSET && st != NULL)
> > > + t = st;
> > >  
> > >  #ifdef PT_STEP
> > >   /*
> > > @@ -495,8 +497,9 @@ ptrace_ctrl(struct proc *p, int req, pid
> > >   break;
> > >  
> > >   case 

Re: Read `ps_single' once

2021-03-04 Thread Patrick Wildt
Am Thu, Mar 04, 2021 at 10:42:24AM +0100 schrieb Mark Kettenis:
> > Date: Thu, 4 Mar 2021 10:34:24 +0100
> > From: Martin Pieuchot 
> > 
> > Running t/rw/msleep(9) w/o KERNEL_LOCK() implies that a thread can
> > change the value of `ps_single' while one of its siblings might be
> > dereferencing it.  
> > 
> > To prevent inconsistencies in the code executed by sibling thread, the
> > diff below makes sure `ps_single' is dereferenced only once in various
> > parts of the kernel.
> > 
> > ok?
> 
> I think that means that ps_single has to be declared "volatile".

Isn't there the READ_ONCE(x) macro, that does exactly that?

> > Index: kern/kern_exit.c
> > ===
> > RCS file: /cvs/src/sys/kern/kern_exit.c,v
> > retrieving revision 1.196
> > diff -u -p -r1.196 kern_exit.c
> > --- kern/kern_exit.c15 Feb 2021 09:35:59 -  1.196
> > +++ kern/kern_exit.c4 Mar 2021 09:29:27 -
> > @@ -274,6 +274,8 @@ exit1(struct proc *p, int xexit, int xsi
> >  */
> > if (qr->ps_flags & PS_TRACED &&
> > !(qr->ps_flags & PS_EXITING)) {
> > +   struct proc *st;
> > +
> > process_untrace(qr);
> >  
> > /*
> > @@ -281,9 +283,9 @@ exit1(struct proc *p, int xexit, int xsi
> >  * direct the signal to the active
> >  * thread to avoid deadlock.
> >  */
> > -   if (qr->ps_single)
> > -   ptsignal(qr->ps_single, SIGKILL,
> > -   STHREAD);
> > +   st = qr->ps_single;
> > +   if (st != NULL)
> > +   ptsignal(st, SIGKILL, STHREAD);
> > else
> > prsignal(qr, SIGKILL);
> > } else {
> > @@ -510,7 +512,7 @@ dowait4(struct proc *q, pid_t pid, int *
> >  {
> > int nfound;
> > struct process *pr;
> > -   struct proc *p;
> > +   struct proc *p, *st;
> > int error;
> >  
> > if (pid == 0)
> > @@ -541,10 +543,11 @@ loop:
> > proc_finish_wait(q, p);
> > return (0);
> > }
> > +
> > +   st = pr->ps_single;
> > if (pr->ps_flags & PS_TRACED &&
> > -   (pr->ps_flags & PS_WAITED) == 0 && pr->ps_single &&
> > -   pr->ps_single->p_stat == SSTOP &&
> > -   (pr->ps_single->p_flag & P_SUSPSINGLE) == 0) {
> > +   (pr->ps_flags & PS_WAITED) == 0 && st != NULL &&
> > +   st->p_stat == SSTOP && (st->p_flag & P_SUSPSINGLE) == 0) {
> > if (single_thread_wait(pr, 0))
> > goto loop;
> >  
> > Index: kern/sys_process.c
> > ===
> > RCS file: /cvs/src/sys/kern/sys_process.c,v
> > retrieving revision 1.86
> > diff -u -p -r1.86 sys_process.c
> > --- kern/sys_process.c  8 Feb 2021 10:51:02 -   1.86
> > +++ kern/sys_process.c  4 Mar 2021 09:29:27 -
> > @@ -273,7 +273,7 @@ sys_ptrace(struct proc *p, void *v, regi
> >  int
> >  ptrace_ctrl(struct proc *p, int req, pid_t pid, caddr_t addr, int data)
> >  {
> > -   struct proc *t; /* target thread */
> > +   struct proc *st, *t;/* target thread */
> > struct process *tr; /* target process */
> > int error = 0;
> > int s;
> > @@ -433,8 +433,9 @@ ptrace_ctrl(struct proc *p, int req, pid
> >  * from where it stopped."
> >  */
> >  
> > -   if (pid < THREAD_PID_OFFSET && tr->ps_single)
> > -   t = tr->ps_single;
> > +   st = tr->ps_single;
> > +   if (pid < THREAD_PID_OFFSET && st != NULL)
> > +   t = st;
> >  
> > /* If the address parameter is not (int *)1, set the pc. */
> > if ((int *)addr != (int *)1)
> > @@ -464,8 +465,9 @@ ptrace_ctrl(struct proc *p, int req, pid
> >  * from where it stopped."
> >  */
> >  
> > -   if (pid < THREAD_PID_OFFSET && tr->ps_single)
> > -   t = tr->ps_single;
> > +   st = tr->ps_single;
> > +   if (pid < THREAD_PID_OFFSET && st != NULL)
> > +   t = st;
> >  
> >  #ifdef PT_STEP
> > /*
> > @@ -495,8 +497,9 @@ ptrace_ctrl(struct proc *p, int req, pid
> > break;
> >  
> > case PT_KILL:
> > -   if (pid < THREAD_PID_OFFSET && tr->ps_single)
> > -   t = tr->ps_single;
> > +   st = tr->ps_single;
> > +   if (pid < THREAD_PID_OFFSET && st != NULL)
> > +   t = st;
> >  
> > /* just send the process a KILL signal. */
> >  

Re: Read `ps_single' once

2021-03-04 Thread Mark Kettenis
> Date: Thu, 4 Mar 2021 10:34:24 +0100
> From: Martin Pieuchot 
> 
> Running t/rw/msleep(9) w/o KERNEL_LOCK() implies that a thread can
> change the value of `ps_single' while one of its siblings might be
> dereferencing it.  
> 
> To prevent inconsistencies in the code executed by sibling thread, the
> diff below makes sure `ps_single' is dereferenced only once in various
> parts of the kernel.
> 
> ok?

I think that means that ps_single has to be declared "volatile".

> Index: kern/kern_exit.c
> ===
> RCS file: /cvs/src/sys/kern/kern_exit.c,v
> retrieving revision 1.196
> diff -u -p -r1.196 kern_exit.c
> --- kern/kern_exit.c  15 Feb 2021 09:35:59 -  1.196
> +++ kern/kern_exit.c  4 Mar 2021 09:29:27 -
> @@ -274,6 +274,8 @@ exit1(struct proc *p, int xexit, int xsi
>*/
>   if (qr->ps_flags & PS_TRACED &&
>   !(qr->ps_flags & PS_EXITING)) {
> + struct proc *st;
> +
>   process_untrace(qr);
>  
>   /*
> @@ -281,9 +283,9 @@ exit1(struct proc *p, int xexit, int xsi
>* direct the signal to the active
>* thread to avoid deadlock.
>*/
> - if (qr->ps_single)
> - ptsignal(qr->ps_single, SIGKILL,
> - STHREAD);
> + st = qr->ps_single;
> + if (st != NULL)
> + ptsignal(st, SIGKILL, STHREAD);
>   else
>   prsignal(qr, SIGKILL);
>   } else {
> @@ -510,7 +512,7 @@ dowait4(struct proc *q, pid_t pid, int *
>  {
>   int nfound;
>   struct process *pr;
> - struct proc *p;
> + struct proc *p, *st;
>   int error;
>  
>   if (pid == 0)
> @@ -541,10 +543,11 @@ loop:
>   proc_finish_wait(q, p);
>   return (0);
>   }
> +
> + st = pr->ps_single;
>   if (pr->ps_flags & PS_TRACED &&
> - (pr->ps_flags & PS_WAITED) == 0 && pr->ps_single &&
> - pr->ps_single->p_stat == SSTOP &&
> - (pr->ps_single->p_flag & P_SUSPSINGLE) == 0) {
> + (pr->ps_flags & PS_WAITED) == 0 && st != NULL &&
> + st->p_stat == SSTOP && (st->p_flag & P_SUSPSINGLE) == 0) {
>   if (single_thread_wait(pr, 0))
>   goto loop;
>  
> Index: kern/sys_process.c
> ===
> RCS file: /cvs/src/sys/kern/sys_process.c,v
> retrieving revision 1.86
> diff -u -p -r1.86 sys_process.c
> --- kern/sys_process.c8 Feb 2021 10:51:02 -   1.86
> +++ kern/sys_process.c4 Mar 2021 09:29:27 -
> @@ -273,7 +273,7 @@ sys_ptrace(struct proc *p, void *v, regi
>  int
>  ptrace_ctrl(struct proc *p, int req, pid_t pid, caddr_t addr, int data)
>  {
> - struct proc *t; /* target thread */
> + struct proc *st, *t;/* target thread */
>   struct process *tr; /* target process */
>   int error = 0;
>   int s;
> @@ -433,8 +433,9 @@ ptrace_ctrl(struct proc *p, int req, pid
>* from where it stopped."
>*/
>  
> - if (pid < THREAD_PID_OFFSET && tr->ps_single)
> - t = tr->ps_single;
> + st = tr->ps_single;
> + if (pid < THREAD_PID_OFFSET && st != NULL)
> + t = st;
>  
>   /* If the address parameter is not (int *)1, set the pc. */
>   if ((int *)addr != (int *)1)
> @@ -464,8 +465,9 @@ ptrace_ctrl(struct proc *p, int req, pid
>* from where it stopped."
>*/
>  
> - if (pid < THREAD_PID_OFFSET && tr->ps_single)
> - t = tr->ps_single;
> + st = tr->ps_single;
> + if (pid < THREAD_PID_OFFSET && st != NULL)
> + t = st;
>  
>  #ifdef PT_STEP
>   /*
> @@ -495,8 +497,9 @@ ptrace_ctrl(struct proc *p, int req, pid
>   break;
>  
>   case PT_KILL:
> - if (pid < THREAD_PID_OFFSET && tr->ps_single)
> - t = tr->ps_single;
> + st = tr->ps_single;
> + if (pid < THREAD_PID_OFFSET && st != NULL)
> + t = st;
>  
>   /* just send the process a KILL signal. */
>   data = SIGKILL;
> @@ -536,6 +539,7 @@ int
>  ptrace_kstate(struct proc *p, int req, pid_t pid, void *addr)
>  {
>   struct process *tr; /* target process */
> + struct proc *st;
>   struct ptrace_event