|
1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | | -#define pr_fmt(fmt) "prime numbers: " fmt |
3 | 2 |
|
4 | 3 | #include <linux/module.h> |
5 | 4 | #include <linux/mutex.h> |
6 | 5 | #include <linux/prime_numbers.h> |
7 | 6 | #include <linux/slab.h> |
8 | 7 |
|
9 | | -struct primes { |
10 | | - struct rcu_head rcu; |
11 | | - unsigned long last, sz; |
12 | | - unsigned long primes[]; |
13 | | -}; |
| 8 | +#include "prime_numbers_private.h" |
14 | 9 |
|
15 | 10 | #if BITS_PER_LONG == 64 |
16 | 11 | static const struct primes small_primes = { |
@@ -62,9 +57,25 @@ static const struct primes small_primes = { |
62 | 57 | static DEFINE_MUTEX(lock); |
63 | 58 | static const struct primes __rcu *primes = RCU_INITIALIZER(&small_primes); |
64 | 59 |
|
65 | | -static unsigned long selftest_max; |
| 60 | +#if IS_ENABLED(CONFIG_PRIME_NUMBERS_KUNIT_TEST) |
| 61 | +/* |
| 62 | + * Calls the callback under RCU lock. The callback must not retain |
| 63 | + * the primes pointer. |
| 64 | + */ |
| 65 | +void with_primes(void *ctx, primes_fn fn) |
| 66 | +{ |
| 67 | + rcu_read_lock(); |
| 68 | + fn(ctx, rcu_dereference(primes)); |
| 69 | + rcu_read_unlock(); |
| 70 | +} |
| 71 | +EXPORT_SYMBOL(with_primes); |
| 72 | + |
| 73 | +EXPORT_SYMBOL(slow_is_prime_number); |
66 | 74 |
|
67 | | -static bool slow_is_prime_number(unsigned long x) |
| 75 | +#else |
| 76 | +static |
| 77 | +#endif |
| 78 | +bool slow_is_prime_number(unsigned long x) |
68 | 79 | { |
69 | 80 | unsigned long y = int_sqrt(x); |
70 | 81 |
|
@@ -239,77 +250,13 @@ bool is_prime_number(unsigned long x) |
239 | 250 | } |
240 | 251 | EXPORT_SYMBOL(is_prime_number); |
241 | 252 |
|
242 | | -static void dump_primes(void) |
243 | | -{ |
244 | | - const struct primes *p; |
245 | | - char *buf; |
246 | | - |
247 | | - buf = kmalloc(PAGE_SIZE, GFP_KERNEL); |
248 | | - |
249 | | - rcu_read_lock(); |
250 | | - p = rcu_dereference(primes); |
251 | | - |
252 | | - if (buf) |
253 | | - bitmap_print_to_pagebuf(true, buf, p->primes, p->sz); |
254 | | - pr_info("primes.{last=%lu, .sz=%lu, .primes[]=...x%lx} = %s\n", |
255 | | - p->last, p->sz, p->primes[BITS_TO_LONGS(p->sz) - 1], buf); |
256 | | - |
257 | | - rcu_read_unlock(); |
258 | | - |
259 | | - kfree(buf); |
260 | | -} |
261 | | - |
262 | | -static int selftest(unsigned long max) |
263 | | -{ |
264 | | - unsigned long x, last; |
265 | | - |
266 | | - if (!max) |
267 | | - return 0; |
268 | | - |
269 | | - for (last = 0, x = 2; x < max; x++) { |
270 | | - bool slow = slow_is_prime_number(x); |
271 | | - bool fast = is_prime_number(x); |
272 | | - |
273 | | - if (slow != fast) { |
274 | | - pr_err("inconsistent result for is-prime(%lu): slow=%s, fast=%s!\n", |
275 | | - x, slow ? "yes" : "no", fast ? "yes" : "no"); |
276 | | - goto err; |
277 | | - } |
278 | | - |
279 | | - if (!slow) |
280 | | - continue; |
281 | | - |
282 | | - if (next_prime_number(last) != x) { |
283 | | - pr_err("incorrect result for next-prime(%lu): expected %lu, got %lu\n", |
284 | | - last, x, next_prime_number(last)); |
285 | | - goto err; |
286 | | - } |
287 | | - last = x; |
288 | | - } |
289 | | - |
290 | | - pr_info("%s(%lu) passed, last prime was %lu\n", __func__, x, last); |
291 | | - return 0; |
292 | | - |
293 | | -err: |
294 | | - dump_primes(); |
295 | | - return -EINVAL; |
296 | | -} |
297 | | - |
298 | | -static int __init primes_init(void) |
299 | | -{ |
300 | | - return selftest(selftest_max); |
301 | | -} |
302 | | - |
303 | 253 | static void __exit primes_exit(void) |
304 | 254 | { |
305 | 255 | free_primes(); |
306 | 256 | } |
307 | 257 |
|
308 | | -module_init(primes_init); |
309 | 258 | module_exit(primes_exit); |
310 | 259 |
|
311 | | -module_param_named(selftest, selftest_max, ulong, 0400); |
312 | | - |
313 | 260 | MODULE_AUTHOR("Intel Corporation"); |
314 | 261 | MODULE_DESCRIPTION("Prime number library"); |
315 | 262 | MODULE_LICENSE("GPL"); |
0 commit comments