output_autoconf(s, o, "autoconf-module-sect-attrs.c", "STAPCONF_MODULE_SECT_ATTRS", NULL);
output_autoconf(s, o, "autoconf-utrace-via-tracepoints.c", "STAPCONF_UTRACE_VIA_TRACEPOINTS", NULL);
+ output_autoconf(s, o, "autoconf-task_work-struct.c", "STAPCONF_TASK_WORK_STRUCT", NULL);
output_autoconf(s, o, "autoconf-vm-area-pte.c", "STAPCONF_VM_AREA_PTE", NULL);
output_autoconf(s, o, "autoconf-relay-umode_t.c", "STAPCONF_RELAY_UMODE_T", NULL);
output_autoconf(s, o, "autoconf-fs_supers-hlist.c", "STAPCONF_FS_SUPERS_HLIST", NULL);
--- /dev/null
+#include <linux/task_work.h>
+
+/* Original task_work code used 'struct task_work' (and
+ * init_task_work() had 3 arguments). */
+void __autoconf_func(void)
+{
+ struct task_work work;
+
+ init_task_work(&work, NULL, NULL);
+}
#include <trace/events/syscalls.h>
#include <linux/task_work.h>
-// The utrace-less task_finder needs either:
-// - 5 specific tracepoints
-// - 4 specific tracepoints and ftrace_set_filter()
-// Both scenarios need <linux/task_work.h>.
-//
-// Check scenario #1.
+// The utrace-less task_finder needs 5 specific tracepoints and
+// <linux/task_work.h>.
void __sched_process_fork(void *cb_data __attribute__((unused)),
struct task_struct *parent __attribute__((unused)),
void __autoconf_func(void)
{
- struct task_work work;
-
(void) register_trace_sched_process_fork(__sched_process_fork, NULL);
(void) register_trace_sched_process_exit(__sched_process_exit, NULL);
(void) register_trace_sched_process_exec(__sched_process_exec, NULL);
(void) register_trace_sys_enter(__sys_enter, NULL);
(void) register_trace_sys_exit(__sys_exit, NULL);
- init_task_work(&work, NULL, NULL);
}
struct __stp_tf_task_work {
struct list_head list;
struct task_struct *task;
+ struct stap_task_finder_target *tgt;
struct task_work work;
};
* a 'struct task_work' for a task that isn't current, we'll need a
* __stp_tf_alloc_task_work_for_task(task) variant.
*/
-static struct task_work *__stp_tf_alloc_task_work(void)
+static struct task_work *
+__stp_tf_alloc_task_work(struct stap_task_finder_target *tgt)
{
struct __stp_tf_task_work *tf_work;
unsigned long flags;
}
tf_work->task = current;
+ tf_work->tgt = tgt;
// Insert new item onto list. This list could be a hashed
// list for easier lookup, but as short as the list should be
static void
__stp_tf_quiesce_worker(struct task_work *work)
{
- struct stap_task_finder_target *tgt = work->data;
+ struct __stp_tf_task_work *tf_work = \
+ container_of(work, struct __stp_tf_task_work, work);
+ struct stap_task_finder_target *tgt = tf_work->tgt;
might_sleep();
__stp_tf_free_task_work(work);
/* If we can't sleep, arrange for the task to truly
* stop so we can sleep. */
- work = __stp_tf_alloc_task_work();
+ work = __stp_tf_alloc_task_work(tgt);
if (work == NULL) {
_stp_error("Unable to allocate space for task_work");
return UTRACE_RESUME;
}
- init_task_work(work, &__stp_tf_quiesce_worker, tgt);
+ stp_init_task_work(work, &__stp_tf_quiesce_worker);
rc = stp_task_work_add(tsk, work);
/* stp_task_work_add() returns -ESRCH if the task has
static void
__stp_tf_mmap_worker(struct task_work *work)
{
- struct stap_task_finder_target *tgt = work->data;
+ struct __stp_tf_task_work *tf_work = \
+ container_of(work, struct __stp_tf_task_work, work);
+ struct stap_task_finder_target *tgt = tf_work->tgt;
struct __stp_tf_map_entry *entry;
might_sleep();
/* If we can't sleep, arrange for the task to truly
* stop so we can sleep. */
- work = __stp_tf_alloc_task_work();
+ work = __stp_tf_alloc_task_work(tgt);
if (work == NULL) {
_stp_error("Unable to allocate space for task_work");
__stp_tf_remove_map_entry(entry);
__stp_tf_handler_end();
return UTRACE_RESUME;
}
- init_task_work(work, &__stp_tf_mmap_worker, tgt);
+ stp_init_task_work(work, &__stp_tf_mmap_worker);
rc = stp_task_work_add(tsk, work);
/* stp_task_work_add() returns -ESRCH if the task has
* already passed exit_task_work(). Just ignore this
--- /dev/null
+/*
+ * task_work compatibility defines and inlines
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * This file is part of systemtap, and is free software. You can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License (GPL); either version 2, or (at your option) any
+ * later version.
+ */
+
+#ifndef _TASK_WORK_COMPATIBILITY_H_
+#define _TASK_WORK_COMPATIBILITY_H_
+
+#include <linux/task_work.h>
+
+/*
+ * Define all the old task_work stuff in terms of the new
+ * interface/names - except for the name of the structure
+ * itself. Originally the task_work stuff had a custom structure,
+ * called 'struct task_work'. The new interface uses a common
+ * structure, 'struct callback_head'. If we define 'callback_head' to
+ * be a 'task_work', then we could never use the common structure on
+ * systems with the old interface.
+ */
+
+#ifdef STAPCONF_TASK_WORK_STRUCT
+
+static inline void
+stp_init_task_work(struct task_work *twork, task_work_func_t func)
+{
+ init_task_work(twork, func, NULL);
+}
+
+#else /* !STAPCONF_TASK_WORK_STRUCT */
+
+#define task_work callback_head
+
+static inline void
+stp_init_task_work(struct task_work *twork, task_work_func_t func)
+{
+ init_task_work(twork, func);
+}
+
+#endif /* !STAPCONF_TASK_WORK_STRUCT */
+
+#endif /* _TASK_WORK_COMPATIBILITY_H_ */
#ifndef _STP_TASK_WORK_C
#define _STP_TASK_WORK_C
-#include <linux/task_work.h>
+#include "linux/task_work_compatibility.h"
#if !defined(STAPCONF_TASK_WORK_ADD_EXPORTED)
typedef int (*task_work_add_fn)(struct task_struct *task,
kmem_cache_free(utrace_cachep, utrace);
}
- init_task_work(&utrace->work, &utrace_resume, NULL);
+ stp_init_task_work(&utrace->work, &utrace_resume);
return true;
}