Commit 9119d6c2 authored by Lorenzo Stoakes's avatar Lorenzo Stoakes Committed by Andrew Morton
Browse files

mm: update vma_modify_flags() to handle residual flags, document

The vma_modify_*() family of functions each either perform splits, a merge
or no changes at all in preparation for the requested modification to
occur.

When doing so for a VMA flags change, we currently don't account for any
flags which may remain (for instance, VM_SOFTDIRTY) despite the requested
change in the case that a merge succeeded.

This is made more important by subsequent patches which will introduce the
concept of sticky VMA flags which rely on this behaviour.

This patch fixes this by passing the VMA flags parameter as a pointer and
updating it accordingly on merge and updating callers to accommodate for
this.

Additionally, while we are here, we add kdocs for each of the
vma_modify_*() functions, as the fact that the requested modification is
not performed is confusing so it is useful to make this abundantly clear.

We also update the VMA userland tests to account for this change.

Link: https://lkml.kernel.org/r/23b5b549b0eaefb2922625626e58c2a352f3e93c.1763460113.git.lorenzo.stoakes@oracle.com


Signed-off-by: default avatarLorenzo Stoakes <lorenzo.stoakes@oracle.com>
Reviewed-by: default avatarPedro Falcato <pfalcato@suse.de>
Reviewed-by: default avatarVlastimil Babka <vbabka@suse.cz>
Cc: Andrei Vagin <avagin@gmail.com>
Cc: Baolin Wang <baolin.wang@linux.alibaba.com>
Cc: Barry Song <baohua@kernel.org>
Cc: David Hildenbrand (Red Hat) <david@kernel.org>
Cc: Dev Jain <dev.jain@arm.com>
Cc: Jann Horn <jannh@google.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Lance Yang <lance.yang@linux.dev>
Cc: Liam Howlett <liam.howlett@oracle.com>
Cc: "Masami Hiramatsu (Google)" <mhiramat@kernel.org>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Nico Pache <npache@redhat.com>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Zi Yan <ziy@nvidia.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent 56882250
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -167,7 +167,7 @@ static int madvise_update_vma(vm_flags_t new_flags,
			range->start, range->end, anon_name);
	else
		vma = vma_modify_flags(&vmi, madv_behavior->prev, vma,
			range->start, range->end, new_flags);
			range->start, range->end, &new_flags);

	if (IS_ERR(vma))
		return PTR_ERR(vma);
+1 −1
Original line number Diff line number Diff line
@@ -478,7 +478,7 @@ static int mlock_fixup(struct vma_iterator *vmi, struct vm_area_struct *vma,
		/* don't set VM_LOCKED or VM_LOCKONFAULT and don't count */
		goto out;

	vma = vma_modify_flags(vmi, *prev, vma, start, end, newflags);
	vma = vma_modify_flags(vmi, *prev, vma, start, end, &newflags);
	if (IS_ERR(vma)) {
		ret = PTR_ERR(vma);
		goto out;
+1 −1
Original line number Diff line number Diff line
@@ -756,7 +756,7 @@ mprotect_fixup(struct vma_iterator *vmi, struct mmu_gather *tlb,
		newflags &= ~VM_ACCOUNT;
	}

	vma = vma_modify_flags(vmi, *pprev, vma, start, end, newflags);
	vma = vma_modify_flags(vmi, *pprev, vma, start, end, &newflags);
	if (IS_ERR(vma)) {
		error = PTR_ERR(vma);
		goto fail;
+5 −4
Original line number Diff line number Diff line
@@ -66,12 +66,13 @@ static int mseal_apply(struct mm_struct *mm,
		prev = vma;

	for_each_vma_range(vmi, vma, end) {
		unsigned long curr_end = MIN(vma->vm_end, end);
		const unsigned long curr_end = MIN(vma->vm_end, end);

		if (!(vma->vm_flags & VM_SEALED)) {
			vma = vma_modify_flags(&vmi, prev, vma,
					curr_start, curr_end,
					vma->vm_flags | VM_SEALED);
			vm_flags_t vm_flags = vma->vm_flags | VM_SEALED;

			vma = vma_modify_flags(&vmi, prev, vma, curr_start,
					       curr_end, &vm_flags);
			if (IS_ERR(vma))
				return PTR_ERR(vma);
			vm_flags_set(vma, VM_SEALED);
+30 −26
Original line number Diff line number Diff line
@@ -1638,24 +1638,34 @@ static struct vm_area_struct *vma_modify(struct vma_merge_struct *vmg)
	return vma;
}

struct vm_area_struct *vma_modify_flags(
	struct vma_iterator *vmi, struct vm_area_struct *prev,
	struct vm_area_struct *vma, unsigned long start, unsigned long end,
	vm_flags_t vm_flags)
struct vm_area_struct *vma_modify_flags(struct vma_iterator *vmi,
		struct vm_area_struct *prev, struct vm_area_struct *vma,
		unsigned long start, unsigned long end,
		vm_flags_t *vm_flags_ptr)
{
	VMG_VMA_STATE(vmg, vmi, prev, vma, start, end);
	const vm_flags_t vm_flags = *vm_flags_ptr;
	struct vm_area_struct *ret;

	vmg.vm_flags = vm_flags;

	return vma_modify(&vmg);
	ret = vma_modify(&vmg);
	if (IS_ERR(ret))
		return ret;

	/*
	 * For a merge to succeed, the flags must match those requested. For
	 * flags which do not obey typical merge rules (i.e. do not need to
	 * match), we must let the caller know about them.
	 */
	if (vmg.state == VMA_MERGE_SUCCESS)
		*vm_flags_ptr = ret->vm_flags;
	return ret;
}

struct vm_area_struct
*vma_modify_name(struct vma_iterator *vmi,
		       struct vm_area_struct *prev,
		       struct vm_area_struct *vma,
		       unsigned long start,
		       unsigned long end,
struct vm_area_struct *vma_modify_name(struct vma_iterator *vmi,
		struct vm_area_struct *prev, struct vm_area_struct *vma,
		unsigned long start, unsigned long end,
		struct anon_vma_name *new_name)
{
	VMG_VMA_STATE(vmg, vmi, prev, vma, start, end);
@@ -1665,10 +1675,8 @@ struct vm_area_struct
	return vma_modify(&vmg);
}

struct vm_area_struct
*vma_modify_policy(struct vma_iterator *vmi,
		   struct vm_area_struct *prev,
		   struct vm_area_struct *vma,
struct vm_area_struct *vma_modify_policy(struct vma_iterator *vmi,
		struct vm_area_struct *prev, struct vm_area_struct *vma,
		unsigned long start, unsigned long end,
		struct mempolicy *new_pol)
{
@@ -1679,14 +1687,10 @@ struct vm_area_struct
	return vma_modify(&vmg);
}

struct vm_area_struct
*vma_modify_flags_uffd(struct vma_iterator *vmi,
		       struct vm_area_struct *prev,
		       struct vm_area_struct *vma,
		       unsigned long start, unsigned long end,
		       vm_flags_t vm_flags,
		       struct vm_userfaultfd_ctx new_ctx,
		       bool give_up_on_oom)
struct vm_area_struct *vma_modify_flags_uffd(struct vma_iterator *vmi,
		struct vm_area_struct *prev, struct vm_area_struct *vma,
		unsigned long start, unsigned long end, vm_flags_t vm_flags,
		struct vm_userfaultfd_ctx new_ctx, bool give_up_on_oom)
{
	VMG_VMA_STATE(vmg, vmi, prev, vma, start, end);

Loading