* [patch 0/9] Conditional Calls
@ 2007-05-29 18:33 Mathieu Desnoyers
2007-05-29 18:33 ` [patch 1/9] Conditional Calls - Architecture Independent Code Mathieu Desnoyers
` (9 more replies)
0 siblings, 10 replies; 19+ messages in thread
From: Mathieu Desnoyers @ 2007-05-29 18:33 UTC (permalink / raw)
To: akpm, linux-kernel
Hi,
Following Andi Kleen's advice, I splitted the jump-over-call into a speparate
piece of infrastructure so it can be used more widely.
It also use a hash table to permit cond_call enable/disable both when the
cond_call is armed and when a module containing an armed cond_call is loaded.
Please add at the end of the 2.6.22-mm1 series,
conditional-calls-architecture-independent-code.patch
conditional-calls-hash-table.patch
conditional-calls-non-optimized-architectures.patch
conditional-calls-kconfig-menus.patch
conditional-calls-i386-optimization.patch
conditional-calls-powerpc-optimization.patch
conditional-calls-documentation.patch
#
f00f-bug-use-cond-calls.patch
profiling-use-cond-calls.patch
Mathieu
--
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
^ permalink raw reply [flat|nested] 19+ messages in thread
* [patch 1/9] Conditional Calls - Architecture Independent Code
2007-05-29 18:33 [patch 0/9] Conditional Calls Mathieu Desnoyers
@ 2007-05-29 18:33 ` Mathieu Desnoyers
2007-05-29 18:33 ` [patch 2/9] Conditional Calls - Hash Table Mathieu Desnoyers
` (8 subsequent siblings)
9 siblings, 0 replies; 19+ messages in thread
From: Mathieu Desnoyers @ 2007-05-29 18:33 UTC (permalink / raw)
To: akpm, linux-kernel; +Cc: Mathieu Desnoyers
[-- Attachment #1: conditional-calls-architecture-independent-code.patch --]
[-- Type: text/plain, Size: 14948 bytes --]
Conditional calls are used to compile in code that is meant to be dynamically
enabled at runtime. When code is disabled, it has a very small footprint.
It has a generic cond_call version and optimized per architecture cond_calls.
The optimized cond_call uses a load immediate to remove a data cache hit.
It adds a new rodata section "__cond_call" to place the pointers to the enable
value.
cond_call activation functions sits in module.c.
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
---
include/asm-generic/vmlinux.lds.h | 16 +-
include/linux/condcall.h | 91 +++++++++++++
include/linux/module.h | 4
kernel/module.c | 248 ++++++++++++++++++++++++++++++++++++++
4 files changed, 356 insertions(+), 3 deletions(-)
Index: linux-2.6-lttng/include/linux/condcall.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6-lttng/include/linux/condcall.h 2007-05-17 02:13:53.000000000 -0400
@@ -0,0 +1,91 @@
+#ifndef _LINUX_CONDCALL_H
+#define _LINUX_CONDCALL_H
+
+/*
+ * Conditional function calls. Cheap when disabled, enabled at runtime.
+ *
+ * (C) Copyright 2007 Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#ifdef __KERNEL__
+
+struct __cond_call_struct {
+ const char *name;
+ void *enable;
+ int flags;
+} __attribute__((packed));
+
+
+/* Cond call flags : selects the mechanism used to enable the conditional calls
+ * and prescribe what can be executed within their function. This is primarily
+ * used at reentrancy-unfriendly sites. */
+#define CF_OPTIMIZED (1 << 0) /* Use optimized cond_call */
+#define CF_LOCKDEP (1 << 1) /* Can call lockdep */
+#define CF_PRINTK (1 << 2) /* Probe can call vprintk */
+#define CF_STATIC_ENABLE (1 << 3) /* Enable cond_call statically */
+#define _CF_NR 4
+
+#ifdef CONFIG_COND_CALL
+
+/* Generic cond_call flavor always available.
+ * Note : the empty asm volatile with read constraint is used here instead of a
+ * "used" attribute to fix a gcc 4.1.x bug. */
+#define cond_call_generic(flags, name, func) \
+ ({ \
+ static const char __cstrtab_name_##name[] \
+ __attribute__((section("__cond_call_strings"))) = #name; \
+ static char __cond_call_enable_##name = \
+ (flags) & CF_STATIC_ENABLE; \
+ static const struct __cond_call_struct __cond_call_##name \
+ __attribute__((section("__cond_call"))) = \
+ { __cstrtab_name_##name, \
+ &__cond_call_enable_##name, \
+ (flags) & ~CF_OPTIMIZED } ; \
+ asm volatile ( "" : : "i" (&__cond_call_##name)); \
+ (unlikely(__cond_call_enable_##name)) ? \
+ (func) : \
+ (__typeof__(func))0; \
+ })
+
+#define COND_CALL_GENERIC_ENABLE_IMMEDIATE_OFFSET 0
+#define COND_CALL_GENERIC_ENABLE_TYPE unsigned char
+/* Dereference enable as lvalue from a pointer to its instruction */
+#define COND_CALL_GENERIC_ENABLE(a) \
+ *(COND_CALL_GENERIC_ENABLE_TYPE*) \
+ ((char*)a+COND_CALL_GENERIC_ENABLE_IMMEDIATE_OFFSET)
+
+static inline int cond_call_generic_set_enable(void *address, char enable)
+{
+ COND_CALL_GENERIC_ENABLE(address) = enable;
+ return 0;
+}
+
+#else /* !CONFIG_COND_CALL */
+#define cond_call_generic(flags, name, func) \
+ ({ \
+ ((flags) & CF_STATIC_ENABLE) ? \
+ (func) : \
+ (__typeof__(func))0; \
+ })
+#endif /* CONFIG_COND_CALL */
+
+#ifdef CONFIG_COND_CALL_ENABLE_OPTIMIZATION
+#include <asm/condcall.h> /* optimized cond_call flavor */
+#else
+#include <asm-generic/condcall.h> /* fallback on generic cond_call */
+#endif
+
+#define COND_CALL_MAX_FORMAT_LEN 1024
+
+extern int cond_call_arm(const char *name);
+extern int cond_call_disarm(const char *name);
+
+/* cond_call_query : Returns 1 if enabled, 0 if disabled or not present */
+extern int cond_call_query(const char *name);
+extern int cond_call_list(const char *name);
+
+#endif /* __KERNEL__ */
+#endif
Index: linux-2.6-lttng/include/asm-generic/vmlinux.lds.h
===================================================================
--- linux-2.6-lttng.orig/include/asm-generic/vmlinux.lds.h 2007-05-17 02:12:25.000000000 -0400
+++ linux-2.6-lttng/include/asm-generic/vmlinux.lds.h 2007-05-17 02:13:42.000000000 -0400
@@ -116,11 +116,22 @@
*(__kcrctab_gpl_future) \
VMLINUX_SYMBOL(__stop___kcrctab_gpl_future) = .; \
} \
- \
+ /* Conditional calls: pointers */ \
+ __cond_call : AT(ADDR(__cond_call) - LOAD_OFFSET) { \
+ VMLINUX_SYMBOL(__start___cond_call) = .; \
+ *(__cond_call) \
+ VMLINUX_SYMBOL(__stop___cond_call) = .; \
+ } \
/* Kernel symbol table: strings */ \
__ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) { \
*(__ksymtab_strings) \
- } \
+ } \
+ /* Conditional calls: strings */ \
+ __cond_call_strings : AT(ADDR(__cond_call_strings) - LOAD_OFFSET) { \
+ *(__cond_call_strings) \
+ } \
+ __end_rodata = .; \
+ . = ALIGN(4096); \
\
/* Built-in module parameters. */ \
__param : AT(ADDR(__param) - LOAD_OFFSET) { \
@@ -228,4 +239,3 @@
*(.initcall6s.init) \
*(.initcall7.init) \
*(.initcall7s.init)
-
Index: linux-2.6-lttng/include/linux/module.h
===================================================================
--- linux-2.6-lttng.orig/include/linux/module.h 2007-05-17 02:12:34.000000000 -0400
+++ linux-2.6-lttng/include/linux/module.h 2007-05-17 02:13:41.000000000 -0400
@@ -16,6 +16,7 @@
#include <linux/stringify.h>
#include <linux/kobject.h>
#include <linux/moduleparam.h>
+#include <linux/condcall.h>
#include <asm/local.h>
#include <asm/module.h>
@@ -356,6 +357,9 @@
/* The command line arguments (may be mangled). People like
keeping pointers to this stuff */
char *args;
+
+ const struct __cond_call_struct *cond_calls;
+ unsigned int num_cond_calls;
};
#ifndef MODULE_ARCH_INIT
#define MODULE_ARCH_INIT {}
Index: linux-2.6-lttng/kernel/module.c
===================================================================
--- linux-2.6-lttng.orig/kernel/module.c 2007-05-17 02:12:25.000000000 -0400
+++ linux-2.6-lttng/kernel/module.c 2007-05-17 02:13:53.000000000 -0400
@@ -32,6 +32,7 @@
#include <linux/cpu.h>
#include <linux/moduleparam.h>
#include <linux/errno.h>
+#include <linux/condcall.h>
#include <linux/err.h>
#include <linux/vermagic.h>
#include <linux/notifier.h>
@@ -141,6 +142,8 @@
extern const unsigned long __start___kcrctab_gpl_future[];
extern const unsigned long __start___kcrctab_unused[];
extern const unsigned long __start___kcrctab_unused_gpl[];
+extern const struct __cond_call_struct __start___cond_call[];
+extern const struct __cond_call_struct __stop___cond_call[];
#ifndef CONFIG_MODVERSIONS
#define symversion(base, idx) NULL
@@ -301,6 +304,230 @@
return NULL;
}
+#ifdef CONFIG_COND_CALL
+
+/* Set the enable bit of the cond_call, choosing the generic or architecture
+ * specific functions depending on the cond_call's flags.
+ */
+static int cond_call_set_enable(void *address, char enable, int flags)
+{
+ if (flags & CF_OPTIMIZED)
+ return cond_call_optimized_set_enable(address, enable);
+ else
+ return cond_call_generic_set_enable(address, enable);
+}
+
+/* Query the state of a cond_calls range. */
+static int _cond_call_query_range(const char *name,
+ const struct __cond_call_struct *begin,
+ const struct __cond_call_struct *end)
+{
+ const struct __cond_call_struct *iter;
+ int ret = 0;
+
+ for (iter = begin; iter < end; iter++) {
+ if (strcmp(name, iter->name) != 0)
+ continue;
+ if (iter->flags & CF_OPTIMIZED)
+ ret = COND_CALL_OPTIMIZED_ENABLE(iter->enable);
+ else
+ ret = COND_CALL_GENERIC_ENABLE(iter->enable);
+ if (ret)
+ break;
+ }
+ return ret;
+}
+
+/* Sets a range of cond_calls to a enabled state : set the enable bit. */
+static int _cond_call_arm_range(const char *name,
+ const struct __cond_call_struct *begin,
+ const struct __cond_call_struct *end)
+{
+ const struct __cond_call_struct *iter;
+ int found = 0;
+
+ for (iter = begin; iter < end; iter++) {
+ if (strcmp(name, iter->name) != 0)
+ continue;
+ cond_call_set_enable(iter->enable, 1, iter->flags);
+ found++;
+ }
+ return found;
+}
+
+/* Sets a range of cond_calls to a disabled state : unset the enable bit. */
+static int _cond_call_disarm_range(const char *name,
+ const struct __cond_call_struct *begin,
+ const struct __cond_call_struct *end)
+{
+ const struct __cond_call_struct *iter;
+ int found = 0;
+
+ for (iter = begin; iter < end; iter++) {
+ if (strcmp(name, iter->name) != 0)
+ continue;
+ cond_call_set_enable(iter->enable, 0, iter->flags);
+ found++;
+ }
+ return found;
+}
+
+/* Provides a listing of the cond_calls present in the kernel with their type
+ * (optimized or generic) and state (enabled or disabled). */
+static int _cond_call_list_range(const char *name,
+ const struct __cond_call_struct *begin,
+ const struct __cond_call_struct *end)
+{
+ const struct __cond_call_struct *iter;
+ int found = 0;
+
+ for (iter = begin; iter < end; iter++) {
+ if (name)
+ if (strcmp(name, iter->name) != 0)
+ continue;
+ printk("name %s \n", iter->name);
+ if (iter->flags & CF_OPTIMIZED)
+ printk(" enable %u optimized\n",
+ COND_CALL_OPTIMIZED_ENABLE(iter->enable));
+ else
+ printk(" enable %u generic\n",
+ COND_CALL_GENERIC_ENABLE(iter->enable));
+ found++;
+ }
+ return found;
+}
+
+/* Calls _cond_call_query_range for the core cond_calls and modules cond_calls.
+ */
+static int _cond_call_query(const char *name)
+{
+ struct module *mod;
+ int ret = 0;
+
+ /* Core kernel cond_calls */
+ ret = _cond_call_query_range(name,
+ __start___cond_call, __stop___cond_call);
+ if (ret)
+ return ret;
+ /* Cond_calls in modules. */
+ list_for_each_entry(mod, &modules, list) {
+ if (mod->taints)
+ continue;
+ ret = _cond_call_query_range(name,
+ mod->cond_calls, mod->cond_calls+mod->num_cond_calls);
+ if (ret)
+ break;
+ }
+ return ret;
+}
+
+/* Cond_call enabling/disabling use the module_mutex to synchronize.
+ * Returns 1 if enabled, 0 if disabled or not present. */
+int cond_call_query(const char *name)
+{
+ int ret = 0;
+
+ mutex_lock(&module_mutex);
+ ret = _cond_call_query(name);
+ mutex_unlock(&module_mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cond_call_query);
+
+/* Calls _cond_call_arm_range for the core cond_calls and modules cond_calls.
+ * FIXME : cond_call will not be active on modules loaded later than the
+ * cond_call_arm. */
+static int _cond_call_arm(const char *name)
+{
+ struct module *mod;
+ int found = 0;
+
+ /* Core kernel cond_calls */
+ found += _cond_call_arm_range(name,
+ __start___cond_call, __stop___cond_call);
+ /* Cond_calls in modules. */
+ list_for_each_entry(mod, &modules, list) {
+ if (mod->taints)
+ continue;
+ found += _cond_call_arm_range(name,
+ mod->cond_calls, mod->cond_calls+mod->num_cond_calls);
+ }
+ return found;
+}
+
+/* Cond_call enabling/disabling use the module_mutex to synchronize. */
+int cond_call_arm(const char *name)
+{
+ int found = 0;
+
+ mutex_lock(&module_mutex);
+ found = _cond_call_arm(name);
+ mutex_unlock(&module_mutex);
+ return found;
+}
+EXPORT_SYMBOL_GPL(cond_call_arm);
+
+/* Calls _cond_call_disarm_range for the core cond_calls and modules cond_calls.
+ */
+static int _cond_call_disarm(const char *name)
+{
+ struct module *mod;
+ int found = 0;
+
+ /* Core kernel cond_calls */
+ found += _cond_call_disarm_range(name,
+ __start___cond_call, __stop___cond_call);
+ /* Cond_calls in modules. */
+ list_for_each_entry(mod, &modules, list) {
+ if (mod->taints)
+ continue;
+ found += _cond_call_disarm_range(name,
+ mod->cond_calls, mod->cond_calls+mod->num_cond_calls);
+ }
+ return found;
+}
+
+/* Cond_call enabling/disabling use the module_mutex to synchronize. */
+int cond_call_disarm(const char *name)
+{
+ int found = 0;
+
+ mutex_lock(&module_mutex);
+ found = _cond_call_disarm(name);
+ mutex_unlock(&module_mutex);
+ return found;
+}
+EXPORT_SYMBOL_GPL(cond_call_disarm);
+
+/* Calls _cond_call_list_range for the core and module cond_calls.
+ * Cond call listing uses the module_mutex to synchronize.
+ * TODO : should output this listing to a procfs file. */
+int cond_call_list(const char *name)
+{
+ struct module *mod;
+ int found = 0;
+
+ mutex_lock(&module_mutex);
+ /* Core kernel cond_calls */
+ printk("Listing kernel cond_calls\n");
+ found += _cond_call_list_range(name,
+ __start___cond_call, __stop___cond_call);
+ /* Cond_calls in modules. */
+ printk("Listing module cond_calls\n");
+ list_for_each_entry(mod, &modules, list) {
+ if (!mod->taints) {
+ printk("Listing cond_calls for module %s\n", mod->name);
+ found += _cond_call_list_range(name, mod->cond_calls,
+ mod->cond_calls+mod->num_cond_calls);
+ }
+ }
+ mutex_unlock(&module_mutex);
+ return found;
+}
+EXPORT_SYMBOL_GPL(cond_call_list);
+
+#endif
+
#ifdef CONFIG_SMP
/* Number of blocks used and allocated. */
static unsigned int pcpu_num_used, pcpu_num_allocated;
@@ -1658,6 +1885,8 @@
unsigned int unusedcrcindex;
unsigned int unusedgplindex;
unsigned int unusedgplcrcindex;
+ unsigned int condcallindex;
+ unsigned int condcallstringsindex;
struct module *mod;
long err = 0;
void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
@@ -1754,6 +1983,8 @@
#ifdef ARCH_UNWIND_SECTION_NAME
unwindex = find_sec(hdr, sechdrs, secstrings, ARCH_UNWIND_SECTION_NAME);
#endif
+ condcallindex = find_sec(hdr, sechdrs, secstrings, "__cond_call");
+ condcallstringsindex = find_sec(hdr, sechdrs, secstrings, "__cond_call_strings");
/* Don't keep modinfo section */
sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
@@ -1764,6 +1995,18 @@
#endif
if (unwindex)
sechdrs[unwindex].sh_flags |= SHF_ALLOC;
+#ifdef CONFIG_COND_CALL
+ if (condcallindex)
+ sechdrs[condcallindex].sh_flags |= SHF_ALLOC;
+ if (condcallstringsindex)
+ sechdrs[condcallstringsindex].sh_flags |= SHF_ALLOC;
+#else
+ if (condcallindex)
+ sechdrs[condcallindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
+ if (condcallstringsindex)
+ sechdrs[condcallstringsindex].sh_flags
+ &= ~(unsigned long)SHF_ALLOC;
+#endif
/* Check module struct version now, before we try to use module. */
if (!check_modstruct_version(sechdrs, versindex, mod)) {
@@ -1904,6 +2147,11 @@
mod->gpl_future_syms = (void *)sechdrs[gplfutureindex].sh_addr;
if (gplfuturecrcindex)
mod->gpl_future_crcs = (void *)sechdrs[gplfuturecrcindex].sh_addr;
+ if (condcallindex) {
+ mod->cond_calls = (void *)sechdrs[condcallindex].sh_addr;
+ mod->num_cond_calls =
+ sechdrs[condcallindex].sh_size / sizeof(*mod->cond_calls);
+ }
mod->unused_syms = (void *)sechdrs[unusedindex].sh_addr;
if (unusedcrcindex)
--
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
^ permalink raw reply [flat|nested] 19+ messages in thread
* [patch 2/9] Conditional Calls - Hash Table
2007-05-29 18:33 [patch 0/9] Conditional Calls Mathieu Desnoyers
2007-05-29 18:33 ` [patch 1/9] Conditional Calls - Architecture Independent Code Mathieu Desnoyers
@ 2007-05-29 18:33 ` Mathieu Desnoyers
2007-05-29 18:33 ` [patch 3/9] Conditional Calls - Non Optimized Architectures Mathieu Desnoyers
` (7 subsequent siblings)
9 siblings, 0 replies; 19+ messages in thread
From: Mathieu Desnoyers @ 2007-05-29 18:33 UTC (permalink / raw)
To: akpm, linux-kernel; +Cc: Mathieu Desnoyers
[-- Attachment #1: conditional-calls-hash-table.patch --]
[-- Type: text/plain, Size: 10654 bytes --]
Reimplementation of the cond calls which uses a hash table to hold the active
cond_calls. It permits to first arm a cond_call and then load supplementary
modules that contain this cond_call.
Without this, the order of loading a module containing a cond_call and arming a
cond_call matters and there is no symbol dependency to check this.
At module load time, each cond_call checks if it is enabled in the hash table
and is set accordingly.
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
---
include/linux/condcall.h | 2
kernel/module.c | 205 +++++++++++++++++++++++++++++------------------
2 files changed, 129 insertions(+), 78 deletions(-)
Index: linux-2.6-lttng/kernel/module.c
===================================================================
--- linux-2.6-lttng.orig/kernel/module.c 2007-05-17 01:42:50.000000000 -0400
+++ linux-2.6-lttng/kernel/module.c 2007-05-17 01:46:42.000000000 -0400
@@ -33,6 +33,8 @@
#include <linux/moduleparam.h>
#include <linux/errno.h>
#include <linux/condcall.h>
+#include <linux/jhash.h>
+#include <linux/list.h>
#include <linux/err.h>
#include <linux/vermagic.h>
#include <linux/notifier.h>
@@ -71,6 +73,20 @@
static BLOCKING_NOTIFIER_HEAD(module_notify_list);
+#ifdef CONFIG_COND_CALL
+/* Conditional call hash table, containing the active cond_calls.
+ * Protected by module_mutex. */
+#define COND_CALL_HASH_BITS 6
+#define COND_CALL_TABLE_SIZE (1 << COND_CALL_HASH_BITS)
+
+struct cond_call_entry {
+ struct hlist_node hlist;
+ char name[0];
+};
+
+static struct hlist_head cond_call_table[COND_CALL_TABLE_SIZE];
+#endif //CONFIG_COND_CALL
+
int register_module_notifier(struct notifier_block * nb)
{
return blocking_notifier_chain_register(&module_notify_list, nb);
@@ -305,6 +321,68 @@
}
#ifdef CONFIG_COND_CALL
+/* Check if the cond_call is present in the hash table.
+ * Returns 1 if present, 0 if not. */
+static int hash_check_cond_call(const char *name)
+{
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct cond_call_entry *e;
+ size_t len = strlen(name);
+ u32 hash = jhash(name, len, 0);
+
+ head = &cond_call_table[hash & ((1 << COND_CALL_HASH_BITS)-1)];
+ hlist_for_each_entry(e, node, head, hlist)
+ if (!strcmp(name, e->name))
+ return 1;
+ return 0;
+}
+
+/* Add the cond_call to the hash table. Must be called with mutex_lock held. */
+static int hash_add_cond_call(const char *name)
+{
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct cond_call_entry *e;
+ size_t len = strlen(name);
+ u32 hash = jhash(name, len, 0);
+
+ head = &cond_call_table[hash & ((1 << COND_CALL_HASH_BITS)-1)];
+ hlist_for_each_entry(e, node, head, hlist)
+ if (!strcmp(name, e->name))
+ return 0; /* Already there */
+ /* Using kmalloc here to allocate a variable length element. Could
+ * cause some memory fragmentation if overused. */
+ e = kmalloc(sizeof(struct cond_call_entry) + len + 1, GFP_KERNEL);
+ if (!e)
+ return -ENOMEM;
+ memcpy(&e->name[0], name, len + 1);
+ hlist_add_head(&e->hlist, head);
+ return 0;
+}
+
+/* Remove the cond_call from the hash table. Must be called with mutex_lock
+ * held. */
+static void hash_remove_cond_call(const char *name)
+{
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct cond_call_entry *e;
+ int found = 0;
+ size_t len = strlen(name);
+ u32 hash = jhash(name, len, 0);
+
+ head = &cond_call_table[hash & ((1 << COND_CALL_HASH_BITS)-1)];
+ hlist_for_each_entry(e, node, head, hlist)
+ if (!strcmp(name, e->name)) {
+ found = 1;
+ break;
+ }
+ if (found) {
+ hlist_del(&e->hlist);
+ kfree(e);
+ }
+}
/* Set the enable bit of the cond_call, choosing the generic or architecture
* specific functions depending on the cond_call's flags.
@@ -317,59 +395,53 @@
return cond_call_generic_set_enable(address, enable);
}
-/* Query the state of a cond_calls range. */
-static int _cond_call_query_range(const char *name,
- const struct __cond_call_struct *begin,
- const struct __cond_call_struct *end)
+static int cond_call_get_enable(void *address, int flags)
+{
+ if (flags & CF_OPTIMIZED)
+ return COND_CALL_OPTIMIZED_ENABLE(address);
+ else
+ return COND_CALL_GENERIC_ENABLE(address);
+}
+
+/* Setup the cond_call according to the data present in the cond_call hash
+ * upon module load. */
+void module_cond_call_setup(struct module *mod)
{
const struct __cond_call_struct *iter;
- int ret = 0;
+ int enable;
- for (iter = begin; iter < end; iter++) {
- if (strcmp(name, iter->name) != 0)
- continue;
- if (iter->flags & CF_OPTIMIZED)
- ret = COND_CALL_OPTIMIZED_ENABLE(iter->enable);
- else
- ret = COND_CALL_GENERIC_ENABLE(iter->enable);
- if (ret)
- break;
+ for (iter = mod->cond_calls;
+ iter < mod->cond_calls+mod->num_cond_calls; iter++) {
+ enable = hash_check_cond_call(iter->name);
+ if (enable != cond_call_get_enable(iter->enable, iter->flags))
+ cond_call_set_enable(iter->enable, enable, iter->flags);
}
- return ret;
}
/* Sets a range of cond_calls to a enabled state : set the enable bit. */
-static int _cond_call_arm_range(const char *name,
+static void _cond_call_arm_range(const char *name,
const struct __cond_call_struct *begin,
const struct __cond_call_struct *end)
{
const struct __cond_call_struct *iter;
- int found = 0;
for (iter = begin; iter < end; iter++) {
- if (strcmp(name, iter->name) != 0)
- continue;
- cond_call_set_enable(iter->enable, 1, iter->flags);
- found++;
+ if (!strcmp(name, iter->name))
+ cond_call_set_enable(iter->enable, 1, iter->flags);
}
- return found;
}
/* Sets a range of cond_calls to a disabled state : unset the enable bit. */
-static int _cond_call_disarm_range(const char *name,
+static void _cond_call_disarm_range(const char *name,
const struct __cond_call_struct *begin,
const struct __cond_call_struct *end)
{
const struct __cond_call_struct *iter;
- int found = 0;
for (iter = begin; iter < end; iter++) {
- if (strcmp(name, iter->name) != 0)
- continue;
- cond_call_set_enable(iter->enable, 0, iter->flags);
- found++;
+ if (!strcmp(name, iter->name))
+ cond_call_set_enable(iter->enable, 0, iter->flags);
}
- return found;
}
/* Provides a listing of the cond_calls present in the kernel with their type
@@ -397,105 +469,79 @@
return found;
}
-/* Calls _cond_call_query_range for the core cond_calls and modules cond_calls.
- */
-static int _cond_call_query(const char *name)
-{
- struct module *mod;
- int ret = 0;
-
- /* Core kernel cond_calls */
- ret = _cond_call_query_range(name,
- __start___cond_call, __stop___cond_call);
- if (ret)
- return ret;
- /* Cond_calls in modules. */
- list_for_each_entry(mod, &modules, list) {
- if (mod->taints)
- continue;
- ret = _cond_call_query_range(name,
- mod->cond_calls, mod->cond_calls+mod->num_cond_calls);
- if (ret)
- break;
- }
- return ret;
-}
-
/* Cond_call enabling/disabling use the module_mutex to synchronize.
- * Returns 1 if enabled, 0 if disabled or not present. */
+ * Returns 1 if enabled, 0 if disabled. */
int cond_call_query(const char *name)
{
- int ret = 0;
+ int ret;
mutex_lock(&module_mutex);
- ret = _cond_call_query(name);
+ ret = hash_check_cond_call(name);
mutex_unlock(&module_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(cond_call_query);
-/* Calls _cond_call_arm_range for the core cond_calls and modules cond_calls.
- * FIXME : cond_call will not be active on modules loaded later than the
- * cond_call_arm. */
+/* Calls _cond_call_arm_range for the core cond_calls and modules cond_calls. */
static int _cond_call_arm(const char *name)
{
struct module *mod;
- int found = 0;
+ int ret;
+
+ ret = hash_add_cond_call(name);
+ if (ret)
+ return ret;
/* Core kernel cond_calls */
- found += _cond_call_arm_range(name,
+ _cond_call_arm_range(name,
__start___cond_call, __stop___cond_call);
/* Cond_calls in modules. */
list_for_each_entry(mod, &modules, list) {
if (mod->taints)
continue;
- found += _cond_call_arm_range(name,
+ _cond_call_arm_range(name,
mod->cond_calls, mod->cond_calls+mod->num_cond_calls);
}
- return found;
+ return ret;
}
/* Cond_call enabling/disabling use the module_mutex to synchronize. */
int cond_call_arm(const char *name)
{
- int found = 0;
+ int ret;
mutex_lock(&module_mutex);
- found = _cond_call_arm(name);
+ ret = _cond_call_arm(name);
mutex_unlock(&module_mutex);
- return found;
+ return ret;
}
EXPORT_SYMBOL_GPL(cond_call_arm);
/* Calls _cond_call_disarm_range for the core cond_calls and modules cond_calls.
*/
-static int _cond_call_disarm(const char *name)
+static void _cond_call_disarm(const char *name)
{
struct module *mod;
- int found = 0;
/* Core kernel cond_calls */
- found += _cond_call_disarm_range(name,
+ _cond_call_disarm_range(name,
__start___cond_call, __stop___cond_call);
/* Cond_calls in modules. */
list_for_each_entry(mod, &modules, list) {
if (mod->taints)
continue;
- found += _cond_call_disarm_range(name,
+ _cond_call_disarm_range(name,
mod->cond_calls, mod->cond_calls+mod->num_cond_calls);
}
- return found;
+ hash_remove_cond_call(name);
}
/* Cond_call enabling/disabling use the module_mutex to synchronize. */
-int cond_call_disarm(const char *name)
+void cond_call_disarm(const char *name)
{
- int found = 0;
-
mutex_lock(&module_mutex);
- found = _cond_call_disarm(name);
+ _cond_call_disarm(name);
mutex_unlock(&module_mutex);
- return found;
}
EXPORT_SYMBOL_GPL(cond_call_disarm);
@@ -525,7 +571,10 @@
return found;
}
EXPORT_SYMBOL_GPL(cond_call_list);
-
+#else
+static void module_cond_call_setup(struct module *mod)
+{
+}
#endif
#ifdef CONFIG_SMP
@@ -2211,6 +2260,8 @@
add_kallsyms(mod, sechdrs, symindex, strindex, secstrings);
+ module_cond_call_setup(mod);
+
err = module_finalize(hdr, sechdrs, mod);
if (err < 0)
goto cleanup;
Index: linux-2.6-lttng/include/linux/condcall.h
===================================================================
--- linux-2.6-lttng.orig/include/linux/condcall.h 2007-05-17 01:42:50.000000000 -0400
+++ linux-2.6-lttng/include/linux/condcall.h 2007-05-17 01:46:42.000000000 -0400
@@ -81,7 +81,7 @@
#define COND_CALL_MAX_FORMAT_LEN 1024
extern int cond_call_arm(const char *name);
-extern int cond_call_disarm(const char *name);
+extern void cond_call_disarm(const char *name);
/* cond_call_query : Returns 1 if enabled, 0 if disabled or not present */
extern int cond_call_query(const char *name);
--
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
^ permalink raw reply [flat|nested] 19+ messages in thread
* [patch 3/9] Conditional Calls - Non Optimized Architectures
2007-05-29 18:33 [patch 0/9] Conditional Calls Mathieu Desnoyers
2007-05-29 18:33 ` [patch 1/9] Conditional Calls - Architecture Independent Code Mathieu Desnoyers
2007-05-29 18:33 ` [patch 2/9] Conditional Calls - Hash Table Mathieu Desnoyers
@ 2007-05-29 18:33 ` Mathieu Desnoyers
2007-05-29 18:34 ` [patch 4/9] Conditional Calls - Add kconfig menus Mathieu Desnoyers
` (6 subsequent siblings)
9 siblings, 0 replies; 19+ messages in thread
From: Mathieu Desnoyers @ 2007-05-29 18:33 UTC (permalink / raw)
To: akpm, linux-kernel; +Cc: Mathieu Desnoyers
[-- Attachment #1: conditional-calls-non-optimized-architectures.patch --]
[-- Type: text/plain, Size: 9947 bytes --]
Architecture agnostic, generic, version of the cond_calls.
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
---
include/asm-alpha/condcall.h | 1 +
include/asm-arm/condcall.h | 1 +
include/asm-arm26/condcall.h | 1 +
include/asm-cris/condcall.h | 1 +
include/asm-frv/condcall.h | 1 +
include/asm-generic/condcall.h | 25 +++++++++++++++++++++++++
include/asm-h8300/condcall.h | 1 +
include/asm-i386/condcall.h | 1 +
include/asm-ia64/condcall.h | 1 +
include/asm-m32r/condcall.h | 1 +
include/asm-m68k/condcall.h | 1 +
include/asm-m68knommu/condcall.h | 1 +
include/asm-mips/condcall.h | 1 +
include/asm-parisc/condcall.h | 1 +
include/asm-powerpc/condcall.h | 1 +
include/asm-ppc/condcall.h | 1 +
include/asm-s390/condcall.h | 1 +
include/asm-sh/condcall.h | 1 +
include/asm-sh64/condcall.h | 1 +
include/asm-sparc/condcall.h | 1 +
include/asm-sparc64/condcall.h | 1 +
include/asm-um/condcall.h | 1 +
include/asm-v850/condcall.h | 1 +
include/asm-x86_64/condcall.h | 1 +
include/asm-xtensa/condcall.h | 1 +
25 files changed, 49 insertions(+)
Index: linux-2.6-lttng/include/asm-generic/condcall.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6-lttng/include/asm-generic/condcall.h 2007-05-29 11:56:07.000000000 -0400
@@ -0,0 +1,25 @@
+#ifndef _ASM_GENERIC_CONDCALL_H
+#define _ASM_GENERIC_CONDCALL_H
+
+/* Default flags, used by _cond_call() */
+#define CF_DEFAULT 0
+
+/* Fallback on the generic cond_call, since no optimized version is available */
+#define cond_call_optimized cond_call_generic
+#define _cond_call(flags, name, func) cond_call_generic(flags, name, func)
+
+/* cond_call with default behavior */
+#define cond_call(name, func) _cond_call(CF_DEFAULT, name, func)
+
+/* Architecture dependant cond_call information, used internally for cond_call
+ * activation. */
+
+#define COND_CALL_OPTIMIZED_ENABLE_IMMEDIATE_OFFSET \
+ COND_CALL_GENERIC_ENABLE_IMMEDIATE_OFFSET
+#define COND_CALL_OPTIMIZED_ENABLE_TYPE COND_CALL_GENERIC_ENABLE_TYPE
+/* Dereference enable as lvalue from a pointer to its instruction */
+#define COND_CALL_OPTIMIZED_ENABLE COND_CALL_GENERIC_ENABLE
+
+#define cond_call_optimized_set_enable cond_call_generic_set_enable
+
+#endif /* _ASM_GENERIC_MARKER_H */
Index: linux-2.6-lttng/include/asm-alpha/condcall.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6-lttng/include/asm-alpha/condcall.h 2007-05-29 11:55:58.000000000 -0400
@@ -0,0 +1 @@
+#include <asm-generic/condcall.h>
Index: linux-2.6-lttng/include/asm-arm/condcall.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6-lttng/include/asm-arm/condcall.h 2007-05-29 11:55:58.000000000 -0400
@@ -0,0 +1 @@
+#include <asm-generic/condcall.h>
Index: linux-2.6-lttng/include/asm-arm26/condcall.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6-lttng/include/asm-arm26/condcall.h 2007-05-29 11:55:58.000000000 -0400
@@ -0,0 +1 @@
+#include <asm-generic/condcall.h>
Index: linux-2.6-lttng/include/asm-cris/condcall.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6-lttng/include/asm-cris/condcall.h 2007-05-29 11:55:58.000000000 -0400
@@ -0,0 +1 @@
+#include <asm-generic/condcall.h>
Index: linux-2.6-lttng/include/asm-frv/condcall.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6-lttng/include/asm-frv/condcall.h 2007-05-29 11:55:58.000000000 -0400
@@ -0,0 +1 @@
+#include <asm-generic/condcall.h>
Index: linux-2.6-lttng/include/asm-h8300/condcall.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6-lttng/include/asm-h8300/condcall.h 2007-05-29 11:55:58.000000000 -0400
@@ -0,0 +1 @@
+#include <asm-generic/condcall.h>
Index: linux-2.6-lttng/include/asm-ia64/condcall.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6-lttng/include/asm-ia64/condcall.h 2007-05-29 11:55:58.000000000 -0400
@@ -0,0 +1 @@
+#include <asm-generic/condcall.h>
Index: linux-2.6-lttng/include/asm-m32r/condcall.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6-lttng/include/asm-m32r/condcall.h 2007-05-29 11:55:58.000000000 -0400
@@ -0,0 +1 @@
+#include <asm-generic/condcall.h>
Index: linux-2.6-lttng/include/asm-m68k/condcall.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6-lttng/include/asm-m68k/condcall.h 2007-05-29 11:55:58.000000000 -0400
@@ -0,0 +1 @@
+#include <asm-generic/condcall.h>
Index: linux-2.6-lttng/include/asm-m68knommu/condcall.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6-lttng/include/asm-m68knommu/condcall.h 2007-05-29 11:55:58.000000000 -0400
@@ -0,0 +1 @@
+#include <asm-generic/condcall.h>
Index: linux-2.6-lttng/include/asm-mips/condcall.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6-lttng/include/asm-mips/condcall.h 2007-05-29 11:55:58.000000000 -0400
@@ -0,0 +1 @@
+#include <asm-generic/condcall.h>
Index: linux-2.6-lttng/include/asm-parisc/condcall.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6-lttng/include/asm-parisc/condcall.h 2007-05-29 11:55:58.000000000 -0400
@@ -0,0 +1 @@
+#include <asm-generic/condcall.h>
Index: linux-2.6-lttng/include/asm-ppc/condcall.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6-lttng/include/asm-ppc/condcall.h 2007-05-29 11:55:58.000000000 -0400
@@ -0,0 +1 @@
+#include <asm-generic/condcall.h>
Index: linux-2.6-lttng/include/asm-s390/condcall.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6-lttng/include/asm-s390/condcall.h 2007-05-29 11:55:58.000000000 -0400
@@ -0,0 +1 @@
+#include <asm-generic/condcall.h>
Index: linux-2.6-lttng/include/asm-sh/condcall.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6-lttng/include/asm-sh/condcall.h 2007-05-29 11:55:58.000000000 -0400
@@ -0,0 +1 @@
+#include <asm-generic/condcall.h>
Index: linux-2.6-lttng/include/asm-sh64/condcall.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6-lttng/include/asm-sh64/condcall.h 2007-05-29 11:55:58.000000000 -0400
@@ -0,0 +1 @@
+#include <asm-generic/condcall.h>
Index: linux-2.6-lttng/include/asm-sparc/condcall.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6-lttng/include/asm-sparc/condcall.h 2007-05-29 11:55:58.000000000 -0400
@@ -0,0 +1 @@
+#include <asm-generic/condcall.h>
Index: linux-2.6-lttng/include/asm-sparc64/condcall.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6-lttng/include/asm-sparc64/condcall.h 2007-05-29 11:55:58.000000000 -0400
@@ -0,0 +1 @@
+#include <asm-generic/condcall.h>
Index: linux-2.6-lttng/include/asm-um/condcall.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6-lttng/include/asm-um/condcall.h 2007-05-29 11:55:58.000000000 -0400
@@ -0,0 +1 @@
+#include <asm-generic/condcall.h>
Index: linux-2.6-lttng/include/asm-v850/condcall.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6-lttng/include/asm-v850/condcall.h 2007-05-29 11:55:58.000000000 -0400
@@ -0,0 +1 @@
+#include <asm-generic/condcall.h>
Index: linux-2.6-lttng/include/asm-x86_64/condcall.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6-lttng/include/asm-x86_64/condcall.h 2007-05-29 11:55:58.000000000 -0400
@@ -0,0 +1 @@
+#include <asm-generic/condcall.h>
Index: linux-2.6-lttng/include/asm-xtensa/condcall.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6-lttng/include/asm-xtensa/condcall.h 2007-05-29 11:55:58.000000000 -0400
@@ -0,0 +1 @@
+#include <asm-generic/condcall.h>
Index: linux-2.6-lttng/include/asm-i386/condcall.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6-lttng/include/asm-i386/condcall.h 2007-05-29 11:55:58.000000000 -0400
@@ -0,0 +1 @@
+#include <asm-generic/condcall.h>
Index: linux-2.6-lttng/include/asm-powerpc/condcall.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6-lttng/include/asm-powerpc/condcall.h 2007-05-29 11:55:58.000000000 -0400
@@ -0,0 +1 @@
+#include <asm-generic/condcall.h>
--
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
^ permalink raw reply [flat|nested] 19+ messages in thread
* [patch 4/9] Conditional Calls - Add kconfig menus
2007-05-29 18:33 [patch 0/9] Conditional Calls Mathieu Desnoyers
` (2 preceding siblings ...)
2007-05-29 18:33 ` [patch 3/9] Conditional Calls - Non Optimized Architectures Mathieu Desnoyers
@ 2007-05-29 18:34 ` Mathieu Desnoyers
2007-05-29 18:34 ` [patch 5/9] Conditional Calls - i386 Optimization Mathieu Desnoyers
` (5 subsequent siblings)
9 siblings, 0 replies; 19+ messages in thread
From: Mathieu Desnoyers @ 2007-05-29 18:34 UTC (permalink / raw)
To: akpm, linux-kernel; +Cc: Mathieu Desnoyers, Adrian Bunk, Andi Kleen
[-- Attachment #1: conditional-calls-kconfig-menus.patch --]
[-- Type: text/plain, Size: 14392 bytes --]
Conditional calls provide a way to compile in kernels features that can be
enabled dynamically, with a very small footprint when disabled.
This patch:
Add Kconfig menus for the marker code.
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
CC: Adrian Bunk <bunk@stusta.de>
CC: Andi Kleen <andi@firstfloor.org>
---
arch/alpha/Kconfig | 6 ++++++
arch/arm/Kconfig | 6 ++++++
arch/arm26/Kconfig | 6 ++++++
arch/avr32/Kconfig.debug | 7 +++++++
arch/cris/Kconfig | 6 ++++++
arch/frv/Kconfig | 6 ++++++
arch/h8300/Kconfig | 6 ++++++
arch/i386/Kconfig | 3 +++
arch/ia64/Kconfig | 3 +++
arch/m32r/Kconfig | 6 ++++++
arch/m68k/Kconfig | 6 ++++++
arch/m68knommu/Kconfig | 6 ++++++
arch/mips/Kconfig | 6 ++++++
arch/parisc/Kconfig | 6 ++++++
arch/powerpc/Kconfig | 3 +++
arch/ppc/Kconfig | 6 ++++++
arch/s390/Kconfig | 2 ++
arch/sh/Kconfig | 6 ++++++
arch/sh64/Kconfig | 6 ++++++
arch/sparc/Kconfig | 2 ++
arch/sparc64/Kconfig | 3 +++
arch/um/Kconfig | 6 ++++++
arch/v850/Kconfig | 6 ++++++
arch/x86_64/Kconfig | 3 +++
arch/xtensa/Kconfig | 6 ++++++
kernel/Kconfig.condcall | 20 ++++++++++++++++++++
26 files changed, 148 insertions(+)
Index: linux-2.6-lttng/arch/alpha/Kconfig
===================================================================
--- linux-2.6-lttng.orig/arch/alpha/Kconfig 2007-05-17 02:12:23.000000000 -0400
+++ linux-2.6-lttng/arch/alpha/Kconfig 2007-05-17 02:13:28.000000000 -0400
@@ -642,6 +642,12 @@
source "arch/alpha/oprofile/Kconfig"
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.condcall"
+
+endmenu
+
source "arch/alpha/Kconfig.debug"
source "security/Kconfig"
Index: linux-2.6-lttng/arch/arm/Kconfig
===================================================================
--- linux-2.6-lttng.orig/arch/arm/Kconfig 2007-05-17 02:12:23.000000000 -0400
+++ linux-2.6-lttng/arch/arm/Kconfig 2007-05-17 02:13:28.000000000 -0400
@@ -1025,6 +1025,12 @@
source "arch/arm/oprofile/Kconfig"
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.condcall"
+
+endmenu
+
source "arch/arm/Kconfig.debug"
source "security/Kconfig"
Index: linux-2.6-lttng/arch/arm26/Kconfig
===================================================================
--- linux-2.6-lttng.orig/arch/arm26/Kconfig 2007-05-17 02:12:23.000000000 -0400
+++ linux-2.6-lttng/arch/arm26/Kconfig 2007-05-17 02:13:28.000000000 -0400
@@ -241,6 +241,12 @@
source "drivers/usb/Kconfig"
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.condcall"
+
+endmenu
+
source "arch/arm26/Kconfig.debug"
source "security/Kconfig"
Index: linux-2.6-lttng/arch/cris/Kconfig
===================================================================
--- linux-2.6-lttng.orig/arch/cris/Kconfig 2007-05-17 02:12:23.000000000 -0400
+++ linux-2.6-lttng/arch/cris/Kconfig 2007-05-17 02:13:28.000000000 -0400
@@ -198,6 +198,12 @@
source "drivers/usb/Kconfig"
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.condcall"
+
+endmenu
+
source "arch/cris/Kconfig.debug"
source "security/Kconfig"
Index: linux-2.6-lttng/arch/frv/Kconfig
===================================================================
--- linux-2.6-lttng.orig/arch/frv/Kconfig 2007-05-17 02:12:23.000000000 -0400
+++ linux-2.6-lttng/arch/frv/Kconfig 2007-05-17 02:13:28.000000000 -0400
@@ -385,6 +385,12 @@
source "fs/Kconfig"
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.condcall"
+
+endmenu
+
source "arch/frv/Kconfig.debug"
source "security/Kconfig"
Index: linux-2.6-lttng/arch/h8300/Kconfig
===================================================================
--- linux-2.6-lttng.orig/arch/h8300/Kconfig 2007-05-17 02:12:23.000000000 -0400
+++ linux-2.6-lttng/arch/h8300/Kconfig 2007-05-17 02:13:28.000000000 -0400
@@ -220,6 +220,12 @@
source "fs/Kconfig"
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.condcall"
+
+endmenu
+
source "arch/h8300/Kconfig.debug"
source "security/Kconfig"
Index: linux-2.6-lttng/arch/i386/Kconfig
===================================================================
--- linux-2.6-lttng.orig/arch/i386/Kconfig 2007-05-17 02:12:23.000000000 -0400
+++ linux-2.6-lttng/arch/i386/Kconfig 2007-05-17 02:13:28.000000000 -0400
@@ -1229,6 +1229,9 @@
a probepoint and specifies the callback. Kprobes is useful
for kernel debugging, non-intrusive instrumentation and testing.
If in doubt, say "N".
+
+source "kernel/Kconfig.condcall"
+
endmenu
source "arch/i386/Kconfig.debug"
Index: linux-2.6-lttng/arch/ia64/Kconfig
===================================================================
--- linux-2.6-lttng.orig/arch/ia64/Kconfig 2007-05-17 02:12:23.000000000 -0400
+++ linux-2.6-lttng/arch/ia64/Kconfig 2007-05-17 02:13:28.000000000 -0400
@@ -591,6 +591,9 @@
a probepoint and specifies the callback. Kprobes is useful
for kernel debugging, non-intrusive instrumentation and testing.
If in doubt, say "N".
+
+source "kernel/Kconfig.condcall"
+
endmenu
source "arch/ia64/Kconfig.debug"
Index: linux-2.6-lttng/arch/m32r/Kconfig
===================================================================
--- linux-2.6-lttng.orig/arch/m32r/Kconfig 2007-05-17 02:12:23.000000000 -0400
+++ linux-2.6-lttng/arch/m32r/Kconfig 2007-05-17 02:13:28.000000000 -0400
@@ -401,6 +401,12 @@
source "arch/m32r/oprofile/Kconfig"
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.condcall"
+
+endmenu
+
source "arch/m32r/Kconfig.debug"
source "security/Kconfig"
Index: linux-2.6-lttng/arch/m68k/Kconfig
===================================================================
--- linux-2.6-lttng.orig/arch/m68k/Kconfig 2007-05-17 02:12:23.000000000 -0400
+++ linux-2.6-lttng/arch/m68k/Kconfig 2007-05-17 02:13:28.000000000 -0400
@@ -670,6 +670,12 @@
source "fs/Kconfig"
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.condcall"
+
+endmenu
+
source "arch/m68k/Kconfig.debug"
source "security/Kconfig"
Index: linux-2.6-lttng/arch/m68knommu/Kconfig
===================================================================
--- linux-2.6-lttng.orig/arch/m68knommu/Kconfig 2007-05-17 02:12:23.000000000 -0400
+++ linux-2.6-lttng/arch/m68knommu/Kconfig 2007-05-17 02:13:28.000000000 -0400
@@ -676,6 +676,12 @@
source "fs/Kconfig"
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.condcall"
+
+endmenu
+
source "arch/m68knommu/Kconfig.debug"
source "security/Kconfig"
Index: linux-2.6-lttng/arch/mips/Kconfig
===================================================================
--- linux-2.6-lttng.orig/arch/mips/Kconfig 2007-05-17 02:12:23.000000000 -0400
+++ linux-2.6-lttng/arch/mips/Kconfig 2007-05-17 02:13:28.000000000 -0400
@@ -2150,6 +2150,12 @@
source "arch/mips/oprofile/Kconfig"
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.condcall"
+
+endmenu
+
source "arch/mips/Kconfig.debug"
source "security/Kconfig"
Index: linux-2.6-lttng/arch/parisc/Kconfig
===================================================================
--- linux-2.6-lttng.orig/arch/parisc/Kconfig 2007-05-17 02:12:23.000000000 -0400
+++ linux-2.6-lttng/arch/parisc/Kconfig 2007-05-17 02:13:28.000000000 -0400
@@ -269,6 +269,12 @@
source "arch/parisc/oprofile/Kconfig"
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.condcall"
+
+endmenu
+
source "arch/parisc/Kconfig.debug"
source "security/Kconfig"
Index: linux-2.6-lttng/arch/powerpc/Kconfig
===================================================================
--- linux-2.6-lttng.orig/arch/powerpc/Kconfig 2007-05-17 02:12:23.000000000 -0400
+++ linux-2.6-lttng/arch/powerpc/Kconfig 2007-05-17 02:13:28.000000000 -0400
@@ -902,6 +902,9 @@
a probepoint and specifies the callback. Kprobes is useful
for kernel debugging, non-intrusive instrumentation and testing.
If in doubt, say "N".
+
+source "kernel/Kconfig.condcall"
+
endmenu
source "arch/powerpc/Kconfig.debug"
Index: linux-2.6-lttng/arch/ppc/Kconfig
===================================================================
--- linux-2.6-lttng.orig/arch/ppc/Kconfig 2007-05-17 02:12:23.000000000 -0400
+++ linux-2.6-lttng/arch/ppc/Kconfig 2007-05-17 02:13:28.000000000 -0400
@@ -1453,8 +1453,14 @@
source "lib/Kconfig"
+menu "Instrumentation Support"
+
source "arch/powerpc/oprofile/Kconfig"
+source "kernel/Kconfig.condcall"
+
+endmenu
+
source "arch/ppc/Kconfig.debug"
source "security/Kconfig"
Index: linux-2.6-lttng/arch/s390/Kconfig
===================================================================
--- linux-2.6-lttng.orig/arch/s390/Kconfig 2007-05-17 02:12:37.000000000 -0400
+++ linux-2.6-lttng/arch/s390/Kconfig 2007-05-17 02:13:28.000000000 -0400
@@ -569,6 +569,8 @@
source "lib/Kconfig.statistic"
+source "kernel/Kconfig.condcall"
+
endmenu
source "arch/s390/Kconfig.debug"
Index: linux-2.6-lttng/arch/sh/Kconfig
===================================================================
--- linux-2.6-lttng.orig/arch/sh/Kconfig 2007-05-17 02:12:23.000000000 -0400
+++ linux-2.6-lttng/arch/sh/Kconfig 2007-05-17 02:13:28.000000000 -0400
@@ -738,6 +738,12 @@
source "arch/sh/oprofile/Kconfig"
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.condcall"
+
+endmenu
+
source "arch/sh/Kconfig.debug"
source "security/Kconfig"
Index: linux-2.6-lttng/arch/sh64/Kconfig
===================================================================
--- linux-2.6-lttng.orig/arch/sh64/Kconfig 2007-05-17 02:12:24.000000000 -0400
+++ linux-2.6-lttng/arch/sh64/Kconfig 2007-05-17 02:13:28.000000000 -0400
@@ -281,6 +281,12 @@
source "arch/sh64/oprofile/Kconfig"
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.condcall"
+
+endmenu
+
source "arch/sh64/Kconfig.debug"
source "security/Kconfig"
Index: linux-2.6-lttng/arch/sparc/Kconfig
===================================================================
--- linux-2.6-lttng.orig/arch/sparc/Kconfig 2007-05-17 02:12:24.000000000 -0400
+++ linux-2.6-lttng/arch/sparc/Kconfig 2007-05-17 02:13:28.000000000 -0400
@@ -306,6 +306,8 @@
source "arch/sparc/oprofile/Kconfig"
+source "kernel/Kconfig.condcall"
+
endmenu
source "arch/sparc/Kconfig.debug"
Index: linux-2.6-lttng/arch/sparc64/Kconfig
===================================================================
--- linux-2.6-lttng.orig/arch/sparc64/Kconfig 2007-05-17 02:12:24.000000000 -0400
+++ linux-2.6-lttng/arch/sparc64/Kconfig 2007-05-17 02:13:28.000000000 -0400
@@ -444,6 +444,9 @@
a probepoint and specifies the callback. Kprobes is useful
for kernel debugging, non-intrusive instrumentation and testing.
If in doubt, say "N".
+
+source "kernel/Kconfig.condcall"
+
endmenu
source "arch/sparc64/Kconfig.debug"
Index: linux-2.6-lttng/arch/um/Kconfig
===================================================================
--- linux-2.6-lttng.orig/arch/um/Kconfig 2007-05-17 02:12:24.000000000 -0400
+++ linux-2.6-lttng/arch/um/Kconfig 2007-05-17 02:13:28.000000000 -0400
@@ -333,4 +333,10 @@
bool
default n
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.condcall"
+
+endmenu
+
source "arch/um/Kconfig.debug"
Index: linux-2.6-lttng/arch/v850/Kconfig
===================================================================
--- linux-2.6-lttng.orig/arch/v850/Kconfig 2007-05-17 02:12:24.000000000 -0400
+++ linux-2.6-lttng/arch/v850/Kconfig 2007-05-17 02:13:28.000000000 -0400
@@ -339,6 +339,12 @@
source "drivers/usb/Kconfig"
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.condcall"
+
+endmenu
+
source "arch/v850/Kconfig.debug"
source "security/Kconfig"
Index: linux-2.6-lttng/arch/x86_64/Kconfig
===================================================================
--- linux-2.6-lttng.orig/arch/x86_64/Kconfig 2007-05-17 02:12:24.000000000 -0400
+++ linux-2.6-lttng/arch/x86_64/Kconfig 2007-05-17 02:13:28.000000000 -0400
@@ -790,6 +790,9 @@
a probepoint and specifies the callback. Kprobes is useful
for kernel debugging, non-intrusive instrumentation and testing.
If in doubt, say "N".
+
+source "kernel/Kconfig.condcall"
+
endmenu
source "arch/x86_64/Kconfig.debug"
Index: linux-2.6-lttng/arch/xtensa/Kconfig
===================================================================
--- linux-2.6-lttng.orig/arch/xtensa/Kconfig 2007-05-17 02:12:24.000000000 -0400
+++ linux-2.6-lttng/arch/xtensa/Kconfig 2007-05-17 02:13:28.000000000 -0400
@@ -251,6 +251,12 @@
provide one yourself.
endmenu
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.condcall"
+
+endmenu
+
source "arch/xtensa/Kconfig.debug"
source "security/Kconfig"
Index: linux-2.6-lttng/kernel/Kconfig.condcall
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6-lttng/kernel/Kconfig.condcall 2007-05-17 02:12:41.000000000 -0400
@@ -0,0 +1,20 @@
+# Code markers configuration
+
+config COND_CALL
+ bool "Activate conditional calls"
+ depends on MODULES
+ help
+ Provides a way to dynamically enable kernel features while having a
+ very small footprint when disabled.
+
+config COND_CALL_DISABLE_OPTIMIZATION
+ bool "Disable conditional calls optimization"
+ depends on COND_CALL && EMBEDDED
+ default n
+ help
+ Disable code replacement jump optimisations. Especially useful if your
+ code is in a read-only rom/flash.
+
+config COND_CALL_ENABLE_OPTIMIZATION
+ def_bool y
+ depends on COND_CALL && !COND_CALL_DISABLE_OPTIMIZATION
Index: linux-2.6-lttng/arch/avr32/Kconfig.debug
===================================================================
--- linux-2.6-lttng.orig/arch/avr32/Kconfig.debug 2007-05-17 02:12:24.000000000 -0400
+++ linux-2.6-lttng/arch/avr32/Kconfig.debug 2007-05-17 02:13:28.000000000 -0400
@@ -6,6 +6,9 @@
source "lib/Kconfig.debug"
+menu "Instrumentation Support"
+ depends on EXPERIMENTAL
+
config KPROBES
bool "Kprobes"
depends on DEBUG_KERNEL
@@ -17,4 +20,8 @@
for kernel debugging, non-intrusive instrumentation and testing.
If in doubt, say "N".
+source "kernel/Kconfig.condcall"
+
+endmenu
+
endmenu
--
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
^ permalink raw reply [flat|nested] 19+ messages in thread
* [patch 5/9] Conditional Calls - i386 Optimization
2007-05-29 18:33 [patch 0/9] Conditional Calls Mathieu Desnoyers
` (3 preceding siblings ...)
2007-05-29 18:34 ` [patch 4/9] Conditional Calls - Add kconfig menus Mathieu Desnoyers
@ 2007-05-29 18:34 ` Mathieu Desnoyers
2007-05-29 18:34 ` [patch 6/9] Conditional Calls - PowerPC Optimization Mathieu Desnoyers
` (4 subsequent siblings)
9 siblings, 0 replies; 19+ messages in thread
From: Mathieu Desnoyers @ 2007-05-29 18:34 UTC (permalink / raw)
To: akpm, linux-kernel; +Cc: Mathieu Desnoyers
[-- Attachment #1: conditional-calls-i386-optimization.patch --]
[-- Type: text/plain, Size: 9294 bytes --]
i386 optimization of the cond_calls which uses a movb with code patching to
set/unset the value used to populate the register used for the branch test.
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
---
arch/i386/kernel/Makefile | 1
arch/i386/kernel/condcall.c | 140 ++++++++++++++++++++++++++++++++++++++++++++
include/asm-i386/condcall.h | 69 +++++++++++++++++++++
3 files changed, 209 insertions(+), 1 deletion(-)
Index: linux-2.6-lttng/include/asm-i386/condcall.h
===================================================================
--- linux-2.6-lttng.orig/include/asm-i386/condcall.h 2007-05-17 01:49:46.000000000 -0400
+++ linux-2.6-lttng/include/asm-i386/condcall.h 2007-05-17 01:52:38.000000000 -0400
@@ -1 +1,68 @@
-#include <asm-generic/condcall.h>
+#ifndef _ASM_I386_CONDCALL_H
+#define _ASM_I386_CONDCALL_H
+
+/*
+ * Conditional function calls. i386 architecture optimizations.
+ *
+ * (C) Copyright 2006 Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+
+#ifdef CONFIG_COND_CALL
+
+#define CF_DEFAULT (CF_OPTIMIZED | CF_LOCKDEP | CF_PRINTK)
+
+/* Optimized version of the cond_call. Passing the flags as a pointer to
+ * the inline assembly to trick it into putting the flags value as third
+ * parameter in the structure. */
+#define cond_call_optimized(flags, name, func) \
+ ({ \
+ static const char __cstrtab_name_##name[] \
+ __attribute__((section("__cond_call_strings"))) = #name; \
+ char condition; \
+ asm ( ".section __cond_call, \"a\", @progbits;\n\t" \
+ ".long %1, 0f, %2;\n\t" \
+ ".previous;\n\t" \
+ ".align 2\n\t" \
+ "0:\n\t" \
+ "movb %3,%0;\n\t" \
+ : "=r" (condition) \
+ : "m" (*__cstrtab_name_##name), \
+ "m" (*(char*)flags), \
+ "i" ((flags) & CF_STATIC_ENABLE)); \
+ (likely(!condition)) ? \
+ (__typeof__(func))0 : \
+ (func); \
+ })
+
+/* cond_call macro selecting the generic or optimized version of cond_call,
+ * depending on the flags specified. */
+#define _cond_call(flags, name, func) \
+({ \
+ (((flags) & CF_LOCKDEP) && ((flags) & CF_OPTIMIZED)) ? \
+ cond_call_optimized(flags, name, func) : \
+ cond_call_generic(flags, name, func); \
+})
+
+/* cond_call with default behavior */
+#define cond_call(name, func) _cond_call(CF_DEFAULT, name, func)
+
+/* Architecture dependant cond_call information, used internally for cond_call
+ * activation. */
+
+/* Offset of the immediate value from the start of the movb instruction, in
+ * bytes. */
+#define COND_CALL_OPTIMIZED_ENABLE_IMMEDIATE_OFFSET 1
+#define COND_CALL_OPTIMIZED_ENABLE_TYPE unsigned char
+/* Dereference enable as lvalue from a pointer to its instruction */
+#define COND_CALL_OPTIMIZED_ENABLE(a) \
+ *(COND_CALL_OPTIMIZED_ENABLE_TYPE*) \
+ ((char*)a+COND_CALL_OPTIMIZED_ENABLE_IMMEDIATE_OFFSET)
+
+extern int cond_call_optimized_set_enable(void *address, char enable);
+
+#endif
+#endif //_ASM_I386_CONDCALL_H
Index: linux-2.6-lttng/arch/i386/kernel/Makefile
===================================================================
--- linux-2.6-lttng.orig/arch/i386/kernel/Makefile 2007-05-17 01:42:46.000000000 -0400
+++ linux-2.6-lttng/arch/i386/kernel/Makefile 2007-05-17 01:52:38.000000000 -0400
@@ -33,6 +33,7 @@
obj-y += sysenter.o vsyscall.o
obj-$(CONFIG_ACPI_SRAT) += srat.o
obj-$(CONFIG_EFI) += efi.o efi_stub.o
+obj-$(CONFIG_COND_CALL_ENABLE_OPTIMIZATION) += condcall.o
obj-$(CONFIG_DOUBLEFAULT) += doublefault.o
obj-$(CONFIG_SERIAL_8250) += legacy_serial.o
obj-$(CONFIG_VM86) += vm86.o
Index: linux-2.6-lttng/arch/i386/kernel/condcall.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6-lttng/arch/i386/kernel/condcall.c 2007-05-17 01:52:38.000000000 -0400
@@ -0,0 +1,140 @@
+/* condcall.c
+ *
+ * - Erratum 49 fix for Intel PIII.
+ * - Still present on newer processors : Intel Core 2 Duo Processor for Intel
+ * Centrino Duo Processor Technology Specification Update, AH33.
+ * Unsynchronized Cross-Modifying Code Operations Can Cause Unexpected
+ * Instruction Execution Results.
+ *
+ * Permits cond_call activation by XMC with correct serialization.
+ *
+ * Reentrant for NMI and trap handler instrumentation. Permits XMC to a
+ * location that has preemption enabled because it involves no temporary or
+ * reused data structure.
+ *
+ * Quoting Richard J Moore, source of the information motivating this
+ * implementation which differs from the one proposed by Intel which is not
+ * suitable for kernel context (does not support NMI and would require disabling
+ * interrupts on every CPU for a long period) :
+ *
+ * "There is another issue to consider when looking into using probes other
+ * then int3:
+ *
+ * Intel erratum 54 - Unsynchronized Cross-modifying code - refers to the
+ * practice of modifying code on one processor where another has prefetched
+ * the unmodified version of the code. Intel states that unpredictable general
+ * protection faults may result if a synchronizing instruction (iret, int,
+ * int3, cpuid, etc ) is not executed on the second processor before it
+ * executes the pre-fetched out-of-date copy of the instruction.
+ *
+ * When we became aware of this I had a long discussion with Intel's
+ * microarchitecture guys. It turns out that the reason for this erratum
+ * (which incidentally Intel does not intend to fix) is because the trace
+ * cache - the stream of micorops resulting from instruction interpretation -
+ * cannot guaranteed to be valid. Reading between the lines I assume this
+ * issue arises because of optimization done in the trace cache, where it is
+ * no longer possible to identify the original instruction boundaries. If the
+ * CPU discoverers that the trace cache has been invalidated because of
+ * unsynchronized cross-modification then instruction execution will be
+ * aborted with a GPF. Further discussion with Intel revealed that replacing
+ * the first opcode byte with an int3 would not be subject to this erratum.
+ *
+ * So, is cmpxchg reliable? One has to guarantee more than mere atomicity."
+ *
+ * Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ */
+
+#include <linux/notifier.h>
+#include <linux/mutex.h>
+#include <linux/preempt.h>
+#include <linux/smp.h>
+#include <linux/notifier.h>
+#include <linux/module.h>
+#include <linux/condcall.h>
+#include <linux/kdebug.h>
+
+#include <asm/cacheflush.h>
+
+#define BREAKPOINT_INSTRUCTION 0xcc
+#define BREAKPOINT_INS_LEN 1
+
+static DEFINE_MUTEX(cond_call_mutex);
+static long target_eip = 0;
+
+static void cond_call_synchronize_core(void *info)
+{
+ sync_core(); /* use cpuid to stop speculative execution */
+}
+
+/* The eip value points right after the breakpoint instruction, in the second
+ * byte of the movb. Incrementing it of 1 byte makes the code resume right after
+ * the movb instruction, effectively skipping this instruction.
+ *
+ * We simply skip the 2 bytes load immediate here, leaving the register in an
+ * undefined state. We don't care about the content (0 or !0), because we are
+ * changing the value 0->1 or 1->0. This small window of undefined value
+ * doesn't matter.
+ */
+static int cond_call_notifier(struct notifier_block *nb,
+ unsigned long val, void *data)
+{
+ enum die_val die_val = (enum die_val) val;
+ struct die_args *args = (struct die_args *)data;
+
+ if (!args->regs || user_mode_vm(args->regs))
+ return NOTIFY_DONE;
+
+ if (die_val == DIE_INT3 && args->regs->eip == target_eip) {
+ args->regs->eip += 1; /* Skip the next byte of load immediate */
+ return NOTIFY_STOP;
+ }
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block cond_call_notify = {
+ .notifier_call = cond_call_notifier,
+ .priority = 0x7fffffff, /* we need to be notified first */
+};
+
+int cond_call_optimized_set_enable(void *address, char enable)
+{
+ char saved_byte;
+ int ret;
+ char *dest = address;
+
+ mutex_lock(&cond_call_mutex);
+
+ if (!(enable ^ dest[1])) /* Must be a state change 0<->1 to execute */
+ goto end;
+
+ target_eip = (long)address + BREAKPOINT_INS_LEN;
+ /* register_die_notifier has memory barriers */
+ register_die_notifier(&cond_call_notify);
+ saved_byte = *dest;
+ *dest = BREAKPOINT_INSTRUCTION;
+ wmb();
+ /* Execute serializing instruction on each CPU.
+ * Acts as a memory barrier. */
+ ret = on_each_cpu(cond_call_synchronize_core, NULL, 1, 1);
+ BUG_ON(ret != 0);
+
+ dest[1] = enable;
+ wmb();
+ *dest = saved_byte;
+ /* Wait for all int3 handlers to end
+ (interrupts are disabled in int3).
+ This CPU is clearly not in a int3 handler,
+ because int3 handler is not preemptible and
+ there cannot be any more int3 handler called
+ for this site, because we placed the original
+ instruction back.
+ synchronize_sched has memory barriers */
+ synchronize_sched();
+ unregister_die_notifier(&cond_call_notify);
+ /* unregister_die_notifier has memory barriers */
+ target_eip = 0;
+end:
+ mutex_unlock(&cond_call_mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cond_call_optimized_set_enable);
--
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
^ permalink raw reply [flat|nested] 19+ messages in thread
* [patch 6/9] Conditional Calls - PowerPC Optimization
2007-05-29 18:33 [patch 0/9] Conditional Calls Mathieu Desnoyers
` (4 preceding siblings ...)
2007-05-29 18:34 ` [patch 5/9] Conditional Calls - i386 Optimization Mathieu Desnoyers
@ 2007-05-29 18:34 ` Mathieu Desnoyers
2007-05-29 18:34 ` [patch 7/9] Conditional Calls - Documentation Mathieu Desnoyers
` (3 subsequent siblings)
9 siblings, 0 replies; 19+ messages in thread
From: Mathieu Desnoyers @ 2007-05-29 18:34 UTC (permalink / raw)
To: akpm, linux-kernel; +Cc: Mathieu Desnoyers
[-- Attachment #1: conditional-calls-powerpc-optimization.patch --]
[-- Type: text/plain, Size: 2965 bytes --]
PowerPC optimization of the cond_calls which uses a li instruction, patched with
an immediate value 0 or 1 to enable/disable the cond_call.
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
---
include/asm-powerpc/condcall.h | 68 ++++++++++++++++++++++++++++++++++++++++-
1 file changed, 67 insertions(+), 1 deletion(-)
Index: linux-2.6-lttng/include/asm-powerpc/condcall.h
===================================================================
--- linux-2.6-lttng.orig/include/asm-powerpc/condcall.h 2007-05-29 11:55:58.000000000 -0400
+++ linux-2.6-lttng/include/asm-powerpc/condcall.h 2007-05-29 11:56:43.000000000 -0400
@@ -1 +1,67 @@
-#include <asm-generic/condcall.h>
+#ifndef _ASM_POWERPC_CONDCALL_H
+#define _ASM_POWERPC_CONDCALL_H
+
+/*
+ * Conditional function calls. PowerPC architecture optimizations.
+ *
+ * (C) Copyright 2006 Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm/asm-compat.h>
+
+#ifdef CONFIG_COND_CALL
+
+#define CF_DEFAULT (CF_OPTIMIZED | CF_LOCKDEP | CF_PRINTK)
+
+/* Optimized version of the cond_call */
+#define cond_call_optimized(flags, name, func) \
+ ({ \
+ static const char __cstrtab_name_##name[] \
+ __attribute__((section("__cond_call_strings"))) = #name; \
+ char condition; \
+ asm ( ".section __cond_call, \"a\", @progbits;\n\t" \
+ PPC_LONG "%1, 0f, %2;\n\t" \
+ ".previous;\n\t" \
+ ".align 4\n\t" \
+ "0:\n\t" \
+ "li %0,%3;\n\t" \
+ : "=r" (condition) \
+ : "i" (__cstrtab_name_##name), \
+ "i" (flags), \
+ "i" ((flags) & CF_STATIC_ENABLE)); \
+ (unlikely(condition)) ? \
+ (func) : \
+ (__typeof__(func))0; \
+ })
+
+/* cond_call macro selecting the generic or optimized version of cond_call,
+ * depending on the flags specified. */
+#define _cond_call(flags, name, func) \
+({ \
+ ((flags) & CF_OPTIMIZED) ? \
+ cond_call_optimized(flags, name, func) : \
+ cond_call_generic(flags, name, func); \
+})
+
+/* cond_call with default behavior */
+#define cond_call(name, func) _cond_call(CF_DEFAULT, name, func)
+
+/* Architecture dependant cond_call information, used internally for cond_call
+ * activation. */
+
+/* Offset of the immediate value from the start of the addi instruction (result
+ * of the li mnemonic), in bytes. */
+#define COND_CALL_OPTIMIZED_ENABLE_IMMEDIATE_OFFSET 2
+#define COND_CALL_OPTIMIZED_ENABLE_TYPE unsigned short
+/* Dereference enable as lvalue from a pointer to its instruction */
+#define COND_CALL_OPTIMIZED_ENABLE(a) \
+ *(COND_CALL_OPTIMIZED_ENABLE_TYPE*) \
+ ((char*)a+COND_CALL_OPTIMIZED_ENABLE_IMMEDIATE_OFFSET)
+
+extern int cond_call_optimized_set_enable(void *address, char enable);
+
+#endif
+#endif //_ASM_POWERPC_CONDCALL_H
--
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
^ permalink raw reply [flat|nested] 19+ messages in thread
* [patch 7/9] Conditional Calls - Documentation
2007-05-29 18:33 [patch 0/9] Conditional Calls Mathieu Desnoyers
` (5 preceding siblings ...)
2007-05-29 18:34 ` [patch 6/9] Conditional Calls - PowerPC Optimization Mathieu Desnoyers
@ 2007-05-29 18:34 ` Mathieu Desnoyers
2007-05-29 18:34 ` [patch 8/9] F00F bug fixup for i386 - use conditional calls Mathieu Desnoyers
` (2 subsequent siblings)
9 siblings, 0 replies; 19+ messages in thread
From: Mathieu Desnoyers @ 2007-05-29 18:34 UTC (permalink / raw)
To: akpm, linux-kernel; +Cc: Mathieu Desnoyers
[-- Attachment #1: conditional-calls-documentation.patch --]
[-- Type: text/plain, Size: 2816 bytes --]
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
---
Documentation/condcall.txt | 60 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 60 insertions(+)
Index: linux-2.6-lttng/Documentation/condcall.txt
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6-lttng/Documentation/condcall.txt 2007-05-17 01:55:05.000000000 -0400
@@ -0,0 +1,60 @@
+ Using the Conditional Calls
+
+ Mathieu Desnoyers
+
+
+This document introduces Conditional Calls and their use.
+
+* Purpose of conditional calls
+
+A conditional call is used to compile into the kernel a function call that is
+disabled at compile-time. Then, at runtime, it can be enabled dynamically. As
+explained below, the opposite can also be done.
+
+
+* Usage
+
+In order to use the macro cond_call, you should include linux/condcall.h.
+
+#include <linux/condcall.h>
+
+Add, in your code :
+
+ret = cond_call(examplecondcall, myfunc(a, b));
+
+Where :
+- examplecondcall is the conditional call identifier
+- myfunc(a, b) is a call to myfunc with valid parameters.
+- "ret" is, optionally, the variable in which the return value of myfunc() must
+ be put. If the conditional call is disabled, ret will be set to 0 casted to
+ the type of the return value of myfunc().
+
+Use cond_call_arm("examplecondcall") to activate the conditional call.
+
+Use cond_call_disarm("examplecondcall") to deactivate the conditional call.
+
+Use cond_call_query("examplecondcall") to query the conditional call state.
+
+The cond_call mechanism supports inserting multiple instances of the same
+cond_call. Conditional calls can be put in inline functions, inlined static
+functions, and unrolled loops.
+
+
+* Optimization for a given architecture
+
+One can implement optimized conditional calls for a given architecture by
+replacing asm-$ARCH/condcall.h.
+
+The CF_* flags can be used to control the type of conditional call. See the
+include/linux/condcall.h header for the list of flags. They can be specified as
+the first parameter of the _cond_call() macro, as in the following example,
+which declares a cond_call enabled statically (which can be disabled/reenabled
+dynamically)
+
+ret = _cond_call(CF_DEFAULT | CF_STATIC_ENABLE, examplecondcall, myfunc(a, b));
+
+Another example of flag usage is to declare a cond_call that always uses the
+generic version of the cond_calls. It can be useful to use this when cond_calls
+are placed in kernel code presenting particular reentrancy challenges.
+
+ret = _cond_call(CF_DEFAULT & ~CF_OPTIMIZED, examplecondcall, myfunc(a, b));
--
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
^ permalink raw reply [flat|nested] 19+ messages in thread
* [patch 8/9] F00F bug fixup for i386 - use conditional calls
2007-05-29 18:33 [patch 0/9] Conditional Calls Mathieu Desnoyers
` (6 preceding siblings ...)
2007-05-29 18:34 ` [patch 7/9] Conditional Calls - Documentation Mathieu Desnoyers
@ 2007-05-29 18:34 ` Mathieu Desnoyers
2007-05-29 18:34 ` [patch 9/9] Scheduler profiling - Use " Mathieu Desnoyers
2007-05-30 12:15 ` [patch 0/9] Conditional Calls Mathieu Desnoyers
9 siblings, 0 replies; 19+ messages in thread
From: Mathieu Desnoyers @ 2007-05-29 18:34 UTC (permalink / raw)
To: akpm, linux-kernel; +Cc: Mathieu Desnoyers
[-- Attachment #1: f00f-bug-use-cond-calls.patch --]
[-- Type: text/plain, Size: 2891 bytes --]
Use the faster conditional calls for F00F bug handling in do_page_fault.
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
---
arch/i386/Kconfig.cpu | 1 +
arch/i386/kernel/traps.c | 2 ++
arch/i386/mm/fault.c | 35 ++++++++++++++++++++++-------------
3 files changed, 25 insertions(+), 13 deletions(-)
Index: linux-2.6-lttng/arch/i386/kernel/traps.c
===================================================================
--- linux-2.6-lttng.orig/arch/i386/kernel/traps.c 2007-05-29 11:05:30.000000000 -0400
+++ linux-2.6-lttng/arch/i386/kernel/traps.c 2007-05-29 11:07:07.000000000 -0400
@@ -31,6 +31,7 @@
#include <linux/uaccess.h>
#include <linux/nmi.h>
#include <linux/bug.h>
+#include <linux/condcall.h>
#ifdef CONFIG_EISA
#include <linux/ioport.h>
@@ -1084,6 +1085,7 @@
*/
idt_descr.address = fix_to_virt(FIX_F00F_IDT);
load_idt(&idt_descr);
+ BUG_ON(cond_call_arm("fix_f00f"));
}
#endif
Index: linux-2.6-lttng/arch/i386/mm/fault.c
===================================================================
--- linux-2.6-lttng.orig/arch/i386/mm/fault.c 2007-05-29 11:05:48.000000000 -0400
+++ linux-2.6-lttng/arch/i386/mm/fault.c 2007-05-29 11:13:16.000000000 -0400
@@ -25,6 +25,7 @@
#include <linux/kprobes.h>
#include <linux/uaccess.h>
#include <linux/kdebug.h>
+#include <linux/condcall.h>
#include <asm/system.h>
#include <asm/desc.h>
@@ -221,6 +222,25 @@
fastcall void do_invalid_op(struct pt_regs *, unsigned long);
+#ifdef CONFIG_X86_F00F_BUG
+/*
+ * Pentium F0 0F C7 C8 bug workaround.
+ */
+static inline int do_f00f_workaround(struct pt_regs *regs,
+ unsigned long address)
+{
+ unsigned long nr;
+
+ nr = (address - idt_descr.address) >> 3;
+
+ if (nr == 6) {
+ do_invalid_op(regs, 0);
+ return 1;
+ }
+ return 0;
+}
+#endif
+
static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address)
{
unsigned index = pgd_index(address);
@@ -474,19 +494,8 @@
}
#ifdef CONFIG_X86_F00F_BUG
- /*
- * Pentium F0 0F C7 C8 bug workaround.
- */
- if (boot_cpu_data.f00f_bug) {
- unsigned long nr;
-
- nr = (address - idt_descr.address) >> 3;
-
- if (nr == 6) {
- do_invalid_op(regs, 0);
- return;
- }
- }
+ if (cond_call(fix_f00f, do_f00f_workaround(regs, address)))
+ return;
#endif
no_context:
Index: linux-2.6-lttng/arch/i386/Kconfig.cpu
===================================================================
--- linux-2.6-lttng.orig/arch/i386/Kconfig.cpu 2007-05-29 11:51:46.000000000 -0400
+++ linux-2.6-lttng/arch/i386/Kconfig.cpu 2007-05-29 11:52:08.000000000 -0400
@@ -275,6 +275,7 @@
config X86_F00F_BUG
bool
depends on M586MMX || M586TSC || M586 || M486 || M386
+ select COND_CALL
default y
config X86_WP_WORKS_OK
--
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
^ permalink raw reply [flat|nested] 19+ messages in thread
* [patch 9/9] Scheduler profiling - Use conditional calls
2007-05-29 18:33 [patch 0/9] Conditional Calls Mathieu Desnoyers
` (7 preceding siblings ...)
2007-05-29 18:34 ` [patch 8/9] F00F bug fixup for i386 - use conditional calls Mathieu Desnoyers
@ 2007-05-29 18:34 ` Mathieu Desnoyers
2007-05-30 12:15 ` [patch 0/9] Conditional Calls Mathieu Desnoyers
9 siblings, 0 replies; 19+ messages in thread
From: Mathieu Desnoyers @ 2007-05-29 18:34 UTC (permalink / raw)
To: akpm, linux-kernel; +Cc: Mathieu Desnoyers
[-- Attachment #1: profiling-use-cond-calls.patch --]
[-- Type: text/plain, Size: 3195 bytes --]
Use conditional calls with lower d-cache hit in optimized version as a
condition for scheduler profiling call.
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
---
kernel/profile.c | 4 ++++
kernel/sched.c | 32 +++++++++++++++++++-------------
2 files changed, 23 insertions(+), 13 deletions(-)
Index: linux-2.6-lttng/kernel/profile.c
===================================================================
--- linux-2.6-lttng.orig/kernel/profile.c 2007-05-29 11:33:11.000000000 -0400
+++ linux-2.6-lttng/kernel/profile.c 2007-05-29 11:37:46.000000000 -0400
@@ -23,6 +23,7 @@
#include <linux/profile.h>
#include <linux/highmem.h>
#include <linux/mutex.h>
+#include <linux/condcall.h>
#include <asm/sections.h>
#include <asm/semaphore.h>
#include <asm/irq_regs.h>
@@ -91,6 +92,8 @@
printk(KERN_INFO "kernel profiling enabled (shift: %ld)\n",
prof_shift);
}
+ if (prof_on)
+ BUG_ON(cond_call_arm("profile_on"));
return 1;
}
__setup("profile=", profile_setup);
@@ -555,6 +558,7 @@
return 0;
out_cleanup:
prof_on = 0;
+ cond_call_disarm("profile_on");
smp_mb();
on_each_cpu(profile_nop, NULL, 0, 1);
for_each_online_cpu(cpu) {
Index: linux-2.6-lttng/kernel/sched.c
===================================================================
--- linux-2.6-lttng.orig/kernel/sched.c 2007-05-29 11:38:06.000000000 -0400
+++ linux-2.6-lttng/kernel/sched.c 2007-05-29 11:42:36.000000000 -0400
@@ -54,6 +54,7 @@
#include <linux/kprobes.h>
#include <linux/delayacct.h>
#include <linux/reciprocal_div.h>
+#include <linux/condcall.h>
#include <asm/tlb.h>
#include <asm/unistd.h>
@@ -972,6 +973,21 @@
}
/*
+ * Sleep time is in units of nanosecs, so shift by 20 to get a
+ * milliseconds-range estimation of the amount of time that the task
+ * spent sleeping:
+ */
+static inline void activate_task_prof(struct task_struct *p,
+ unsigned long long now)
+{
+ if (unlikely(prof_on == SLEEP_PROFILING)) {
+ if (p->state == TASK_UNINTERRUPTIBLE)
+ profile_hits(SLEEP_PROFILING, (void *)get_wchan(p),
+ (now - p->timestamp) >> 20);
+ }
+}
+
+/*
* activate_task - move a task to the runqueue and do priority recalculation
*
* Update all the scheduling statistics stuff. (sleep average
@@ -993,18 +1009,7 @@
+ rq->most_recent_timestamp;
}
#endif
-
- /*
- * Sleep time is in units of nanosecs, so shift by 20 to get a
- * milliseconds-range estimation of the amount of time that the task
- * spent sleeping:
- */
- if (unlikely(prof_on == SLEEP_PROFILING)) {
- if (p->state == TASK_UNINTERRUPTIBLE)
- profile_hits(SLEEP_PROFILING, (void *)get_wchan(p),
- (now - p->timestamp) >> 20);
- }
-
+ cond_call(profile_on, activate_task_prof(p, now));
p->prio = recalc_task_prio(p, now);
/*
@@ -3534,7 +3539,8 @@
print_irqtrace_events(current);
dump_stack();
}
- profile_hit(SCHED_PROFILING, __builtin_return_address(0));
+ cond_call(profile_on,
+ profile_hit(SCHED_PROFILING, __builtin_return_address(0)));
need_resched:
preempt_disable();
--
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [patch 0/9] Conditional Calls
2007-05-29 18:33 [patch 0/9] Conditional Calls Mathieu Desnoyers
` (8 preceding siblings ...)
2007-05-29 18:34 ` [patch 9/9] Scheduler profiling - Use " Mathieu Desnoyers
@ 2007-05-30 12:15 ` Mathieu Desnoyers
9 siblings, 0 replies; 19+ messages in thread
From: Mathieu Desnoyers @ 2007-05-30 12:15 UTC (permalink / raw)
To: akpm, linux-kernel
It seems I was still working on 2.6.21-mm2. A new patch for 2.6.22-mm1
will be posted in a jiffy.
Mathieu
* Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca) wrote:
> Hi,
>
> Following Andi Kleen's advice, I splitted the jump-over-call into a speparate
> piece of infrastructure so it can be used more widely.
>
> It also use a hash table to permit cond_call enable/disable both when the
> cond_call is armed and when a module containing an armed cond_call is loaded.
>
> Please add at the end of the 2.6.22-mm1 series,
>
> conditional-calls-architecture-independent-code.patch
> conditional-calls-hash-table.patch
> conditional-calls-non-optimized-architectures.patch
> conditional-calls-kconfig-menus.patch
> conditional-calls-i386-optimization.patch
> conditional-calls-powerpc-optimization.patch
> conditional-calls-documentation.patch
> #
> f00f-bug-use-cond-calls.patch
> profiling-use-cond-calls.patch
>
> Mathieu
>
> --
> Mathieu Desnoyers
> Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
> OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
>
--
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
^ permalink raw reply [flat|nested] 19+ messages in thread
* [patch 8/9] F00F bug fixup for i386 - use conditional calls
2007-05-30 14:00 [patch 0/9] Conditional Calls - for 2.6.22-rc2-mm1 Mathieu Desnoyers
@ 2007-05-30 14:00 ` Mathieu Desnoyers
2007-05-30 20:33 ` Andrew Morton
0 siblings, 1 reply; 19+ messages in thread
From: Mathieu Desnoyers @ 2007-05-30 14:00 UTC (permalink / raw)
To: akpm, linux-kernel; +Cc: Mathieu Desnoyers
[-- Attachment #1: f00f-bug-use-cond-calls.patch --]
[-- Type: text/plain, Size: 2891 bytes --]
Use the faster conditional calls for F00F bug handling in do_page_fault.
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
---
arch/i386/Kconfig.cpu | 1 +
arch/i386/kernel/traps.c | 2 ++
arch/i386/mm/fault.c | 35 ++++++++++++++++++++++-------------
3 files changed, 25 insertions(+), 13 deletions(-)
Index: linux-2.6-lttng/arch/i386/kernel/traps.c
===================================================================
--- linux-2.6-lttng.orig/arch/i386/kernel/traps.c 2007-05-29 11:05:30.000000000 -0400
+++ linux-2.6-lttng/arch/i386/kernel/traps.c 2007-05-29 11:07:07.000000000 -0400
@@ -31,6 +31,7 @@
#include <linux/uaccess.h>
#include <linux/nmi.h>
#include <linux/bug.h>
+#include <linux/condcall.h>
#ifdef CONFIG_EISA
#include <linux/ioport.h>
@@ -1084,6 +1085,7 @@
*/
idt_descr.address = fix_to_virt(FIX_F00F_IDT);
load_idt(&idt_descr);
+ BUG_ON(cond_call_arm("fix_f00f"));
}
#endif
Index: linux-2.6-lttng/arch/i386/mm/fault.c
===================================================================
--- linux-2.6-lttng.orig/arch/i386/mm/fault.c 2007-05-29 11:05:48.000000000 -0400
+++ linux-2.6-lttng/arch/i386/mm/fault.c 2007-05-29 11:13:16.000000000 -0400
@@ -25,6 +25,7 @@
#include <linux/kprobes.h>
#include <linux/uaccess.h>
#include <linux/kdebug.h>
+#include <linux/condcall.h>
#include <asm/system.h>
#include <asm/desc.h>
@@ -221,6 +222,25 @@
fastcall void do_invalid_op(struct pt_regs *, unsigned long);
+#ifdef CONFIG_X86_F00F_BUG
+/*
+ * Pentium F0 0F C7 C8 bug workaround.
+ */
+static inline int do_f00f_workaround(struct pt_regs *regs,
+ unsigned long address)
+{
+ unsigned long nr;
+
+ nr = (address - idt_descr.address) >> 3;
+
+ if (nr == 6) {
+ do_invalid_op(regs, 0);
+ return 1;
+ }
+ return 0;
+}
+#endif
+
static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address)
{
unsigned index = pgd_index(address);
@@ -474,19 +494,8 @@
}
#ifdef CONFIG_X86_F00F_BUG
- /*
- * Pentium F0 0F C7 C8 bug workaround.
- */
- if (boot_cpu_data.f00f_bug) {
- unsigned long nr;
-
- nr = (address - idt_descr.address) >> 3;
-
- if (nr == 6) {
- do_invalid_op(regs, 0);
- return;
- }
- }
+ if (cond_call(fix_f00f, do_f00f_workaround(regs, address)))
+ return;
#endif
no_context:
Index: linux-2.6-lttng/arch/i386/Kconfig.cpu
===================================================================
--- linux-2.6-lttng.orig/arch/i386/Kconfig.cpu 2007-05-29 11:51:46.000000000 -0400
+++ linux-2.6-lttng/arch/i386/Kconfig.cpu 2007-05-29 11:52:08.000000000 -0400
@@ -275,6 +275,7 @@
config X86_F00F_BUG
bool
depends on M586MMX || M586TSC || M586 || M486 || M386
+ select COND_CALL
default y
config X86_WP_WORKS_OK
--
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [patch 8/9] F00F bug fixup for i386 - use conditional calls
2007-05-30 14:00 ` [patch 8/9] F00F bug fixup for i386 - use conditional calls Mathieu Desnoyers
@ 2007-05-30 20:33 ` Andrew Morton
2007-05-31 21:07 ` Mathieu Desnoyers
0 siblings, 1 reply; 19+ messages in thread
From: Andrew Morton @ 2007-05-30 20:33 UTC (permalink / raw)
To: Mathieu Desnoyers; +Cc: linux-kernel
On Wed, 30 May 2007 10:00:33 -0400
Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca> wrote:
> Use the faster conditional calls for F00F bug handling in do_page_fault.
>
I guess this means that CONDCALL will be enabled on pretty much all i386,
in which case making the whole feature Kconfigurable is starting to look
marginal.
Perhaps a better approach would have to made this change dependent upon
CONDCALL, rather than forcing it on.
> @@ -1084,6 +1085,7 @@
> */
> idt_descr.address = fix_to_virt(FIX_F00F_IDT);
> load_idt(&idt_descr);
> + BUG_ON(cond_call_arm("fix_f00f"));
It is generally poor C style to do
assert(something_which_has_side_effects())
because people can legitimately expect to do
#define assert() /*nothing*/
for production code.
The kernel doesn't actually do the right thing here when CONFIG_BUG=n,
sadly. But still, children might be watching, so the better and preferred
style is
if (cond_call_arm("fix_f00f"))
BUG();
> }
> #endif
>
> Index: linux-2.6-lttng/arch/i386/mm/fault.c
> ===================================================================
> --- linux-2.6-lttng.orig/arch/i386/mm/fault.c 2007-05-29 11:05:48.000000000 -0400
> +++ linux-2.6-lttng/arch/i386/mm/fault.c 2007-05-29 11:13:16.000000000 -0400
> @@ -25,6 +25,7 @@
> #include <linux/kprobes.h>
> #include <linux/uaccess.h>
> #include <linux/kdebug.h>
> +#include <linux/condcall.h>
>
> #include <asm/system.h>
> #include <asm/desc.h>
> @@ -221,6 +222,25 @@
>
> fastcall void do_invalid_op(struct pt_regs *, unsigned long);
>
> +#ifdef CONFIG_X86_F00F_BUG
> +/*
> + * Pentium F0 0F C7 C8 bug workaround.
> + */
> +static inline int do_f00f_workaround(struct pt_regs *regs,
> + unsigned long address)
> +{
> + unsigned long nr;
> +
> + nr = (address - idt_descr.address) >> 3;
> +
> + if (nr == 6) {
> + do_invalid_op(regs, 0);
> + return 1;
> + }
> + return 0;
> +}
> +#endif
> +
> static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address)
> {
> unsigned index = pgd_index(address);
> @@ -474,19 +494,8 @@
> }
>
> #ifdef CONFIG_X86_F00F_BUG
> - /*
> - * Pentium F0 0F C7 C8 bug workaround.
> - */
> - if (boot_cpu_data.f00f_bug) {
> - unsigned long nr;
> -
> - nr = (address - idt_descr.address) >> 3;
> -
> - if (nr == 6) {
> - do_invalid_op(regs, 0);
> - return;
> - }
> - }
> + if (cond_call(fix_f00f, do_f00f_workaround(regs, address)))
> + return;
We do a cond_call() to an inlined function? That's a bit weird, isn't it?
> #endif
>
> no_context:
> Index: linux-2.6-lttng/arch/i386/Kconfig.cpu
> ===================================================================
> --- linux-2.6-lttng.orig/arch/i386/Kconfig.cpu 2007-05-29 11:51:46.000000000 -0400
> +++ linux-2.6-lttng/arch/i386/Kconfig.cpu 2007-05-29 11:52:08.000000000 -0400
> @@ -275,6 +275,7 @@
> config X86_F00F_BUG
> bool
> depends on M586MMX || M586TSC || M586 || M486 || M386
> + select COND_CALL
That hurts.
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [patch 8/9] F00F bug fixup for i386 - use conditional calls
2007-05-30 20:33 ` Andrew Morton
@ 2007-05-31 21:07 ` Mathieu Desnoyers
2007-05-31 21:21 ` Andrew Morton
0 siblings, 1 reply; 19+ messages in thread
From: Mathieu Desnoyers @ 2007-05-31 21:07 UTC (permalink / raw)
To: Andrew Morton; +Cc: linux-kernel
* Andrew Morton (akpm@linux-foundation.org) wrote:
> > Use the faster conditional calls for F00F bug handling in do_page_fault.
> >
>
> I guess this means that CONDCALL will be enabled on pretty much all i386,
> in which case making the whole feature Kconfigurable is starting to look
> marginal.
>
> Perhaps a better approach would have to made this change dependent upon
> CONDCALL, rather than forcing it on.
>
Do you mean making X86_F00F_BUG depend on COND_CALL instead of selecting
it ?
> > + if (cond_call(fix_f00f, do_f00f_workaround(regs, address)))
> > + return;
>
> We do a cond_call() to an inlined function? That's a bit weird, isn't it?
>
Yes, but it works :) I will add this information to the documentation.
--
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [patch 8/9] F00F bug fixup for i386 - use conditional calls
2007-05-31 21:07 ` Mathieu Desnoyers
@ 2007-05-31 21:21 ` Andrew Morton
2007-05-31 21:38 ` Mathieu Desnoyers
0 siblings, 1 reply; 19+ messages in thread
From: Andrew Morton @ 2007-05-31 21:21 UTC (permalink / raw)
To: Mathieu Desnoyers; +Cc: linux-kernel
On Thu, 31 May 2007 17:07:55 -0400
Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca> wrote:
> * Andrew Morton (akpm@linux-foundation.org) wrote:
>
> > > Use the faster conditional calls for F00F bug handling in do_page_fault.
> > >
> >
> > I guess this means that CONDCALL will be enabled on pretty much all i386,
> > in which case making the whole feature Kconfigurable is starting to look
> > marginal.
> >
> > Perhaps a better approach would have to made this change dependent upon
> > CONDCALL, rather than forcing it on.
> >
>
> Do you mean making X86_F00F_BUG depend on COND_CALL instead of selecting
> it ?
yup
> > > + if (cond_call(fix_f00f, do_f00f_workaround(regs, address)))
> > > + return;
> >
> > We do a cond_call() to an inlined function? That's a bit weird, isn't it?
> >
>
> Yes, but it works :) I will add this information to the documentation.
But why does it work? Did the compiler generate an out-of-line copy
of the function? If so, we'll end up with multiple copies of the function if
there are other callers. If not, the `inline' was pointless.
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [patch 8/9] F00F bug fixup for i386 - use conditional calls
2007-05-31 21:21 ` Andrew Morton
@ 2007-05-31 21:38 ` Mathieu Desnoyers
0 siblings, 0 replies; 19+ messages in thread
From: Mathieu Desnoyers @ 2007-05-31 21:38 UTC (permalink / raw)
To: Andrew Morton; +Cc: linux-kernel
* Andrew Morton (akpm@linux-foundation.org) wrote:
> On Thu, 31 May 2007 17:07:55 -0400
> Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca> wrote:
>
> > * Andrew Morton (akpm@linux-foundation.org) wrote:
> >
> > > > Use the faster conditional calls for F00F bug handling in do_page_fault.
> > > >
> > >
> > > I guess this means that CONDCALL will be enabled on pretty much all i386,
> > > in which case making the whole feature Kconfigurable is starting to look
> > > marginal.
> > >
> > > Perhaps a better approach would have to made this change dependent upon
> > > CONDCALL, rather than forcing it on.
> > >
> >
> > Do you mean making X86_F00F_BUG depend on COND_CALL instead of selecting
> > it ?
>
> yup
>
> > > > + if (cond_call(fix_f00f, do_f00f_workaround(regs, address)))
> > > > + return;
> > >
> > > We do a cond_call() to an inlined function? That's a bit weird, isn't it?
> > >
> >
> > Yes, but it works :) I will add this information to the documentation.
>
> But why does it work? Did the compiler generate an out-of-line copy
> of the function? If so, we'll end up with multiple copies of the function if
> there are other callers. If not, the `inline' was pointless.
Yes, it's doing an out-of-line copy. Just like the compiler would have
done if we place a call to an inline function within a if() { } block.
--
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [patch 8/9] F00F bug fixup for i386 - use conditional calls
@ 2007-06-01 0:14 Mikael Pettersson
2007-06-01 0:43 ` Andrew Morton
0 siblings, 1 reply; 19+ messages in thread
From: Mikael Pettersson @ 2007-06-01 0:14 UTC (permalink / raw)
To: akpm, mathieu.desnoyers; +Cc: linux-kernel
Andrew Morton wrote:
> Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca> wrote:
>
> > * Andrew Morton (akpm@linux-foundation.org) wrote:
> >
> > > > Use the faster conditional calls for F00F bug handling in do_page_fault.
> > > >
> > >
> > > I guess this means that CONDCALL will be enabled on pretty much all i386,
> > > in which case making the whole feature Kconfigurable is starting to look
> > > marginal.
> > >
> > > Perhaps a better approach would have to made this change dependent upon
> > > CONDCALL, rather than forcing it on.
> > >
> >
> > Do you mean making X86_F00F_BUG depend on COND_CALL instead of selecting
> > it ?
>
> yup
X86_F00F_BUG needs to be enabled in all kernels capable of booting on
P5 class machines, whether or not some obscure CONFIG_COND_CALL thingy
is enabled or not. X86_F00F_BUG is not some optional optimisation, it's
an essential workaround for a serious hardware bug.
Therefore it seems select rather than depend is called for.
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [patch 8/9] F00F bug fixup for i386 - use conditional calls
2007-06-01 0:14 Mikael Pettersson
@ 2007-06-01 0:43 ` Andrew Morton
2007-06-01 1:13 ` Mathieu Desnoyers
0 siblings, 1 reply; 19+ messages in thread
From: Andrew Morton @ 2007-06-01 0:43 UTC (permalink / raw)
To: Mikael Pettersson; +Cc: mathieu.desnoyers, linux-kernel
On Fri, 1 Jun 2007 02:14:53 +0200 (MEST)
Mikael Pettersson <mikpe@it.uu.se> wrote:
> Andrew Morton wrote:
> > Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca> wrote:
> >
> > > * Andrew Morton (akpm@linux-foundation.org) wrote:
> > >
> > > > > Use the faster conditional calls for F00F bug handling in do_page_fault.
> > > > >
> > > >
> > > > I guess this means that CONDCALL will be enabled on pretty much all i386,
> > > > in which case making the whole feature Kconfigurable is starting to look
> > > > marginal.
> > > >
> > > > Perhaps a better approach would have to made this change dependent upon
> > > > CONDCALL, rather than forcing it on.
> > > >
> > >
> > > Do you mean making X86_F00F_BUG depend on COND_CALL instead of selecting
> > > it ?
> >
> > yup
>
> X86_F00F_BUG needs to be enabled in all kernels capable of booting on
> P5 class machines, whether or not some obscure CONFIG_COND_CALL thingy
> is enabled or not. X86_F00F_BUG is not some optional optimisation, it's
> an essential workaround for a serious hardware bug.
>
> Therefore it seems select rather than depend is called for.
Nope.
CONFIG_COND_CALL=n -> do f00f handling the present way
CONFIG_COND_CALL=y -> do f00f handling the new, fast-n-fancy way
Because I don't think everyone will want to drag all this cond_call stuff
into their kernel just for slightly faster f00f handling.
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [patch 8/9] F00F bug fixup for i386 - use conditional calls
2007-06-01 0:43 ` Andrew Morton
@ 2007-06-01 1:13 ` Mathieu Desnoyers
0 siblings, 0 replies; 19+ messages in thread
From: Mathieu Desnoyers @ 2007-06-01 1:13 UTC (permalink / raw)
To: Andrew Morton; +Cc: Mikael Pettersson, linux-kernel
* Andrew Morton (akpm@linux-foundation.org) wrote:
> On Fri, 1 Jun 2007 02:14:53 +0200 (MEST)
> Mikael Pettersson <mikpe@it.uu.se> wrote:
>
> > Andrew Morton wrote:
> > > Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca> wrote:
> > >
> > > > * Andrew Morton (akpm@linux-foundation.org) wrote:
> > > >
> > > > > > Use the faster conditional calls for F00F bug handling in do_page_fault.
> > > > > >
> > > > >
> > > > > I guess this means that CONDCALL will be enabled on pretty much all i386,
> > > > > in which case making the whole feature Kconfigurable is starting to look
> > > > > marginal.
> > > > >
> > > > > Perhaps a better approach would have to made this change dependent upon
> > > > > CONDCALL, rather than forcing it on.
> > > > >
> > > >
> > > > Do you mean making X86_F00F_BUG depend on COND_CALL instead of selecting
> > > > it ?
> > >
> > > yup
> >
> > X86_F00F_BUG needs to be enabled in all kernels capable of booting on
> > P5 class machines, whether or not some obscure CONFIG_COND_CALL thingy
> > is enabled or not. X86_F00F_BUG is not some optional optimisation, it's
> > an essential workaround for a serious hardware bug.
> >
> > Therefore it seems select rather than depend is called for.
>
> Nope.
>
> CONFIG_COND_CALL=n -> do f00f handling the present way
> CONFIG_COND_CALL=y -> do f00f handling the new, fast-n-fancy way
>
>
> Because I don't think everyone will want to drag all this cond_call stuff
> into their kernel just for slightly faster f00f handling.
>
Then I should probably leave the redundant
if (boot_cpu_data.f00f_bug)
test in do_f00f_workaround so that configuration where cond_calls are
not enabled still behave the same way as before. The redundant test will
make the case when cond calls are present a little slower, but we still
have the improvement when the architecture does not need the workaround.
I could also wrap this test in a #ifndef CONFIG_COND_CALL, but it seems
ugly.
Also, since the default is not to set the CF_STATIC_ENABLE flag, the
workaround won't be compiled in the kernel if the conditional calls are
configured out.
The question that arises is : what should be the default behavior of a
cond_call when the cond_calls are configured out? Active, active only
if the CF_STATIC_ENABLE flags is set or inactive?
--
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2007-06-01 1:13 UTC | newest]
Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-05-29 18:33 [patch 0/9] Conditional Calls Mathieu Desnoyers
2007-05-29 18:33 ` [patch 1/9] Conditional Calls - Architecture Independent Code Mathieu Desnoyers
2007-05-29 18:33 ` [patch 2/9] Conditional Calls - Hash Table Mathieu Desnoyers
2007-05-29 18:33 ` [patch 3/9] Conditional Calls - Non Optimized Architectures Mathieu Desnoyers
2007-05-29 18:34 ` [patch 4/9] Conditional Calls - Add kconfig menus Mathieu Desnoyers
2007-05-29 18:34 ` [patch 5/9] Conditional Calls - i386 Optimization Mathieu Desnoyers
2007-05-29 18:34 ` [patch 6/9] Conditional Calls - PowerPC Optimization Mathieu Desnoyers
2007-05-29 18:34 ` [patch 7/9] Conditional Calls - Documentation Mathieu Desnoyers
2007-05-29 18:34 ` [patch 8/9] F00F bug fixup for i386 - use conditional calls Mathieu Desnoyers
2007-05-29 18:34 ` [patch 9/9] Scheduler profiling - Use " Mathieu Desnoyers
2007-05-30 12:15 ` [patch 0/9] Conditional Calls Mathieu Desnoyers
-- strict thread matches above, loose matches on Subject: below --
2007-05-30 14:00 [patch 0/9] Conditional Calls - for 2.6.22-rc2-mm1 Mathieu Desnoyers
2007-05-30 14:00 ` [patch 8/9] F00F bug fixup for i386 - use conditional calls Mathieu Desnoyers
2007-05-30 20:33 ` Andrew Morton
2007-05-31 21:07 ` Mathieu Desnoyers
2007-05-31 21:21 ` Andrew Morton
2007-05-31 21:38 ` Mathieu Desnoyers
2007-06-01 0:14 Mikael Pettersson
2007-06-01 0:43 ` Andrew Morton
2007-06-01 1:13 ` Mathieu Desnoyers
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox