diff options
Diffstat (limited to 'kernel/marker.c')
-rw-r--r-- | kernel/marker.c | 36 |
1 files changed, 24 insertions, 12 deletions
diff --git a/kernel/marker.c b/kernel/marker.c index 7d1faecd7a51..e9c6b2bc9400 100644 --- a/kernel/marker.c +++ b/kernel/marker.c | |||
@@ -62,7 +62,7 @@ struct marker_entry { | |||
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; | 63 | struct rcu_head rcu; |
64 | void *oldptr; | 64 | void *oldptr; |
65 | unsigned char rcu_pending:1; | 65 | int rcu_pending; |
66 | unsigned char ptype:1; | 66 | unsigned char ptype:1; |
67 | char name[0]; /* Contains name'\0'format'\0' */ | 67 | char name[0]; /* Contains name'\0'format'\0' */ |
68 | }; | 68 | }; |
@@ -103,11 +103,11 @@ void marker_probe_cb(const struct marker *mdata, void *call_private, ...) | |||
103 | char ptype; | 103 | char ptype; |
104 | 104 | ||
105 | /* | 105 | /* |
106 | * preempt_disable does two things : disabling preemption to make sure | 106 | * rcu_read_lock_sched does two things : disabling preemption to make |
107 | * the teardown of the callbacks can be done correctly when they are in | 107 | * sure the teardown of the callbacks can be done correctly when they |
108 | * modules and they insure RCU read coherency. | 108 | * are in modules and they insure RCU read coherency. |
109 | */ | 109 | */ |
110 | preempt_disable(); | 110 | rcu_read_lock_sched(); |
111 | ptype = mdata->ptype; | 111 | ptype = mdata->ptype; |
112 | if (likely(!ptype)) { | 112 | if (likely(!ptype)) { |
113 | marker_probe_func *func; | 113 | marker_probe_func *func; |
@@ -145,7 +145,7 @@ void marker_probe_cb(const struct marker *mdata, void *call_private, ...) | |||
145 | va_end(args); | 145 | va_end(args); |
146 | } | 146 | } |
147 | } | 147 | } |
148 | preempt_enable(); | 148 | rcu_read_unlock_sched(); |
149 | } | 149 | } |
150 | EXPORT_SYMBOL_GPL(marker_probe_cb); | 150 | EXPORT_SYMBOL_GPL(marker_probe_cb); |
151 | 151 | ||
@@ -162,7 +162,7 @@ void marker_probe_cb_noarg(const struct marker *mdata, void *call_private, ...) | |||
162 | va_list args; /* not initialized */ | 162 | va_list args; /* not initialized */ |
163 | char ptype; | 163 | char ptype; |
164 | 164 | ||
165 | preempt_disable(); | 165 | rcu_read_lock_sched(); |
166 | ptype = mdata->ptype; | 166 | ptype = mdata->ptype; |
167 | if (likely(!ptype)) { | 167 | if (likely(!ptype)) { |
168 | marker_probe_func *func; | 168 | marker_probe_func *func; |
@@ -195,7 +195,7 @@ void marker_probe_cb_noarg(const struct marker *mdata, void *call_private, ...) | |||
195 | multi[i].func(multi[i].probe_private, call_private, | 195 | multi[i].func(multi[i].probe_private, call_private, |
196 | mdata->format, &args); | 196 | mdata->format, &args); |
197 | } | 197 | } |
198 | preempt_enable(); | 198 | rcu_read_unlock_sched(); |
199 | } | 199 | } |
200 | EXPORT_SYMBOL_GPL(marker_probe_cb_noarg); | 200 | EXPORT_SYMBOL_GPL(marker_probe_cb_noarg); |
201 | 201 | ||
@@ -560,7 +560,7 @@ static int set_marker(struct marker_entry **entry, struct marker *elem, | |||
560 | * Disable a marker and its probe callback. | 560 | * Disable a marker and its probe callback. |
561 | * Note: only waiting an RCU period after setting elem->call to the empty | 561 | * Note: only waiting an RCU period after setting elem->call to the empty |
562 | * function insures that the original callback is not used anymore. This insured | 562 | * function insures that the original callback is not used anymore. This insured |
563 | * by preempt_disable around the call site. | 563 | * by rcu_read_lock_sched around the call site. |
564 | */ | 564 | */ |
565 | static void disable_marker(struct marker *elem) | 565 | static void disable_marker(struct marker *elem) |
566 | { | 566 | { |
@@ -653,11 +653,17 @@ int marker_probe_register(const char *name, const char *format, | |||
653 | entry = get_marker(name); | 653 | entry = get_marker(name); |
654 | if (!entry) { | 654 | if (!entry) { |
655 | entry = add_marker(name, format); | 655 | entry = add_marker(name, format); |
656 | if (IS_ERR(entry)) { | 656 | if (IS_ERR(entry)) |
657 | ret = PTR_ERR(entry); | 657 | ret = PTR_ERR(entry); |
658 | goto end; | 658 | } else if (format) { |
659 | } | 659 | if (!entry->format) |
660 | ret = marker_set_format(&entry, format); | ||
661 | else if (strcmp(entry->format, format)) | ||
662 | ret = -EPERM; | ||
660 | } | 663 | } |
664 | if (ret) | ||
665 | goto end; | ||
666 | |||
661 | /* | 667 | /* |
662 | * If we detect that a call_rcu is pending for this marker, | 668 | * If we detect that a call_rcu is pending for this marker, |
663 | * make sure it's executed now. | 669 | * make sure it's executed now. |
@@ -674,6 +680,8 @@ int marker_probe_register(const char *name, const char *format, | |||
674 | mutex_lock(&markers_mutex); | 680 | mutex_lock(&markers_mutex); |
675 | entry = get_marker(name); | 681 | entry = get_marker(name); |
676 | WARN_ON(!entry); | 682 | WARN_ON(!entry); |
683 | if (entry->rcu_pending) | ||
684 | rcu_barrier_sched(); | ||
677 | entry->oldptr = old; | 685 | entry->oldptr = old; |
678 | entry->rcu_pending = 1; | 686 | entry->rcu_pending = 1; |
679 | /* write rcu_pending before calling the RCU callback */ | 687 | /* write rcu_pending before calling the RCU callback */ |
@@ -717,6 +725,8 @@ int marker_probe_unregister(const char *name, | |||
717 | entry = get_marker(name); | 725 | entry = get_marker(name); |
718 | if (!entry) | 726 | if (!entry) |
719 | goto end; | 727 | goto end; |
728 | if (entry->rcu_pending) | ||
729 | rcu_barrier_sched(); | ||
720 | entry->oldptr = old; | 730 | entry->oldptr = old; |
721 | entry->rcu_pending = 1; | 731 | entry->rcu_pending = 1; |
722 | /* write rcu_pending before calling the RCU callback */ | 732 | /* write rcu_pending before calling the RCU callback */ |
@@ -795,6 +805,8 @@ int marker_probe_unregister_private_data(marker_probe_func *probe, | |||
795 | mutex_lock(&markers_mutex); | 805 | mutex_lock(&markers_mutex); |
796 | entry = get_marker_from_private_data(probe, probe_private); | 806 | entry = get_marker_from_private_data(probe, probe_private); |
797 | WARN_ON(!entry); | 807 | WARN_ON(!entry); |
808 | if (entry->rcu_pending) | ||
809 | rcu_barrier_sched(); | ||
798 | entry->oldptr = old; | 810 | entry->oldptr = old; |
799 | entry->rcu_pending = 1; | 811 | entry->rcu_pending = 1; |
800 | /* write rcu_pending before calling the RCU callback */ | 812 | /* write rcu_pending before calling the RCU callback */ |