mm: move destroy_mm into mmap.c and remove len check
Subsystems (4)
RFC PATCH 1/2 mm: move destroy_mm into mmap.c and remove len check
Break do_munmap into two pieces, so we can avoid the check for > TASK_SIZE in destroy_mm(), when we trust the vmas are proper.
Really I wonder whether we can pull a lot more out of the fn used by destroy_mm: is there really a need to be looking whether we need to split vmas? We always send in one full vma at a time, so maybe we should just be calling detach_vmas_to_be_unmapped() and unmap_region() by hand?
this makes 32-bit tasks on x86-64 with COMPAT_VDSO work again. It also gets us passed the munmap -EINVAL when restart_64 restarts a 32-bit image and unloads its own 64-bit vmas.
(But there is still a
ckpt[2446] general protection ip:ffffe42f sp:ffc9304c error:0
with that case)
--- checkpoint/memory.c | 18 ------------------ include/linux/mm.h | 1 + mm/mmap.c | 38 ++++++++++++++++++++++++++++++++++---- 3 files changed, 35 insertions(+), 22 deletions(-)
checkpoint/memory.c +0 -18
@@ -1205,24 +1205,6 @@ static int restore_vma(struct ckpt_ctx *ctx, struct mm_struct *mm)return ret; } -static int destroy_mm (struct mm_struct *mm) -{ -struct vm_area_struct *vmnext = mm->mmap; -struct vm_area_struct *vma; -int ret; - -while (vmnext) { - vma = vmnext; - vmnext = vmnext->vm_next; - ret =do_munmap (mm, vma->vm_start, vma->vm_end-vma->vm_start); -if (ret <0 ) { -pr_warning ("c/r: failed do_munmap (%d)\n" , ret); -return ret; - } - } -return 0 ; -} -static struct mm_struct *do_restore_mm (struct ckpt_ctx *ctx) {struct ckpt_hdr_mm *h;
include/linux/mm.h +1 -0
@@ -1168,6 +1168,7 @@ out: }extern int do_munmap (struct mm_struct *,unsigned long ,size_t ); +extern int destroy_mm (struct mm_struct *);extern unsigned long do_brk (unsigned long ,unsigned long );
mm/mmap.c +34 -4
@@ -1890,14 +1890,11 @@ int split_vma(struct mm_struct * mm, struct vm_area_struct * vma,* work. This now handles partial unmappings. * Jeremy Fitzhardinge <[email protected]> */ -int do_munmap (struct mm_struct *mm,unsigned long start,size_t len) +int do_munmap_nocheck (struct mm_struct *mm,unsigned long start,size_t len) {unsigned long end;struct vm_area_struct *vma, *prev, *last; -if ((start & ~PAGE_MASK ) || start >TASK_SIZE || len >TASK_SIZE -start) -return -EINVAL ; -if ((len =PAGE_ALIGN (len)) ==0 )return -EINVAL ;
@@ -1961,8 +1958,41 @@ int do_munmap(struct mm_struct *mm, unsigned long start, size_t len)return 0 ; } +int do_munmap (struct mm_struct *mm,unsigned long start,size_t len) +{ +unsigned long end; +struct vm_area_struct *vma, *prev, *last; + +if ((start & ~PAGE_MASK ) || start >TASK_SIZE || len >TASK_SIZE -start) +return -EINVAL ; + +return do_munmap_nocheck (mm, start, len); +} +EXPORT_SYMBOL (do_munmap); +/* +* called with mm->mmap-sem held +* only called from checkpoint/memory.c:restore_mm() +*/ +int destroy_mm (struct mm_struct *mm) { +struct vm_area_struct *vmnext = mm->mmap; +struct vm_area_struct *vma; +int ret; + +while (vmnext) { + vma = vmnext; + vmnext = vmnext->vm_next; + ret =do_munmap_nocheck (mm, vma->vm_start, + vma->vm_end-vma->vm_start); +if (ret <0 ) { +pr_warning ("%s: failed munmap (%d)\n" , __func__, ret); +return ret; + } + } +return 0 ; +} + SYSCALL_DEFINE2(munmap, unsigned long, addr, size_t, len) {int ret;
Signature · 1 line
1.6.0.6
A message that is not in the archive (sent off-list or not yet received): 20100128042137.GA15723-r/[email protected]
PATCH 2/2 allow 32-bit restart of 64-bit and vice versa
--- arch/x86/kernel/checkpoint.c | 21 +++++---------------- 1 files changed, 5 insertions(+), 16 deletions(-)
arch/x86/kernel/checkpoint.c +5 -16
@@ -272,22 +272,11 @@ int restore_thread(struct ckpt_ctx *ctx)load_TLS (thread, cpu);put_cpu (); -#if defined(CONFIG_X86_64 ) - { -int pre, post; -/* -* Eventually we'd like to support mixed-bit restart, but for -* now don't pretend to. -*/ - pre =test_thread_flag (TIF_IA32 ); - post = h->thread_info_flags & _TIF_IA32; -if ((pre && !post) || (post && !pre)) { - ret = -EINVAL ; -ckpt_err (ctx, ret,"%d-bit restarting %d-bit\n" , - pre ?32 :64 , post ?32 :64 ); - goto out; - } - } +#if defined(CONFIG_X86_64 ) && defined(CONFIG_COMPAT ) +if (h->thread_info_flags & _TIF_IA32) +set_thread_flag (TIF_IA32 ); +else +clear_thread_flag (TIF_IA32 );#endif /* TODO: restore TIF flags as necessary (e.g. TIF_NOTSC) */
Signature · 1 line
1.6.0.6
Both applied, thanks.
Quoted 130 lines · Serge E. Hallyn
Break
do_munmapinto two pieces, so we can avoid the check for >TASK_SIZEindestroy_mm(), when we trust the vmas are proper.Really I wonder whether we can pull a lot more out of the fn used by
destroy_mm: is there really a need to be looking whether we need to split vmas? We always send in one full vma at a time, so maybe we should just be callingdetach_vmas_to_be_unmapped()andunmap_region()by hand?this makes 32-bit tasks on x86-64 with
COMPAT_VDSOwork again. It also gets us passed the munmap-EINVALwhenrestart_64restarts a 32-bit image and unloads its own 64-bit vmas.(But there is still a
ckpt[2446] general protection ip:ffffe42f sp:ffc9304c error:0with that case)
Signed-off-by Serge E. Hallyn <serue-r/[email protected]>--- checkpoint/memory.c | 18 ------------------ include/linux/mm.h | 1 + mm/mmap.c | 38 ++++++++++++++++++++++++++++++++++---- 3 files changed, 35 insertions(+), 22 deletions(-)checkpoint/memory.c +0
-18@@ -1205,24 +1205,6 @@ static int restore_vma(struct ckpt_ctx *ctx, struct mm_struct *mm)return ret; } -static int destroy_mm (struct mm_struct *mm) -{ -struct vm_area_struct *vmnext = mm->mmap; -struct vm_area_struct *vma; -int ret; - -while (vmnext) { - vma = vmnext; - vmnext = vmnext->vm_next; - ret =do_munmap (mm, vma->vm_start, vma->vm_end-vma->vm_start); -if (ret <0 ) { -pr_warning ("c/r: failed do_munmap (%d)\n" , ret); -return ret; - } - } -return 0 ; -} -static struct mm_struct *do_restore_mm (struct ckpt_ctx *ctx) {struct ckpt_hdr_mm *h;include/linux/mm.h +1
-0@@ -1168,6 +1168,7 @@ out: }extern int do_munmap (struct mm_struct *,unsigned long ,size_t ); +extern int destroy_mm (struct mm_struct *);extern unsigned long do_brk (unsigned long ,unsigned long );mm/mmap.c +34
-4@@ -1890,14 +1890,11 @@ int split_vma(struct mm_struct * mm, struct vm_area_struct * vma,* work. This now handles partial unmappings. * Jeremy Fitzhardinge <[email protected]> */ -int do_munmap (struct mm_struct *mm,unsigned long start,size_t len) +int do_munmap_nocheck (struct mm_struct *mm,unsigned long start,size_t len) {unsigned long end;struct vm_area_struct *vma, *prev, *last; -if ((start & ~PAGE_MASK ) || start >TASK_SIZE || len >TASK_SIZE -start) -return -EINVAL ; -if ((len =PAGE_ALIGN (len)) ==0 )return -EINVAL ;@@ -1961,8 +1958,41 @@ int do_munmap(struct mm_struct *mm, unsigned long start, size_t len)return 0 ; } +int do_munmap (struct mm_struct *mm,unsigned long start,size_t len) +{ +unsigned long end; +struct vm_area_struct *vma, *prev, *last; + +if ((start & ~PAGE_MASK ) || start >TASK_SIZE || len >TASK_SIZE -start) +return -EINVAL ; + +return do_munmap_nocheck (mm, start, len); +} +EXPORT_SYMBOL (do_munmap); +/* +* called with mm->mmap-sem held +* only called from checkpoint/memory.c:restore_mm() +*/ +int destroy_mm (struct mm_struct *mm) { +struct vm_area_struct *vmnext = mm->mmap; +struct vm_area_struct *vma; +int ret; + +while (vmnext) { + vma = vmnext; + vmnext = vmnext->vm_next; + ret =do_munmap_nocheck (mm, vma->vm_start, + vma->vm_end-vma->vm_start); +if (ret <0 ) { +pr_warning ("%s: failed munmap (%d)\n" , __func__, ret); +return ret; + } + } +return 0 ; +} + SYSCALL_DEFINE2(munmap, unsigned long, addr, size_t, len) {int ret;