From patchwork Fri Mar 12 09:55:22 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Johannes Berg X-Patchwork-Id: 1451814 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.infradead.org (client-ip=2001:8b0:10b:1:d65d:64ff:fe57:4e05; helo=desiato.infradead.org; envelope-from=linux-um-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=desiato.20200630 header.b=QUydDQ58; dkim-atps=neutral Received: from desiato.infradead.org (desiato.infradead.org [IPv6:2001:8b0:10b:1:d65d:64ff:fe57:4e05]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4Dxh68311nz9sRR for ; Fri, 12 Mar 2021 20:56:16 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding :Content-Type:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date: Subject:Cc:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=Ypvj5oK+bpwO74XRXUcYo18cLFFGdeWEp1ZwzljrPUg=; b=QUydDQ58IBtZhLTKsvdw0U9K3 CBPqkgm74yaehSBw6VIktiHDKG2NHhZczNYbJEnivQ0bzVsVJd9qzpicZwmGAN/iq+d6NhNvYejir sNYCduztICQzAvdeIxLstlv/OYfhy4qlb/zlXA1l36911f+6aXKIYvyZ/LxJl6oB401Cq7+5OZ0Z+ XoQoLEU3ulk+g9kmst8BeP4ianGrHVVcC947GnQmAFFxqwZsGpu0Irj99HO+sRscCQJF2RhXgxOkc aIEdQo00D9EPqJH3uEFw2/nQ/nM4Er/cqzK4AEwIa2kD8BNxsc0CrM/4z5QsEydT/EaMgUs4rKNLn /pxjmHPGw==; Received: from localhost ([::1] helo=desiato.infradead.org) by desiato.infradead.org with esmtp (Exim 4.94 #2 (Red Hat Linux)) id 1lKeWZ-00B5e3-IM; Fri, 12 Mar 2021 09:56:04 +0000 Received: from s3.sipsolutions.net ([2a01:4f8:191:4433::2] helo=sipsolutions.net) by desiato.infradead.org with esmtps (Exim 4.94 #2 (Red Hat Linux)) id 1lKeW5-00B5Tm-Ra for linux-um@lists.infradead.org; Fri, 12 Mar 2021 09:55:49 +0000 Received: by sipsolutions.net with esmtpsa (TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.94) (envelope-from ) id 1lKeW1-00F7m8-KI; Fri, 12 Mar 2021 10:55:29 +0100 From: Johannes Berg To: linux-kernel@vger.kernel.org, linux-um@lists.infradead.org Cc: Jessica Yu , Alexander Viro , linux-fsdevel@vger.kernel.org, Johannes Berg Subject: [PATCH 2/6] module: add support for CONFIG_MODULE_DESTRUCTORS Date: Fri, 12 Mar 2021 10:55:22 +0100 Message-Id: <20210312104627.8b2523b0593c.Ib0fb7906e3d7bd69ebe5eb877e2e9f33ef915d4b@changeid> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210312095526.197739-1-johannes@sipsolutions.net> References: <20210312095526.197739-1-johannes@sipsolutions.net> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210312_095534_855185_CFE6C0D8 X-CRM114-Status: GOOD ( 19.92 ) X-Spam-Score: 0.4 (/) X-Spam-Report: Spam detection software, running on the system "desiato.infradead.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: From: Johannes Berg At least in ARCH=um with CONFIG_GCOV (which writes all the coverage data directly out from the userspace binary rather than presenting it in debugfs) it's necessary to run all the atexit handlers (dto [...] Content analysis details: (0.4 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 SPF_NONE SPF: sender does not publish an SPF Record 0.4 KHOP_HELO_FCRDNS Relay HELO differs from its IP's reverse DNS X-BeenThere: linux-um@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-um" Errors-To: linux-um-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org From: Johannes Berg At least in ARCH=um with CONFIG_GCOV (which writes all the coverage data directly out from the userspace binary rather than presenting it in debugfs) it's necessary to run all the atexit handlers (dtors/fini_array) so that gcov actually does write out the data. Add a new config option CONFIG_MODULE_DESTRUCTORS that can be selected via CONFIG_WANT_MODULE_DESTRUCTORS that the arch selects (this indirection exists so the architecture doesn't have to worry about whether or not CONFIG_MODULES is on). Additionally, the architecture must then (when it exits and no more module code can run) call run_all_module_destructors to run the code for all modules that are still loaded. When modules are unloaded, the handlers are called as well. Signed-off-by: Johannes Berg --- include/linux/module.h | 14 ++++++++++++++ init/Kconfig | 17 +++++++++++++++++ kernel/module.c | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+) diff --git a/include/linux/module.h b/include/linux/module.h index 59f094fa6f74..8574d76a884d 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -517,6 +517,12 @@ struct module { unsigned int num_ctors; #endif +#ifdef CONFIG_MODULE_DESTRUCTORS + /* Destructor functions. */ + ctor_fn_t *dtors; + unsigned int num_dtors; +#endif + #ifdef CONFIG_FUNCTION_ERROR_INJECTION struct error_injection_entry *ei_funcs; unsigned int num_ei_funcs; @@ -853,4 +859,12 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *, unsigned long), void *data); +#ifdef CONFIG_MODULE_DESTRUCTORS +void run_all_module_destructors(void); +#else +static inline void run_all_module_destructors(void) +{ +} +#endif + #endif /* _LINUX_MODULE_H */ diff --git a/init/Kconfig b/init/Kconfig index 22946fe5ded9..b0f0f51f9d2c 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -2295,6 +2295,23 @@ config UNUSED_KSYMS_WHITELIST endif # MODULES +config WANT_MODULE_DESTRUCTORS + bool + help + Architectures may select this if they need atexit functions (such as + generated by the compiler for -ftest-coverage/gcov) to run in modules. + They're then responsible for calling run_all_module_destructors() at + shutdown so that module destructors are called for all still loaded + modules as well. + + Note that CONFIG_GCOV_KERNEL does *not* require this since it keeps + all the coverage data in the kernel, notably CONFIG_GCOV in ARCH=um + requires this. + +config MODULE_DESTRUCTORS + def_bool y + depends on WANT_MODULE_DESTRUCTORS && MODULES + config MODULES_TREE_LOOKUP def_bool y depends on PERF_EVENTS || TRACING diff --git a/kernel/module.c b/kernel/module.c index 30479355ab85..3023b5f054d4 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -904,6 +904,27 @@ EXPORT_SYMBOL(module_refcount); /* This exists whether we can unload or not */ static void free_module(struct module *mod); +#ifdef CONFIG_MODULE_DESTRUCTORS +static void do_mod_dtors(struct module *mod) +{ + unsigned long i; + + for (i = 0; i < mod->num_dtors; i++) + mod->dtors[i](); +} + +void run_all_module_destructors(void) +{ + struct module *mod; + + /* we no longer need to care about locking at this point */ + list_for_each_entry(mod, &modules, list) + do_mod_dtors(mod); +} +#else +static inline void do_mod_dtors(struct module *mod) {} +#endif + SYSCALL_DEFINE2(delete_module, const char __user *, name_user, unsigned int, flags) { @@ -966,6 +987,7 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user, MODULE_STATE_GOING, mod); klp_module_going(mod); ftrace_release_mod(mod); + do_mod_dtors(mod); async_synchronize_full(); @@ -3263,6 +3285,23 @@ static int find_module_sections(struct module *mod, struct load_info *info) } #endif +#ifdef CONFIG_MODULE_DESTRUCTORS + mod->dtors = section_objs(info, ".dtors", + sizeof(*mod->dtors), &mod->num_dtors); + if (!mod->dtors) + mod->dtors = section_objs(info, ".fini_array", + sizeof(*mod->dtors), &mod->num_dtors); + else if (find_sec(info, ".fini_array")) { + /* + * This shouldn't happen with same compiler and binutils + * building all parts of the module. + */ + pr_warn("%s: has both .dtors and .fini_array.\n", + mod->name); + return -EINVAL; + } +#endif + mod->noinstr_text_start = section_objs(info, ".noinstr.text", 1, &mod->noinstr_text_size);