@@ -46,14 +46,8 @@ static struct {
46
46
int used ; /* number of elements used */
47
47
bool sorted ; /* if elements are sorted */
48
48
bool whitelist ; /* if list is a blacklist or whitelist */
49
- } report_filterlist = {
50
- .addrs = NULL ,
51
- .size = 8 , /* small initial size */
52
- .used = 0 ,
53
- .sorted = false,
54
- .whitelist = false, /* default is blacklist */
55
- };
56
- static DEFINE_SPINLOCK (report_filterlist_lock );
49
+ } report_filterlist ;
50
+ static DEFINE_RAW_SPINLOCK (report_filterlist_lock );
57
51
58
52
/*
59
53
* The microbenchmark allows benchmarking KCSAN core runtime only. To run
@@ -110,7 +104,7 @@ bool kcsan_skip_report_debugfs(unsigned long func_addr)
110
104
return false;
111
105
func_addr -= offset ; /* Get function start */
112
106
113
- spin_lock_irqsave (& report_filterlist_lock , flags );
107
+ raw_spin_lock_irqsave (& report_filterlist_lock , flags );
114
108
if (report_filterlist .used == 0 )
115
109
goto out ;
116
110
@@ -127,67 +121,70 @@ bool kcsan_skip_report_debugfs(unsigned long func_addr)
127
121
ret = !ret ;
128
122
129
123
out :
130
- spin_unlock_irqrestore (& report_filterlist_lock , flags );
124
+ raw_spin_unlock_irqrestore (& report_filterlist_lock , flags );
131
125
return ret ;
132
126
}
133
127
134
128
static void set_report_filterlist_whitelist (bool whitelist )
135
129
{
136
130
unsigned long flags ;
137
131
138
- spin_lock_irqsave (& report_filterlist_lock , flags );
132
+ raw_spin_lock_irqsave (& report_filterlist_lock , flags );
139
133
report_filterlist .whitelist = whitelist ;
140
- spin_unlock_irqrestore (& report_filterlist_lock , flags );
134
+ raw_spin_unlock_irqrestore (& report_filterlist_lock , flags );
141
135
}
142
136
143
137
/* Returns 0 on success, error-code otherwise. */
144
138
static ssize_t insert_report_filterlist (const char * func )
145
139
{
146
140
unsigned long flags ;
147
141
unsigned long addr = kallsyms_lookup_name (func );
142
+ unsigned long * delay_free = NULL ;
143
+ unsigned long * new_addrs = NULL ;
144
+ size_t new_size = 0 ;
148
145
ssize_t ret = 0 ;
149
146
150
147
if (!addr ) {
151
148
pr_err ("could not find function: '%s'\n" , func );
152
149
return - ENOENT ;
153
150
}
154
151
155
- spin_lock_irqsave (& report_filterlist_lock , flags );
152
+ retry_alloc :
153
+ /*
154
+ * Check if we need an allocation, and re-validate under the lock. Since
155
+ * the report_filterlist_lock is a raw, cannot allocate under the lock.
156
+ */
157
+ if (data_race (report_filterlist .used == report_filterlist .size )) {
158
+ new_size = (report_filterlist .size ?: 4 ) * 2 ;
159
+ delay_free = new_addrs = kmalloc_array (new_size , sizeof (unsigned long ), GFP_KERNEL );
160
+ if (!new_addrs )
161
+ return - ENOMEM ;
162
+ }
156
163
157
- if (report_filterlist .addrs == NULL ) {
158
- /* initial allocation */
159
- report_filterlist .addrs =
160
- kmalloc_array (report_filterlist .size ,
161
- sizeof (unsigned long ), GFP_ATOMIC );
162
- if (report_filterlist .addrs == NULL ) {
163
- ret = - ENOMEM ;
164
- goto out ;
165
- }
166
- } else if (report_filterlist .used == report_filterlist .size ) {
167
- /* resize filterlist */
168
- size_t new_size = report_filterlist .size * 2 ;
169
- unsigned long * new_addrs =
170
- krealloc (report_filterlist .addrs ,
171
- new_size * sizeof (unsigned long ), GFP_ATOMIC );
172
-
173
- if (new_addrs == NULL ) {
174
- /* leave filterlist itself untouched */
175
- ret = - ENOMEM ;
176
- goto out ;
164
+ raw_spin_lock_irqsave (& report_filterlist_lock , flags );
165
+ if (report_filterlist .used == report_filterlist .size ) {
166
+ /* Check we pre-allocated enough, and retry if not. */
167
+ if (report_filterlist .used >= new_size ) {
168
+ raw_spin_unlock_irqrestore (& report_filterlist_lock , flags );
169
+ kfree (new_addrs ); /* kfree(NULL) is safe */
170
+ delay_free = new_addrs = NULL ;
171
+ goto retry_alloc ;
177
172
}
178
173
174
+ if (report_filterlist .used )
175
+ memcpy (new_addrs , report_filterlist .addrs , report_filterlist .used * sizeof (unsigned long ));
176
+ delay_free = report_filterlist .addrs ; /* free the old list */
177
+ report_filterlist .addrs = new_addrs ; /* switch to the new list */
179
178
report_filterlist .size = new_size ;
180
- report_filterlist .addrs = new_addrs ;
181
179
}
182
180
183
181
/* Note: deduplicating should be done in userspace. */
184
- report_filterlist .addrs [report_filterlist .used ++ ] =
185
- kallsyms_lookup_name (func );
182
+ report_filterlist .addrs [report_filterlist .used ++ ] = addr ;
186
183
report_filterlist .sorted = false;
187
184
188
- out :
189
- spin_unlock_irqrestore (& report_filterlist_lock , flags );
185
+ raw_spin_unlock_irqrestore (& report_filterlist_lock , flags );
190
186
187
+ kfree (delay_free );
191
188
return ret ;
192
189
}
193
190
@@ -204,13 +201,13 @@ static int show_info(struct seq_file *file, void *v)
204
201
}
205
202
206
203
/* show filter functions, and filter type */
207
- spin_lock_irqsave (& report_filterlist_lock , flags );
204
+ raw_spin_lock_irqsave (& report_filterlist_lock , flags );
208
205
seq_printf (file , "\n%s functions: %s\n" ,
209
206
report_filterlist .whitelist ? "whitelisted" : "blacklisted" ,
210
207
report_filterlist .used == 0 ? "none" : "" );
211
208
for (i = 0 ; i < report_filterlist .used ; ++ i )
212
209
seq_printf (file , " %ps\n" , (void * )report_filterlist .addrs [i ]);
213
- spin_unlock_irqrestore (& report_filterlist_lock , flags );
210
+ raw_spin_unlock_irqrestore (& report_filterlist_lock , flags );
214
211
215
212
return 0 ;
216
213
}
0 commit comments