aboutsummaryrefslogtreecommitdiffstats
path: root/mm/mmap.c
diff options
context:
space:
mode:
authorKOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>2009-12-14 20:57:56 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-12-15 11:53:11 -0500
commit659ace584e7a9fdda872eab4d6d7be1e0afb6cae (patch)
treee9d8ca3d7429bfa48e823a6f105d76254e34daf0 /mm/mmap.c
parentbb86a7338b7a864c03e1736a8d370b10254b0300 (diff)
mmap: don't return ENOMEM when mapcount is temporarily exceeded in munmap()
On ia64, the following test program exit abnormally, because glibc thread library called abort(). ======================================================== (gdb) bt #0 0xa000000000010620 in __kernel_syscall_via_break () #1 0x20000000003208e0 in raise () from /lib/libc.so.6.1 #2 0x2000000000324090 in abort () from /lib/libc.so.6.1 #3 0x200000000027c3e0 in __deallocate_stack () from /lib/libpthread.so.0 #4 0x200000000027f7c0 in start_thread () from /lib/libpthread.so.0 #5 0x200000000047ef60 in __clone2 () from /lib/libc.so.6.1 ======================================================== The fact is, glibc call munmap() when thread exitng time for freeing stack, and it assume munlock() never fail. However, munmap() often make vma splitting and it with many mapcount make -ENOMEM. Oh well, that's crazy, because stack unmapping never increase mapcount. The maxcount exceeding is only temporary. internal temporary exceeding shouldn't make ENOMEM. This patch does it. test_max_mapcount.c ================================================================== #include<stdio.h> #include<stdlib.h> #include<string.h> #include<pthread.h> #include<errno.h> #include<unistd.h> #define THREAD_NUM 30000 #define MAL_SIZE (8*1024*1024) void *wait_thread(void *args) { void *addr; addr = malloc(MAL_SIZE); sleep(10); return NULL; } void *wait_thread2(void *args) { sleep(60); return NULL; } int main(int argc, char *argv[]) { int i; pthread_t thread[THREAD_NUM], th; int ret, count = 0; pthread_attr_t attr; ret = pthread_attr_init(&attr); if(ret) { perror("pthread_attr_init"); } ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); if(ret) { perror("pthread_attr_setdetachstate"); } for (i = 0; i < THREAD_NUM; i++) { ret = pthread_create(&th, &attr, wait_thread, NULL); if(ret) { fprintf(stderr, "[%d] ", count); perror("pthread_create"); } else { printf("[%d] create OK.\n", count); } count++; ret = pthread_create(&thread[i], &attr, wait_thread2, NULL); if(ret) { fprintf(stderr, "[%d] ", count); perror("pthread_create"); } else { printf("[%d] create OK.\n", count); } count++; } sleep(3600); return 0; } ================================================================== [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> Signed-off-by: Hugh Dickins <hugh.dickins@tiscali.co.uk> Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/mmap.c')
-rw-r--r--mm/mmap.c36
1 files changed, 28 insertions, 8 deletions
diff --git a/mm/mmap.c b/mm/mmap.c
index ed70a68e882a..02c09f33df8b 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1811,10 +1811,10 @@ detach_vmas_to_be_unmapped(struct mm_struct *mm, struct vm_area_struct *vma,
1811} 1811}
1812 1812
1813/* 1813/*
1814 * Split a vma into two pieces at address 'addr', a new vma is allocated 1814 * __split_vma() bypasses sysctl_max_map_count checking. We use this on the
1815 * either for the first part or the tail. 1815 * munmap path where it doesn't make sense to fail.
1816 */ 1816 */
1817int split_vma(struct mm_struct * mm, struct vm_area_struct * vma, 1817static int __split_vma(struct mm_struct * mm, struct vm_area_struct * vma,
1818 unsigned long addr, int new_below) 1818 unsigned long addr, int new_below)
1819{ 1819{
1820 struct mempolicy *pol; 1820 struct mempolicy *pol;
@@ -1824,9 +1824,6 @@ int split_vma(struct mm_struct * mm, struct vm_area_struct * vma,
1824 ~(huge_page_mask(hstate_vma(vma))))) 1824 ~(huge_page_mask(hstate_vma(vma)))))
1825 return -EINVAL; 1825 return -EINVAL;
1826 1826
1827 if (mm->map_count >= sysctl_max_map_count)
1828 return -ENOMEM;
1829
1830 new = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); 1827 new = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL);
1831 if (!new) 1828 if (!new)
1832 return -ENOMEM; 1829 return -ENOMEM;
@@ -1866,6 +1863,19 @@ int split_vma(struct mm_struct * mm, struct vm_area_struct * vma,
1866 return 0; 1863 return 0;
1867} 1864}
1868 1865
1866/*
1867 * Split a vma into two pieces at address 'addr', a new vma is allocated
1868 * either for the first part or the tail.
1869 */
1870int split_vma(struct mm_struct *mm, struct vm_area_struct *vma,
1871 unsigned long addr, int new_below)
1872{
1873 if (mm->map_count >= sysctl_max_map_count)
1874 return -ENOMEM;
1875
1876 return __split_vma(mm, vma, addr, new_below);
1877}
1878
1869/* Munmap is split into 2 main parts -- this part which finds 1879/* Munmap is split into 2 main parts -- this part which finds
1870 * what needs doing, and the areas themselves, which do the 1880 * what needs doing, and the areas themselves, which do the
1871 * work. This now handles partial unmappings. 1881 * work. This now handles partial unmappings.
@@ -1901,7 +1911,17 @@ int do_munmap(struct mm_struct *mm, unsigned long start, size_t len)
1901 * places tmp vma above, and higher split_vma places tmp vma below. 1911 * places tmp vma above, and higher split_vma places tmp vma below.
1902 */ 1912 */
1903 if (start > vma->vm_start) { 1913 if (start > vma->vm_start) {
1904 int error = split_vma(mm, vma, start, 0); 1914 int error;
1915
1916 /*
1917 * Make sure that map_count on return from munmap() will
1918 * not exceed its limit; but let map_count go just above
1919 * its limit temporarily, to help free resources as expected.
1920 */
1921 if (end < vma->vm_end && mm->map_count >= sysctl_max_map_count)
1922 return -ENOMEM;
1923
1924 error = __split_vma(mm, vma, start, 0);
1905 if (error) 1925 if (error)
1906 return error; 1926 return error;
1907 prev = vma; 1927 prev = vma;
@@ -1910,7 +1930,7 @@ int do_munmap(struct mm_struct *mm, unsigned long start, size_t len)
1910 /* Does it split the last one? */ 1930 /* Does it split the last one? */
1911 last = find_vma(mm, end); 1931 last = find_vma(mm, end);
1912 if (last && end > last->vm_start) { 1932 if (last && end > last->vm_start) {
1913 int error = split_vma(mm, last, end, 1); 1933 int error = __split_vma(mm, last, end, 1);
1914 if (error) 1934 if (error)
1915 return error; 1935 return error;
1916 } 1936 }