| @@ -86,17 +86,12 @@ struct kcov_remote { · 85 unmodified lines |
| 86 | 86 | |
| 87 | 87 | static DEFINE_SPINLOCK(kcov_remote_lock); |
| 88 | 88 | static DEFINE_HASHTABLE(kcov_remote_map, 4); |
| 89 | | −static struct list_head kcov_remote_areas = LIST_HEAD_INIT(kcov_remote_areas); |
| 89 | +static struct list_head kcov_remote_areas[2] = { |
| 90 | + LIST_HEAD_INIT(kcov_remote_areas[0]), LIST_HEAD_INIT(kcov_remote_areas[1]) |
| 91 | +}; |
| 90 | 92 | |
| 91 | 93 | struct kcov_percpu_data { |
| 92 | | − void *irq_area; |
| 93 | 94 | local_lock_t lock; |
| 94 | | − |
| 95 | | − unsigned int saved_mode; |
| 96 | | − unsigned int saved_size; |
| 97 | | − void *saved_area; |
| 98 | | − struct kcov *saved_kcov; |
| 99 | | − int saved_sequence; |
| 100 | 95 | }; |
| 101 | 96 | |
| 102 | 97 | static DEFINE_PER_CPU(struct kcov_percpu_data, kcov_percpu_data) = { |
| @@ -132,12 +127,13 @@ static struct kcov_remote *kcov_remote_add(struct kcov *kcov, u64 handle) · 29 unmodified lines |
| 132 | 127 | } |
| 133 | 128 | |
| 134 | 129 | /* Must be called with kcov_remote_lock locked. */ |
| 135 | | −static struct kcov_remote_area *kcov_remote_area_get(unsigned int size) |
| 130 | +static struct kcov_remote_area *kcov_remote_area_get(unsigned int size, bool irq) |
| 136 | 131 | { |
| 137 | 132 | struct kcov_remote_area *area; |
| 138 | 133 | struct list_head *pos; |
| 134 | + struct list_head *list = &kcov_remote_areas[irq]; |
| 139 | 135 | |
| 140 | | − list_for_each(pos, &kcov_remote_areas) { |
| 136 | + list_for_each(pos, list) { |
| 141 | 137 | area = list_entry(pos, struct kcov_remote_area, list); |
| 142 | 138 | if (area->size == size) { |
| 143 | 139 | list_del(&area->list); |
| @@ -149,11 +145,11 @@ static struct kcov_remote_area *kcov_remote_area_get(unsigned int size) · 5 unmodified lines |
| 149 | 145 | |
| 150 | 146 | /* Must be called with kcov_remote_lock locked. */ |
| 151 | 147 | static void kcov_remote_area_put(struct kcov_remote_area *area, |
| 152 | | − unsigned int size) |
| 148 | + unsigned int size, bool irq) |
| 153 | 149 | { |
| 154 | 150 | INIT_LIST_HEAD(&area->list); |
| 155 | 151 | area->size = size; |
| 156 | | − list_add(&area->list, &kcov_remote_areas); |
| 152 | + list_add(&area->list, &kcov_remote_areas[irq]); |
| 157 | 153 | /* |
| 158 | 154 | * KMSAN doesn't instrument this file, so it may not know area->list |
| 159 | 155 | * is initialized. Unpoison it explicitly to avoid reports in |
| @@ -390,6 +386,12 @@ void kcov_task_init(struct task_struct *t) · 230 unmodified lines |
| 390 | 386 | kcov_task_reset(t); |
| 391 | 387 | t->kcov_remote = NULL; |
| 392 | 388 | t->kcov_handle = current->kcov_handle; |
| 389 | + t->kcov_softirq = 0; |
| 390 | + t->kcov_saved_mode = 0; |
| 391 | + t->kcov_saved_size = 0; |
| 392 | + t->kcov_saved_area = NULL; |
| 393 | + t->kcov_saved_kcov = NULL; |
| 394 | + t->kcov_saved_sequence = 0; |
| 393 | 395 | } |
| 394 | 396 | |
| 395 | 397 | static void kcov_reset(struct kcov *kcov) |
| @@ -836,17 +838,16 @@ static inline bool kcov_mode_enabled(unsigned int mode) · 440 unmodified lines |
| 836 | 838 | static void kcov_remote_softirq_start(struct task_struct *t) |
| 837 | 839 | __must_hold(&kcov_percpu_data.lock) |
| 838 | 840 | { |
| 839 | | − struct kcov_percpu_data *data = this_cpu_ptr(&kcov_percpu_data); |
| 840 | 841 | unsigned int mode; |
| 841 | 842 | |
| 842 | 843 | mode = READ_ONCE(t->kcov_mode); |
| 843 | 844 | barrier(); |
| 844 | 845 | if (kcov_mode_enabled(mode)) { |
| 845 | | − data->saved_mode = mode; |
| 846 | | − data->saved_size = t->kcov_size; |
| 847 | | − data->saved_area = t->kcov_area; |
| 848 | | − data->saved_sequence = t->kcov_sequence; |
| 849 | | − data->saved_kcov = t->kcov; |
| 846 | + t->kcov_saved_mode = mode; |
| 847 | + t->kcov_saved_size = t->kcov_size; |
| 848 | + t->kcov_saved_area = t->kcov_area; |
| 849 | + t->kcov_saved_sequence = t->kcov_sequence; |
| 850 | + t->kcov_saved_kcov = t->kcov; |
| 850 | 851 | kcov_stop(t); |
| 851 | 852 | } |
| 852 | 853 | } |
| @@ -854,17 +855,15 @@ static void kcov_remote_softirq_start(struct task_struct *t) · 1 unmodified line |
| 854 | 855 | static void kcov_remote_softirq_stop(struct task_struct *t) |
| 855 | 856 | __must_hold(&kcov_percpu_data.lock) |
| 856 | 857 | { |
| 857 | | − struct kcov_percpu_data *data = this_cpu_ptr(&kcov_percpu_data); |
| 858 | | − |
| 859 | | − if (data->saved_kcov) { |
| 860 | | − kcov_start(t, data->saved_kcov, data->saved_size, |
| 861 | | − data->saved_area, data->saved_mode, |
| 862 | | − data->saved_sequence); |
| 863 | | − data->saved_mode = 0; |
| 864 | | − data->saved_size = 0; |
| 865 | | − data->saved_area = NULL; |
| 866 | | − data->saved_sequence = 0; |
| 867 | | − data->saved_kcov = NULL; |
| 858 | + if (t->kcov_saved_kcov) { |
| 859 | + kcov_start(t, t->kcov_saved_kcov, t->kcov_saved_size, |
| 860 | + t->kcov_saved_area, t->kcov_saved_mode, |
| 861 | + t->kcov_saved_sequence); |
| 862 | + t->kcov_saved_mode = 0; |
| 863 | + t->kcov_saved_size = 0; |
| 864 | + t->kcov_saved_area = NULL; |
| 865 | + t->kcov_saved_sequence = 0; |
| 866 | + t->kcov_saved_kcov = NULL; |
| 868 | 867 | } |
| 869 | 868 | } |
| 870 | 869 | |
| @@ -927,17 +926,17 @@ void kcov_remote_start(u64 handle) · 56 unmodified lines |
| 927 | 926 | sequence = kcov->sequence; |
| 928 | 927 | if (in_task()) { |
| 929 | 928 | size = kcov->remote_size; |
| 930 | | − area = kcov_remote_area_get(size); |
| 929 | + area = kcov_remote_area_get(size, false); |
| 931 | 930 | } else { |
| 932 | 931 | size = CONFIG_KCOV_IRQ_AREA_SIZE; |
| 933 | | − area = this_cpu_ptr(&kcov_percpu_data)->irq_area; |
| 932 | + area = kcov_remote_area_get(size, true); |
| 934 | 933 | } |
| 935 | 934 | spin_unlock(&kcov_remote_lock); |
| 936 | 935 | |
| 937 | | − /* Can only happen when in_task(). */ |
| 936 | + /* Allocate new buffer if we can sleep. */ |
| 938 | 937 | if (!area) { |
| 939 | 938 | local_unlock_irqrestore(&kcov_percpu_data.lock, flags); |
| 940 | | − area = vmalloc(size * sizeof(unsigned long)); |
| 939 | + area = in_task() ? vmalloc(size * sizeof(unsigned long)) : NULL; |
| 941 | 940 | if (!area) { |
| 942 | 941 | kcov_put(kcov); |
| 943 | 942 | return; |
| @@ -1079,11 +1078,9 @@ void kcov_remote_stop(void) · 135 unmodified lines |
| 1079 | 1078 | kcov_move_area(kcov->mode, kcov->area, kcov->size, area); |
| 1080 | 1079 | spin_unlock(&kcov->lock); |
| 1081 | 1080 | |
| 1082 | | − if (in_task()) { |
| 1083 | | − spin_lock(&kcov_remote_lock); |
| 1084 | | − kcov_remote_area_put(area, size); |
| 1085 | | − spin_unlock(&kcov_remote_lock); |
| 1086 | | − } |
| 1081 | + spin_lock(&kcov_remote_lock); |
| 1082 | + kcov_remote_area_put(area, size, !in_task()); |
| 1083 | + spin_unlock(&kcov_remote_lock); |
| 1087 | 1084 | |
| 1088 | 1085 | local_unlock_irqrestore(&kcov_percpu_data.lock, flags); |
| 1089 | 1086 | |
| @@ -1129,14 +1126,21 @@ static void __init selftest(void) · 39 unmodified lines |
| 1129 | 1126 | |
| 1130 | 1127 | static int __init kcov_init(void) |
| 1131 | 1128 | { |
| 1132 | | − int cpu; |
| 1129 | + int cpu = num_possible_cpus(); |
| 1130 | + |
| 1131 | +#ifdef CONFIG_PREEMPT_RT |
| 1132 | + /* Allocate some extra buffers in order to prepare for softirq preemption. */ |
| 1133 | + cpu = cpu >= 4 ? cpu * 2 : cpu + 4; |
| 1134 | +#endif |
| 1135 | + while (cpu--) { |
| 1136 | + void *area = vmalloc(CONFIG_KCOV_IRQ_AREA_SIZE * sizeof(unsigned long)); |
| 1137 | + unsigned long flags; |
| 1133 | 1138 | |
| 1134 | | − for_each_possible_cpu(cpu) { |
| 1135 | | − void *area = vmalloc_node(CONFIG_KCOV_IRQ_AREA_SIZE * |
| 1136 | | − sizeof(unsigned long), cpu_to_node(cpu)); |
| 1137 | 1139 | if (!area) |
| 1138 | 1140 | return -ENOMEM; |
| 1139 | | − per_cpu_ptr(&kcov_percpu_data, cpu)->irq_area = area; |
| 1141 | + spin_lock_irqsave(&kcov_remote_lock, flags); |
| 1142 | + kcov_remote_area_put(area, CONFIG_KCOV_IRQ_AREA_SIZE, true); |
| 1143 | + spin_unlock_irqrestore(&kcov_remote_lock, flags); |
| 1140 | 1144 | } |
| 1141 | 1145 | |
| 1142 | 1146 | /* |