Skip to content

Commit 769ca7d

Browse files
committed
Merge tag 'kcsan-20241112-v6.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/melver/linux
Pull Kernel Concurrency Sanitizer (KCSAN) updates from Marco Elver: - Make KCSAN compatible with PREEMPT_RT - Minor cleanup * tag 'kcsan-20241112-v6.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/melver/linux: kcsan: Remove redundant call of kallsyms_lookup_name() kcsan: Turn report_filterlist_lock into a raw_spinlock
2 parents 8cdf2d1 + b86f7c9 commit 769ca7d

File tree

1 file changed

+37
-40
lines changed

1 file changed

+37
-40
lines changed

kernel/kcsan/debugfs.c

Lines changed: 37 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -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

129123
out:
130-
spin_unlock_irqrestore(&report_filterlist_lock, flags);
124+
raw_spin_unlock_irqrestore(&report_filterlist_lock, flags);
131125
return ret;
132126
}
133127

134128
static 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. */
144138
static 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

Comments
 (0)