@@ -46,14 +46,8 @@ static struct {
4646 int used ; /* number of elements used */
4747 bool sorted ; /* if elements are sorted */
4848 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 );
5751
5852/*
5953 * The microbenchmark allows benchmarking KCSAN core runtime only. To run
@@ -110,7 +104,7 @@ bool kcsan_skip_report_debugfs(unsigned long func_addr)
110104 return false;
111105 func_addr -= offset ; /* Get function start */
112106
113- spin_lock_irqsave (& report_filterlist_lock , flags );
107+ raw_spin_lock_irqsave (& report_filterlist_lock , flags );
114108 if (report_filterlist .used == 0 )
115109 goto out ;
116110
@@ -127,67 +121,70 @@ bool kcsan_skip_report_debugfs(unsigned long func_addr)
127121 ret = !ret ;
128122
129123out :
130- spin_unlock_irqrestore (& report_filterlist_lock , flags );
124+ raw_spin_unlock_irqrestore (& report_filterlist_lock , flags );
131125 return ret ;
132126}
133127
134128static void set_report_filterlist_whitelist (bool whitelist )
135129{
136130 unsigned long flags ;
137131
138- spin_lock_irqsave (& report_filterlist_lock , flags );
132+ raw_spin_lock_irqsave (& report_filterlist_lock , flags );
139133 report_filterlist .whitelist = whitelist ;
140- spin_unlock_irqrestore (& report_filterlist_lock , flags );
134+ raw_spin_unlock_irqrestore (& report_filterlist_lock , flags );
141135}
142136
143137/* Returns 0 on success, error-code otherwise. */
144138static ssize_t insert_report_filterlist (const char * func )
145139{
146140 unsigned long flags ;
147141 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 ;
148145 ssize_t ret = 0 ;
149146
150147 if (!addr ) {
151148 pr_err ("could not find function: '%s'\n" , func );
152149 return - ENOENT ;
153150 }
154151
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+ }
156163
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 ;
177172 }
178173
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 */
179178 report_filterlist .size = new_size ;
180- report_filterlist .addrs = new_addrs ;
181179 }
182180
183181 /* 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 ;
186183 report_filterlist .sorted = false;
187184
188- out :
189- spin_unlock_irqrestore (& report_filterlist_lock , flags );
185+ raw_spin_unlock_irqrestore (& report_filterlist_lock , flags );
190186
187+ kfree (delay_free );
191188 return ret ;
192189}
193190
@@ -204,13 +201,13 @@ static int show_info(struct seq_file *file, void *v)
204201 }
205202
206203 /* show filter functions, and filter type */
207- spin_lock_irqsave (& report_filterlist_lock , flags );
204+ raw_spin_lock_irqsave (& report_filterlist_lock , flags );
208205 seq_printf (file , "\n%s functions: %s\n" ,
209206 report_filterlist .whitelist ? "whitelisted" : "blacklisted" ,
210207 report_filterlist .used == 0 ? "none" : "" );
211208 for (i = 0 ; i < report_filterlist .used ; ++ i )
212209 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 );
214211
215212 return 0 ;
216213}
0 commit comments