[PATCH 1/3] drivers/char/mem: eliminate unnecessary use of success_hook
From: Lorenzo Stoakes
Date: Thu May 21 2026 - 13:07:02 EST
Introduce vma_desc_set_anonymous() and invoke it from mmap_zero_prepare()
in order to eliminate the use of the mmap_action->success_hook.
Note that file-backed VMAs default to vma->vm_ops == dummy_vm_ops, so if an
mmap or mmap_prepare hook does not set desc->vm_ops, the VMA will remain
file-backed.
We also update set_vma_user_defined_fields() to make clear that we are
either setting vma->vm_ops to what is provided by the driver (or defaulting
to dummy_vm_ops if not set), or setting the VMA anonymous.
This lays the groundwork for removing the success hook, which was provided
as a workaround for drivers (mostly, hugetlb) that still absolutely seemed
to rely upon having access to a VMA pointer.
However, for the transition to be useful, we really must eliminate this and
make no exceptions, otherwise drivers can simply work around it.
Signed-off-by: Lorenzo Stoakes <ljs@xxxxxxxxxx>
---
drivers/char/mem.c | 17 +++++------------
include/linux/mm.h | 5 +++++
mm/vma.c | 2 ++
3 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 5fd421e48c04..a4297eb39887 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -504,17 +504,6 @@ static ssize_t read_zero(struct file *file, char __user *buf,
return cleared;
}
-static int mmap_zero_private_success(const struct vm_area_struct *vma)
-{
- /*
- * This is a highly unique situation where we mark a MAP_PRIVATE mapping
- * of /dev/zero anonymous, despite it not being.
- */
- vma_set_anonymous((struct vm_area_struct *)vma);
-
- return 0;
-}
-
static int mmap_zero_prepare(struct vm_area_desc *desc)
{
#ifndef CONFIG_MMU
@@ -523,7 +512,11 @@ static int mmap_zero_prepare(struct vm_area_desc *desc)
if (vma_desc_test(desc, VMA_SHARED_BIT))
return shmem_zero_setup_desc(desc);
- desc->action.success_hook = mmap_zero_private_success;
+ /*
+ * This is a highly unique situation where we mark a MAP_PRIVATE mapping
+ * of /dev/zero anonymous, despite it not being.
+ */
+ vma_desc_set_anonymous(desc);
return 0;
}
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 9cedc5e75aa9..2138c86403f5 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1489,6 +1489,11 @@ static inline void vma_set_anonymous(struct vm_area_struct *vma)
vma->vm_ops = NULL;
}
+static inline void vma_desc_set_anonymous(struct vm_area_desc *desc)
+{
+ desc->vm_ops = NULL;
+}
+
static inline bool vma_is_anonymous(struct vm_area_struct *vma)
{
return !vma->vm_ops;
diff --git a/mm/vma.c b/mm/vma.c
index d90791b00a7b..07486390c692 100644
--- a/mm/vma.c
+++ b/mm/vma.c
@@ -2697,6 +2697,8 @@ static void set_vma_user_defined_fields(struct vm_area_struct *vma,
{
if (map->vm_ops)
vma->vm_ops = map->vm_ops;
+ else /* Only /dev/zero should do this. */
+ vma_set_anonymous(vma);
vma->vm_private_data = map->vm_private_data;
}
--
2.54.0