All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/6] module: avoid userspace pressure on unwanted allocations
@ 2023-04-05  2:26 Luis Chamberlain
  2023-04-05  2:26 ` [PATCH v2 1/6] module: fix kmemleak annotations for non init ELF sections Luis Chamberlain
                   ` (5 more replies)
  0 siblings, 6 replies; 23+ messages in thread
From: Luis Chamberlain @ 2023-04-05  2:26 UTC (permalink / raw)
  To: david, patches, linux-modules, linux-mm, linux-kernel, pmladek,
	petr.pavlu, prarit, torvalds, gregkh, rafael
  Cc: christophe.leroy, tglx, peterz, song, rppt, dave, willy, vbabka,
	mhocko, dave.hansen, colin.i.king, jim.cromie, catalin.marinas,
	jbaron, rick.p.edgecombe, mcgrof

This v2 series follows up on the first iteration of these patches [0].
They have the following changes made:

  o Rolled in fix for an kmemleak issue reported by Jim Cromie
  o Dropped from this series all the semaphore & and simplifications
    on kmod.c as that should just be sent as a separate bike-shedding
    opporunity patch series and it does not in any way address the
    the unwanted allocations.
  o The rest of the feedback was just from Greg KH and I've addressed
    all his feedback. I decided to do away with the debug.c as a
    separate file and leave the #ifdef CONFIG_MODULE_DEBUG eyesore
    at the end of main.c. I guess it's not so bad there.
  o *Tons* of fixes and enhancements to my counters, including tons
    of documentation to help ensure we don't loose track of some of
    the tribal knowledge and so to help ensure we have references to
    what our accounting looks like. Those large wasted virtual memory
    allocations on a simple qemu idle boring boot are simply rediculous, I
    am quite baffled we had not spotted this before, and so it all reveals
    we have quite a bit of optimizations left to do to make loading modules
    an even more smoother experience at bootup.

If you'd like a tree this is on my 20230404-module-alloc-opts branch based
on modules-next [1].

[0] https://lkml.kernel.org/r/20230329053149.3976378-1-mcgrof@kernel.org
[1] https://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/linux.git/log/?h=20230404-module-alloc-opts

Luis Chamberlain (6):
  module: fix kmemleak annotations for non init ELF sections
  module: move finished_loading()
  module: extract patient module check into helper
  module: avoid allocation if module is already present and ready
  debugfs: add debugfs_create_atomic64_t for atomic64_t
  module: add debug stats to help identify memory pressure

 Documentation/core-api/kernel-api.rst |  22 +-
 fs/debugfs/file.c                     |  36 +++
 include/linux/debugfs.h               |   2 +
 kernel/module/Kconfig                 |  37 +++
 kernel/module/Makefile                |   1 +
 kernel/module/decompress.c            |   4 +
 kernel/module/internal.h              |  74 +++++
 kernel/module/main.c                  | 198 ++++++++----
 kernel/module/stats.c                 | 428 ++++++++++++++++++++++++++
 kernel/module/tracking.c              |   7 +-
 10 files changed, 742 insertions(+), 67 deletions(-)
 create mode 100644 kernel/module/stats.c

-- 
2.39.2


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH v2 1/6] module: fix kmemleak annotations for non init ELF sections
  2023-04-05  2:26 [PATCH v2 0/6] module: avoid userspace pressure on unwanted allocations Luis Chamberlain
@ 2023-04-05  2:26 ` Luis Chamberlain
  2023-04-05  6:52   ` Song Liu
  2023-04-11 15:17   ` Catalin Marinas
  2023-04-05  2:26 ` [PATCH v2 2/6] module: move finished_loading() Luis Chamberlain
                   ` (4 subsequent siblings)
  5 siblings, 2 replies; 23+ messages in thread
From: Luis Chamberlain @ 2023-04-05  2:26 UTC (permalink / raw)
  To: david, patches, linux-modules, linux-mm, linux-kernel, pmladek,
	petr.pavlu, prarit, torvalds, gregkh, rafael
  Cc: christophe.leroy, tglx, peterz, song, rppt, dave, willy, vbabka,
	mhocko, dave.hansen, colin.i.king, jim.cromie, catalin.marinas,
	jbaron, rick.p.edgecombe, mcgrof

Commit ac3b43283923 ("module: replace module_layout with module_memory")
reworked the way to handle memory allocations to make it clearer. But it
lost in translation how we handled kmemleak_ignore() or kmemleak_not_leak()
for different ELF sections.

Fix this and clarify the comments a bit more.

Fixes: ac3b43283923 ("module: replace module_layout with module_memory")
Reported-by: Jim Cromie <jim.cromie@gmail.com>
Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
---
 kernel/module/main.c | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/kernel/module/main.c b/kernel/module/main.c
index 5cc21083af04..d8bb23fa6989 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -2233,11 +2233,23 @@ static int move_module(struct module *mod, struct load_info *info)
 		ptr = module_memory_alloc(mod->mem[type].size, type);
 
 		/*
-		 * The pointer to this block is stored in the module structure
-		 * which is inside the block. Just mark it as not being a
-		 * leak.
+		 * The pointer to these blocks of memory are stored on the module
+		 * structure and we keep that around so long as the module is
+		 * around. We only free that memory when we unload the module.
+		 * Just mark them as not being a leak then. The .init* ELF
+		 * sections *do* get freed after boot so we treat them slightly
+		 * differently and only grey them out -- they work as typical
+		 * memory allocations which *do* eventually get freed.
 		 */
-		kmemleak_ignore(ptr);
+		switch (type) {
+		case MOD_INIT_TEXT: /* fallthrough */
+		case MOD_INIT_DATA: /* fallthrough */
+		case MOD_INIT_RODATA: /* fallthrough */
+			kmemleak_ignore(ptr);
+			break;
+		default:
+			kmemleak_not_leak(ptr);
+		}
 		if (!ptr) {
 			t = type;
 			goto out_enomem;
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 2/6] module: move finished_loading()
  2023-04-05  2:26 [PATCH v2 0/6] module: avoid userspace pressure on unwanted allocations Luis Chamberlain
  2023-04-05  2:26 ` [PATCH v2 1/6] module: fix kmemleak annotations for non init ELF sections Luis Chamberlain
@ 2023-04-05  2:26 ` Luis Chamberlain
  2023-04-05 17:06   ` David Hildenbrand
  2023-04-05  2:26 ` [PATCH v2 3/6] module: extract patient module check into helper Luis Chamberlain
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 23+ messages in thread
From: Luis Chamberlain @ 2023-04-05  2:26 UTC (permalink / raw)
  To: david, patches, linux-modules, linux-mm, linux-kernel, pmladek,
	petr.pavlu, prarit, torvalds, gregkh, rafael
  Cc: christophe.leroy, tglx, peterz, song, rppt, dave, willy, vbabka,
	mhocko, dave.hansen, colin.i.king, jim.cromie, catalin.marinas,
	jbaron, rick.p.edgecombe, mcgrof

This has no functional change, just moves a routine earlier
as we'll make use of it next.

Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
---
 kernel/module/main.c | 42 +++++++++++++++++++++---------------------
 1 file changed, 21 insertions(+), 21 deletions(-)

diff --git a/kernel/module/main.c b/kernel/module/main.c
index d8bb23fa6989..98c261928325 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -2454,27 +2454,6 @@ static int post_relocation(struct module *mod, const struct load_info *info)
 	return module_finalize(info->hdr, info->sechdrs, mod);
 }
 
-/* Is this module of this name done loading?  No locks held. */
-static bool finished_loading(const char *name)
-{
-	struct module *mod;
-	bool ret;
-
-	/*
-	 * The module_mutex should not be a heavily contended lock;
-	 * if we get the occasional sleep here, we'll go an extra iteration
-	 * in the wait_event_interruptible(), which is harmless.
-	 */
-	sched_annotate_sleep();
-	mutex_lock(&module_mutex);
-	mod = find_module_all(name, strlen(name), true);
-	ret = !mod || mod->state == MODULE_STATE_LIVE
-		|| mod->state == MODULE_STATE_GOING;
-	mutex_unlock(&module_mutex);
-
-	return ret;
-}
-
 /* Call module constructors. */
 static void do_mod_ctors(struct module *mod)
 {
@@ -2638,6 +2617,27 @@ static int may_init_module(void)
 	return 0;
 }
 
+/* Is this module of this name done loading?  No locks held. */
+static bool finished_loading(const char *name)
+{
+	struct module *mod;
+	bool ret;
+
+	/*
+	 * The module_mutex should not be a heavily contended lock;
+	 * if we get the occasional sleep here, we'll go an extra iteration
+	 * in the wait_event_interruptible(), which is harmless.
+	 */
+	sched_annotate_sleep();
+	mutex_lock(&module_mutex);
+	mod = find_module_all(name, strlen(name), true);
+	ret = !mod || mod->state == MODULE_STATE_LIVE
+		|| mod->state == MODULE_STATE_GOING;
+	mutex_unlock(&module_mutex);
+
+	return ret;
+}
+
 /*
  * We try to place it in the list now to make sure it's unique before
  * we dedicate too many resources.  In particular, temporary percpu
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 3/6] module: extract patient module check into helper
  2023-04-05  2:26 [PATCH v2 0/6] module: avoid userspace pressure on unwanted allocations Luis Chamberlain
  2023-04-05  2:26 ` [PATCH v2 1/6] module: fix kmemleak annotations for non init ELF sections Luis Chamberlain
  2023-04-05  2:26 ` [PATCH v2 2/6] module: move finished_loading() Luis Chamberlain
@ 2023-04-05  2:26 ` Luis Chamberlain
  2023-04-05 17:11   ` David Hildenbrand
  2023-04-05  2:27 ` [PATCH v2 4/6] module: avoid allocation if module is already present and ready Luis Chamberlain
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 23+ messages in thread
From: Luis Chamberlain @ 2023-04-05  2:26 UTC (permalink / raw)
  To: david, patches, linux-modules, linux-mm, linux-kernel, pmladek,
	petr.pavlu, prarit, torvalds, gregkh, rafael
  Cc: christophe.leroy, tglx, peterz, song, rppt, dave, willy, vbabka,
	mhocko, dave.hansen, colin.i.king, jim.cromie, catalin.marinas,
	jbaron, rick.p.edgecombe, mcgrof

The patient module check inside add_unformed_module() is large
enough as we need it. It is a bit hard to read too, so just
move it to a helper and do the inverse checks first to help
shift the code and make it easier to read. The new helper then
is module_patient_check_exists().

Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
---
 kernel/module/main.c | 71 +++++++++++++++++++++++++-------------------
 1 file changed, 40 insertions(+), 31 deletions(-)

diff --git a/kernel/module/main.c b/kernel/module/main.c
index 98c261928325..8f382580195b 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -2638,6 +2638,43 @@ static bool finished_loading(const char *name)
 	return ret;
 }
 
+/* Must be called with module_mutex held */
+static int module_patient_check_exists(const char *name)
+{
+	struct module *old;
+	int err = 0;
+
+	old = find_module_all(name, strlen(name), true);
+	if (old == NULL)
+		return 0;
+
+	if (old->state == MODULE_STATE_COMING
+	    || old->state == MODULE_STATE_UNFORMED) {
+		/* Wait in case it fails to load. */
+		mutex_unlock(&module_mutex);
+		err = wait_event_interruptible(module_wq,
+				       finished_loading(name));
+		if (err)
+			return err;
+
+		/* The module might have gone in the meantime. */
+		mutex_lock(&module_mutex);
+		old = find_module_all(name, strlen(name), true);
+	}
+
+	/*
+	 * We are here only when the same module was being loaded. Do
+	 * not try to load it again right now. It prevents long delays
+	 * caused by serialized module load failures. It might happen
+	 * when more devices of the same type trigger load of
+	 * a particular module.
+	 */
+	if (old && old->state == MODULE_STATE_LIVE)
+		return -EEXIST;
+	else
+		return -EBUSY;
+}
+
 /*
  * We try to place it in the list now to make sure it's unique before
  * we dedicate too many resources.  In particular, temporary percpu
@@ -2646,41 +2683,14 @@ static bool finished_loading(const char *name)
 static int add_unformed_module(struct module *mod)
 {
 	int err;
-	struct module *old;
 
 	mod->state = MODULE_STATE_UNFORMED;
 
 	mutex_lock(&module_mutex);
-	old = find_module_all(mod->name, strlen(mod->name), true);
-	if (old != NULL) {
-		if (old->state == MODULE_STATE_COMING
-		    || old->state == MODULE_STATE_UNFORMED) {
-			/* Wait in case it fails to load. */
-			mutex_unlock(&module_mutex);
-			err = wait_event_interruptible(module_wq,
-					       finished_loading(mod->name));
-			if (err)
-				goto out_unlocked;
-
-			/* The module might have gone in the meantime. */
-			mutex_lock(&module_mutex);
-			old = find_module_all(mod->name, strlen(mod->name),
-					      true);
-		}
-
-		/*
-		 * We are here only when the same module was being loaded. Do
-		 * not try to load it again right now. It prevents long delays
-		 * caused by serialized module load failures. It might happen
-		 * when more devices of the same type trigger load of
-		 * a particular module.
-		 */
-		if (old && old->state == MODULE_STATE_LIVE)
-			err = -EEXIST;
-		else
-			err = -EBUSY;
+	err = module_patient_check_exists(mod->name);
+	if (err)
 		goto out;
-	}
+
 	mod_update_bounds(mod);
 	list_add_rcu(&mod->list, &modules);
 	mod_tree_insert(mod);
@@ -2688,7 +2698,6 @@ static int add_unformed_module(struct module *mod)
 
 out:
 	mutex_unlock(&module_mutex);
-out_unlocked:
 	return err;
 }
 
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 4/6] module: avoid allocation if module is already present and ready
  2023-04-05  2:26 [PATCH v2 0/6] module: avoid userspace pressure on unwanted allocations Luis Chamberlain
                   ` (2 preceding siblings ...)
  2023-04-05  2:26 ` [PATCH v2 3/6] module: extract patient module check into helper Luis Chamberlain
@ 2023-04-05  2:27 ` Luis Chamberlain
  2023-04-05  2:27 ` [PATCH v2 5/6] debugfs: add debugfs_create_atomic64_t for atomic64_t Luis Chamberlain
  2023-04-05  2:27 ` [PATCH v2 6/6] module: add debug stats to help identify memory pressure Luis Chamberlain
  5 siblings, 0 replies; 23+ messages in thread
From: Luis Chamberlain @ 2023-04-05  2:27 UTC (permalink / raw)
  To: david, patches, linux-modules, linux-mm, linux-kernel, pmladek,
	petr.pavlu, prarit, torvalds, gregkh, rafael
  Cc: christophe.leroy, tglx, peterz, song, rppt, dave, willy, vbabka,
	mhocko, dave.hansen, colin.i.king, jim.cromie, catalin.marinas,
	jbaron, rick.p.edgecombe, mcgrof

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
kernel moduile auto-loading (request_module() calls in-kernel) and the
other is modprobe calls from userspace. The auto-loading is in-kernel, that
pings back to userspace to just call modprobe. We already have a way to
restrict the amount of concurrent kernel auto-loads in a given time, however
that does not stop a system from issuing tons of system calls to load a
module and for the races to exist. 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, issues for which we already have fixes merged or are working
towards, but 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 with the Linux kernel selftests kmod
test 0008. With the new stress-ng module test I see a 145 MiB difference
in max memory consumption with 100 ops. The stress-ng module ops tests can be
pretty pathalogical -- it is not realistic, however it was used to
finally successfully reproduce issues which are only reported to happen on
system with over 400 CPUs [0] by just usign 100 ops on a 8vcpu 8 GiB RAM
system.

This can be observed and visualized below. The time it takes to run the
test is also not affected.

The kmod tests 0008:

The gnuplot is set to a range from 400000 KiB (390 Mib) - 580000 (566 Mib)
given the tests peak around that range.

cat kmod.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

The stress-ng module tests:

This is used to run the test to try to reproduce the vmap issues
reported by David:

  echo 0 > /proc/sys/vm/oom_dump_tasks
  ./stress-ng --module 100 --module-name xfs

Prior to this commit:
root@kmod ~ # free -k -s 1 -c 40 | grep Mem | awk '{print $3}' > baseline-stress-ng.txt
root@kmod ~ # sort -n -r baseline-stress-ng.txt | head -1
5046456

After this commit:
root@kmod ~ # free -k -s 1 -c 40 | grep Mem | awk '{print $3}' > after-stress-ng.txt
root@kmod ~ # sort -n -r after-stress-ng.txt | head -1
4896972

5046456 - 4896972
149484
149484/1024
145.98046875000000000000

So this commit using stress-ng reveals saving about 145 MiB in memory
using 100 ops from stress-ng which reproduced the vmap issue reported.

cat kmod.plot
set term dumb
set output fileout
set yrange [4700000:5070000]
plot filein with linespoints title "Memory usage (KiB)"

root@kmod ~ # gnuplot -e "filein='baseline-stress-ng.txt'; fileout='graph-stress-ng-before.txt'"  kmod-simple-stress-ng.plot
root@kmod ~ # gnuplot -e "filein='after-stress-ng.txt'; fileout='graph-stress-ng-after.txt'"  kmod-simple-stress-ng.plot

root@kmod ~ # cat graph-stress-ng-before.txt

           +---------------------------------------------------------------+
  5.05e+06 |-+     + A     +       +       +       +       +       +     +-|
           |         *                          Memory usage (KiB) ***A*** |
           |         *                             A                       |
     5e+06 |-+      **                            **                     +-|
           |        **                            * *    A                 |
  4.95e+06 |-+      * *                          A  *   A*               +-|
           |        * *      A       A           *  *  *  *             A  |
           |       *  *     * *     * *        *A   *  *  *      A      *  |
   4.9e+06 |-+     *  *     * A*A   * A*AA*A  A      *A    **A   **A*A  *+-|
           |       A  A*A  A    *  A       *  *      A     A *  A    * **  |
           |      *      **      **         * *              *  *    * * * |
  4.85e+06 |-+   A       A       A          **               *  *     ** *-|
           |     *                           *               * *      ** * |
           |     *                           A               * *      *  * |
   4.8e+06 |-+   *                                           * *      A  A-|
           |     *                                           * *           |
  4.75e+06 |-+  *                                            * *         +-|
           |    *                                            **            |
           |    *  +       +       +       +       +       + **    +       |
   4.7e+06 +---------------------------------------------------------------+
           0       5       10      15      20      25      30      35      40

root@kmod ~ # cat graph-stress-ng-after.txt

           +---------------------------------------------------------------+
  5.05e+06 |-+     +       +       +       +       +       +       +     +-|
           |                                    Memory usage (KiB) ***A*** |
           |                                                               |
     5e+06 |-+                                                           +-|
           |                                                               |
  4.95e+06 |-+                                                           +-|
           |                                                               |
           |                                                               |
   4.9e+06 |-+                                      *AA                  +-|
           |  A*AA*A*A  A  A*AA*AA*A*AA*A  A  A  A*A   *AA*A*A  A  A*AA*AA |
           |  *      * **  *            *  *  ** *            ***  *       |
  4.85e+06 |-+*       ***  *            * * * ***             A *  *     +-|
           |  *       A *  *             ** * * A               *  *       |
           |  *         *  *             *  **                  *  *       |
   4.8e+06 |-+*         *  *             A   *                  *  *     +-|
           | *          * *                  A                  * *        |
  4.75e+06 |-*          * *                                     * *      +-|
           | *          * *                                     * *        |
           | *     +    * *+       +       +       +       +    * *+       |
   4.7e+06 +---------------------------------------------------------------+
           0       5       10      15      20      25      30      35      40

[0] https://lkml.kernel.org/r/20221013180518.217405-1-david@redhat.com

Reported-by: David Hildenbrand <david@redhat.com>
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 8f382580195b..137fd9292dc0 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -2797,7 +2797,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.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 5/6] debugfs: add debugfs_create_atomic64_t for atomic64_t
  2023-04-05  2:26 [PATCH v2 0/6] module: avoid userspace pressure on unwanted allocations Luis Chamberlain
                   ` (3 preceding siblings ...)
  2023-04-05  2:27 ` [PATCH v2 4/6] module: avoid allocation if module is already present and ready Luis Chamberlain
@ 2023-04-05  2:27 ` Luis Chamberlain
  2023-04-05 15:26   ` Linus Torvalds
  2023-04-05  2:27 ` [PATCH v2 6/6] module: add debug stats to help identify memory pressure Luis Chamberlain
  5 siblings, 1 reply; 23+ messages in thread
From: Luis Chamberlain @ 2023-04-05  2:27 UTC (permalink / raw)
  To: david, patches, linux-modules, linux-mm, linux-kernel, pmladek,
	petr.pavlu, prarit, torvalds, gregkh, rafael
  Cc: christophe.leroy, tglx, peterz, song, rppt, dave, willy, vbabka,
	mhocko, dave.hansen, colin.i.king, jim.cromie, catalin.marinas,
	jbaron, rick.p.edgecombe, mcgrof

Sometimes you want to add debugfs entries for atomic counters which
can be pretty large using atomic64_t. Add support for these.

Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
---
 fs/debugfs/file.c       | 36 ++++++++++++++++++++++++++++++++++++
 include/linux/debugfs.h |  2 ++
 2 files changed, 38 insertions(+)

diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c
index 1f971c880dde..76d923503861 100644
--- a/fs/debugfs/file.c
+++ b/fs/debugfs/file.c
@@ -780,6 +780,42 @@ void debugfs_create_atomic_t(const char *name, umode_t mode,
 }
 EXPORT_SYMBOL_GPL(debugfs_create_atomic_t);
 
+static int debugfs_atomic64_t_set(void *data, u64 val)
+{
+	atomic64_set((atomic64_t *)data, val);
+	return 0;
+}
+static int debugfs_atomic64_t_get(void *data, u64 *val)
+{
+	*val = atomic64_read((atomic64_t *)data);
+	return 0;
+}
+DEFINE_DEBUGFS_ATTRIBUTE_SIGNED(fops_atomic64_t, debugfs_atomic64_t_get,
+			debugfs_atomic64_t_set, "%lld\n");
+DEFINE_DEBUGFS_ATTRIBUTE_SIGNED(fops_atomic64_t_ro, debugfs_atomic64_t_get, NULL,
+			"%lld\n");
+DEFINE_DEBUGFS_ATTRIBUTE_SIGNED(fops_atomic64_t_wo, NULL, debugfs_atomic64_t_set,
+			"%lld\n");
+
+/**
+ * debugfs_create_atomic64_t - create a debugfs file that is used to read and
+ * write an atomic64_t value
+ * @name: a pointer to a string containing the name of the file to create.
+ * @mode: the permission that the file should have
+ * @parent: a pointer to the parent dentry for this file.  This should be a
+ *          directory dentry if set.  If this parameter is %NULL, then the
+ *          file will be created in the root of the debugfs filesystem.
+ * @value: a pointer to the variable that the file should read to and write
+ *         from.
+ */
+void debugfs_create_atomic64_t(const char *name, umode_t mode,
+			     struct dentry *parent, atomic64_t *value)
+{
+	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_atomic64_t,
+				   &fops_atomic64_t_ro, &fops_atomic64_t_wo);
+}
+EXPORT_SYMBOL_GPL(debugfs_create_atomic64_t);
+
 ssize_t debugfs_read_file_bool(struct file *file, char __user *user_buf,
 			       size_t count, loff_t *ppos)
 {
diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h
index ea2d919fd9c7..f5cc613a545e 100644
--- a/include/linux/debugfs.h
+++ b/include/linux/debugfs.h
@@ -136,6 +136,8 @@ void debugfs_create_size_t(const char *name, umode_t mode,
 			   struct dentry *parent, size_t *value);
 void debugfs_create_atomic_t(const char *name, umode_t mode,
 			     struct dentry *parent, atomic_t *value);
+void debugfs_create_atomic64_t(const char *name, umode_t mode,
+			       struct dentry *parent, atomic64_t *value);
 void debugfs_create_bool(const char *name, umode_t mode, struct dentry *parent,
 			 bool *value);
 void debugfs_create_str(const char *name, umode_t mode,
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 6/6] module: add debug stats to help identify memory pressure
  2023-04-05  2:26 [PATCH v2 0/6] module: avoid userspace pressure on unwanted allocations Luis Chamberlain
                   ` (4 preceding siblings ...)
  2023-04-05  2:27 ` [PATCH v2 5/6] debugfs: add debugfs_create_atomic64_t for atomic64_t Luis Chamberlain
@ 2023-04-05  2:27 ` Luis Chamberlain
  5 siblings, 0 replies; 23+ messages in thread
From: Luis Chamberlain @ 2023-04-05  2:27 UTC (permalink / raw)
  To: david, patches, linux-modules, linux-mm, linux-kernel, pmladek,
	petr.pavlu, prarit, torvalds, gregkh, rafael
  Cc: christophe.leroy, tglx, peterz, song, rppt, dave, willy, vbabka,
	mhocko, dave.hansen, colin.i.king, jim.cromie, catalin.marinas,
	jbaron, rick.p.edgecombe, mcgrof

Loading modules with finit_module() can end up using vmalloc(), vmap()
and vmalloc() again, for a total of up to 3 separate allocations in the
worst case for a single module. We always kernel_read*() the module,
that's a vmalloc(). Then vmap() is used for the module decompression,
and if so the last read buffer is freed as we use the now decompressed
module buffer to stuff data into our copy module. The last allocation is
specific to each architectures but pretty much that's generally a series
of vmalloc() calls or a variation of vmalloc to handle ELF sections with
special permissions.

Evaluation with new stress-ng module support [1] with just 100 ops
is proving that you can end up using GiBs of data easily even with all
care we have in the kernel and userspace today in trying to not load modules
which are already loaded. 100 ops seems to resemble the sort of pressure a
system with about 400 CPUs can create on module loading. Although issues
relating to duplicate module requests due to each CPU inucurring a new
module reuest is silly and some of these are being fixed, we currently lack
proper tooling to help diagnose easily what happened, when it happened
and who likely is to blame -- userspace or kernel module autoloading.

Provide an initial set of stats which use debugfs to let us easily scrape
post-boot information about failed loads. This sort of information can
be used on production worklaods to try to optimize *avoiding* redundant
memory pressure using finit_module().

The following screen shot, of a simple 8vcpu 8 GiB KVM guest shows
226.53 MiB are wasted in virtual memory allocations which due to
duplicate module requests during boot. It also shows an average
module memory size of 167.10 KiB and an an average module
.text + .init.text size of 61.13 KiB. The end shows all modules
which were detected as duplicate requests and whether or not they
failed early after just the first kernel_read*() call or late after
we've already allocated the private space for the module in
layout_and_allocate(). A system with module decompression would
reveal more wasted virtual memory space.

We should put effort now into identifying the source of these duplicate
module requests and trimming these down as much possible. Larger systems
will obviously show much more wasted virtual memory allocations.

root@kmod ~ # cat /sys/kernel/debug/modules/stats
         Mods ever loaded       67
     Mods failed on kread       0
Mods failed on decompress       0
  Mods failed on becoming       83
      Mods failed on load       16
        Total module size       11464704
      Total mod text size       4194304
       Failed kread bytes       0
  Failed decompress bytes       0
    Failed becoming bytes       228959096
        Failed kmod bytes       8578080
 Virtual mem wasted bytes       237537176
         Average mod size       171115
    Average mod text size       62602
  Avg fail becoming bytes       2758544
  Average fail load bytes       536130
Duplicate failed modules:
              module-name        How-many-times                    Reason
                kvm_intel                     7                  Becoming
                      kvm                     7                  Becoming
                irqbypass                     6           Becoming & Load
         crct10dif_pclmul                     7           Becoming & Load
      ghash_clmulni_intel                     7           Becoming & Load
             sha512_ssse3                     6           Becoming & Load
           sha512_generic                     7           Becoming & Load
              aesni_intel                     7                  Becoming
              crypto_simd                     7           Becoming & Load
                   cryptd                     3           Becoming & Load
                    evdev                     1                  Becoming
                serio_raw                     1                  Becoming
                     nvme                     3                  Becoming
                nvme_core                     3                  Becoming
                   t10_pi                     3                  Becoming
               virtio_pci                     3                  Becoming
             crc32_pclmul                     6           Becoming & Load
           crc64_rocksoft                     3                  Becoming
             crc32c_intel                     3                  Becoming
    virtio_pci_modern_dev                     2                  Becoming
    virtio_pci_legacy_dev                     1                  Becoming
                    crc64                     2                  Becoming
                   virtio                     2                  Becoming
              virtio_ring                     2                  Becoming

[0] https://github.com/ColinIanKing/stress-ng.git
[1] echo 0 > /proc/sys/vm/oom_dump_tasks
    ./stress-ng --module 100 --module-name xfs

Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
---
 Documentation/core-api/kernel-api.rst |  22 +-
 kernel/module/Kconfig                 |  37 +++
 kernel/module/Makefile                |   1 +
 kernel/module/decompress.c            |   4 +
 kernel/module/internal.h              |  74 +++++
 kernel/module/main.c                  |  65 +++-
 kernel/module/stats.c                 | 428 ++++++++++++++++++++++++++
 kernel/module/tracking.c              |   7 +-
 8 files changed, 625 insertions(+), 13 deletions(-)
 create mode 100644 kernel/module/stats.c

diff --git a/Documentation/core-api/kernel-api.rst b/Documentation/core-api/kernel-api.rst
index e27728596008..9b3f3e5f5a95 100644
--- a/Documentation/core-api/kernel-api.rst
+++ b/Documentation/core-api/kernel-api.rst
@@ -220,12 +220,30 @@ relay interface
 Module Support
 ==============
 
-Module Loading
---------------
+Kernel module auto-loading
+--------------------------
 
 .. kernel-doc:: kernel/module/kmod.c
    :export:
 
+Module debugging
+----------------
+
+.. kernel-doc:: kernel/module/stats.c
+   :doc: module debugging statistics overview
+
+dup_failed_modules - tracks duplicate failed modules
+****************************************************
+
+.. kernel-doc:: kernel/module/stats.c
+   :doc: dup_failed_modules - tracks duplicate failed modules
+
+module statistics debugfs counters
+**********************************
+
+.. kernel-doc:: kernel/module/stats.c
+   :doc: module statistics debugfs counters
+
 Inter Module support
 --------------------
 
diff --git a/kernel/module/Kconfig b/kernel/module/Kconfig
index 424b3bc58f3f..ca277b945a67 100644
--- a/kernel/module/Kconfig
+++ b/kernel/module/Kconfig
@@ -22,6 +22,43 @@ menuconfig MODULES
 
 if MODULES
 
+config MODULE_DEBUG
+	bool "Module debugging"
+	depends on DEBUG_FS
+	help
+	  Allows you to enable / disable features which can help you debug
+	  modules. You don't need these options in produciton systems. You can
+	  and probably should enable this prior to making your kernel
+	  produciton ready though.
+
+if MODULE_DEBUG
+
+config MODULE_STATS
+	bool "Module statistics"
+	depends on DEBUG_FS
+	help
+	  This option allows you to maintain a record of module statistics.
+	  For example each all modules size, average size, text size, and
+	  failed modules and the size for each of those. For failed
+	  modules we keep track of module which failed due to either the
+	  existing module taking too long to load or that module already
+	  was loaded.
+
+	  You should enable this if you are debugging production loads
+	  and want to see if userspace or the kernel is doing stupid things
+	  with loading modules when it shouldn't or if you want to help
+	  optimize userspace / kernel space module autoloading schemes.
+	  You might want to do this because failed modules tend to use
+	  use up significan amount of memory, and so you'd be doing everyone
+	  a favor in avoiding these failure proactively.
+
+	  This functionality is also useful for those experimenting with
+	  module .text ELF section optimization.
+
+	  If unsure, say N.
+
+endif # MODULE_DEBUG
+
 config MODULE_FORCE_LOAD
 	bool "Forced module loading"
 	default n
diff --git a/kernel/module/Makefile b/kernel/module/Makefile
index 5b1d26b53b8d..52340bce497e 100644
--- a/kernel/module/Makefile
+++ b/kernel/module/Makefile
@@ -21,3 +21,4 @@ obj-$(CONFIG_SYSFS) += sysfs.o
 obj-$(CONFIG_KGDB_KDB) += kdb.o
 obj-$(CONFIG_MODVERSIONS) += version.o
 obj-$(CONFIG_MODULE_UNLOAD_TAINT_TRACKING) += tracking.o
+obj-$(CONFIG_MODULE_STATS) += stats.o
diff --git a/kernel/module/decompress.c b/kernel/module/decompress.c
index 7ddc87bee274..e97232b125eb 100644
--- a/kernel/module/decompress.c
+++ b/kernel/module/decompress.c
@@ -297,6 +297,10 @@ int module_decompress(struct load_info *info, const void *buf, size_t size)
 	ssize_t data_size;
 	int error;
 
+#if defined(CONFIG_MODULE_STATS)
+	info->compressed_len = size;
+#endif
+
 	/*
 	 * Start with number of pages twice as big as needed for
 	 * compressed data.
diff --git a/kernel/module/internal.h b/kernel/module/internal.h
index 6ae29bb8836f..aef4a355cc2b 100644
--- a/kernel/module/internal.h
+++ b/kernel/module/internal.h
@@ -59,6 +59,9 @@ struct load_info {
 	unsigned long mod_kallsyms_init_off;
 #endif
 #ifdef CONFIG_MODULE_DECOMPRESS
+#ifdef CONFIG_MODULE_STATS
+	unsigned long compressed_len;
+#endif
 	struct page **pages;
 	unsigned int max_pages;
 	unsigned int used_pages;
@@ -143,6 +146,77 @@ static inline bool set_livepatch_module(struct module *mod)
 #endif
 }
 
+/**
+ * enum fail_dup_mod_reason - state at which a duplicate module was detected
+ *
+ * @FAIL_DUP_MOD_BECOMING: the module is read properly, passes all checks but
+ * 	we've determined that another module with the same name is already loaded
+ * 	or being processed on our &modules list. This happens on early_mod_check()
+ * 	right before layout_and_allocate(). The kernel would have already
+ * 	vmalloc()'d space for the entire module through finit_module(). If
+ * 	decompression was used two vmap() spaces were used. These failures can
+ * 	happen when userspace has not seen the module present on the kernel and
+ * 	tries to load the module multiple times at same time.
+ * @FAIL_DUP_MOD_LOAD: the module has been read properly, passes all validation
+ *	checks and the kernel determines that the module was unique and because
+ *	of this allocated yet another private kernel copy of the module space in
+ *	layout_and_allocate() but after this determined in add_unformed_module()
+ *	that another module with the same name is already loaded or being processed.
+ *	These failures should be mitigated as much as possible and are indicative
+ *	of really fast races in loading modules. Without module decompression
+ *	they waste twice as much vmap space. With module decompression three
+ *	times the module's size vmap space is wasted.
+ */
+enum fail_dup_mod_reason {
+	FAIL_DUP_MOD_BECOMING = 0,
+	FAIL_DUP_MOD_LOAD,
+};
+
+#ifdef CONFIG_MODULE_STATS
+
+#define mod_stat_add64(count, var) atomic64_add(count, var)
+#define mod_stat_inc(name) atomic_inc(name)
+
+extern atomic64_t total_mod_size;
+extern atomic64_t total_text_size;
+extern atomic64_t invalid_kread_bytes;
+extern atomic64_t invalid_decompress_bytes;
+
+extern atomic_t modcount;
+extern atomic_t failed_kreads;
+extern atomic_t failed_decompress;
+struct mod_fail_load {
+	struct list_head list;
+	char name[MODULE_NAME_LEN];
+	atomic64_t count;
+	unsigned long dup_fail_mask;
+};
+
+int try_add_failed_module(const char *name, size_t len, enum fail_dup_mod_reason reason);
+void mod_stat_bump_invalid(struct load_info *info, int flags);
+void mod_stat_bump_becoming(struct load_info *info, int flags);
+
+#else
+
+#define mod_stat_add64(name)
+#define mod_stat_inc(name)
+
+static inline int try_add_failed_module(const char *name, size_t len,
+					enum fail_dup_mod_reason reason)
+{
+	return 0;
+}
+
+static inline void mod_stat_bump_invalid(struct load_info *info, int flags)
+{
+}
+
+static inline void mod_stat_bump_becoming(struct load_info *info, int flags)
+{
+}
+
+#endif /* CONFIG_MODULE_STATS */
+
 #ifdef CONFIG_MODULE_UNLOAD_TAINT_TRACKING
 struct mod_unload_taint {
 	struct list_head list;
diff --git a/kernel/module/main.c b/kernel/module/main.c
index 137fd9292dc0..7a9744f03cd4 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -56,6 +56,7 @@
 #include <linux/dynamic_debug.h>
 #include <linux/audit.h>
 #include <linux/cfi.h>
+#include <linux/debugfs.h>
 #include <uapi/linux/module.h>
 #include "internal.h"
 
@@ -87,6 +88,8 @@ struct symsearch {
 	enum mod_license license;
 };
 
+struct dentry *mod_debugfs_root;
+
 /*
  * Bounds of module memory, for speeding up __module_address.
  * Protected by module_mutex.
@@ -2507,6 +2510,16 @@ static noinline int do_init_module(struct module *mod)
 {
 	int ret = 0;
 	struct mod_initfree *freeinit;
+	unsigned int text_size = 0, total_size = 0;
+
+	for_each_mod_mem_type(type) {
+		const struct module_memory *mod_mem = &mod->mem[type];
+		if (mod_mem->size) {
+			total_size += mod_mem->size;
+			if (type == MOD_TEXT || type == MOD_INIT_TEXT)
+				text_size += mod->mem[type].size;
+		}
+	}
 
 	freeinit = kmalloc(sizeof(*freeinit), GFP_KERNEL);
 	if (!freeinit) {
@@ -2568,6 +2581,7 @@ static noinline int do_init_module(struct module *mod)
 		mod->mem[type].base = NULL;
 		mod->mem[type].size = 0;
 	}
+
 #ifdef CONFIG_DEBUG_INFO_BTF_MODULES
 	/* .BTF is not SHF_ALLOC and will get removed, so sanitize pointer */
 	mod->btf_data = NULL;
@@ -2591,6 +2605,11 @@ static noinline int do_init_module(struct module *mod)
 	mutex_unlock(&module_mutex);
 	wake_up_all(&module_wq);
 
+	mod_stat_add64(text_size, &total_text_size);
+	mod_stat_add64(total_size, &total_mod_size);
+
+	mod_stat_inc(&modcount);
+
 	return 0;
 
 fail_free_freeinit:
@@ -2606,6 +2625,7 @@ static noinline int do_init_module(struct module *mod)
 	ftrace_release_mod(mod);
 	free_module(mod);
 	wake_up_all(&module_wq);
+
 	return ret;
 }
 
@@ -2639,7 +2659,8 @@ static bool finished_loading(const char *name)
 }
 
 /* Must be called with module_mutex held */
-static int module_patient_check_exists(const char *name)
+static int module_patient_check_exists(const char *name,
+				       enum fail_dup_mod_reason reason)
 {
 	struct module *old;
 	int err = 0;
@@ -2662,6 +2683,9 @@ static int module_patient_check_exists(const char *name)
 		old = find_module_all(name, strlen(name), true);
 	}
 
+	if (try_add_failed_module(name, strlen(name), reason))
+		pr_warn("Could not add fail-tracking for module: %s\n", name);
+
 	/*
 	 * We are here only when the same module was being loaded. Do
 	 * not try to load it again right now. It prevents long delays
@@ -2687,7 +2711,7 @@ static int add_unformed_module(struct module *mod)
 	mod->state = MODULE_STATE_UNFORMED;
 
 	mutex_lock(&module_mutex);
-	err = module_patient_check_exists(mod->name);
+	err = module_patient_check_exists(mod->name, FAIL_DUP_MOD_LOAD);
 	if (err)
 		goto out;
 
@@ -2798,7 +2822,7 @@ static int early_mod_check(struct load_info *info, int flags)
 		return err;
 
 	mutex_lock(&module_mutex);
-	err = module_patient_check_exists(info->mod->name);
+	err = module_patient_check_exists(info->mod->name, FAIL_DUP_MOD_BECOMING);
 	mutex_unlock(&module_mutex);
 
 	return err;
@@ -2812,6 +2836,7 @@ static int load_module(struct load_info *info, const char __user *uargs,
 		       int flags)
 {
 	struct module *mod;
+	bool module_allocated = false;
 	long err = 0;
 	char *after_dashes;
 
@@ -2851,6 +2876,8 @@ static int load_module(struct load_info *info, const char __user *uargs,
 		goto free_copy;
 	}
 
+	module_allocated = true;
+
 	audit_log_kern_module(mod->name);
 
 	/* Reserve our place in the list. */
@@ -2995,6 +3022,7 @@ static int load_module(struct load_info *info, const char __user *uargs,
 	synchronize_rcu();
 	mutex_unlock(&module_mutex);
  free_module:
+	mod_stat_bump_invalid(info, flags);
 	/* Free lock-classes; relies on the preceding sync_rcu() */
 	for_class_mod_mem_type(type, core_data) {
 		lockdep_free_key_range(mod->mem[type].base,
@@ -3003,6 +3031,13 @@ static int load_module(struct load_info *info, const char __user *uargs,
 
 	module_deallocate(mod, info);
  free_copy:
+	/*
+	 * The info->len is always set. We distinguish between
+	 * failures once the proper module was allocated and
+	 * before that.
+	 */
+	if (!module_allocated)
+		mod_stat_bump_becoming(info, flags);
 	free_copy(info, flags);
 	return err;
 }
@@ -3021,8 +3056,11 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
 	       umod, len, uargs);
 
 	err = copy_module_from_user(umod, len, &info);
-	if (err)
+	if (err) {
+		mod_stat_inc(&failed_kreads);
+		mod_stat_add64(len, &invalid_kread_bytes);
 		return err;
+	}
 
 	return load_module(&info, uargs, 0);
 }
@@ -3047,14 +3085,20 @@ 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)
+	if (len < 0) {
+		mod_stat_inc(&failed_kreads);
+		mod_stat_add64(len, &invalid_kread_bytes);
 		return len;
+	}
 
 	if (flags & MODULE_INIT_COMPRESSED_FILE) {
 		err = module_decompress(&info, buf, len);
 		vfree(buf); /* compressed data is no longer needed */
-		if (err)
+		if (err) {
+			mod_stat_inc(&failed_decompress);
+			mod_stat_add64(len, &invalid_decompress_bytes);
 			return err;
+		}
 	} else {
 		info.hdr = buf;
 		info.len = len;
@@ -3228,3 +3272,12 @@ void print_modules(void)
 			last_unloaded_module.taints);
 	pr_cont("\n");
 }
+
+#ifdef CONFIG_MODULE_DEBUG
+static int module_debugfs_init(void)
+{
+	mod_debugfs_root = debugfs_create_dir("modules", NULL);
+	return 0;
+}
+module_init(module_debugfs_init);
+#endif
diff --git a/kernel/module/stats.c b/kernel/module/stats.c
new file mode 100644
index 000000000000..2f8e1b0ab2c5
--- /dev/null
+++ b/kernel/module/stats.c
@@ -0,0 +1,428 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Debugging module statistics.
+ *
+ * Copyright (C) 2023 Luis Chamberlain <mcgrof@kernel.org>
+ */
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/printk.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/debugfs.h>
+#include <linux/rculist.h>
+
+#include "internal.h"
+
+/**
+ * DOC: module debugging statistics overview
+ *
+ * Enabling CONFIG_MODULE_STATS enables module debugging statistics which
+ * are useful to monitor and root cause memory pressure issues with module
+ * loading. These statistics are useful to allow us to improve production
+ * workloads.
+ *
+ * The current module debugging statistics supported help keep track of module
+ * loading failures to enable improvements either for kernel module
+ * auto-loading usage (request_module()) or interactions with userspace.
+ * Statistics are provided to track of all possible failures in the
+ * finit_module() path and memory wasted in this process space.  Each of the
+ * failure counters are associated to a type of module loading failure which
+ * is known to incur a certain amount of memory allocation loss. In the worst
+ * case loading a module will fail after a 3 step memory allocation process:
+ *
+ *   a) memory allocated with kernel_read_file_from_fd()
+ *   b) module decompression processes the file read from
+ *      kernel_read_file_from_fd(), and vmap() is used to map
+ *      the decompressed module to a new local buffer which represents
+ *      a copy of the decompressed module passed from userspace. The buffer
+ *      from kernel_read_file_from_fd() is freed right away.
+ *   c) layout_and_allocate() allocates space for the final resting
+ *      place where we would keep the module if it were to be processed
+ *      successfully.
+ *
+ * If a failure occurs after these three different allocations only one
+ * counters will be incremetned with the summation of the lost bytes incurred
+ * during this failure. Likewise, if a module loading failed only after step b)
+ * a separate counter is used and incremented for the bytes lost during both
+ * of those allocations.
+ *
+ * Virtual memory space can be limited, for example on x86 virtual memory size
+ * defaults to 128 MiB. We should strive to limit and avoid wasting virtual
+ * memory allocations when possible. These module dubugging statistics help
+ * to evaluate how much memory is being wasted on bootup due to module loading
+ * failures.
+ *
+ * All counters are designed to be incremental. Atomic counters are used so to
+ * remain simple and avoid delays and deadlocks.
+ */
+
+extern struct dentry *mod_debugfs_root;
+
+/**
+ * DOC: dup_failed_modules - tracks duplicate failed modules
+ *
+ * Linked list of modules which failed to be loaded because an already existing
+ * module with the same name was already being processed or already loaded.
+ * The finit_module() system call incurs heavy virtual memory allocations. In
+ * the worst case an finit_module() system call can end up allocating virtual
+ * memory 3 times:
+ *
+ *   1) kernel_read_file_from_fd() call uses vmalloc()
+ *   2) optional module decompression uses vmap()
+ *   3) layout_and allocate() can use vzalloc() or an arch specific variation of
+ *      vmalloc to deal with ELF sections requiring special permissions
+ *
+ * In practice on a typical boot today most finit_module() calls fail due to
+ * the module with the same name already being loaded or about to be processed.
+ * All virtual memory allocated to these failed modules will be lost with
+ * no functional use.
+ *
+ * To help with this the dup_failed_modules allows us to track modules which
+ * failed to load due to the fact that a module already was loaded or being
+ * processed already.  There are only two points at which we can fail such
+ * calls, we list them below along with the number of virtual memory allocation
+ * calls:
+ *
+ *   a) FAIL_DUP_MOD_BECOMING: at the end of early_mod_check() before
+ *	layout_and_allocate()
+ *	- with module decompression: 2 virtual memory allocation calls
+ *	- without module decompression: 1 virtual memory allocation calls
+ *   b) FAIL_DUP_MOD_LOAD: after layout_and_allocate() on add_unformed_module()
+ *   	- with module decompression 3 virtual memory allocation calls
+ *   	- without module decompression 2 virtual memory allocation calls
+ *
+ * We should strive to get this list to be as small as possible. If this list
+ * is not empty it is a reflection of possible work or optimizations possible
+ * either in-kernel or in userspace.
+ */
+static LIST_HEAD(dup_failed_modules);
+
+/**
+ * DOC: module statistics debugfs counters
+ *
+ * The total amount of wasted virtual memory allocation space during module
+ * loading can be computed by adding the total from the summation:
+ *
+ *   * @invalid_kread_bytes +
+ *     @invalid_decompress_bytes +
+ *     @invalid_mod_becoming_bytes +
+ *     @invalid_mod_bytes
+ *
+ * The following debugfs counters are available to inspect module loading
+ * failures:
+ *
+ *   * total_mod_size: total bytes ever used by all modules we've dealt with on
+ *     this system
+ *   * total_text_size: total bytes of the .text and .init.text ELF section
+ *     sizes we've dealt with on this system
+ *   * invalid_kread_bytes: bytes wasted in failures which happen due to
+ *     memory allocations with the initial kernel_read_file_from_fd().
+ *     kernel_read_file_from_fd() uses vmalloc() and so these are wasted
+ *     vmalloc() memory allocations. These should typically not happen unless
+ *     your system is under memory pressure.
+ *   * invalid_decompress_bytes: number of bytes wasted due to
+ *     memory allocations in the module decompression path that use vmap().
+ *     These typically should not happen unless your system is under memory
+ *     presssure.
+ *   * invalid_mod_becoming_bytes: total number of bytes wasted due to
+ *     allocations used to read the kernel module userspace wants us to read
+ *     before promote it to be processed to be added to our @modules linked
+ *     list. These failures can happen in between between a successul
+ *     kernel_read_file_from_fd() call and right before we allocate the our
+ *     private memory for the module which would be kept if the module is
+ *     successfully loaded. The most common reason for this failure
+ *     is when userspace is racing to load a module which it does not yet see
+ *     loaded. The first module to succeed in add_unformed_module() will add a
+ *     module to our &modules list and subsequent loads of modules with the
+ *     same name will error out at the end of early_mod_check(). The check
+ *     for module_patient_check_exists() at the end of early_mod_check() was
+ *     added to prevent duplicate allocations on layout_and_allocate() for
+ *     modules already being processed. These duplicate failed modules are
+ *     non-fatal, however they typically are indicative of userspace not seeing
+ *     a module in userspace loaded yet and unecessarily trying to load a
+ *     module before the kernel even has a chance to begin to process prior
+ *     requests. Although duplicate failures can be non-fatal, we should try to
+ *     reduce vmalloc() pressure proactively, so ideally after boot this will
+ *     be close to as 0 as possible.  If module decompression was used we also
+ *     add to this counter the cost of the initial kernel_read_file_from_fd()
+ *     of the compressed module. If module decompression was not used the
+ *     value represents the total wasted allocations in kernel_read_file_from_fd()
+ *     calls for these type of failures. These failures can occur because:
+ *
+ *    * module_sig_check() - module signature checks
+ *    * elf_validity_cache_copy() - some ELF validation issue
+ *    * early_mod_check():
+ *
+ *      * blacklisting
+ *      * failed to rewrite section headers
+ *      * version magic
+ *      * live patch requirements didn't check out
+ *      * the module was detected as being already present
+ *
+ *   * invalid_mod_bytes: these are the total number of bytes lost due to
+ *     failures after we did all the sanity checks of the module which userspace
+ *     passed to us and after our first check that the module is unique.  A
+ *     module can still fail to load if we detect the module is loaded after we
+ *     allocate space for it with layout_and_allocate(), we do this check right
+ *     before processing the module as live and run its initialiation routines.
+ *     Note that you have a failure of this type it also means the respective
+ *     kernel_read_file_from_fd() memory space was also wasted, and so we
+ *     increment this counter with twice the size of the module. Additionally
+ *     if you used module decompression the size of the compressed module is
+ *     also added to this counter.
+ *
+ *  * modcount: how many modules we've loaded in our kernel life time
+ *  * failed_kreads: how many modules failed due to failed kernel_read_file_from_fd()
+ *  * failed_decompress: how many failed module decompression attempts we've had.
+ *    These really should not happen unless your compression / decompression
+ *    might be broken.
+ *  * failed_becoming: how many modules failed after we kernel_read_file_from_fd()
+ *    it and before we allocate memory for it with layout_and_allocate(). This
+ *    counter is never incremented if you manage to validate the module and
+ *    call layout_and_allocate() for it.
+ *  * failed_load_modules: how many modules failed once we've allocated our
+ *    private space for our module using layout_and_allocate(). These failures
+ *    should hopefully mostly be dealt with already. Races in theory could
+ *    still exist here, but it would just mean the kernel had started processing
+ *    two threads concurrently up to early_mod_check() and then one just one
+ *    thread won. These failures are good signs the kernel or userspace is
+ *    doing something seriously stupid or that could be improved. We should
+ *    strive to fix these, but it is perhaps not easy to fix them.
+ *    A recent example are the modules requests incurred for frequency modules,
+ *    a separate module request was being issued for each CPU on a system.
+ */
+
+atomic64_t total_mod_size;
+atomic64_t total_text_size;
+atomic64_t invalid_kread_bytes;
+atomic64_t invalid_decompress_bytes;
+static atomic64_t invalid_mod_becoming_bytes;
+static atomic64_t invalid_mod_bytes;
+atomic_t modcount;
+atomic_t failed_kreads;
+atomic_t failed_decompress;
+static atomic_t failed_becoming;
+static atomic_t failed_load_modules;
+
+static const char *mod_fail_to_str(struct mod_fail_load *mod_fail)
+{
+	if (test_bit(FAIL_DUP_MOD_BECOMING, &mod_fail->dup_fail_mask) &&
+	    test_bit(FAIL_DUP_MOD_LOAD, &mod_fail->dup_fail_mask))
+		return "Becoming & Load";
+	if (test_bit(FAIL_DUP_MOD_BECOMING, &mod_fail->dup_fail_mask))
+		return "Becoming";
+	if (test_bit(FAIL_DUP_MOD_LOAD, &mod_fail->dup_fail_mask))
+		return "Load";
+	return "Bug-on-stats";
+}
+
+void mod_stat_bump_invalid(struct load_info *info, int flags)
+{
+	atomic64_add(info->len * 2, &invalid_mod_bytes);
+	atomic_inc(&failed_load_modules);
+#if defined(CONFIG_MODULE_DECOMPRESS)
+	if (flags & MODULE_INIT_COMPRESSED_FILE)
+		atomic64_add(info->compressed_len, &invalid_mod_byte);
+#endif
+}
+
+void mod_stat_bump_becoming(struct load_info *info, int flags)
+{
+	atomic_inc(&failed_becoming);
+	atomic64_add(info->len, &invalid_mod_becoming_bytes);
+#if defined(CONFIG_MODULE_DECOMPRESS)
+	if (flags & MODULE_INIT_COMPRESSED_FILE)
+		atomic64_add(info->compressed_len, &invalid_mod_becoming_bytes);
+#endif
+}
+
+int try_add_failed_module(const char *name, size_t len, enum fail_dup_mod_reason reason)
+{
+	struct mod_fail_load *mod_fail;
+
+	list_for_each_entry_rcu(mod_fail, &dup_failed_modules, list,
+				lockdep_is_held(&module_mutex)) {
+		if (strlen(mod_fail->name) == len && !memcmp(mod_fail->name, name, len)) {
+                        atomic64_inc(&mod_fail->count);
+			__set_bit(reason, &mod_fail->dup_fail_mask);
+                        goto out;
+                }
+        }
+
+	mod_fail = kzalloc(sizeof(*mod_fail), GFP_KERNEL);
+	if (!mod_fail)
+		return -ENOMEM;
+	memcpy(mod_fail->name, name, len);
+	__set_bit(reason, &mod_fail->dup_fail_mask);
+        atomic64_inc(&mod_fail->count);
+        list_add_rcu(&mod_fail->list, &dup_failed_modules);
+out:
+	return 0;
+}
+
+/*
+ * At 64 bytes per module and assuming a 1024 bytes preamble we can fit the
+ * 112 module prints within 8k.
+ *
+ * 1024 + (64*112) = 8k
+ */
+#define MAX_PREAMBLE 1024
+#define MAX_FAILED_MOD_PRINT 112
+#define MAX_BYTES_PER_MOD 64
+static ssize_t read_file_mod_stats(struct file *file, char __user *user_buf,
+				   size_t count, loff_t *ppos)
+{
+	struct mod_fail_load *mod_fail;
+	unsigned int len, size, count_failed = 0;
+	char *buf;
+	u32 live_mod_count, fkreads, fdecompress, fbecoming, floads;
+	u64 total_size, text_size, ikread_bytes, ibecoming_bytes, idecompress_bytes, imod_bytes,
+	    total_virtual_lost;
+
+	live_mod_count = atomic_read(&modcount);
+	fkreads = atomic_read(&failed_kreads);
+	fdecompress = atomic_read(&failed_decompress);
+	fbecoming = atomic_read(&failed_becoming);
+	floads = atomic_read(&failed_load_modules);
+
+	total_size = atomic64_read(&total_mod_size);
+	text_size = atomic64_read(&total_text_size);
+	ikread_bytes = atomic64_read(&invalid_kread_bytes);
+	idecompress_bytes = atomic64_read(&invalid_decompress_bytes);
+	ibecoming_bytes = atomic64_read(&invalid_mod_becoming_bytes);
+	imod_bytes = atomic64_read(&invalid_mod_bytes);
+
+	total_virtual_lost = ikread_bytes + idecompress_bytes + ibecoming_bytes + imod_bytes;
+
+	size = MAX_PREAMBLE + min((unsigned int)(floads + fbecoming) * MAX_BYTES_PER_MOD,
+			  (unsigned int) MAX_FAILED_MOD_PRINT * MAX_BYTES_PER_MOD);
+	buf = kzalloc(size, GFP_KERNEL);
+	if (buf == NULL)
+		return -ENOMEM;
+
+	/* The beginning of our debug preamble */
+	len += scnprintf(buf + len, size - len, "%25s\t%u\n", "Mods ever loaded", live_mod_count);
+
+	len += scnprintf(buf + len, size - len, "%25s\t%u\n", "Mods failed on kread", fkreads);
+
+	len += scnprintf(buf + len, size - len, "%25s\t%u\n", "Mods failed on decompress",
+			 fdecompress);
+	len += scnprintf(buf + len, size - len, "%25s\t%u\n", "Mods failed on becoming", fbecoming);
+
+	len += scnprintf(buf + len, size - len, "%25s\t%u\n", "Mods failed on load", floads);
+
+	len += scnprintf(buf + len, size - len, "%25s\t%llu\n", "Total module size", total_size);
+	len += scnprintf(buf + len, size - len, "%25s\t%llu\n", "Total mod text size", text_size);
+
+	len += scnprintf(buf + len, size - len, "%25s\t%llu\n", "Failed kread bytes", ikread_bytes);
+
+	len += scnprintf(buf + len, size - len, "%25s\t%llu\n", "Failed decompress bytes",
+			 idecompress_bytes);
+
+	len += scnprintf(buf + len, size - len, "%25s\t%llu\n", "Failed becoming bytes", ibecoming_bytes);
+
+	len += scnprintf(buf + len, size - len, "%25s\t%llu\n", "Failed kmod bytes", imod_bytes);
+
+	len += scnprintf(buf + len, size - len, "%25s\t%llu\n", "Virtual mem wasted bytes", total_virtual_lost);
+
+	if (live_mod_count && total_size) {
+		len += scnprintf(buf + len, size - len, "%25s\t%llu\n", "Average mod size",
+				 DIV_ROUND_UP(total_size, live_mod_count));
+	}
+
+	if (live_mod_count && text_size) {
+		len += scnprintf(buf + len, size - len, "%25s\t%llu\n", "Average mod text size",
+				 DIV_ROUND_UP(text_size, live_mod_count));
+	}
+
+	/*
+	 * We use WARN_ON_ONCE() for the counters to ensure we always have parity
+	 * for keeping tabs on a type of failure with one type of byte counter.
+	 * The counters for imod_bytes does not increase for fkreads failures
+	 * for example, and so on.
+	 */
+
+	WARN_ON_ONCE(ikread_bytes && !fkreads);
+	if (fkreads && ikread_bytes) {
+		len += scnprintf(buf + len, size - len, "%25s\t%llu\n", "Avg fail kread bytes",
+				 DIV_ROUND_UP(ikread_bytes, fkreads));
+	}
+
+	WARN_ON_ONCE(ibecoming_bytes && !fbecoming);
+	if (fbecoming && ibecoming_bytes) {
+		len += scnprintf(buf + len, size - len, "%25s\t%llu\n", "Avg fail becoming bytes",
+				 DIV_ROUND_UP(ibecoming_bytes, fbecoming));
+	}
+
+	WARN_ON_ONCE(idecompress_bytes && !fdecompress);
+	if (fdecompress && idecompress_bytes) {
+		len += scnprintf(buf + len, size - len, "%25s\t%llu\n", "Avg fail decomp bytes",
+				 DIV_ROUND_UP(idecompress_bytes, fdecompress));
+	}
+
+	WARN_ON_ONCE(imod_bytes && !floads);
+	if (floads && imod_bytes) {
+		len += scnprintf(buf + len, size - len, "%25s\t%llu\n", "Average fail load bytes",
+				 DIV_ROUND_UP(imod_bytes, floads));
+	}
+
+	/* End of our debug preamble header. */
+
+	/* Catch when we've gone beyond our expected preamble */
+	WARN_ON_ONCE(len >= MAX_PREAMBLE);
+
+	if (list_empty(&dup_failed_modules))
+		goto out;
+
+	len += scnprintf(buf + len, size - len, "Duplicate failed modules:\n");
+	len += scnprintf(buf + len, size - len, "%25s\t%15s\t%25s\n",
+			 "module-name", "How-many-times", "Reason");
+	mutex_lock(&module_mutex);
+
+
+	list_for_each_entry_rcu(mod_fail, &dup_failed_modules, list) {
+		if (WARN_ON_ONCE(++count_failed >= MAX_FAILED_MOD_PRINT))
+			goto out_unlock;
+		len += scnprintf(buf + len, size - len, "%25s\t%15llu\t%25s\n", mod_fail->name,
+				 atomic64_read(&mod_fail->count), mod_fail_to_str(mod_fail));
+	}
+out_unlock:
+	mutex_unlock(&module_mutex);
+out:
+	kfree(buf);
+        return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+#undef MAX_PREAMBLE
+#undef MAX_FAILED_MOD_PRINT
+#undef MAX_BYTES_PER_MOD
+
+static const struct file_operations fops_mod_stats = {
+	.read = read_file_mod_stats,
+	.open = simple_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+static int __init module_stats_init(void)
+{
+	debugfs_create_atomic64_t("total_mod_size", 0400, mod_debugfs_root, &total_mod_size);
+	debugfs_create_atomic64_t("total_text_size", 0400, mod_debugfs_root, &total_text_size);
+	debugfs_create_atomic64_t("invalid_kread_bytes", 0400, mod_debugfs_root,
+				  &invalid_kread_bytes);
+	debugfs_create_atomic64_t("invalid_decompress_bytes", 0400, mod_debugfs_root,
+				  &invalid_decompress_bytes);
+	debugfs_create_atomic64_t("invalid_becoming_bytes", 0400, mod_debugfs_root,
+				  &invalid_mod_becoming_bytes);
+	debugfs_create_atomic64_t("invalid_mod_bytes", 0400, mod_debugfs_root, &invalid_mod_bytes);
+	debugfs_create_atomic_t("modcount", 0400, mod_debugfs_root, &modcount);
+	debugfs_create_atomic_t("failed_kreads", 0400, mod_debugfs_root, &failed_kreads);
+	debugfs_create_atomic_t("failed_decompress", 0400, mod_debugfs_root, &failed_decompress);
+	debugfs_create_atomic_t("failed_becoming", 0400, mod_debugfs_root, &failed_becoming);
+	debugfs_create_atomic_t("failed_load_modules", 0400, mod_debugfs_root, &failed_load_modules);
+	debugfs_create_file("stats", 0400, mod_debugfs_root, mod_debugfs_root, &fops_mod_stats);
+
+	return 0;
+}
+module_init(module_stats_init);
diff --git a/kernel/module/tracking.c b/kernel/module/tracking.c
index 26d812e07615..16742d1c630c 100644
--- a/kernel/module/tracking.c
+++ b/kernel/module/tracking.c
@@ -15,6 +15,7 @@
 #include "internal.h"
 
 static LIST_HEAD(unloaded_tainted_modules);
+extern struct dentry *mod_debugfs_root;
 
 int try_add_tainted_module(struct module *mod)
 {
@@ -120,12 +121,8 @@ static const struct file_operations unloaded_tainted_modules_fops = {
 
 static int __init unloaded_tainted_modules_init(void)
 {
-	struct dentry *dir;
-
-	dir = debugfs_create_dir("modules", NULL);
-	debugfs_create_file("unloaded_tainted", 0444, dir, NULL,
+	debugfs_create_file("unloaded_tainted", 0444, mod_debugfs_root, NULL,
 			    &unloaded_tainted_modules_fops);
-
 	return 0;
 }
 module_init(unloaded_tainted_modules_init);
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 1/6] module: fix kmemleak annotations for non init ELF sections
  2023-04-05  2:26 ` [PATCH v2 1/6] module: fix kmemleak annotations for non init ELF sections Luis Chamberlain
@ 2023-04-05  6:52   ` Song Liu
  2023-04-11 15:17   ` Catalin Marinas
  1 sibling, 0 replies; 23+ messages in thread
From: Song Liu @ 2023-04-05  6:52 UTC (permalink / raw)
  To: Luis Chamberlain
  Cc: david, patches, linux-modules, linux-mm, linux-kernel, pmladek,
	petr.pavlu, prarit, torvalds, gregkh, rafael, christophe.leroy,
	tglx, peterz, rppt, dave, willy, vbabka, mhocko, dave.hansen,
	colin.i.king, jim.cromie, catalin.marinas, jbaron,
	rick.p.edgecombe

On Tue, Apr 4, 2023 at 7:27 PM Luis Chamberlain <mcgrof@kernel.org> wrote:
>
> Commit ac3b43283923 ("module: replace module_layout with module_memory")
> reworked the way to handle memory allocations to make it clearer. But it
> lost in translation how we handled kmemleak_ignore() or kmemleak_not_leak()
> for different ELF sections.
>
> Fix this and clarify the comments a bit more.
>
> Fixes: ac3b43283923 ("module: replace module_layout with module_memory")
> Reported-by: Jim Cromie <jim.cromie@gmail.com>
> Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>

Acked-by: Song Liu <song@kernel.org>

Thanks for the fix!

> ---
>  kernel/module/main.c | 20 ++++++++++++++++----
>  1 file changed, 16 insertions(+), 4 deletions(-)
>
> diff --git a/kernel/module/main.c b/kernel/module/main.c
> index 5cc21083af04..d8bb23fa6989 100644
> --- a/kernel/module/main.c
> +++ b/kernel/module/main.c
> @@ -2233,11 +2233,23 @@ static int move_module(struct module *mod, struct load_info *info)
>                 ptr = module_memory_alloc(mod->mem[type].size, type);
>
>                 /*
> -                * The pointer to this block is stored in the module structure
> -                * which is inside the block. Just mark it as not being a
> -                * leak.
> +                * The pointer to these blocks of memory are stored on the module
> +                * structure and we keep that around so long as the module is
> +                * around. We only free that memory when we unload the module.
> +                * Just mark them as not being a leak then. The .init* ELF
> +                * sections *do* get freed after boot so we treat them slightly
> +                * differently and only grey them out -- they work as typical
> +                * memory allocations which *do* eventually get freed.
>                  */
> -               kmemleak_ignore(ptr);
> +               switch (type) {
> +               case MOD_INIT_TEXT: /* fallthrough */
> +               case MOD_INIT_DATA: /* fallthrough */
> +               case MOD_INIT_RODATA: /* fallthrough */
> +                       kmemleak_ignore(ptr);
> +                       break;
> +               default:
> +                       kmemleak_not_leak(ptr);
> +               }
>                 if (!ptr) {
>                         t = type;
>                         goto out_enomem;
> --
> 2.39.2
>

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 5/6] debugfs: add debugfs_create_atomic64_t for atomic64_t
  2023-04-05  2:27 ` [PATCH v2 5/6] debugfs: add debugfs_create_atomic64_t for atomic64_t Luis Chamberlain
@ 2023-04-05 15:26   ` Linus Torvalds
  2023-04-05 16:04     ` Luis Chamberlain
  0 siblings, 1 reply; 23+ messages in thread
From: Linus Torvalds @ 2023-04-05 15:26 UTC (permalink / raw)
  To: Luis Chamberlain
  Cc: david, patches, linux-modules, linux-mm, linux-kernel, pmladek,
	petr.pavlu, prarit, gregkh, rafael, christophe.leroy, tglx,
	peterz, song, rppt, dave, willy, vbabka, mhocko, dave.hansen,
	colin.i.king, jim.cromie, catalin.marinas, jbaron,
	rick.p.edgecombe

On Tue, Apr 4, 2023 at 7:27 PM Luis Chamberlain <mcgrof@kernel.org> wrote:
>
> Sometimes you want to add debugfs entries for atomic counters which
> can be pretty large using atomic64_t. Add support for these.

So I realize why you use atomic64, but I really suspect you'd be
better off with just the regular "atomic_long".

This is not some debug stat that we care deeply about on 32-bit, and
"atomic64" is often really really nasty on 32-bit architectures.

For example, on x86, instead of being a single instruction, it ends up
being a cmpxchg loop. In fact, even a single atomic read is a cmpxchg
(admittedly without the need for looping).

And yeah, I realize that we don't have a "atomic_long" debugfs
interface either. But I think we could just use atomic_long for the
module code (avoiding all the horrors of 64-bit atomics on 32-bit
architectures), and then using just 'var->counter' for the value. It's
not like the debugfs stuff actually does any truly atomic updates.

So something like

        debugfs_create_ulong(... &val->counter ..);

instead of

        debugfs_create_atomic64(... &val ..);

Hmm?

I dunno. I just think this is not something that may be worth
introducing a new thing for, when it is *so* painful on 32-bit, and
doesn't seem worth it.

                   Linus

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 5/6] debugfs: add debugfs_create_atomic64_t for atomic64_t
  2023-04-05 15:26   ` Linus Torvalds
@ 2023-04-05 16:04     ` Luis Chamberlain
  2023-04-05 16:11       ` Luis Chamberlain
  0 siblings, 1 reply; 23+ messages in thread
From: Luis Chamberlain @ 2023-04-05 16:04 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: david, patches, linux-modules, linux-mm, linux-kernel, pmladek,
	petr.pavlu, prarit, gregkh, rafael, christophe.leroy, tglx,
	peterz, song, rppt, dave, willy, vbabka, mhocko, dave.hansen,
	colin.i.king, jim.cromie, catalin.marinas, jbaron,
	rick.p.edgecombe

On Wed, Apr 05, 2023 at 08:26:18AM -0700, Linus Torvalds wrote:
> So I realize why you use atomic64, but I really suspect you'd be
> better off with just the regular "atomic_long".

<-- snip --> 

> So something like
> 
>         debugfs_create_ulong(... &val->counter ..);
> 
> instead of
> 
>         debugfs_create_atomic64(... &val ..);
> 
> Hmm?

We already have debugfs_create_ulong(), it just uses unsigned long
with no atomic_long. I can just use that then.

  Luis

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 5/6] debugfs: add debugfs_create_atomic64_t for atomic64_t
  2023-04-05 16:04     ` Luis Chamberlain
@ 2023-04-05 16:11       ` Luis Chamberlain
  2023-04-05 16:23         ` Linus Torvalds
  0 siblings, 1 reply; 23+ messages in thread
From: Luis Chamberlain @ 2023-04-05 16:11 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: david, patches, linux-modules, linux-mm, linux-kernel, pmladek,
	petr.pavlu, prarit, gregkh, rafael, christophe.leroy, tglx,
	peterz, song, rppt, dave, willy, vbabka, mhocko, dave.hansen,
	colin.i.king, jim.cromie, catalin.marinas, jbaron,
	rick.p.edgecombe

On Wed, Apr 05, 2023 at 09:04:27AM -0700, Luis Chamberlain wrote:
> On Wed, Apr 05, 2023 at 08:26:18AM -0700, Linus Torvalds wrote:
> > So I realize why you use atomic64, but I really suspect you'd be
> > better off with just the regular "atomic_long".
> 
> <-- snip --> 
> 
> > So something like
> > 
> >         debugfs_create_ulong(... &val->counter ..);
> > 
> > instead of
> > 
> >         debugfs_create_atomic64(... &val ..);
> > 
> > Hmm?
> 
> We already have debugfs_create_ulong(), it just uses unsigned long
> with no atomic_long. I can just use that then.

Oh but I don't get the atomic incs, so we'd need debugfs_create_atomic_long_t().

  Luis

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 5/6] debugfs: add debugfs_create_atomic64_t for atomic64_t
  2023-04-05 16:11       ` Luis Chamberlain
@ 2023-04-05 16:23         ` Linus Torvalds
  2023-04-05 16:53           ` Luis Chamberlain
  0 siblings, 1 reply; 23+ messages in thread
From: Linus Torvalds @ 2023-04-05 16:23 UTC (permalink / raw)
  To: Luis Chamberlain
  Cc: david, patches, linux-modules, linux-mm, linux-kernel, pmladek,
	petr.pavlu, prarit, gregkh, rafael, christophe.leroy, tglx,
	peterz, song, rppt, dave, willy, vbabka, mhocko, dave.hansen,
	colin.i.king, jim.cromie, catalin.marinas, jbaron,
	rick.p.edgecombe

On Wed, Apr 5, 2023 at 9:11 AM Luis Chamberlain <mcgrof@kernel.org> wrote:
>
> Oh but I don't get the atomic incs, so we'd need debugfs_create_atomic_long_t().

No, you misunderstand what I meant.

Just use "atomic_long_t" in the module code.

But then the debugfs code should do

        debugfs_create_ulong(... &val->counter ..);

to expose said atomic_long values.

No need for new debugfs interfaces.

Because "atomic_long" is just a regular "long" as far as plain
read/set operations are concerned - which is all that the debugfs code
does anyway.

So I think you can do something like

  atomic_long_t total_mod_size;

   ...

  debugfs_create_ulong("total_mod_size",
       0400, mod_debugfs_root,
       &total_mod_size.counter);

but I didn't actually try to compile that kind of version.

(I think "counter" is actually a _signed_ long, so maybe the types don't match).

               Linus

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 5/6] debugfs: add debugfs_create_atomic64_t for atomic64_t
  2023-04-05 16:23         ` Linus Torvalds
@ 2023-04-05 16:53           ` Luis Chamberlain
  2023-04-06  8:15             ` David Laight
  0 siblings, 1 reply; 23+ messages in thread
From: Luis Chamberlain @ 2023-04-05 16:53 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: david, patches, linux-modules, linux-mm, linux-kernel, pmladek,
	petr.pavlu, prarit, gregkh, rafael, christophe.leroy, tglx,
	peterz, song, rppt, dave, willy, vbabka, mhocko, dave.hansen,
	colin.i.king, jim.cromie, catalin.marinas, jbaron,
	rick.p.edgecombe

On Wed, Apr 05, 2023 at 09:23:09AM -0700, Linus Torvalds wrote:
> On Wed, Apr 5, 2023 at 9:11 AM Luis Chamberlain <mcgrof@kernel.org> wrote:
> >
> > Oh but I don't get the atomic incs, so we'd need debugfs_create_atomic_long_t().
> 
>   debugfs_create_ulong("total_mod_size",
>        0400, mod_debugfs_root,
>        &total_mod_size.counter);
> 
> but I didn't actually try to compile that kind of version.
> 
> (I think "counter" is actually a _signed_ long, so maybe the types don't match).

I see yes, sadly we'd have to cast to (unsigned long *) to make that
work as atomic_long counters are long long int:

   debugfs_create_ulong("total_mod_size",
        0400, mod_debugfs_root,
-        &total_mod_size.counter);
+        (unsigned long *)&total_mod_size.counter);

That's:

unsigned long min bits 32
long long     min bits 64

But since we'd be doing our accounting in atomic_long and just use
debugfs for prints I think that's fine. Just a bit ugly.

  Luis

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 2/6] module: move finished_loading()
  2023-04-05  2:26 ` [PATCH v2 2/6] module: move finished_loading() Luis Chamberlain
@ 2023-04-05 17:06   ` David Hildenbrand
  2023-04-05 19:55     ` Luis Chamberlain
  0 siblings, 1 reply; 23+ messages in thread
From: David Hildenbrand @ 2023-04-05 17:06 UTC (permalink / raw)
  To: Luis Chamberlain, patches, linux-modules, linux-mm, linux-kernel,
	pmladek, petr.pavlu, prarit, torvalds, gregkh, rafael
  Cc: christophe.leroy, tglx, peterz, song, rppt, dave, willy, vbabka,
	mhocko, dave.hansen, colin.i.king, jim.cromie, catalin.marinas,
	jbaron, rick.p.edgecombe

On 05.04.23 04:26, Luis Chamberlain wrote:
> This has no functional change, just moves a routine earlier
> as we'll make use of it next.
> 
> Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
> ---

I'd simply squash into #3, as that's short enough that the move doesn't 
add significant noise. Anyhow:

Reviewed-by: David Hildenbrand <david@redhat.com>

-- 
Thanks,

David / dhildenb


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 3/6] module: extract patient module check into helper
  2023-04-05  2:26 ` [PATCH v2 3/6] module: extract patient module check into helper Luis Chamberlain
@ 2023-04-05 17:11   ` David Hildenbrand
  2023-04-05 19:45     ` Luis Chamberlain
  0 siblings, 1 reply; 23+ messages in thread
From: David Hildenbrand @ 2023-04-05 17:11 UTC (permalink / raw)
  To: Luis Chamberlain, patches, linux-modules, linux-mm, linux-kernel,
	pmladek, petr.pavlu, prarit, torvalds, gregkh, rafael
  Cc: christophe.leroy, tglx, peterz, song, rppt, dave, willy, vbabka,
	mhocko, dave.hansen, colin.i.king, jim.cromie, catalin.marinas,
	jbaron, rick.p.edgecombe

On 05.04.23 04:26, Luis Chamberlain wrote:
> The patient module check inside add_unformed_module() is large
> enough as we need it. It is a bit hard to read too, so just
> move it to a helper and do the inverse checks first to help
> shift the code and make it easier to read. The new helper then
> is module_patient_check_exists().
> 
> Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
> ---
>   kernel/module/main.c | 71 +++++++++++++++++++++++++-------------------
>   1 file changed, 40 insertions(+), 31 deletions(-)
> 
> diff --git a/kernel/module/main.c b/kernel/module/main.c
> index 98c261928325..8f382580195b 100644
> --- a/kernel/module/main.c
> +++ b/kernel/module/main.c
> @@ -2638,6 +2638,43 @@ static bool finished_loading(const char *name)
>   	return ret;
>   }
>   
> +/* Must be called with module_mutex held */
> +static int module_patient_check_exists(const char *name)
> +{
> +	struct module *old;
> +	int err = 0;
> +
> +	old = find_module_all(name, strlen(name), true);
> +	if (old == NULL)
> +		return 0;
> +
> +	if (old->state == MODULE_STATE_COMING
> +	    || old->state == MODULE_STATE_UNFORMED) {

I never understood why people prefer to prefix the || on a newline. But 
it seems to be a thing in the module/ world :)


> +		/* Wait in case it fails to load. */
> +		mutex_unlock(&module_mutex);
> +		err = wait_event_interruptible(module_wq,
> +				       finished_loading(name));
> +		if (err)
> +			return err;

You return with the mutex unlocked. The caller will unlock again ...

> +
> +		/* The module might have gone in the meantime. */
> +		mutex_lock(&module_mutex);
> +		old = find_module_all(name, strlen(name), true);
> +	}
> +
> +	/*
> +	 * We are here only when the same module was being loaded. Do
> +	 * not try to load it again right now. It prevents long delays
> +	 * caused by serialized module load failures. It might happen
> +	 * when more devices of the same type trigger load of
> +	 * a particular module.
> +	 */
> +	if (old && old->state == MODULE_STATE_LIVE)
> +		return -EEXIST;
> +	else
> +		return -EBUSY;

You can drop the else and return right away.

> +}
> +
>   /*
>    * We try to place it in the list now to make sure it's unique before

Besides, LGTM.

-- 
Thanks,

David / dhildenb


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 3/6] module: extract patient module check into helper
  2023-04-05 17:11   ` David Hildenbrand
@ 2023-04-05 19:45     ` Luis Chamberlain
  0 siblings, 0 replies; 23+ messages in thread
From: Luis Chamberlain @ 2023-04-05 19:45 UTC (permalink / raw)
  To: David Hildenbrand
  Cc: patches, linux-modules, linux-mm, linux-kernel, pmladek,
	petr.pavlu, prarit, torvalds, gregkh, rafael, christophe.leroy,
	tglx, peterz, song, rppt, dave, willy, vbabka, mhocko,
	dave.hansen, colin.i.king, jim.cromie, catalin.marinas, jbaron,
	rick.p.edgecombe

On Wed, Apr 05, 2023 at 07:11:24PM +0200, David Hildenbrand wrote:
> On 05.04.23 04:26, Luis Chamberlain wrote:
> > The patient module check inside add_unformed_module() is large
> > enough as we need it. It is a bit hard to read too, so just
> > move it to a helper and do the inverse checks first to help
> > shift the code and make it easier to read. The new helper then
> > is module_patient_check_exists().
> > 
> > Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
> > ---
> >   kernel/module/main.c | 71 +++++++++++++++++++++++++-------------------
> >   1 file changed, 40 insertions(+), 31 deletions(-)
> > 
> > diff --git a/kernel/module/main.c b/kernel/module/main.c
> > index 98c261928325..8f382580195b 100644
> > --- a/kernel/module/main.c
> > +++ b/kernel/module/main.c
> > @@ -2638,6 +2638,43 @@ static bool finished_loading(const char *name)
> >   	return ret;
> >   }
> > +/* Must be called with module_mutex held */
> > +static int module_patient_check_exists(const char *name)
> > +{
> > +	struct module *old;
> > +	int err = 0;
> > +
> > +	old = find_module_all(name, strlen(name), true);
> > +	if (old == NULL)
> > +		return 0;
> > +
> > +	if (old->state == MODULE_STATE_COMING
> > +	    || old->state == MODULE_STATE_UNFORMED) {
> 
> I never understood why people prefer to prefix the || on a newline. But it
> seems to be a thing in the module/ world :)

Yeah the other way seems better, I'll make it pretty.

> > +		/* Wait in case it fails to load. */
> > +		mutex_unlock(&module_mutex);
> > +		err = wait_event_interruptible(module_wq,
> > +				       finished_loading(name));
> > +		if (err)
> > +			return err;
> 
> You return with the mutex unlocked. The caller will unlock again ...

Fixed now by moving the mutex below up after the wait_event_interruptible(),
thanks.

> > +
> > +		/* The module might have gone in the meantime. */
> > +		mutex_lock(&module_mutex);
> > +		old = find_module_all(name, strlen(name), true);
> > +	}
> > +
> > +	/*
> > +	 * We are here only when the same module was being loaded. Do
> > +	 * not try to load it again right now. It prevents long delays
> > +	 * caused by serialized module load failures. It might happen
> > +	 * when more devices of the same type trigger load of
> > +	 * a particular module.
> > +	 */
> > +	if (old && old->state == MODULE_STATE_LIVE)
> > +		return -EEXIST;
> > +	else
> > +		return -EBUSY;
> 
> You can drop the else and return right away.

Will make it pretty like that, thanks.

  Luis

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 2/6] module: move finished_loading()
  2023-04-05 17:06   ` David Hildenbrand
@ 2023-04-05 19:55     ` Luis Chamberlain
  0 siblings, 0 replies; 23+ messages in thread
From: Luis Chamberlain @ 2023-04-05 19:55 UTC (permalink / raw)
  To: David Hildenbrand
  Cc: patches, linux-modules, linux-mm, linux-kernel, pmladek,
	petr.pavlu, prarit, torvalds, gregkh, rafael, christophe.leroy,
	tglx, peterz, song, rppt, dave, willy, vbabka, mhocko,
	dave.hansen, colin.i.king, jim.cromie, catalin.marinas, jbaron,
	rick.p.edgecombe

On Wed, Apr 05, 2023 at 07:06:35PM +0200, David Hildenbrand wrote:
> On 05.04.23 04:26, Luis Chamberlain wrote:
> > This has no functional change, just moves a routine earlier
> > as we'll make use of it next.
> > 
> > Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
> > ---
> 
> I'd simply squash into #3, as that's short enough that the move doesn't add
> significant noise. Anyhow:

I'll fold that, thanks.

> Reviewed-by: David Hildenbrand <david@redhat.com>

What would be *really* nice, if you can, is an output of the new module
debugfs stats on your big system. It would be nice to also see the stats
if you revert the patch "module: avoid allocation if module is already present
and ready".

The delta between those stats should give us a more realistic analysis
of probable savings due to that patch on virtual memory on bootup on a
large system. In particular the delta between "Virtual mem wasted bytes".

  Luis

^ permalink raw reply	[flat|nested] 23+ messages in thread

* RE: [PATCH v2 5/6] debugfs: add debugfs_create_atomic64_t for atomic64_t
  2023-04-05 16:53           ` Luis Chamberlain
@ 2023-04-06  8:15             ` David Laight
  2023-04-06 13:38               ` Christophe Leroy
  0 siblings, 1 reply; 23+ messages in thread
From: David Laight @ 2023-04-06  8:15 UTC (permalink / raw)
  To: 'Luis Chamberlain', Linus Torvalds
  Cc: david, patches, linux-modules, linux-mm, linux-kernel, pmladek,
	petr.pavlu, prarit, gregkh, rafael, christophe.leroy, tglx,
	peterz, song, rppt, dave, willy, vbabka, mhocko, dave.hansen,
	colin.i.king, jim.cromie, catalin.marinas, jbaron,
	rick.p.edgecombe

From: Luis Chamberlain  Luis Chamberlain
> Sent: 05 April 2023 17:53
> 
> On Wed, Apr 05, 2023 at 09:23:09AM -0700, Linus Torvalds wrote:
> > On Wed, Apr 5, 2023 at 9:11 AM Luis Chamberlain <mcgrof@kernel.org> wrote:
> > >
> > > Oh but I don't get the atomic incs, so we'd need debugfs_create_atomic_long_t().
> >
> >   debugfs_create_ulong("total_mod_size",
> >        0400, mod_debugfs_root,
> >        &total_mod_size.counter);
> >
> > but I didn't actually try to compile that kind of version.
> >
> > (I think "counter" is actually a _signed_ long, so maybe the types don't match).
> 
> I see yes, sadly we'd have to cast to (unsigned long *) to make that
> work as atomic_long counters are long long int:
> 
>    debugfs_create_ulong("total_mod_size",
>         0400, mod_debugfs_root,
> -        &total_mod_size.counter);
> +        (unsigned long *)&total_mod_size.counter);
> 
> That's:
> 
> unsigned long min bits 32
> long long     min bits 64
> 
> But since we'd be doing our accounting in atomic_long and just use
> debugfs for prints I think that's fine. Just a bit ugly.

That isn't going to work.
It is pretty much never right to do *(integer_type *)&integer_variable.

But are you really sure 'atomic_long' is 'long long'
doesn't sound right at all.
'long long' is 128bit on 64bit and 64bit on 32bit - so is always
a double-register access.
This is worse than atomic_u64.

I should probably try to lookup and/or measure the performance
of atomic operations (esp. cmpxchg) on x86.
Historically they were a separate read and write bus cycles with
the 'lock' signal asserted (and still are if they cross cache
line boundaries).
But it is possible that at least some of the locked operations
(esp. the xchg ones) are implemented within the cache itself
so are just a single cpu -> cache operation.
If not it is actually possible that the _local variants that
seem to have been added should not use the locked instructions!

	David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 5/6] debugfs: add debugfs_create_atomic64_t for atomic64_t
  2023-04-06  8:15             ` David Laight
@ 2023-04-06 13:38               ` Christophe Leroy
  2023-04-06 13:48                 ` David Laight
  0 siblings, 1 reply; 23+ messages in thread
From: Christophe Leroy @ 2023-04-06 13:38 UTC (permalink / raw)
  To: David Laight, 'Luis Chamberlain', Linus Torvalds
  Cc: david, patches, linux-modules, linux-mm, linux-kernel, pmladek,
	petr.pavlu, prarit, gregkh, rafael, tglx, peterz, song, rppt,
	dave, willy, vbabka, mhocko, dave.hansen, colin.i.king,
	jim.cromie, catalin.marinas, jbaron, rick.p.edgecombe



Le 06/04/2023 à 10:15, David Laight a écrit :
> From: Luis Chamberlain  Luis Chamberlain
>> Sent: 05 April 2023 17:53
>>
>> On Wed, Apr 05, 2023 at 09:23:09AM -0700, Linus Torvalds wrote:
>>> On Wed, Apr 5, 2023 at 9:11 AM Luis Chamberlain <mcgrof@kernel.org> wrote:
>>>>
>>>> Oh but I don't get the atomic incs, so we'd need debugfs_create_atomic_long_t().
>>>
>>>    debugfs_create_ulong("total_mod_size",
>>>         0400, mod_debugfs_root,
>>>         &total_mod_size.counter);
>>>
>>> but I didn't actually try to compile that kind of version.
>>>
>>> (I think "counter" is actually a _signed_ long, so maybe the types don't match).
>>
>> I see yes, sadly we'd have to cast to (unsigned long *) to make that
>> work as atomic_long counters are long long int:
>>
>>     debugfs_create_ulong("total_mod_size",
>>          0400, mod_debugfs_root,
>> -        &total_mod_size.counter);
>> +        (unsigned long *)&total_mod_size.counter);
>>
>> That's:
>>
>> unsigned long min bits 32
>> long long     min bits 64
>>
>> But since we'd be doing our accounting in atomic_long and just use
>> debugfs for prints I think that's fine. Just a bit ugly.
> 
> That isn't going to work.
> It is pretty much never right to do *(integer_type *)&integer_variable.
> 
> But are you really sure 'atomic_long' is 'long long'
> doesn't sound right at all.
> 'long long' is 128bit on 64bit and 64bit on 32bit - so is always
> a double-register access.
> This is worse than atomic_u64.

On powerpc 'long long' is 64 bits on both PPC32 and PPC64.

Christophe


> 
> I should probably try to lookup and/or measure the performance
> of atomic operations (esp. cmpxchg) on x86.
> Historically they were a separate read and write bus cycles with
> the 'lock' signal asserted (and still are if they cross cache
> line boundaries).
> But it is possible that at least some of the locked operations
> (esp. the xchg ones) are implemented within the cache itself
> so are just a single cpu -> cache operation.
> If not it is actually possible that the _local variants that
> seem to have been added should not use the locked instructions!
> 
> 	David
> 
> -
> Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
> Registration No: 1397386 (Wales)

^ permalink raw reply	[flat|nested] 23+ messages in thread

* RE: [PATCH v2 5/6] debugfs: add debugfs_create_atomic64_t for atomic64_t
  2023-04-06 13:38               ` Christophe Leroy
@ 2023-04-06 13:48                 ` David Laight
  2023-04-06 14:14                   ` David Hildenbrand
  0 siblings, 1 reply; 23+ messages in thread
From: David Laight @ 2023-04-06 13:48 UTC (permalink / raw)
  To: 'Christophe Leroy', 'Luis Chamberlain', Linus Torvalds
  Cc: david, patches, linux-modules, linux-mm, linux-kernel, pmladek,
	petr.pavlu, prarit, gregkh, rafael, tglx, peterz, song, rppt,
	dave, willy, vbabka, mhocko, dave.hansen, colin.i.king,
	jim.cromie, catalin.marinas, jbaron, rick.p.edgecombe

From: Christophe Leroy
> Sent: 06 April 2023 14:38
...
> On powerpc 'long long' is 64 bits on both PPC32 and PPC64.

It probably in on x85-64 as well.
By brain is getting frazzled.

On 64bit long long ought to be 128bit.

	David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 5/6] debugfs: add debugfs_create_atomic64_t for atomic64_t
  2023-04-06 13:48                 ` David Laight
@ 2023-04-06 14:14                   ` David Hildenbrand
  0 siblings, 0 replies; 23+ messages in thread
From: David Hildenbrand @ 2023-04-06 14:14 UTC (permalink / raw)
  To: David Laight, 'Christophe Leroy',
	'Luis Chamberlain',
	Linus Torvalds
  Cc: patches, linux-modules, linux-mm, linux-kernel, pmladek,
	petr.pavlu, prarit, gregkh, rafael, tglx, peterz, song, rppt,
	dave, willy, vbabka, mhocko, dave.hansen, colin.i.king,
	jim.cromie, catalin.marinas, jbaron, rick.p.edgecombe

On 06.04.23 15:48, David Laight wrote:
> From: Christophe Leroy
>> Sent: 06 April 2023 14:38
> ...
>> On powerpc 'long long' is 64 bits on both PPC32 and PPC64.
> 
> It probably in on x85-64 as well.
> By brain is getting frazzled.
> 
> On 64bit long long ought to be 128bit.

I might have been living under a rock, but the only requirement I am 
aware of is for long long to be at least 64bit wide.

AFAIK, that is also the case on s390x and aarch64.

-- 
Thanks,

David / dhildenb


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 1/6] module: fix kmemleak annotations for non init ELF sections
  2023-04-05  2:26 ` [PATCH v2 1/6] module: fix kmemleak annotations for non init ELF sections Luis Chamberlain
  2023-04-05  6:52   ` Song Liu
@ 2023-04-11 15:17   ` Catalin Marinas
  2023-04-11 17:06     ` Luis Chamberlain
  1 sibling, 1 reply; 23+ messages in thread
From: Catalin Marinas @ 2023-04-11 15:17 UTC (permalink / raw)
  To: Luis Chamberlain
  Cc: david, patches, linux-modules, linux-mm, linux-kernel, pmladek,
	petr.pavlu, prarit, torvalds, gregkh, rafael, christophe.leroy,
	tglx, peterz, song, rppt, dave, willy, vbabka, mhocko,
	dave.hansen, colin.i.king, jim.cromie, jbaron, rick.p.edgecombe

On Tue, Apr 04, 2023 at 07:26:57PM -0700, Luis Chamberlain wrote:
> diff --git a/kernel/module/main.c b/kernel/module/main.c
> index 5cc21083af04..d8bb23fa6989 100644
> --- a/kernel/module/main.c
> +++ b/kernel/module/main.c
> @@ -2233,11 +2233,23 @@ static int move_module(struct module *mod, struct load_info *info)
>  		ptr = module_memory_alloc(mod->mem[type].size, type);
>  
>  		/*
> -		 * The pointer to this block is stored in the module structure
> -		 * which is inside the block. Just mark it as not being a
> -		 * leak.
> +		 * The pointer to these blocks of memory are stored on the module
> +		 * structure and we keep that around so long as the module is
> +		 * around. We only free that memory when we unload the module.
> +		 * Just mark them as not being a leak then. The .init* ELF
> +		 * sections *do* get freed after boot so we treat them slightly
> +		 * differently and only grey them out -- they work as typical
> +		 * memory allocations which *do* eventually get freed.
>  		 */
> -		kmemleak_ignore(ptr);
> +		switch (type) {
> +		case MOD_INIT_TEXT: /* fallthrough */
> +		case MOD_INIT_DATA: /* fallthrough */
> +		case MOD_INIT_RODATA: /* fallthrough */
> +			kmemleak_ignore(ptr);
> +			break;
> +		default:
> +			kmemleak_not_leak(ptr);
> +		}

This works as well but if you want to keep it simple, just call
kmemleak_not_leak() in all cases. When freeing the init sections, they
would be removed from the kmemleak tracing anyway.

-- 
Catalin

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 1/6] module: fix kmemleak annotations for non init ELF sections
  2023-04-11 15:17   ` Catalin Marinas
@ 2023-04-11 17:06     ` Luis Chamberlain
  0 siblings, 0 replies; 23+ messages in thread
From: Luis Chamberlain @ 2023-04-11 17:06 UTC (permalink / raw)
  To: Catalin Marinas
  Cc: david, patches, linux-modules, linux-mm, linux-kernel, pmladek,
	petr.pavlu, prarit, torvalds, gregkh, rafael, christophe.leroy,
	tglx, peterz, song, rppt, dave, willy, vbabka, mhocko,
	dave.hansen, colin.i.king, jim.cromie, jbaron, rick.p.edgecombe

On Tue, Apr 11, 2023 at 04:17:35PM +0100, Catalin Marinas wrote:
> On Tue, Apr 04, 2023 at 07:26:57PM -0700, Luis Chamberlain wrote:
> > diff --git a/kernel/module/main.c b/kernel/module/main.c
> > index 5cc21083af04..d8bb23fa6989 100644
> > --- a/kernel/module/main.c
> > +++ b/kernel/module/main.c
> > @@ -2233,11 +2233,23 @@ static int move_module(struct module *mod, struct load_info *info)
> >  		ptr = module_memory_alloc(mod->mem[type].size, type);
> >  
> >  		/*
> > -		 * The pointer to this block is stored in the module structure
> > -		 * which is inside the block. Just mark it as not being a
> > -		 * leak.
> > +		 * The pointer to these blocks of memory are stored on the module
> > +		 * structure and we keep that around so long as the module is
> > +		 * around. We only free that memory when we unload the module.
> > +		 * Just mark them as not being a leak then. The .init* ELF
> > +		 * sections *do* get freed after boot so we treat them slightly
> > +		 * differently and only grey them out -- they work as typical
> > +		 * memory allocations which *do* eventually get freed.
> >  		 */
> > -		kmemleak_ignore(ptr);
> > +		switch (type) {
> > +		case MOD_INIT_TEXT: /* fallthrough */
> > +		case MOD_INIT_DATA: /* fallthrough */
> > +		case MOD_INIT_RODATA: /* fallthrough */
> > +			kmemleak_ignore(ptr);
> > +			break;
> > +		default:
> > +			kmemleak_not_leak(ptr);
> > +		}
> 
> This works as well but if you want to keep it simple, just call
> kmemleak_not_leak() in all cases. When freeing the init sections, they
> would be removed from the kmemleak tracing anyway.

It is up to you as you were the one who originally used different calls
here, so I didn't want to change the old mechanism. Changing it to use
kmemleak_not_leak() would be a functional change, do we loose anything
for using kmemleak_not_leak() for all? Ie, why had you used a different
set of calls when you first added this depending on the if its init or
not? Is the value no longer there?

  Luis

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2023-04-11 17:06 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-04-05  2:26 [PATCH v2 0/6] module: avoid userspace pressure on unwanted allocations Luis Chamberlain
2023-04-05  2:26 ` [PATCH v2 1/6] module: fix kmemleak annotations for non init ELF sections Luis Chamberlain
2023-04-05  6:52   ` Song Liu
2023-04-11 15:17   ` Catalin Marinas
2023-04-11 17:06     ` Luis Chamberlain
2023-04-05  2:26 ` [PATCH v2 2/6] module: move finished_loading() Luis Chamberlain
2023-04-05 17:06   ` David Hildenbrand
2023-04-05 19:55     ` Luis Chamberlain
2023-04-05  2:26 ` [PATCH v2 3/6] module: extract patient module check into helper Luis Chamberlain
2023-04-05 17:11   ` David Hildenbrand
2023-04-05 19:45     ` Luis Chamberlain
2023-04-05  2:27 ` [PATCH v2 4/6] module: avoid allocation if module is already present and ready Luis Chamberlain
2023-04-05  2:27 ` [PATCH v2 5/6] debugfs: add debugfs_create_atomic64_t for atomic64_t Luis Chamberlain
2023-04-05 15:26   ` Linus Torvalds
2023-04-05 16:04     ` Luis Chamberlain
2023-04-05 16:11       ` Luis Chamberlain
2023-04-05 16:23         ` Linus Torvalds
2023-04-05 16:53           ` Luis Chamberlain
2023-04-06  8:15             ` David Laight
2023-04-06 13:38               ` Christophe Leroy
2023-04-06 13:48                 ` David Laight
2023-04-06 14:14                   ` David Hildenbrand
2023-04-05  2:27 ` [PATCH v2 6/6] module: add debug stats to help identify memory pressure Luis Chamberlain

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.