diff options
| author | Matthew Wilcox (Oracle) <willy@infradead.org> | 2022-06-08 15:18:34 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2022-06-14 18:41:49 +0200 |
| commit | c0c84962e297927ba57fd6ddc2bb000c9d149655 (patch) | |
| tree | 53ae800e565589ad5410ee177753b0e719389c04 | |
| parent | 2e9d662a0492e5ffbcbe6fb37d6601529cd0944c (diff) | |
| download | linux-c0c84962e297927ba57fd6ddc2bb000c9d149655.tar.gz linux-c0c84962e297927ba57fd6ddc2bb000c9d149655.zip | |
mm/huge_memory: Fix xarray node memory leak
commit 69a37a8ba1b408a1c7616494aa7018e4b3844cbe upstream.
If xas_split_alloc() fails to allocate the necessary nodes to complete the
xarray entry split, it sets the xa_state to -ENOMEM, which xas_nomem()
then interprets as "Please allocate more memory", not as "Please free
any unnecessary memory" (which was the intended outcome). It's confusing
to use xas_nomem() to free memory in this context, so call xas_destroy()
instead.
Reported-by: syzbot+9e27a75a8c24f3fe75c1@syzkaller.appspotmail.com
Fixes: 6b24ca4a1a8d ("mm: Use multi-index entries in the page cache")
Cc: stable@vger.kernel.org
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
| -rw-r--r-- | include/linux/xarray.h | 1 | ||||
| -rw-r--r-- | lib/xarray.c | 5 | ||||
| -rw-r--r-- | mm/huge_memory.c | 3 |
3 files changed, 5 insertions, 4 deletions
diff --git a/include/linux/xarray.h b/include/linux/xarray.h index 66e28bc1a023..9409a3d26dfd 100644 --- a/include/linux/xarray.h +++ b/include/linux/xarray.h @@ -1506,6 +1506,7 @@ void *xas_find_marked(struct xa_state *, unsigned long max, xa_mark_t); void xas_init_marks(const struct xa_state *); bool xas_nomem(struct xa_state *, gfp_t); +void xas_destroy(struct xa_state *); void xas_pause(struct xa_state *); void xas_create_range(struct xa_state *); diff --git a/lib/xarray.c b/lib/xarray.c index 32e1669d5b64..276d56bd19a2 100644 --- a/lib/xarray.c +++ b/lib/xarray.c @@ -264,9 +264,10 @@ static void xa_node_free(struct xa_node *node) * xas_destroy() - Free any resources allocated during the XArray operation. * @xas: XArray operation state. * - * This function is now internal-only. + * Most users will not need to call this function; it is called for you + * by xas_nomem(). */ -static void xas_destroy(struct xa_state *xas) +void xas_destroy(struct xa_state *xas) { struct xa_node *next, *node = xas->xa_alloc; diff --git a/mm/huge_memory.c b/mm/huge_memory.c index fb9163691705..33be0864aeba 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -2736,8 +2736,7 @@ out_unlock: if (mapping) i_mmap_unlock_read(mapping); out: - /* Free any memory we didn't use */ - xas_nomem(&xas, 0); + xas_destroy(&xas); count_vm_event(!ret ? THP_SPLIT_PAGE : THP_SPLIT_PAGE_FAILED); return ret; } |
