patch-2.2.12 linux/kernel/fork.c
Next file: linux/mm/mlock.c
Previous file: linux/kernel/exit.c
Back to the patch index
Back to the overall index
- Lines: 210
- Date:
Wed Aug 25 17:29:53 1999
- Orig file:
v2.2.11/linux/kernel/fork.c
- Orig date:
Mon Aug 9 16:05:57 1999
diff -u --recursive --new-file v2.2.11/linux/kernel/fork.c linux/kernel/fork.c
@@ -362,6 +362,9 @@
if (clone_flags & CLONE_VM) {
mmget(current->mm);
+ tsk->min_flt = tsk->maj_flt = 0;
+ tsk->cmin_flt = tsk->cmaj_flt = 0;
+ tsk->nswap = tsk->cnswap = 0;
/*
* Set up the LDT descriptor for the clone task.
*/
@@ -414,32 +417,11 @@
return 0;
}
-/*
- * Copy a fd_set and compute the maximum fd it contains.
- */
-static inline int __copy_fdset(unsigned long *d, unsigned long *src)
-{
- int i;
- unsigned long *p = src;
- unsigned long *max = src;
-
- for (i = __FDSET_LONGS; i; --i) {
- if ((*d++ = *p++) != 0)
- max = p;
- }
- return (max - src)*sizeof(long)*8;
-}
-
-static inline int copy_fdset(fd_set *dst, fd_set *src)
-{
- return __copy_fdset(dst->fds_bits, src->fds_bits);
-}
-
static int copy_files(unsigned long clone_flags, struct task_struct * tsk)
{
struct files_struct *oldf, *newf;
struct file **old_fds, **new_fds;
- int size, i, error = 0;
+ int nfds, size, i, error = 0;
/*
* A background process may not have any files ...
@@ -459,25 +441,74 @@
if (!newf)
goto out;
- /*
- * Allocate the fd array, using get_free_page() if possible.
- * Eventually we want to make the array size variable ...
- */
- size = NR_OPEN * sizeof(struct file *);
- if (size == PAGE_SIZE)
- new_fds = (struct file **) __get_free_page(GFP_KERNEL);
- else
- new_fds = (struct file **) kmalloc(size, GFP_KERNEL);
- if (!new_fds)
- goto out_release;
+ size = oldf->max_fdset;
+ nfds = NR_OPEN_DEFAULT;
+#ifdef FDSET_DEBUG
+ printk (KERN_ERR __FUNCTION__ " size = %d/%d\n",
+ oldf->max_fds, oldf->max_fdset);
+#endif
atomic_set(&newf->count, 1);
- newf->max_fds = NR_OPEN;
- newf->fd = new_fds;
- newf->close_on_exec = oldf->close_on_exec;
- i = copy_fdset(&newf->open_fds, &oldf->open_fds);
+ newf->next_fd = 0;
+ newf->max_fds = NR_OPEN_DEFAULT;
+ newf->max_fdset = __FD_SETSIZE;
+ newf->close_on_exec = &newf->close_on_exec_init;
+ newf->open_fds = &newf->open_fds_init;
+ newf->fd = &newf->fd_array[0];
+
+ /* Even if the old fdset gets grown here, we'll only copy "size" fds */
+ if (size > __FD_SETSIZE) {
+ newf->max_fdset = 0;
+ error = expand_fdset(newf, size);
+ if (error)
+ goto out_release;
+ }
+ memcpy(newf->open_fds->fds_bits, oldf->open_fds->fds_bits, size/8);
+ memcpy(newf->close_on_exec->fds_bits, oldf->close_on_exec->fds_bits, size/8);
+ if (newf->max_fdset > size) {
+ int left = (newf->max_fdset-size)/8;
+ int start = size / (8 * sizeof(unsigned long));
+
+ memset(&newf->open_fds->fds_bits[start], 0, left);
+ memset(&newf->close_on_exec->fds_bits[start], 0, left);
+ }
+
+ /* Find the last open fd */
+ for (i = size/(8*sizeof(long)); i > 0; ) {
+ if (newf->open_fds->fds_bits[--i])
+ break;
+ }
+ i = (i+1) * 8 * sizeof(long);
+
+#ifdef FDSET_DEBUG
+ printk (KERN_ERR __FUNCTION__ " first-free = %d/%d\n", i, size);
+#endif
+
+ /* Do a sanity check ... */
+ if (i > oldf->max_fds)
+ printk(KERN_ERR
+ "copy_files: pid %d, open files %d exceeds max %d!\n",
+ current->pid, i, oldf->max_fds);
+
+ /*
+ * Check whether we need to allocate a larger fd array.
+ * Note: we're not a clone task, so the open count won't
+ * change.
+ */
+ if (i > NR_OPEN_DEFAULT) {
+ newf->max_fds = 0;
+ error = expand_fd_array(newf, i);
+ if (error)
+ goto out_release;
+ nfds = newf->max_fds;
+ }
+
+ /* compute the remainder to be cleared */
+ size = (nfds - i) * sizeof(struct file *);
old_fds = oldf->fd;
+ new_fds = newf->fd;
+
for (; i != 0; i--) {
struct file *f = *old_fds++;
*new_fds = f;
@@ -486,14 +517,20 @@
new_fds++;
}
/* This is long word aligned thus could use a optimized version */
- memset(new_fds, 0, (char *)newf->fd + size - (char *)new_fds);
+ memset(new_fds, 0, size);
tsk->files = newf;
error = 0;
out:
+#ifdef FDSET_DEBUG
+ if (error)
+ printk (KERN_ERR "copy_files: return %d\n", error);
+#endif
return error;
out_release:
+ free_fdset (newf->close_on_exec, newf->max_fdset);
+ free_fdset (newf->open_fds, newf->max_fdset);
kmem_cache_free(files_cachep, newf);
goto out;
}
@@ -553,13 +590,14 @@
if (p->user) {
if (atomic_read(&p->user->count) >= p->rlim[RLIMIT_NPROC].rlim_cur)
goto bad_fork_free;
+ atomic_inc(&p->user->count);
}
{
struct task_struct **tslot;
tslot = find_empty_process();
if (!tslot)
- goto bad_fork_free;
+ goto bad_fork_cleanup_count;
p->tarray_ptr = tslot;
*tslot = p;
nr = tslot - &task[0];
@@ -632,7 +670,7 @@
goto bad_fork_cleanup_sighand;
retval = copy_thread(nr, clone_flags, usp, p, regs);
if (retval)
- goto bad_fork_cleanup_sighand;
+ goto bad_fork_cleanup_mm;
p->semundo = NULL;
/* ok, now we should be set up.. */
@@ -663,8 +701,6 @@
write_unlock_irq(&tasklist_lock);
nr_tasks++;
- if (p->user)
- atomic_inc(&p->user->count);
p->next_run = NULL;
p->prev_run = NULL;
@@ -679,6 +715,9 @@
down(&sem);
return retval;
+bad_fork_cleanup_mm:
+ mmput(p->mm);
+ p->mm = NULL;
bad_fork_cleanup_sighand:
exit_sighand(p);
bad_fork_cleanup_fs:
@@ -692,6 +731,9 @@
__MOD_DEC_USE_COUNT(p->binfmt->module);
add_free_taskslot(p->tarray_ptr);
+bad_fork_cleanup_count:
+ if (p->user)
+ free_uid(p);
bad_fork_free:
free_task_struct(p);
goto bad_fork;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)