LWN.net Logo

rmap 26 __setup_arg_pages

From:  Hugh Dickins <hugh@veritas.com>
To:  Andrew Morton <akpm@osdl.org>
Subject:  [PATCH] rmap 26 __setup_arg_pages
Date:  Sat, 8 May 2004 22:58:31 +0100 (BST)
Cc:  Andrea Arcangeli <andrea@suse.de>, <davidm@hpl.hp.com>, <schwidefsky@de.ibm.com>, <ak@suse.de>, <linux-kernel@vger.kernel.org>

anon_vma will need to pass vma to "put_dirty_page"; but instead of just
adding that arg to its callers, try to tidy this area up a little with
__setup_arg_pages(bprm, stack_top, vm_stack_flags), cutting duplicated
code out of the 64-bit support for 32-bit execs.  Still fairly horrid
(they tend to #include fs/binfmt_elf.c after #defining setup_arg_pages
to local variant), I'd break their builds if we went further.

Rename put_dirty_page to install_arg_page, now static to fs/exec.c.
While there, moved its flush_dcache_page up before page_table_lock -
doesn't in fact matter at all, just saves one worry when researching
flush_dcache_page locking constraints.

 arch/ia64/ia32/binfmt_elf32.c  |   59 +++----------------------------
 arch/ia64/mm/init.c            |    2 -
 arch/s390/kernel/compat_exec.c |   78 +----------------------------------------
 arch/x86_64/ia32/ia32_binfmt.c |   65 ++++------------------------------
 fs/exec.c                      |   52 +++++++++++++++------------
 include/linux/binfmts.h        |    2 +
 include/linux/mm.h             |    2 -
 7 files changed, 49 insertions(+), 211 deletions(-)

--- rmap25/arch/ia64/ia32/binfmt_elf32.c	2004-05-05 13:29:08.000000000 +0100
+++ rmap26/arch/ia64/ia32/binfmt_elf32.c	2004-05-08 20:54:54.347237808 +0100
@@ -152,61 +152,14 @@ ia64_elf32_init (struct pt_regs *regs)
 int
 ia32_setup_arg_pages (struct linux_binprm *bprm, int executable_stack)
 {
-	unsigned long stack_base;
-	struct vm_area_struct *mpnt;
-	struct mm_struct *mm = current->mm;
-	int i;
+	unsigned long vm_stack_flags = VM_STACK_FLAGS;
 
-	stack_base = IA32_STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE;
-	mm->arg_start = bprm->p + stack_base;
+	if (executable_stack == EXSTACK_ENABLE_X)
+		vm_stack_flags |= VM_EXEC;
+	else if (executable_stack == EXSTACK_DISABLE_X)
+		vm_stack_flags &= ~VM_EXEC;
 
-	bprm->p += stack_base;
-	if (bprm->loader)
-		bprm->loader += stack_base;
-	bprm->exec += stack_base;
-
-	mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
-	if (!mpnt)
-		return -ENOMEM;
-
-	if (security_vm_enough_memory((IA32_STACK_TOP - (PAGE_MASK & (unsigned long) bprm->p))>>PAGE_SHIFT)) {
-		kmem_cache_free(vm_area_cachep, mpnt);
-		return -ENOMEM;
-	}
-
-	down_write(&current->mm->mmap_sem);
-	{
-		mpnt->vm_mm = current->mm;
-		mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
-		mpnt->vm_end = IA32_STACK_TOP;
-		if (executable_stack == EXSTACK_ENABLE_X)
-			mpnt->vm_flags = VM_STACK_FLAGS |  VM_EXEC;
-		else if (executable_stack == EXSTACK_DISABLE_X)
-			mpnt->vm_flags = VM_STACK_FLAGS & ~VM_EXEC;
-		else
-			mpnt->vm_flags = VM_STACK_FLAGS;
-		mpnt->vm_page_prot = (mpnt->vm_flags & VM_EXEC)?
-					PAGE_COPY_EXEC: PAGE_COPY;
-		mpnt->vm_ops = NULL;
-		mpnt->vm_pgoff = 0;
-		mpnt->vm_file = NULL;
-		mpnt->vm_private_data = 0;
-		mpol_set_vma_default(mpnt);
-		insert_vm_struct(current->mm, mpnt);
-		current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
-	}
-
-	for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
-		struct page *page = bprm->page[i];
-		if (page) {
-			bprm->page[i] = NULL;
-			put_dirty_page(current, page, stack_base, mpnt->vm_page_prot);
-		}
-		stack_base += PAGE_SIZE;
-	}
-	up_write(&current->mm->mmap_sem);
-
-	return 0;
+	return __setup_arg_pages(bprm, IA32_STACK_TOP, vm_stack_flags);
 }
 
 static void
--- rmap25/arch/ia64/mm/init.c	2004-05-05 13:29:12.000000000 +0100
+++ rmap26/arch/ia64/mm/init.c	2004-05-08 20:54:54.349237504 +0100
@@ -222,7 +222,7 @@ free_initrd_mem (unsigned long start, un
 }
 
 /*
- * This is like put_dirty_page() but installs a clean page in the kernel's page table.
+ * This installs a clean page in the kernel's page table.
  */
 struct page *
 put_kernel_page (struct page *page, unsigned long address, pgprot_t pgprot)
--- rmap25/arch/s390/kernel/compat_exec.c	2004-05-05 13:29:08.000000000 +0100
+++ rmap26/arch/s390/kernel/compat_exec.c	2004-05-08 20:54:54.350237352 +0100
@@ -8,87 +8,13 @@
  *
  */
 
-#include <linux/config.h>
-#include <linux/slab.h>
-#include <linux/file.h>
-#include <linux/mman.h>
-#include <linux/a.out.h>
-#include <linux/stat.h>
-#include <linux/fcntl.h>
-#include <linux/smp_lock.h>
-#include <linux/init.h>
-#include <linux/pagemap.h>
 #include <linux/mm.h>
-#include <linux/highmem.h>
-#include <linux/spinlock.h>
 #include <linux/binfmts.h>
 #include <linux/module.h>
-#include <linux/security.h>
-
-#include <asm/uaccess.h>
-#include <asm/pgalloc.h>
-#include <asm/mmu_context.h>
-
-#ifdef CONFIG_KMOD
-#include <linux/kmod.h>
-#endif
-
-
-#undef STACK_TOP
-#define STACK_TOP TASK31_SIZE
 
 int setup_arg_pages32(struct linux_binprm *bprm, int executable_stack)
 {
-	unsigned long stack_base;
-	struct vm_area_struct *mpnt;
-	struct mm_struct *mm = current->mm;
-	int i;
-
-	stack_base = STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE;
-	mm->arg_start = bprm->p + stack_base;
-
-	bprm->p += stack_base;
-	if (bprm->loader)
-		bprm->loader += stack_base;
-	bprm->exec += stack_base;
-
-	mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
-	if (!mpnt) 
-		return -ENOMEM; 
-	
-	if (security_vm_enough_memory((STACK_TOP - (PAGE_MASK & (unsigned long) bprm->p))>>PAGE_SHIFT)) {
-		kmem_cache_free(vm_area_cachep, mpnt);
-		return -ENOMEM;
-	}
-
-	down_write(&mm->mmap_sem);
-	{
-		mpnt->vm_mm = mm;
-		mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
-		mpnt->vm_end = STACK_TOP;
-		/* executable stack setting would be applied here */
-		mpnt->vm_page_prot = PAGE_COPY;
-		mpnt->vm_flags = VM_STACK_FLAGS;
-		mpnt->vm_ops = NULL;
-		mpnt->vm_pgoff = 0;
-		mpnt->vm_file = NULL;
-		mpol_set_vma_default(mpnt);
-		mpnt->vm_private_data = (void *) 0;
-		insert_vm_struct(mm, mpnt);
-		mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
-	} 
-
-	for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
-		struct page *page = bprm->page[i];
-		if (page) {
-			bprm->page[i] = NULL;
-			put_dirty_page(current,page,stack_base,PAGE_COPY);
-		}
-		stack_base += PAGE_SIZE;
-	}
-	up_write(&mm->mmap_sem);
-	
-	return 0;
+	/* executable_stack argument is currently ignored */
+	return __setup_arg_pages(bprm, TASK31_SIZE, VM_STACK_FLAGS);
 }
-
 EXPORT_SYMBOL(setup_arg_pages32);
--- rmap25/arch/x86_64/ia32/ia32_binfmt.c	2004-05-05 13:29:08.000000000 +0100
+++ rmap26/arch/x86_64/ia32/ia32_binfmt.c	2004-05-08 20:54:54.351237200 +0100
@@ -325,63 +325,16 @@ static void elf32_init(struct pt_regs *r
 	me->thread.es = __USER_DS;
 }
 
-int setup_arg_pages(struct linux_binprm *bprm, int executable_stack)
+int ia32_setup_arg_pages(struct linux_binprm *bprm, int executable_stack)
 {
-	unsigned long stack_base;
-	struct vm_area_struct *mpnt;
-	struct mm_struct *mm = current->mm;
-	int i;
-
-	stack_base = IA32_STACK_TOP - MAX_ARG_PAGES * PAGE_SIZE;
-	mm->arg_start = bprm->p + stack_base;
-
-	bprm->p += stack_base;
-	if (bprm->loader)
-		bprm->loader += stack_base;
-	bprm->exec += stack_base;
-
-	mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
-	if (!mpnt) 
-		return -ENOMEM; 
-	
-	if (security_vm_enough_memory((IA32_STACK_TOP - (PAGE_MASK & (unsigned long) bprm->p))>>PAGE_SHIFT)) {
-		kmem_cache_free(vm_area_cachep, mpnt);
-		return -ENOMEM;
-	}
-
-	down_write(&mm->mmap_sem);
-	{
-		mpnt->vm_mm = mm;
-		mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
-		mpnt->vm_end = IA32_STACK_TOP;
-		if (executable_stack == EXSTACK_ENABLE_X)
-			mpnt->vm_flags = vm_stack_flags32 |  VM_EXEC;
-		else if (executable_stack == EXSTACK_DISABLE_X)
-			mpnt->vm_flags = vm_stack_flags32 & ~VM_EXEC;
-		else
-			mpnt->vm_flags = vm_stack_flags32;
- 		mpnt->vm_page_prot = (mpnt->vm_flags & VM_EXEC) ? 
- 			PAGE_COPY_EXEC : PAGE_COPY;
-		mpnt->vm_ops = NULL;
-		mpnt->vm_pgoff = 0;
-		mpnt->vm_file = NULL;
-		mpol_set_vma_default(mpnt);
-		mpnt->vm_private_data = (void *) 0;
-		insert_vm_struct(mm, mpnt);
-		mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
-	} 
-
-	for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
-		struct page *page = bprm->page[i];
-		if (page) {
-			bprm->page[i] = NULL;
-			put_dirty_page(current,page,stack_base,mpnt->vm_page_prot);
-		}
-		stack_base += PAGE_SIZE;
-	}
-	up_write(&mm->mmap_sem);
-	
-	return 0;
+	unsigned long vm_stack_flags = vm_stack_flags32;
+
+	if (executable_stack == EXSTACK_ENABLE_X)
+		vm_stack_flags |= VM_EXEC;
+	else if (executable_stack == EXSTACK_DISABLE_X)
+		vm_stack_flags &= ~VM_EXEC;
+
+	return __setup_arg_pages(bprm, IA32_STACK_TOP, vm_stack_flags);
 }
 
 static unsigned long
--- rmap25/fs/exec.c	2004-05-05 13:29:10.000000000 +0100
+++ rmap26/fs/exec.c	2004-05-08 20:54:54.354236744 +0100
@@ -293,17 +293,19 @@ EXPORT_SYMBOL(copy_strings_kernel);
  * This routine is used to map in a page into an address space: needed by
  * execve() for the initial stack and environment pages.
  *
- * tsk->mm->mmap_sem is held for writing.
+ * vma->vm_mm->mmap_sem is held for writing.
  */
-void put_dirty_page(struct task_struct *tsk, struct page *page,
-			unsigned long address, pgprot_t prot)
+static void install_arg_page(struct vm_area_struct *vma,
+			struct page *page, unsigned long address)
 {
-	struct mm_struct *mm = tsk->mm;
+	struct mm_struct *mm = vma->vm_mm;
 	pgd_t * pgd;
 	pmd_t * pmd;
 	pte_t * pte;
 
+	flush_dcache_page(page);
 	pgd = pgd_offset(mm, address);
+
 	spin_lock(&mm->page_table_lock);
 	pmd = pmd_alloc(mm, pgd, address);
 	if (!pmd)
@@ -317,8 +319,8 @@ void put_dirty_page(struct task_struct *
 	}
 	mm->rss++;
 	lru_cache_add_active(page);
-	flush_dcache_page(page);
-	set_pte(pte, pte_mkdirty(pte_mkwrite(mk_pte(page, prot))));
+	set_pte(pte, pte_mkdirty(pte_mkwrite(mk_pte(
+					page, vma->vm_page_prot))));
 	page_add_anon_rmap(page, mm, address);
 	pte_unmap(pte);
 	spin_unlock(&mm->page_table_lock);
@@ -328,10 +330,11 @@ void put_dirty_page(struct task_struct *
 out:
 	spin_unlock(&mm->page_table_lock);
 	__free_page(page);
-	force_sig(SIGKILL, tsk);
+	force_sig(SIGKILL, current);
 }
 
-int setup_arg_pages(struct linux_binprm *bprm, int executable_stack)
+int __setup_arg_pages(struct linux_binprm *bprm,
+		unsigned long stack_top, unsigned long vm_stack_flags)
 {
 	unsigned long stack_base;
 	struct vm_area_struct *mpnt;
@@ -375,7 +378,7 @@ int setup_arg_pages(struct linux_binprm 
 	stack_base = current->rlim[RLIMIT_STACK].rlim_max;
 	if (stack_base > (1 << 30))
 		stack_base = 1 << 30;
-	stack_base = PAGE_ALIGN(STACK_TOP - stack_base);
+	stack_base = PAGE_ALIGN(stack_top - stack_base);
 
 	mm->arg_start = stack_base;
 	arg_size = i << PAGE_SHIFT;
@@ -384,9 +387,9 @@ int setup_arg_pages(struct linux_binprm 
 	while (i < MAX_ARG_PAGES)
 		bprm->page[i++] = NULL;
 #else
-	stack_base = STACK_TOP - MAX_ARG_PAGES * PAGE_SIZE;
+	stack_base = stack_top - MAX_ARG_PAGES * PAGE_SIZE;
 	mm->arg_start = bprm->p + stack_base;
-	arg_size = STACK_TOP - (PAGE_MASK & (unsigned long) mm->arg_start);
+	arg_size = stack_top - (PAGE_MASK & (unsigned long) mm->arg_start);
 #endif
 
 	bprm->p += stack_base;
@@ -412,17 +415,9 @@ int setup_arg_pages(struct linux_binprm 
 			(PAGE_SIZE - 1 + (unsigned long) bprm->p);
 #else
 		mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
-		mpnt->vm_end = STACK_TOP;
+		mpnt->vm_end = stack_top;
 #endif
-		/* Adjust stack execute permissions; explicitly enable
-		 * for EXSTACK_ENABLE_X, disable for EXSTACK_DISABLE_X
-		 * and leave alone (arch default) otherwise. */
-		if (unlikely(executable_stack == EXSTACK_ENABLE_X))
-			mpnt->vm_flags = VM_STACK_FLAGS |  VM_EXEC;
-		else if (executable_stack == EXSTACK_DISABLE_X)
-			mpnt->vm_flags = VM_STACK_FLAGS & ~VM_EXEC;
-		else
-			mpnt->vm_flags = VM_STACK_FLAGS;
+		mpnt->vm_flags = vm_stack_flags;
 		mpnt->vm_page_prot = protection_map[mpnt->vm_flags & 0x7];
 		mpnt->vm_ops = NULL;
 		mpnt->vm_pgoff = 0;
@@ -437,8 +432,7 @@ int setup_arg_pages(struct linux_binprm 
 		struct page *page = bprm->page[i];
 		if (page) {
 			bprm->page[i] = NULL;
-			put_dirty_page(current, page, stack_base,
-					mpnt->vm_page_prot);
+			install_arg_page(mpnt, page, stack_base);
 		}
 		stack_base += PAGE_SIZE;
 	}
@@ -446,7 +440,19 @@ int setup_arg_pages(struct linux_binprm 
 	
 	return 0;
 }
+EXPORT_SYMBOL(__setup_arg_pages);
 
+int setup_arg_pages(struct linux_binprm *bprm, int executable_stack)
+{
+	unsigned long vm_stack_flags = VM_STACK_FLAGS;
+
+	if (executable_stack == EXSTACK_ENABLE_X)
+		vm_stack_flags |= VM_EXEC;
+	else if (executable_stack == EXSTACK_DISABLE_X)
+		vm_stack_flags &= ~VM_EXEC;
+
+	return __setup_arg_pages(bprm, STACK_TOP, vm_stack_flags);
+}
 EXPORT_SYMBOL(setup_arg_pages);
 
 #define free_arg_pages(bprm) do { } while (0)
--- rmap25/include/linux/binfmts.h	2004-05-05 13:29:09.000000000 +0100
+++ rmap26/include/linux/binfmts.h	2004-05-08 20:54:54.355236592 +0100
@@ -69,6 +69,8 @@ extern int flush_old_exec(struct linux_b
 #define EXSTACK_ENABLE_X  2	/* Enable executable stacks */
 
 extern int setup_arg_pages(struct linux_binprm * bprm, int executable_stack);
+extern int __setup_arg_pages(struct linux_binprm *bprm,
+		unsigned long stack_top, unsigned long vm_flags);
 extern int copy_strings(int argc,char __user * __user * argv,struct linux_binprm *bprm); 
 extern int copy_strings_kernel(int argc,char ** argv,struct linux_binprm *bprm);
 extern void compute_creds(struct linux_binprm *binprm);
--- rmap25/include/linux/mm.h	2004-05-05 13:29:08.000000000 +0100
+++ rmap26/include/linux/mm.h	2004-05-08 20:54:54.356236440 +0100
@@ -495,8 +495,6 @@ extern int install_file_pte(struct mm_st
 extern int handle_mm_fault(struct mm_struct *mm,struct vm_area_struct *vma, unsigned long address, int write_access);
 extern int make_pages_present(unsigned long addr, unsigned long end);
 extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write);
-void put_dirty_page(struct task_struct *tsk, struct page *page,
-			unsigned long address, pgprot_t prot);
 
 int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start,
 		int len, int write, int force, struct page **pages, struct vm_area_struct **vmas);

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Copyright © 2004, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds