mremap should return -ENOMEM when __vm_enough_memory fail
Subsystems (2)
PATCH 1/2 mremap should return -ENOMEM when __vm_enough_memory fail
Recently I straced bash behavior in this dd zero pipe to read test, in part of testing under vm.overcommit_memory=2 (OVERCOMMIT_NEVER mode):
# dd if=/dev/zero | read x
The bash sub shell is calling mremap to reallocate more and more memory untill it finally failed -ENOMEM (I expect), or to be killed by system OOM killer (which should not happen under OVERCOMMIT_NEVER mode); But the mremap system call actually failed of -EFAULT, which is a surprise to me, I think it's supposed to be -ENOMEM? then I wrote this piece of C code testing confirmed it:
https://gist.github.com/crquan/326bde37e1ddda8effe5
$ ./remap
allocated one page @0x7f686bf71000, (PAGE_SIZE: 4096)
grabbed 7680512000 bytes of memory (1875125 pages) @ 00007f6690993000.
mremap failed Bad address (14).The -EFAULT comes from the branch of security_vm_enough_memory_mm failure, underlyingly it calls __vm_enough_memory which returns only 0 for success or -ENOMEM; So why vma_to_resize needs to return -EFAULT in this case? this sounds like a mistake to me.
Some more digging into git history:
1) Before commit 119f657c7 in May 1 2005 (pre 2.6.12 days) it was returning -ENOMEM for this failure;
2) but commit 119f657c7 changed it accidentally, to what ever is preserved in local ret, which happened to be -EFAULT, in a previous assignment;
3) then in commit 54f5de709 code refactoring, it's explicitly returning -EFAULT, should be wrong.
--- mm/mremap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
mm/mremap.c +1 -1
@@ -375,7 +375,7 @@ static struct vm_area_struct *vma_to_resize(unsigned long addr,if (vma->vm_flags &VM_ACCOUNT ) {unsigned long charged = (new_len - old_len) >>PAGE_SHIFT ;if (security_vm_enough_memory_mm (mm, charged)) - goto Efault; + goto Enomem; *p = charged; }
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 2/2 clean up to just return ERR_PTR
--- mm/mremap.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-)
mm/mremap.c +8 -17
@@ -339,25 +339,25 @@ static struct vm_area_struct *vma_to_resize(unsigned long addr,struct vm_area_struct *vma =find_vma (mm, addr);if (!vma || vma->vm_start > addr) - goto Efault; +return ERR_PTR (-EFAULT );if (is_vm_hugetlb_page (vma)) - goto Einval; +return ERR_PTR (-EINVAL );/* We can't remap across vm area boundaries */ if (old_len > vma->vm_end - addr) - goto Efault; +return ERR_PTR (-EFAULT );/* Need to be careful about a growing mapping */ if (new_len > old_len) {unsigned long pgoff;if (vma->vm_flags & (VM_DONTEXPAND |VM_PFNMAP )) - goto Efault; +return ERR_PTR (-EFAULT ); pgoff = (addr - vma->vm_start) >>PAGE_SHIFT ; pgoff += vma->vm_pgoff;if (pgoff + (new_len >>PAGE_SHIFT ) < pgoff) - goto Einval; +return ERR_PTR (-EINVAL ); }if (vma->vm_flags &VM_LOCKED ) {
@@ -366,29 +366,20 @@ static struct vm_area_struct *vma_to_resize(unsigned long addr, lock_limit =rlimit (RLIMIT_MEMLOCK ); locked += new_len - old_len;if (locked > lock_limit && !capable (CAP_IPC_LOCK )) - goto Eagain; +return ERR_PTR (-EAGAIN ); }if (!may_expand_vm (mm, (new_len - old_len) >>PAGE_SHIFT )) - goto Enomem; +return ERR_PTR (-ENOMEM );if (vma->vm_flags &VM_ACCOUNT ) {unsigned long charged = (new_len - old_len) >>PAGE_SHIFT ;if (security_vm_enough_memory_mm (mm, charged)) - goto Enomem; +return ERR_PTR (-ENOMEM ); *p = charged; }return vma; - -Efault:/* very odd choice for most of the cases, but... */ -return ERR_PTR (-EFAULT ); -Einval: -return ERR_PTR (-EINVAL ); -Enomem: -return ERR_PTR (-ENOMEM ); -Eagain: -return ERR_PTR (-EAGAIN ); } static unsigned long mremap_to(unsigned long addr, unsigned long old_len,
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 2/2] clean up to just return ERR_PTR
Quoted 3 lines · On Tue, 17 Mar 2015, [email protected] wrote:
Signed-off-by Derek Che <[email protected]>Acked-by David Rientjes <[email protected]>
I don't believe Kirill ever acked this patch, you need to wait for the person to respond to your email with the line themself before you can add it to your commit message. Please see Documentation/SubmittingPatches.
He also suggested that this patch be done, so you need to add
You need a proper subject line for the patch, in this case it would be something like "mm, mremap: avoid unnecessary gotos in vma_to_resize()" and you also need a proper commit message such as:
The "goto"s in vma_to_resize() aren't necessary since they just return a specific value. Switch these statements to explicit return statements.
My acked-by was never given before this, but it can be added because it looks good:
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 30 lines · On Tue, 17 Mar 2015, [email protected] wrote:
Recently I straced bash behavior in this dd zero pipe to read test, in part of testing under vm.overcommit_memory=2 (
OVERCOMMIT_NEVERmode):# dd if=/dev/zero | read xThe bash sub shell is calling mremap to reallocate more and more memory untill it finally failed
-ENOMEM(I expect), or to be killed by system OOM killer (which should not happen underOVERCOMMIT_NEVERmode); But the mremap system call actually failed of-EFAULT, which is a surprise to me, I think it's supposed to be-ENOMEM? then I wrote this piece of C code testing confirmed it:
https://gist.github.com/crquan/326bde37e1ddda8effe5$ ./remap allocated one page @0x7f686bf71000, (PAGE_SIZE: 4096) grabbed 7680512000 bytes of memory (1875125 pages) @ 00007f6690993000. mremap failed Bad address (14).The
-EFAULTcomes from the branch ofsecurity_vm_enough_memory_mmfailure, underlyingly it calls__vm_enough_memorywhich returns only 0 for success or-ENOMEM; So whyvma_to_resizeneeds to return-EFAULTin this case? this sounds like a mistake to me.Some more digging into git history:
1) Before commit119f657c7in May 1 2005 (pre 2.6.12 days) it was returning-ENOMEMfor this failure;
2) but commit119f657c7changed it accidentally, to what ever is preserved in local ret, which happened to be-EFAULT, in a previous assignment;
3) then in commit54f5de709code refactoring, it's explicitly returning-EFAULT, should be wrong.
Quoted 3 lines
Signed-off-by Derek Che <[email protected]>Acked-by David Rientjes <[email protected]>
Did Kirill ack this patch?
Quoted 9 lines
--- mm/mremap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)mm/mremap.c +0
-0
mm/mremap.c static struct vm_area_struct *vma_to_resize(unsigned long addr, · line 380
Quoted 7 lines
mm/mremap.c +1
-1@@ -375,7 +375,7 @@ static struct vm_area_struct *vma_to_resize(unsigned long addr,if (vma->vm_flags &VM_ACCOUNT ) {unsigned long charged = (new_len - old_len) >>PAGE_SHIFT ;if (security_vm_enough_memory_mm (mm, charged)) - goto Efault; + goto Enomem; *p = charged; }
The patch is corrupted and won't apply because there aren't three lines after the changed line.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>