Re: [PATCH 0/1] Was: utrace-cleanup branch

2009-11-13 Thread Oleg Nesterov
On 11/12, Oleg Nesterov wrote:

 On 11/12, Roland McGrath wrote:
 
  I did some tweaks that I think address the several things you've raised.
  But I didn't try to reply point by point.  I've merged everything up now,
  so the utrace-cleanup branch is gone.  Please review the current code and
  post about anything we still need to fix.

 Great, thanks.

 I will definitely read the changes in utrace.c, if nothing else this is
 interesting to me. But for now, until utrace-ptrace is updated/finished,
 I will assume it is correct and doesn't need any further changes.

(except the SIGTRAP changes in utrace_report_syscall_exit() we are discussing
 in another thread)

Roland, I pulled the last changes in your tree (utrace-cleanup merged
in utrace-ptrace) and did some testing.

In short: utrace-ptrace does not work at all.

It fails a lot (if not most) of tests, in particular
sa-resethand-on-cont-signal hangs and clone-multi-ptrace silently
crashes the kernel.

The quick investigation didn't help, utrace.c has too much changes,
I will read the code tomorrow from the very beginning.

Today I am going to pretend utrace works and do the discussed changes
in utrace-ptrace, then try to fix utrace.

Oleg.



Re: [PATCH 0/1] Was: utrace-cleanup branch

2009-11-12 Thread Roland McGrath
I did some tweaks that I think address the several things you've raised.
But I didn't try to reply point by point.  I've merged everything up now,
so the utrace-cleanup branch is gone.  Please review the current code and
post about anything we still need to fix.

I merged into utrace-ptrace and did the trivial hack to handle
UTRACE_SYSCALL_RESUMED.  Later we probably want to change this to some
smarter handling so that ptrace doesn't report until other engines have
finished their fiddling and let the thread resume.  That way we can have
e.g. strace vs kmview show something consistent.  But we can refine this
later.  I think what I did is sufficient to maintain the status quo in your
code.  You can fix it up as needed.


Thanks,
Roland



Re: [PATCH 0/1] Was: utrace-cleanup branch

2009-11-12 Thread Oleg Nesterov
On 11/12, Roland McGrath wrote:

 I did some tweaks that I think address the several things you've raised.
 But I didn't try to reply point by point.  I've merged everything up now,
 so the utrace-cleanup branch is gone.  Please review the current code and
 post about anything we still need to fix.

Great, thanks.

I will definitely read the changes in utrace.c, if nothing else this is
interesting to me. But for now, until utrace-ptrace is updated/finished,
I will assume it is correct and doesn't need any further changes.

Oleg.



Re: [PATCH 0/1] Was: utrace-cleanup branch

2009-11-04 Thread Roland McGrath
 3. Now that we have utrace-resume, can't we kill report-resume_action ?

I thought this initially when making the change and then decided against
it.  I don't recall exactly what was in my mind at the time.  It would
take some more thought now to be sure whether there is a semantic
problem.  But at any rate, keeping it reduces the number of cases in
which we take the utrace lock in finish_callback_report, which seems
like a good thing.  Still, if you propose a patch to remove it with
thorough rationale on why it's good or better, then that will be fine.


Thanks,
Roland



Re: [PATCH 0/1] Was: utrace-cleanup branch

2009-11-03 Thread Roland McGrath
 8. Completely off-topic, but utrace_control() has a very strange comment
under case UTRACE_INTERRUPT,
 
* When it's stopped, we know it's always going
* through utrace_get_signal() and will recalculate.
 
can't recall if it were ever true, but surely it is not now?

I think what's true now is what's always been true.  The comment is a bit
confusing, though.  The two kinds of stopped are inside do_signal_stop()
and inside utrace_stop().  In the former, it is inside the signal-checking
loop and will check again.  In the latter, utrace_stop() ends with a call
to recalc_sigpending().


Thanks,
Roland



Re: [PATCH 0/1] Was: utrace-cleanup branch

2009-11-03 Thread Roland McGrath
 4. One of the changes in utrace_get_signal() doesn't look exactly right.
 
   if (utrace-resume  UTRACE_RESUME || utrace-signal_handler) {
   ...
   if (resume  UTRACE_REPORT) {
   report.action = resume;
   finish_resume_report(report);
   }
 
Yes, we need finish_resume_report() here, but since report-takers
is not set, finish_report_reset() will always call utrace_reset().
 
OTOH, we can't set -takers before finish_resume_report(), we can
miss UTRACE_DETACH request. utrace_control(DETACH)-utrace_do_stop()
does not change utrace-resume != UTRACE_RESUME.
 
And since utrace_do_stop() never upgrades utrace-resume, we have
another problem: UTRACE_STOP request can be lost here.

Hmm.  Maybe this?

diff --git a/kernel/utrace.c b/kernel/utrace.c
index f46854b..000 100644  
--- a/kernel/utrace.c
+++ b/kernel/utrace.c
@@ -1740,8 +1740,6 @@ static void finish_resume_report(struct 
 struct task_struct *task,
 struct utrace *utrace)
 {
-   finish_report_reset(task, utrace, report);
-
switch (report-action) {
case UTRACE_STOP:
utrace_stop(task, utrace, report-resume_action);
@@ -1829,6 +1827,8 @@ void utrace_resume(struct task_struct *t
report.action = UTRACE_RESUME;
list_for_each_entry(engine, utrace-attached, entry)
start_callback(utrace, report, engine, task, 0);
+
+   finish_report_reset(task, utrace, report);
}
 
/*
@@ -2147,6 +2147,7 @@ int utrace_get_signal(struct task_struct
 * as in utrace_resume(), above.  After we've dealt with that,
 * our caller will relock and come back through here.
 */
+   finish_report_reset(task, utrace, report);
finish_resume_report(report, task, utrace);
 
if (unlikely(fatal_signal_pending(task))) {


 5. utrace_resume() has the same problems. If report-action != REPORT
we do not call callbacks and finish_resume_report() is called with
-takers == F.

 6. But! I think utrace_resume() was always wrong here. Because it
calls start_callback(events = 0) and thus we nevet set -takers.

I think that change covers these too.  What do you think?


Thanks,
Roland



Re: [PATCH 0/1] Was: utrace-cleanup branch

2009-11-03 Thread Roland McGrath
 7. utrace_attach_task() has an implicit wmb() between -utrace = new_utrace
and -utrace_flags = REAP, this is good.
 
But, for example, tracehook_force_sigpending() does not have rmb(),
this means utrace_interrupt_pending() can OOPS in theory.

Ok.  Please send a patch.  Off hand it seems to me it isn't worth using a
barrier because the winner of that race doesn't matter.  So:

struct utrace *utrace = task_utrace_struct(current);
return likely(utrace)  utrace-resume == UTRACE_INTERRUPT;

is fine, right?  (With comment changes to explain the need for the check.)


Thanks,
Roland



Re: [PATCH 0/1] Was: utrace-cleanup branch

2009-11-03 Thread Roland McGrath
 2. Cosmetic, but the usage of utrace_task_alloc() looks a bit strange.
Why it returns bool, not struct utrace * ?

The pointer it would return is always target-utrace or it's NULL.
So the bool just says which of those it would be instead.  Either
way I imagine it should be inlined so the check on the return value
from kmem_cache_zalloc is the only test/branch.  I have no special
opinion about the cosmetic choice.  Whatever you and/or upstream
prefer is fine.  Send a patch if you would like it to be different.


Thanks,
Roland



[PATCH 0/1] Was: utrace-cleanup branch

2009-11-02 Thread Oleg Nesterov
On 10/28, Roland McGrath wrote:

 I've made a new branch, utrace-cleanup.
 This forks from utrace-indirect and has:

 26fefca utrace: sticky resume action
 28b2774 utrace: remove -stopped field

I am not sure I understand the new code in details - too much changes.
Anyway, I can never understand the code after the first reading. At
first glance, imho this change is right in general but:

1. This breaks the current implementation of utrace-ptrace.

  I guess I misunderstood you when we discussed this before, I thought
  that the tracee should handle UTRACE_SINGLESTEP right after resume
  and call user_enable_single_step(). However, enable_step() is called
  at utrace_resume/utrace_get_signal time, this is too late for ptrace.

  I guess this branch is the code which will be sent to lkml, right?

  In this case utrace-cleanup should be merged into utrace-ptrace right
  now, then I need to fix ptrace. Basically, ptrace_report_quiesce() and
  ptrace_report_interrupt() should detect the case when the tracee was
  resumed by PTRACE_XXXSTEP and then it passed syscall_trace_leave()
  without TIF_SINGLESTEP, and synthesize a trap.

  The main problem is that this is not consistent across the different
  arch'es :[


2. Cosmetic, but the usage of utrace_task_alloc() looks a bit strange.
   Why it returns bool, not struct utrace * ?


3. Now that we have utrace-resume, can't we kill report-resume_action ?


4. One of the changes in utrace_get_signal() doesn't look exactly right.

if (utrace-resume  UTRACE_RESUME || utrace-signal_handler) {
...
if (resume  UTRACE_REPORT) {
report.action = resume;
finish_resume_report(report);
}

   Yes, we need finish_resume_report() here, but since report-takers
   is not set, finish_report_reset() will always call utrace_reset().

   OTOH, we can't set -takers before finish_resume_report(), we can
   miss UTRACE_DETACH request. utrace_control(DETACH)-utrace_do_stop()
   does not change utrace-resume != UTRACE_RESUME.

   And since utrace_do_stop() never upgrades utrace-resume, we have
   another problem: UTRACE_STOP request can be lost here.


5. utrace_resume() has the same problems. If report-action != REPORT
   we do not call callbacks and finish_resume_report() is called with
   -takers == F.

6. But! I think utrace_resume() was always wrong here. Because it
   calls start_callback(events = 0) and thus we nevet set -takers.


7. utrace_attach_task() has an implicit wmb() between -utrace = new_utrace
   and -utrace_flags = REAP, this is good.

   But, for example, tracehook_force_sigpending() does not have rmb(),
   this means utrace_interrupt_pending() can OOPS in theory.


8. Completely off-topic, but utrace_control() has a very strange comment
   under case UTRACE_INTERRUPT,

 * When it's stopped, we know it's always going
 * through utrace_get_signal() and will recalculate.

   can't recall if it were ever true, but surely it is not now?

Oleg.



Re: utrace-cleanup branch

2009-10-29 Thread Oleg Nesterov
Btw, why does utrace_set_events() check utrace-stopped?

If a tracee is stopped then -reporting == engine is not possible,
-reporting must be NULL.

To optimize out other checks + mb() in the likely stopped case?

Oleg.



Re: utrace-cleanup branch

2009-10-29 Thread Roland McGrath
 To optimize out other checks + mb() in the likely stopped case?

Yes.


Thanks,
Roland



Re: utrace-cleanup branch

2009-10-29 Thread Roland McGrath
 Can't comment right now, need to read the code.

Such gentlemanly restraint.

 Afaics, we can't just remove utrace_finish_jctl() and the similar code in
 utrace_stop(). We need
 
   void utrace_finish_jctl(void)
   {
   struct utrace *utrace = task_utrace_struct(current);
   /*
* While in TASK_STOPPED, we can be considered safely stopped by
* utrace_do_stop(). Make sure we can do nothing until the 
 tracer
* drops utrace-lock
*/
   if (unlikely(__fatal_signal_pending()))
   spin_unlock_wait(utrace-lock);
   }
 
 and utrace_stop() should do the same.

I see.  The comments should be more clear that SIGKILL breaking
TASK_TRACED is the only way this can arise.  In the jctl case, that is
in particular after utrace_do_stop() changed TASK_STOPPED into TASK_TRACED.

 Otherwise, the killed tracee can start another reporting loop and
 list_for_each() can race with, say, utrace_reset(DETACH)-utrace_reset().
 More generally, if the tracer sees it is stopped under utrace-lock,
 the tracee must be really stopped until we drop utrace-lock(), it
 must not escape from utrace_stop() or do_signal_stop().

Correct.

So today -stopped really does still mean one other thing.  It means
that it's either still in TASK_TRACED or is just waking up for SIGKILL.

I think we've discussed the related stuff before.  A contrary approach
would be to ensure that in the SIGKILL-breaks-UTRACE_STOP case we never
make any more normal reports at all before utrace_report_death.  It
seems like a good API choice on its face: if you used UTRACE_STOP, you
didn't expect to see any SYSCALL_EXIT, SIGNAL, etc. events--the special
case is the instant-death scenario, so straight to report_death makes
some sense.  I was attracted by this until I started going through it.
It's all good until you consider report_clone.  If a SIGKILL is pending
when you get to utrace_report_clone(), the clone has already happened.
If you skip that callback, the engine doesn't find out about the new
child, and that matters if it's not a CLONE_THREAD.


Thanks,
Roland



Re: utrace-cleanup branch

2009-10-29 Thread Oleg Nesterov
On 10/29, Roland McGrath wrote:

  void utrace_finish_jctl(void)
  {
  struct utrace *utrace = task_utrace_struct(current);
  /*
   * While in TASK_STOPPED, we can be considered safely stopped by
   * utrace_do_stop(). Make sure we can do nothing until the 
  tracer
   * drops utrace-lock
   */
  if (unlikely(__fatal_signal_pending()))
  spin_unlock_wait(utrace-lock);
  }
 
  and utrace_stop() should do the same.

 I see.  The comments should be more clear that SIGKILL breaking
 TASK_TRACED is the only way this can arise.  In the jctl case, that is
 in particular after utrace_do_stop() changed TASK_STOPPED into TASK_TRACED.

Agreed.

 So today -stopped really does still mean one other thing.  It means
 that it's either still in TASK_TRACED or is just waking up for SIGKILL.

 I think we've discussed the related stuff before.  A contrary approach
 would be to ensure that in the SIGKILL-breaks-UTRACE_STOP case we never
 make any more normal reports at all before utrace_report_death.

Yes, I agree.

 I was attracted by this until I started going through it.
 It's all good until you consider report_clone.  If a SIGKILL is pending
 when you get to utrace_report_clone(), the clone has already happened.
 If you skip that callback, the engine doesn't find out about the new
 child, and that matters if it's not a CLONE_THREAD.

another nasty case is report_exit(). Even if we fix the discussed problems
with explicit/implicit SIGKILL's. We shouldn't afaics skip this report if
the tracee was killed by execing sub-thread.

Both can be fixed if we add spin_unlock_wait() before REPORT(). But imho
it would be safer if we start with spin_unlock_wait() in utrace_stop(),
perhaps there is something else to consider.

Oleg.



utrace-cleanup branch

2009-10-28 Thread Roland McGrath
I've made a new branch, utrace-cleanup.
This forks from utrace-indirect and has:

26fefca utrace: sticky resume action
28b2774 utrace: remove -stopped field

Those are the two changes we talked about during tangential ptrace discussions.

Again, I have compiled these but not tested a lick.  I'd just like to get
some feedback.  They both seem like happy clean-ups to me, making the code
smaller and simpler.

What do you think?


Thanks,
Roland