summaryrefslogtreecommitdiffstats
path: root/fs/exec.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2001-04-05 04:55:58 +0000
committerRalf Baechle <ralf@linux-mips.org>2001-04-05 04:55:58 +0000
commit74a9f2e1b4d3ab45a9f72cb5b556c9f521524ab3 (patch)
tree7c4cdb103ab1b388c9852a88bd6fb1e73eba0b5c /fs/exec.c
parentee6374c8b0d333c08061c6a97bc77090d7461225 (diff)
Merge with Linux 2.4.3.
Note that mingetty does no longer work with serial console, you have to switch to another getty like getty_ps. This commit also includes a fix for a setitimer bug which did prevent getty_ps from working on older kernels.
Diffstat (limited to 'fs/exec.c')
-rw-r--r--fs/exec.c45
1 files changed, 24 insertions, 21 deletions
diff --git a/fs/exec.c b/fs/exec.c
index 835d77136..26778aba0 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -252,6 +252,8 @@ int copy_strings_kernel(int argc,char ** argv, struct linux_binprm *bprm)
/*
* This routine is used to map in a page into an address space: needed by
* execve() for the initial stack and environment pages.
+ *
+ * tsk->mmap_sem is held for writing.
*/
void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long address)
{
@@ -262,27 +264,29 @@ void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long a
if (page_count(page) != 1)
printk("mem_map disagrees with %p at %08lx\n", page, address);
pgd = pgd_offset(tsk->mm, address);
- pmd = pmd_alloc(pgd, address);
- if (!pmd) {
- __free_page(page);
- force_sig(SIGKILL, tsk);
- return;
- }
- pte = pte_alloc(pmd, address);
- if (!pte) {
- __free_page(page);
- force_sig(SIGKILL, tsk);
- return;
- }
- if (!pte_none(*pte)) {
- pte_ERROR(*pte);
- __free_page(page);
- return;
- }
+
+ spin_lock(&tsk->mm->page_table_lock);
+ pmd = pmd_alloc(tsk->mm, pgd, address);
+ if (!pmd)
+ goto out;
+ pte = pte_alloc(tsk->mm, pmd, address);
+ if (!pte)
+ goto out;
+ if (!pte_none(*pte))
+ goto out;
flush_dcache_page(page);
flush_page_to_ram(page);
set_pte(pte, pte_mkdirty(pte_mkwrite(mk_pte(page, PAGE_COPY))));
-/* no need for flush_tlb */
+ tsk->mm->rss++;
+ spin_unlock(&tsk->mm->page_table_lock);
+
+ /* no need for flush_tlb */
+ return;
+out:
+ spin_unlock(&tsk->mm->page_table_lock);
+ __free_page(page);
+ force_sig(SIGKILL, tsk);
+ return;
}
int setup_arg_pages(struct linux_binprm *bprm)
@@ -302,7 +306,7 @@ int setup_arg_pages(struct linux_binprm *bprm)
if (!mpnt)
return -ENOMEM;
- down(&current->mm->mmap_sem);
+ down_write(&current->mm->mmap_sem);
{
mpnt->vm_mm = current->mm;
mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
@@ -321,12 +325,11 @@ int setup_arg_pages(struct linux_binprm *bprm)
struct page *page = bprm->page[i];
if (page) {
bprm->page[i] = NULL;
- current->mm->rss++;
put_dirty_page(current,page,stack_base);
}
stack_base += PAGE_SIZE;
}
- up(&current->mm->mmap_sem);
+ up_write(&current->mm->mmap_sem);
return 0;
}