Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+37 -40
+37 -40
kernel/kcsan/debugfs.c
··· 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 ··· 104 110 return false; 105 111 func_addr -= offset; /* Get function start */ 106 112 107 - spin_lock_irqsave(&report_filterlist_lock, flags); 113 + raw_spin_lock_irqsave(&report_filterlist_lock, flags); 108 114 if (report_filterlist.used == 0) 109 115 goto out; 110 116 ··· 121 127 ret = !ret; 122 128 123 129 out: 124 - spin_unlock_irqrestore(&report_filterlist_lock, flags); 130 + raw_spin_unlock_irqrestore(&report_filterlist_lock, flags); 125 131 return ret; 126 132 } 127 133 ··· 129 135 { 130 136 unsigned long flags; 131 137 132 - spin_lock_irqsave(&report_filterlist_lock, flags); 138 + raw_spin_lock_irqsave(&report_filterlist_lock, flags); 133 139 report_filterlist.whitelist = whitelist; 134 - spin_unlock_irqrestore(&report_filterlist_lock, flags); 140 + raw_spin_unlock_irqrestore(&report_filterlist_lock, flags); 135 141 } 136 142 137 143 /* Returns 0 on success, error-code otherwise. */ ··· 139 145 { 140 146 unsigned long flags; 141 147 unsigned long addr = kallsyms_lookup_name(func); 148 + unsigned long *delay_free = NULL; 149 + unsigned long *new_addrs = NULL; 150 + size_t new_size = 0; 142 151 ssize_t ret = 0; 143 152 144 153 if (!addr) { ··· 149 152 return -ENOENT; 150 153 } 151 154 152 - spin_lock_irqsave(&report_filterlist_lock, flags); 155 + retry_alloc: 156 + /* 157 + * Check if we need an allocation, and re-validate under the lock. Since 158 + * the report_filterlist_lock is a raw, cannot allocate under the lock. 159 + */ 160 + if (data_race(report_filterlist.used == report_filterlist.size)) { 161 + new_size = (report_filterlist.size ?: 4) * 2; 162 + delay_free = new_addrs = kmalloc_array(new_size, sizeof(unsigned long), GFP_KERNEL); 163 + if (!new_addrs) 164 + return -ENOMEM; 165 + } 153 166 154 - if (report_filterlist.addrs == NULL) { 155 - /* initial allocation */ 156 - report_filterlist.addrs = 157 - kmalloc_array(report_filterlist.size, 158 - sizeof(unsigned long), GFP_ATOMIC); 159 - if (report_filterlist.addrs == NULL) { 160 - ret = -ENOMEM; 161 - goto out; 162 - } 163 - } else if (report_filterlist.used == report_filterlist.size) { 164 - /* resize filterlist */ 165 - size_t new_size = report_filterlist.size * 2; 166 - unsigned long *new_addrs = 167 - krealloc(report_filterlist.addrs, 168 - new_size * sizeof(unsigned long), GFP_ATOMIC); 169 - 170 - if (new_addrs == NULL) { 171 - /* leave filterlist itself untouched */ 172 - ret = -ENOMEM; 173 - goto out; 167 + raw_spin_lock_irqsave(&report_filterlist_lock, flags); 168 + if (report_filterlist.used == report_filterlist.size) { 169 + /* Check we pre-allocated enough, and retry if not. */ 170 + if (report_filterlist.used >= new_size) { 171 + raw_spin_unlock_irqrestore(&report_filterlist_lock, flags); 172 + kfree(new_addrs); /* kfree(NULL) is safe */ 173 + delay_free = new_addrs = NULL; 174 + goto retry_alloc; 174 175 } 175 176 177 + if (report_filterlist.used) 178 + memcpy(new_addrs, report_filterlist.addrs, report_filterlist.used * sizeof(unsigned long)); 179 + delay_free = report_filterlist.addrs; /* free the old list */ 180 + report_filterlist.addrs = new_addrs; /* switch to the new list */ 176 181 report_filterlist.size = new_size; 177 - report_filterlist.addrs = new_addrs; 178 182 } 179 183 180 184 /* Note: deduplicating should be done in userspace. */ 181 - report_filterlist.addrs[report_filterlist.used++] = 182 - kallsyms_lookup_name(func); 185 + report_filterlist.addrs[report_filterlist.used++] = addr; 183 186 report_filterlist.sorted = false; 184 187 185 - out: 186 - spin_unlock_irqrestore(&report_filterlist_lock, flags); 188 + raw_spin_unlock_irqrestore(&report_filterlist_lock, flags); 187 189 190 + kfree(delay_free); 188 191 return ret; 189 192 } 190 193 ··· 201 204 } 202 205 203 206 /* show filter functions, and filter type */ 204 - spin_lock_irqsave(&report_filterlist_lock, flags); 207 + raw_spin_lock_irqsave(&report_filterlist_lock, flags); 205 208 seq_printf(file, "\n%s functions: %s\n", 206 209 report_filterlist.whitelist ? "whitelisted" : "blacklisted", 207 210 report_filterlist.used == 0 ? "none" : ""); 208 211 for (i = 0; i < report_filterlist.used; ++i) 209 212 seq_printf(file, " %ps\n", (void *)report_filterlist.addrs[i]); 210 - spin_unlock_irqrestore(&report_filterlist_lock, flags); 213 + raw_spin_unlock_irqrestore(&report_filterlist_lock, flags); 211 214 212 215 return 0; 213 216 }