Re: UTRACE_STOP in exec handler

2008-09-22 Thread Roland McGrath
Hi, David.  I'm back in the saddle at home today and got a chance to look
into this bug.

I've fixed it in the current utrace git/patch.  I also committed it for the
next rawhide kernel.  I think rawhide mirrors are in f10-beta freeze, so
you have to go to http://kojipkgs.fedoraproject.org/packages/kernel/2.6.27/
and check for when a build = 2.6.27-0.343 arrives.  One should be there
before Tuesday morning, even if rawhide proper doesn't get updated.

The bug was that the attach could leave the bookkeeping in a wrong state so
that the utrace_control call would skip some flag-setting it needed to get
the pending UTRACE_STOP to be noticed.  To hack on the kernel you have, you
can work around it with:
set_thread_flag(TIF_NOTIFY_RESUME);
after attach.  That will be harmless on fixed kernels, though I wouldn't
recommend leaving it in.


Thanks,
Roland



UTRACE_STOP in exec handler

2008-09-16 Thread David Smith
Roland,

I'm seeing a problem on with the new utrace on
2.6.27-0.323.rc6.fc10.x86_64.  Basically, if I attach a new engine in an
exec handler, and use utrace_control() with UTRACE_STOP, the task
doesn't reliably stop.

I was seeing this behaviour with systemtap, so I started with
crash-suspend.c and mangled it to do something similar, to hopefully
simplify the problem down a bit.

So, try compiling this module, then insmod it with the pid of a bash
process.  What I expected to happen is that every new process exec'ed by
that bash shell gets stopped once.  Instead, ls will run to completion
without stopping. If you run cat, then use Ctrl-C to kill it, you'll
get a quiesce event.

So, is this a problem with the way I'm attempting to stop the thread or
a utrace bug?

(Note that I've tried returning UTRACE_STOP from the exec handler
instead of calling utrace_control(), but it makes no difference.)

-- 
David Smith
[EMAIL PROTECTED]
Red Hat
http://www.redhat.com
256.217.0141 (direct)
256.837.0057 (fax)
#include linux/sched.h
#include linux/pid.h
#include linux/utrace.h
#include linux/err.h
#include linux/module.h
#include linux/errno.h

MODULE_DESCRIPTION(automatic suspend on crash);
MODULE_LICENSE(GPL);

static int target_pid;
static int verbose;

module_param_named(pid, target_pid, int, 0);
module_param(verbose, bool, 0);

#define MY_EVENTS (UTRACE_EVENT(CLONE) | UTRACE_EVENT(EXEC))

#define MY_EVENTS2 (UTRACE_EVENT(QUIESCE))

static u32
crash_suspend_quiesce(u32 action, struct utrace_attached_engine *engine,
		  struct task_struct *tsk, unsigned long event)
{

	if (tsk != NULL) {
		printk(pid %d quiesced\n, tsk-pid);
	}

	return UTRACE_DETACH;
}

static const struct utrace_engine_ops crash_suspend_ops2 =
{
	.report_quiesce = crash_suspend_quiesce,
};

/*
 * On clone, attach to the child.
 */
static u32
crash_suspend_clone(enum utrace_resume_action action,
		struct utrace_attached_engine *engine,
		struct task_struct *parent,
		unsigned long clone_flags,
		struct task_struct *child)
{
	struct utrace_attached_engine *child_engine;

	child_engine = utrace_attach_task(child, UTRACE_ATTACH_CREATE,
	  engine-ops, 0);
	if (IS_ERR(child_engine)) {
		printk(attach to clone child %d (%lx) from 0x%p = %ld\n,
		   child-pid, clone_flags, engine, PTR_ERR(child_engine));
	} else {
		int err = utrace_set_events(child, child_engine, MY_EVENTS);
		WARN_ON(err);

		utrace_engine_put(child_engine);
	}

	return UTRACE_RESUME;
}

static u32
crash_suspend_exec(enum utrace_resume_action action,
		   struct utrace_attached_engine *engine,
		   struct task_struct *tsk,
		   const struct linux_binfmt *fmt,
		   const struct linux_binprm *bprm,
		   struct pt_regs *regs)
{
	struct utrace_attached_engine *engine2;

	engine2 = utrace_attach_task(tsk, UTRACE_ATTACH_CREATE,
 crash_suspend_ops2, 0);
	if (IS_ERR(engine2)) {
		printk(attach to exec %d from 0x%p = %ld\n,
		   tsk-pid, engine2, PTR_ERR(engine2));
	} else {
		int err = utrace_set_events(tsk, engine2, MY_EVENTS2);
		WARN_ON(err);

		err = utrace_control(tsk, engine2, UTRACE_STOP);
		printk(utrace_control(%d) returned %d\n,
		   (int)tsk-pid, err);

		utrace_engine_put(engine2);
	}

	return UTRACE_RESUME;
}

/*
 * If we are still attached at task death, it didn't die by core dump signal.
 * Just detach and let it go.
 */
static u32
crash_suspend_death(struct utrace_attached_engine *engine,
		struct task_struct *tsk,
		bool group_dead, int signal)
{
	return UTRACE_DETACH;
}

static const struct utrace_engine_ops crash_suspend_ops =
{
	.report_clone = crash_suspend_clone,
	.report_exec = crash_suspend_exec,
};

static int __init init_crash_suspend(void)
{
	struct pid *pid;
	struct utrace_attached_engine *engine;
	int ret;

	pid = find_get_pid(target_pid);
	if (pid == NULL) {
		printk(cannot find PID %d\n, target_pid);
		return -ESRCH;
	}

	engine = utrace_attach_pid(pid, UTRACE_ATTACH_CREATE,
   crash_suspend_ops, 0);
	if (IS_ERR(engine))
		printk(utrace_attach: %ld\n, PTR_ERR(engine));
	else if (engine == NULL)
		printk(utrace_attach = null!\n);
	else
		printk(attached to %d = 0x%p\n, pid_vnr(pid), engine);

	ret = utrace_set_events_pid(pid, engine, MY_EVENTS);
	if (ret == -ESRCH)
		printk(pid %d died during setup\n, pid_vnr(pid));
	else
		WARN_ON(ret);

	put_pid(pid);
	if (engine  !IS_ERR(engine))
		utrace_engine_put(engine);

	return 0;
}

static void __exit exit_crash_suspend(void)
{
	struct task_struct *t;
	struct utrace_attached_engine *engine;
	int n = 0;
	int ret;

restart:
	rcu_read_lock();
	for_each_process(t) {
		engine = utrace_attach_task(t, UTRACE_ATTACH_MATCH_OPS,
	crash_suspend_ops, 0);
		if (IS_ERR(engine)) {
			int error = -PTR_ERR(engine);
			if (error != ENOENT)
printk(!!! utrace_attach returned %d on %d\n,
   error, t-pid);
			continue;
		}

		ret = utrace_control(t, engine, UTRACE_DETACH);
		if (ret == -EINPROGRESS) {
			/*
			 * It's running our callback, so we have

Re: UTRACE_STOP in exec handler

2008-09-16 Thread Roland McGrath
Off hand I don't see anything wrong with your test module.
But I'll have to test it out myself, and I won't be able
to do that until I'm back from travelling (next week).


Thanks,
Roland