[PATCH 4.8 05/92] mm, frontswap: make sure allocated frontswap map is assigned

From: Greg Kroah-Hartman
Date: Thu Nov 17 2016 - 05:34:47 EST


4.8-stable review patch. If anyone has any objections, please let me know.

------------------

From: Vlastimil Babka <vbabka@xxxxxxx>

commit 5e322beefc8699b5747cfb35539a9496034e4296 upstream.

Christian Borntraeger reports:

With commit 8ea1d2a1985a ("mm, frontswap: convert frontswap_enabled to
static key") kmemleak complains about a memory leak in swapon

unreferenced object 0x3e09ba56000 (size 32112640):
comm "swapon", pid 7852, jiffies 4294968787 (age 1490.770s)
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:
__vmalloc_node_range+0x194/0x2d8
vzalloc+0x58/0x68
SyS_swapon+0xd60/0x12f8
system_call+0xd6/0x270

Turns out kmemleak is right. We now allocate the frontswap map
depending on the kernel config (and no longer on the enablement)

swapfile.c:
[...]
if (IS_ENABLED(CONFIG_FRONTSWAP))
frontswap_map = vzalloc(BITS_TO_LONGS(maxpages) * sizeof(long));

but later on this is passed along
--> enable_swap_info(p, prio, swap_map, cluster_info, frontswap_map);

and ignored if frontswap is disabled
--> frontswap_init(p->type, frontswap_map);

static inline void frontswap_init(unsigned type, unsigned long *map)
{
if (frontswap_enabled())
__frontswap_init(type, map);
}

Thing is, that frontswap map is never freed.

The leakage is relatively not that bad, because swapon is an infrequent
and privileged operation. However, if the first frontswap backend is
registered after a swap type has been already enabled, it will WARN_ON
in frontswap_register_ops() and frontswap will not be available for the
swap type.

Fix this by making sure the map is assigned by frontswap_init() as long
as CONFIG_FRONTSWAP is enabled.

Fixes: 8ea1d2a1985a ("mm, frontswap: convert frontswap_enabled to static key")
Link: http://lkml.kernel.org/r/20161026134220.2566-1-vbabka@xxxxxxx
Signed-off-by: Vlastimil Babka <vbabka@xxxxxxx>
Reported-by: Christian Borntraeger <borntraeger@xxxxxxxxxx>
Cc: Konrad Rzeszutek Wilk <konrad.wilk@xxxxxxxxxx>
Cc: Boris Ostrovsky <boris.ostrovsky@xxxxxxxxxx>
Cc: David Vrabel <david.vrabel@xxxxxxxxxx>
Cc: Juergen Gross <jgross@xxxxxxxx>
Cc: "Kirill A. Shutemov" <kirill.shutemov@xxxxxxxxxxxxxxx>
Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx>
Signed-off-by: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>

---
include/linux/frontswap.h | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

--- a/include/linux/frontswap.h
+++ b/include/linux/frontswap.h
@@ -106,8 +106,9 @@ static inline void frontswap_invalidate_

static inline void frontswap_init(unsigned type, unsigned long *map)
{
- if (frontswap_enabled())
- __frontswap_init(type, map);
+#ifdef CONFIG_FRONTSWAP
+ __frontswap_init(type, map);
+#endif
}

#endif /* _LINUX_FRONTSWAP_H */