diff --git a/[refs] b/[refs] index 1b04e2ad580d..c81e2902fe41 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 5d9881ea1440f046ee851bbaa2a2962543336a11 +refs/heads/master: fd3fdf11d3c649769e02459c5f1b8081a15e9007 diff --git a/trunk/arch/x86/Kconfig.debug b/trunk/arch/x86/Kconfig.debug index 2a3dfbd5e677..fa013f529b74 100644 --- a/trunk/arch/x86/Kconfig.debug +++ b/trunk/arch/x86/Kconfig.debug @@ -186,14 +186,10 @@ config IOMMU_LEAK Add a simple leak tracer to the IOMMU code. This is useful when you are debugging a buggy device driver that leaks IOMMU mappings. -config MMIOTRACE_HOOKS - bool - config MMIOTRACE bool "Memory mapped IO tracing" depends on DEBUG_KERNEL && PCI select TRACING - select MMIOTRACE_HOOKS help Mmiotrace traces Memory Mapped I/O access and is meant for debugging and reverse engineering. It is called from the ioremap diff --git a/trunk/arch/x86/mm/Makefile b/trunk/arch/x86/mm/Makefile index 59f89b434b45..0a21b7aab9dc 100644 --- a/trunk/arch/x86/mm/Makefile +++ b/trunk/arch/x86/mm/Makefile @@ -8,9 +8,8 @@ obj-$(CONFIG_X86_PTDUMP) += dump_pagetables.o obj-$(CONFIG_HIGHMEM) += highmem_32.o -obj-$(CONFIG_MMIOTRACE_HOOKS) += kmmio.o obj-$(CONFIG_MMIOTRACE) += mmiotrace.o -mmiotrace-y := pf_in.o mmio-mod.o +mmiotrace-y := kmmio.o pf_in.o mmio-mod.o obj-$(CONFIG_MMIOTRACE_TEST) += testmmiotrace.o obj-$(CONFIG_NUMA) += numa_$(BITS).o diff --git a/trunk/arch/x86/mm/fault.c b/trunk/arch/x86/mm/fault.c index 31e8730fa246..4152d3c3b138 100644 --- a/trunk/arch/x86/mm/fault.c +++ b/trunk/arch/x86/mm/fault.c @@ -53,7 +53,7 @@ static inline int kmmio_fault(struct pt_regs *regs, unsigned long addr) { -#ifdef CONFIG_MMIOTRACE_HOOKS +#ifdef CONFIG_MMIOTRACE if (unlikely(is_kmmio_active())) if (kmmio_handler(regs, addr) == 1) return -1; diff --git a/trunk/include/linux/marker.h b/trunk/include/linux/marker.h index 4cf45472d9f5..889196c7fbb1 100644 --- a/trunk/include/linux/marker.h +++ b/trunk/include/linux/marker.h @@ -136,6 +136,8 @@ extern marker_probe_func __mark_empty_function; extern void marker_probe_cb(const struct marker *mdata, void *call_private, ...); +extern void marker_probe_cb_noarg(const struct marker *mdata, + void *call_private, ...); /* * Connect a probe to a marker. diff --git a/trunk/kernel/marker.c b/trunk/kernel/marker.c index 2898b647d415..e9c6b2bc9400 100644 --- a/trunk/kernel/marker.c +++ b/trunk/kernel/marker.c @@ -43,7 +43,6 @@ static DEFINE_MUTEX(markers_mutex); */ #define MARKER_HASH_BITS 6 #define MARKER_TABLE_SIZE (1 << MARKER_HASH_BITS) -static struct hlist_head marker_table[MARKER_TABLE_SIZE]; /* * Note about RCU : @@ -65,10 +64,11 @@ struct marker_entry { void *oldptr; int rcu_pending; unsigned char ptype:1; - unsigned char format_allocated:1; char name[0]; /* Contains name'\0'format'\0' */ }; +static struct hlist_head marker_table[MARKER_TABLE_SIZE]; + /** * __mark_empty_function - Empty probe callback * @probe_private: probe private data @@ -157,7 +157,7 @@ EXPORT_SYMBOL_GPL(marker_probe_cb); * * Should be connected to markers "MARK_NOARGS". */ -static void marker_probe_cb_noarg(const struct marker *mdata, void *call_private, ...) +void marker_probe_cb_noarg(const struct marker *mdata, void *call_private, ...) { va_list args; /* not initialized */ char ptype; @@ -197,6 +197,7 @@ static void marker_probe_cb_noarg(const struct marker *mdata, void *call_private } rcu_read_unlock_sched(); } +EXPORT_SYMBOL_GPL(marker_probe_cb_noarg); static void free_old_closure(struct rcu_head *head) { @@ -415,7 +416,6 @@ static struct marker_entry *add_marker(const char *name, const char *format) e->single.probe_private = NULL; e->multi = NULL; e->ptype = 0; - e->format_allocated = 0; e->refcount = 0; e->rcu_pending = 0; hlist_add_head(&e->hlist, head); @@ -447,8 +447,6 @@ static int remove_marker(const char *name) if (e->single.func != __mark_empty_function) return -EBUSY; hlist_del(&e->hlist); - if (e->format_allocated) - kfree(e->format); /* Make sure the call_rcu has been executed */ if (e->rcu_pending) rcu_barrier_sched(); @@ -459,34 +457,57 @@ static int remove_marker(const char *name) /* * Set the mark_entry format to the format found in the element. */ -static int marker_set_format(struct marker_entry *entry, const char *format) +static int marker_set_format(struct marker_entry **entry, const char *format) { - entry->format = kstrdup(format, GFP_KERNEL); - if (!entry->format) - return -ENOMEM; - entry->format_allocated = 1; + struct marker_entry *e; + size_t name_len = strlen((*entry)->name) + 1; + size_t format_len = strlen(format) + 1; + + e = kmalloc(sizeof(struct marker_entry) + name_len + format_len, + GFP_KERNEL); + if (!e) + return -ENOMEM; + memcpy(&e->name[0], (*entry)->name, name_len); + e->format = &e->name[name_len]; + memcpy(e->format, format, format_len); + if (strcmp(e->format, MARK_NOARGS) == 0) + e->call = marker_probe_cb_noarg; + else + e->call = marker_probe_cb; + e->single = (*entry)->single; + e->multi = (*entry)->multi; + e->ptype = (*entry)->ptype; + e->refcount = (*entry)->refcount; + e->rcu_pending = 0; + hlist_add_before(&e->hlist, &(*entry)->hlist); + hlist_del(&(*entry)->hlist); + /* Make sure the call_rcu has been executed */ + if ((*entry)->rcu_pending) + rcu_barrier_sched(); + kfree(*entry); + *entry = e; trace_mark(core_marker_format, "name %s format %s", - entry->name, entry->format); + e->name, e->format); return 0; } /* * Sets the probe callback corresponding to one marker. */ -static int set_marker(struct marker_entry *entry, struct marker *elem, +static int set_marker(struct marker_entry **entry, struct marker *elem, int active) { int ret; - WARN_ON(strcmp(entry->name, elem->name) != 0); + WARN_ON(strcmp((*entry)->name, elem->name) != 0); - if (entry->format) { - if (strcmp(entry->format, elem->format) != 0) { + if ((*entry)->format) { + if (strcmp((*entry)->format, elem->format) != 0) { printk(KERN_NOTICE "Format mismatch for probe %s " "(%s), marker (%s)\n", - entry->name, - entry->format, + (*entry)->name, + (*entry)->format, elem->format); return -EPERM; } @@ -502,33 +523,34 @@ static int set_marker(struct marker_entry *entry, struct marker *elem, * pass from a "safe" callback (with argument) to an "unsafe" * callback (does not set arguments). */ - elem->call = entry->call; + elem->call = (*entry)->call; /* * Sanity check : * We only update the single probe private data when the ptr is * set to a _non_ single probe! (0 -> 1 and N -> 1, N != 1) */ WARN_ON(elem->single.func != __mark_empty_function - && elem->single.probe_private != entry->single.probe_private - && !elem->ptype); - elem->single.probe_private = entry->single.probe_private; + && elem->single.probe_private + != (*entry)->single.probe_private && + !elem->ptype); + elem->single.probe_private = (*entry)->single.probe_private; /* * Make sure the private data is valid when we update the * single probe ptr. */ smp_wmb(); - elem->single.func = entry->single.func; + elem->single.func = (*entry)->single.func; /* * We also make sure that the new probe callbacks array is consistent * before setting a pointer to it. */ - rcu_assign_pointer(elem->multi, entry->multi); + rcu_assign_pointer(elem->multi, (*entry)->multi); /* * Update the function or multi probe array pointer before setting the * ptype. */ smp_wmb(); - elem->ptype = entry->ptype; + elem->ptype = (*entry)->ptype; elem->state = active; return 0; @@ -572,7 +594,8 @@ void marker_update_probe_range(struct marker *begin, for (iter = begin; iter < end; iter++) { mark_entry = get_marker(iter->name); if (mark_entry) { - set_marker(mark_entry, iter, !!mark_entry->refcount); + set_marker(&mark_entry, iter, + !!mark_entry->refcount); /* * ignore error, continue */ @@ -634,7 +657,7 @@ int marker_probe_register(const char *name, const char *format, ret = PTR_ERR(entry); } else if (format) { if (!entry->format) - ret = marker_set_format(entry, format); + ret = marker_set_format(&entry, format); else if (strcmp(entry->format, format)) ret = -EPERM; } @@ -825,6 +848,8 @@ void *marker_get_private_data(const char *name, marker_probe_func *probe, if (!e->ptype) { if (num == 0 && e->single.func == probe) return e->single.probe_private; + else + break; } else { struct marker_probe_closure *closure; int match = 0; @@ -836,7 +861,6 @@ void *marker_get_private_data(const char *name, marker_probe_func *probe, return closure[i].probe_private; } } - break; } } return ERR_PTR(-ENOENT);