aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/marker.c
diff options
context:
space:
mode:
authorMathieu Desnoyers <mathieu.desnoyers@polymtl.ca>2008-10-01 12:03:25 -0400
committerIngo Molnar <mingo@elte.hu>2008-10-14 04:38:38 -0400
commited86a59071a4ccd0e9bcefc61e013759a21eda78 (patch)
tree013abe0cb9e3cd4d7e6c2a9655f86517423a2623 /kernel/marker.c
parent5b9261d93e5fa3db4995d5b77b5ed365166e001c (diff)
markers: re-enable fast batch registration
Lai Jiangshan discovered a reentrancy issue with markers and fixed it by adding synchronize_sched() calls at each registration/unregistraiton. It works, but it removes the ability to do batch registration/unregistration and can cause registration of ~100 markers to take about 30 seconds on a loaded machine (synchronize_sched() is much slower on such workloads). This patch implements a version of the fix which won't slow down marker batch registration/unregistration. It also go back to the original non-synchronized reg/unreg. Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/marker.c')
-rw-r--r--kernel/marker.c58
1 files changed, 52 insertions, 6 deletions
diff --git a/kernel/marker.c b/kernel/marker.c
index fe5ca72f9659..05a25776f71f 100644
--- a/kernel/marker.c
+++ b/kernel/marker.c
@@ -60,6 +60,9 @@ struct marker_entry {
60 struct marker_probe_closure single; 60 struct marker_probe_closure single;
61 struct marker_probe_closure *multi; 61 struct marker_probe_closure *multi;
62 int refcount; /* Number of times armed. 0 if disarmed. */ 62 int refcount; /* Number of times armed. 0 if disarmed. */
63 struct rcu_head rcu;
64 void *oldptr;
65 unsigned char rcu_pending:1;
63 unsigned char ptype:1; 66 unsigned char ptype:1;
64 char name[0]; /* Contains name'\0'format'\0' */ 67 char name[0]; /* Contains name'\0'format'\0' */
65}; 68};
@@ -196,6 +199,16 @@ void marker_probe_cb_noarg(const struct marker *mdata, void *call_private, ...)
196} 199}
197EXPORT_SYMBOL_GPL(marker_probe_cb_noarg); 200EXPORT_SYMBOL_GPL(marker_probe_cb_noarg);
198 201
202static void free_old_closure(struct rcu_head *head)
203{
204 struct marker_entry *entry = container_of(head,
205 struct marker_entry, rcu);
206 kfree(entry->oldptr);
207 /* Make sure we free the data before setting the pending flag to 0 */
208 smp_wmb();
209 entry->rcu_pending = 0;
210}
211
199static void debug_print_probes(struct marker_entry *entry) 212static void debug_print_probes(struct marker_entry *entry)
200{ 213{
201 int i; 214 int i;
@@ -404,6 +417,7 @@ static struct marker_entry *add_marker(const char *name, const char *format)
404 e->multi = NULL; 417 e->multi = NULL;
405 e->ptype = 0; 418 e->ptype = 0;
406 e->refcount = 0; 419 e->refcount = 0;
420 e->rcu_pending = 0;
407 hlist_add_head(&e->hlist, head); 421 hlist_add_head(&e->hlist, head);
408 return e; 422 return e;
409} 423}
@@ -433,6 +447,9 @@ static int remove_marker(const char *name)
433 if (e->single.func != __mark_empty_function) 447 if (e->single.func != __mark_empty_function)
434 return -EBUSY; 448 return -EBUSY;
435 hlist_del(&e->hlist); 449 hlist_del(&e->hlist);
450 /* Make sure the call_rcu has been executed */
451 if (e->rcu_pending)
452 rcu_barrier_sched();
436 kfree(e); 453 kfree(e);
437 return 0; 454 return 0;
438} 455}
@@ -462,8 +479,12 @@ static int marker_set_format(struct marker_entry **entry, const char *format)
462 e->multi = (*entry)->multi; 479 e->multi = (*entry)->multi;
463 e->ptype = (*entry)->ptype; 480 e->ptype = (*entry)->ptype;
464 e->refcount = (*entry)->refcount; 481 e->refcount = (*entry)->refcount;
482 e->rcu_pending = 0;
465 hlist_add_before(&e->hlist, &(*entry)->hlist); 483 hlist_add_before(&e->hlist, &(*entry)->hlist);
466 hlist_del(&(*entry)->hlist); 484 hlist_del(&(*entry)->hlist);
485 /* Make sure the call_rcu has been executed */
486 if ((*entry)->rcu_pending)
487 rcu_barrier_sched();
467 kfree(*entry); 488 kfree(*entry);
468 *entry = e; 489 *entry = e;
469 trace_mark(core_marker_format, "name %s format %s", 490 trace_mark(core_marker_format, "name %s format %s",
@@ -637,6 +658,12 @@ int marker_probe_register(const char *name, const char *format,
637 goto end; 658 goto end;
638 } 659 }
639 } 660 }
661 /*
662 * If we detect that a call_rcu is pending for this marker,
663 * make sure it's executed now.
664 */
665 if (entry->rcu_pending)
666 rcu_barrier_sched();
640 old = marker_entry_add_probe(entry, probe, probe_private); 667 old = marker_entry_add_probe(entry, probe, probe_private);
641 if (IS_ERR(old)) { 668 if (IS_ERR(old)) {
642 ret = PTR_ERR(old); 669 ret = PTR_ERR(old);
@@ -644,11 +671,16 @@ int marker_probe_register(const char *name, const char *format,
644 } 671 }
645 mutex_unlock(&markers_mutex); 672 mutex_unlock(&markers_mutex);
646 marker_update_probes(); /* may update entry */ 673 marker_update_probes(); /* may update entry */
647 synchronize_sched();
648 kfree(old);
649 mutex_lock(&markers_mutex); 674 mutex_lock(&markers_mutex);
650 entry = get_marker(name); 675 entry = get_marker(name);
651 WARN_ON(!entry); 676 WARN_ON(!entry);
677 if (entry->rcu_pending)
678 rcu_barrier_sched();
679 entry->oldptr = old;
680 entry->rcu_pending = 1;
681 /* write rcu_pending before calling the RCU callback */
682 smp_wmb();
683 call_rcu_sched(&entry->rcu, free_old_closure);
652end: 684end:
653 mutex_unlock(&markers_mutex); 685 mutex_unlock(&markers_mutex);
654 return ret; 686 return ret;
@@ -678,15 +710,22 @@ int marker_probe_unregister(const char *name,
678 entry = get_marker(name); 710 entry = get_marker(name);
679 if (!entry) 711 if (!entry)
680 goto end; 712 goto end;
713 if (entry->rcu_pending)
714 rcu_barrier_sched();
681 old = marker_entry_remove_probe(entry, probe, probe_private); 715 old = marker_entry_remove_probe(entry, probe, probe_private);
682 mutex_unlock(&markers_mutex); 716 mutex_unlock(&markers_mutex);
683 marker_update_probes(); /* may update entry */ 717 marker_update_probes(); /* may update entry */
684 synchronize_sched();
685 kfree(old);
686 mutex_lock(&markers_mutex); 718 mutex_lock(&markers_mutex);
687 entry = get_marker(name); 719 entry = get_marker(name);
688 if (!entry) 720 if (!entry)
689 goto end; 721 goto end;
722 if (entry->rcu_pending)
723 rcu_barrier_sched();
724 entry->oldptr = old;
725 entry->rcu_pending = 1;
726 /* write rcu_pending before calling the RCU callback */
727 smp_wmb();
728 call_rcu_sched(&entry->rcu, free_old_closure);
690 remove_marker(name); /* Ignore busy error message */ 729 remove_marker(name); /* Ignore busy error message */
691 ret = 0; 730 ret = 0;
692end: 731end:
@@ -752,14 +791,21 @@ int marker_probe_unregister_private_data(marker_probe_func *probe,
752 ret = -ENOENT; 791 ret = -ENOENT;
753 goto end; 792 goto end;
754 } 793 }
794 if (entry->rcu_pending)
795 rcu_barrier_sched();
755 old = marker_entry_remove_probe(entry, NULL, probe_private); 796 old = marker_entry_remove_probe(entry, NULL, probe_private);
756 mutex_unlock(&markers_mutex); 797 mutex_unlock(&markers_mutex);
757 marker_update_probes(); /* may update entry */ 798 marker_update_probes(); /* may update entry */
758 synchronize_sched();
759 kfree(old);
760 mutex_lock(&markers_mutex); 799 mutex_lock(&markers_mutex);
761 entry = get_marker_from_private_data(probe, probe_private); 800 entry = get_marker_from_private_data(probe, probe_private);
762 WARN_ON(!entry); 801 WARN_ON(!entry);
802 if (entry->rcu_pending)
803 rcu_barrier_sched();
804 entry->oldptr = old;
805 entry->rcu_pending = 1;
806 /* write rcu_pending before calling the RCU callback */
807 smp_wmb();
808 call_rcu_sched(&entry->rcu, free_old_closure);
763 remove_marker(entry->name); /* Ignore busy error message */ 809 remove_marker(entry->name); /* Ignore busy error message */
764end: 810end:
765 mutex_unlock(&markers_mutex); 811 mutex_unlock(&markers_mutex);