markers: simplify marker_set_format()

current marker_set_format() is complex this patch simplify it,
and decrease the overhead of marker_update_probes().

Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com>
Acked-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
Lai Jiangshan 2008-10-15 14:56:37 +08:00 committed by Ingo Molnar
parent f8d56f1771
commit 0eec481e8f
1 changed files with 25 additions and 46 deletions

View File

@ -64,6 +64,7 @@ struct marker_entry {
void *oldptr; void *oldptr;
int rcu_pending; int rcu_pending;
unsigned char ptype:1; unsigned char ptype:1;
unsigned char format_allocated:1;
char name[0]; /* Contains name'\0'format'\0' */ char name[0]; /* Contains name'\0'format'\0' */
}; };
@ -416,6 +417,7 @@ static struct marker_entry *add_marker(const char *name, const char *format)
e->single.probe_private = NULL; e->single.probe_private = NULL;
e->multi = NULL; e->multi = NULL;
e->ptype = 0; e->ptype = 0;
e->format_allocated = 0;
e->refcount = 0; e->refcount = 0;
e->rcu_pending = 0; e->rcu_pending = 0;
hlist_add_head(&e->hlist, head); hlist_add_head(&e->hlist, head);
@ -447,6 +449,8 @@ static int remove_marker(const char *name)
if (e->single.func != __mark_empty_function) if (e->single.func != __mark_empty_function)
return -EBUSY; return -EBUSY;
hlist_del(&e->hlist); hlist_del(&e->hlist);
if (e->format_allocated)
kfree(e->format);
/* Make sure the call_rcu has been executed */ /* Make sure the call_rcu has been executed */
if (e->rcu_pending) if (e->rcu_pending)
rcu_barrier_sched(); rcu_barrier_sched();
@ -457,57 +461,34 @@ static int remove_marker(const char *name)
/* /*
* Set the mark_entry format to the format found in the element. * 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)
{ {
struct marker_entry *e; entry->format = kstrdup(format, GFP_KERNEL);
size_t name_len = strlen((*entry)->name) + 1; if (!entry->format)
size_t format_len = strlen(format) + 1;
e = kmalloc(sizeof(struct marker_entry) + name_len + format_len,
GFP_KERNEL);
if (!e)
return -ENOMEM; return -ENOMEM;
memcpy(&e->name[0], (*entry)->name, name_len); entry->format_allocated = 1;
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", trace_mark(core_marker_format, "name %s format %s",
e->name, e->format); entry->name, entry->format);
return 0; return 0;
} }
/* /*
* Sets the probe callback corresponding to one marker. * 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 active)
{ {
int ret; int ret;
WARN_ON(strcmp((*entry)->name, elem->name) != 0); WARN_ON(strcmp(entry->name, elem->name) != 0);
if ((*entry)->format) { if (entry->format) {
if (strcmp((*entry)->format, elem->format) != 0) { if (strcmp(entry->format, elem->format) != 0) {
printk(KERN_NOTICE printk(KERN_NOTICE
"Format mismatch for probe %s " "Format mismatch for probe %s "
"(%s), marker (%s)\n", "(%s), marker (%s)\n",
(*entry)->name, entry->name,
(*entry)->format, entry->format,
elem->format); elem->format);
return -EPERM; return -EPERM;
} }
@ -523,34 +504,33 @@ static int set_marker(struct marker_entry **entry, struct marker *elem,
* pass from a "safe" callback (with argument) to an "unsafe" * pass from a "safe" callback (with argument) to an "unsafe"
* callback (does not set arguments). * callback (does not set arguments).
*/ */
elem->call = (*entry)->call; elem->call = entry->call;
/* /*
* Sanity check : * Sanity check :
* We only update the single probe private data when the ptr is * 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) * set to a _non_ single probe! (0 -> 1 and N -> 1, N != 1)
*/ */
WARN_ON(elem->single.func != __mark_empty_function WARN_ON(elem->single.func != __mark_empty_function
&& elem->single.probe_private && elem->single.probe_private != entry->single.probe_private
!= (*entry)->single.probe_private && && !elem->ptype);
!elem->ptype); elem->single.probe_private = entry->single.probe_private;
elem->single.probe_private = (*entry)->single.probe_private;
/* /*
* Make sure the private data is valid when we update the * Make sure the private data is valid when we update the
* single probe ptr. * single probe ptr.
*/ */
smp_wmb(); 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 * We also make sure that the new probe callbacks array is consistent
* before setting a pointer to it. * 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 * Update the function or multi probe array pointer before setting the
* ptype. * ptype.
*/ */
smp_wmb(); smp_wmb();
elem->ptype = (*entry)->ptype; elem->ptype = entry->ptype;
elem->state = active; elem->state = active;
return 0; return 0;
@ -594,8 +574,7 @@ void marker_update_probe_range(struct marker *begin,
for (iter = begin; iter < end; iter++) { for (iter = begin; iter < end; iter++) {
mark_entry = get_marker(iter->name); mark_entry = get_marker(iter->name);
if (mark_entry) { if (mark_entry) {
set_marker(&mark_entry, iter, set_marker(mark_entry, iter, !!mark_entry->refcount);
!!mark_entry->refcount);
/* /*
* ignore error, continue * ignore error, continue
*/ */
@ -657,7 +636,7 @@ int marker_probe_register(const char *name, const char *format,
ret = PTR_ERR(entry); ret = PTR_ERR(entry);
} else if (format) { } else if (format) {
if (!entry->format) if (!entry->format)
ret = marker_set_format(&entry, format); ret = marker_set_format(entry, format);
else if (strcmp(entry->format, format)) else if (strcmp(entry->format, format))
ret = -EPERM; ret = -EPERM;
} }