summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/Makefile2
-rw-r--r--kernel/irq/handle.c1
-rw-r--r--kernel/itimer.c6
-rw-r--r--kernel/kallsyms.c13
-rw-r--r--kernel/kprobes.c142
-rw-r--r--kernel/power/main.c6
-rw-r--r--kernel/printk.c72
-rw-r--r--kernel/profile.c16
-rw-r--r--kernel/sched.c2
-rw-r--r--kernel/sys.c2
10 files changed, 201 insertions, 61 deletions
diff --git a/kernel/Makefile b/kernel/Makefile
index eb88b44..b01d26f 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -29,7 +29,7 @@ obj-$(CONFIG_SYSFS) += ksysfs.o
obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
obj-$(CONFIG_SECCOMP) += seccomp.o
-ifneq ($(CONFIG_IA64),y)
+ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y)
# According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
# needed for x86 only. Why this used to be enabled for all architectures is beyond
# me. I suspect most platforms don't need this, but until we know that for sure
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c
index 2fb0e46..06b5a63 100644
--- a/kernel/irq/handle.c
+++ b/kernel/irq/handle.c
@@ -30,6 +30,7 @@
*/
irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = {
[0 ... NR_IRQS-1] = {
+ .status = IRQ_DISABLED,
.handler = &no_irq_type,
.lock = SPIN_LOCK_UNLOCKED
}
diff --git a/kernel/itimer.c b/kernel/itimer.c
index e9a40e9..1dc988e 100644
--- a/kernel/itimer.c
+++ b/kernel/itimer.c
@@ -123,7 +123,11 @@ static inline void it_real_arm(struct task_struct *p, unsigned long interval)
return;
if (interval > (unsigned long) LONG_MAX)
interval = LONG_MAX;
- p->signal->real_timer.expires = jiffies + interval;
+ /* the "+ 1" below makes sure that the timer doesn't go off before
+ * the interval requested. This could happen if
+ * time requested % (usecs per jiffy) is more than the usecs left
+ * in the current jiffy */
+ p->signal->real_timer.expires = jiffies + interval + 1;
add_timer(&p->signal->real_timer);
}
diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c
index 1627f8d..13bcec1 100644
--- a/kernel/kallsyms.c
+++ b/kernel/kallsyms.c
@@ -46,6 +46,14 @@ static inline int is_kernel_inittext(unsigned long addr)
return 0;
}
+static inline int is_kernel_extratext(unsigned long addr)
+{
+ if (addr >= (unsigned long)_sextratext
+ && addr <= (unsigned long)_eextratext)
+ return 1;
+ return 0;
+}
+
static inline int is_kernel_text(unsigned long addr)
{
if (addr >= (unsigned long)_stext && addr <= (unsigned long)_etext)
@@ -169,8 +177,9 @@ const char *kallsyms_lookup(unsigned long addr,
namebuf[0] = 0;
if ((all_var && is_kernel(addr)) ||
- (!all_var && (is_kernel_text(addr) || is_kernel_inittext(addr)))) {
- unsigned long symbol_end=0;
+ (!all_var && (is_kernel_text(addr) || is_kernel_inittext(addr) ||
+ is_kernel_extratext(addr)))) {
+ unsigned long symbol_end = 0;
/* do a binary search on the sorted kallsyms_addresses array */
low = 0;
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 1d5dd13..037142b7 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -44,6 +44,7 @@ static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE];
unsigned int kprobe_cpu = NR_CPUS;
static DEFINE_SPINLOCK(kprobe_lock);
+static struct kprobe *curr_kprobe;
/* Locks kprobe: irqs must be disabled */
void lock_kprobes(void)
@@ -73,22 +74,139 @@ struct kprobe *get_kprobe(void *addr)
return NULL;
}
+/*
+ * Aggregate handlers for multiple kprobes support - these handlers
+ * take care of invoking the individual kprobe handlers on p->list
+ */
+int aggr_pre_handler(struct kprobe *p, struct pt_regs *regs)
+{
+ struct kprobe *kp;
+
+ list_for_each_entry(kp, &p->list, list) {
+ if (kp->pre_handler) {
+ curr_kprobe = kp;
+ kp->pre_handler(kp, regs);
+ curr_kprobe = NULL;
+ }
+ }
+ return 0;
+}
+
+void aggr_post_handler(struct kprobe *p, struct pt_regs *regs,
+ unsigned long flags)
+{
+ struct kprobe *kp;
+
+ list_for_each_entry(kp, &p->list, list) {
+ if (kp->post_handler) {
+ curr_kprobe = kp;
+ kp->post_handler(kp, regs, flags);
+ curr_kprobe = NULL;
+ }
+ }
+ return;
+}
+
+int aggr_fault_handler(struct kprobe *p, struct pt_regs *regs, int trapnr)
+{
+ /*
+ * if we faulted "during" the execution of a user specified
+ * probe handler, invoke just that probe's fault handler
+ */
+ if (curr_kprobe && curr_kprobe->fault_handler) {
+ if (curr_kprobe->fault_handler(curr_kprobe, regs, trapnr))
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Fill in the required fields of the "manager kprobe". Replace the
+ * earlier kprobe in the hlist with the manager kprobe
+ */
+static inline void add_aggr_kprobe(struct kprobe *ap, struct kprobe *p)
+{
+ ap->addr = p->addr;
+ ap->opcode = p->opcode;
+ memcpy(&ap->ainsn, &p->ainsn, sizeof(struct arch_specific_insn));
+
+ ap->pre_handler = aggr_pre_handler;
+ ap->post_handler = aggr_post_handler;
+ ap->fault_handler = aggr_fault_handler;
+
+ INIT_LIST_HEAD(&ap->list);
+ list_add(&p->list, &ap->list);
+
+ INIT_HLIST_NODE(&ap->hlist);
+ hlist_del(&p->hlist);
+ hlist_add_head(&ap->hlist,
+ &kprobe_table[hash_ptr(ap->addr, KPROBE_HASH_BITS)]);
+}
+
+/*
+ * This is the second or subsequent kprobe at the address - handle
+ * the intricacies
+ * TODO: Move kcalloc outside the spinlock
+ */
+static int register_aggr_kprobe(struct kprobe *old_p, struct kprobe *p)
+{
+ int ret = 0;
+ struct kprobe *ap;
+
+ if (old_p->break_handler || p->break_handler) {
+ ret = -EEXIST; /* kprobe and jprobe can't (yet) coexist */
+ } else if (old_p->pre_handler == aggr_pre_handler) {
+ list_add(&p->list, &old_p->list);
+ } else {
+ ap = kcalloc(1, sizeof(struct kprobe), GFP_ATOMIC);
+ if (!ap)
+ return -ENOMEM;
+ add_aggr_kprobe(ap, old_p);
+ list_add(&p->list, &ap->list);
+ }
+ return ret;
+}
+
+/* kprobe removal house-keeping routines */
+static inline void cleanup_kprobe(struct kprobe *p, unsigned long flags)
+{
+ *p->addr = p->opcode;
+ hlist_del(&p->hlist);
+ flush_icache_range((unsigned long) p->addr,
+ (unsigned long) p->addr + sizeof(kprobe_opcode_t));
+ spin_unlock_irqrestore(&kprobe_lock, flags);
+ arch_remove_kprobe(p);
+}
+
+static inline void cleanup_aggr_kprobe(struct kprobe *old_p,
+ struct kprobe *p, unsigned long flags)
+{
+ list_del(&p->list);
+ if (list_empty(&old_p->list)) {
+ cleanup_kprobe(old_p, flags);
+ kfree(old_p);
+ } else
+ spin_unlock_irqrestore(&kprobe_lock, flags);
+}
+
int register_kprobe(struct kprobe *p)
{
int ret = 0;
unsigned long flags = 0;
+ struct kprobe *old_p;
if ((ret = arch_prepare_kprobe(p)) != 0) {
goto rm_kprobe;
}
spin_lock_irqsave(&kprobe_lock, flags);
- INIT_HLIST_NODE(&p->hlist);
- if (get_kprobe(p->addr)) {
- ret = -EEXIST;
+ old_p = get_kprobe(p->addr);
+ if (old_p) {
+ ret = register_aggr_kprobe(old_p, p);
goto out;
}
- arch_copy_kprobe(p);
+ arch_copy_kprobe(p);
+ INIT_HLIST_NODE(&p->hlist);
hlist_add_head(&p->hlist,
&kprobe_table[hash_ptr(p->addr, KPROBE_HASH_BITS)]);
@@ -107,13 +225,17 @@ rm_kprobe:
void unregister_kprobe(struct kprobe *p)
{
unsigned long flags;
- arch_remove_kprobe(p);
+ struct kprobe *old_p;
+
spin_lock_irqsave(&kprobe_lock, flags);
- *p->addr = p->opcode;
- hlist_del(&p->hlist);
- flush_icache_range((unsigned long) p->addr,
- (unsigned long) p->addr + sizeof(kprobe_opcode_t));
- spin_unlock_irqrestore(&kprobe_lock, flags);
+ old_p = get_kprobe(p->addr);
+ if (old_p) {
+ if (old_p->pre_handler == aggr_pre_handler)
+ cleanup_aggr_kprobe(old_p, p, flags);
+ else
+ cleanup_kprobe(p, flags);
+ } else
+ spin_unlock_irqrestore(&kprobe_lock, flags);
}
static struct notifier_block kprobe_exceptions_nb = {
diff --git a/kernel/power/main.c b/kernel/power/main.c
index 7960ddf..4cdebc9 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -156,14 +156,14 @@ static int enter_state(suspend_state_t state)
goto Unlock;
}
- pr_debug("PM: Preparing system for suspend\n");
+ pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);
if ((error = suspend_prepare(state)))
goto Unlock;
- pr_debug("PM: Entering state.\n");
+ pr_debug("PM: Entering %s sleep\n", pm_states[state]);
error = suspend_enter(state);
- pr_debug("PM: Finishing up.\n");
+ pr_debug("PM: Finishing wakeup.\n");
suspend_finish(state);
Unlock:
up(&pm_sem);
diff --git a/kernel/printk.c b/kernel/printk.c
index 290a07c..01b58d7 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -160,42 +160,6 @@ static int __init console_setup(char *str)
__setup("console=", console_setup);
-/**
- * add_preferred_console - add a device to the list of preferred consoles.
- *
- * The last preferred console added will be used for kernel messages
- * and stdin/out/err for init. Normally this is used by console_setup
- * above to handle user-supplied console arguments; however it can also
- * be used by arch-specific code either to override the user or more
- * commonly to provide a default console (ie from PROM variables) when
- * the user has not supplied one.
- */
-int __init add_preferred_console(char *name, int idx, char *options)
-{
- struct console_cmdline *c;
- int i;
-
- /*
- * See if this tty is not yet registered, and
- * if we have a slot free.
- */
- for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
- if (strcmp(console_cmdline[i].name, name) == 0 &&
- console_cmdline[i].index == idx) {
- selected_console = i;
- return 0;
- }
- if (i == MAX_CMDLINECONSOLES)
- return -E2BIG;
- selected_console = i;
- c = &console_cmdline[i];
- memcpy(c->name, name, sizeof(c->name));
- c->name[sizeof(c->name) - 1] = 0;
- c->options = options;
- c->index = idx;
- return 0;
-}
-
static int __init log_buf_len_setup(char *str)
{
unsigned long size = memparse(str, &str);
@@ -671,6 +635,42 @@ static void call_console_drivers(unsigned long start, unsigned long end) {}
#endif
/**
+ * add_preferred_console - add a device to the list of preferred consoles.
+ *
+ * The last preferred console added will be used for kernel messages
+ * and stdin/out/err for init. Normally this is used by console_setup
+ * above to handle user-supplied console arguments; however it can also
+ * be used by arch-specific code either to override the user or more
+ * commonly to provide a default console (ie from PROM variables) when
+ * the user has not supplied one.
+ */
+int __init add_preferred_console(char *name, int idx, char *options)
+{
+ struct console_cmdline *c;
+ int i;
+
+ /*
+ * See if this tty is not yet registered, and
+ * if we have a slot free.
+ */
+ for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
+ if (strcmp(console_cmdline[i].name, name) == 0 &&
+ console_cmdline[i].index == idx) {
+ selected_console = i;
+ return 0;
+ }
+ if (i == MAX_CMDLINECONSOLES)
+ return -E2BIG;
+ selected_console = i;
+ c = &console_cmdline[i];
+ memcpy(c->name, name, sizeof(c->name));
+ c->name[sizeof(c->name) - 1] = 0;
+ c->options = options;
+ c->index = idx;
+ return 0;
+}
+
+/**
* acquire_console_sem - lock the console system for exclusive use.
*
* Acquires a semaphore which guarantees that the caller has
diff --git a/kernel/profile.c b/kernel/profile.c
index 0221a50..ad8cbb7 100644
--- a/kernel/profile.c
+++ b/kernel/profile.c
@@ -49,15 +49,19 @@ static DECLARE_MUTEX(profile_flip_mutex);
static int __init profile_setup(char * str)
{
+ static char __initdata schedstr[] = "schedule";
int par;
- if (!strncmp(str, "schedule", 8)) {
+ if (!strncmp(str, schedstr, strlen(schedstr))) {
prof_on = SCHED_PROFILING;
- printk(KERN_INFO "kernel schedule profiling enabled\n");
- if (str[7] == ',')
- str += 8;
- }
- if (get_option(&str,&par)) {
+ if (str[strlen(schedstr)] == ',')
+ str += strlen(schedstr) + 1;
+ if (get_option(&str, &par))
+ prof_shift = par;
+ printk(KERN_INFO
+ "kernel schedule profiling enabled (shift: %ld)\n",
+ prof_shift);
+ } else if (get_option(&str, &par)) {
prof_shift = par;
prof_on = CPU_PROFILING;
printk(KERN_INFO "kernel profiling enabled (shift: %ld)\n",
diff --git a/kernel/sched.c b/kernel/sched.c
index 0dc3158..66b2ed7 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -4243,7 +4243,7 @@ static void move_task_off_dead_cpu(int dead_cpu, struct task_struct *tsk)
/* No more Mr. Nice Guy. */
if (dest_cpu == NR_CPUS) {
- tsk->cpus_allowed = cpuset_cpus_allowed(tsk);
+ cpus_setall(tsk->cpus_allowed);
dest_cpu = any_online_cpu(tsk->cpus_allowed);
/*
diff --git a/kernel/sys.c b/kernel/sys.c
index f64e97c..f006632 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1195,7 +1195,7 @@ static int groups_from_user(struct group_info *group_info,
return 0;
}
-/* a simple shell-metzner sort */
+/* a simple Shell sort */
static void groups_sort(struct group_info *group_info)
{
int base, max, stride;
OpenPOWER on IntegriCloud