diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 423807f40cad15b787004db891f0ea19cdcd5997..a3240a084f5f4374c38470467d51462e4d6bf905 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,104 +1,6 @@
-stages:
-  - approve
-  - test
-
-approve1:
-  stage: approve
-  script:
-    - echo "Approved..."
-  rules:
-    # TODO: Filter only safe repositories, or user in developers
-    - if: $CI_PROJECT_PATH != "csonto/lvm2" && $CI_PROJECT_PATH != "lvmteam/lvm2"
-      when: manual
-    # TODO: for other branches than main/rhel: run pipeline only when requested:
-    - if: $CI_COMMIT_BRANCH != "main" && $CI_COMMIT_BRANCH !~ "^rhel.*"
-      when: manual
-    - when: on_success
-  allow_failure: false
-
-
-pages:
-  image: elecnix/ikiwiki
-  stage: test
-  script:
-    - ikiwiki --setup ikiwiki.setup --libdir themes/ikistrap/lib
-  artifacts:
-    paths:
-      - public
-  only:
-    refs:
-      - main
-    changes:
-      - doc/**/*
-      - ikiwiki.setup
-
-
-# TODO:
-# - check results of autoreconf and make generate - may need additional commit
-#     - we need a particular setup (rawhide OR latest supported fedora?)
-# - do make rpm and publish results as artifacts - we will use packit/COPR for this eventually
-
-# Run on any commits to main (master), rhel8, rhel9 branches
-test-job:
-  stage: test
-  parallel:
-    matrix:
-      - TAG: rhel8
-        CONFIGURE: >
-          --with-cluster=internal
-          --enable-cmirrord
-      - TAG: rhel9
-        CONFIGURE: >
-          --with-default-use-devices-file=1
-          --enable-app-machineid
-          --enable-editline
-          --disable-readline
-  artifacts:
-    paths:
-      - test/results/
-    expire_in: 1 week
-  tags:
-      - ${TAG}
-  timeout: 2h
-  script:
-    # Common options go here, diffs to the above matrix
-    - >
-      ./configure ${CONFIGURE}
-      --enable-fsadm
-      --enable-write_install
-      --enable-pkgconfig
-      --enable-cmdlib
-      --enable-dmeventd
-      --enable-blkid_wiping
-      --enable-udev_sync
-      --with-thin=internal
-      --with-cache=internal
-      --enable-lvmpolld
-      --enable-lvmlockd-dlm --enable-lvmlockd-dlmcontrol
-      --enable-lvmlockd-sanlock
-      --enable-dbus-service --enable-notify-dbus
-      --enable-dmfilemapd
-      --with-writecache=internal
-      --with-vdo=internal --with-vdo-format=/usr/bin/vdoformat
-      --with-integrity=internal
-      --disable-silent-rules
-    - make
-    - rm -rf test/results
-    - mkdir -p /dev/shm/lvm2-test
-    - mount -o remount,dev /dev/shm
-    # TODO: Need to distinguish failed test from failed harness
-    # TODO: Also need a way to find if run is incomplete, e.g. full disk resulting in many skipped tests
-    - VERBOSE=0 BATCH=1 LVM_TEST_DIR=/dev/shm/lvm2-test make check || true
-    - rm -rf /dev/shm/lvm2-test
-    - cut -d' ' -f2 test/results/list | sort | uniq -c
-    # Filter artifacts - keep only logs from tests which are not pass
-    - cd test/results && rm $(grep 'passed$' list | cut -d' ' -f1 | sed -e 's|/|_|g' -e 's|.*|\0.txt|')
-    # TODO: Keep a list of known failures, and translate into regexp - or simply use python...
-    - if grep failed test/results/list | grep -v '\\\(dbustest\|lvconvert-mirror\)\.sh' | sort; then false; else true; fi
-  rules:
-    # Filter only safe repositories, or user in developers:
-    # NOTE: Already done in approve stage, may be more caution than necessary
-    - if: $CI_PROJECT_PATH != "csonto/lvm2" && $CI_PROJECT_PATH != "lvmteam/lvm2"
-      when: manual
-    - when: on_success
-
+include:
+- local: debian/pipeline/workflow.yml
+- local: debian/pipeline/variables.yml
+- local: debian/pipeline/source.yml
+- local: debian/pipeline/build.yml
+- local: debian/pipeline/test.yml
diff --git a/configure.ac b/configure.ac
index e5e5e71ce1bf8df56b62b284490c167d4b1b594a..121d2b61b200299b606aa85368d10d993e36ac55 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1742,11 +1742,7 @@ AS_IF([test "$BUILD_DMFILEMAPD" = "yes"], [
 ])
 
 ################################################################################
-AC_PATH_TOOL(MODPROBE_CMD, modprobe, [], [$PATH_SBIN])
-
-AS_IF([test -n "$MODPROBE_CMD"], [
-	AC_DEFINE_UNQUOTED([MODPROBE_CMD], ["$MODPROBE_CMD"], [The path to 'modprobe', if available.])
-])
+AC_DEFINE_UNQUOTED([MODPROBE_CMD], ["/sbin/modprobe"], [The path to 'modprobe', if available.])
 
 SYSCONFDIR="$(eval echo $(eval echo $sysconfdir))"
 
diff --git a/daemons/dmeventd/.exported_symbols b/daemons/dmeventd/.exported_symbols
index fab74dc1d6f3dd8e740a3806d8424855bb399df6..46c14fb5ae4935104891f41e2cd626078baf22f9 100644
--- a/daemons/dmeventd/.exported_symbols
+++ b/daemons/dmeventd/.exported_symbols
@@ -1,4 +1,4 @@
-init_fifos
-fini_fifos
-daemon_talk
+dm_event_daemon_init_fifos
+dm_event_daemon_fini_fifos
+dm_event_daemon_talk
 dm_event_get_version
diff --git a/daemons/dmeventd/dmeventd.c b/daemons/dmeventd/dmeventd.c
index b823a0476e267db1b40579051c19866b37434fce..97249515ce5bb8e5a60e4605d281fef6fa156648 100644
--- a/daemons/dmeventd/dmeventd.c
+++ b/daemons/dmeventd/dmeventd.c
@@ -2025,7 +2025,7 @@ static int _reinstate_registrations(struct dm_event_fifos *fifos)
 	unsigned long mask_value, timeout_value;
 	int i, ret;
 
-	ret = daemon_talk(fifos, &msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0);
+	ret = dm_event_daemon_talk(fifos, &msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0);
 	free(msg.data);
 	msg.data = NULL;
 
@@ -2058,7 +2058,7 @@ static int _reinstate_registrations(struct dm_event_fifos *fifos)
 			continue;
 		}
 
-		if (daemon_talk(fifos, &msg, DM_EVENT_CMD_REGISTER_FOR_EVENT,
+		if (dm_event_daemon_talk(fifos, &msg, DM_EVENT_CMD_REGISTER_FOR_EVENT,
 				dso_name,
 				dev_name,
 				(enum dm_event_mask) mask_value,
@@ -2083,7 +2083,7 @@ static int _info_dmeventd(const char *name, struct dm_event_fifos *fifos)
 	}
 
 	/* Get the list of registrations from the running daemon. */
-	if (!init_fifos(fifos)) {
+	if (!dm_event_daemon_init_fifos(fifos)) {
 		fprintf(stderr, "Could not initiate communication with existing dmeventd.\n");
 		return 0;
 	}
@@ -2099,7 +2099,7 @@ static int _info_dmeventd(const char *name, struct dm_event_fifos *fifos)
 		goto out;
 	}
 
-	if (daemon_talk(fifos, &msg, DM_EVENT_CMD_GET_STATUS, "-", "-", 0, 0)) {
+	if (dm_event_daemon_talk(fifos, &msg, DM_EVENT_CMD_GET_STATUS, "-", "-", 0, 0)) {
 		fprintf(stderr, "Failed to acquire status from existing dmeventd.\n");
 		goto out;
 	}
@@ -2121,7 +2121,7 @@ static int _info_dmeventd(const char *name, struct dm_event_fifos *fifos)
 		printf("%s does not monitor any device.\n", name);
 
 	if (version >= 2) {
-		if (daemon_talk(fifos, &msg, DM_EVENT_CMD_GET_PARAMETERS, "-", "-", 0, 0)) {
+		if (dm_event_daemon_talk(fifos, &msg, DM_EVENT_CMD_GET_PARAMETERS, "-", "-", 0, 0)) {
 			fprintf(stderr, "Failed to acquire parameters from existing dmeventd.\n");
 			goto out;
 		}
@@ -2131,7 +2131,7 @@ static int _info_dmeventd(const char *name, struct dm_event_fifos *fifos)
 
 	ret = 1;
 out:
-	fini_fifos(fifos);
+	dm_event_daemon_fini_fifos(fifos);
 
 	return ret;
 }
@@ -2151,7 +2151,7 @@ static int _restart_dmeventd(struct dm_event_fifos *fifos)
 	}
 
 	/* Get the list of registrations from the running daemon. */
-	if (!init_fifos(fifos)) {
+	if (!dm_event_daemon_init_fifos(fifos)) {
 		fprintf(stderr, "WARNING: Could not initiate communication with existing dmeventd.\n");
 		return 0;
 	}
@@ -2168,7 +2168,7 @@ static int _restart_dmeventd(struct dm_event_fifos *fifos)
 		goto bad;
 	}
 
-	if (daemon_talk(fifos, &msg, DM_EVENT_CMD_GET_STATUS, "-", "-", 0, 0))
+	if (dm_event_daemon_talk(fifos, &msg, DM_EVENT_CMD_GET_STATUS, "-", "-", 0, 0))
 		goto bad;
 
 	message = strchr(msg.data, ' ') + 1;
@@ -2192,7 +2192,7 @@ static int _restart_dmeventd(struct dm_event_fifos *fifos)
 	}
 
 	if (version >= 2) {
-		if (daemon_talk(fifos, &msg, DM_EVENT_CMD_GET_PARAMETERS, "-", "-", 0, 0)) {
+		if (dm_event_daemon_talk(fifos, &msg, DM_EVENT_CMD_GET_PARAMETERS, "-", "-", 0, 0)) {
 			fprintf(stderr, "Failed to acquire parameters from old dmeventd.\n");
 			goto bad;
 		}
@@ -2212,7 +2212,7 @@ static int _restart_dmeventd(struct dm_event_fifos *fifos)
 	}
 #endif
 
-	if (daemon_talk(fifos, &msg, DM_EVENT_CMD_DIE, "-", "-", 0, 0)) {
+	if (dm_event_daemon_talk(fifos, &msg, DM_EVENT_CMD_DIE, "-", "-", 0, 0)) {
 		fprintf(stderr, "Old dmeventd refused to die.\n");
 		goto bad;
 	}
@@ -2221,7 +2221,7 @@ static int _restart_dmeventd(struct dm_event_fifos *fifos)
 	    ((e = getenv(SD_ACTIVATION_ENV_VAR_NAME)) && strcmp(e, "1")))
 		_systemd_activation = 1;
 
-	fini_fifos(fifos);
+	dm_event_daemon_fini_fifos(fifos);
 
 	/* Give a few seconds dmeventd to finish */
 	_wait_for_new_pid();
@@ -2230,7 +2230,7 @@ static int _restart_dmeventd(struct dm_event_fifos *fifos)
 		return 2; // continue with dmeventd start up
 
 	/* Reopen fifos. */
-	if (!init_fifos(fifos)) {
+	if (!dm_event_daemon_init_fifos(fifos)) {
 		fprintf(stderr, "Could not initiate communication with new instance of dmeventd.\n");
 		return 0;
 	}
@@ -2240,10 +2240,10 @@ static int _restart_dmeventd(struct dm_event_fifos *fifos)
 		goto bad;
 	}
 
-	fini_fifos(fifos);
+	dm_event_daemon_fini_fifos(fifos);
 	return 1;
 bad:
-	fini_fifos(fifos);
+	dm_event_daemon_fini_fifos(fifos);
 	return 0;
 }
 
diff --git a/daemons/dmeventd/dmeventd.h b/daemons/dmeventd/dmeventd.h
index e8e22765e99b05846a6a94afaaa39ad355b56ba4..9d5253736560b31daaf5f01729b3f80d8f6e576d 100644
--- a/daemons/dmeventd/dmeventd.h
+++ b/daemons/dmeventd/dmeventd.h
@@ -67,12 +67,12 @@ struct dm_event_fifos {
 
 /* Implemented in libdevmapper-event.c, but not part of public API. */
 // FIXME  misuse of bitmask as enum
-int daemon_talk(struct dm_event_fifos *fifos,
+int dm_event_daemon_talk(struct dm_event_fifos *fifos,
 		struct dm_event_daemon_message *msg, int cmd,
 		const char *dso_name, const char *dev_name,
 		unsigned evmask, uint32_t timeout);
-int init_fifos(struct dm_event_fifos *fifos);
-void fini_fifos(struct dm_event_fifos *fifos);
+int dm_event_daemon_init_fifos(struct dm_event_fifos *fifos);
+void dm_event_daemon_fini_fifos(struct dm_event_fifos *fifos);
 int dm_event_get_version(struct dm_event_fifos *fifos, int *version);
 
 #endif /* __DMEVENTD_DOT_H__ */
diff --git a/daemons/dmeventd/libdevmapper-event.c b/daemons/dmeventd/libdevmapper-event.c
index 485f04605c3ae550b5282a6e89b1eadf7c2f2619..d46defde8b6a15364c0c1ccebbc07adbe4ac4201 100644
--- a/daemons/dmeventd/libdevmapper-event.c
+++ b/daemons/dmeventd/libdevmapper-event.c
@@ -349,7 +349,7 @@ static int _daemon_write(struct dm_event_fifos *fifos,
 	return bytes == size;
 }
 
-int daemon_talk(struct dm_event_fifos *fifos,
+int dm_event_daemon_talk(struct dm_event_fifos *fifos,
 		struct dm_event_daemon_message *msg, int cmd,
 		const char *dso_name, const char *dev_name,
 		unsigned evmask, uint32_t timeout)
@@ -528,7 +528,7 @@ static int _start_daemon(char *dmeventd_path, struct dm_event_fifos *fifos)
 	return ret;
 }
 
-int init_fifos(struct dm_event_fifos *fifos)
+int dm_event_daemon_init_fifos(struct dm_event_fifos *fifos)
 {
 	/* FIXME? Is fifo the most suitable method? Why not share
 	   comms/daemon code with something else e.g. multipath? */
@@ -569,10 +569,10 @@ static int _init_client(char *dmeventd_path, struct dm_event_fifos *fifos)
 	if (!_start_daemon(dmeventd_path, fifos))
 		return_0;
 
-	return init_fifos(fifos);
+	return dm_event_daemon_init_fifos(fifos);
 }
 
-void fini_fifos(struct dm_event_fifos *fifos)
+void dm_event_daemon_fini_fifos(struct dm_event_fifos *fifos)
 {
 	if (fifos->client >= 0 && close(fifos->client))
 		log_sys_debug("close", fifos->client_path);
@@ -661,16 +661,16 @@ static int _do_event(int cmd, char *dmeventd_path, struct dm_event_daemon_messag
 		goto_out;
 	}
 
-	ret = daemon_talk(&fifos, msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0);
+	ret = dm_event_daemon_talk(&fifos, msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0);
 
 	free(msg->data);
 	msg->data = 0;
 
 	if (!ret)
-		ret = daemon_talk(&fifos, msg, cmd, dso_name, dev_name, evmask, timeout);
+		ret = dm_event_daemon_talk(&fifos, msg, cmd, dso_name, dev_name, evmask, timeout);
 out:
 	/* what is the opposite of init? */
-	fini_fifos(&fifos);
+	dm_event_daemon_fini_fifos(&fifos);
 
 	return ret;
 }
@@ -880,7 +880,7 @@ int dm_event_get_version(struct dm_event_fifos *fifos, int *version) {
 	struct dm_event_daemon_message msg = { 0 };
 	int ret = 0;
 
-	if (daemon_talk(fifos, &msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0))
+	if (dm_event_daemon_talk(fifos, &msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0))
 		return 0;
 	p = msg.data;
 	*version = 0;
diff --git a/daemons/lvmdbusd/Makefile.in b/daemons/lvmdbusd/Makefile.in
index 08b061fb29707886b0bc113ee998aa8cabd66318..745a9fb0af12b00ff92f9d364ae0bf6f65ea65cb 100644
--- a/daemons/lvmdbusd/Makefile.in
+++ b/daemons/lvmdbusd/Makefile.in
@@ -58,8 +58,6 @@ install_lvmdbusd: $(LVMDBUSD)
 	$(Q) $(INSTALL_DIR) $(lvmdbusdir) $(lvmdbusdir)/__pycache__
 	$(Q) (cd $(srcdir); $(INSTALL_DATA) $(LVMDBUS_SRCDIR_FILES) $(lvmdbusdir))
 	$(Q) $(INSTALL_DATA) $(LVMDBUS_BUILDDIR_FILES) $(lvmdbusdir)
-	$(Q) PYTHON=$(PYTHON3) $(PYCOMPILE) --destdir "$(DESTDIR)" --basedir "$(lvmdbuspydir)" $(LVMDBUS_SRCDIR_FILES) $(LVMDBUS_BUILDDIR_FILES)
-	$(Q) $(CHMOD) 444 $(lvmdbusdir)/__pycache__/*.py[co]
 
 install_lvm2: install_lvmdbusd
 
diff --git a/make.tmpl.in b/make.tmpl.in
index a80aca167a07004a5945bb7a346872b1e1264162..5f3a804f3cf827ecb0fc5d1ae10b01449a92cd05 100644
--- a/make.tmpl.in
+++ b/make.tmpl.in
@@ -521,7 +521,7 @@ DEFS+=-D_FILE_OFFSET_BITS=64
 %.o: %.cpp $(DEPS)
 	$(SHOW) "    [CXX] $(<F)"
 	@mkdir -p $(@D)
-	$(Q) $(CXX) $(DEPFLAGS) -c $(INCLUDES) $(VALGRIND_CFLAGS) $(DEFS) $(DEFS_$@) $(WFLAGS) $(CXXFLAGS) $(CXXFLAGS_$@) $< -o $@
+	$(Q) $(CXX) $(DEPFLAGS) -c $(INCLUDES) $(VALGRIND_CFLAGS) $(DEFS) $(DEFS_$@) $(WFLAGS) $(CXXFLAGS) $(CXXFLAGS_$@) $(CPPFLAGS) $< -o $@
 
 %.pot: %.c $(DEPS)
 	$(SHOW) "    [CC] $(<F)"
diff --git a/udev/69-dm-lvm.rules.in b/udev/69-dm-lvm.rules.in
index f7a6eef8fa772f7bec37d375d954dc7daf1f672f..ce0ab8ca176695027283229f266d5810081fb391 100644
--- a/udev/69-dm-lvm.rules.in
+++ b/udev/69-dm-lvm.rules.in
@@ -85,8 +85,14 @@ LABEL="lvm_scan"
 # it's better suited to appearing in the journal.
 
 IMPORT{program}="(LVM_EXEC)/lvm pvscan --cache --listvg --checkcomplete --vgonline --autoactivation event --udevoutput --journal=output $env{DEVNAME}"
+TEST!="/run/systemd/system", GOTO="lvm_direct_vgchange"
+
 ENV{LVM_VG_NAME_COMPLETE}=="?*", RUN+="(SYSTEMDRUN) --no-block --property DefaultDependencies=no --unit lvm-activate-$env{LVM_VG_NAME_COMPLETE} (LVM_EXEC)/lvm vgchange -aay --autoactivation event $env{LVM_VG_NAME_COMPLETE}"
 GOTO="lvm_end"
 
+LABEL="lvm_direct_vgchange"
+ENV{LVM_VG_NAME_COMPLETE}=="?*", RUN+="(LVM_EXEC)/lvm vgchange -aay --autoactivation event $env{LVM_VG_NAME_COMPLETE}"
+GOTO="lvm_end"
+
 LABEL="lvm_end"
 
diff --git a/udev/Makefile.in b/udev/Makefile.in
index 166a4572ab7e7e5a8d9c0986abed0f409fe029a9..00d9e4f7e0b2e4954fbb13a2c1ebaac799899c47 100644
--- a/udev/Makefile.in
+++ b/udev/Makefile.in
@@ -17,8 +17,8 @@ top_builddir = @top_builddir@
 
 include $(top_builddir)/make.tmpl
 
-DM_RULES=10-dm.rules 13-dm-disk.rules 95-dm-notify.rules
-LVM_RULES=11-dm-lvm.rules 69-dm-lvm.rules
+DM_RULES=55-dm.rules 60-persistent-storage-dm.rules 95-dm-notify.rules
+LVM_RULES=56-lvm.rules 69-lvm.rules
 
 DM_DIR=$(shell $(AWK) '/^.define DM_DIR/ {print $$3}' $(top_srcdir)/libdm/misc/dm-ioctl.h)
 
@@ -46,6 +46,18 @@ endif
 %.rules: $(srcdir)/%.rules.in
 	$(Q) $(SED) -e "s+(DM_DIR)+$(DM_DIR)+;s+(SYSTEMDRUN)+$(SYSTEMDRUN)+;s+(BLKID_RULE)+$(BLKID_RULE)+;s+(DM_EXEC_RULE)+$(DM_EXEC_RULE)+;s+(DM_EXEC)+$(DM_EXEC)+;s+(LVM_EXEC_RULE)+$(LVM_EXEC_RULE)+;s+(LVM_EXEC)+$(LVM_EXEC)+;" $< >$@
 
+55-dm.rules: 10-dm.rules
+	ln -s $< $@
+
+56-lvm.rules: 11-dm-lvm.rules
+	ln -s $< $@
+
+60-persistent-storage-dm.rules: 13-dm-disk.rules
+	ln -s $< $@
+
+69-lvm.rules: 69-dm-lvm.rules
+	ln -s $< $@
+
 %_install: %.rules
 	$(SHOW) "    [INSTALL] $<"
 	$(Q) $(INSTALL_DATA) -D $< $(udevdir)/$(<F)
