Re: [PATCH 133] stepping, accommodate to utrace-cleanup changes
The former is e.g. PTRACE_SINGLESTEP while an unrelated engine uses UTRACE_EVENT(SYSCALL_ENTRY). The ptrace engine's report_quiesce returns UTRACE_SINGLESTEP. finish_resume_report() calls user_enable_single_step(). That seems fine. Right? In this case ptrace_report_quiesce(event) returns UTRACE_RESUME, note that it does return event ? UTRACE_RESUME : ctx-resume; and event == SYSCALL_ENTRY. This looks correct. With the utrace layer changes we're discussing, we need it to return UTRACE_SINGLESTEP (i.e. ctx-resume) here. AFAICT that never hurts even with today's utrace layer. I see. finish_resume_report() will only do utrace_stop() and then we'll go directly into the syscall unless someone used UTRACE_REPORT. Yes, utrace_stop() will only set TIF_NOTIFY_RESUME and utrace-resume. In the real resume-to-user cases, that's fine because we'll handle that in utrace_resume() or utrace_get_signal() before doing anything else. Not sure I understand. utrace_stop() will not set TIF_NOTIFY_RESUME? We are talking about the case when the tracee stops in SYSCALL_ENTER, and then the tracer does utrace_control(UTRACE_SINGLESTEP) to resume. In this case utrace_control() sets -resume/TIF_NOTIFY_RESUME, yes. I think you do understand fine. Yes, that's what it will do. I was just recognizing that this isn't enough in the syscall-entry case. this seems like the right idea for how to get tracehook_report_syscall_exit called in the cases where it is in old ptrace. Afaics yes. But, what if another engine does utrace_control(UTRACE_INTERRUPT) ? Hmm. Yes, I think this is the one case that is unlike all the others. That is, UTRACE_INTERRUPT at syscall-entry. In all other cases, nothing would care about utrace-resume until we get to get_signal_to_deliver anyway, where the UTRACE_SIGNAL_REPORT pass will trump any pending resume action anyway so you don't care that you lost track of it when UTRACE_INTERRUPT came in. Hmm. So what does UTRACE_INTERRUPT mean here anyway? It means that we should report soon and that signal_pending() should be true until that report. So today that means you can get into the syscall with signal_pending() and depending on the particular call that might cause a normal blocking path not to block and/or a -EINTR/-ERESTART* return, but some syscalls will just complete normally. How about if we say that UTRACE_INTERRUPT at syscall-entry means that the syscall really doesn't happen at all? That is, instead, you force an -ERESTARTNOHAND return and the normal roll-back such that you get your report_signal callback before the syscall is entered. That even seems like a useful utrace API feature, as well as conveniently smoothing over this quirk in the resume action handling. My idea here is that this makes it OK to lose UTRACE_SINGLESTEP here because from the user-mode-centric perspective no instruction has happened yet. The original guy who did UTRACE_SINGLESTEP (and perhaps never cared about syscall tracing) will get a generic report_quiesce or report_signal at which it needs to reassert UTRACE_SINGLESTEP. This merits more thought. For now, let's just leave an XXX comment about a UTRACE_INTERRUPT effectively swallowing the UTRACE_SINGLESTEP that should cause utrace_report_syscall_exit to be called. I think we can revisit this corner after we have merged up all the rest of it. Argh. I meant, from the caller pov, utrace_control(UTRACE_SINGLESTEP) does enable_step() immediately, like it did before utrace-cleanup changes. I see. From the utrace API perspective, I don't think anything changes here. In today's code, the resume action can take effect without a subsequent utrace callback. So that's the same as it ever was, and where this actually happens is not something that a utrace caller should know or can tell. IOW, suppose the tracee is stopped, and ptrace does UTRACE_SINGLESTEP. The tracee resumes, processes -resume, and does enable_step(). From the ptrace pov, it looks as if utrace_control() does enable_step() before utrace_wakeup(). Sure. I meant, every time the tracee stops, it should process -resume after wakeup. Looks like, the patch you sent in another thread (which adds apply_resume_action()) does something like this, right? Right. Thanks, Roland
Re: [PATCH 133] stepping, accommodate to utrace-cleanup changes
On 11/18, Roland McGrath wrote: Hmm. not sure I understand how this can work. I mean, this won't enable stepping (in this particular case we are discussing). I might be confused. I'm thinking of two cases: the report_syscall_entry pass yields UTRACE_SINGLESTEP, or that it yields UTRACE_STOP and then utrace_control() sets utrace-resume to UTRACE_SINGLESTEP. The former is e.g. PTRACE_SINGLESTEP while an unrelated engine uses UTRACE_EVENT(SYSCALL_ENTRY). The ptrace engine's report_quiesce returns UTRACE_SINGLESTEP. finish_resume_report() calls user_enable_single_step(). That seems fine. Right? In this case ptrace_report_quiesce(event) returns UTRACE_RESUME, note that it does return event ? UTRACE_RESUME : ctx-resume; and event == SYSCALL_ENTRY. This looks correct. The latter is e.g. PTRACE_SINGLESTEP after ptrace stop at syscall entry. Yes, this is the case I was talking about. I see. finish_resume_report() will only do utrace_stop() and then we'll go directly into the syscall unless someone used UTRACE_REPORT. Yes, utrace_stop() will only set TIF_NOTIFY_RESUME and utrace-resume. In the real resume-to-user cases, that's fine because we'll handle that in utrace_resume() or utrace_get_signal() before doing anything else. Not sure I understand. utrace_stop() will not set TIF_NOTIFY_RESUME? We are talking about the case when the tracee stops in SYSCALL_ENTER, and then the tracer does utrace_control(UTRACE_SINGLESTEP) to resume. In this case utrace_control() sets -resume/TIF_NOTIFY_RESUME, yes. @@ -1794,11 +1794,13 @@ static void finish_resume_report(struct { finish_report_reset(task, utrace, report); - switch (report-action) { - case UTRACE_STOP: - utrace_stop(task, utrace, report-resume_action); - break; + if (report-action == UTRACE_STOP) { + utrace_stop(task, utrace, report-resume_action, true); + report-action = start_report(utrace); + WARN_ON(report-action == UTRACE_STOP); + } + switch (report-action) { case UTRACE_INTERRUPT: if (!signal_pending(task)) set_tsk_thread_flag(task, TIF_SIGPENDING); Yes, this means the tracee gets TIF_SINGLESTEP right after resume, and this seems like the right idea for how to get tracehook_report_syscall_exit called in the cases where it is in old ptrace. Afaics yes. But, what if another engine does utrace_control(UTRACE_INTERRUPT) ? Instead of fixing utrace_report_syscall_entry(), perhaps we should change utrace_stop() path to enable the stepping if needed, but this means we return to synchronous utrace_control(UTRACE_XXXSTEP). I don't really follow what you mean by synchronous. Argh. I meant, from the caller pov, utrace_control(UTRACE_SINGLESTEP) does enable_step() immediately, like it did before utrace-cleanup changes. IOW, suppose the tracee is stopped, and ptrace does UTRACE_SINGLESTEP. The tracee resumes, processes -resume, and does enable_step(). From the ptrace pov, it looks as if utrace_control() does enable_step() before utrace_wakeup(). Your suggestion is equivalent to making utrace_finish_vfork call finish_resume_report instead of utrace_stop, isn't it? I meant, every time the tracee stops, it should process -resume after wakeup. Looks like, the patch you sent in another thread (which adds apply_resume_action()) does something like this, right? I'll try to read it carefully now. Oleg.
Re: copy_process utrace_init_task (Was: [PATCH 133] stepping, accommodate to utrace-cleanup changes)
Found the trivial but nasty problem. Ah! Good catch. I added tracehook_init_task() in my tree. I don't see much benefit in sending any tracehook patch upstream for this. tracehook_init_task() corresponds to tracehook_free_task(), which is only added by utrace (and both would just be empty in a separate preparatory patch). I don't see any reason to fiddle the ptrace_init_task() call. The setup it does is all stuff that only matters for teardown done by release_task() or even earlier in the exit sequence. So it makes enough sense that the setup side should happen later as it does now. In the long run, the ptrace init stuff will all just go away. Before then I can't see any rationale for touching it. Thanks, Roland
Re: copy_process utrace_init_task (Was: [PATCH 133] stepping, accommodate to utrace-cleanup changes)
On 11/18, Roland McGrath wrote: I added tracehook_init_task() in my tree. I don't see much benefit in sending any tracehook patch upstream for this. tracehook_init_task() corresponds to tracehook_free_task(), which is only added by utrace (and both would just be empty in a separate preparatory patch). I don't see any reason to fiddle the ptrace_init_task() call. ... In the long run, the ptrace init stuff will all just go away. OK, agreed. Oleg.
Re: [PATCH 133] stepping, accommodate to utrace-cleanup changes
On 11/18, Roland McGrath wrote: Once again. The tracee sleeps in SYSCALL_ENTER. The tracer resumes the tracee via utrace_control(UTRACE_SINGLESTEP). Right. This is another strange corner. It doesn't necessarily make especially good sense intrinsically for single-step to have this meaning from this place. But it's the status quo in the ptrace interface. Yes. So, I think we should do something like tracehook_report_syscall_exit(step) // do not use step at all if (task_utrace_flags() != 0) utrace_report_syscall_exit(); The trouble here is that the arch code looks like this: step = test_thread_flag(TIF_SINGLESTEP); if (step || test_thread_flag(TIF_SYSCALL_TRACE)) tracehook_report_syscall_exit(regs, step); i.e. unless syscall tracing is enabled, we won't even get there at all. You are right, I missed this. utrace_report_syscall_exit() if (UTRACE_EVENT(SYSCALL_EXIT)) REPORT(report_syscall_exit); if (utrace-resume == UTRACE_SINGLESTEP || utrace-resume == UTRACE_BLOCKSTEP) send_sigtrap(); What do you think? This can't work in the REPORT case. There start_report() will have reset utrace-resume, Yes, yes, the pseudo-code above was just for illustration. (This would go with un-reverting f19442c and reverting 3bd4be9.) --- a/kernel/utrace.c +++ b/kernel/utrace.c @@ -1584,20 +1584,25 @@ static inline u32 do_report_syscall_entr UTRACE_EVENT(SYSCALL_ENTRY), report_syscall_entry, resume_report | report-result | report-action, engine, current, regs); - finish_report(task, utrace, report, false); + + /* + * Now we'll stop if asked. If we're proceeding with the syscall, + * now we'll first enable single-step if asked. That leaves the + * task in stepping state so tracehook_report_syscall_exit() and + * the arch code that calls it will know. + */ + finish_resume_report(task, utrace, report); Hmm. not sure I understand how this can work. I mean, this won't enable stepping (in this particular case we are discussing). - } else if (utrace-resume == UTRACE_REPORT) { + } else if (utrace-resume = UTRACE_REPORT) { perhaps, you meant = UTRACE_REPORT ? In this case yes, UTRACE_SINGLESTEP will be noticed after resume, and ptrace or another engine can reassert it during the next reporting loop, and then finish_resume_report() will enable the stepping. But we can't trust =, another engine can do utrace_control(INTERRUPT) and change -resume before the tracee resumes. OK, probably I missed the implemenation details, but I think I got the idea, and this should fix the step-after-syscall_enter problem. But. We have the same problem with utrace_finish_vfork(), no? Instead of fixing utrace_report_syscall_entry(), perhaps we should change utrace_stop() path to enable the stepping if needed, but this means we return to synchronous utrace_control(UTRACE_XXXSTEP). Oleg.
Re: [PATCH 133] stepping, accommodate to utrace-cleanup changes
I'll reply tomorrow, it is to late for me. But I noticed the funny detail in your email, On 11/18, Roland McGrath wrote: Yes. But, hmm. utrace_stop(task, utrace, UTRACE_RESUME); /* XXX */ This XXX was there about passing UTRACE_RESUME, because that's not really right. I didn't notice this XXX marker, but I guess I just sent the patch which makes this case correct. (of course this patch doesn't fix the problem we are dicussing in this thread). Oleg.
copy_process utrace_init_task (Was: [PATCH 133] stepping, accommodate to utrace-cleanup changes)
On 11/16, Oleg Nesterov wrote: On 11/16, Oleg Nesterov wrote: And I didn't check make xcheck, I guess it still crashes the kernel. Yes it does. I am almost sure the bug should be trivial, but somehow can't find find it. Found the trivial but nasty problem. tracehook_finish_clone()-utrace_init_task() sets -utrace = NULL, but this is too late. If copy_process() fails before, tracehook_free_task() will free parent's -utrace copied by dup_task_struct(). This is nasty because we need some changes outside of utrace/tracehook files. Perhaps we should send something like the patch below to Andrew right now? And! While this bug could perfectly explain the crash, it doesn't. I appiled this patch --- UTRACE-PTRACE/kernel/fork.c~XXX_CRASH 2009-11-16 20:26:23.0 +0100 +++ UTRACE-PTRACE/kernel/fork.c 2009-11-17 20:33:50.0 +0100 @@ -1019,6 +1019,7 @@ static struct task_struct *copy_process( if (!p) goto fork_out; +p-utrace = NULL; ftrace_graph_init_task(p); rt_mutex_init_task(p); but make xcheck still crashes. Still investigating. Oleg. --- TH/include/linux/ptrace.h~TH_INIT_TASK 2009-11-10 21:31:25.0 +0100 +++ TH/include/linux/ptrace.h 2009-11-17 20:43:42.0 +0100 @@ -148,6 +148,14 @@ static inline int ptrace_event(int mask, return 1; } +static inline void ptrace_init_task(struct task_struct *child) +{ + INIT_LIST_HEAD(child-ptrace_entry); + INIT_LIST_HEAD(child-ptraced); + child-parent = child-real_parent; + child-ptrace = 0; +} + /** * ptrace_init_task - initialize ptrace state for a new child * @child: new child task @@ -158,12 +166,8 @@ static inline int ptrace_event(int mask, * * Called with current's siglock and write_lock_irq(tasklist_lock) held. */ -static inline void ptrace_init_task(struct task_struct *child, bool ptrace) +static inline void ptrace_finish_clone(struct task_struct *child, bool ptrace) { - INIT_LIST_HEAD(child-ptrace_entry); - INIT_LIST_HEAD(child-ptraced); - child-parent = child-real_parent; - child-ptrace = 0; if (unlikely(ptrace) (current-ptrace PT_PTRACED)) { child-ptrace = current-ptrace; __ptrace_link(child, current-parent); --- TH/include/linux/tracehook.h~TH_INIT_TASK 2009-11-11 21:49:42.0 +0100 +++ TH/include/linux/tracehook.h2009-11-17 20:42:43.0 +0100 @@ -247,6 +247,11 @@ static inline int tracehook_prepare_clon return 0; } +static inline void tracehook_init_task(struct task_struct *child) +{ + ptrace_init_task(child); +} + /** * tracehook_finish_clone - new child created and being attached * @child: new child task @@ -261,7 +266,7 @@ static inline int tracehook_prepare_clon static inline void tracehook_finish_clone(struct task_struct *child, unsigned long clone_flags, int trace) { - ptrace_init_task(child, (clone_flags CLONE_PTRACE) || trace); + ptrace_finish_clone(child, (clone_flags CLONE_PTRACE) || trace); } /** --- TH/kernel/fork.c~TH_INIT_TASK 2009-11-07 22:15:15.0 +0100 +++ TH/kernel/fork.c2009-11-17 20:40:52.0 +0100 @@ -1018,8 +1018,8 @@ static struct task_struct *copy_process( if (!p) goto fork_out; + tracehook_init_task(p); ftrace_graph_init_task(p); - rt_mutex_init_task(p); #ifdef CONFIG_PROVE_LOCKING
tracehook_report_syscall_exit() PT_PTRACED (Was: [PATCH 133] stepping, accommodate to utrace-cleanup changes)
On 11/16, Roland McGrath wrote: The change we talked about before seems simple enough and should cover this without new kludges in the ptrace layer. I did this (commit f19442c). I will reply to this in the next email, I'd like to discuss another minor related issue first. I noticed this change in your tree commit 2583b3267ed599cb25f6f893c24465204e06b3a6 utrace: nit for utrace-ptrace --- a/include/linux/tracehook.h +++ b/include/linux/tracehook.h @@ -143,7 +143,7 @@ static inline void tracehook_report_syscall_exit(struct pt_regs *regs, int step) if (task_utrace_flags(current) UTRACE_EVENT(SYSCALL_EXIT)) utrace_report_syscall_exit(regs); - if (step task_ptrace(current)) { + if (step (task_ptrace(current) PT_PTRACED)) { siginfo_t info; user_single_step_siginfo(current, regs, info); force_sig_info(SIGTRAP, info, current); Yes, and in fact I already had this change in my tree but didn't send it to you yet. But, I can't understand whats going on, - if (step task_ptrace(current)) { + if (step (task_ptrace(current) PT_PTRACED)) { The code after ptrace-change-tracehook_report_syscall_exit-to-handle-stepping.patch is if (step), not if (step task_ptrace(current)), can't understand where did this task_ptrace(current) come from. The previous commit in your tree is 462a57bb7a6a5c67b70e4388f97239f1e4da98df ptrace: change tracehook_report_syscall_exit() to handle stepping Initially I was going to add the change below into tracehooks: prepare for utrace-ptrace, --- a/include/linux/tracehook.h +++ b/include/linux/tracehook.h @@ -134,6 +134,9 @@ static inline __must_check int tracehook */ static inline void tracehook_report_syscall_exit(struct pt_regs *regs, int step) { + if (!(task_ptrace(current) PT_PTRACED)) + return; + if (step) { siginfo_t info; user_single_step_siginfo(current, regs, info); but now I think perhaps it would be better to send ptrace-change-tracehook_report_syscall_exit-to-handle-stepping_fix to akpm right now: --- a/include/linux/tracehook.h +++ b/include/linux/tracehook.h @@ -134,7 +134,7 @@ static inline __must_check int tracehook */ static inline void tracehook_report_syscall_exit(struct pt_regs *regs, int step) { - if (step) { + if (step (task_ptrace(current) PT_PTRACED)) { siginfo_t info; user_single_step_siginfo(current, regs, info); force_sig_info(SIGTRAP, info, current); What do you think? Now, let's return to the original topic. Please note that utrace does not need int step at all, see the next email. Oleg.
Re: [PATCH 133] stepping, accommodate to utrace-cleanup changes
On 11/16, Roland McGrath wrote: Whatever temporary hacks are fine by me one way or the other. They will just be coming out later along with assorted other cleanup. We certainly do want to get this right in the utrace layer. Yes. But imho it is always good to test/review the patches against the working kernel. The patch I sent is very simple, and can be easily reverted once we improve utrace. IOW, I am asking you to apply my patch for now and revert your change to have the working tree, then discuss the right fix. The change we talked about before seems simple enough and should cover this without new kludges in the ptrace layer. I did this (commit f19442c). I don't think this can work. tracehook_report_syscall_exit(step) if (step || UTRACE_EVENT(SYSCALL_EXIT)) utrace_report_syscall_exit(step); and, utrace_report_syscall_exit(step) if (step) send_sigtrap(); The problems is: we can trust bool step, and in fact we do not need it at all. Once again. The tracee sleeps in SYSCALL_ENTER. The tracer resumes the tracee via utrace_control(UTRACE_SINGLESTEP). By the time the resumed tracee passes tracehook_report_syscall_exit() step == F, utrace_control() does not set TIF_SINGLESTEP. So, I think we should do something like tracehook_report_syscall_exit(step) // do not use step at all if (task_utrace_flags() != 0) utrace_report_syscall_exit(); // this code below is only for old ptrace if (step (task_ptrace(current) PT_PTRACED)) send_sigtrap(); ptrace_report_syscall(); and, utrace_report_syscall_exit() if (UTRACE_EVENT(SYSCALL_EXIT)) REPORT(report_syscall_exit); if (utrace-resume == UTRACE_SINGLESTEP || utrace-resume == UTRACE_BLOCKSTEP) send_sigtrap(); What do you think? Oleg.
Re: tracehook_report_syscall_exit() PT_PTRACED (Was: [PATCH 133] stepping, accommodate to utrace-cleanup changes)
but now I think perhaps it would be better to send ptrace-change-tracehook_report_syscall_exit-to-handle-stepping_fix to akpm right now: --- a/include/linux/tracehook.h +++ b/include/linux/tracehook.h @@ -134,7 +134,7 @@ static inline __must_check int tracehook */ static inline void tracehook_report_syscall_exit(struct pt_regs *regs, int step) { - if (step) { + if (step (task_ptrace(current) PT_PTRACED)) { siginfo_t info; user_single_step_siginfo(current, regs, info); force_sig_info(SIGTRAP, info, current); What do you think? Yes, this makes it consistent with the x86 behavior before the change, which used tracehook_consider_fatal_signal(current, SIGTRAP) in its test. Thanks, Roland
[PATCH 133] stepping, accommodate to utrace-cleanup changes
This needs more comment, I'll try to add them in a separate patch. With the recent changes in utrace API utrace_control(UTRACE_SINGLESTEP) postpones enable_step() to utrace_resume() stage. The tracee can pass tracehook_report_syscall_exit() without TIF_SINGLESTEP, this breaks the send_sigtrap() logic. Change ptrace_resume_action() to set UTRACE_EVENT(SYSCALL_EXIT) in PTRACE_SINGLESTEP/PTRACE_SINGLEBLOCK case, change report_syscall_exit() to check ctx-resume to detect this case. To synthesize the trap we set ctx-signr = SIGTRAP and provoke UTRACE_SIGNAL_REPORT, like ptrace_resume() does. Roland, we already discussed this a bit and I agree, this is not optimal. We need some changes in utrace, but currently it has a lot of problems and it is not clear yet what utrace should do. Let's fix the code now, once we find a better solution we can revert this change. With this patch make check passes all tests again (to clarify, except some tests which upstream doesn't pass too), including this one: #include stdio.h #include unistd.h #include stdlib.h #include signal.h #include errno.h #include sys/wait.h #include sys/ptrace.h #include assert.h #include sys/user.h #include sys/debugreg.h #include sys/syscall.h #define WEVENT(s) ((s 0xFF) 16) static int verbose; #define d_printf(fmt, ...) do { if (verbose) printf(fmt, ##__VA_ARGS__); } while (0) static struct user_regs_struct regs; static void resume(int pid, int req, int ck_stat) { int stat; assert(0 == ptrace(req, pid, 0, 0)); assert(waitpid(pid, stat, __WALL) == pid); //d_printf(=== %06X\n %06X\n, ck_stat, stat); assert(stat == ck_stat); assert(0 == ptrace(PTRACE_GETREGS, pid, NULL, regs)); } int main(int argc, const char *argv[]) { int pid, child, stat; long rip, nxt_rip; if (getpid() == __NR_getppid) { printf(sorry, restart\n); return 0; } verbose = argc 1; pid = fork(); if (!pid) { assert(0 == ptrace(PTRACE_TRACEME, 0,0,0)); kill(getpid(), SIGSTOP); // 1: SYSCALL + SYSCALL + STEP getppid(); // 2: SYSCALL + STEP getppid(); // 3: STEP getppid(); // 4: SYSCALL + STEP if (!fork()) exit(73); // STEPs only if (!fork()) exit(73); assert(0); } assert(wait(stat) == pid); assert(WIFSTOPPED(stat) WSTOPSIG(stat) == SIGSTOP); assert(0 == ptrace(PTRACE_SETOPTIONS, pid, 0, PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEFORK)); //- d_printf(1: syscall enter\n); resume(pid, PTRACE_SYSCALL, 0x857F); assert(regs.orig_rax == __NR_getppid); assert(regs.rax == -ENOSYS); rip = regs.rip; d_printf(1: syscall leave\n); resume(pid, PTRACE_SYSCALL, 0x857F); assert(regs.orig_rax == __NR_getppid); assert(regs.rax == getpid()); assert(regs.rip == rip); d_printf(1: singlestep\n); resume(pid, PTRACE_SINGLESTEP, 0x57F); assert((long)regs.orig_rax 0); assert(regs.rax == getpid()); assert(regs.rip != rip); d_printf(1: singlestep\n); resume(pid, PTRACE_SINGLESTEP, 0x57F); assert(regs.rip != rip); // d_printf(2: stop before syscall insn\n); do { resume(pid, PTRACE_SINGLESTEP, 0x57F); } while (regs.rip != rip - 2); assert(regs.rax == __NR_getppid); d_printf(2: syscall enter\n); resume(pid, PTRACE_SYSCALL, 0x857F); assert(regs.orig_rax == __NR_getppid); assert(regs.rax == -ENOSYS); assert(regs.rip == rip); d_printf(2: singlestep\n); resume(pid, PTRACE_SINGLESTEP, 0x57F); assert(regs.orig_rax == __NR_getppid); assert(regs.rax == getpid()); assert(regs.rip == rip); d_printf(2: singlestep\n); resume(pid, PTRACE_SINGLESTEP,
Re: [PATCH 133] stepping, accommodate to utrace-cleanup changes
Just in case, forgot to clarify... On 11/16, Oleg Nesterov wrote: With this patch make check passes all tests again (to clarify, except some tests which upstream doesn't pass too), including this one: with this patch + [HACK] utrace: fix utrace_resume()-finish_resume_report() logic And I didn't check make xcheck, I guess it still crashes the kernel. Oleg.
Re: [PATCH 133] stepping, accommodate to utrace-cleanup changes
On 11/16, Oleg Nesterov wrote: And I didn't check make xcheck, I guess it still crashes the kernel. Yes it does. I am almost sure the bug should be trivial, but somehow can't find find it. Just fyi, to ensure this is connected to utrace-indirect I applied the hack below and the bug goes away. OK. Tomorrow I will just read utrace.c trying to understand the details of the new code, perhaps I will notice something. Oleg. --- UTRACE-PTRACE/kernel/fork.c~XXX_CRASH 2009-11-16 20:26:23.0 +0100 +++ UTRACE-PTRACE/kernel/fork.c 2009-11-16 21:18:57.0 +0100 @@ -970,6 +970,8 @@ static void posix_cpu_timers_init(struct * parts of the process environment (as per the clone * flags). The actual kick-off is left to the caller. */ +bool utrace_task_alloc(struct task_struct *task); + static struct task_struct *copy_process(unsigned long clone_flags, unsigned long stack_start, struct pt_regs *regs, @@ -1227,6 +1229,10 @@ static struct task_struct *copy_process( cgroup_fork_callbacks(p); cgroup_callbacks_done = 1; + p-utrace = NULL; + if (!utrace_task_alloc(p)) + WARN_ON(1); + /* Need tasklist lock for parent etc handling! */ write_lock_irq(tasklist_lock); --- UTRACE-PTRACE/kernel/utrace.c~XXX_CRASH 2009-11-16 20:31:38.0 +0100 +++ UTRACE-PTRACE/kernel/utrace.c 2009-11-16 21:19:26.0 +0100 @@ -87,9 +87,9 @@ module_init(utrace_init); * * This returns false only in case of a memory allocation failure. */ -static bool utrace_task_alloc(struct task_struct *task) +bool utrace_task_alloc(struct task_struct *task) { - struct utrace *utrace = kmem_cache_zalloc(utrace_cachep, GFP_KERNEL); + struct utrace *utrace = kzalloc(sizeof(struct utrace), GFP_KERNEL); if (unlikely(!utrace)) return false; spin_lock_init(utrace-lock); @@ -108,7 +108,7 @@ static bool utrace_task_alloc(struct tas } task_unlock(task); if (unlikely(task-utrace != utrace)) - kmem_cache_free(utrace_cachep, utrace); + kfree(utrace); return true; } @@ -118,7 +118,7 @@ static bool utrace_task_alloc(struct tas */ void utrace_free_task(struct task_struct *task) { - kmem_cache_free(utrace_cachep, task-utrace); + kfree(task-utrace); } /* @@ -286,6 +286,8 @@ struct utrace_engine *utrace_attach_task struct utrace_engine *engine; int ret; + WARN_ON(!utrace); + if (!(flags UTRACE_ATTACH_CREATE)) { if (unlikely(!utrace)) return ERR_PTR(-ENOENT); --- UTRACE-PTRACE/include/linux/utrace.h~XXX_CRASH 2009-11-16 01:06:34.0 +0100 +++ UTRACE-PTRACE/include/linux/utrace.h2009-11-16 20:50:38.0 +0100 @@ -163,7 +163,7 @@ static inline struct utrace *task_utrace static inline void utrace_init_task(struct task_struct *task) { task-utrace_flags = 0; - task-utrace = NULL; + WARN_ON(!task-utrace); } void utrace_release_task(struct task_struct *);
Re: [PATCH 133] stepping, accommodate to utrace-cleanup changes
Whatever temporary hacks are fine by me one way or the other. They will just be coming out later along with assorted other cleanup. We certainly do want to get this right in the utrace layer. The change we talked about before seems simple enough and should cover this without new kludges in the ptrace layer. I did this (commit f19442c). I think that should cover what you need without this ptrace change. (All untested, of course!) Thanks, Roland
Re: [PATCH 133] stepping, accommodate to utrace-cleanup changes
Yes it does. I am almost sure the bug should be trivial, but somehow can't find find it. Just fyi, to ensure this is connected to utrace-indirect I applied the hack below and the bug goes away. Does s/kmem_cache_zalloc/kzalloc/ really have anything to do with it? Isn't it just the allocation synchronization logic? OK. Tomorrow I will just read utrace.c trying to understand the details of the new code, perhaps I will notice something. Ok. I hope you'll find something not too strange. But if it takes long, then probably we should just change utrace_init_task() to eagerly call utrace_task_alloc() and let you work through other issues first. Thanks, Roland