mm: abstract vma_expand() to use vma_merge_struct
The purpose of the vmg is to thread merge state through functions and avoid egregious parameter lists. We expand this to vma_expand(), which is used for a number of merge cases. Accordingly, adjust its callers, mmap_region() and relocate_vma_down(), to use a vmg. An added purpose of this change is the ability in a future commit to perform all new VMA range merging using vma_expand(). Link: https://lkml.kernel.org/r/4bc8c9dbc9ca52452ef8e587b28fe555854ceb38.1725040657.git.lorenzo.stoakes@oracle.com Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com> Reviewed-by: Liam R. Howlett <Liam.Howlett@oracle.com> Cc: Mark Brown <broonie@kernel.org> Cc: Vlastimil Babka <vbabka@suse.cz> Cc: Bert Karwatzki <spasswolf@web.de> Cc: Jeff Xu <jeffxu@chromium.org> Cc: Jiri Olsa <olsajiri@gmail.com> Cc: Kees Cook <kees@kernel.org> Cc: Lorenzo Stoakes <lstoakes@gmail.com> Cc: Matthew Wilcox <willy@infradead.org> Cc: "Paul E. McKenney" <paulmck@kernel.org> Cc: Paul Moore <paul@paul-moore.com> Cc: Sidhartha Kumar <sidhartha.kumar@oracle.com> Cc: Suren Baghdasaryan <surenb@google.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
parent
3e01310d29
commit
fc21959f74
15
mm/mmap.c
15
mm/mmap.c
@ -1371,7 +1371,6 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
|
|||||||
struct ma_state mas_detach;
|
struct ma_state mas_detach;
|
||||||
struct maple_tree mt_detach;
|
struct maple_tree mt_detach;
|
||||||
unsigned long end = addr + len;
|
unsigned long end = addr + len;
|
||||||
unsigned long merge_start = addr, merge_end = end;
|
|
||||||
bool writable_file_mapping = false;
|
bool writable_file_mapping = false;
|
||||||
int error = -ENOMEM;
|
int error = -ENOMEM;
|
||||||
VMA_ITERATOR(vmi, mm, addr);
|
VMA_ITERATOR(vmi, mm, addr);
|
||||||
@ -1424,8 +1423,8 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
|
|||||||
/* Attempt to expand an old mapping */
|
/* Attempt to expand an old mapping */
|
||||||
/* Check next */
|
/* Check next */
|
||||||
if (next && next->vm_start == end && can_vma_merge_before(&vmg)) {
|
if (next && next->vm_start == end && can_vma_merge_before(&vmg)) {
|
||||||
merge_end = next->vm_end;
|
vmg.end = next->vm_end;
|
||||||
vma = next;
|
vma = vmg.vma = next;
|
||||||
vmg.pgoff = next->vm_pgoff - pglen;
|
vmg.pgoff = next->vm_pgoff - pglen;
|
||||||
/*
|
/*
|
||||||
* We set this here so if we will merge with the previous VMA in
|
* We set this here so if we will merge with the previous VMA in
|
||||||
@ -1438,15 +1437,15 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
|
|||||||
|
|
||||||
/* Check prev */
|
/* Check prev */
|
||||||
if (prev && prev->vm_end == addr && can_vma_merge_after(&vmg)) {
|
if (prev && prev->vm_end == addr && can_vma_merge_after(&vmg)) {
|
||||||
merge_start = prev->vm_start;
|
vmg.start = prev->vm_start;
|
||||||
vma = prev;
|
vma = vmg.vma = prev;
|
||||||
vmg.pgoff = prev->vm_pgoff;
|
vmg.pgoff = prev->vm_pgoff;
|
||||||
vma_prev(&vmi); /* Equivalent to going to the previous range */
|
vma_prev(&vmi); /* Equivalent to going to the previous range */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vma) {
|
if (vma) {
|
||||||
/* Actually expand, if possible */
|
/* Actually expand, if possible */
|
||||||
if (!vma_expand(&vmi, vma, merge_start, merge_end, vmg.pgoff, next)) {
|
if (!vma_expand(&vmg)) {
|
||||||
khugepaged_enter_vma(vma, vm_flags);
|
khugepaged_enter_vma(vma, vm_flags);
|
||||||
goto expanded;
|
goto expanded;
|
||||||
}
|
}
|
||||||
@ -2320,6 +2319,7 @@ int relocate_vma_down(struct vm_area_struct *vma, unsigned long shift)
|
|||||||
unsigned long new_start = old_start - shift;
|
unsigned long new_start = old_start - shift;
|
||||||
unsigned long new_end = old_end - shift;
|
unsigned long new_end = old_end - shift;
|
||||||
VMA_ITERATOR(vmi, mm, new_start);
|
VMA_ITERATOR(vmi, mm, new_start);
|
||||||
|
VMG_STATE(vmg, mm, &vmi, new_start, old_end, 0, vma->vm_pgoff);
|
||||||
struct vm_area_struct *next;
|
struct vm_area_struct *next;
|
||||||
struct mmu_gather tlb;
|
struct mmu_gather tlb;
|
||||||
|
|
||||||
@ -2336,7 +2336,8 @@ int relocate_vma_down(struct vm_area_struct *vma, unsigned long shift)
|
|||||||
/*
|
/*
|
||||||
* cover the whole range: [new_start, old_end)
|
* cover the whole range: [new_start, old_end)
|
||||||
*/
|
*/
|
||||||
if (vma_expand(&vmi, vma, new_start, old_end, vma->vm_pgoff, NULL))
|
vmg.vma = vma;
|
||||||
|
if (vma_expand(&vmg))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
39
mm/vma.c
39
mm/vma.c
@ -467,30 +467,25 @@ void validate_mm(struct mm_struct *mm)
|
|||||||
/*
|
/*
|
||||||
* vma_expand - Expand an existing VMA
|
* vma_expand - Expand an existing VMA
|
||||||
*
|
*
|
||||||
* @vmi: The vma iterator
|
* @vmg: Describes a VMA expansion operation.
|
||||||
* @vma: The vma to expand
|
|
||||||
* @start: The start of the vma
|
|
||||||
* @end: The exclusive end of the vma
|
|
||||||
* @pgoff: The page offset of vma
|
|
||||||
* @next: The current of next vma.
|
|
||||||
*
|
*
|
||||||
* Expand @vma to @start and @end. Can expand off the start and end. Will
|
* Expand @vma to vmg->start and vmg->end. Can expand off the start and end.
|
||||||
* expand over @next if it's different from @vma and @end == @next->vm_end.
|
* Will expand over vmg->next if it's different from vmg->vma and vmg->end ==
|
||||||
* Checking if the @vma can expand and merge with @next needs to be handled by
|
* vmg->next->vm_end. Checking if the vmg->vma can expand and merge with
|
||||||
* the caller.
|
* vmg->next needs to be handled by the caller.
|
||||||
*
|
*
|
||||||
* Returns: 0 on success
|
* Returns: 0 on success
|
||||||
*/
|
*/
|
||||||
int vma_expand(struct vma_iterator *vmi, struct vm_area_struct *vma,
|
int vma_expand(struct vma_merge_struct *vmg)
|
||||||
unsigned long start, unsigned long end, pgoff_t pgoff,
|
|
||||||
struct vm_area_struct *next)
|
|
||||||
{
|
{
|
||||||
struct vm_area_struct *anon_dup = NULL;
|
struct vm_area_struct *anon_dup = NULL;
|
||||||
bool remove_next = false;
|
bool remove_next = false;
|
||||||
|
struct vm_area_struct *vma = vmg->vma;
|
||||||
|
struct vm_area_struct *next = vmg->next;
|
||||||
struct vma_prepare vp;
|
struct vma_prepare vp;
|
||||||
|
|
||||||
vma_start_write(vma);
|
vma_start_write(vma);
|
||||||
if (next && (vma != next) && (end == next->vm_end)) {
|
if (next && (vma != next) && (vmg->end == next->vm_end)) {
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
remove_next = true;
|
remove_next = true;
|
||||||
@ -503,21 +498,21 @@ int vma_expand(struct vma_iterator *vmi, struct vm_area_struct *vma,
|
|||||||
init_multi_vma_prep(&vp, vma, NULL, remove_next ? next : NULL, NULL);
|
init_multi_vma_prep(&vp, vma, NULL, remove_next ? next : NULL, NULL);
|
||||||
/* Not merging but overwriting any part of next is not handled. */
|
/* Not merging but overwriting any part of next is not handled. */
|
||||||
VM_WARN_ON(next && !vp.remove &&
|
VM_WARN_ON(next && !vp.remove &&
|
||||||
next != vma && end > next->vm_start);
|
next != vma && vmg->end > next->vm_start);
|
||||||
/* Only handles expanding */
|
/* Only handles expanding */
|
||||||
VM_WARN_ON(vma->vm_start < start || vma->vm_end > end);
|
VM_WARN_ON(vma->vm_start < vmg->start || vma->vm_end > vmg->end);
|
||||||
|
|
||||||
/* Note: vma iterator must be pointing to 'start' */
|
/* Note: vma iterator must be pointing to 'start' */
|
||||||
vma_iter_config(vmi, start, end);
|
vma_iter_config(vmg->vmi, vmg->start, vmg->end);
|
||||||
if (vma_iter_prealloc(vmi, vma))
|
if (vma_iter_prealloc(vmg->vmi, vma))
|
||||||
goto nomem;
|
goto nomem;
|
||||||
|
|
||||||
vma_prepare(&vp);
|
vma_prepare(&vp);
|
||||||
vma_adjust_trans_huge(vma, start, end, 0);
|
vma_adjust_trans_huge(vma, vmg->start, vmg->end, 0);
|
||||||
vma_set_range(vma, start, end, pgoff);
|
vma_set_range(vma, vmg->start, vmg->end, vmg->pgoff);
|
||||||
vma_iter_store(vmi, vma);
|
vma_iter_store(vmg->vmi, vma);
|
||||||
|
|
||||||
vma_complete(&vp, vmi, vma->vm_mm);
|
vma_complete(&vp, vmg->vmi, vma->vm_mm);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
nomem:
|
nomem:
|
||||||
|
5
mm/vma.h
5
mm/vma.h
@ -128,10 +128,7 @@ void init_vma_prep(struct vma_prepare *vp,
|
|||||||
void vma_complete(struct vma_prepare *vp,
|
void vma_complete(struct vma_prepare *vp,
|
||||||
struct vma_iterator *vmi, struct mm_struct *mm);
|
struct vma_iterator *vmi, struct mm_struct *mm);
|
||||||
|
|
||||||
int vma_expand(struct vma_iterator *vmi, struct vm_area_struct *vma,
|
int vma_expand(struct vma_merge_struct *vmg);
|
||||||
unsigned long start, unsigned long end, pgoff_t pgoff,
|
|
||||||
struct vm_area_struct *next);
|
|
||||||
|
|
||||||
int vma_shrink(struct vma_iterator *vmi, struct vm_area_struct *vma,
|
int vma_shrink(struct vma_iterator *vmi, struct vm_area_struct *vma,
|
||||||
unsigned long start, unsigned long end, pgoff_t pgoff);
|
unsigned long start, unsigned long end, pgoff_t pgoff);
|
||||||
|
|
||||||
|
@ -121,8 +121,7 @@ static struct vm_area_struct *merge_existing(struct vma_merge_struct *vmg)
|
|||||||
*/
|
*/
|
||||||
static int expand_existing(struct vma_merge_struct *vmg)
|
static int expand_existing(struct vma_merge_struct *vmg)
|
||||||
{
|
{
|
||||||
return vma_expand(vmg->vmi, vmg->vma, vmg->start, vmg->end, vmg->pgoff,
|
return vma_expand(vmg);
|
||||||
vmg->next);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user