[PATCH v2 1/2] mm/vmalloc: Add a safer version of find_vm_area() for debug

From: Joel Fernandes (Google)
Date: Thu Aug 31 2023 - 13:18:36 EST


It is unsafe to dump vmalloc area information when trying to do so from
some contexts. Add a safer trylock version of the same function to do a
best-effort VMA finding and use it from vmalloc_dump_obj().

[apply test robot feedback on unused function fix.]

Reported-by: Zhen Lei <thunder.leizhen@xxxxxxxxxxxxxxx>
Cc: Paul E. McKenney <paulmck@xxxxxxxxxx>
Cc: rcu@xxxxxxxxxxxxxxx
Cc: Zqiang <qiang.zhang1211@xxxxxxxxx>
Reviewed-by: Matthew Wilcox (Oracle) <willy@xxxxxxxxxxxxx>
Signed-off-by: Joel Fernandes (Google) <joel@xxxxxxxxxxxxxxxxx>
---
v1->v2: Apply review tags and test robot feedback.

mm/vmalloc.c | 39 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 38 insertions(+), 1 deletion(-)

diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 93cf99aba335..f09e882ae3b8 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -1865,6 +1865,20 @@ struct vmap_area *find_vmap_area(unsigned long addr)
return va;
}

+#ifdef CONFIG_PRINTK
+static struct vmap_area *find_vmap_area_trylock(unsigned long addr)
+{
+ struct vmap_area *va;
+
+ if (!spin_trylock(&vmap_area_lock))
+ return NULL;
+ va = __find_vmap_area(addr, &vmap_area_root);
+ spin_unlock(&vmap_area_lock);
+
+ return va;
+}
+#endif
+
static struct vmap_area *find_unlink_vmap_area(unsigned long addr)
{
struct vmap_area *va;
@@ -2671,6 +2685,29 @@ struct vm_struct *find_vm_area(const void *addr)
return va->vm;
}

+/**
+ * try_to_find_vm_area - find a continuous kernel virtual area
+ * @addr: base address
+ *
+ * This function is the same as find_vm_area() except that it is
+ * safe to call if vmap_area_lock is already held and returns NULL
+ * if it is. See comments in find_vmap_area() for other details.
+ *
+ * Return: the area descriptor on success or %NULL on failure.
+ */
+#ifdef CONFIG_PRINTK
+static struct vm_struct *try_to_find_vm_area(const void *addr)
+{
+ struct vmap_area *va;
+
+ va = find_vmap_area_trylock((unsigned long)addr);
+ if (!va)
+ return NULL;
+
+ return va->vm;
+}
+#endif
+
/**
* remove_vm_area - find and remove a continuous kernel virtual area
* @addr: base address
@@ -4277,7 +4314,7 @@ bool vmalloc_dump_obj(void *object)
struct vm_struct *vm;
void *objp = (void *)PAGE_ALIGN((unsigned long)object);

- vm = find_vm_area(objp);
+ vm = try_to_find_vm_area(objp);
if (!vm)
return false;
pr_cont(" %u-page vmalloc region starting at %#lx allocated at %pS\n",
--
2.42.0.rc2.253.gd59a3bf2b4-goog