diff mbox series

[kmod] testsuite: add tests for weak dependencies

Message ID 20240530070836.9438-1-jtornosm@redhat.com (mailing list archive)
State Handled Elsewhere
Headers show
Series [kmod] testsuite: add tests for weak dependencies | expand

Commit Message

Jose Ignacio Tornos Martinez May 30, 2024, 7:08 a.m. UTC
The following tests to verify weak dependencies have been implemented:
1) modprobe test to check that related weakdep modules are not loaded
   due to being a weakdep.
2) depmod test to check weakdep output.
3) user test to check that configuration files with weakdep are parsed
   correctly and related weakdep modules can be read correctly from user
   applications.

Signed-off-by: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
---
 Makefile.am                                   |   4 +-
 testsuite/.gitignore                          |   3 +
 testsuite/module-playground/Makefile          |   2 +
 testsuite/module-playground/mod-weakdep.c     |  15 +++
 .../lib/modules/4.4.4/correct-modules.weakdep |   2 +
 .../etc/modprobe.d/dumb-weakdep.conf          |   1 +
 .../lib/modules/4.4.4/modules.alias           |   1 +
 .../lib/modules/4.4.4/modules.alias.bin       | Bin 0 -> 12 bytes
 .../modules/4.4.4/modules.builtin.alias.bin   |   0
 .../lib/modules/4.4.4/modules.builtin.bin     |   0
 .../lib/modules/4.4.4/modules.dep             |   3 +
 .../lib/modules/4.4.4/modules.dep.bin         | Bin 0 -> 188 bytes
 .../lib/modules/4.4.4/modules.devname         |   1 +
 .../lib/modules/4.4.4/modules.softdep         |   1 +
 .../lib/modules/4.4.4/modules.symbols         |   3 +
 .../lib/modules/4.4.4/modules.symbols.bin     | Bin 0 -> 78 bytes
 .../lib/modules/4.4.4/modules.weakdep         |   1 +
 .../test-user/correct-weakdep.txt             |   2 +
 .../etc/modprobe.d/dumb-weakdep.conf          |   1 +
 .../test-user/lib/modules/4.4.4/modules.alias |   1 +
 .../lib/modules/4.4.4/modules.alias.bin       | Bin 0 -> 12 bytes
 .../modules/4.4.4/modules.builtin.alias.bin   |   0
 .../lib/modules/4.4.4/modules.builtin.bin     |   0
 .../test-user/lib/modules/4.4.4/modules.dep   |   4 +
 .../lib/modules/4.4.4/modules.dep.bin         | Bin 0 -> 242 bytes
 .../lib/modules/4.4.4/modules.devname         |   0
 .../lib/modules/4.4.4/modules.softdep         |   1 +
 .../lib/modules/4.4.4/modules.symbols         |   3 +
 .../lib/modules/4.4.4/modules.symbols.bin     | Bin 0 -> 78 bytes
 .../lib/modules/4.4.4/modules.weakdep         |   2 +
 testsuite/setup-rootfs.sh                     |   9 ++
 testsuite/test-depmod.c                       |  27 +++++
 testsuite/test-modprobe.c                     |  23 ++++
 testsuite/test-user.c                         | 110 ++++++++++++++++++
 testsuite/testsuite.c                         |  94 +++++++++++++--
 testsuite/testsuite.h                         |   1 +
 36 files changed, 305 insertions(+), 10 deletions(-)
 create mode 100644 testsuite/module-playground/mod-weakdep.c
 create mode 100644 testsuite/rootfs-pristine/test-depmod/check-weakdep/lib/modules/4.4.4/correct-modules.weakdep
 create mode 100644 testsuite/rootfs-pristine/test-modprobe/weakdep-loop/etc/modprobe.d/dumb-weakdep.conf
 create mode 100644 testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.alias
 create mode 100644 testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.alias.bin
 create mode 100644 testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.builtin.alias.bin
 create mode 100644 testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.builtin.bin
 create mode 100644 testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.dep
 create mode 100644 testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.dep.bin
 create mode 100644 testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.devname
 create mode 100644 testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.softdep
 create mode 100644 testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.symbols
 create mode 100644 testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.symbols.bin
 create mode 100644 testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.weakdep
 create mode 100644 testsuite/rootfs-pristine/test-user/correct-weakdep.txt
 create mode 100644 testsuite/rootfs-pristine/test-user/etc/modprobe.d/dumb-weakdep.conf
 create mode 100644 testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.alias
 create mode 100644 testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.alias.bin
 create mode 100644 testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.builtin.alias.bin
 create mode 100644 testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.builtin.bin
 create mode 100644 testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.dep
 create mode 100644 testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.dep.bin
 create mode 100644 testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.devname
 create mode 100644 testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.softdep
 create mode 100644 testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.symbols
 create mode 100644 testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.symbols.bin
 create mode 100644 testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.weakdep
 create mode 100644 testsuite/test-user.c

Comments

Lucas De Marchi June 14, 2024, 7:17 p.m. UTC | #1
On Thu, May 30, 2024 at 09:08:27AM GMT, Jose Ignacio Tornos Martinez wrote:
>The following tests to verify weak dependencies have been implemented:
>1) modprobe test to check that related weakdep modules are not loaded
>   due to being a weakdep.
>2) depmod test to check weakdep output.
>3) user test to check that configuration files with weakdep are parsed
>   correctly and related weakdep modules can be read correctly from user
>   applications.
>
>Signed-off-by: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>

A few whitespace issues below in testsuite/test-user.c
Also we need to define MODULE_WEAKDEP for the mod-weakdep.ko otherwise
we break the build without that defined by kernel-headers.

I fixed those, squashed, and pushed.

Thanks
Lucas De Marchi
Emil Velikov July 8, 2024, 2:58 p.m. UTC | #2
Hello Jose,

On 2024/05/30, Jose Ignacio Tornos Martinez wrote:
> The following tests to verify weak dependencies have been implemented:
> 1) modprobe test to check that related weakdep modules are not loaded
>    due to being a weakdep.
> 2) depmod test to check weakdep output.
> 3) user test to check that configuration files with weakdep are parsed
>    correctly and related weakdep modules can be read correctly from user
>    applications.
> 
> Signed-off-by: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
> ---

Seems like this commit has regressed make distcheck on my end. Namely
I'm running the following commands:

git clone ...
cd kmod
git clean -fxd
./autogen.sh c
make distcheck

Result in:

...
make[5]: *** No rule to make target '.../kmod-32/_build/sub/testsuite/module-playground/mod-weakdep.o', needed by '.../kmod-32/_build/sub/testsuite/module-playground/mod-weakdep.mod'.  Stop.
make[4]: *** [Makefile:1903: .../kmod-32/_build/sub/testsuite/module-playground] Error 2


Can you reproduce it on your end?


While in the area, a couple of question if I may:

- Should we move the new weakdeps API in libkmod/libkmod.sym near the
  end in a separate LIBKMOD_XX section?

As-is, it looks like we're adding symbols to what should be a frozen set
(aka LIBKMOD_5, which was released decade+ ago).

Admittedly there was a similar erroneous(?) change not loo long ago -
9becaae ("libkmod: Add lookup from module name").

@Lucas can/should we fix the kmod_module_new_from_name_lookup symbol in
the version script?


- Is this work related to the weak-modules used in RHEL/Fedora [1]?
  Alternatively, would the RedHat team consider having the weak-modules
  solution in upstream kmod?

... assuming Lucas is OK with the idea. I'm approaching with with my
dkms co-maintainer hat on, where the fewer "if distro == X" logic we
have the better.

Thanks in advance,
Emil

[1] https://src.fedoraproject.org/rpms/kmod/blob/rawhide/f/weak-modules
Lucas De Marchi July 9, 2024, 5:11 a.m. UTC | #3
On Mon, Jul 08, 2024 at 03:58:03PM GMT, Emil Velikov wrote:
>Hello Jose,
>
>On 2024/05/30, Jose Ignacio Tornos Martinez wrote:
>> The following tests to verify weak dependencies have been implemented:
>> 1) modprobe test to check that related weakdep modules are not loaded
>>    due to being a weakdep.
>> 2) depmod test to check weakdep output.
>> 3) user test to check that configuration files with weakdep are parsed
>>    correctly and related weakdep modules can be read correctly from user
>>    applications.
>>
>> Signed-off-by: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
>> ---
>
>Seems like this commit has regressed make distcheck on my end. Namely
>I'm running the following commands:
>
>git clone ...
>cd kmod
>git clean -fxd
>./autogen.sh c
>make distcheck
>
>Result in:
>
>...
>make[5]: *** No rule to make target '.../kmod-32/_build/sub/testsuite/module-playground/mod-weakdep.o', needed by '.../kmod-32/_build/sub/testsuite/module-playground/mod-weakdep.mod'.  Stop.
>make[4]: *** [Makefile:1903: .../kmod-32/_build/sub/testsuite/module-playground] Error 2

I added a fix in
https://lore.kernel.org/linux-modules/20240709044758.67725-1-lucas.de.marchi@gmail.com/T/#t

and also sketched the new CI hooks using github.

>
>
>Can you reproduce it on your end?
>
>
>While in the area, a couple of question if I may:
>
>- Should we move the new weakdeps API in libkmod/libkmod.sym near the
>  end in a separate LIBKMOD_XX section?

yes

>
>As-is, it looks like we're adding symbols to what should be a frozen set
>(aka LIBKMOD_5, which was released decade+ ago).
>
>Admittedly there was a similar erroneous(?) change not loo long ago -
>9becaae ("libkmod: Add lookup from module name").

yes, my bad

>
>@Lucas can/should we fix the kmod_module_new_from_name_lookup symbol in
>the version script?

yes and this should be something for distros to backport.

>
>
>- Is this work related to the weak-modules used in RHEL/Fedora [1]?
>  Alternatively, would the RedHat team consider having the weak-modules
>  solution in upstream kmod?
>
>... assuming Lucas is OK with the idea. I'm approaching with with my

I was not familiar with that weak-modules and will wait for Jose to
clarify.

thanks
Lucas De Marchi

>dkms co-maintainer hat on, where the fewer "if distro == X" logic we
>have the better.
>
>Thanks in advance,
>Emil
>
>[1] https://src.fedoraproject.org/rpms/kmod/blob/rawhide/f/weak-modules
Jose Ignacio Tornos Martinez July 9, 2024, 7:45 a.m. UTC | #4
Hello,

>>Seems like this commit has regressed make distcheck on my end. Namely
>>I'm running the following commands:
>>
>>git clone ...
>>cd kmod
>>git clean -fxd
>>./autogen.sh c
>>make distcheck
>>
>>Result in:
>>
>>...
>>make[5]: *** No rule to make target '.../kmod-32/_build/sub/testsuite/module-playground/mod-weakdep.o', needed by '.../kmod-32/_build/sub/testsuite/module-playground/mod-weakdep.mod'.  Stop.
>>make[4]: *** [Makefile:1903: .../kmod-32/_build/sub/testsuite/module-playground] Error 2
>
>I added a fix in
>https://lore.kernel.org/linux-modules/20240709044758.67725-1-lucas.de.marchi@gmail.com/T/#t
>
>and also sketched the new CI hooks using github.
>
>>Can you reproduce it on your end?

Sorry Emil, I only tested with 'make check' and I didn't try 'make distcheck'
(really I didn't know it).
Yes, it was failing for me too, and I have verified that with the solution
from Lucas ([PATCH 2/3] build: Add mod-weakdep.c to EXTRA_DIST) is working.
Thanks Lucas for fixing it.

>>
>>
>>- Is this work related to the weak-modules used in RHEL/Fedora [1]?
>>  Alternatively, would the RedHat team consider having the weak-modules
>>  solution in upstream kmod?
>>
>>... assuming Lucas is OK with the idea. I'm approaching with with my
>>dkms co-maintainer hat on, where the fewer "if distro == X" logic we
>>have the better.
>
>I was not familiar with that weak-modules and will wait for Jose to
>clarify.

weak modules concept is very different from weak dependencies and not
related. Let me try to explain:

weak modules is about keeping KABI compatibility between kernels with
the same version, in order to reuse modules (internal or external ones),
so it is mainly for RHEL and the update process.
For Fedora, that is the upstream distro, and with no guarantee for KABI,
is not necessary. 

weak dependencies is to be used by upstream (and everywhere) to allow user
applications to be aware of internal dependencies that are not declared as
softdep because they are dynamically loaded.
dracut has approved this feature from yesterday and I am waiting to have
the kernel declaration in linux master branch to apply some weak dependencies
(i.e. lan78xx).

Best regards
José Ignacio
diff mbox series

Patch

diff --git a/Makefile.am b/Makefile.am
index e2e2411..4b67ee2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -262,7 +262,7 @@  TESTSUITE = \
 	testsuite/test-modinfo testsuite/test-util testsuite/test-new-module \
 	testsuite/test-modprobe testsuite/test-blacklist \
 	testsuite/test-dependencies testsuite/test-depmod \
-	testsuite/test-list
+	testsuite/test-list testsuite/test-user
 
 check_PROGRAMS = $(TESTSUITE)
 TESTS = $(TESTSUITE)
@@ -305,6 +305,8 @@  testsuite_test_depmod_LDADD = $(TESTSUITE_LDADD)
 testsuite_test_depmod_CPPFLAGS = $(TESTSUITE_CPPFLAGS)
 testsuite_test_list_LDADD = $(TESTSUITE_LDADD)
 testsuite_test_list_CPPFLAGS = $(TESTSUITE_CPPFLAGS)
+testsuite_test_user_LDADD = $(TESTSUITE_LDADD)
+testsuite_test_user_CPPFLAGS = $(TESTSUITE_CPPFLAGS)
 
 testsuite-distclean:
 	$(RM) -r $(ROOTFS)
diff --git a/testsuite/.gitignore b/testsuite/.gitignore
index 5465b1a..56d628e 100644
--- a/testsuite/.gitignore
+++ b/testsuite/.gitignore
@@ -18,6 +18,7 @@ 
 /test-modprobe
 /test-hash
 /test-list
+/test-user
 /rootfs
 /stamp-rootfs
 /test-scratchbuf.log
@@ -52,3 +53,5 @@ 
 /test-testsuite.trs
 /test-list.log
 /test-list.trs
+/test-user.log
+/test-user.trs
diff --git a/testsuite/module-playground/Makefile b/testsuite/module-playground/Makefile
index a7ab09b..42c750b 100644
--- a/testsuite/module-playground/Makefile
+++ b/testsuite/module-playground/Makefile
@@ -37,6 +37,8 @@  obj-m += mod-fake-hpsa.o
 obj-m += mod-fake-scsi-mod.o
 obj-m += mod-fake-cciss.o
 
+obj-m += mod-weakdep.o
+
 else
 # only build ARCH-specific module
 ifeq ($(ARCH),)
diff --git a/testsuite/module-playground/mod-weakdep.c b/testsuite/module-playground/mod-weakdep.c
new file mode 100644
index 0000000..d8a9d48
--- /dev/null
+++ b/testsuite/module-playground/mod-weakdep.c
@@ -0,0 +1,15 @@ 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/module.h>
+
+static int __init weakdep_init(void)
+{
+	return 0;
+}
+
+module_init(weakdep_init);
+
+MODULE_AUTHOR("Jose Ignacio Tornos Martinez <jtornosm@redhat.com>");
+MODULE_LICENSE("LGPL");
+MODULE_WEAKDEP("mod-simple");
diff --git a/testsuite/rootfs-pristine/test-depmod/check-weakdep/lib/modules/4.4.4/correct-modules.weakdep b/testsuite/rootfs-pristine/test-depmod/check-weakdep/lib/modules/4.4.4/correct-modules.weakdep
new file mode 100644
index 0000000..00777b8
--- /dev/null
+++ b/testsuite/rootfs-pristine/test-depmod/check-weakdep/lib/modules/4.4.4/correct-modules.weakdep
@@ -0,0 +1,2 @@ 
+# Weak dependencies extracted from modules themselves.
+weakdep mod_weakdep mod-simple
diff --git a/testsuite/rootfs-pristine/test-modprobe/weakdep-loop/etc/modprobe.d/dumb-weakdep.conf b/testsuite/rootfs-pristine/test-modprobe/weakdep-loop/etc/modprobe.d/dumb-weakdep.conf
new file mode 100644
index 0000000..181714a
--- /dev/null
+++ b/testsuite/rootfs-pristine/test-modprobe/weakdep-loop/etc/modprobe.d/dumb-weakdep.conf
@@ -0,0 +1 @@ 
+weakdep mod-loop-b mod-loop-a mod-simple
diff --git a/testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.alias b/testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.alias
new file mode 100644
index 0000000..ba76e18
--- /dev/null
+++ b/testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.alias
@@ -0,0 +1 @@ 
+# Aliases extracted from modules themselves.
diff --git a/testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.alias.bin b/testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.alias.bin
new file mode 100644
index 0000000000000000000000000000000000000000..7075435f6268c4d815aec093d61e26647666ba76
GIT binary patch
literal 12
TcmdnM{w17&iGh)Ufq@4A6;A>Z

literal 0
HcmV?d00001

diff --git a/testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.builtin.alias.bin b/testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.builtin.alias.bin
new file mode 100644
index 0000000..e69de29
diff --git a/testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.builtin.bin b/testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.builtin.bin
new file mode 100644
index 0000000..e69de29
diff --git a/testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.dep b/testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.dep
new file mode 100644
index 0000000..9207182
--- /dev/null
+++ b/testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.dep
@@ -0,0 +1,3 @@ 
+kernel/mod-loop-b.ko:
+kernel/mod-loop-a.ko:
+kernel/mod-simple.ko:
diff --git a/testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.dep.bin b/testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.dep.bin
new file mode 100644
index 0000000000000000000000000000000000000000..418d5839a88c95cb08ed24e128ffdb8717ca1504
GIT binary patch
literal 188
zcmdnM{w17&iGfjpfngg10|O%vGi9e1<)!B6=jNyA=H%xW=qBoA=UXYDizWd@fvUk;
z7_muOF#t8kGbAQCFfi}{v3+K4K~5@A2UrUOl9pny49FIS{FHcxoZ<xx46z`E*uVh>
MhMe5o1q=)m03nerJ^%m!

literal 0
HcmV?d00001

diff --git a/testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.devname b/testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.devname
new file mode 100644
index 0000000..58f6d6d
--- /dev/null
+++ b/testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.devname
@@ -0,0 +1 @@ 
+# Device nodes to trigger on-demand module loading.
diff --git a/testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.softdep b/testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.softdep
new file mode 100644
index 0000000..5554ccc
--- /dev/null
+++ b/testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.softdep
@@ -0,0 +1 @@ 
+# Soft dependencies extracted from modules themselves.
diff --git a/testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.symbols b/testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.symbols
new file mode 100644
index 0000000..6c53580
--- /dev/null
+++ b/testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.symbols
@@ -0,0 +1,3 @@ 
+# Aliases for symbols, used by symbol_request().
+alias symbol:printB mod_loop_b
+alias symbol:printA mod_loop_a
diff --git a/testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.symbols.bin b/testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.symbols.bin
new file mode 100644
index 0000000000000000000000000000000000000000..27c5f4330c93722f6bab5c7a91601ab58fdda577
GIT binary patch
literal 78
zcmdnM{w17&iGfjpfx&};fq@Z-nR4?};&bxz3*r-jJg^WWTqud5GB+td$Eu(xGp~ff
T(aC{<fd`1?i;EX9Fc<*<pZgLP

literal 0
HcmV?d00001

diff --git a/testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.weakdep b/testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.weakdep
new file mode 100644
index 0000000..569696d
--- /dev/null
+++ b/testsuite/rootfs-pristine/test-modprobe/weakdep-loop/lib/modules/4.4.4/modules.weakdep
@@ -0,0 +1 @@ 
+# Weak dependencies extracted from modules themselves.
diff --git a/testsuite/rootfs-pristine/test-user/correct-weakdep.txt b/testsuite/rootfs-pristine/test-user/correct-weakdep.txt
new file mode 100644
index 0000000..ac09f8d
--- /dev/null
+++ b/testsuite/rootfs-pristine/test-user/correct-weakdep.txt
@@ -0,0 +1,2 @@ 
+mod-loop-b: mod_loop_a mod_simple
+mod-weakdep: mod_simple
diff --git a/testsuite/rootfs-pristine/test-user/etc/modprobe.d/dumb-weakdep.conf b/testsuite/rootfs-pristine/test-user/etc/modprobe.d/dumb-weakdep.conf
new file mode 100644
index 0000000..181714a
--- /dev/null
+++ b/testsuite/rootfs-pristine/test-user/etc/modprobe.d/dumb-weakdep.conf
@@ -0,0 +1 @@ 
+weakdep mod-loop-b mod-loop-a mod-simple
diff --git a/testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.alias b/testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.alias
new file mode 100644
index 0000000..ba76e18
--- /dev/null
+++ b/testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.alias
@@ -0,0 +1 @@ 
+# Aliases extracted from modules themselves.
diff --git a/testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.alias.bin b/testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.alias.bin
new file mode 100644
index 0000000000000000000000000000000000000000..7075435f6268c4d815aec093d61e26647666ba76
GIT binary patch
literal 12
TcmdnM{w17&iGh)Ufq@4A6;A>Z

literal 0
HcmV?d00001

diff --git a/testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.builtin.alias.bin b/testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.builtin.alias.bin
new file mode 100644
index 0000000..e69de29
diff --git a/testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.builtin.bin b/testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.builtin.bin
new file mode 100644
index 0000000..e69de29
diff --git a/testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.dep b/testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.dep
new file mode 100644
index 0000000..3ffbd6b
--- /dev/null
+++ b/testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.dep
@@ -0,0 +1,4 @@ 
+kernel/mod-weakdep.ko:
+kernel/mod-simple.ko:
+kernel/mod-loop-b.ko:
+kernel/mod-loop-a.ko: kernel/mod-loop-b.ko
diff --git a/testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.dep.bin b/testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.dep.bin
new file mode 100644
index 0000000000000000000000000000000000000000..70a6e76b79f9a74037dcb00b69fe2555cf022a51
GIT binary patch
literal 242
zcmdnM{w17&iGfjpf#D4U0|O%vGiRq3<)!B6=jNyA=H%xW=qBoA=UXYDizWd@fvUk;
zn6OD&F#t8kGbAQCFfi}{v3+K4K~5@A2UrUul9pny49FIS)WqzR)B>0y1|&u05Gk;#
h{FHcxobm+>46z`U*uVh>h8$#ZAb&z`?g9peZ2%o<Ih+6h

literal 0
HcmV?d00001

diff --git a/testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.devname b/testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.devname
new file mode 100644
index 0000000..e69de29
diff --git a/testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.softdep b/testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.softdep
new file mode 100644
index 0000000..5554ccc
--- /dev/null
+++ b/testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.softdep
@@ -0,0 +1 @@ 
+# Soft dependencies extracted from modules themselves.
diff --git a/testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.symbols b/testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.symbols
new file mode 100644
index 0000000..6c53580
--- /dev/null
+++ b/testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.symbols
@@ -0,0 +1,3 @@ 
+# Aliases for symbols, used by symbol_request().
+alias symbol:printB mod_loop_b
+alias symbol:printA mod_loop_a
diff --git a/testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.symbols.bin b/testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.symbols.bin
new file mode 100644
index 0000000000000000000000000000000000000000..8683b6cb7f60e035be224d97cd560a822e269b1f
GIT binary patch
literal 78
zcmdnM{w17&iGfjpfx&};fq@Z-nRD|~;&bxz3*r-jJg^WGTqud5GB+td$Eu(xGp~ff
T(aC{<fd`1?i;EX9Fc<*<pk5Lf

literal 0
HcmV?d00001

diff --git a/testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.weakdep b/testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.weakdep
new file mode 100644
index 0000000..00777b8
--- /dev/null
+++ b/testsuite/rootfs-pristine/test-user/lib/modules/4.4.4/modules.weakdep
@@ -0,0 +1,2 @@ 
+# Weak dependencies extracted from modules themselves.
+weakdep mod_weakdep mod-simple
diff --git a/testsuite/setup-rootfs.sh b/testsuite/setup-rootfs.sh
index 5477c69..f57ef19 100755
--- a/testsuite/setup-rootfs.sh
+++ b/testsuite/setup-rootfs.sh
@@ -68,6 +68,8 @@  map=(
     ["test-depmod/search-order-external-last/lib/modules/external/"]="mod-simple.ko"
     ["test-depmod/search-order-override$MODULE_DIRECTORY/4.4.4/foo/"]="mod-simple.ko"
     ["test-depmod/search-order-override$MODULE_DIRECTORY/4.4.4/override/"]="mod-simple.ko"
+    ["test-depmod/check-weakdep$MODULE_DIRECTORY/4.4.4/kernel/mod-weakdep.ko"]="mod-weakdep.ko"
+    ["test-depmod/check-weakdep$MODULE_DIRECTORY/4.4.4/kernel/mod-simple.ko"]="mod-simple.ko"
     ["test-dependencies$MODULE_DIRECTORY/4.0.20-kmod/kernel/fs/foo/"]="mod-foo-b.ko"
     ["test-dependencies$MODULE_DIRECTORY/4.0.20-kmod/kernel/"]="mod-foo-c.ko"
     ["test-dependencies$MODULE_DIRECTORY/4.0.20-kmod/kernel/lib/"]="mod-foo-a.ko"
@@ -80,6 +82,9 @@  map=(
     ["test-modprobe/show-exports/mod-loop-a.ko"]="mod-loop-a.ko"
     ["test-modprobe/softdep-loop$MODULE_DIRECTORY/4.4.4/kernel/mod-loop-a.ko"]="mod-loop-a.ko"
     ["test-modprobe/softdep-loop$MODULE_DIRECTORY/4.4.4/kernel/mod-loop-b.ko"]="mod-loop-b.ko"
+    ["test-modprobe/weakdep-loop$MODULE_DIRECTORY/4.4.4/kernel/mod-loop-a.ko"]="mod-loop-a.ko"
+    ["test-modprobe/weakdep-loop$MODULE_DIRECTORY/4.4.4/kernel/mod-loop-b.ko"]="mod-loop-b.ko"
+    ["test-modprobe/weakdep-loop$MODULE_DIRECTORY/4.4.4/kernel/mod-simple.ko"]="mod-simple.ko"
     ["test-modprobe/install-cmd-loop$MODULE_DIRECTORY/4.4.4/kernel/mod-loop-a.ko"]="mod-loop-a.ko"
     ["test-modprobe/install-cmd-loop$MODULE_DIRECTORY/4.4.4/kernel/mod-loop-b.ko"]="mod-loop-b.ko"
     ["test-modprobe/force$MODULE_DIRECTORY/4.4.4/kernel/"]="mod-simple.ko"
@@ -103,6 +108,10 @@  map=(
     ["test-modinfo/mod-simple-sha256.ko"]="mod-simple.ko"
     ["test-modinfo/mod-simple-pkcs7.ko"]="mod-simple.ko"
     ["test-modinfo/external/lib/modules/external/mod-simple.ko"]="mod-simple.ko"
+    ["test-user$MODULE_DIRECTORY/4.4.4/kernel/mod-loop-a.ko"]="mod-loop-a.ko"
+    ["test-user$MODULE_DIRECTORY/4.4.4/kernel/mod-loop-b.ko"]="mod-loop-b.ko"
+    ["test-user$MODULE_DIRECTORY/4.4.4/kernel/mod-simple.ko"]="mod-simple.ko"
+    ["test-user$MODULE_DIRECTORY/4.4.4/kernel/mod-weakdep.ko"]="mod-weakdep.ko"
 )
 
 gzip_array=(
diff --git a/testsuite/test-depmod.c b/testsuite/test-depmod.c
index c96dbf0..eaa5b1a 100644
--- a/testsuite/test-depmod.c
+++ b/testsuite/test-depmod.c
@@ -244,4 +244,31 @@  DEFINE_TEST(depmod_search_order_override,
 		},
 	});
 
+#define CHECK_WEAKDEP_ROOTFS TESTSUITE_ROOTFS "test-depmod/check-weakdep"
+#define CHECK_WEAKDEP_LIB_MODULES CHECK_WEAKDEP_ROOTFS MODULE_DIRECTORY "/" MODULES_UNAME
+static noreturn int depmod_check_weakdep(const struct test *t)
+{
+	const char *progname = ABS_TOP_BUILDDIR "/tools/depmod";
+	const char *const args[] = {
+		progname,
+		NULL,
+	};
+
+	test_spawn_prog(progname, args);
+	exit(EXIT_FAILURE);
+}
+DEFINE_TEST(depmod_check_weakdep,
+	.description = "check weakdep output",
+	.config = {
+		[TC_UNAME_R] = MODULES_UNAME,
+		[TC_ROOTFS] = CHECK_WEAKDEP_ROOTFS,
+	},
+	.output = {
+		.files = (const struct keyval[]) {
+			{ CHECK_WEAKDEP_LIB_MODULES "/correct-modules.weakdep",
+			  CHECK_WEAKDEP_LIB_MODULES "/modules.weakdep" },
+			{ }
+		},
+	});
+
 TESTSUITE_MAIN();
diff --git a/testsuite/test-modprobe.c b/testsuite/test-modprobe.c
index 309f3e3..6a824c9 100644
--- a/testsuite/test-modprobe.c
+++ b/testsuite/test-modprobe.c
@@ -181,6 +181,29 @@  DEFINE_TEST(modprobe_softdep_loop,
 	.modules_loaded = "mod-loop-a,mod-loop-b",
 	);
 
+static noreturn int modprobe_weakdep_loop(const struct test *t)
+{
+	const char *progname = ABS_TOP_BUILDDIR "/tools/modprobe";
+	const char *const args[] = {
+		progname,
+		"mod-loop-b",
+		NULL,
+	};
+
+	test_spawn_prog(progname, args);
+	exit(EXIT_FAILURE);
+}
+DEFINE_TEST(modprobe_weakdep_loop,
+	.description = "check if modprobe breaks weakdep loop",
+	.config = {
+		[TC_UNAME_R] = "4.4.4",
+		[TC_ROOTFS] = TESTSUITE_ROOTFS "test-modprobe/weakdep-loop",
+		[TC_INIT_MODULE_RETCODES] = "",
+	},
+	.modules_loaded = "mod-loop-b",
+	.modules_not_loaded = "mod-loop-a,mod-simple-c",
+	);
+
 static noreturn int modprobe_install_cmd_loop(const struct test *t)
 {
 	const char *progname = ABS_TOP_BUILDDIR "/tools/modprobe";
diff --git a/testsuite/test-user.c b/testsuite/test-user.c
new file mode 100644
index 0000000..f2b789a
--- /dev/null
+++ b/testsuite/test-user.c
@@ -0,0 +1,110 @@ 
+/*
+ * Copyright Red Hat
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <libkmod/libkmod.h>
+
+#include "testsuite.h"
+
+#define TEST_USER_ROOTFS TESTSUITE_ROOTFS "test-user/"
+#define TEST_USER_KERNEL_DIR TEST_USER_ROOTFS "lib/modules/4.4.4/"
+
+static const char *const test_user_config_paths[] = {
+        TEST_USER_ROOTFS "etc/modprobe.d",
+        NULL
+};
+
+static const char *const mod_name[] = {
+	"mod-loop-b",
+	"mod-weakdep",
+	NULL
+};
+
+static int test_user_weakdep(const struct test *t)
+{
+	struct kmod_ctx *ctx;
+	int mod_name_index = 0;
+	int err;
+
+	ctx = kmod_new(TEST_USER_KERNEL_DIR, test_user_config_paths);
+	if (ctx == NULL)
+		exit(EXIT_FAILURE);
+
+	while(mod_name[mod_name_index]) {
+		struct kmod_list *list = NULL;
+		struct kmod_module *mod = NULL;
+		struct kmod_list *mod_list = NULL;
+		struct kmod_list *itr = NULL;
+
+		printf("%s:", mod_name[mod_name_index]);
+		err = kmod_module_new_from_lookup(ctx, mod_name[mod_name_index], &list);
+		if (list == NULL || err < 0) {
+			fprintf(stderr, "module %s not found in directory %s\n",
+				mod_name[mod_name_index],
+				ctx ? kmod_get_dirname(ctx) : "(missing)");
+			exit(EXIT_FAILURE);
+		}
+
+		mod = kmod_module_get_module(list);
+
+		err = kmod_module_get_weakdeps(mod, &mod_list);
+		if (err) {
+			fprintf(stderr, "weak dependencies can not be read for %s (%d)\n",
+				mod_name[mod_name_index], err);
+			exit(EXIT_FAILURE);
+		}
+
+		kmod_list_foreach(itr, mod_list) {
+			struct kmod_module *weakdep_mod = kmod_module_get_module(itr);
+			const char *weakdep_name = kmod_module_get_name(weakdep_mod);
+
+			printf(" %s", weakdep_name);
+			kmod_module_unref(weakdep_mod);
+		}
+		printf("\n");
+
+		kmod_module_unref_list(mod_list);
+		kmod_module_unref(mod);
+		kmod_module_unref_list(list);
+
+		mod_name_index++;
+	}
+
+	kmod_unref(ctx);
+
+        return EXIT_SUCCESS;
+}
+DEFINE_TEST(test_user_weakdep,
+        .description = "check if modprobe breaks weakdep2",
+        .config = {
+                [TC_UNAME_R] = "4.4.4",
+                [TC_ROOTFS] = TESTSUITE_ROOTFS "test-user",
+                [TC_INIT_MODULE_RETCODES] = "",
+        },
+	.need_spawn = true,
+	.output = {
+		.out = TESTSUITE_ROOTFS "test-user/correct-weakdep.txt",
+	});
+
+TESTSUITE_MAIN();
diff --git a/testsuite/testsuite.c b/testsuite/testsuite.c
index 318343a..3198524 100644
--- a/testsuite/testsuite.c
+++ b/testsuite/testsuite.c
@@ -772,10 +772,10 @@  static int cmp_modnames(const void *m1, const void *m2)
 }
 
 /*
- * Store the expected module names in buf and return a list of pointers to
- * them.
+ * Auxiliary function to store the module names in buf and return a list
+ * of pointers to them.
  */
-static const char **read_expected_modules(const struct test *t,
+static const char **read_modules(const char* modules,
 		char **buf, int *count)
 {
 	const char **res;
@@ -783,12 +783,8 @@  static const char **read_expected_modules(const struct test *t,
 	int i;
 	char *p;
 
-	if (t->modules_loaded[0] == '\0') {
-		*count = 0;
-		*buf = NULL;
-		return NULL;
-	}
-	*buf = strdup(t->modules_loaded);
+
+	*buf = strdup(modules);
 	if (!*buf) {
 		*count = -1;
 		return NULL;
@@ -816,6 +812,36 @@  static const char **read_expected_modules(const struct test *t,
 	return res;
 }
 
+/*
+ * Store the expected module names in buf and return a list of pointers to
+ * them.
+ */
+static const char **read_expected_modules(const struct test *t,
+		char **buf, int *count)
+{
+	if (t->modules_loaded[0] == '\0') {
+		*count = 0;
+		*buf = NULL;
+		return NULL;
+	}
+	return read_modules(t->modules_loaded, buf, count);
+}
+
+/*
+ * Store the unexpected module names in buf and return a list of pointers to
+ * them.
+ */
+static const char **read_unexpected_modules(const struct test *t,
+		char **buf, int *count)
+{
+	if (t->modules_not_loaded[0] == '\0') {
+		*count = 0;
+		*buf = NULL;
+		return NULL;
+	}
+	return read_modules(t->modules_not_loaded, buf, count);
+}
+
 static char **read_loaded_modules(const struct test *t, char **buf, int *count)
 {
 	char dirname[PATH_MAX];
@@ -930,6 +956,54 @@  out_a1:
 	return err;
 }
 
+static int check_not_loaded_modules(const struct test *t)
+{
+	int l1, l2, i1, i2;
+	const char **a1;
+	char **a2;
+	char *buf1, *buf2;
+	int err = false;
+
+	a1 = read_unexpected_modules(t, &buf1, &l1);
+	if (l1 < 0)
+		return err;
+	a2 = read_loaded_modules(t, &buf2, &l2);
+	if (l2 < 0)
+		goto out_a1;
+	qsort(a1, l1, sizeof(char *), cmp_modnames);
+	qsort(a2, l2, sizeof(char *), cmp_modnames);
+	i1 = i2 = 0;
+	err = true;
+	while (i1 < l1 || i2 < l2) {
+		int cmp;
+
+		if (i1 >= l1)
+			cmp = 1;
+		else if (i2 >= l2)
+			cmp = -1;
+		else
+			cmp = cmp_modnames(&a1[i1], &a2[i2]);
+		if (cmp == 0) {
+			err = false;
+			ERR("module %s loaded\n", a1[i1]);
+			i1++;
+		} else if (cmp < 0) {
+			i1++;
+			i2++;
+		} else  {
+			err = false;
+			ERR("module %s is loaded but should not be\n", a2[i2]);
+			i2++;
+		}
+	}
+	free(a2);
+	free(buf2);
+out_a1:
+	free(a1);
+	free(buf1);
+	return err;
+}
+
 static inline int test_run_parent(const struct test *t, int fdout[2],
 				int fderr[2], int fdmonitor[2], pid_t child)
 {
@@ -994,6 +1068,8 @@  static inline int test_run_parent(const struct test *t, int fdout[2],
 		match_modules = check_loaded_modules(t);
 	else
 		match_modules = true;
+	if (match_modules && t->modules_not_loaded)
+		match_modules = check_not_loaded_modules(t);
 
 	if (t->expected_fail == false) {
 		if (err == 0) {
diff --git a/testsuite/testsuite.h b/testsuite/testsuite.h
index 44d1730..4b2565c 100644
--- a/testsuite/testsuite.h
+++ b/testsuite/testsuite.h
@@ -103,6 +103,7 @@  struct test {
 	} output;
 	/* comma-separated list of loaded modules at the end of the test */
 	const char *modules_loaded;
+	const char *modules_not_loaded;
 	testfunc func;
 	const char *config[_TC_LAST];
 	const char *path;