From patchwork Fri Apr 14 05:28:40 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luis Chamberlain X-Patchwork-Id: 13210957 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 79D29C77B70 for ; Fri, 14 Apr 2023 05:28:55 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id E701D900003; Fri, 14 Apr 2023 01:28:53 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id DD2BF90000B; Fri, 14 Apr 2023 01:28:53 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id C46B3900008; Fri, 14 Apr 2023 01:28:53 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0016.hostedemail.com [216.40.44.16]) by kanga.kvack.org (Postfix) with ESMTP id A5296900008 for ; Fri, 14 Apr 2023 01:28:53 -0400 (EDT) Received: from smtpin01.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay08.hostedemail.com (Postfix) with ESMTP id 70D2C140136 for ; Fri, 14 Apr 2023 05:28:53 +0000 (UTC) X-FDA: 80678867346.01.BBAB137 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) by imf01.hostedemail.com (Postfix) with ESMTP id C466F4000D for ; Fri, 14 Apr 2023 05:28:51 +0000 (UTC) Authentication-Results: imf01.hostedemail.com; dkim=pass header.d=infradead.org header.s=bombadil.20210309 header.b=pyZpQs+2; spf=none (imf01.hostedemail.com: domain of mcgrof@infradead.org has no SPF policy when checking 198.137.202.133) smtp.mailfrom=mcgrof@infradead.org; dmarc=fail reason="No valid SPF, DKIM not aligned (relaxed)" header.from=kernel.org (policy=none) ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1681450131; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=iHqXveUS6IchndxGgVtwZgcMZJ63gxl6r7jEFf+BmmQ=; b=cNTZINLVyAZ5gmlHbrwrpf29IEme15PoVbKrZWt0M16Kbs2X253X0F7B2iGKHr1cpJVHrJ ARXaSsklvADcYabCj2hwoxyJp5BoTlKKaRA5NTtbfxB1J8bzO4fxrDV1m73Yn6G2H0fMVu v4+Q8Hm3Vt6A6nrAk20gj3aPVbjbnug= ARC-Authentication-Results: i=1; imf01.hostedemail.com; dkim=pass header.d=infradead.org header.s=bombadil.20210309 header.b=pyZpQs+2; spf=none (imf01.hostedemail.com: domain of mcgrof@infradead.org has no SPF policy when checking 198.137.202.133) smtp.mailfrom=mcgrof@infradead.org; dmarc=fail reason="No valid SPF, DKIM not aligned (relaxed)" header.from=kernel.org (policy=none) ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1681450131; a=rsa-sha256; cv=none; b=PUB6kyS6iz1sBNbRrsURCgzfivih83dfLji/GARYragf3Dipo8SSASJIbFjCsag0mykbJf FKHy9ua5z42zMJiJPiKk3Q/l7CwUMtD+FeaLhhE4DbfqW+m/nv5STHAfGIax/o1brf7TWL BBhuy7CnTztKUwlgsDlo4gvmqwlaP7w= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=bombadil.20210309; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description; bh=iHqXveUS6IchndxGgVtwZgcMZJ63gxl6r7jEFf+BmmQ=; b=pyZpQs+2xUZDAnoUe91m55tZ9q kcL7s7vIi+nON6Qz7z6OecQophFoBQ/0SkX1pNpLz4trrf2w/feIZd+VfsAVN+ZV0O/xJzjhaZR4b VaIMJHAYptwtfbcf8Ui0qNGgQ/XCgwu/OM0sA7PtnI2J0kK/UtJ++8WzTKOpK5dtERQievV63UQkg lbYYuEiB9vd/qfXl58xqd7G28Y8QO17HxGr79uEpA9XuaOJG+3DK+Fa3YhHEQqdeB8Znji1Uhnb4s 8+MK1f7MkPtDth6H6pQ6smxGuoM/mUFf7Dg4DrANgOgaPOfoxupyKUr9kfIdAnED7La6RhoP17+nP 3hZPX9Jw==; Received: from mcgrof by bombadil.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pnBzK-008Msj-0u; Fri, 14 Apr 2023 05:28:46 +0000 From: Luis Chamberlain To: david@redhat.com, patches@lists.linux.dev, linux-modules@vger.kernel.org, linux-mm@kvack.org, linux-kernel@vger.kernel.org, pmladek@suse.com, petr.pavlu@suse.com, prarit@redhat.com, torvalds@linux-foundation.org, gregkh@linuxfoundation.org, rafael@kernel.org Cc: christophe.leroy@csgroup.eu, tglx@linutronix.de, peterz@infradead.org, song@kernel.org, rppt@kernel.org, dave@stgolabs.net, willy@infradead.org, vbabka@suse.cz, mhocko@suse.com, dave.hansen@linux.intel.com, colin.i.king@gmail.com, jim.cromie@gmail.com, catalin.marinas@arm.com, jbaron@akamai.com, rick.p.edgecombe@intel.com, mcgrof@kernel.org Subject: [RFC 2/2] kread: avoid duplicates Date: Thu, 13 Apr 2023 22:28:40 -0700 Message-Id: <20230414052840.1994456-3-mcgrof@kernel.org> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20230414052840.1994456-1-mcgrof@kernel.org> References: <20230414052840.1994456-1-mcgrof@kernel.org> MIME-Version: 1.0 X-Rspam-User: X-Rspamd-Server: rspam03 X-Stat-Signature: byikuabep38j7cjnkuesitjhht751nau X-Rspamd-Queue-Id: C466F4000D X-HE-Tag: 1681450131-508581 X-HE-Meta: U2FsdGVkX19jFfoVrrKWOaSp3xD4TiBCWhJx91M7AHe7jZxcpy2A0KKqYrHefIa9NTwkb/SXG/VVtzkiimcwQfLm1s3J6bw6CIHPTMY96vui/bkr231Ce7luZ+jbKLYK2ws3puOsuA3rIfNSdBrElg0M17/6r1Ykm+/UoEWwMEJ0kLaatdsRxaEfE9R0T6iXktPgEPo7Ueh+veFCCmzXTqJ/L1a4qQgPzc/CKuligPckS32rNBl3R4GAEpOzg//2uo8F5rNNK+G5wex+RFlQFsylPvqdleNRzj6ZepIPZnFlPYUCECJabyOiwJVLxjSNeGfAiA/qJcaiNPOWztgVhy0CdFVbcK7Ee1MwtGSs3Bj30DFNS8nX0dK0X43c6YxrI62thgVXY6PqjWaefh7wZtVtgV+haiK0wD93tJS7fcraXnipnG6QyA5mRCmYjMXCV0em0gf/g8WEzfJmdlKazF1P/rVzw05V5a+lNoDAmAXk1ATx7yWoB4ZyZpcIf406oN1cPRlQ468pAA+ADaQ1pxs0r0JxCnWhPDSi1St73Of4GkMQHu1hiUGYHjjMmDZu16gbZsr3K8cZx53dHCgwUKu5nPBdxzvIC+35SixLCM7NhqnlBGGLYgd/PJhs+BHlDKCoJgbgn0Fh9pvavbD+/ccl0T/OEiZV7GfqPcyyHknO8IjKC+jLV0KZIeQtjpvqW9AhLv/1QyQ3tmebiS2dhkXo3timeMwkoc/IjVKM7PqDB/vOHwqdZpoztAQw93NSoPa9zoGWTrzLUaVWcNb1i79AV/NDZjH0yYr64msLXDGMBNVOpw5+GjvgRj4TK2i4xi8BdZ591pUKcZBgK9psPZsFwE4qoC/v63TZvfoitTf6qgw4JI7pX8s7QM8aJaZWbPOYDEr3t5SNRuGcTHVPH++1OoL3X5I43mBVeswMFnZVaA/ttZIp01kfDhD/EoJafv2yBnVtuHJDPpGBRH/ zxIj52lO 5VE+C0qq/2OHKTf+vIrrZR0R3IuC2Uod6DuCT4TLbq4yFk/bcWnTBpgbv50G1rxq/d/UH2DHvuaHZoQDaupGgC+k4fPkNHPo2ro+rNLa2fye6AiFm+wHZn0TqsSHOxXZRSVzkHKywSJwLPU8KL6T65sLTFOHT936YD6byCg2/Cpu+wYQ3mGa9KThX6jO199E4YnRn3VRUEADNzQlp7yZOISDMMTLnXj68PMNnqLWGe9mk4ViRqmITNegQFR/tnDK3TSjV7GDSbyujOph9rdITjHNSj/I6nBY4O7I+iFhincnTppgh8iJOTt1nA444S0S3uXWqDqfun24Z5E4g6Vvtg807vYWmuyk2EMXGDOCaTuFS2/22licOvdsMlZ3e+r+EuIU7JGKQBYjtTIBHmqsZEreV6ftEvyzjdug0d0W0ZiDaIa4/gPylcNPIOdSscMUgoJXurEOJLh6Zy31Gl1GsKgnsXqIDlneUtmj4MRTKcT5HQ0g= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: With this we run into 0 wasted virtual memory bytes. Signed-off-by: Luis Chamberlain --- fs/kernel_read_file.c | 150 ++++++++++++++++++++++++++++++++++++++++++ kernel/module/main.c | 6 +- 2 files changed, 154 insertions(+), 2 deletions(-) diff --git a/fs/kernel_read_file.c b/fs/kernel_read_file.c index 5d826274570c..209c56764442 100644 --- a/fs/kernel_read_file.c +++ b/fs/kernel_read_file.c @@ -4,6 +4,7 @@ #include #include #include +#include /** * kernel_read_file() - read file contents into a kernel buffer @@ -171,17 +172,166 @@ ssize_t kernel_read_file_from_path_initns(const char *path, loff_t offset, } EXPORT_SYMBOL_GPL(kernel_read_file_from_path_initns); +DEFINE_MUTEX(kread_dup_mutex); +static LIST_HEAD(kread_dup_reqs); + +struct kread_dup_req { + struct list_head list; + char name[PATH_MAX]; + struct completion first_req_done; + struct work_struct complete_work; + struct delayed_work delete_work; + int dup_ret; +}; + +static struct kread_dup_req *kread_dup_request_lookup(char *name) +{ + struct kread_dup_req *kread_req; + + list_for_each_entry_rcu(kread_req, &kread_dup_reqs, list, + lockdep_is_held(&kread_dup_mutex)) { + if (strlen(kread_req->name) == strlen(name) && + !memcmp(kread_req->name, name, strlen(name))) { + return kread_req; + } + } + + return NULL; +} + +static void kread_dup_request_delete(struct work_struct *work) +{ + struct kread_dup_req *kread_req; + kread_req = container_of(to_delayed_work(work), struct kread_dup_req, delete_work); + + mutex_lock(&kread_dup_mutex); + list_del_rcu(&kread_req->list); + synchronize_rcu(); + mutex_unlock(&kread_dup_mutex); + kfree(kread_req); +} + +static void kread_dup_request_complete(struct work_struct *work) +{ + struct kread_dup_req *kread_req; + + kread_req = container_of(work, struct kread_dup_req, complete_work); + + complete_all(&kread_req->first_req_done); + queue_delayed_work(system_wq, &kread_req->delete_work, 60 * HZ); +} + +static bool kread_dup_request_exists_wait(char *name, int *dup_ret) +{ + struct kread_dup_req *kread_req, *new_kread_req; + int ret; + + /* + * Pre-allocate the entry in case we have to use it later + * to avoid contention with the mutex. + */ + new_kread_req = kzalloc(sizeof(*new_kread_req), GFP_KERNEL); + if (!new_kread_req) + return false; + + memcpy(new_kread_req->name, name, strlen(name)); + INIT_WORK(&new_kread_req->complete_work, kread_dup_request_complete); + INIT_DELAYED_WORK(&new_kread_req->delete_work, kread_dup_request_delete); + init_completion(&new_kread_req->first_req_done); + + mutex_lock(&kread_dup_mutex); + + kread_req = kread_dup_request_lookup(name); + if (!kread_req) { + /* + * There was no duplicate, just add the request so we can + * keep tab on duplicates later. + */ + //pr_info("New kread request for %s\n", name); + list_add_rcu(&new_kread_req->list, &kread_dup_reqs); + mutex_unlock(&kread_dup_mutex); + return false; + } + mutex_unlock(&kread_dup_mutex); + + /* We are dealing with a duplicate request now */ + + kfree(new_kread_req); + + //pr_warn("kread: duplicate request for file %s\n", name); + + ret = wait_for_completion_state(&kread_req->first_req_done, + TASK_UNINTERRUPTIBLE | TASK_KILLABLE); + if (ret) { + *dup_ret = ret; + return true; + } + + /* breath */ + schedule_timeout(2*HZ); + + *dup_ret = kread_req->dup_ret; + + return true; +} + +void kread_dup_request_announce(char *name, int ret) +{ + struct kread_dup_req *kread_req; + + mutex_lock(&kread_dup_mutex); + + kread_req = kread_dup_request_lookup(name); + if (!kread_req) + goto out; + + kread_req->dup_ret = ret; + + /* + * If we complete() here we may allow duplicate threads + * to continue before the first one that submitted the + * request. We're in no rush but avoid boot delays caused + * by these threads waiting too long. + */ + queue_work(system_wq, &kread_req->complete_work); + +out: + mutex_unlock(&kread_dup_mutex); +} + ssize_t kernel_read_file_from_fd(int fd, loff_t offset, void **buf, size_t buf_size, size_t *file_size, enum kernel_read_file_id id) { struct fd f = fdget(fd); ssize_t ret = -EBADF; + char *name, *path; + int dup_ret; if (!f.file || !(f.file->f_mode & FMODE_READ)) goto out; + path = kzalloc(PATH_MAX, GFP_KERNEL); + if (!path) + return -ENOMEM; + + name = file_path(f.file, path, PATH_MAX); + if (IS_ERR(name)) { + ret = PTR_ERR(name); + goto out_mem; + } + + if (kread_dup_request_exists_wait(name, &dup_ret)) { + ret = -EBUSY; + goto out_mem; + } + ret = kernel_read_file(f.file, offset, buf, buf_size, file_size, id); + + kread_dup_request_announce(name, ret); + +out_mem: + kfree(path); out: fdput(f); return ret; diff --git a/kernel/module/main.c b/kernel/module/main.c index 1ed373145278..e99419b4d85c 100644 --- a/kernel/module/main.c +++ b/kernel/module/main.c @@ -3080,8 +3080,10 @@ SYSCALL_DEFINE3(finit_module, int, fd, const char __user *, uargs, int, flags) len = kernel_read_file_from_fd(fd, 0, &buf, INT_MAX, NULL, READING_MODULE); if (len < 0) { - mod_stat_inc(&failed_kreads); - mod_stat_add_long(len, &invalid_kread_bytes); + if (len != -EBUSY) { + mod_stat_inc(&failed_kreads); + mod_stat_add_long(len, &invalid_kread_bytes); + } return len; }