diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/Makefile | 1 | ||||
| -rw-r--r-- | kernel/fork.c | 2 | ||||
| -rw-r--r-- | kernel/user-return-notifier.c | 46 |
3 files changed, 49 insertions, 0 deletions
diff --git a/kernel/Makefile b/kernel/Makefile index 9943202b4355..864ff75d65f2 100644 --- a/kernel/Makefile +++ b/kernel/Makefile | |||
| @@ -99,6 +99,7 @@ obj-$(CONFIG_SLOW_WORK) += slow-work.o | |||
| 99 | obj-$(CONFIG_SLOW_WORK_DEBUG) += slow-work-debugfs.o | 99 | obj-$(CONFIG_SLOW_WORK_DEBUG) += slow-work-debugfs.o |
| 100 | obj-$(CONFIG_PERF_EVENTS) += perf_event.o | 100 | obj-$(CONFIG_PERF_EVENTS) += perf_event.o |
| 101 | obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o | 101 | obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o |
| 102 | obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o | ||
| 102 | 103 | ||
| 103 | ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y) | 104 | ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y) |
| 104 | # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is | 105 | # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is |
diff --git a/kernel/fork.c b/kernel/fork.c index 3d6f121bbe8a..edeff9ceaab9 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
| @@ -64,6 +64,7 @@ | |||
| 64 | #include <linux/magic.h> | 64 | #include <linux/magic.h> |
| 65 | #include <linux/perf_event.h> | 65 | #include <linux/perf_event.h> |
| 66 | #include <linux/posix-timers.h> | 66 | #include <linux/posix-timers.h> |
| 67 | #include <linux/user-return-notifier.h> | ||
| 67 | 68 | ||
| 68 | #include <asm/pgtable.h> | 69 | #include <asm/pgtable.h> |
| 69 | #include <asm/pgalloc.h> | 70 | #include <asm/pgalloc.h> |
| @@ -249,6 +250,7 @@ static struct task_struct *dup_task_struct(struct task_struct *orig) | |||
| 249 | goto out; | 250 | goto out; |
| 250 | 251 | ||
| 251 | setup_thread_stack(tsk, orig); | 252 | setup_thread_stack(tsk, orig); |
| 253 | clear_user_return_notifier(tsk); | ||
| 252 | stackend = end_of_stack(tsk); | 254 | stackend = end_of_stack(tsk); |
| 253 | *stackend = STACK_END_MAGIC; /* for overflow detection */ | 255 | *stackend = STACK_END_MAGIC; /* for overflow detection */ |
| 254 | 256 | ||
diff --git a/kernel/user-return-notifier.c b/kernel/user-return-notifier.c new file mode 100644 index 000000000000..03e2d6fd9b18 --- /dev/null +++ b/kernel/user-return-notifier.c | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | |||
| 2 | #include <linux/user-return-notifier.h> | ||
| 3 | #include <linux/percpu.h> | ||
| 4 | #include <linux/sched.h> | ||
| 5 | #include <linux/module.h> | ||
| 6 | |||
| 7 | static DEFINE_PER_CPU(struct hlist_head, return_notifier_list); | ||
| 8 | |||
| 9 | #define URN_LIST_HEAD per_cpu(return_notifier_list, raw_smp_processor_id()) | ||
| 10 | |||
| 11 | /* | ||
| 12 | * Request a notification when the current cpu returns to userspace. Must be | ||
| 13 | * called in atomic context. The notifier will also be called in atomic | ||
| 14 | * context. | ||
| 15 | */ | ||
| 16 | void user_return_notifier_register(struct user_return_notifier *urn) | ||
| 17 | { | ||
| 18 | set_tsk_thread_flag(current, TIF_USER_RETURN_NOTIFY); | ||
| 19 | hlist_add_head(&urn->link, &URN_LIST_HEAD); | ||
| 20 | } | ||
| 21 | EXPORT_SYMBOL_GPL(user_return_notifier_register); | ||
| 22 | |||
| 23 | /* | ||
| 24 | * Removes a registered user return notifier. Must be called from atomic | ||
| 25 | * context, and from the same cpu registration occured in. | ||
| 26 | */ | ||
| 27 | void user_return_notifier_unregister(struct user_return_notifier *urn) | ||
| 28 | { | ||
| 29 | hlist_del(&urn->link); | ||
| 30 | if (hlist_empty(&URN_LIST_HEAD)) | ||
| 31 | clear_tsk_thread_flag(current, TIF_USER_RETURN_NOTIFY); | ||
| 32 | } | ||
| 33 | EXPORT_SYMBOL_GPL(user_return_notifier_unregister); | ||
| 34 | |||
| 35 | /* Calls registered user return notifiers */ | ||
| 36 | void fire_user_return_notifiers(void) | ||
| 37 | { | ||
| 38 | struct user_return_notifier *urn; | ||
| 39 | struct hlist_node *tmp1, *tmp2; | ||
| 40 | struct hlist_head *head; | ||
| 41 | |||
| 42 | head = &get_cpu_var(return_notifier_list); | ||
| 43 | hlist_for_each_entry_safe(urn, tmp1, tmp2, head, link) | ||
| 44 | urn->on_user_return(urn); | ||
| 45 | put_cpu_var(return_notifier_list); | ||
| 46 | } | ||
