From 91abab83839aa2eba073e4a63c729832fdb27ea1 Mon Sep 17 00:00:00 2001 From: "Matthew Wilcox (Oracle)" Date: Mon, 1 Jul 2019 17:03:29 -0400 Subject: XArray: Fix xas_next() with a single entry at 0 If there is only a single entry at 0, the first time we call xas_next(), we return the entry. Unfortunately, all subsequent times we call xas_next(), we also return the entry at 0 instead of noticing that the xa_index is now greater than zero. This broke find_get_pages_contig(). Fixes: 64d3e9a9e0cc ("xarray: Step through an XArray") Reported-by: Kent Overstreet Signed-off-by: Matthew Wilcox (Oracle) --- lib/test_xarray.c | 24 ++++++++++++++++++++++++ lib/xarray.c | 4 ++++ 2 files changed, 28 insertions(+) (limited to 'lib') diff --git a/lib/test_xarray.c b/lib/test_xarray.c index 9d631a7b6a70..7df4f7f395bf 100644 --- a/lib/test_xarray.c +++ b/lib/test_xarray.c @@ -1110,6 +1110,28 @@ static noinline void check_find_entry(struct xarray *xa) XA_BUG_ON(xa, !xa_empty(xa)); } +static noinline void check_move_tiny(struct xarray *xa) +{ + XA_STATE(xas, xa, 0); + + XA_BUG_ON(xa, !xa_empty(xa)); + rcu_read_lock(); + XA_BUG_ON(xa, xas_next(&xas) != NULL); + XA_BUG_ON(xa, xas_next(&xas) != NULL); + rcu_read_unlock(); + xa_store_index(xa, 0, GFP_KERNEL); + rcu_read_lock(); + xas_set(&xas, 0); + XA_BUG_ON(xa, xas_next(&xas) != xa_mk_index(0)); + XA_BUG_ON(xa, xas_next(&xas) != NULL); + xas_set(&xas, 0); + XA_BUG_ON(xa, xas_prev(&xas) != xa_mk_index(0)); + XA_BUG_ON(xa, xas_prev(&xas) != NULL); + rcu_read_unlock(); + xa_erase_index(xa, 0); + XA_BUG_ON(xa, !xa_empty(xa)); +} + static noinline void check_move_small(struct xarray *xa, unsigned long idx) { XA_STATE(xas, xa, 0); @@ -1217,6 +1239,8 @@ static noinline void check_move(struct xarray *xa) xa_destroy(xa); + check_move_tiny(xa); + for (i = 0; i < 16; i++) check_move_small(xa, 1UL << i); diff --git a/lib/xarray.c b/lib/xarray.c index 446b956c9188..1237c213f52b 100644 --- a/lib/xarray.c +++ b/lib/xarray.c @@ -994,6 +994,8 @@ void *__xas_prev(struct xa_state *xas) if (!xas_frozen(xas->xa_node)) xas->xa_index--; + if (!xas->xa_node) + return set_bounds(xas); if (xas_not_node(xas->xa_node)) return xas_load(xas); @@ -1031,6 +1033,8 @@ void *__xas_next(struct xa_state *xas) if (!xas_frozen(xas->xa_node)) xas->xa_index++; + if (!xas->xa_node) + return set_bounds(xas); if (xas_not_node(xas->xa_node)) return xas_load(xas); -- cgit v1.2.3 From c90012ac85c24547e5c3468ef00aabf44aa7332d Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Sun, 6 Oct 2019 10:30:28 +1100 Subject: lib: test_user_copy: style cleanup While writing the tests for copy_struct_from_user(), I used a construct that Linus doesn't appear to be too fond of: On 2019-10-04, Linus Torvalds wrote: > Hmm. That code is ugly, both before and after the fix. > > This just doesn't make sense for so many reasons: > > if ((ret |= test(umem_src == NULL, "kmalloc failed"))) > > where the insanity comes from > > - why "|=" when you know that "ret" was zero before (and it had to > be, for the test to make sense) > > - why do this as a single line anyway? > > - don't do the stupid "double parenthesis" to hide a warning. Make it > use an actual comparison if you add a layer of parentheses. So instead, use a bog-standard check that isn't nearly as ugly. Fixes: 341115822f88 ("usercopy: Add parentheses around assignment in test_copy_struct_from_user") Fixes: f5a1a536fa14 ("lib: introduce copy_struct_from_user() helper") Signed-off-by: Aleksa Sarai Reviewed-by: Nathan Chancellor Reviewed-by: Christian Brauner Link: https://lore.kernel.org/r/20191005233028.18566-1-cyphar@cyphar.com Signed-off-by: Christian Brauner --- lib/test_user_copy.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/test_user_copy.c b/lib/test_user_copy.c index e365ace06538..ad2372727b1b 100644 --- a/lib/test_user_copy.c +++ b/lib/test_user_copy.c @@ -52,13 +52,14 @@ static int test_check_nonzero_user(char *kmem, char __user *umem, size_t size) size_t zero_end = size - zero_start; /* - * We conduct a series of check_nonzero_user() tests on a block of memory - * with the following byte-pattern (trying every possible [start,end] - * pair): + * We conduct a series of check_nonzero_user() tests on a block of + * memory with the following byte-pattern (trying every possible + * [start,end] pair): * * [ 00 ff 00 ff ... 00 00 00 00 ... ff 00 ff 00 ] * - * And we verify that check_nonzero_user() acts identically to memchr_inv(). + * And we verify that check_nonzero_user() acts identically to + * memchr_inv(). */ memset(kmem, 0x0, size); @@ -93,11 +94,13 @@ static int test_copy_struct_from_user(char *kmem, char __user *umem, size_t ksize, usize; umem_src = kmalloc(size, GFP_KERNEL); - if ((ret |= test(umem_src == NULL, "kmalloc failed"))) + ret = test(umem_src == NULL, "kmalloc failed"); + if (ret) goto out_free; expected = kmalloc(size, GFP_KERNEL); - if ((ret |= test(expected == NULL, "kmalloc failed"))) + ret = test(expected == NULL, "kmalloc failed"); + if (ret) goto out_free; /* Fill umem with a fixed byte pattern. */ -- cgit v1.2.3 From 50a2610adec9d796b25e262734edb56ef324ce15 Mon Sep 17 00:00:00 2001 From: Vincenzo Frascino Date: Thu, 3 Oct 2019 18:48:38 +0100 Subject: lib: vdso: Remove CROSS_COMPILE_COMPAT_VDSO arm64 was the last architecture using CROSS_COMPILE_COMPAT_VDSO config option. With this patch series the dependency in the architecture has been removed. Remove CROSS_COMPILE_COMPAT_VDSO from the Unified vDSO library code. Cc: Thomas Gleixner Cc: Andy Lutomirski Signed-off-by: Vincenzo Frascino Signed-off-by: Will Deacon --- lib/vdso/Kconfig | 9 --------- 1 file changed, 9 deletions(-) (limited to 'lib') diff --git a/lib/vdso/Kconfig b/lib/vdso/Kconfig index cc00364bd2c2..9fe698ff62ec 100644 --- a/lib/vdso/Kconfig +++ b/lib/vdso/Kconfig @@ -24,13 +24,4 @@ config GENERIC_COMPAT_VDSO help This config option enables the compat VDSO layer. -config CROSS_COMPILE_COMPAT_VDSO - string "32 bit Toolchain prefix for compat vDSO" - default "" - depends on GENERIC_COMPAT_VDSO - help - Defines the cross-compiler prefix for compiling compat vDSO. - If a 64 bit compiler (i.e. x86_64) can compile the VDSO for - 32 bit, it does not need to define this parameter. - endif -- cgit v1.2.3 From bec500777089b3c96c53681fc0aa6fee59711d4a Mon Sep 17 00:00:00 2001 From: Arvind Sankar Date: Mon, 7 Oct 2019 18:00:02 -0400 Subject: lib/string: Make memzero_explicit() inline instead of external With the use of the barrier implied by barrier_data(), there is no need for memzero_explicit() to be extern. Making it inline saves the overhead of a function call, and allows the code to be reused in arch/*/purgatory without having to duplicate the implementation. Tested-by: Hans de Goede Signed-off-by: Arvind Sankar Reviewed-by: Hans de Goede Cc: Ard Biesheuvel Cc: Borislav Petkov Cc: H . Peter Anvin Cc: Herbert Xu Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephan Mueller Cc: Thomas Gleixner Cc: linux-crypto@vger.kernel.org Cc: linux-s390@vger.kernel.org Fixes: 906a4bb97f5d ("crypto: sha256 - Use get/put_unaligned_be32 to get input, memzero_explicit") Link: https://lkml.kernel.org/r/20191007220000.GA408752@rani.riverdale.lan Signed-off-by: Ingo Molnar --- include/linux/string.h | 21 ++++++++++++++++++++- lib/string.c | 21 --------------------- 2 files changed, 20 insertions(+), 22 deletions(-) (limited to 'lib') diff --git a/include/linux/string.h b/include/linux/string.h index b2f9df7f0761..b6ccdc2c7f02 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -227,7 +227,26 @@ static inline bool strstarts(const char *str, const char *prefix) } size_t memweight(const void *ptr, size_t bytes); -void memzero_explicit(void *s, size_t count); + +/** + * memzero_explicit - Fill a region of memory (e.g. sensitive + * keying data) with 0s. + * @s: Pointer to the start of the area. + * @count: The size of the area. + * + * Note: usually using memset() is just fine (!), but in cases + * where clearing out _local_ data at the end of a scope is + * necessary, memzero_explicit() should be used instead in + * order to prevent the compiler from optimising away zeroing. + * + * memzero_explicit() doesn't need an arch-specific version as + * it just invokes the one of memset() implicitly. + */ +static inline void memzero_explicit(void *s, size_t count) +{ + memset(s, 0, count); + barrier_data(s); +} /** * kbasename - return the last part of a pathname. diff --git a/lib/string.c b/lib/string.c index cd7a10c19210..08ec58cc673b 100644 --- a/lib/string.c +++ b/lib/string.c @@ -748,27 +748,6 @@ void *memset(void *s, int c, size_t count) EXPORT_SYMBOL(memset); #endif -/** - * memzero_explicit - Fill a region of memory (e.g. sensitive - * keying data) with 0s. - * @s: Pointer to the start of the area. - * @count: The size of the area. - * - * Note: usually using memset() is just fine (!), but in cases - * where clearing out _local_ data at the end of a scope is - * necessary, memzero_explicit() should be used instead in - * order to prevent the compiler from optimising away zeroing. - * - * memzero_explicit() doesn't need an arch-specific version as - * it just invokes the one of memset() implicitly. - */ -void memzero_explicit(void *s, size_t count) -{ - memset(s, 0, count); - barrier_data(s); -} -EXPORT_SYMBOL(memzero_explicit); - #ifndef __HAVE_ARCH_MEMSET16 /** * memset16() - Fill a memory area with a uint16_t -- cgit v1.2.3 From 3c52b0af059e11a063970aed1ad143b9284a79c7 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 14 Oct 2019 14:11:54 -0700 Subject: lib/generic-radix-tree.c: add kmemleak annotations Kmemleak is falsely reporting a leak of the slab allocation in sctp_stream_init_ext(): BUG: memory leak unreferenced object 0xffff8881114f5d80 (size 96): comm "syz-executor934", pid 7160, jiffies 4294993058 (age 31.950s) hex dump (first 32 bytes): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace: [<00000000ce7a1326>] kmemleak_alloc_recursive include/linux/kmemleak.h:55 [inline] [<00000000ce7a1326>] slab_post_alloc_hook mm/slab.h:439 [inline] [<00000000ce7a1326>] slab_alloc mm/slab.c:3326 [inline] [<00000000ce7a1326>] kmem_cache_alloc_trace+0x13d/0x280 mm/slab.c:3553 [<000000007abb7ac9>] kmalloc include/linux/slab.h:547 [inline] [<000000007abb7ac9>] kzalloc include/linux/slab.h:742 [inline] [<000000007abb7ac9>] sctp_stream_init_ext+0x2b/0xa0 net/sctp/stream.c:157 [<0000000048ecb9c1>] sctp_sendmsg_to_asoc+0x946/0xa00 net/sctp/socket.c:1882 [<000000004483ca2b>] sctp_sendmsg+0x2a8/0x990 net/sctp/socket.c:2102 [...] But it's freed later. Kmemleak misses the allocation because its pointer is stored in the generic radix tree sctp_stream::out, and the generic radix tree uses raw pages which aren't tracked by kmemleak. Fix this by adding the kmemleak hooks to the generic radix tree code. Link: http://lkml.kernel.org/r/20191004065039.727564-1-ebiggers@kernel.org Signed-off-by: Eric Biggers Reported-by: Reviewed-by: Marcelo Ricardo Leitner Acked-by: Neil Horman Reviewed-by: Catalin Marinas Cc: Kent Overstreet Cc: Vlad Yasevich Cc: Xin Long Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- lib/generic-radix-tree.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/generic-radix-tree.c b/lib/generic-radix-tree.c index ae25e2fa2187..f25eb111c051 100644 --- a/lib/generic-radix-tree.c +++ b/lib/generic-radix-tree.c @@ -2,6 +2,7 @@ #include #include #include +#include #define GENRADIX_ARY (PAGE_SIZE / sizeof(struct genradix_node *)) #define GENRADIX_ARY_SHIFT ilog2(GENRADIX_ARY) @@ -75,6 +76,27 @@ void *__genradix_ptr(struct __genradix *radix, size_t offset) } EXPORT_SYMBOL(__genradix_ptr); +static inline struct genradix_node *genradix_alloc_node(gfp_t gfp_mask) +{ + struct genradix_node *node; + + node = (struct genradix_node *)__get_free_page(gfp_mask|__GFP_ZERO); + + /* + * We're using pages (not slab allocations) directly for kernel data + * structures, so we need to explicitly inform kmemleak of them in order + * to avoid false positive memory leak reports. + */ + kmemleak_alloc(node, PAGE_SIZE, 1, gfp_mask); + return node; +} + +static inline void genradix_free_node(struct genradix_node *node) +{ + kmemleak_free(node); + free_page((unsigned long)node); +} + /* * Returns pointer to the specified byte @offset within @radix, allocating it if * necessary - newly allocated slots are always zeroed out: @@ -97,8 +119,7 @@ void *__genradix_ptr_alloc(struct __genradix *radix, size_t offset, break; if (!new_node) { - new_node = (void *) - __get_free_page(gfp_mask|__GFP_ZERO); + new_node = genradix_alloc_node(gfp_mask); if (!new_node) return NULL; } @@ -121,8 +142,7 @@ void *__genradix_ptr_alloc(struct __genradix *radix, size_t offset, n = READ_ONCE(*p); if (!n) { if (!new_node) { - new_node = (void *) - __get_free_page(gfp_mask|__GFP_ZERO); + new_node = genradix_alloc_node(gfp_mask); if (!new_node) return NULL; } @@ -133,7 +153,7 @@ void *__genradix_ptr_alloc(struct __genradix *radix, size_t offset, } if (new_node) - free_page((unsigned long) new_node); + genradix_free_node(new_node); return &n->data[offset]; } @@ -191,7 +211,7 @@ static void genradix_free_recurse(struct genradix_node *n, unsigned level) genradix_free_recurse(n->children[i], level - 1); } - free_page((unsigned long) n); + genradix_free_node(n); } int __genradix_prealloc(struct __genradix *radix, size_t size, -- cgit v1.2.3 From 03a9349ac0e095dea6ef8b5b7b14f9c23e5fabe6 Mon Sep 17 00:00:00 2001 From: Alexander Potapenko Date: Mon, 14 Oct 2019 14:12:00 -0700 Subject: lib/test_meminit: add a kmem_cache_alloc_bulk() test Make sure allocations from kmem_cache_alloc_bulk() and kmem_cache_free_bulk() are properly initialized. Link: http://lkml.kernel.org/r/20191007091605.30530-2-glider@google.com Signed-off-by: Alexander Potapenko Cc: Kees Cook Cc: Christoph Lameter Cc: Laura Abbott Cc: Thibaut Sautereau Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- lib/test_meminit.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'lib') diff --git a/lib/test_meminit.c b/lib/test_meminit.c index 9729f271d150..9742e5cb853a 100644 --- a/lib/test_meminit.c +++ b/lib/test_meminit.c @@ -297,6 +297,32 @@ out: return 1; } +static int __init do_kmem_cache_size_bulk(int size, int *total_failures) +{ + struct kmem_cache *c; + int i, iter, maxiter = 1024; + int num, bytes; + bool fail = false; + void *objects[10]; + + c = kmem_cache_create("test_cache", size, size, 0, NULL); + for (iter = 0; (iter < maxiter) && !fail; iter++) { + num = kmem_cache_alloc_bulk(c, GFP_KERNEL, ARRAY_SIZE(objects), + objects); + for (i = 0; i < num; i++) { + bytes = count_nonzero_bytes(objects[i], size); + if (bytes) + fail = true; + fill_with_garbage(objects[i], size); + } + + if (num) + kmem_cache_free_bulk(c, num, objects); + } + *total_failures += fail; + return 1; +} + /* * Test kmem_cache allocation by creating caches of different sizes, with and * without constructors, with and without SLAB_TYPESAFE_BY_RCU. @@ -318,6 +344,7 @@ static int __init test_kmemcache(int *total_failures) num_tests += do_kmem_cache_size(size, ctor, rcu, zero, &failures); } + num_tests += do_kmem_cache_size_bulk(size, &failures); } REPORT_FAILURES_IN_FN(); *total_failures += failures; -- cgit v1.2.3 From f418dddffc8007945fd5962380ebde770a240cf5 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 16 Oct 2019 23:27:32 +1100 Subject: usercopy: Avoid soft lockups in test_check_nonzero_user() On a machine with a 64K PAGE_SIZE, the nested for loops in test_check_nonzero_user() can lead to soft lockups, eg: watchdog: BUG: soft lockup - CPU#4 stuck for 22s! [modprobe:611] Modules linked in: test_user_copy(+) vmx_crypto gf128mul crc32c_vpmsum virtio_balloon ip_tables x_tables autofs4 CPU: 4 PID: 611 Comm: modprobe Tainted: G L 5.4.0-rc1-gcc-8.2.0-00001-gf5a1a536fa14-dirty #1151 ... NIP __might_sleep+0x20/0xc0 LR __might_fault+0x40/0x60 Call Trace: check_zeroed_user+0x12c/0x200 test_user_copy_init+0x67c/0x1210 [test_user_copy] do_one_initcall+0x60/0x340 do_init_module+0x7c/0x2f0 load_module+0x2d94/0x30e0 __do_sys_finit_module+0xc8/0x150 system_call+0x5c/0x68 Even with a 4K PAGE_SIZE the test takes multiple seconds. Instead tweak it to only scan a 1024 byte region, but make it cross the page boundary. Fixes: f5a1a536fa14 ("lib: introduce copy_struct_from_user() helper") Suggested-by: Aleksa Sarai Signed-off-by: Michael Ellerman Reviewed-by: Aleksa Sarai Acked-by: Christian Brauner Link: https://lore.kernel.org/r/20191016122732.13467-1-mpe@ellerman.id.au Signed-off-by: Christian Brauner --- lib/test_user_copy.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/test_user_copy.c b/lib/test_user_copy.c index ad2372727b1b..5ff04d8fe971 100644 --- a/lib/test_user_copy.c +++ b/lib/test_user_copy.c @@ -47,9 +47,25 @@ static bool is_zeroed(void *from, size_t size) static int test_check_nonzero_user(char *kmem, char __user *umem, size_t size) { int ret = 0; - size_t start, end, i; - size_t zero_start = size / 4; - size_t zero_end = size - zero_start; + size_t start, end, i, zero_start, zero_end; + + if (test(size < 2 * PAGE_SIZE, "buffer too small")) + return -EINVAL; + + /* + * We want to cross a page boundary to exercise the code more + * effectively. We also don't want to make the size we scan too large, + * otherwise the test can take a long time and cause soft lockups. So + * scan a 1024 byte region across the page boundary. + */ + size = 1024; + start = PAGE_SIZE - (size / 2); + + kmem += start; + umem += start; + + zero_start = size / 4; + zero_end = size - zero_start; /* * We conduct a series of check_nonzero_user() tests on a block of -- cgit v1.2.3 From 1638b8f096ca165965189b9626564c933c79fe63 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 21 Oct 2019 12:07:15 +0200 Subject: lib/vdso: Make clock_getres() POSIX compliant again A recent commit removed the NULL pointer check from the clock_getres() implementation causing a test case to fault. POSIX requires an explicit NULL pointer check for clock_getres() aside of the validity check of the clock_id argument for obscure reasons. Add it back for both 32bit and 64bit. Note, this is only a partial revert of the offending commit which does not bring back the broken fallback invocation in the the 32bit compat implementations of clock_getres() and clock_gettime(). Fixes: a9446a906f52 ("lib/vdso/32: Remove inconsistent NULL pointer checks") Reported-by: Andreas Schwab Signed-off-by: Thomas Gleixner Tested-by: Christophe Leroy Cc: stable@vger.kernel.org Link: https://lkml.kernel.org/r/alpine.DEB.2.21.1910211202260.1904@nanos.tec.linutronix.de --- lib/vdso/gettimeofday.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/vdso/gettimeofday.c b/lib/vdso/gettimeofday.c index e630e7ff57f1..45f57fd2db64 100644 --- a/lib/vdso/gettimeofday.c +++ b/lib/vdso/gettimeofday.c @@ -214,9 +214,10 @@ int __cvdso_clock_getres_common(clockid_t clock, struct __kernel_timespec *res) return -1; } - res->tv_sec = 0; - res->tv_nsec = ns; - + if (likely(res)) { + res->tv_sec = 0; + res->tv_nsec = ns; + } return 0; } @@ -245,7 +246,7 @@ __cvdso_clock_getres_time32(clockid_t clock, struct old_timespec32 *res) ret = clock_getres_fallback(clock, &ts); #endif - if (likely(!ret)) { + if (likely(!ret && res)) { res->tv_sec = ts.tv_sec; res->tv_nsec = ts.tv_nsec; } -- cgit v1.2.3 From 5a74ac4c4a97bd8b7dba054304d598e2a882fea6 Mon Sep 17 00:00:00 2001 From: "Matthew Wilcox (Oracle)" Date: Fri, 1 Nov 2019 21:36:39 -0400 Subject: idr: Fix idr_get_next_ul race with idr_remove Commit 5c089fd0c734 ("idr: Fix idr_get_next race with idr_remove") neglected to fix idr_get_next_ul(). As far as I can tell, nobody's actually using this interface under the RCU read lock, but fix it now before anybody decides to use it. Fixes: 5c089fd0c734 ("idr: Fix idr_get_next race with idr_remove") Signed-off-by: Matthew Wilcox (Oracle) --- lib/idr.c | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) (limited to 'lib') diff --git a/lib/idr.c b/lib/idr.c index 66a374892482..c2cf2c52bbde 100644 --- a/lib/idr.c +++ b/lib/idr.c @@ -215,7 +215,7 @@ int idr_for_each(const struct idr *idr, EXPORT_SYMBOL(idr_for_each); /** - * idr_get_next() - Find next populated entry. + * idr_get_next_ul() - Find next populated entry. * @idr: IDR handle. * @nextid: Pointer to an ID. * @@ -224,7 +224,7 @@ EXPORT_SYMBOL(idr_for_each); * to the ID of the found value. To use in a loop, the value pointed to by * nextid must be incremented by the user. */ -void *idr_get_next(struct idr *idr, int *nextid) +void *idr_get_next_ul(struct idr *idr, unsigned long *nextid) { struct radix_tree_iter iter; void __rcu **slot; @@ -245,18 +245,14 @@ void *idr_get_next(struct idr *idr, int *nextid) } if (!slot) return NULL; - id = iter.index + base; - - if (WARN_ON_ONCE(id > INT_MAX)) - return NULL; - *nextid = id; + *nextid = iter.index + base; return entry; } -EXPORT_SYMBOL(idr_get_next); +EXPORT_SYMBOL(idr_get_next_ul); /** - * idr_get_next_ul() - Find next populated entry. + * idr_get_next() - Find next populated entry. * @idr: IDR handle. * @nextid: Pointer to an ID. * @@ -265,22 +261,17 @@ EXPORT_SYMBOL(idr_get_next); * to the ID of the found value. To use in a loop, the value pointed to by * nextid must be incremented by the user. */ -void *idr_get_next_ul(struct idr *idr, unsigned long *nextid) +void *idr_get_next(struct idr *idr, int *nextid) { - struct radix_tree_iter iter; - void __rcu **slot; - unsigned long base = idr->idr_base; unsigned long id = *nextid; + void *entry = idr_get_next_ul(idr, &id); - id = (id < base) ? 0 : id - base; - slot = radix_tree_iter_find(&idr->idr_rt, &iter, id); - if (!slot) + if (WARN_ON_ONCE(id > INT_MAX)) return NULL; - - *nextid = iter.index + base; - return rcu_dereference_raw(*slot); + *nextid = id; + return entry; } -EXPORT_SYMBOL(idr_get_next_ul); +EXPORT_SYMBOL(idr_get_next); /** * idr_replace() - replace pointer for given ID. -- cgit v1.2.3 From b7e9728f3d7fc5c5c8508d99f1675212af5cfd49 Mon Sep 17 00:00:00 2001 From: "Matthew Wilcox (Oracle)" Date: Sat, 2 Nov 2019 00:25:08 -0400 Subject: idr: Fix idr_alloc_u32 on 32-bit systems Attempting to allocate an entry at 0xffffffff when one is already present would succeed in allocating one at 2^32, which would confuse everything. Return -ENOSPC in this case, as expected. Signed-off-by: Matthew Wilcox (Oracle) --- lib/radix-tree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/radix-tree.c b/lib/radix-tree.c index 18c1dfbb1765..c8fa1d274530 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c @@ -1529,7 +1529,7 @@ void __rcu **idr_get_free(struct radix_tree_root *root, offset = radix_tree_find_next_bit(node, IDR_FREE, offset + 1); start = next_index(start, node, offset); - if (start > max) + if (start > max || start == 0) return ERR_PTR(-ENOSPC); while (offset == RADIX_TREE_MAP_SIZE) { offset = node->offset + 1; -- cgit v1.2.3 From 5cbf2fff3bba8d3c6a4d47c1754de1cf57e2b01f Mon Sep 17 00:00:00 2001 From: Kevin Hao Date: Tue, 5 Nov 2019 21:16:57 -0800 Subject: dump_stack: avoid the livelock of the dump_lock In the current code, we use the atomic_cmpxchg() to serialize the output of the dump_stack(), but this implementation suffers the thundering herd problem. We have observed such kind of livelock on a Marvell cn96xx board(24 cpus) when heavily using the dump_stack() in a kprobe handler. Actually we can let the competitors to wait for the releasing of the lock before jumping to atomic_cmpxchg(). This will definitely mitigate the thundering herd problem. Thanks Linus for the suggestion. [akpm@linux-foundation.org: fix comment] Link: http://lkml.kernel.org/r/20191030031637.6025-1-haokexin@gmail.com Fixes: b58d977432c8 ("dump_stack: serialize the output from dump_stack()") Signed-off-by: Kevin Hao Suggested-by: Linus Torvalds Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- lib/dump_stack.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/dump_stack.c b/lib/dump_stack.c index 5cff72f18c4a..33ffbf308853 100644 --- a/lib/dump_stack.c +++ b/lib/dump_stack.c @@ -106,7 +106,12 @@ retry: was_locked = 1; } else { local_irq_restore(flags); - cpu_relax(); + /* + * Wait for the lock to release before jumping to + * atomic_cmpxchg() in order to mitigate the thundering herd + * problem. + */ + do { cpu_relax(); } while (atomic_read(&dump_lock) != -1); goto retry; } -- cgit v1.2.3 From 820b7c717f09ea5f024f2185e69e2847fd2851dd Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Sun, 10 Nov 2019 16:27:54 +0000 Subject: lib: Remove select of inexistant GENERIC_IO config option GENERIC_IO was removed but still selected by lib/kconfig This patch finish the cleaning. Fixes: 9de8da47742b ("kconfig: kill off GENERIC_IO option") Acked-by: Rob Herring Signed-off-by: Corentin Labbe Signed-off-by: Linus Torvalds --- lib/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'lib') diff --git a/lib/Kconfig b/lib/Kconfig index 183f92a297ca..3321d04dfa5a 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -447,7 +447,6 @@ config ASSOCIATIVE_ARRAY config HAS_IOMEM bool depends on !NO_IOMEM - select GENERIC_IO default y config HAS_IOPORT_MAP -- cgit v1.2.3 From 8e20ba2e53fc6198cbfbcc700e9f884157052a8d Mon Sep 17 00:00:00 2001 From: Lasse Collin Date: Fri, 15 Nov 2019 17:34:39 -0800 Subject: lib/xz: fix XZ_DYNALLOC to avoid useless memory reallocations s->dict.allocated was initialized to 0 but never set after a successful allocation, thus the code always thought that the dictionary buffer has to be reallocated. Link: http://lkml.kernel.org/r/20191104185107.3b6330df@tukaani.org Signed-off-by: Lasse Collin Reported-by: Yu Sun Acked-by: Daniel Walker Cc: "Yixia Si (yisi)" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- lib/xz/xz_dec_lzma2.c | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/xz/xz_dec_lzma2.c b/lib/xz/xz_dec_lzma2.c index 08c3c8049998..156f26fdc4c9 100644 --- a/lib/xz/xz_dec_lzma2.c +++ b/lib/xz/xz_dec_lzma2.c @@ -1146,6 +1146,7 @@ XZ_EXTERN enum xz_ret xz_dec_lzma2_reset(struct xz_dec_lzma2 *s, uint8_t props) if (DEC_IS_DYNALLOC(s->dict.mode)) { if (s->dict.allocated < s->dict.size) { + s->dict.allocated = s->dict.size; vfree(s->dict.buf); s->dict.buf = vmalloc(s->dict.size); if (s->dict.buf == NULL) { -- cgit v1.2.3