]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
mm/huge_memory: Fix xarray node memory leak
authorMatthew Wilcox (Oracle) <willy@infradead.org>
Wed, 8 Jun 2022 19:18:34 +0000 (15:18 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 14 Jun 2022 16:41:49 +0000 (18:41 +0200)
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>
include/linux/xarray.h
lib/xarray.c
mm/huge_memory.c

index 66e28bc1a023f3a9974183cca231749d25476fd8..9409a3d26dfd641ba95955c05ae6ca5e41e88588 100644 (file)
@@ -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 *);
index 32e1669d5b649b1d33a2ebb041d0313a38c0aa63..276d56bd19a20de27cf3aa693e639915095cba2a 100644 (file)
@@ -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;
 
index fb916369170575fd0660d8603e657403f1f3e9f9..33be0864aebae76f25180b910979eb535af11f92 100644 (file)
@@ -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;
 }