From: Luis Chamberlain <mcgrof@kernel.org>
To: linux-modules@vger.kernel.org, linux-kernel@vger.kernel.org,
pmladek@suse.com, david@redhat.com, petr.pavlu@suse.com,
prarit@redhat.com
Cc: christophe.leroy@csgroup.eu, song@kernel.org, mcgrof@kernel.org
Subject: [RFT 3/5] module: avoid allocation if module is already present and ready
Date: Sun, 19 Mar 2023 14:49:24 -0700 [thread overview]
Message-ID: <20230319214926.1794108-4-mcgrof@kernel.org> (raw)
In-Reply-To: <20230319214926.1794108-1-mcgrof@kernel.org>
load_module() will allocate a struct module before even checking
if the module is already loaded. This can create unecessary memory
pressure since we can easily just check if the module is already
present early with the copy of the module information from userspace
after we've validated it a bit.
This can only be an issue if a system is getting hammered with userspace
loading modules. Note that there are two ways to load modules, one is
auto-loading in-kernel and that pings back to userspace to just call
modprobe, and we already have a way to restrict the count and load
from there on the kernel usermode helper. However that does not stop
a system from issuing tons of system calls to load a module. So userspace
itself *is* supposed to check if a module is present before loading it.
But we're observing situations where tons of the same module are in effect
being loaded. Although some of these are acknolwedged as in-kernel bugs
such as the ACPI frequency modules we can also help a bit more in the
modules side to avoid those dramatic situations. All that is just memory
being allocated to then be thrown away.
To avoid memory pressure for such stupid cases put a stop gap for them.
We now check for the module being present *before* allocation, and then
right after we are going to add it to the system.
On a 8vcpu 8 GiB RAM system using kdevops and testing against selftests
kmod.sh -t 0008 I see a saving in the *highest* side of memory
consumption of up to ~ 84 MiB. This can be obvserved and visualized
below. The time it takes to run the test is also not affected.
The gnuplot is set to a range from 400000 KiB (390 Mib) - 580000 (566 Mib)
given the tests peak around that range.
cat kmod-simple.plot
set term dumb
set output fileout
set yrange [400000:580000]
plot filein with linespoints title "Memory usage (KiB)"
Before:
root@kmod ~ # /data/linux-next/tools/testing/selftests/kmod/kmod.sh -t 0008
root@kmod ~ # free -k -s 1 -c 40 | grep Mem | awk '{print $3}' > log-0008-before.txt ^C
root@kmod ~ # sort -n -r log-0008-before.txt | head -1
528732
So ~516.33 MiB
After:
root@kmod ~ # /data/linux-next/tools/testing/selftests/kmod/kmod.sh -t 0008
root@kmod ~ # free -k -s 1 -c 40 | grep Mem | awk '{print $3}' > log-0008-after.txt ^C
root@kmod ~ # sort -n -r log-0008-after.txt | head -1
442516
So ~432.14 MiB
That's about 84 ~MiB in savings in the worst case. The graphs:
root@kmod ~ # gnuplot -e "filein='log-0008-before.txt'; fileout='graph-0008-before.txt'" kmod.plot
root@kmod ~ # gnuplot -e "filein='log-0008-after.txt'; fileout='graph-0008-after.txt'" kmod.plot
root@kmod ~ # cat graph-0008-before.txt
580000 +-----------------------------------------------------------------+
| + + + + + + + |
560000 |-+ Memory usage (KiB) ***A***-|
| |
540000 |-+ +-|
| |
| *A *AA*AA*A*AA *A*AA A*A*A *AA*A*AA*A A |
520000 |-+A*A*AA *AA*A *A*AA*A*AA *A*A A *A+-|
|*A |
500000 |-+ +-|
| |
480000 |-+ +-|
| |
460000 |-+ +-|
| |
| |
440000 |-+ +-|
| |
420000 |-+ +-|
| + + + + + + + |
400000 +-----------------------------------------------------------------+
0 5 10 15 20 25 30 35 40
root@kmod ~ # cat graph-0008-after.txt
580000 +-----------------------------------------------------------------+
| + + + + + + + |
560000 |-+ Memory usage (KiB) ***A***-|
| |
540000 |-+ +-|
| |
| |
520000 |-+ +-|
| |
500000 |-+ +-|
| |
480000 |-+ +-|
| |
460000 |-+ +-|
| |
| *A *A*A |
440000 |-+A*A*AA*A A A*A*AA A*A*AA*A*AA*A*AA*A*AA*AA*A*AA*A*AA-|
|*A *A*AA*A |
420000 |-+ +-|
| + + + + + + + |
400000 +-----------------------------------------------------------------+
0 5 10 15 20 25 30 35 40
Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
---
kernel/module/main.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/kernel/module/main.c b/kernel/module/main.c
index 3644438ff96e..0ad26455def2 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -2787,7 +2787,11 @@ static int early_mod_check(struct load_info *info, int flags)
if (err)
return err;
- return 0;
+ mutex_lock(&module_mutex);
+ err = module_patient_check_exists(info->mod->name);
+ mutex_unlock(&module_mutex);
+
+ return err;
}
/*
--
2.39.1
next prev parent reply other threads:[~2023-03-19 21:50 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-03-19 21:49 [RFT 0/5] module: avoid userspace pressure on unwanted allocations Luis Chamberlain
2023-03-19 21:49 ` [RFT 1/5] module: move finished_loading() Luis Chamberlain
2023-03-19 21:49 ` [RFT 2/5] module: extract patient module check into helper Luis Chamberlain
2023-03-19 21:49 ` Luis Chamberlain [this message]
2023-03-19 21:49 ` [RFT 4/5] module: use list_add_tail_rcu() when adding module Luis Chamberlain
2023-03-19 21:49 ` [RFT 5/5] module: add a sanity check prior to allowing kernel module auto-loading Luis Chamberlain
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230319214926.1794108-4-mcgrof@kernel.org \
--to=mcgrof@kernel.org \
--cc=christophe.leroy@csgroup.eu \
--cc=david@redhat.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-modules@vger.kernel.org \
--cc=petr.pavlu@suse.com \
--cc=pmladek@suse.com \
--cc=prarit@redhat.com \
--cc=song@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox