When using this program (as root):
        #include <err.h>
        #include <stdio.h>
        #include <stdlib.h>
        #include <unistd.h>

        #include <sys/io.h>
        #include <sys/types.h>
        #include <sys/wait.h>

        #define ITER 1000
        #define FORKERS 15
        #define THREADS (6000/FORKERS) // 1850 is proc max

        static void fork_100_wait()
        {
                unsigned a, to_wait = 0;

                printf("\t%d forking %d\n", THREADS, getpid());

                for (a = 0; a < THREADS; a++) {
                        switch (fork()) {
                        case 0:
                                usleep(1000);
                                exit(0);
                                break;
                        case -1:
                                break;
                        default:
                                to_wait++;
                                break;
                        }
                }

                printf("\t%d forked from %d, waiting for %d\n", THREADS, 
getpid(),
                                to_wait);

                for (a = 0; a < to_wait; a++)
                        wait(NULL);

                printf("\t%d waited from %d\n", THREADS, getpid());
        }

        static void run_forkers()
        {
                pid_t forkers[FORKERS];
                unsigned a;

                for (a = 0; a < FORKERS; a++) {
                        switch ((forkers[a] = fork())) {
                        case 0:
                                fork_100_wait();
                                exit(0);
                                break;
                        case -1:
                                err(1, "DIE fork of %d'th forker", a);
                                break;
                        default:
                                break;
                        }
                }

                for (a = 0; a < FORKERS; a++)
                        waitpid(forkers[a], NULL, 0);
        }

        int main()
        {
                unsigned a;
                int ret;

                ret = ioperm(10, 20, 0);
                if (ret < 0)
                        err(1, "ioperm");

                for (a = 0; a < ITER; a++)
                        run_forkers();

                return 0;
        }

kmemleak reports many occurences of this leak:
unreferenced object 0xffff8805917c8000 (size 8192):
  comm "fork-leak", pid 2932, jiffies 4295354292 (age 1871.028s)
  hex dump (first 32 bytes):
    ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  ................
    ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  ................
  backtrace:
    [<ffffffff814cfbf5>] kmemdup+0x25/0x50
    [<ffffffff8103ab43>] copy_thread_tls+0x6c3/0x9a0
    [<ffffffff81150174>] copy_process+0x1a84/0x5790
    [<ffffffff811dc375>] wake_up_new_task+0x2d5/0x6f0
    [<ffffffff8115411d>] _do_fork+0x12d/0x820
...

Make sure the memory is freed when fork fails later in copy_process.
This is done by calling exit_thread with the thread to kill.

Signed-off-by: Jiri Slaby <jsl...@suse.cz>
---
 kernel/fork.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/kernel/fork.c b/kernel/fork.c
index d277e83ed3e0..0ac98c9ea15e 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1470,7 +1470,7 @@ static struct task_struct *copy_process(unsigned long 
clone_flags,
                pid = alloc_pid(p->nsproxy->pid_ns_for_children);
                if (IS_ERR(pid)) {
                        retval = PTR_ERR(pid);
-                       goto bad_fork_cleanup_io;
+                       goto bad_fork_cleanup_thread;
                }
        }
 
@@ -1632,6 +1632,8 @@ bad_fork_cancel_cgroup:
 bad_fork_free_pid:
        if (pid != &init_struct_pid)
                free_pid(pid);
+bad_fork_cleanup_thread:
+       exit_thread(p);
 bad_fork_cleanup_io:
        if (p->io_context)
                exit_io_context(p);
-- 
2.7.4

Reply via email to