patch-2.1.51 linux/kernel/fork.c
Next file: linux/kernel/ksyms.c
Previous file: linux/include/linux/tty.h
Back to the patch index
Back to the overall index
- Lines: 159
- Date:
Mon Aug 18 16:13:34 1997
- Orig file:
v2.1.50/linux/kernel/fork.c
- Orig date:
Thu Aug 14 20:49:17 1997
diff -u --recursive --new-file v2.1.50/linux/kernel/fork.c linux/kernel/fork.c
@@ -206,6 +206,7 @@
static inline int dup_mmap(struct mm_struct * mm)
{
struct vm_area_struct * mpnt, *tmp, **pprev;
+ int retval;
mm->mmap = mm->mmap_cache = NULL;
flush_cache_mm(current->mm);
@@ -213,19 +214,17 @@
for (mpnt = current->mm->mmap ; mpnt ; mpnt = mpnt->vm_next) {
struct dentry *dentry;
+ retval = -ENOMEM;
tmp = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
- if (!tmp) {
- exit_mmap(mm);
- flush_tlb_mm(current->mm);
- return -ENOMEM;
- }
+ if (!tmp)
+ goto fail_nomem;
*tmp = *mpnt;
tmp->vm_flags &= ~VM_LOCKED;
tmp->vm_mm = mm;
tmp->vm_next = NULL;
dentry = tmp->vm_dentry;
if (dentry) {
- dentry->d_count++;
+ dget(dentry);
if (tmp->vm_flags & VM_DENYWRITE)
dentry->d_inode->i_writecount--;
@@ -236,60 +235,79 @@
mpnt->vm_next_share = tmp;
tmp->vm_pprev_share = &mpnt->vm_next_share;
}
- if (copy_page_range(mm, current->mm, tmp)) {
- exit_mmap(mm);
- flush_tlb_mm(current->mm);
- return -ENOMEM;
- }
- if (tmp->vm_ops && tmp->vm_ops->open)
+
+ /* Copy the pages, but defer checking for errors */
+ retval = copy_page_range(mm, current->mm, tmp);
+ if (!retval && tmp->vm_ops && tmp->vm_ops->open)
tmp->vm_ops->open(tmp);
- /* Ok, finally safe to link it in. */
+ /*
+ * Link in the new vma even if an error occurred,
+ * so that exit_mmap() can clean up the mess.
+ */
if((tmp->vm_next = *pprev) != NULL)
(*pprev)->vm_pprev = &tmp->vm_next;
*pprev = tmp;
tmp->vm_pprev = pprev;
pprev = &tmp->vm_next;
+ if (retval)
+ goto fail_nomem;
}
flush_tlb_mm(current->mm);
return 0;
+
+fail_nomem:
+ exit_mmap(mm);
+ flush_tlb_mm(current->mm);
+ return retval;
}
static inline int copy_mm(unsigned long clone_flags, struct task_struct * tsk)
{
- if (!(clone_flags & CLONE_VM)) {
- struct mm_struct * mm = kmem_cache_alloc(mm_cachep, SLAB_KERNEL);
- if (!mm)
- return -1;
- *mm = *current->mm;
- init_new_context(mm);
- mm->count = 1;
- mm->def_flags = 0;
- mm->mmap_sem = MUTEX;
-
- /* It has not run yet, so cannot be present in anyone's
- * cache or tlb.
- */
- mm->cpu_vm_mask = 0;
+ struct mm_struct * mm;
+ int retval;
- tsk->mm = mm;
- tsk->min_flt = tsk->maj_flt = 0;
- tsk->cmin_flt = tsk->cmaj_flt = 0;
- tsk->nswap = tsk->cnswap = 0;
- if (new_page_tables(tsk))
- goto free_mm;
- if (dup_mmap(mm)) {
- free_page_tables(mm);
-free_mm:
- kmem_cache_free(mm_cachep, mm);
- return -1;
- }
+ if (clone_flags & CLONE_VM) {
+ current->mm->count++;
+ SET_PAGE_DIR(tsk, current->mm->pgd);
return 0;
}
- current->mm->count++;
- SET_PAGE_DIR(tsk, current->mm->pgd);
+
+ retval = -ENOMEM;
+ mm = kmem_cache_alloc(mm_cachep, SLAB_KERNEL);
+ if (!mm)
+ goto fail_nomem;
+ *mm = *current->mm;
+ init_new_context(mm);
+ mm->count = 1;
+ mm->def_flags = 0;
+ mm->mmap_sem = MUTEX;
+
+ /* It has not run yet, so cannot be present in anyone's
+ * cache or tlb.
+ */
+ mm->cpu_vm_mask = 0;
+
+ tsk->mm = mm;
+ tsk->min_flt = tsk->maj_flt = 0;
+ tsk->cmin_flt = tsk->cmaj_flt = 0;
+ tsk->nswap = tsk->cnswap = 0;
+ retval = new_page_tables(tsk);
+ if (retval)
+ goto free_mm;
+ retval = dup_mmap(mm);
+ if (retval)
+ goto free_pt;
return 0;
+
+free_pt:
+ free_page_tables(mm);
+free_mm:
+ tsk->mm = NULL;
+ kmem_cache_free(mm_cachep, mm);
+fail_nomem:
+ return retval;
}
static inline int copy_fs(unsigned long clone_flags, struct task_struct * tsk)
@@ -478,9 +496,9 @@
bad_fork_cleanup_sighand:
exit_sighand(p);
bad_fork_cleanup_fs:
- exit_fs(p);
+ exit_fs(p); /* blocking */
bad_fork_cleanup_files:
- exit_files(p);
+ exit_files(p); /* blocking */
bad_fork_cleanup:
charge_uid(current, -1);
if (p->exec_domain && p->exec_domain->module)
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov