#include <linux/file.h>
#include <linux/fdtable.h>
#include <linux/mm.h>
+#include <linux/maple_tree.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/swap.h>
unsigned long new_start = old_start - shift;
unsigned long new_end = old_end - shift;
VMA_ITERATOR(vmi, mm, new_start);
- struct vm_area_struct *next;
+ struct vm_area_struct *next, *new_vma;
struct mmu_gather tlb;
+ MA_STATE(mas, &mm->mm_mt, new_start, new_start);
BUG_ON(new_start > new_end);
if (vma != vma_next(&vmi))
return -EFAULT;
+ if (mas_preallocate(&mas, vma, GFP_KERNEL))
+ return -ENOMEM;
/*
* cover the whole range: [new_start, old_end)
*/
- if (vma_adjust(vma, new_start, old_end, vma->vm_pgoff, NULL))
+ if (vma_expand(&mas, vma, new_start, old_end, vma->vm_pgoff, vma))
return -ENOMEM;
/*
*/
if (length != move_page_tables(vma, old_start,
vma, new_start, length, false))
- return -ENOMEM;
+ goto pt_move_failed;
lru_add_drain();
tlb_gather_mmu(&tlb, mm);
}
tlb_finish_mmu(&tlb);
+ if (sub_vma(mm, vma, &new_vma, new_start, new_end))
+ goto sub_vma_failed;
+
/*
* Shrink the vma to just the new range. Always succeeds.
*/
- vma_adjust(vma, new_start, new_end, vma->vm_pgoff, NULL);
+ vma_mas_store(new_vma, &mas);
+ vma_mas_szero(&mas, new_end, old_end);
return 0;
+
+sub_vma_failed:
+pt_move_failed:
+ mas_destroy(&mas);
+
+ return -ENOMEM;
}
/*
extern int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin);
extern int vma_adjust(struct vm_area_struct *vma, unsigned long start,
unsigned long end, pgoff_t pgoff, struct vm_area_struct *expand);
+inline int vma_expand(struct ma_state *mas, struct vm_area_struct *vma,
+ unsigned long start, unsigned long end, pgoff_t pgoff,
+ struct vm_area_struct *next);
+inline void vma_mas_szero(struct ma_state *mas, unsigned long start,
+ unsigned long end);
+inline void vma_mas_store(struct vm_area_struct *vma, struct ma_state *mas);
+int sub_vma(struct mm_struct *mm, struct vm_area_struct *vma,
+ struct vm_area_struct **new_vma, unsigned long start, unsigned long end);
+
extern struct vm_area_struct *vma_merge(struct mm_struct *,
struct vm_area_struct *prev, unsigned long addr, unsigned long end,
unsigned long vm_flags, struct anon_vma *, struct file *, pgoff_t,
* @start: The start address to zero
* @end: The end address to zero.
*/
-static inline void vma_mas_szero(struct ma_state *mas, unsigned long start,
+inline void vma_mas_szero(struct ma_state *mas, unsigned long start,
unsigned long end)
{
trace_vma_mas_szero(mas->tree, start, end - 1);