From patchwork Mon Mar 26 01:28:56 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tim Gardner X-Patchwork-Id: 148619 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from chlorine.canonical.com (chlorine.canonical.com [91.189.94.204]) by ozlabs.org (Postfix) with ESMTP id 2FE77B6F9D for ; Mon, 26 Mar 2012 12:29:18 +1100 (EST) Received: from localhost ([127.0.0.1] helo=chlorine.canonical.com) by chlorine.canonical.com with esmtp (Exim 4.71) (envelope-from ) id 1SByk6-0007Ec-A2; Mon, 26 Mar 2012 01:29:06 +0000 Received: from mail.tpi.com ([70.99.223.143]) by chlorine.canonical.com with esmtp (Exim 4.71) (envelope-from ) id 1SByjy-0007DL-Qx for kernel-team@lists.ubuntu.com; Mon, 26 Mar 2012 01:28:59 +0000 Received: from salmon.rtg.net (mail.tpi.com [70.99.223.143]) by mail.tpi.com (Postfix) with ESMTP id B19AC3145AC for ; Sun, 25 Mar 2012 18:28:36 -0700 (PDT) Received: by salmon.rtg.net (Postfix, from userid 1000) id 749E6203B0; Sun, 25 Mar 2012 19:28:58 -0600 (MDT) From: Tim Gardner To: kernel-team@lists.ubuntu.com Subject: [Oneiric PATCH 7/8] kmod: make __request_module() killable Date: Sun, 25 Mar 2012 19:28:56 -0600 Message-Id: <1332725337-58475-7-git-send-email-tim.gardner@canonical.com> X-Mailer: git-send-email 1.7.9.1 In-Reply-To: <1332725337-58475-1-git-send-email-tim.gardner@canonical.com> References: <1332725337-58475-1-git-send-email-tim.gardner@canonical.com> X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.13 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: kernel-team-bounces@lists.ubuntu.com Errors-To: kernel-team-bounces@lists.ubuntu.com From: Oleg Nesterov BugLink: http://bugs.launchpad.net/bugs/963685 As Tetsuo Handa pointed out, request_module() can stress the system while the oom-killed caller sleeps in TASK_UNINTERRUPTIBLE. The task T uses "almost all" memory, then it does something which triggers request_module(). Say, it can simply call sys_socket(). This in turn needs more memory and leads to OOM. oom-killer correctly chooses T and kills it, but this can't help because it sleeps in TASK_UNINTERRUPTIBLE and after that oom-killer becomes "disabled" by the TIF_MEMDIE task T. Make __request_module() killable. The only necessary change is that call_modprobe() should kmalloc argv and module_name, they can't live in the stack if we use UMH_KILLABLE. This memory is freed via call_usermodehelper_freeinfo()->cleanup. Reported-by: Tetsuo Handa Signed-off-by: Oleg Nesterov Cc: Rusty Russell Cc: Tejun Heo Cc: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds (cherry picked from commit 1cc684ab75123efe7ff446eb821d44375ba8fa30) Signed-off-by: Tim Gardner --- kernel/kmod.c | 26 ++++++++++++++++++++++++-- 1 files changed, 24 insertions(+), 2 deletions(-) diff --git a/kernel/kmod.c b/kernel/kmod.c index ca9d2b1..fecaf21 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -58,6 +58,12 @@ static DEFINE_SPINLOCK(umh_sysctl_lock); */ char modprobe_path[KMOD_PATH_LEN] = "/sbin/modprobe"; +static void free_modprobe_argv(struct subprocess_info *info) +{ + kfree(info->argv[3]); /* check call_modprobe() */ + kfree(info->argv); +} + static int call_modprobe(char *module_name, int wait) { static char *envp[] = { @@ -67,10 +73,26 @@ static int call_modprobe(char *module_name, int wait) NULL }; - char *argv[] = { modprobe_path, "-q", "--", module_name, NULL }; + char **argv = kmalloc(sizeof(char *[5]), GFP_KERNEL); + if (!argv) + goto out; + + module_name = kstrdup(module_name, GFP_KERNEL); + if (!module_name) + goto free_argv; + + argv[0] = modprobe_path; + argv[1] = "-q"; + argv[2] = "--"; + argv[3] = module_name; /* check free_modprobe_argv() */ + argv[4] = NULL; return call_usermodehelper_fns(modprobe_path, argv, envp, - wait, NULL, NULL, NULL); + wait | UMH_KILLABLE, NULL, free_modprobe_argv, NULL); +free_argv: + kfree(argv); +out: + return -ENOMEM; } /**