patch-1.3.22 linux/kernel/fork.c

Next file: linux/kernel/ksyms.c
Previous file: linux/kernel/exit.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.21/linux/kernel/fork.c linux/kernel/fork.c
@@ -24,6 +24,25 @@
 #include <asm/segment.h>
 #include <asm/system.h>
 
+/*
+ * This is how a process data structure is allocated. In most
+ * cases, the "tsk" pointers point to the same allocation unit
+ * substructures, but if the new process shares part (or all)
+ * of the sub-units with the parent process, the tsk pointers
+ * may point to the parent instead.
+ *
+ * Regardless, we always allocate the full allocation unit, as
+ * the normal fork() semantics require all of them and doing
+ * suballocations would be wasteful.
+ */
+struct allocation_struct {
+	struct task_struct tsk;
+	struct sigaction sigaction[32];
+	struct fs_struct fs;
+	struct files_struct files;
+	struct mm_struct mm;
+};
+
 int nr_tasks=1;
 int nr_running=1;
 long last_pid=0;
@@ -60,28 +79,6 @@
 	return free_task;
 }
 
-static struct file * copy_fd(struct file * old_file)
-{
-	struct file * new_file = get_empty_filp();
-	int error;
-
-	if (new_file) {
-		memcpy(new_file,old_file,sizeof(struct file));
-		new_file->f_count = 1;
-		if (new_file->f_inode)
-			new_file->f_inode->i_count++;
-		if (new_file->f_op && new_file->f_op->open) {
-			error = new_file->f_op->open(new_file->f_inode,new_file);
-			if (error) {
-				iput(new_file->f_inode);
-				new_file->f_count = 0;
-				new_file = NULL;
-			}
-		}
-	}
-	return new_file;
-}
-
 static int dup_mmap(struct task_struct * tsk)
 {
 	struct vm_area_struct * mpnt, **p, *tmp;
@@ -113,50 +110,74 @@
 	return 0;
 }
 
-/*
- * SHAREFD not yet implemented..
- */
-static void copy_files(unsigned long clone_flags, struct task_struct * p)
+static int copy_mm(unsigned long clone_flags, struct allocation_struct * u)
 {
-	int i;
-	struct file * f;
+	if (clone_flags & CLONE_VM) {
+		if (clone_page_tables(&u->tsk))
+			return -1;
+		current->mm->count++;
+		mem_map[MAP_NR(current->mm)]++;
+		return 0;
+	}
+	u->tsk.mm = &u->mm;
+	u->mm = *current->mm;
+	u->mm.count = 1;
+	u->mm.min_flt = u->mm.maj_flt = 0;
+	u->mm.cmin_flt = u->mm.cmaj_flt = 0;
+	if (copy_page_tables(&u->tsk))
+		return -1;
+	if (dup_mmap(&u->tsk))
+		return -1;
+	mem_map[MAP_NR(u)]++;
+	return 0;
+}
 
-	if (clone_flags & COPYFD) {
-		for (i=0; i<NR_OPEN;i++)
-			if ((f = p->files->fd[i]) != NULL)
-				p->files->fd[i] = copy_fd(f);
-	} else {
-		for (i=0; i<NR_OPEN;i++)
-			if ((f = p->files->fd[i]) != NULL)
-				f->f_count++;
+static void copy_fs(unsigned long clone_flags, struct allocation_struct * u)
+{
+	if (clone_flags & CLONE_FS) {
+		current->fs->count++;
+		mem_map[MAP_NR(current->fs)]++;
+		return;
 	}
+	u->tsk.fs = &u->fs;
+	u->fs = *current->fs;
+	u->fs.count = 1;
+	if (u->fs.pwd)
+		u->fs.pwd->i_count++;
+	if (u->fs.root)
+		u->fs.root->i_count++;
+	mem_map[MAP_NR(u)]++;
 }
 
-/*
- * CLONEVM not yet correctly implemented: needs to clone the mmap
- * instead of duplicating it..
- */
-static int copy_mm(unsigned long clone_flags, struct task_struct * p)
+static void copy_files(unsigned long clone_flags, struct allocation_struct * u)
 {
-	if (clone_flags & COPYVM) {
-		p->mm->min_flt = p->mm->maj_flt = 0;
-		p->mm->cmin_flt = p->mm->cmaj_flt = 0;
-		if (copy_page_tables(p))
-			return 1;
-		return dup_mmap(p);
-	} else {
-		if (clone_page_tables(p))
-			return 1;
-		return dup_mmap(p);		/* wrong.. */
+	int i;
+
+	if (clone_flags & CLONE_FILES) {
+		current->files->count++;
+		mem_map[MAP_NR(current->files)]++;
+		return;
+	}
+	u->tsk.files = &u->files;
+	u->files = *current->files;
+	u->files.count = 1;
+	for (i = 0; i < NR_OPEN; i++) {
+		struct file * f = u->files.fd[i];
+		if (f)
+			f->f_count++;
 	}
+	mem_map[MAP_NR(u)]++;
 }
 
-static void copy_fs(unsigned long clone_flags, struct task_struct * p)
-{
-	if (current->fs->pwd)
-		current->fs->pwd->i_count++;
-	if (current->fs->root)
-		current->fs->root->i_count++;
+static void copy_sighand(unsigned long clone_flags, struct allocation_struct * u)
+{
+	if (clone_flags & CLONE_SIGHAND) {
+		mem_map[MAP_NR(current->sigaction)]++;
+		return;
+	}
+	u->tsk.sigaction = u->sigaction;
+	memcpy(u->sigaction, current->sigaction, sizeof(u->sigaction));
+	mem_map[MAP_NR(u)]++;
 }
 
 /*
@@ -169,9 +190,12 @@
 	int nr;
 	unsigned long new_stack;
 	struct task_struct *p;
+	struct allocation_struct *alloc;
 
-	if(!(p = (struct task_struct*)__get_free_page(GFP_KERNEL)))
+	alloc = (struct allocation_struct *) __get_free_page(GFP_KERNEL);
+	if (!alloc)
 		goto bad_fork;
+	p = &alloc->tsk;
 	new_stack = get_free_page(GFP_KERNEL);
 	if (!new_stack)
 		goto bad_fork_free;
@@ -206,18 +230,18 @@
 	p->utime = p->stime = 0;
 	p->cutime = p->cstime = 0;
 	p->start_time = jiffies;
-	p->mm->swappable = 0;	/* don't try to swap it out before it's set up */
 	task[nr] = p;
 	SET_LINKS(p);
 	nr_tasks++;
 
 	/* copy all the process information */
 	copy_thread(nr, clone_flags, usp, p, regs);
-	if (copy_mm(clone_flags, p))
+	if (copy_mm(clone_flags, alloc))
 		goto bad_fork_cleanup;
 	p->semundo = NULL;
-	copy_files(clone_flags, p);
-	copy_fs(clone_flags, p);
+	copy_files(clone_flags, alloc);
+	copy_fs(clone_flags, alloc);
+	copy_sighand(clone_flags, alloc);
 
 	/* ok, now we should be set up.. */
 	p->mm->swappable = 1;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this