All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/44] multipath-tools: devmapper API refactored
@ 2024-07-09 21:38 Martin Wilck
  2024-07-09 21:38 ` [PATCH 01/44] multipath-tools CI: more fixes for arm/v7 Martin Wilck
                   ` (44 more replies)
  0 siblings, 45 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:38 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

Patch 1-9 are generic cleanups, partly targeting the previously reported
issues with multipath-tools installation on NixOS by removing hard-coded
paths as much as possible.

Patch 10-16 are basic cleanups for the devmapper code.

Patch 17 is the heart of this patch set, introducing the function
libmp_mapinfo(), which is supposed to serve as general API for fetching
information about maps from libdevmapper. It can work with arbitrary
input for identifying a map, and produce any combination of desired
outputs, with the most lightweight (combination of) ioctls possible.
This part of the set removes some code that had been changed
in patch 10-16. This is sort of suboptimal, but IMO it improves
the readability of the set as  a whole.

Patch 18 adds unit tests for this function.

Patch 19-44 change the libmultipath code to use the new API everywhere,
and add some additional minor improvements and fixes.

The code is pushed to https://github.com/openSUSE/multipath-tools/tree/tip.

Comments and reviews welcome.

Martin Wilck (44):
  multipath-tools CI: more fixes for arm/v7
  multipath-tools CI: fix dmevents test for Debian Sid, arm/v7
  create-config.mk: use printf instead of /bin/echo
  multipathd.service.in: use @BINDIR@ instead of /sbin
  Makefile.inc: replace @BINDIR@ with $(TGTDIR)/$(bindir)
  kpartx.rules: use @BINDIR@ to locate kpartx
  multipath-tools: Remove hard-coded paths to executables
  multipath-tools: compile_commands.json fixes
  multipath-tools: .gitignore: ignore o.wrap files for CI helpers
  libmultipath: remove unused includes in devmapper.h
  libmultipath: use DM_DEVICE_INFO in dm_mapname()
  multipath-tools: don't call dm_task_no_open_count()
  libmpathutil: export cleanup_udev_device()
  libmpathutil: add cleanup_vector()
  libmultipath: add cleanup helpers for struct multipath
  libmultipath: add cleanup_dm_task(), and use it in devmapper.c
  libmultipath: add libmp_mapinfo()
  libmultipath tests: add tests for libmp_mapinfo()
  libmultipath: implement dm_get_info() and dm_map_present() with new
    API
  libmultipath: remove dm_get_prefixed_uuid()
  libmultipath: is_mpath_part(): improve parsing
  libmultipath: rename dm_get_uuid() -> dm_get_wwid()
  libmultipath: improve dm_get_wwid() return value logic
  libmultipath: reimplement dm_map_name() with new API
  libmultipath: reimplement dm_map_present_by_uuid()
  libmultipath: reimplement dm_get_opencount() with new API
  libmpathpersist: skip redundant dm_map_present() call
  libmultipath: implement dm_is_mpath() with new API
  libmultipath: implement dm_get_multipath() with new API
  libmultipath: use libmp_mapinfo() in _dm_flush_map()
  libmultipath: add is_mpath_uuid() helper
  libmultipath: add is_mpath_part_uuid() helper
  libmultipath: add dmp_errstr() helper
  libmultipath: use libmp_mapinfo() in do_foreach_partmaps()
  libmultipath: use libmp_pathinfo() in update_multipath_table()
  libmultipath: update mpp->dmi in update_multipath_table()
  libmultipath: drop extra call to dm_map_present() in domap()
  libmultipath: split off update_multipath_table__()
  multipath: implement check_usable_paths() with libmp_pathinfo()
  multipathd: implement add_map_without_path() with libmp_mapinfo()
  libmultipath: simplify dm_get_maps()
  llibmultipath: fix return code check for dm_is_suspended()
  libmpathpersist: use libmp_mapinfo() in get_mpvec()
  libmpathpersist: use mpp->alias in do_mpath_persistent_reserve_out()

 .gitignore                               |    4 +
 Makefile                                 |    4 +-
 Makefile.inc                             |   29 +-
 create-config.mk                         |    4 +-
 kpartx/Makefile                          |    4 +-
 kpartx/devmapper.c                       |   15 -
 kpartx/{kpartx.rules => kpartx.rules.in} |    2 +-
 kpartx/kpartx_id                         |    8 +-
 libmpathpersist/mpath_persist_int.c      |   85 +-
 libmpathutil/libmpathutil.version        |    5 +
 libmpathutil/util.c                      |    6 +
 libmpathutil/util.h                      |    3 +
 libmpathutil/vector.c                    |    6 +
 libmpathutil/vector.h                    |    1 +
 libmultipath/alias.c                     |    5 +-
 libmultipath/configure.c                 |   27 +-
 libmultipath/devmapper.c                 | 1020 ++++++++------------
 libmultipath/devmapper.h                 |  101 +-
 libmultipath/libmultipath.version        |   10 +-
 libmultipath/print.c                     |    6 -
 libmultipath/structs.c                   |   12 +
 libmultipath/structs.h                   |    2 +
 libmultipath/structs_vec.c               |   50 +-
 libmultipath/structs_vec.h               |    2 +
 libmultipath/valid.c                     |    2 +-
 libmultipath/wwids.c                     |    2 +-
 multipath/11-dm-mpath.rules.in           |    4 +-
 multipath/main.c                         |   60 +-
 multipath/multipath.rules.in             |    6 +-
 multipathd/dmevents.c                    |    6 +-
 multipathd/main.c                        |   71 +-
 multipathd/multipathd.service.in         |    4 +-
 multipathd/waiter.c                      |    2 -
 tests/Makefile                           |    5 +-
 tests/alias.c                            |   32 +-
 tests/dmevents.c                         |   34 +-
 tests/mapinfo.c                          | 1121 ++++++++++++++++++++++
 tests/valid.c                            |   10 +-
 tests/wrap64.h                           |    9 +-
 39 files changed, 1916 insertions(+), 863 deletions(-)
 rename kpartx/{kpartx.rules => kpartx.rules.in} (96%)
 create mode 100644 tests/mapinfo.c

-- 
2.45.2


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

* [PATCH 01/44] multipath-tools CI: more fixes for arm/v7
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
@ 2024-07-09 21:38 ` Martin Wilck
  2024-07-10  7:06   ` Martin Wilck
  2024-07-09 21:38 ` [PATCH 02/44] multipath-tools CI: fix dmevents test for Debian Sid, arm/v7 Martin Wilck
                   ` (43 subsequent siblings)
  44 siblings, 1 reply; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:38 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

The previous fix for the CI under arm/v7 was incomplete, and actually broke
the tests under openSUSE Tumbleweed. Closer examination showed that the issues
were caused by Debian's move to 64bit time_t on some 32 bit architectures [1][2].
This effort causes _TIME_BITS=64 to be set by gcc internally, and introduces
symbol redirections for libaio [3], on Debian with gcc 13 and newer only.

Fix the conditions for symbol remappings in wrap64.h.

[1] https://wiki.debian.org/ReleaseGoals/64bit-time
[2] https://salsa.debian.org/toolchain-team/gcc/-/commit/d82fb8a8ab7b84f61fb8290a2c3aa2e3f54e7b8a
[3] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1062218

Fixes: 6a7524a ("multipath-tools tests: fix CI failures on arm/v7 with glibc 2.37")
Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 tests/wrap64.h | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/tests/wrap64.h b/tests/wrap64.h
index 7e43420..890fae8 100644
--- a/tests/wrap64.h
+++ b/tests/wrap64.h
@@ -47,7 +47,8 @@
  * fcntl() needs special treatment; fcntl64() has been introduced in 2.28.
  * https://savannah.gnu.org/forum/forum.php?forum_id=9205
  */
-#if defined(__GLIBC__) && __GLIBC_PREREQ(2, 37) && defined(__arm__) && __ARM_ARCH == 7
+#if defined(__GLIBC__) && __GLIBC_PREREQ(2, 34) && __BITS_PER_LONG == 32 \
+	 && defined(_TIME_BITS) && _TIME_BITS == 64
 #define WRAP_FCNTL_NAME __fcntl_time64
 #elif defined(__GLIBC__) && __GLIBC_PREREQ(2, 28)
 #define WRAP_FCNTL_NAME WRAP_NAME(fcntl)
@@ -60,7 +61,8 @@
 /*
  * glibc 2.37 uses __ioctl_time64 for ioctl
  */
-#if defined(__GLIBC__) && __GLIBC_PREREQ(2, 37) && defined(__arm__) && __ARM_ARCH == 7
+#if defined(__GLIBC__) && __GLIBC_PREREQ(2, 34) && __BITS_PER_LONG == 32 \
+	 && defined(_TIME_BITS) && _TIME_BITS == 64
 #define WRAP_IOCTL_NAME __ioctl_time64
 #else
 #define WRAP_IOCTL_NAME ioctl
@@ -68,7 +70,8 @@
 #define WRAP_IOCTL CONCAT2(__wrap_, WRAP_IOCTL_NAME)
 #define REAL_IOCTL CONCAT2(__real_, WRAP_IOCTL_NAME)
 
-#if defined(__NR_io_pgetevents) && __BITS_PER_LONG == 32 && defined(_TIME_BITS) && _TIME_BITS == 64
+#if defined(__GLIBC__) && defined(LIBAIO_REDIRECT) && __BITS_PER_LONG == 32 \
+	&& defined(_TIME_BITS) && _TIME_BITS == 64
 #define WRAP_IO_GETEVENTS_NAME io_getevents_time64
 #else
 #define WRAP_IO_GETEVENTS_NAME io_getevents
-- 
2.45.2


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

* [PATCH 02/44] multipath-tools CI: fix dmevents test for Debian Sid, arm/v7
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
  2024-07-09 21:38 ` [PATCH 01/44] multipath-tools CI: more fixes for arm/v7 Martin Wilck
@ 2024-07-09 21:38 ` Martin Wilck
  2024-07-09 21:38 ` [PATCH 03/44] create-config.mk: use printf instead of /bin/echo Martin Wilck
                   ` (42 subsequent siblings)
  44 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:38 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

Same fix as in 6a7524a ("multipath-tools tests: fix CI failures on arm/v7 with
glibc 2.37").

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 tests/dmevents.c | 21 +++++++++------------
 1 file changed, 9 insertions(+), 12 deletions(-)

diff --git a/tests/dmevents.c b/tests/dmevents.c
index 395b16d..668e6d2 100644
--- a/tests/dmevents.c
+++ b/tests/dmevents.c
@@ -253,8 +253,9 @@ int __wrap_dm_geteventnr(const char *name)
 	return -1;
 }
 
-int __wrap_ioctl(int fd, unsigned long request, void *argp)
+int WRAP_IOCTL(int fd, unsigned long request, void *argp)
 {
+	condlog(1, "%s %ld", __func__, request);
 	assert_int_equal(fd, waiter->fd);
 	assert_int_equal(request, DM_DEV_ARM_POLL);
 	return mock_type(int);
@@ -675,7 +676,7 @@ static void test_dmevent_loop_bad1(void **state)
 		skip();
 
 	will_return(__wrap_poll, 1);
-	will_return(__wrap_ioctl, -1);
+	wrap_will_return(WRAP_IOCTL, -1);
 	assert_int_equal(dmevent_loop(), 1);
 	dev_evt = find_dmevents("foo");
 	assert_ptr_not_equal(dev_evt, NULL);
@@ -697,7 +698,7 @@ static void test_dmevent_loop_bad2(void **state)
 		skip();
 
 	will_return(__wrap_poll, 1);
-	will_return(__wrap_ioctl, 0);
+	wrap_will_return(WRAP_IOCTL, 0);
 	will_return(__wrap_libmp_dm_task_create, NULL);
 	assert_int_equal(dmevent_loop(), 1);
 	dev_evt = find_dmevents("foo");
@@ -721,9 +722,8 @@ static void test_dmevent_loop_good0(void **state)
 	remove_all_dm_device_events();
 	unwatch_all_dmevents();
 	will_return(__wrap_poll, 1);
-	will_return(__wrap_ioctl, 0);
+	wrap_will_return(WRAP_IOCTL, 0);
 	will_return(__wrap_libmp_dm_task_create, &data);
-	will_return(__wrap_dm_task_no_open_count, 1);
 	will_return(__wrap_dm_task_run, 1);
 	will_return(__wrap_dm_task_get_names, 1);
 	assert_int_equal(dmevent_loop(), 1);
@@ -757,9 +757,8 @@ static void test_dmevent_loop_good1(void **state)
 	assert_int_equal(add_dm_device_event("foo", 1, 6), 0);
 	assert_int_equal(remove_dm_device_event("xyzzy"), 0);
 	will_return(__wrap_poll, 1);
-	will_return(__wrap_ioctl, 0);
+	wrap_will_return(WRAP_IOCTL, 0);
 	will_return(__wrap_libmp_dm_task_create, &data);
-	will_return(__wrap_dm_task_no_open_count, 1);
 	will_return(__wrap_dm_task_run, 1);
 	will_return(__wrap_dm_task_get_names, 1);
 	expect_string(__wrap_update_multipath, mapname, "foo");
@@ -805,9 +804,8 @@ static void test_dmevent_loop_good2(void **state)
 	assert_int_equal(watch_dmevents("baz"), 0);
 	assert_int_equal(add_dm_device_event("baz", 1, 14), 0);
 	will_return(__wrap_poll, 1);
-	will_return(__wrap_ioctl, 0);
+	wrap_will_return(WRAP_IOCTL, 0);
 	will_return(__wrap_libmp_dm_task_create, &data);
-	will_return(__wrap_dm_task_no_open_count, 1);
 	will_return(__wrap_dm_task_run, 1);
 	will_return(__wrap_dm_task_get_names, 1);
 	expect_string(__wrap_update_multipath, mapname, "bar");
@@ -849,9 +847,8 @@ static void test_dmevent_loop_good3(void **state)
 	assert_int_equal(remove_dm_device_event("foo"), 0);
 	unwatch_dmevents("bar");
 	will_return(__wrap_poll, 1);
-	will_return(__wrap_ioctl, 0);
+	wrap_will_return(WRAP_IOCTL, 0);
 	will_return(__wrap_libmp_dm_task_create, &data);
-	will_return(__wrap_dm_task_no_open_count, 1);
 	will_return(__wrap_dm_task_run, 1);
 	will_return(__wrap_dm_task_get_names, 1);
 	expect_string(__wrap_remove_map_by_alias, alias, "foo");
@@ -874,7 +871,7 @@ static void test_arm_poll(void **state)
 	struct test_data *datap = (struct test_data *)(*state);
 	if (datap == NULL)
 		skip();
-	will_return(__wrap_ioctl, 0);
+	wrap_will_return(WRAP_IOCTL, 0);
 	assert_int_equal(arm_dm_event_poll(waiter->fd), 0);
 }
 
-- 
2.45.2


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

* [PATCH 03/44] create-config.mk: use printf instead of /bin/echo
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
  2024-07-09 21:38 ` [PATCH 01/44] multipath-tools CI: more fixes for arm/v7 Martin Wilck
  2024-07-09 21:38 ` [PATCH 02/44] multipath-tools CI: fix dmevents test for Debian Sid, arm/v7 Martin Wilck
@ 2024-07-09 21:38 ` Martin Wilck
  2024-07-09 21:38 ` [PATCH 04/44] multipathd.service.in: use @BINDIR@ instead of /sbin Martin Wilck
                   ` (41 subsequent siblings)
  44 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:38 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

The behavior of "echo -e" is not part of the POSIY standard and
different shells handle it differently. OTOH, /bin/echo isn't necessarily
available, either. Use printf instead, which is part of POSIX.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 create-config.mk | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/create-config.mk b/create-config.mk
index 4d318b9..0abbb3a 100644
--- a/create-config.mk
+++ b/create-config.mk
@@ -147,11 +147,11 @@ TEST_CC_OPTION = $(shell \
 # On some distros (e.g. Debian Buster) it will be falsely reported as supported
 # but it doesn't seem to make a difference wrt the compilation result.
 FORTIFY_OPT := $(shell \
-	if /bin/echo -e '$(__HASH__)include <string.h>\nint main(void) { return 0; }' | \
+	if printf '$(__HASH__)include <string.h>\nint main(void) { return 0; }\n' | \
 		$(CC) -o /dev/null $(OPTFLAGS) -c -Werror -D_FORTIFY_SOURCE=3 -xc - 2>/dev/null; \
 	then \
 		echo "-D_FORTIFY_SOURCE=3"; \
-	elif /bin/echo -e '$(__HASH__)include <string.h>\nint main(void) { return 0; }' | \
+	elif printf '$(__HASH__)include <string.h>\nint main(void) { return 0; }\n' | \
 		$(CC) -o /dev/null $(OPTFLAGS) -c -Werror -D_FORTIFY_SOURCE=2 -xc - 2>/dev/null; \
 	then \
 		echo "-D_FORTIFY_SOURCE=2"; \
-- 
2.45.2


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

* [PATCH 04/44] multipathd.service.in: use @BINDIR@ instead of /sbin
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (2 preceding siblings ...)
  2024-07-09 21:38 ` [PATCH 03/44] create-config.mk: use printf instead of /bin/echo Martin Wilck
@ 2024-07-09 21:38 ` Martin Wilck
  2024-07-09 21:38 ` [PATCH 05/44] Makefile.inc: replace @BINDIR@ with $(TGTDIR)/$(bindir) Martin Wilck
                   ` (40 subsequent siblings)
  44 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:38 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

The path in the unit file should match the actual installation path.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 multipathd/multipathd.service.in | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/multipathd/multipathd.service.in b/multipathd/multipathd.service.in
index a63ddd9..646001e 100644
--- a/multipathd/multipathd.service.in
+++ b/multipathd/multipathd.service.in
@@ -16,8 +16,8 @@ ConditionVirtualization=!container
 [Service]
 Type=notify
 NotifyAccess=main
-ExecStart=/sbin/multipathd -d -s
-ExecReload=/sbin/multipathd reconfigure
+ExecStart=@BINDIR@/multipathd -d -s
+ExecReload=@BINDIR@/multipathd reconfigure
 TasksMax=infinity
 LimitRTPRIO=10
 CPUWeight=1000
-- 
2.45.2


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

* [PATCH 05/44] Makefile.inc: replace @BINDIR@ with $(TGTDIR)/$(bindir)
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (3 preceding siblings ...)
  2024-07-09 21:38 ` [PATCH 04/44] multipathd.service.in: use @BINDIR@ instead of /sbin Martin Wilck
@ 2024-07-09 21:38 ` Martin Wilck
  2024-07-09 21:38 ` [PATCH 06/44] kpartx.rules: use @BINDIR@ to locate kpartx Martin Wilck
                   ` (39 subsequent siblings)
  44 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:38 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

The unit files and udev rules that use @BINDIR@ for substitutions
have the installation target's point of view, they must include
$(TGTDIR) (which is empty by default).

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 Makefile.inc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Makefile.inc b/Makefile.inc
index ed4a423..28b6032 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -150,4 +150,4 @@ NV_VERSION_SCRIPT = $(DEVLIB:%.so=%-nv.version)
 
 %:	%.in
 	@echo creating $@
-	$(Q)sed 's:@CONFIGFILE@:'$(TGTDIR)$(configfile)':g;s:@CONFIGDIR@:'$(TGTDIR)$(configdir)':g;s:@STATE_DIR@:'$(TGTDIR)$(statedir)':g;s:@RUNTIME_DIR@:'$(runtimedir)':g;s/@MODPROBE_UNIT@/'$(MODPROBE_UNIT)'/g;s:@BINDIR@:'$(bindir)':g' $< >$@
+	$(Q)sed 's:@CONFIGFILE@:'$(TGTDIR)$(configfile)':g;s:@CONFIGDIR@:'$(TGTDIR)$(configdir)':g;s:@STATE_DIR@:'$(TGTDIR)$(statedir)':g;s:@RUNTIME_DIR@:'$(runtimedir)':g;s/@MODPROBE_UNIT@/'$(MODPROBE_UNIT)'/g;s:@BINDIR@:'$(TGTDIR)$(bindir)':g' $< >$@
-- 
2.45.2


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

* [PATCH 06/44] kpartx.rules: use @BINDIR@ to locate kpartx
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (4 preceding siblings ...)
  2024-07-09 21:38 ` [PATCH 05/44] Makefile.inc: replace @BINDIR@ with $(TGTDIR)/$(bindir) Martin Wilck
@ 2024-07-09 21:38 ` Martin Wilck
  2024-07-10 16:30   ` Benjamin Marzinski
  2024-07-09 21:38 ` [PATCH 07/44] multipath-tools: Remove hard-coded paths to executables Martin Wilck
                   ` (38 subsequent siblings)
  44 siblings, 1 reply; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:38 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

The path for kpartx should match the installed binary.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 .gitignore                               | 1 +
 kpartx/Makefile                          | 4 ++--
 kpartx/{kpartx.rules => kpartx.rules.in} | 2 +-
 3 files changed, 4 insertions(+), 3 deletions(-)
 rename kpartx/{kpartx.rules => kpartx.rules.in} (96%)

diff --git a/.gitignore b/.gitignore
index 049ffe8..355ddbb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,6 +12,7 @@ config.mk
 cscope.files
 cscope.out
 kpartx/kpartx
+kpartx/kpartx.rules
 multipath/multipath
 multipath/multipath.8
 multipath/multipath.conf.5
diff --git a/kpartx/Makefile b/kpartx/Makefile
index 7720a74..0d4c798 100644
--- a/kpartx/Makefile
+++ b/kpartx/Makefile
@@ -19,7 +19,7 @@ $(EXEC): $(OBJS)
 	@echo building $@ because of $?
 	$(Q)$(CC) $(CFLAGS) $(OBJS) -o $(EXEC) $(LDFLAGS) $(LIBDEPS)
 
-install: $(EXEC) $(EXEC).8
+install: $(EXEC) $(EXEC).8 kpartx.rules
 	$(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir)
 	$(Q)$(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)
 	$(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(libudevdir)
@@ -41,7 +41,7 @@ uninstall:
 	$(Q)$(RM) $(DESTDIR)$(libudevdir)/rules.d/68-del-part-nodes.rules
 
 clean: dep_clean
-	$(Q)$(RM) core *.o $(EXEC)
+	$(Q)$(RM) core *.o $(EXEC) kpartx.rules
 
 include $(wildcard $(OBJS:.o=.d))
 
diff --git a/kpartx/kpartx.rules b/kpartx/kpartx.rules.in
similarity index 96%
rename from kpartx/kpartx.rules
rename to kpartx/kpartx.rules.in
index 8dd3369..9d87960 100644
--- a/kpartx/kpartx.rules
+++ b/kpartx/kpartx.rules.in
@@ -39,6 +39,6 @@ LABEL="mpath_kpartx_end"
 GOTO="kpartx_end"
 
 LABEL="run_kpartx"
-RUN+="/sbin/kpartx -un -p -part /dev/$name"
+RUN+="@BINDIR@/kpartx -un -p -part /dev/$name"
 
 LABEL="kpartx_end"
-- 
2.45.2


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

* [PATCH 07/44] multipath-tools: Remove hard-coded paths to executables
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (5 preceding siblings ...)
  2024-07-09 21:38 ` [PATCH 06/44] kpartx.rules: use @BINDIR@ to locate kpartx Martin Wilck
@ 2024-07-09 21:38 ` Martin Wilck
  2024-07-09 21:38 ` [PATCH 08/44] multipath-tools: compile_commands.json fixes Martin Wilck
                   ` (37 subsequent siblings)
  44 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:38 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 Makefile.inc                   | 17 ++++++++++++++---
 kpartx/kpartx_id               |  8 ++++----
 multipath/11-dm-mpath.rules.in |  4 ++--
 multipath/multipath.rules.in   |  6 +++---
 4 files changed, 23 insertions(+), 12 deletions(-)

diff --git a/Makefile.inc b/Makefile.inc
index 28b6032..fe9f1bf 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -42,9 +42,11 @@ etc_prefix	:= $(prefix)
 # Where to install systemd-related files. systemd is usually installed under /usr
 # Note: systemd installations with "split-usr=true" use separate "prefixdir" and
 # "rootprefixdir". Our systemd_prefix corresponds to "prefixdir".
-# In this case, override only unitdir and libudevdir below to use
-# systemd's "rootprefixdir" instead of $(systemd_prefix)
+# In this case, override only unitdir, libudevdir and sys_execprefix below
+# to use systemd's "rootprefixdir" instead of $(systemd_prefix)
 systemd_prefix  := /usr
+# Prefix for binaries that are owned by other packages (including systemd)
+sys_execprefix  := /usr
 
 # Make sure all prefix variables end in "/"
 append-slash = $(1)$(if $(filter %/,$(1)),,/)
@@ -53,6 +55,7 @@ override exec_prefix     := $(call append-slash,$(exec_prefix))
 override usr_prefix      := $(call append-slash,$(usr_prefix))
 override etc_prefix      := $(call append-slash,$(etc_prefix))
 override systemd_prefix  := $(call append-slash,$(systemd_prefix))
+override sys_execprefix  := $(call append-slash,$(sys_execprefix))
 
 unitdir		:= $(systemd_prefix)lib/systemd/system
 tmpfilesdir	:= $(systemd_prefix)lib/tmpfiles.d
@@ -74,6 +77,7 @@ runtimedir      := $(if $(shell test -L /var/run -o ! -d /var/run && echo 1),/ru
 devmapper_incdir := $(or $(shell $(PKG_CONFIG) --variable=includedir devmapper),/usr/include)
 libudev_incdir	:= $(or $(shell $(PKG_CONFIG) --variable=includedir libudev),/usr/include)
 kernel_incdir	:= /usr/include
+sysdir_bin      := $(sys_execprefix)bin
 
 ifeq ($(V),)
 Q		:= @
@@ -150,4 +154,11 @@ NV_VERSION_SCRIPT = $(DEVLIB:%.so=%-nv.version)
 
 %:	%.in
 	@echo creating $@
-	$(Q)sed 's:@CONFIGFILE@:'$(TGTDIR)$(configfile)':g;s:@CONFIGDIR@:'$(TGTDIR)$(configdir)':g;s:@STATE_DIR@:'$(TGTDIR)$(statedir)':g;s:@RUNTIME_DIR@:'$(runtimedir)':g;s/@MODPROBE_UNIT@/'$(MODPROBE_UNIT)'/g;s:@BINDIR@:'$(TGTDIR)$(bindir)':g' $< >$@
+	$(Q)sed -e 's:@CONFIGFILE@:'$(TGTDIR)$(configfile)':g' \
+		-e 's:@CONFIGDIR@:'$(TGTDIR)$(configdir)':g' \
+		-e 's:@STATE_DIR@:'$(TGTDIR)$(statedir)':g' \
+		-e 's:@BINDIR@:'$(TGTDIR)$(bindir)':g' \
+		-e 's:@SYSDIR_BIN@:'$(sysdir_bin)': g' \
+		-e 's:@RUNTIME_DIR@:'$(runtimedir)':g' \
+		-e 's/@MODPROBE_UNIT@/'$(MODPROBE_UNIT)'/g' \
+		$< >$@
diff --git a/kpartx/kpartx_id b/kpartx/kpartx_id
index 4672927..f9211d2 100755
--- a/kpartx/kpartx_id
+++ b/kpartx/kpartx_id
@@ -21,8 +21,6 @@
 # sent upstream but has not been accepted yet.
 #
 
-DMSETUP=/sbin/dmsetup
-
 MAJOR=$1
 MINOR=$2
 UUID=$3
@@ -32,12 +30,14 @@ if [ -z "$MAJOR" -o -z "$MINOR" ]; then
     exit 1;
 fi
 
+DMSETUP=$(command -v dmsetup) || DMSETUP=/sbin/dmsetup
+
 # Device-mapper not installed; not an error
-if [ ! -x $DMSETUP ] ; then
+if [ ! -x "$DMSETUP" ] ; then
+    echo "$0: dmsetup not found" >&2
     exit 0
 fi
 
-
 # Table UUIDs are always '<type>-<uuid>'.
 dmuuid=${UUID#*-}
 dmtbl=${UUID%%-*}
diff --git a/multipath/11-dm-mpath.rules.in b/multipath/11-dm-mpath.rules.in
index 0562edd..30647b9 100644
--- a/multipath/11-dm-mpath.rules.in
+++ b/multipath/11-dm-mpath.rules.in
@@ -9,7 +9,7 @@ ENV{.DM_SUSPENDED}!="?*", ENV{.DM_SUSPENDED}="$env{DM_SUSPENDED}"
 
 # Coldplug event while device is suspended (e.g. during a reload)
 ACTION=="add", ENV{DM_ACTIVATION}=="1", ENV{.DM_SUSPENDED}=="1", \
-	PROGRAM="/bin/logger -t 11-dm-mpath.rules -p daemon.warning \"Coldplug event for suspended device\"", \
+	PROGRAM="@SYSDIR_BIN@/logger -t 11-dm-mpath.rules -p daemon.warning \"Coldplug event for suspended device\"", \
 	ENV{DM_COLDPLUG_SUSPENDED}="1", GOTO="scan_import"
 
 # Coldplug event. Import previously set properties.
@@ -70,7 +70,7 @@ LABEL="check_mpath_unchanged"
 IMPORT{db}="DM_COLDPLUG_SUSPENDED"
 ENV{DM_COLDPLUG_SUSPENDED}=="1", ENV{.DM_SUSPENDED}!="1", \
 	ENV{DM_ACTIVATION}="1", ENV{MPATH_UNCHANGED}="0", \
-	PROGRAM="/bin/logger -t 11-dm-mpath.rules -p daemon.notice \"Forcing activation of previously suspended device\"", \
+	PROGRAM="@SYSDIR_BIN@/logger -t 11-dm-mpath.rules -p daemon.notice \"Forcing activation of previously suspended device\"", \
 	GOTO="check_mpath_ready"
 
 # DM_SUBSYSTEM_UDEV_FLAG0 is the "RELOAD" flag for multipath subsystem.
diff --git a/multipath/multipath.rules.in b/multipath/multipath.rules.in
index 780bf85..2ac1972 100644
--- a/multipath/multipath.rules.in
+++ b/multipath/multipath.rules.in
@@ -2,7 +2,7 @@
 SUBSYSTEM!="block", GOTO="end_mpath"
 KERNEL!="sd*|dasd*|nvme*", GOTO="end_mpath"
 ACTION=="remove", TEST=="@RUNTIME_DIR@/multipath/find_multipaths/$major:$minor", \
-	RUN+="/usr/bin/rm -f @RUNTIME_DIR@/multipath/find_multipaths/$major:$minor"
+	RUN+="@SYSDIR_BIN@/rm -f @RUNTIME_DIR@/multipath/find_multipaths/$major:$minor"
 ACTION!="add|change", GOTO="end_mpath"
 
 IMPORT{cmdline}="nompath"
@@ -69,7 +69,7 @@ ENV{.SAVED_FM_WAIT_UNTIL}=="?*", GOTO="pretend_mpath"
 #
 # We must trigger an "add" event because LVM2 will only act on those.
 
-RUN+="/usr/bin/systemd-run --unit=cancel-multipath-wait-$kernel --description 'cancel waiting for multipath siblings of $kernel' --no-block --timer-property DefaultDependencies=no --timer-property Conflicts=shutdown.target --timer-property Before=shutdown.target --timer-property Conflicts=initrd-cleanup.service --timer-property Before=initrd-cleanup.service --timer-property AccuracySec=500ms --property DefaultDependencies=no --property Conflicts=shutdown.target --property Before=shutdown.target --property Conflicts=initrd-cleanup.service --property Before=initrd-cleanup.service --on-active=$env{FIND_MULTIPATHS_WAIT_UNTIL} /usr/bin/udevadm trigger --action=add $sys$devpath"
+RUN+="@SYSDIR_BIN@/systemd-run --unit=cancel-multipath-wait-$kernel --description 'cancel waiting for multipath siblings of $kernel' --no-block --timer-property DefaultDependencies=no --timer-property Conflicts=shutdown.target --timer-property Before=shutdown.target --timer-property Conflicts=initrd-cleanup.service --timer-property Before=initrd-cleanup.service --timer-property AccuracySec=500ms --property DefaultDependencies=no --property Conflicts=shutdown.target --property Before=shutdown.target --property Conflicts=initrd-cleanup.service --property Before=initrd-cleanup.service --on-active=$env{FIND_MULTIPATHS_WAIT_UNTIL} @SYSDIR_BIN@/udevadm trigger --action=add $sys$devpath"
 
 LABEL="pretend_mpath"
 ENV{DM_MULTIPATH_DEVICE_PATH}="1"
@@ -85,7 +85,7 @@ ENV{FIND_MULTIPATHS_WAIT_UNTIL}!="?*", GOTO="end_mpath"
 ENV{FIND_MULTIPATHS_WAIT_UNTIL}=="0", GOTO="end_mpath"
 
 ENV{FIND_MULTIPATHS_WAIT_CANCELLED}="1"
-RUN+="/usr/bin/systemctl stop cancel-multipath-wait-$kernel.timer"
+RUN+="@SYSDIR_BIN@/systemctl stop cancel-multipath-wait-$kernel.timer"
 
 # If "multipath -u" failed, no values are imported from the program,
 # and we are still using the values for DM_MULTIPATH_DEVICE_PATH and
-- 
2.45.2


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

* [PATCH 08/44] multipath-tools: compile_commands.json fixes
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (6 preceding siblings ...)
  2024-07-09 21:38 ` [PATCH 07/44] multipath-tools: Remove hard-coded paths to executables Martin Wilck
@ 2024-07-09 21:38 ` Martin Wilck
  2024-07-09 21:39 ` [PATCH 09/44] multipath-tools: .gitignore: ignore o.wrap files for CI helpers Martin Wilck
                   ` (36 subsequent siblings)
  44 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:38 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

compile_commands.json serves as input for clangd, while working with
lsp under emacs. It's normal for functions and parameters to be unused while
writing code. Therefore suppress -Werror for this use case. clangd will
display the warnings.

Use "make testprogs" to generate compile_commands.json, in order to be
able to use clangd for the CI code, too.

Finally, don't remove compile_commands.json with "make clean". Normally the
compile commands remain the same, even if a clean rebuild of the binaries
is necessary. Put the file into .gitignore instead.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 .gitignore   |  1 +
 Makefile     |  4 ++--
 Makefile.inc | 12 +++++++++---
 3 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/.gitignore b/.gitignore
index 355ddbb..efdbd8a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,6 +8,7 @@
 *.gz
 *.d
 \#*
+compile_commands.json
 config.mk
 cscope.files
 cscope.out
diff --git a/Makefile b/Makefile
index 4df5f16..14bbac2 100644
--- a/Makefile
+++ b/Makefile
@@ -83,7 +83,7 @@ abi-test:	abi reference-abi $(wildcard abi/*.abi)
 # Requires bear (https://github.com/rizsotto/Bear)
 compile_commands.json: Makefile Makefile.inc $(BUILDDIRS:=/Makefile)
 	$(Q)$(MAKE) clean
-	$(Q)bear -- $(MAKE)
+	$(Q)bear -- $(MAKE) WARN_ONLY=1 test-progs || rm $@
 
 libmpathutil libdmmp: libmpathcmd
 libmultipath: libmpathutil
@@ -109,7 +109,7 @@ $(BUILDDIRS:=.uninstall):
 clean:
 	@touch config.mk
 	$(Q)$(MAKE) $(BUILDDIRS:=.clean) tests.clean || true
-	$(Q)$(RM) -r abi abi.tar.gz abi-test compile_commands.json config.mk
+	$(Q)$(RM) -r abi abi.tar.gz abi-test config.mk
 
 install: $(BUILDDIRS:=.install)
 uninstall: $(BUILDDIRS:=.uninstall)
diff --git a/Makefile.inc b/Makefile.inc
index fe9f1bf..729618b 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -100,9 +100,15 @@ MODPROBE_UNIT := $(shell test "0$(SYSTEMD)" -lt 245 2>/dev/null || \
 			echo "modprobe@dm_multipath.service")
 
 OPTFLAGS	:= -O2 -g $(STACKPROT) --param=ssp-buffer-size=4
-WARNFLAGS	:= -Werror -Wall -Wextra -Wformat=2 $(WFORMATOVERFLOW) -Werror=implicit-int \
-		  -Werror=implicit-function-declaration -Werror=format-security \
-		  $(WNOCLOBBERED) -Werror=cast-qual $(ERROR_DISCARDED_QUALIFIERS) $(W_URCU_TYPE_LIMITS)
+
+# Set WARN_ONLY=1 to avoid compilation erroring out due to warnings. Useful during development.
+WARN_ONLY       :=
+ERROR           := $(if $(WARN_ONLY),,error=)
+WERROR          := $(if $(WARN_ONLY),,-Werror)
+WARNFLAGS	:= $(WERROR) -Wall -Wextra -Wformat=2 $(WFORMATOVERFLOW) -W$(ERROR)implicit-int \
+		  -W$(ERROR)implicit-function-declaration -W$(ERROR)format-security \
+		  $(WNOCLOBBERED) -W$(ERROR)cast-qual $(ERROR_DISCARDED_QUALIFIERS) $(W_URCU_TYPE_LIMITS)
+
 CPPFLAGS	:= $(FORTIFY_OPT) $(CPPFLAGS) $(D_URCU_VERSION) \
 		   -D_FILE_OFFSET_BITS=64 \
 		   -DBIN_DIR=\"$(bindir)\" -DMULTIPATH_DIR=\"$(TGTDIR)$(plugindir)\" \
-- 
2.45.2


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

* [PATCH 09/44] multipath-tools: .gitignore: ignore o.wrap files for CI helpers
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (7 preceding siblings ...)
  2024-07-09 21:38 ` [PATCH 08/44] multipath-tools: compile_commands.json fixes Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-09 21:39 ` [PATCH 10/44] libmultipath: remove unused includes in devmapper.h Martin Wilck
                   ` (35 subsequent siblings)
  44 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

Unlike the .o.wrap files for the CI tests themselves, these are
not automatically deleted by "make" as intermediate files. Ignore them.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 .gitignore | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/.gitignore b/.gitignore
index efdbd8a..4548cfb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,6 +42,8 @@ libdmmp/test/libdmmp_speed_test
 tests/*-test
 tests/*.out
 tests/*.vgr
+tests/test-lib.o.wrap
+tests/test-log.o.wrap
 libmultipath/nvme-ioctl.c
 libmultipath/nvme-ioctl.h
 libmultipath/autoconfig.h
-- 
2.45.2


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

* [PATCH 10/44] libmultipath: remove unused includes in devmapper.h
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (8 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 09/44] multipath-tools: .gitignore: ignore o.wrap files for CI helpers Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-09 21:39 ` [PATCH 11/44] libmultipath: use DM_DEVICE_INFO in dm_mapname() Martin Wilck
                   ` (34 subsequent siblings)
  44 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmultipath/devmapper.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index 08bb3c5..3ee8555 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -17,13 +17,11 @@
 #include <linux/dm-ioctl.h>
 
 #include "util.h"
-#include "checkers.h"
 #include "vector.h"
 #include "structs.h"
 #include "debug.h"
 #include "devmapper.h"
 #include "sysfs.h"
-#include "config.h"
 #include "wwids.h"
 #include "version.h"
 #include "time-util.h"
-- 
2.45.2


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

* [PATCH 11/44] libmultipath: use DM_DEVICE_INFO in dm_mapname()
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (9 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 10/44] libmultipath: remove unused includes in devmapper.h Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-09 21:39 ` [PATCH 12/44] multipath-tools: don't call dm_task_no_open_count() Martin Wilck
                   ` (33 subsequent siblings)
  44 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

DM_DEVICE_INFO aka the kernel's DM_DEV_STATUS ioctl, is sufficient to
fetch the map name, and more lightweight than DM_DEVICE_STATUS, which maps to
the kernel's DM_TABLE_STATUS ioctl.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmultipath/devmapper.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index 3ee8555..baa1ead 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -1412,7 +1412,7 @@ dm_mapname(int major, int minor)
 	struct dm_task *dmt;
 	int r;
 
-	if (!(dmt = libmp_dm_task_create(DM_DEVICE_STATUS)))
+	if (!(dmt = libmp_dm_task_create(DM_DEVICE_INFO)))
 		return NULL;
 
 	if (!dm_task_set_major(dmt, major) ||
@@ -1422,7 +1422,7 @@ dm_mapname(int major, int minor)
 	dm_task_no_open_count(dmt);
 	r = libmp_dm_task_run(dmt);
 	if (!r) {
-		dm_log_error(2, DM_DEVICE_STATUS, dmt);
+		dm_log_error(2, DM_DEVICE_INFO, dmt);
 		goto bad;
 	}
 
-- 
2.45.2


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

* [PATCH 12/44] multipath-tools: don't call dm_task_no_open_count()
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (10 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 11/44] libmultipath: use DM_DEVICE_INFO in dm_mapname() Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-09 21:39 ` [PATCH 13/44] libmpathutil: export cleanup_udev_device() Martin Wilck
                   ` (32 subsequent siblings)
  44 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

dm_task_no_open_count() only sets DM_SKIP_BDGET_FLAG in the dm task,
which has been ignored by the kernel since 5c6bd75d06db ("[PATCH] dm: prevent
removal if open") (v2.6.18 / 2006). Even for older kernels, not setting
this flag has only a minor, performance-related effect (skipping one call
to bdget_disk()). Don't use this dead API any more.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 kpartx/devmapper.c       | 15 ---------------
 libmultipath/devmapper.c | 36 ------------------------------------
 multipathd/dmevents.c    |  2 --
 multipathd/waiter.c      |  2 --
 tests/dmevents.c         | 13 -------------
 5 files changed, 68 deletions(-)

diff --git a/kpartx/devmapper.c b/kpartx/devmapper.c
index f12762c..bf07838 100644
--- a/kpartx/devmapper.c
+++ b/kpartx/devmapper.c
@@ -35,8 +35,6 @@ int dm_prereq(char * str, uint32_t x, uint32_t y, uint32_t z)
 	if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS)))
 		return 1;
 
-	dm_task_no_open_count(dmt);
-
 	if (!dm_task_run(dmt))
 		goto out;
 
@@ -78,7 +76,6 @@ int dm_simplecmd(int task, const char *name, int no_flush, __DM_API_COOKIE_UNUSE
 	if (!dm_task_set_name(dmt, name))
 		goto out;
 
-	dm_task_no_open_count(dmt);
 	dm_task_skip_lockfs(dmt);
 
 	if (no_flush)
@@ -175,8 +172,6 @@ int dm_addmap(int task, const char *name, const char *target,
 	if (!dm_task_set_gid(dmt, gid))
 		goto addout;
 
-	dm_task_no_open_count(dmt);
-
 #ifdef LIBDM_API_COOKIE
 	if (!udev_sync)
 		udev_flags = DM_UDEV_DISABLE_LIBRARY_FALLBACK;
@@ -212,8 +207,6 @@ static int dm_map_present(char *str, char **uuid)
 	if (!dm_task_set_name(dmt, str))
 		goto out;
 
-	dm_task_no_open_count(dmt);
-
 	if (!dm_task_run(dmt))
 		goto out;
 
@@ -247,7 +240,6 @@ static int dm_rename (const char *old, const char *new)
 
 	if (!dm_task_set_name(dmt, old) ||
 	    !dm_task_set_newname(dmt, new) ||
-	    !dm_task_no_open_count(dmt) ||
 	    !dm_task_set_cookie(dmt, &cookie, udev_flags))
 		goto out;
 
@@ -291,7 +283,6 @@ dm_mapname(int major, int minor)
 	if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
 		return NULL;
 
-	dm_task_no_open_count(dmt);
 	dm_task_set_major(dmt, major);
 	dm_task_set_minor(dmt, minor);
 
@@ -352,7 +343,6 @@ dm_mapuuid(const char *mapname)
 
 	if (!dm_task_set_name(dmt, mapname))
 		goto out;
-	dm_task_no_open_count(dmt);
 
 	if (!dm_task_run(dmt))
 		goto out;
@@ -407,7 +397,6 @@ dm_get_map(const char *mapname, char * outparams)
 
 	if (!dm_task_set_name(dmt, mapname))
 		goto out;
-	dm_task_no_open_count(dmt);
 
 	if (!dm_task_run(dmt))
 		goto out;
@@ -474,8 +463,6 @@ dm_type(const char * name, char * type)
 	if (!dm_task_set_name(dmt, name))
 		goto out;
 
-	dm_task_no_open_count(dmt);
-
 	if (!dm_task_run(dmt))
 		goto out;
 
@@ -545,8 +532,6 @@ do_foreach_partmaps (const char * mapname, const char *uuid,
 	if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
 		return 1;
 
-	dm_task_no_open_count(dmt);
-
 	if (!dm_task_run(dmt))
 		goto out;
 
diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index baa1ead..8996c1d 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -217,8 +217,6 @@ static int dm_tgt_version (unsigned int *version, char *str)
 	if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS)))
 		return 1;
 
-	dm_task_no_open_count(dmt);
-
 	if (!libmp_dm_task_run(dmt)) {
 		dm_log_error(2, DM_DEVICE_LIST_VERSIONS, dmt);
 		condlog(0, "Cannot communicate with kernel DM");
@@ -398,7 +396,6 @@ dm_simplecmd (int task, const char *name, int flags, uint16_t udev_flags) {
 	if (!dm_task_set_name (dmt, name))
 		goto out;
 
-	dm_task_no_open_count(dmt);
 	dm_task_skip_lockfs(dmt);	/* for DM_DEVICE_RESUME */
 #ifdef LIBDM_API_FLUSH
 	if (flags & DMFL_NO_FLUSH)
@@ -495,8 +492,6 @@ dm_addmap (int task, const char *target, struct multipath *mpp,
 		task == DM_DEVICE_RELOAD ? "reload" : "addmap", mpp->size,
 		target, params);
 
-	dm_task_no_open_count(dmt);
-
 	if (task == DM_DEVICE_CREATE &&
 	    !dm_task_set_cookie(dmt, &cookie, udev_flags))
 		goto freeout;
@@ -627,8 +622,6 @@ dm_get_info(const char *name, struct dm_info *info)
 	if (!dm_task_set_name(dmt, name))
 		goto out;
 
-	dm_task_no_open_count(dmt);
-
 	if (!libmp_dm_task_run(dmt)) {
 		dm_log_error(3, DM_DEVICE_INFO, dmt);
 		goto out;
@@ -667,8 +660,6 @@ int dm_get_map(const char *name, unsigned long long *size, char **outparams)
 	if (!dm_task_set_name(dmt, name))
 		goto out;
 
-	dm_task_no_open_count(dmt);
-
 	errno = 0;
 	if (!libmp_dm_task_run(dmt)) {
 		dm_log_error(3, DM_DEVICE_TABLE, dmt);
@@ -787,8 +778,6 @@ int dm_get_status(const char *name, char **outstatus)
 	if (!dm_task_set_name(dmt, name))
 		goto out;
 
-	dm_task_no_open_count(dmt);
-
 	errno = 0;
 	if (!libmp_dm_task_run(dmt)) {
 		dm_log_error(3, DM_DEVICE_STATUS, dmt);
@@ -845,8 +834,6 @@ int dm_type(const char *name, char *type)
 	if (!dm_task_set_name(dmt, name))
 		goto out;
 
-	dm_task_no_open_count(dmt);
-
 	if (!libmp_dm_task_run(dmt)) {
 		dm_log_error(3, DM_DEVICE_TABLE, dmt);
 		goto out;
@@ -889,8 +876,6 @@ int dm_is_mpath(const char *name)
 	if (!dm_task_set_name(dmt, name))
 		goto out_task;
 
-	dm_task_no_open_count(dmt);
-
 	if (!libmp_dm_task_run(dmt)) {
 		dm_log_error(3, DM_DEVICE_TABLE, dmt);
 		goto out_task;
@@ -950,8 +935,6 @@ dm_map_present_by_uuid(const char *uuid)
 	if (!(dmt = libmp_dm_task_create(DM_DEVICE_INFO)))
 		goto out;
 
-	dm_task_no_open_count(dmt);
-
 	if (!dm_task_set_uuid(dmt, prefixed_uuid))
 		goto out_task;
 
@@ -1158,8 +1141,6 @@ int dm_flush_maps (int retries)
 	if (!(dmt = libmp_dm_task_create (DM_DEVICE_LIST)))
 		return r;
 
-	dm_task_no_open_count(dmt);
-
 	if (!libmp_dm_task_run (dmt)) {
 		dm_log_error(3, DM_DEVICE_LIST, dmt);
 		goto out;
@@ -1205,8 +1186,6 @@ dm_message(const char * mapname, char * message)
 	if (!dm_task_set_message(dmt, message))
 		goto out;
 
-	dm_task_no_open_count(dmt);
-
 	if (!libmp_dm_task_run(dmt)) {
 		dm_log_error(2, DM_DEVICE_TARGET_MSG, dmt);
 		goto out;
@@ -1341,8 +1320,6 @@ dm_get_maps (vector mp)
 	if (!(dmt = libmp_dm_task_create(DM_DEVICE_LIST)))
 		return 1;
 
-	dm_task_no_open_count(dmt);
-
 	if (!libmp_dm_task_run(dmt)) {
 		dm_log_error(3, DM_DEVICE_LIST, dmt);
 		goto out;
@@ -1419,7 +1396,6 @@ dm_mapname(int major, int minor)
 	    !dm_task_set_minor(dmt, minor))
 		goto bad;
 
-	dm_task_no_open_count(dmt);
 	r = libmp_dm_task_run(dmt);
 	if (!r) {
 		dm_log_error(2, DM_DEVICE_INFO, dmt);
@@ -1455,8 +1431,6 @@ do_foreach_partmaps (const char * mapname,
 	if (!(dmt = libmp_dm_task_create(DM_DEVICE_LIST)))
 		return 1;
 
-	dm_task_no_open_count(dmt);
-
 	if (!libmp_dm_task_run(dmt)) {
 		dm_log_error(3, DM_DEVICE_LIST, dmt);
 		goto out;
@@ -1665,8 +1639,6 @@ dm_rename (const char * old, char * new, char *delim, int skip_kpartx)
 	if (!dm_task_set_newname(dmt, new))
 		goto out;
 
-	dm_task_no_open_count(dmt);
-
 	if (!dm_task_set_cookie(dmt, &cookie, udev_flags))
 		goto out;
 	r = libmp_dm_task_run(dmt);
@@ -1713,8 +1685,6 @@ int dm_reassign_table(const char *name, char *old, char *new)
 	if (!dm_task_set_name(dmt, name))
 		goto out;
 
-	dm_task_no_open_count(dmt);
-
 	if (!libmp_dm_task_run(dmt)) {
 		dm_log_error(3, DM_DEVICE_TABLE, dmt);
 		goto out;
@@ -1756,8 +1726,6 @@ int dm_reassign_table(const char *name, char *old, char *new)
 	} while (next);
 
 	if (modified) {
-		dm_task_no_open_count(reload_dmt);
-
 		if (!libmp_dm_task_run(reload_dmt)) {
 			dm_log_error(3, DM_DEVICE_RELOAD, reload_dmt);
 			condlog(3, "%s: failed to reassign targets", name);
@@ -1803,8 +1771,6 @@ int dm_reassign(const char *mapname)
 	if (!dm_task_set_name(dmt, mapname))
 		goto out;
 
-	dm_task_no_open_count(dmt);
-
 	if (!libmp_dm_task_run(dmt)) {
 		dm_log_error(3, DM_DEVICE_DEPS, dmt);
 		goto out;
@@ -1861,8 +1827,6 @@ int dm_setgeometry(struct multipath *mpp)
 	if (!dm_task_set_name(dmt, mpp->alias))
 		goto out;
 
-	dm_task_no_open_count(dmt);
-
 	/* What a sick interface ... */
 	snprintf(heads, 4, "%u", pp->geom.heads);
 	snprintf(sectors, 4, "%u", pp->geom.sectors);
diff --git a/multipathd/dmevents.c b/multipathd/dmevents.c
index 5657000..3fbdc55 100644
--- a/multipathd/dmevents.c
+++ b/multipathd/dmevents.c
@@ -154,8 +154,6 @@ static int dm_get_events(void)
 	if (!(dmt = libmp_dm_task_create(DM_DEVICE_LIST)))
 		return -1;
 
-	dm_task_no_open_count(dmt);
-
 	if (!libmp_dm_task_run(dmt)) {
 		dm_log_error(3, DM_DEVICE_LIST, dmt);
 		goto fail;
diff --git a/multipathd/waiter.c b/multipathd/waiter.c
index d1f344b..1dd93c5 100644
--- a/multipathd/waiter.c
+++ b/multipathd/waiter.c
@@ -108,8 +108,6 @@ static int waiteventloop (struct event_thread *waiter)
 		return 1;
 	}
 
-	dm_task_no_open_count(waiter->dmt);
-
 	/* wait */
 	sigemptyset(&set);
 	sigaddset(&set, SIGUSR2);
diff --git a/tests/dmevents.c b/tests/dmevents.c
index 668e6d2..2f98173 100644
--- a/tests/dmevents.c
+++ b/tests/dmevents.c
@@ -267,15 +267,6 @@ struct dm_task *__wrap_libmp_dm_task_create(int task)
 	return mock_type(struct dm_task *);
 }
 
-int __real_dm_task_no_open_count(struct dm_task *dmt);
-int __wrap_dm_task_no_open_count(struct dm_task *dmt)
-{
-	if (!setup_done)
-		return __real_dm_task_no_open_count(dmt);
-	assert_ptr_equal((struct test_data *)dmt, &data);
-	return mock_type(int);
-}
-
 int __real_dm_task_run(struct dm_task *dmt);
 int __wrap_dm_task_run(struct dm_task *dmt)
 {
@@ -554,7 +545,6 @@ static void test_get_events_bad1(void **state)
 		skip();
 
 	will_return(__wrap_libmp_dm_task_create, &data);
-	will_return(__wrap_dm_task_no_open_count, 1);
 	will_return(__wrap_dm_task_run, 0);
 	assert_int_equal(dm_get_events(), -1);
 }
@@ -567,7 +557,6 @@ static void test_get_events_bad2(void **state)
 		skip();
 
 	will_return(__wrap_libmp_dm_task_create, &data);
-	will_return(__wrap_dm_task_no_open_count, 1);
 	will_return(__wrap_dm_task_run, 1);
 	will_return(__wrap_dm_task_get_names, 0);
 	assert_int_equal(dm_get_events(), -1);
@@ -582,7 +571,6 @@ static void test_get_events_good0(void **state)
 
 	assert_int_equal(add_dm_device_event("foo", 1, 5), 0);
 	will_return(__wrap_libmp_dm_task_create, &data);
-	will_return(__wrap_dm_task_no_open_count, 1);
 	will_return(__wrap_dm_task_run, 1);
 	will_return(__wrap_dm_task_get_names, 1);
 	assert_int_equal(dm_get_events(), 0);
@@ -617,7 +605,6 @@ static void test_get_events_good1(void **state)
 	assert_int_equal(add_dm_device_event("foo", 1, 6), 0);
 	assert_int_equal(remove_dm_device_event("xyzzy"), 0);
 	will_return(__wrap_libmp_dm_task_create, &data);
-	will_return(__wrap_dm_task_no_open_count, 1);
 	will_return(__wrap_dm_task_run, 1);
 	will_return(__wrap_dm_task_get_names, 1);
 	assert_int_equal(dm_get_events(), 0);
-- 
2.45.2


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

* [PATCH 13/44] libmpathutil: export cleanup_udev_device()
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (11 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 12/44] multipath-tools: don't call dm_task_no_open_count() Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-09 21:39 ` [PATCH 14/44] libmpathutil: add cleanup_vector() Martin Wilck
                   ` (31 subsequent siblings)
  44 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

This function is useful in multiple callers.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmpathutil/libmpathutil.version | 4 ++++
 libmpathutil/util.c               | 6 ++++++
 libmpathutil/util.h               | 3 +++
 libmultipath/print.c              | 6 ------
 tests/Makefile                    | 2 +-
 5 files changed, 14 insertions(+), 7 deletions(-)

diff --git a/libmpathutil/libmpathutil.version b/libmpathutil/libmpathutil.version
index fee74a3..86450f4 100644
--- a/libmpathutil/libmpathutil.version
+++ b/libmpathutil/libmpathutil.version
@@ -133,3 +133,7 @@ LIBMPATHUTIL_2.0 {
 LIBMPATHUTIL_2.1 {
 	libmp_basename;
 };
+
+LIBMPATHUTIL_2.2 {
+	cleanup_udev_device;
+};
diff --git a/libmpathutil/util.c b/libmpathutil/util.c
index 23d303f..67db3c8 100644
--- a/libmpathutil/util.c
+++ b/libmpathutil/util.c
@@ -373,3 +373,9 @@ void cleanup_ucharp(unsigned char **p)
 {
 	free(*p);
 }
+
+void cleanup_udev_device(struct udev_device **udd)
+{
+	if (*udd)
+		udev_device_unref(*udd);
+}
diff --git a/libmpathutil/util.h b/libmpathutil/util.h
index 4997fed..c19f749 100644
--- a/libmpathutil/util.h
+++ b/libmpathutil/util.h
@@ -10,6 +10,7 @@
 #include <inttypes.h>
 #include <stdbool.h>
 #include <stdio.h>
+#include <libudev.h>
 
 size_t strchop(char *);
 
@@ -139,4 +140,6 @@ static inline void clear_bit_in_bitfield(unsigned int bit, struct bitfield *bf)
 
 void cleanup_charp(char **p);
 void cleanup_ucharp(unsigned char **p);
+void cleanup_udev_device(struct udev_device **udd);
+
 #endif /* _UTIL_H */
diff --git a/libmultipath/print.c b/libmultipath/print.c
index d592001..b7af913 100644
--- a/libmultipath/print.c
+++ b/libmultipath/print.c
@@ -436,12 +436,6 @@ snprint_multipath_vpd_data(struct strbuf *buff,
 	return append_strbuf_str(buff, "[undef]");
 }
 
-static void cleanup_udev_device(struct udev_device **udd)
-{
-	if (*udd)
-		udev_device_unref(*udd);
-}
-
 static int
 snprint_multipath_max_sectors_kb(struct strbuf *buff, const struct multipath *mpp)
 {
diff --git a/tests/Makefile b/tests/Makefile
index 4005204..8afa8c6 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -53,7 +53,7 @@ vpd-test_OBJDEPS :=  $(multipathdir)/discovery.o
 vpd-test_LIBDEPS := -ludev -lpthread -ldl
 alias-test_TESTDEPS := test-log.o
 alias-test_OBJDEPS := $(mpathutildir)/util.o
-alias-test_LIBDEPS := -lpthread -ldl
+alias-test_LIBDEPS := -ludev -lpthread -ldl
 valid-test_OBJDEPS := $(multipathdir)/valid.o $(multipathdir)/discovery.o
 valid-test_LIBDEPS := -lmount -ludev -lpthread -ldl
 devt-test_LIBDEPS := -ludev
-- 
2.45.2


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

* [PATCH 14/44] libmpathutil: add cleanup_vector()
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (12 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 13/44] libmpathutil: export cleanup_udev_device() Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-09 21:39 ` [PATCH 15/44] libmultipath: add cleanup helpers for struct multipath Martin Wilck
                   ` (30 subsequent siblings)
  44 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmpathutil/libmpathutil.version | 1 +
 libmpathutil/vector.c             | 6 ++++++
 libmpathutil/vector.h             | 1 +
 3 files changed, 8 insertions(+)

diff --git a/libmpathutil/libmpathutil.version b/libmpathutil/libmpathutil.version
index 86450f4..cb05231 100644
--- a/libmpathutil/libmpathutil.version
+++ b/libmpathutil/libmpathutil.version
@@ -136,4 +136,5 @@ LIBMPATHUTIL_2.1 {
 
 LIBMPATHUTIL_2.2 {
 	cleanup_udev_device;
+	cleanup_vector;
 };
diff --git a/libmpathutil/vector.c b/libmpathutil/vector.c
index df59db5..7c3ce43 100644
--- a/libmpathutil/vector.c
+++ b/libmpathutil/vector.c
@@ -169,6 +169,12 @@ vector_free(vector v)
 	free(v);
 }
 
+void cleanup_vector(vector *pv)
+{
+	if (*pv)
+		vector_free(*pv);
+}
+
 void
 free_strvec(vector strvec)
 {
diff --git a/libmpathutil/vector.h b/libmpathutil/vector.h
index c0b09cb..a41f157 100644
--- a/libmpathutil/vector.h
+++ b/libmpathutil/vector.h
@@ -78,6 +78,7 @@ extern vector vector_alloc(void);
 extern bool vector_alloc_slot(vector v);
 vector vector_reset(vector v);
 extern void vector_free(vector v);
+void cleanup_vector(vector *pv);
 #define vector_free_const(x) vector_free((vector)(long)(x))
 extern void free_strvec(vector strvec);
 extern void vector_set_slot(vector v, void *value);
-- 
2.45.2


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

* [PATCH 15/44] libmultipath: add cleanup helpers for struct multipath
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (13 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 14/44] libmpathutil: add cleanup_vector() Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-09 21:39 ` [PATCH 16/44] libmultipath: add cleanup_dm_task(), and use it in devmapper.c Martin Wilck
                   ` (29 subsequent siblings)
  44 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

Export cleanup_multipath_and_paths(), which will be used by multipath.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmultipath/libmultipath.version |  1 +
 libmultipath/structs.c            | 12 ++++++++++++
 libmultipath/structs.h            |  2 ++
 3 files changed, 15 insertions(+)

diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version
index eb51174..f58cb1d 100644
--- a/libmultipath/libmultipath.version
+++ b/libmultipath/libmultipath.version
@@ -66,6 +66,7 @@ global:
 	check_foreign;
 	cleanup_bindings;
 	cleanup_lock;
+	cleanup_multipath_and_paths;
 	coalesce_paths;
 	count_active_paths;
 	delete_all_foreign;
diff --git a/libmultipath/structs.c b/libmultipath/structs.c
index be3125e..1583e00 100644
--- a/libmultipath/structs.c
+++ b/libmultipath/structs.c
@@ -329,6 +329,18 @@ free_multipath (struct multipath * mpp, enum free_path_mode free_paths)
 	free(mpp);
 }
 
+void cleanup_multipath(struct multipath **pmpp)
+{
+	if (*pmpp)
+		free_multipath(*pmpp, KEEP_PATHS);
+}
+
+void cleanup_multipath_and_paths(struct multipath **pmpp)
+{
+	if (*pmpp)
+		free_multipath(*pmpp, FREE_PATHS);
+}
+
 void
 drop_multipath (vector mpvec, char * wwid, enum free_path_mode free_paths)
 {
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
index dbaf4d4..3b91e39 100644
--- a/libmultipath/structs.h
+++ b/libmultipath/structs.h
@@ -544,6 +544,8 @@ void free_pathvec (vector vec, enum free_path_mode free_paths);
 void free_pathgroup (struct pathgroup * pgp, enum free_path_mode free_paths);
 void free_pgvec (vector pgvec, enum free_path_mode free_paths);
 void free_multipath (struct multipath *, enum free_path_mode free_paths);
+void cleanup_multipath(struct multipath **pmpp);
+void cleanup_multipath_and_paths(struct multipath **pmpp);
 void free_multipath_attributes (struct multipath *);
 void drop_multipath (vector mpvec, char * wwid, enum free_path_mode free_paths);
 void free_multipathvec (vector mpvec, enum free_path_mode free_paths);
-- 
2.45.2


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

* [PATCH 16/44] libmultipath: add cleanup_dm_task(), and use it in devmapper.c
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (14 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 15/44] libmultipath: add cleanup helpers for struct multipath Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-10 20:12   ` Benjamin Marzinski
  2024-07-09 21:39 ` [PATCH 17/44] libmultipath: add libmp_mapinfo() Martin Wilck
                   ` (28 subsequent siblings)
  44 siblings, 1 reply; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

This allows us to get rid of a lot of goto statements, and generally
obtain cleaner code.

Additional small changes:

 - simplify the logic of dm_tgt_version(); the only caller isn't interested
   in the nature of the error if the version couldn't be obtained.
 - libmultipath: rename dm_type() to the more fitting dm_type_match()
 - use symbolic return values in dm_is_mpath()

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmpathpersist/mpath_persist_int.c |   2 +-
 libmultipath/devmapper.c            | 315 ++++++++++++----------------
 libmultipath/devmapper.h            |   7 +-
 multipath/main.c                    |   4 +-
 multipathd/dmevents.c               |   4 +-
 multipathd/main.c                   |   2 +-
 6 files changed, 145 insertions(+), 189 deletions(-)

diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
index 178c2f5..6da0401 100644
--- a/libmpathpersist/mpath_persist_int.c
+++ b/libmpathpersist/mpath_persist_int.c
@@ -185,7 +185,7 @@ static int mpath_get_map(vector curmp, vector pathvec, int fd, char **palias,
 
 	condlog(3, "alias = %s", alias);
 
-	if (dm_map_present(alias) && dm_is_mpath(alias) != 1){
+	if (dm_map_present(alias) && dm_is_mpath(alias) != DM_IS_MPATH_YES) {
 		condlog(3, "%s: not a multipath device.", alias);
 		goto out;
 	}
diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index 8996c1d..3685ef7 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -91,6 +91,12 @@ int libmp_dm_task_run(struct dm_task *dmt)
 	return r;
 }
 
+static void cleanup_dm_task(struct dm_task **pdmt)
+{
+	if (*pdmt)
+		dm_task_destroy(*pdmt);
+}
+
 __attribute__((format(printf, 4, 5))) static void
 dm_write_log (int level, const char *file, int line, const char *f, ...)
 {
@@ -203,8 +209,8 @@ static void init_dm_drv_version(void)
 
 static int dm_tgt_version (unsigned int *version, char *str)
 {
-	int r = 2;
-	struct dm_task *dmt;
+	bool found = false;
+	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
 	struct dm_versions *target;
 	struct dm_versions *last_target;
 	unsigned int *v;
@@ -220,31 +226,28 @@ static int dm_tgt_version (unsigned int *version, char *str)
 	if (!libmp_dm_task_run(dmt)) {
 		dm_log_error(2, DM_DEVICE_LIST_VERSIONS, dmt);
 		condlog(0, "Cannot communicate with kernel DM");
-		goto out;
+		return 1;
 	}
 	target = dm_task_get_versions(dmt);
 
 	do {
 		last_target = target;
 		if (!strncmp(str, target->name, strlen(str))) {
-			r = 1;
+			found = true;
 			break;
 		}
 		target = (void *) target + target->next;
 	} while (last_target != target);
 
-	if (r == 2) {
+	if (!found) {
 		condlog(0, "DM %s kernel driver not loaded", str);
-		goto out;
+		return 1;
 	}
 	v = target->version;
 	version[0] = v[0];
 	version[1] = v[1];
 	version[2] = v[2];
-	r = 0;
-out:
-	dm_task_destroy(dmt);
-	return r;
+	return 0;
 }
 
 static void init_dm_mpath_version(void)
@@ -383,18 +386,18 @@ libmp_dm_task_create(int task)
 
 static int
 dm_simplecmd (int task, const char *name, int flags, uint16_t udev_flags) {
-	int r = 0;
+	int r;
 	int udev_wait_flag = (((flags & DMFL_NEED_SYNC) || udev_flags) &&
 			      (task == DM_DEVICE_RESUME ||
 			       task == DM_DEVICE_REMOVE));
 	uint32_t cookie = 0;
-	struct dm_task *dmt;
+	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
 
 	if (!(dmt = libmp_dm_task_create (task)))
 		return 0;
 
 	if (!dm_task_set_name (dmt, name))
-		goto out;
+		return 0;
 
 	dm_task_skip_lockfs(dmt);	/* for DM_DEVICE_RESUME */
 #ifdef LIBDM_API_FLUSH
@@ -408,7 +411,7 @@ dm_simplecmd (int task, const char *name, int flags, uint16_t udev_flags) {
 	if (udev_wait_flag &&
 	    !dm_task_set_cookie(dmt, &cookie,
 				DM_UDEV_DISABLE_LIBRARY_FALLBACK | udev_flags))
-		goto out;
+		return 0;
 
 	r = libmp_dm_task_run (dmt);
 	if (!r)
@@ -416,8 +419,6 @@ dm_simplecmd (int task, const char *name, int flags, uint16_t udev_flags) {
 
 	if (udev_wait_flag)
 			libmp_udev_wait(cookie);
-out:
-	dm_task_destroy (dmt);
 	return r;
 }
 
@@ -440,8 +441,9 @@ static int
 dm_addmap (int task, const char *target, struct multipath *mpp,
 	   char * params, int ro, uint16_t udev_flags) {
 	int r = 0;
-	struct dm_task *dmt;
-	char *prefixed_uuid = NULL;
+	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
+	char __attribute__((cleanup(cleanup_charp))) *prefixed_uuid = NULL;
+
 	uint32_t cookie = 0;
 
 	if (task == DM_DEVICE_CREATE && strlen(mpp->wwid) == 0) {
@@ -457,10 +459,10 @@ dm_addmap (int task, const char *target, struct multipath *mpp,
 		return 0;
 
 	if (!dm_task_set_name (dmt, mpp->alias))
-		goto addout;
+		return 0;
 
 	if (!dm_task_add_target (dmt, 0, mpp->size, target, params))
-		goto addout;
+		return 0;
 
 	if (ro)
 		dm_task_set_ro(dmt);
@@ -469,10 +471,10 @@ dm_addmap (int task, const char *target, struct multipath *mpp,
 		if (asprintf(&prefixed_uuid, UUID_PREFIX "%s", mpp->wwid) < 0) {
 			condlog(0, "cannot create prefixed uuid : %s",
 				strerror(errno));
-			goto addout;
+			return 0;
 		}
 		if (!dm_task_set_uuid(dmt, prefixed_uuid))
-			goto freeout;
+			return 0;
 		dm_task_skip_lockfs(dmt);
 #ifdef LIBDM_API_FLUSH
 		dm_task_no_flush(dmt);
@@ -481,33 +483,28 @@ dm_addmap (int task, const char *target, struct multipath *mpp,
 
 	if (mpp->attribute_flags & (1 << ATTR_MODE) &&
 	    !dm_task_set_mode(dmt, mpp->mode))
-		goto freeout;
+		return 0;
 	if (mpp->attribute_flags & (1 << ATTR_UID) &&
 	    !dm_task_set_uid(dmt, mpp->uid))
-		goto freeout;
+		return 0;
 	if (mpp->attribute_flags & (1 << ATTR_GID) &&
 	    !dm_task_set_gid(dmt, mpp->gid))
-		goto freeout;
+		return 0;
+
 	condlog(2, "%s: %s [0 %llu %s %s]", mpp->alias,
 		task == DM_DEVICE_RELOAD ? "reload" : "addmap", mpp->size,
 		target, params);
 
 	if (task == DM_DEVICE_CREATE &&
 	    !dm_task_set_cookie(dmt, &cookie, udev_flags))
-		goto freeout;
+		return 0;
 
 	r = libmp_dm_task_run (dmt);
 	if (!r)
 		dm_log_error(2, task, dmt);
 
 	if (task == DM_DEVICE_CREATE)
-			libmp_udev_wait(cookie);
-freeout:
-	if (prefixed_uuid)
-		free(prefixed_uuid);
-
-addout:
-	dm_task_destroy (dmt);
+		libmp_udev_wait(cookie);
 
 	if (r)
 		mpp->need_reload = false;
@@ -648,46 +645,41 @@ int dm_map_present(const char * str)
 
 int dm_get_map(const char *name, unsigned long long *size, char **outparams)
 {
-	int r = DMP_ERR;
-	struct dm_task *dmt;
+	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
 	uint64_t start, length;
 	char *target_type = NULL;
 	char *params = NULL;
 
 	if (!(dmt = libmp_dm_task_create(DM_DEVICE_TABLE)))
-		return r;
+		return DMP_ERR;
 
 	if (!dm_task_set_name(dmt, name))
-		goto out;
+		return DMP_ERR;
 
 	errno = 0;
 	if (!libmp_dm_task_run(dmt)) {
 		dm_log_error(3, DM_DEVICE_TABLE, dmt);
 		if (dm_task_get_errno(dmt) == ENXIO)
-			r = DMP_NOT_FOUND;
-		goto out;
+			return DMP_NOT_FOUND;
+		else
+			return DMP_ERR;
 	}
 
-	r = DMP_NOT_FOUND;
 	/* Fetch 1st target */
 	if (dm_get_next_target(dmt, NULL, &start, &length,
 			       &target_type, &params) != NULL || !params)
 		/* more than one target or not found target */
-		goto out;
+		return DMP_NOT_FOUND;
 
 	if (size)
 		*size = length;
 
 	if (!outparams)
-		r = DMP_OK;
+		return DMP_OK;
 	else {
 		*outparams = strdup(params);
-		r = *outparams ? DMP_OK : DMP_ERR;
+		return *outparams ? DMP_OK : DMP_ERR;
 	}
-
-out:
-	dm_task_destroy(dmt);
-	return r;
 }
 
 static int
@@ -767,7 +759,7 @@ is_mpath_part(const char *part_name, const char *map_name)
 int dm_get_status(const char *name, char **outstatus)
 {
 	int r = DMP_ERR;
-	struct dm_task *dmt;
+	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
 	uint64_t start, length;
 	char *target_type = NULL;
 	char *status = NULL;
@@ -796,7 +788,7 @@ int dm_get_status(const char *name, char **outstatus)
 		goto out;
 
 	if (!status) {
-		condlog(2, "get null status.");
+		condlog(2, "got null status.");
 		goto out;
 	}
 
@@ -808,62 +800,56 @@ int dm_get_status(const char *name, char **outstatus)
 	}
 out:
 	if (r != DMP_OK)
-		condlog(0, "%s: error getting map status string", name);
+		condlog(0, "%s: %s: error getting map status string: %d",
+			__func__, name, r);
 
-	dm_task_destroy(dmt);
 	return r;
 }
 
-/*
- * returns:
- *    1 : match
- *    0 : no match
- *   -1 : empty map, or more than 1 target
- */
-int dm_type(const char *name, char *type)
+enum {
+	DM_TYPE_NOMATCH = 0,
+	DM_TYPE_MATCH,
+	/* more than 1 target */
+	DM_TYPE_MULTI,
+	/* empty map */
+	DM_TYPE_EMPTY,
+	DM_TYPE_ERR,
+};
+static int dm_type_match(const char *name, char *type)
 {
-	int r = 0;
-	struct dm_task *dmt;
+	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
 	uint64_t start, length;
 	char *target_type = NULL;
 	char *params;
 
 	if (!(dmt = libmp_dm_task_create(DM_DEVICE_TABLE)))
-		return 0;
+		return DM_TYPE_ERR;
 
 	if (!dm_task_set_name(dmt, name))
-		goto out;
+		return DM_TYPE_ERR;
 
 	if (!libmp_dm_task_run(dmt)) {
 		dm_log_error(3, DM_DEVICE_TABLE, dmt);
-		goto out;
+		return DM_TYPE_ERR;
 	}
 
 	/* Fetch 1st target */
 	if (dm_get_next_target(dmt, NULL, &start, &length,
 			       &target_type, &params) != NULL)
 		/* multiple targets */
-		r = -1;
+		return DM_TYPE_MULTI;
 	else if (!target_type)
-		r = -1;
+		return DM_TYPE_EMPTY;
 	else if (!strcmp(target_type, type))
-		r = 1;
-
-out:
-	dm_task_destroy(dmt);
-	return r;
+		return DM_TYPE_MATCH;
+	else
+		return DM_TYPE_NOMATCH;
 }
 
-/*
- * returns:
- * 1  : is multipath device
- * 0  : is not multipath device
- * -1 : error
- */
 int dm_is_mpath(const char *name)
 {
-	int r = -1;
-	struct dm_task *dmt;
+	int r = DM_IS_MPATH_ERR;
+	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
 	struct dm_info info;
 	uint64_t start, length;
 	char *target_type = NULL;
@@ -874,41 +860,39 @@ int dm_is_mpath(const char *name)
 		goto out;
 
 	if (!dm_task_set_name(dmt, name))
-		goto out_task;
+		goto out;
 
 	if (!libmp_dm_task_run(dmt)) {
 		dm_log_error(3, DM_DEVICE_TABLE, dmt);
-		goto out_task;
+		goto out;
 	}
 
 	if (!dm_task_get_info(dmt, &info))
-		goto out_task;
+		goto out;
 
-	r = 0;
+	r = DM_IS_MPATH_NO;
 
 	if (!info.exists)
-		goto out_task;
+		goto out;
 
 	uuid = dm_task_get_uuid(dmt);
 
 	if (!uuid || strncmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN) != 0)
-		goto out_task;
+		goto out;
 
 	/* Fetch 1st target */
 	if (dm_get_next_target(dmt, NULL, &start, &length, &target_type,
 			       &params) != NULL)
 		/* multiple targets */
-		goto out_task;
+		goto out;
 
 	if (!target_type || strcmp(target_type, TGT_MPATH) != 0)
-		goto out_task;
+		goto out;
 
-	r = 1;
-out_task:
-	dm_task_destroy(dmt);
+	r = DM_IS_MPATH_YES;
 out:
 	if (r < 0)
-		condlog(3, "%s: dm command failed in %s: %s", name, __FUNCTION__, strerror(errno));
+		condlog(3, "%s: dm command failed in %s: %s", name, __func__, strerror(errno));
 	return r;
 }
 
@@ -1049,7 +1033,7 @@ int _dm_flush_map (const char *mapname, int flags, int retries)
 	unsigned long long mapsize;
 	char *params = NULL;
 
-	if (dm_is_mpath(mapname) != 1)
+	if (dm_is_mpath(mapname) != DM_IS_MPATH_YES)
 		return DM_FLUSH_OK; /* nothing to do */
 
 	/* if the device currently has no partitions, do not
@@ -1096,7 +1080,7 @@ int _dm_flush_map (const char *mapname, int flags, int retries)
 			}
 			condlog(4, "multipath map %s removed", mapname);
 			return DM_FLUSH_OK;
-		} else if (dm_is_mpath(mapname) != 1) {
+		} else if (dm_is_mpath(mapname) != DM_IS_MPATH_YES) {
 			condlog(4, "multipath map %s removed externally",
 				mapname);
 			return DM_FLUSH_OK; /* raced. someone else removed it */
@@ -1131,10 +1115,10 @@ dm_flush_map_nopaths(const char *mapname, int deferred_remove __DR_UNUSED__)
 	return _dm_flush_map(mapname, flags, 0);
 }
 
-int dm_flush_maps (int retries)
+int dm_flush_maps(int retries)
 {
 	int r = DM_FLUSH_FAIL;
-	struct dm_task *dmt;
+	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
 	struct dm_names *names;
 	unsigned next = 0;
 
@@ -1143,15 +1127,15 @@ int dm_flush_maps (int retries)
 
 	if (!libmp_dm_task_run (dmt)) {
 		dm_log_error(3, DM_DEVICE_LIST, dmt);
-		goto out;
+		return r;
 	}
 
 	if (!(names = dm_task_get_names (dmt)))
-		goto out;
+		return r;
 
 	r = DM_FLUSH_OK;
 	if (!names->dev)
-		goto out;
+		return r;
 
 	do {
 		int ret;
@@ -1163,16 +1147,13 @@ int dm_flush_maps (int retries)
 		names = (void *) names + next;
 	} while (next);
 
-out:
-	dm_task_destroy (dmt);
 	return r;
 }
 
 int
 dm_message(const char * mapname, char * message)
 {
-	int r = 1;
-	struct dm_task *dmt;
+	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
 
 	if (!(dmt = libmp_dm_task_create(DM_DEVICE_TARGET_MSG)))
 		return 1;
@@ -1191,13 +1172,10 @@ dm_message(const char * mapname, char * message)
 		goto out;
 	}
 
-	r = 0;
+	return 0;
 out:
-	if (r)
-		condlog(0, "DM message failed [%s]", message);
-
-	dm_task_destroy(dmt);
-	return r;
+	condlog(0, "DM message failed [%s]", message);
+	return 1;
 }
 
 int
@@ -1305,12 +1283,10 @@ out:
 	return NULL;
 }
 
-int
-dm_get_maps (vector mp)
+int dm_get_maps(vector mp)
 {
 	struct multipath * mpp;
-	int r = 1;
-	struct dm_task *dmt;
+	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
 	struct dm_names *names;
 	unsigned next = 0;
 
@@ -1322,28 +1298,28 @@ dm_get_maps (vector mp)
 
 	if (!libmp_dm_task_run(dmt)) {
 		dm_log_error(3, DM_DEVICE_LIST, dmt);
-		goto out;
+		return 1;
 	}
 
 	if (!(names = dm_task_get_names(dmt)))
-		goto out;
+		return 1;
 
 	if (!names->dev) {
-		r = 0; /* this is perfectly valid */
-		goto out;
+		/* this is perfectly valid */
+		return 0;
 	}
 
 	do {
-		if (dm_is_mpath(names->name) != 1)
+		if (dm_is_mpath(names->name) != DM_IS_MPATH_YES)
 			goto next;
 
 		mpp = dm_get_multipath(names->name);
 		if (!mpp)
-			goto out;
+			return 1;
 
 		if (!vector_alloc_slot(mp)) {
 			free_multipath(mpp, KEEP_PATHS);
-			goto out;
+			return 1;
 		}
 
 		vector_set_slot(mp, mpp);
@@ -1352,11 +1328,7 @@ next:
 		names = (void *) names + next;
 	} while (next);
 
-	r = 0;
-	goto out;
-out:
-	dm_task_destroy (dmt);
-	return r;
+	return 0;
 }
 
 int
@@ -1419,10 +1391,10 @@ do_foreach_partmaps (const char * mapname,
 		     int (*partmap_func)(const char *, void *),
 		     void *data)
 {
-	struct dm_task *dmt;
+	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
+	char __attribute__((cleanup(cleanup_charp))) *params = NULL;
 	struct dm_names *names;
 	unsigned next = 0;
-	char *params = NULL;
 	unsigned long long size;
 	char dev_t[32];
 	int r = 1;
@@ -1431,28 +1403,25 @@ do_foreach_partmaps (const char * mapname,
 	if (!(dmt = libmp_dm_task_create(DM_DEVICE_LIST)))
 		return 1;
 
-	if (!libmp_dm_task_run(dmt)) {
-		dm_log_error(3, DM_DEVICE_LIST, dmt);
-		goto out;
-	}
+	if (!libmp_dm_task_run(dmt))
+		return 1;
 
 	if (!(names = dm_task_get_names(dmt)))
-		goto out;
+		return 1;
 
-	if (!names->dev) {
-		r = 0; /* this is perfectly valid */
-		goto out;
-	}
+	if (!names->dev)
+		/* this is perfectly valid */
+		return 0;
 
 	if (dm_dev_t(mapname, &dev_t[0], 32))
-		goto out;
+		return 1;
 
 	do {
 		if (
 		    /*
 		     * if there is only a single "linear" target
 		     */
-		    (dm_type(names->name, TGT_PART) == 1) &&
+		    (dm_type_match(names->name, TGT_PART) == DM_TYPE_MATCH) &&
 
 		    /*
 		     * and the uuid of the target is a partition of the
@@ -1472,7 +1441,7 @@ do_foreach_partmaps (const char * mapname,
 		    !isdigit(*(p + strlen(dev_t)))
 		   ) {
 			if ((r = partmap_func(names->name, data)) != 0)
-				goto out;
+				return 1;
 		}
 
 		free(params);
@@ -1481,11 +1450,7 @@ do_foreach_partmaps (const char * mapname,
 		names = (void *) names + next;
 	} while (next);
 
-	r = 0;
-out:
-	free(params);
-	dm_task_destroy (dmt);
-	return r;
+	return 0;
 }
 
 struct remove_data {
@@ -1623,7 +1588,7 @@ int
 dm_rename (const char * old, char * new, char *delim, int skip_kpartx)
 {
 	int r = 0;
-	struct dm_task *dmt;
+	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
 	uint32_t cookie = 0;
 	uint16_t udev_flags = DM_UDEV_DISABLE_LIBRARY_FALLBACK | ((skip_kpartx == SKIP_KPARTX_ON)? MPATH_UDEV_NO_KPARTX_FLAG : 0);
 
@@ -1634,22 +1599,19 @@ dm_rename (const char * old, char * new, char *delim, int skip_kpartx)
 		return r;
 
 	if (!dm_task_set_name(dmt, old))
-		goto out;
+		return r;
 
 	if (!dm_task_set_newname(dmt, new))
-		goto out;
+		return r;
 
 	if (!dm_task_set_cookie(dmt, &cookie, udev_flags))
-		goto out;
+		return r;
+
 	r = libmp_dm_task_run(dmt);
 	if (!r)
 		dm_log_error(2, DM_DEVICE_RENAME, dmt);
 
 	libmp_udev_wait(cookie);
-
-out:
-	dm_task_destroy(dmt);
-
 	return r;
 }
 
@@ -1672,9 +1634,10 @@ void dm_reassign_deps(char *table, const char *dep, const char *newdep)
 
 int dm_reassign_table(const char *name, char *old, char *new)
 {
-	int r = 0, modified = 0;
+	int modified = 0;
 	uint64_t start, length;
-	struct dm_task *dmt, *reload_dmt;
+	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
+	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *reload_dmt = NULL;
 	char *target, *params = NULL;
 	char *buff;
 	void *next = NULL;
@@ -1683,16 +1646,16 @@ int dm_reassign_table(const char *name, char *old, char *new)
 		return 0;
 
 	if (!dm_task_set_name(dmt, name))
-		goto out;
+		return 0;
 
 	if (!libmp_dm_task_run(dmt)) {
 		dm_log_error(3, DM_DEVICE_TABLE, dmt);
-		goto out;
+		return 0;
 	}
 	if (!(reload_dmt = libmp_dm_task_create(DM_DEVICE_RELOAD)))
-		goto out;
+		return 0;
 	if (!dm_task_set_name(reload_dmt, name))
-		goto out_reload;
+		return 0;
 
 	do {
 		next = dm_get_next_target(dmt, next, &start, &length,
@@ -1705,13 +1668,13 @@ int dm_reassign_table(const char *name, char *old, char *new)
 			 */
 			condlog(1, "%s: invalid target found in map %s",
 				__func__, name);
-			goto out_reload;
+			return 0;
 		}
 		buff = strdup(params);
 		if (!buff) {
 			condlog(3, "%s: failed to replace target %s, "
 				"out of memory", name, target);
-			goto out_reload;
+			return 0;
 		}
 		if (strcmp(target, TGT_MPATH) && strstr(params, old)) {
 			condlog(3, "%s: replace target %s %s",
@@ -1729,18 +1692,12 @@ int dm_reassign_table(const char *name, char *old, char *new)
 		if (!libmp_dm_task_run(reload_dmt)) {
 			dm_log_error(3, DM_DEVICE_RELOAD, reload_dmt);
 			condlog(3, "%s: failed to reassign targets", name);
-			goto out_reload;
+			return 0;
 		}
 		dm_simplecmd_noflush(DM_DEVICE_RESUME, name,
 				     MPATH_UDEV_RELOAD_FLAG);
 	}
-	r = 1;
-
-out_reload:
-	dm_task_destroy(reload_dmt);
-out:
-	dm_task_destroy(dmt);
-	return r;
+	return 1;
 }
 
 
@@ -1752,10 +1709,9 @@ out:
 int dm_reassign(const char *mapname)
 {
 	struct dm_deps *deps;
-	struct dm_task *dmt;
+	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
 	struct dm_info info;
 	char dev_t[32], dm_dep[32];
-	int r = 0;
 	unsigned int i;
 
 	if (dm_dev_t(mapname, &dev_t[0], 32)) {
@@ -1769,21 +1725,21 @@ int dm_reassign(const char *mapname)
 	}
 
 	if (!dm_task_set_name(dmt, mapname))
-		goto out;
+		return 0;
 
 	if (!libmp_dm_task_run(dmt)) {
 		dm_log_error(3, DM_DEVICE_DEPS, dmt);
-		goto out;
+		return 0;
 	}
 
 	if (!dm_task_get_info(dmt, &info))
-		goto out;
+		return 0;
 
 	if (!(deps = dm_task_get_deps(dmt)))
-		goto out;
+		return 0;
 
 	if (!info.exists)
-		goto out;
+		return 0;
 
 	for (i = 0; i < deps->count; i++) {
 		sprintf(dm_dep, "%d:%d",
@@ -1792,15 +1748,12 @@ int dm_reassign(const char *mapname)
 		sysfs_check_holders(dm_dep, dev_t);
 	}
 
-	r = 1;
-out:
-	dm_task_destroy (dmt);
-	return r;
+	return 1;
 }
 
 int dm_setgeometry(struct multipath *mpp)
 {
-	struct dm_task *dmt;
+	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
 	struct path *pp;
 	char heads[4], sectors[4];
 	char cylinders[10], start[32];
@@ -1825,7 +1778,7 @@ int dm_setgeometry(struct multipath *mpp)
 		return 0;
 
 	if (!dm_task_set_name(dmt, mpp->alias))
-		goto out;
+		return 0;
 
 	/* What a sick interface ... */
 	snprintf(heads, 4, "%u", pp->geom.heads);
@@ -1834,14 +1787,12 @@ int dm_setgeometry(struct multipath *mpp)
 	snprintf(start, 32, "%lu", pp->geom.start);
 	if (!dm_task_set_geometry(dmt, cylinders, heads, sectors, start)) {
 		condlog(3, "%s: Failed to set geometry", mpp->alias);
-		goto out;
+		return 0;
 	}
 
 	r = libmp_dm_task_run(dmt);
 	if (!r)
 		dm_log_error(3, DM_DEVICE_SET_GEOMETRY, dmt);
-out:
-	dm_task_destroy(dmt);
 
 	return r;
 }
diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h
index 19b79c5..9438c2d 100644
--- a/libmultipath/devmapper.h
+++ b/libmultipath/devmapper.h
@@ -46,7 +46,12 @@ int dm_map_present (const char *name);
 int dm_map_present_by_uuid(const char *uuid);
 int dm_get_map(const char *name, unsigned long long *size, char **outparams);
 int dm_get_status(const char *name, char **outstatus);
-int dm_type(const char *name, char *type);
+
+enum {
+	DM_IS_MPATH_NO,
+	DM_IS_MPATH_YES,
+	DM_IS_MPATH_ERR,
+};
 int dm_is_mpath(const char *name);
 
 enum {
diff --git a/multipath/main.c b/multipath/main.c
index ce702e7..c82bc86 100644
--- a/multipath/main.c
+++ b/multipath/main.c
@@ -247,7 +247,7 @@ static int check_usable_paths(struct config *conf,
 		goto out;
 	}
 
-	if (dm_is_mpath(mapname) != 1) {
+	if (dm_is_mpath(mapname) != DM_IS_MPATH_YES) {
 		condlog(1, "%s is not a multipath map", devpath);
 		goto free;
 	}
@@ -1080,7 +1080,7 @@ main (int argc, char *argv[])
 		goto out;
 	}
 	if (cmd == CMD_FLUSH_ONE) {
-		if (dm_is_mpath(dev) != 1) {
+		if (dm_is_mpath(dev) != DM_IS_MPATH_YES) {
 			condlog(0, "%s is not a multipath device", dev);
 			r = RTVL_FAIL;
 			goto out;
diff --git a/multipathd/dmevents.c b/multipathd/dmevents.c
index 3fbdc55..605219e 100644
--- a/multipathd/dmevents.c
+++ b/multipathd/dmevents.c
@@ -170,7 +170,7 @@ static int dm_get_events(void)
 
 		/* Don't delete device if dm_is_mpath() fails without
 		 * checking the device type */
-		if (dm_is_mpath(names->name) == 0)
+		if (dm_is_mpath(names->name) != DM_IS_MPATH_YES)
 			goto next;
 
 		event_nr = dm_event_nr(names);
@@ -208,7 +208,7 @@ int watch_dmevents(char *name)
 
 	/* We know that this is a multipath device, so only fail if
 	 * device-mapper tells us that we're wrong */
-	if (dm_is_mpath(name) == 0) {
+	if (dm_is_mpath(name) != DM_IS_MPATH_YES) {
 		condlog(0, "%s: not a multipath device. can't watch events",
 			name);
 		return -1;
diff --git a/multipathd/main.c b/multipathd/main.c
index 58afe14..132bb2e 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -865,7 +865,7 @@ ev_add_map (char * dev, const char * alias, struct vectors * vecs)
 	int reassign_maps;
 	struct config *conf;
 
-	if (dm_is_mpath(alias) != 1) {
+	if (dm_is_mpath(alias) != DM_IS_MPATH_YES) {
 		condlog(4, "%s: not a multipath map", alias);
 		return 0;
 	}
-- 
2.45.2


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

* [PATCH 17/44] libmultipath: add libmp_mapinfo()
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (15 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 16/44] libmultipath: add cleanup_dm_task(), and use it in devmapper.c Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-10 22:53   ` Benjamin Marzinski
  2024-07-09 21:39 ` [PATCH 18/44] libmultipath tests: add tests for libmp_mapinfo() Martin Wilck
                   ` (27 subsequent siblings)
  44 siblings, 1 reply; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

libmp_mapinfo() is intended as a generic abstraction for retrieving information from
the kernel device-mapper driver. It retrieves the information that the caller
needs, with a minimal set of DM ioctls, and never more then 2 ioctl calls.

libdm's DM_DEVICE_TABLE and DM_DEVICE_STATUS calls map to the kernel's
DM_TABLE_STATUS ioctl, with or without the DM_STATUS_TABLE_FLAG set,
respectively. DM_TABLE_STATUS always retrieves the basic map status (struct
dm_info) and the map UUID and name, too.

Note: I'd prefer to use an unnamed struct instead of _u in
union libmp_map_identifer. But doing using an unnamed struct and and
initializing the union like this in a function argument:

  func((mapid_t) { .major = major, .minor = minor })

is not part of C99, and not supported in gcc 4.8, which we still support.

Likewise, the following syntax for initializing an empty struct:

  (mapinfo_t) { 0 }

is not supported on all architectures we support (notably clang 3.5 under
Debian Jessie).

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmultipath/devmapper.c          | 181 +++++++++++++++++++++++++++++-
 libmultipath/devmapper.h          |  66 +++++++++++
 libmultipath/libmultipath.version |   3 +-
 3 files changed, 248 insertions(+), 2 deletions(-)

diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index 3685ef7..5c9f9d8 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -14,7 +14,6 @@
 #include <errno.h>
 #include <syslog.h>
 #include <sys/sysmacros.h>
-#include <linux/dm-ioctl.h>
 
 #include "util.h"
 #include "vector.h"
@@ -604,6 +603,186 @@ has_dm_info(const struct multipath *mpp)
 	return (mpp && mpp->dmi.exists != 0);
 }
 
+static int libmp_set_map_identifier(int flags, mapid_t id, struct dm_task *dmt)
+{
+	switch (flags & __DM_MAP_BY_MASK) {
+	case DM_MAP_BY_UUID:
+		if (!id.str || !(*id.str))
+			return 0;
+		return dm_task_set_uuid(dmt, id.str);
+	case DM_MAP_BY_NAME:
+		if (!id.str || !(*id.str))
+			return 0;
+		return dm_task_set_name(dmt, id.str);
+	case DM_MAP_BY_DEV:
+		if (!dm_task_set_major(dmt, id._u.major))
+			return 0;
+		return  dm_task_set_minor(dmt, id._u.minor);
+	default:
+		condlog(0, "%s: invalid by_id", __func__);
+		return 0;
+	}
+}
+
+static int libmp_mapinfo__(int flags, mapid_t id, mapinfo_t info, const char *map_id)
+{
+	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
+	struct dm_info dmi;
+	int rc, ioctl_nr;
+	uint64_t start, length = 0;
+	char *target_type = NULL, *params = NULL;
+	const char *name = NULL, *uuid = NULL;
+	char __attribute__((cleanup(cleanup_charp))) *tmp_target = NULL;
+	char __attribute__((cleanup(cleanup_charp))) *tmp_status = NULL;
+	bool tgt_set = false;
+
+	/*
+	 * If both info.target and info.status are set, we need two
+	 * ioctls. Call this function recursively.
+	 * If successful, tmp_target will be non-NULL.
+	 */
+	if (info.target && info.status) {
+		rc = libmp_mapinfo__(flags, id,
+				     (mapinfo_t) {
+					     .target = &tmp_target,
+					     .tgt_type = info.tgt_type,
+				     },
+				     map_id);
+		if (rc != DMP_OK)
+			return rc;
+		tgt_set = true;
+	}
+
+	/*
+	 * The DM_DEVICE_TABLE and DM_DEVICE_STATUS ioctls both fetch the basic
+	 * information from DM_DEVICE_INFO, too.
+	 * Choose the most lightweight ioctl to fetch all requested info.
+	 */
+	if (info.target && !info.status)
+		ioctl_nr = DM_DEVICE_TABLE;
+	else if (info.status || info.size || info.tgt_type)
+		ioctl_nr = DM_DEVICE_STATUS;
+	else
+		ioctl_nr = DM_DEVICE_INFO;
+
+	if (!(dmt = libmp_dm_task_create(ioctl_nr)))
+		return DMP_ERR;
+
+	if (!libmp_set_map_identifier(flags, id, dmt)) {
+		condlog(2, "%s: failed to set map identifier to %s", __func__, map_id);
+		return DMP_ERR;
+	}
+
+	if (!libmp_dm_task_run(dmt)) {
+		dm_log_error(3, ioctl_nr, dmt);
+		if (dm_task_get_errno(dmt) == ENXIO) {
+			condlog(2, "%s: map %s not found", __func__, map_id);
+			return DMP_NOT_FOUND;
+		} else
+			return DMP_ERR;
+	}
+
+	condlog(4, "%s: DM ioctl %d succeeded for %s",
+		__func__, ioctl_nr, map_id);
+
+	if (!dm_task_get_info(dmt, &dmi) || !dmi.exists) {
+		condlog(2, "%s: map %s doesn't exist", __func__, map_id);
+		return DMP_NOT_FOUND;
+	}
+
+	if (info.target || info.status || info.size || info.tgt_type) {
+		if (dm_get_next_target(dmt, NULL, &start, &length,
+				       &target_type, &params) != NULL) {
+			condlog(2, "%s: map %s has multiple targets", __func__, map_id);
+			return DMP_NOT_FOUND;
+		}
+		if (!params) {
+			condlog(2, "%s: map %s has no targets", __func__, map_id);
+			return DMP_NOT_FOUND;
+		}
+		if (info.tgt_type && strcmp(info.tgt_type, target_type)) {
+			condlog(3, "%s: target type mismatch: \"%s\" != \"%s\"",
+				__func__, info.tgt_type, target_type);
+			return DMP_NO_MATCH;
+		}
+	}
+
+	/*
+	 * Check possible error conditions.
+	 * If error is returned, don't touch any output parameters.
+	 */
+	if ((info.name && !(name = dm_task_get_name(dmt)))
+	    || (info.uuid && !(uuid = dm_task_get_uuid(dmt)))
+	    || (info.status && !(tmp_status = strdup(params)))
+	    || (info.target && !tmp_target && !(tmp_target = strdup(params))))
+		return DMP_ERR;
+
+	if (info.name) {
+		strlcpy(info.name, name, WWID_SIZE);
+		condlog(4, "%s: %s: name: \"%s\"", __func__, map_id, info.name);
+	}
+	if (info.uuid) {
+		strlcpy(info.uuid, uuid, DM_UUID_LEN);
+		condlog(4, "%s: %s: uuid: \"%s\"", __func__, map_id, info.uuid);
+	}
+
+	if (info.size) {
+		*info.size = length;
+		condlog(4, "%s: %s: size: %lld", __func__, map_id, *info.size);
+	}
+
+	if (info.dmi) {
+		memcpy(info.dmi, &dmi, sizeof(*info.dmi));
+		condlog(4, "%s: %s %d:%d, %d targets, %s table, %s, %s, %d opened, %u events",
+			__func__, map_id,
+			info.dmi->major, info.dmi->minor,
+			info.dmi->target_count,
+			info.dmi->live_table ? "live" :
+				info.dmi->inactive_table ? "inactive" : "no",
+			info.dmi->suspended ? "suspended" : "active",
+			info.dmi->read_only ? "ro" : "rw",
+			info.dmi->open_count,
+			info.dmi->event_nr);
+	}
+
+	if (info.target) {
+		*info.target = steal_ptr(tmp_target);
+		if (!tgt_set)
+			condlog(4, "%s: %s: target: \"%s\"", __func__, map_id, *info.target);
+	}
+
+	if (info.status) {
+		*info.status = steal_ptr(tmp_status);
+		condlog(4, "%s: %s: status: \"%s\"", __func__, map_id, *info.status);
+	}
+
+	return DMP_OK;
+}
+
+/* Helper: format a string describing the map for log messages */
+static const char* libmp_map_identifier(int flags, mapid_t id, char buf[BLK_DEV_SIZE])
+{
+	switch (flags & __DM_MAP_BY_MASK) {
+	case DM_MAP_BY_NAME:
+	case DM_MAP_BY_UUID:
+		return id.str;
+	case DM_MAP_BY_DEV:
+		safe_snprintf(buf, BLK_DEV_SIZE, "%d:%d", id._u.major, id._u.minor);
+		return buf;
+	default:
+		safe_snprintf(buf, BLK_DEV_SIZE, "*invalid*");
+		return buf;
+	}
+}
+
+int libmp_mapinfo(int flags, mapid_t id, mapinfo_t info)
+{
+	char idbuf[BLK_DEV_SIZE];
+
+	return libmp_mapinfo__(flags, id, info,
+			       libmp_map_identifier(flags, id, idbuf));
+}
+
 int
 dm_get_info(const char *name, struct dm_info *info)
 {
diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h
index 9438c2d..269389b 100644
--- a/libmultipath/devmapper.h
+++ b/libmultipath/devmapper.h
@@ -1,5 +1,6 @@
 #ifndef _DEVMAPPER_H
 #define _DEVMAPPER_H
+#include <linux/dm-ioctl.h>
 #include "autoconfig.h"
 #include "structs.h"
 
@@ -31,8 +32,73 @@ enum {
 	DMP_ERR,
 	DMP_OK,
 	DMP_NOT_FOUND,
+	DMP_NO_MATCH,
 };
 
+/**
+ * enum mapinfo_flags: input flags for libmp_mapinfo()
+ */
+enum __mapinfo_flags {
+	/** DM_MAP_BY_NAME: identify map by device-mapper name from @name */
+	DM_MAP_BY_NAME      = 0,
+	/** DM_MAP_BY_UUID: identify map by device-mapper UUID from @uuid */
+	DM_MAP_BY_UUID,
+	/** DM_MAP_BY_DEV: identify map by major/minor number from @dmi */
+	DM_MAP_BY_DEV,
+	__DM_MAP_BY_MASK    = (1 << 3) - 1,
+};
+
+typedef union libmp_map_identifier {
+	const char *str;
+	struct {
+		int major;
+		int minor;
+	} _u;
+} mapid_t;
+
+typedef struct libmp_map_info {
+	/** @name: name of the map.
+	 * If non-NULL, it must point to an array of WWID_SIZE bytes
+	 */
+	char *name;
+	/** @uuid: UUID of the map.
+	 * If non-NULL it must point to an array of DM_UUID_LEN bytes
+	 */
+	char *uuid;
+	/** @dmi: Basic info, must point to a valid dm_info buffer if non-NULL */
+	struct dm_info *dmi;
+	/** @target: target params, *@target will be allocated if @target is non-NULL*/
+	char **target;
+	/** @size: target size. Will be ignored if @target is NULL */
+	unsigned long long *size;
+	/** @status: target status, *@status will be allocated if @status is non-NULL */
+	char **status;
+	/** @tgt_type: (input) set to a target type, e.g. "multipath" to limit
+	 * successful return to just this target type in libmp_mapinfo().
+	 */
+	const char *tgt_type;
+} mapinfo_t;
+
+/**
+ * libmp_mapinfo(): obtain information about a map from the kernel
+ * @param flags: see __mapinfo_flags above.
+ *     Exactly one of DM_MAP_BY_NAME, DM_MAP_BY_UUID, and DM_MAP_BY_DEV must be set.
+ * @param id: string or major/minor to identify the map to query
+ * @param info: output parameters, see above. Non-NULL elements will be filled in.
+ * @returns:
+ *     DMP_OK if successful.
+ *     DMP_NOT_FOUND if the map wasn't found, or has no or multiple targets.
+ *     DMP_NO_MATCH if the map didn't match @tgt_type (see above).
+ *     DMP_ERR if some other error occurred.
+ *
+ * This function obtains the requested information for the device-mapper map
+ * identified by the input parameters.
+ * Output parameters are only filled in if the return value is DMP_OK.
+ * For target / status / size information, the  map's table should contain
+ * only one target (usually multipath or linear).
+ */
+int libmp_mapinfo(int flags, mapid_t id, mapinfo_t info);
+
 int dm_prereq(unsigned int *v);
 void skip_libmp_dm_init(void);
 void libmp_dm_exit(void);
diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version
index f58cb1d..48c2b67 100644
--- a/libmultipath/libmultipath.version
+++ b/libmultipath/libmultipath.version
@@ -43,7 +43,7 @@ LIBMPATHCOMMON_1.0.0 {
 	put_multipath_config;
 };
 
-LIBMULTIPATH_24.0.0 {
+LIBMULTIPATH_25.0.0 {
 global:
 	/* symbols referenced by multipath and multipathd */
 	add_foreign;
@@ -134,6 +134,7 @@ global:
 	libmp_get_version;
 	libmp_get_multipath_config;
 	libmp_dm_task_run;
+	libmp_mapinfo;
 	libmp_put_multipath_config;
 	libmp_udev_set_sync_support;
 	libmultipath_exit;
-- 
2.45.2


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

* [PATCH 18/44] libmultipath tests: add tests for libmp_mapinfo()
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (16 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 17/44] libmultipath: add libmp_mapinfo() Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-09 21:39 ` [PATCH 19/44] libmultipath: implement dm_get_info() and dm_map_present() with new API Martin Wilck
                   ` (26 subsequent siblings)
  44 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

Unfortunately, we need several ugly compatibility macros again
in order to make these tests work with the entire set of compilers
and libraries supported by multipath-tools. Details are found in
comments in the code.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 tests/Makefile  |    3 +-
 tests/mapinfo.c | 1121 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 1123 insertions(+), 1 deletion(-)
 create mode 100644 tests/mapinfo.c

diff --git a/tests/Makefile b/tests/Makefile
index 8afa8c6..55fbf0f 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -9,7 +9,7 @@ CFLAGS += $(BIN_CFLAGS) -Wno-unused-parameter $(W_MISSING_INITIALIZERS)
 LIBDEPS += -L. -L $(mpathutildir) -L$(mpathcmddir) -lmultipath -lmpathutil -lmpathcmd -lcmocka
 
 TESTS := uevent parser util dmevents hwtable blacklist unaligned vpd pgpolicy \
-	 alias directio valid devt mpathvalid strbuf sysfs features cli
+	 alias directio valid devt mpathvalid strbuf sysfs features cli mapinfo
 HELPERS := test-lib.o test-log.o
 
 .PRECIOUS: $(TESTS:%=%-test)
@@ -68,6 +68,7 @@ sysfs-test_OBJDEPS := $(multipathdir)/sysfs.o $(mpathutildir)/util.o
 sysfs-test_LIBDEPS := -ludev -lpthread -ldl
 features-test_LIBDEPS := -ludev -lpthread
 cli-test_OBJDEPS := $(daemondir)/cli.o
+mapinfo-test_LIBDEPS = -lpthread -ldevmapper
 
 %.o: %.c
 	@echo building $@ because of $?
diff --git a/tests/mapinfo.c b/tests/mapinfo.c
new file mode 100644
index 0000000..eb61d2e
--- /dev/null
+++ b/tests/mapinfo.c
@@ -0,0 +1,1121 @@
+/*
+ * Copyright (c) 2024 Martin Wilck, SUSE
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+/*
+ * glibc <= 2.19 (Ubuntu Trusty, Debian Jessie) uses macros to inline strdup(),
+ * which makes our strdup wrapper fail.
+ */
+#define _GNU_SOURCE 1
+#include <features.h>
+#include <linux/types.h>
+#ifndef __GLIBC_PREREQ
+#define __GLIBC_PREREQ(x, y) 0
+#endif
+#if defined(__GLIBC__) && !(__GLIBC_PREREQ(2, 20))
+#define __NO_STRING_INLINES 1
+#endif
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <cmocka.h>
+#include "util.h"
+#include "devmapper.h"
+#include "globals.c"
+/*
+ * We can't just use mapinfo-test_OBJDEPS because
+ */
+#include "../libmultipath/devmapper.c"
+
+static const struct dm_info __attribute__((unused)) MPATH_DMI_01 = {
+	.exists = 1,
+	.live_table = 1,
+	.open_count = 1,
+	.target_count = 1,
+	.major = 254,
+	.minor = 123,
+};
+
+static const char __attribute__((unused)) MPATH_NAME_01[] = "mpathx";
+static const char __attribute__((unused)) MPATH_UUID_01[] =
+	"mpath-3600a098038302d414b2b4d4453474f62";
+static const char __attribute__((unused)) MPATH_TARGET_01[] =
+	"2 pg_init_retries 50 1 alua 2 1 "
+	"service-time 0 3 2 65:32 1 1 67:64 1 1 69:96 1 1 "
+	"service-time 0 3 2 8:16 1 1 66:48 1 1 68:80 1 1 ";
+static const char __attribute__((unused)) MPATH_STATUS_01[] =
+	"2 0 1 0 2 1 "
+	"A 0 3 2 65:32 A 0 0 1 67:64 A 0 0 1 69:96 A 0 0 1 "
+	"E 0 3 2 8:16 A 0 0 1 66:48 A 0 0 1 68:80 A 0 0 1 ";
+
+char *__real_strdup(const char *str);
+char *__wrap_strdup(const char *str)
+{
+	if (mock_type(int))
+		return __real_strdup(str);
+	return NULL;
+}
+
+void __wrap_dm_task_destroy(struct dm_task *t)
+{
+}
+
+struct dm_task *__wrap_dm_task_create(int task)
+{
+	check_expected(task);
+	return mock_ptr_type(void *);
+}
+
+int __wrap_dm_task_run(struct dm_task *t)
+{
+	return mock_type(int);
+}
+
+/*
+ * Hack for older versions of libdevmapper, where dm_task_get_errno()
+ * is not available.
+ */
+#ifndef LIBDM_API_GET_ERRNO
+#define WILL_RETURN_GET_ERRNO(y) do { errno = y; } while (0)
+#else
+int __wrap_dm_task_get_errno(struct dm_task *t)
+{
+	return mock_type(int);
+}
+#define WILL_RETURN_GET_ERRNO(y) will_return(__wrap_dm_task_get_errno, y)
+#endif
+
+int __wrap_dm_task_set_name(struct dm_task *t, const char *name)
+{
+	check_expected(name);
+	return mock_type(int);
+}
+
+int __wrap_dm_task_set_uuid(struct dm_task *t, const char *uuid)
+{
+	check_expected(uuid);
+	return mock_type(int);
+}
+
+int __wrap_dm_task_set_major(struct dm_task *t, int val)
+{
+	check_expected(val);
+	return mock_type(int);
+}
+
+int __wrap_dm_task_set_minor(struct dm_task *t, int val)
+{
+	check_expected(val);
+	return mock_type(int);
+}
+
+/* between LVM2 2.02.110 and 2.02.112, dm_task_get_info was a macro */
+#ifdef dm_task_get_info
+#define WRAP_DM_TASK_GET_INFO(x) \
+	will_return(__wrap_dm_task_get_info_with_deferred_remove, x)
+int __wrap_dm_task_get_info_with_deferred_remove(struct dm_task *t, struct dm_info *dmi)
+#else
+#define WRAP_DM_TASK_GET_INFO(x) \
+	will_return(__wrap_dm_task_get_info, x)
+int __wrap_dm_task_get_info(struct dm_task *t, struct dm_info *dmi)
+#endif
+{
+	int rc = mock_type(int);
+
+	assert_non_null(dmi);
+	if (rc) {
+		struct dm_info *info = mock_ptr_type(struct dm_info *);
+
+		memcpy(dmi, info, sizeof(*dmi));
+	}
+	return rc;
+}
+
+void * __wrap_dm_get_next_target(struct dm_task *dmt, void *next,
+				uint64_t *start, uint64_t *length,
+				char **target_type, char **params)
+{
+	*start = 0;
+	*length = mock_type(uint64_t);
+	*target_type = mock_ptr_type(char *);
+	*params = mock_ptr_type(char *);
+	return mock_ptr_type(void *);
+}
+
+static void mock_dm_get_next_target(uint64_t len, const char *target_type,
+				    const char *params, void *next)
+{
+	will_return(__wrap_dm_get_next_target, len);
+	will_return(__wrap_dm_get_next_target, target_type);
+	will_return(__wrap_dm_get_next_target, params);
+	will_return(__wrap_dm_get_next_target, next);
+}
+
+const char *__wrap_dm_task_get_name(struct dm_task *t)
+{
+	return mock_ptr_type(const char *);
+}
+
+const char *__wrap_dm_task_get_uuid(struct dm_task *t)
+{
+	return mock_ptr_type(const char *);
+}
+
+static void mock_mapinfo_name_1(int ioctl_nr, int create_rc, const char *name,
+				int name_rc, int run_rc, int err)
+{
+	expect_value(__wrap_dm_task_create, task, ioctl_nr);
+	will_return(__wrap_dm_task_create, create_rc);
+	if (create_rc == 0)
+		return;
+	expect_value(__wrap_dm_task_set_name, name, name);
+	will_return(__wrap_dm_task_set_name, name_rc);
+	if (name_rc == 0)
+		return;
+	will_return(__wrap_dm_task_run, run_rc);
+	if (run_rc == 0) {
+		WILL_RETURN_GET_ERRNO(err);
+		/* for dm_log_error() */
+		WILL_RETURN_GET_ERRNO(err);
+	}
+}
+
+static void test_mapinfo_bad_task_create_01(void **state)
+{
+	int rc;
+
+	mock_mapinfo_name_1(DM_DEVICE_INFO, 0, NULL, 0, 0, 0);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .name = NULL });
+	assert_int_equal(rc, DMP_ERR);
+}
+
+static void test_mapinfo_bad_mapid(void **state)
+{
+	int rc;
+
+	/* can't use mock_mapinfo_name() here because of invalid id type */
+	expect_value(__wrap_dm_task_create, task, DM_DEVICE_INFO);
+	will_return(__wrap_dm_task_create, 1);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME + 100,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .name = NULL });
+	assert_int_equal(rc, DMP_ERR);
+}
+
+static void test_mapinfo_bad_set_name(void **state)
+{
+	int rc;
+
+	mock_mapinfo_name_1(DM_DEVICE_INFO, 1, "foo", 0, 0, 0);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .name = NULL });
+	assert_int_equal(rc, DMP_ERR);
+}
+
+static void test_mapinfo_bad_task_run_01(void **state)
+{
+	int rc;
+
+	mock_mapinfo_name_1(DM_DEVICE_INFO, 1, "foo", 1, 0, EINVAL);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .name = NULL });
+	assert_int_equal(rc, DMP_ERR);
+}
+
+static void test_mapinfo_bad_task_run_02(void **state)
+{
+	int rc;
+
+	mock_mapinfo_name_1(DM_DEVICE_INFO, 1, "foo", 1, 0, ENXIO);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .name = NULL });
+	assert_int_equal(rc, DMP_NOT_FOUND);
+}
+
+/* If tgt_type is set, libmp_mapinfo must choose DM_DEVICE_STATUS */
+static void test_mapinfo_bad_task_run_03(void **state)
+{
+	int rc;
+
+	mock_mapinfo_name_1(DM_DEVICE_STATUS, 1, "foo", 1, 0, EINVAL);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .tgt_type = TGT_MPATH });
+	assert_int_equal(rc, DMP_ERR);
+}
+
+static void test_mapinfo_bad_task_run_04(void **state)
+{
+	int rc;
+
+	mock_mapinfo_name_1(DM_DEVICE_STATUS, 1, "foo", 1, 0, ENXIO);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .tgt_type = TGT_MPATH });
+	assert_int_equal(rc, DMP_NOT_FOUND);
+}
+
+/* If target is set, libmp_mapinfo must choose DM_DEVICE_TABLE */
+static void test_mapinfo_bad_task_run_05(void **state)
+{
+	int rc;
+	char *params = NULL;
+
+	mock_mapinfo_name_1(DM_DEVICE_TABLE, 1, "foo", 1, 0, EINVAL);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .target = &params });
+	assert_int_equal(rc, DMP_ERR);
+	assert_ptr_equal(params, NULL);
+}
+
+static void test_mapinfo_bad_task_run_06(void **state)
+{
+	int rc;
+	char *params = NULL;
+
+	mock_mapinfo_name_1(DM_DEVICE_TABLE, 1, "foo", 1, 0, ENXIO);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .target = &params });
+	assert_int_equal(rc, DMP_NOT_FOUND);
+	assert_ptr_equal(params, NULL);
+}
+
+/* If status is set, libmp_mapinfo must choose DM_DEVICE_STATUS */
+static void test_mapinfo_bad_task_run_07(void **state)
+{
+	int rc;
+	char *params = NULL;
+
+	mock_mapinfo_name_1(DM_DEVICE_STATUS, 1, "foo", 1, 0, EINVAL);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .status = &params });
+	assert_int_equal(rc, DMP_ERR);
+	assert_ptr_equal(params, NULL);
+}
+
+static void test_mapinfo_bad_task_run_08(void **state)
+{
+	int rc;
+	char *params = NULL;
+
+	mock_mapinfo_name_1(DM_DEVICE_STATUS, 1, "foo", 1, 0, ENXIO);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .status = &params });
+	assert_int_equal(rc, DMP_NOT_FOUND);
+	assert_ptr_equal(params, NULL);
+}
+
+static void test_mapinfo_bad_task_run_09(void **state)
+{
+	int rc;
+	char *params = NULL, *status = NULL;
+
+	mock_mapinfo_name_1(DM_DEVICE_TABLE, 1, "foo", 1, 0, EINVAL);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .target = &params, .status = &status });
+	assert_int_equal(rc, DMP_ERR);
+	assert_ptr_equal(params, NULL);
+	assert_ptr_equal(status, NULL);
+}
+
+static void test_mapinfo_bad_task_run_10(void **state)
+{
+	int rc;
+	char *params = NULL, *status = NULL;
+
+	mock_mapinfo_name_1(DM_DEVICE_TABLE, 1, "foo", 1, 0, ENXIO);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .target = &params, .status = &status });
+	assert_int_equal(rc, DMP_NOT_FOUND);
+	assert_ptr_equal(params, NULL);
+	assert_ptr_equal(status, NULL);
+}
+
+static void test_mapinfo_bad_get_info_01(void **state)
+{
+	int rc;
+
+	mock_mapinfo_name_1(DM_DEVICE_INFO, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(0);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .name = NULL });
+	assert_int_equal(rc, DMP_NOT_FOUND);
+}
+
+static void test_mapinfo_bad_get_info_02(void **state)
+{
+	int rc;
+	struct dm_info dmi = { .suspended = 0 };
+
+	mock_mapinfo_name_1(DM_DEVICE_INFO, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&dmi);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .name = NULL });
+	assert_int_equal(rc, DMP_NOT_FOUND);
+}
+
+static void test_mapinfo_bad_get_info_03(void **state)
+{
+	int rc;
+
+	mock_mapinfo_name_1(DM_DEVICE_STATUS, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(0);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .tgt_type = TGT_PART });
+	assert_int_equal(rc, DMP_NOT_FOUND);
+}
+
+static void test_mapinfo_bad_get_info_04(void **state)
+{
+	int rc;
+	struct dm_info dmi = { .suspended = 0 };
+
+	mock_mapinfo_name_1(DM_DEVICE_STATUS, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&dmi);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .tgt_type = TGT_PART });
+	assert_int_equal(rc, DMP_NOT_FOUND);
+}
+
+static void test_mapinfo_good_exists(void **state)
+{
+	int rc;
+
+	mock_mapinfo_name_1(DM_DEVICE_INFO, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&MPATH_DMI_01);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .name = NULL });
+	assert_int_equal(rc, DMP_OK);
+}
+
+static void test_mapinfo_bad_set_uuid(void **state)
+{
+	int rc;
+
+	expect_value(__wrap_dm_task_create, task, DM_DEVICE_INFO);
+	will_return(__wrap_dm_task_create, 1);
+	expect_value(__wrap_dm_task_set_uuid, uuid, "foo");
+	will_return(__wrap_dm_task_set_uuid, 0);
+	rc = libmp_mapinfo(DM_MAP_BY_UUID,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .name = NULL });
+	assert_int_equal(rc, DMP_ERR);
+}
+
+static void test_mapinfo_bad_set_dev_01(void **state)
+{
+	int rc;
+
+	expect_value(__wrap_dm_task_create, task, DM_DEVICE_INFO);
+	will_return(__wrap_dm_task_create, 1);
+	expect_value(__wrap_dm_task_set_major, val, 254);
+	will_return(__wrap_dm_task_set_major, 0);
+	rc = libmp_mapinfo(DM_MAP_BY_DEV,
+			   (mapid_t) { ._u = { 254, 123 } },
+			   (mapinfo_t) { .name = NULL });
+	assert_int_equal(rc, DMP_ERR);
+}
+
+static void test_mapinfo_bad_set_dev_02(void **state)
+{
+	int rc;
+
+	expect_value(__wrap_dm_task_create, task, DM_DEVICE_INFO);
+	will_return(__wrap_dm_task_create, 1);
+	expect_value(__wrap_dm_task_set_major, val, 254);
+	will_return(__wrap_dm_task_set_major, 1);
+	expect_value(__wrap_dm_task_set_minor, val, 123);
+	will_return(__wrap_dm_task_set_minor, 0);
+	rc = libmp_mapinfo(DM_MAP_BY_DEV,
+			   (mapid_t) { ._u = { 254, 123 } },
+			   (mapinfo_t) { .name = NULL });
+	assert_int_equal(rc, DMP_ERR);
+}
+
+static void test_mapinfo_good_info(void **state)
+{
+	int rc;
+	struct dm_info dmi;
+
+	mock_mapinfo_name_1(DM_DEVICE_INFO, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&MPATH_DMI_01);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .dmi = &dmi });
+	assert_int_equal(rc, DMP_OK);
+	assert_memory_equal(&dmi, &MPATH_DMI_01, sizeof(dmi));
+}
+
+static void test_mapinfo_good_by_uuid_info(void **state)
+{
+	int rc;
+	struct dm_info dmi;
+
+	expect_value(__wrap_dm_task_create, task, DM_DEVICE_INFO);
+	will_return(__wrap_dm_task_create, 1);
+	expect_value(__wrap_dm_task_set_uuid, uuid, "foo");
+	will_return(__wrap_dm_task_set_uuid, 1);
+	will_return(__wrap_dm_task_run, 1);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&MPATH_DMI_01);
+	rc = libmp_mapinfo(DM_MAP_BY_UUID,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .dmi = &dmi });
+	assert_int_equal(rc, DMP_OK);
+	assert_memory_equal(&dmi, &MPATH_DMI_01, sizeof(dmi));
+}
+
+static void test_mapinfo_good_by_dev_info(void **state)
+{
+	int rc;
+	struct dm_info dmi;
+
+	expect_value(__wrap_dm_task_create, task, DM_DEVICE_INFO);
+	will_return(__wrap_dm_task_create, 1);
+	expect_value(__wrap_dm_task_set_major, val, 254);
+	will_return(__wrap_dm_task_set_major, 1);
+	expect_value(__wrap_dm_task_set_minor, val, 123);
+	will_return(__wrap_dm_task_set_minor, 1);
+	will_return(__wrap_dm_task_run, 1);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&MPATH_DMI_01);
+	rc = libmp_mapinfo(DM_MAP_BY_DEV,
+			   (mapid_t) { ._u = { 254, 123 } },
+			   (mapinfo_t) { .dmi = &dmi });
+	assert_int_equal(rc, DMP_OK);
+	assert_memory_equal(&dmi, &MPATH_DMI_01, sizeof(dmi));
+}
+
+static void test_mapinfo_bad_name(void **state)
+{
+	int rc;
+	char name[WWID_SIZE] = { 0 };
+
+	mock_mapinfo_name_1(DM_DEVICE_INFO, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&MPATH_DMI_01);
+	will_return(__wrap_dm_task_get_name, NULL);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .name = name });
+	assert_int_equal(rc, DMP_ERR);
+}
+
+static void test_mapinfo_good_name(void **state)
+{
+	int rc;
+	char name[WWID_SIZE] = { 0 };
+
+	mock_mapinfo_name_1(DM_DEVICE_INFO, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&MPATH_DMI_01);
+	will_return(__wrap_dm_task_get_name, MPATH_NAME_01);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .name = name });
+	assert_int_equal(rc, DMP_OK);
+	assert_true(!strcmp(name, MPATH_NAME_01));
+}
+
+static void test_mapinfo_bad_uuid(void **state)
+{
+	int rc;
+	char uuid[DM_UUID_LEN] = { 0 };
+
+	mock_mapinfo_name_1(DM_DEVICE_INFO, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&MPATH_DMI_01);
+	will_return(__wrap_dm_task_get_uuid, NULL);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .uuid = uuid });
+	assert_int_equal(rc, DMP_ERR);
+}
+
+static void test_mapinfo_good_uuid(void **state)
+{
+	int rc;
+	char uuid[DM_UUID_LEN] = { 0 };
+
+	mock_mapinfo_name_1(DM_DEVICE_INFO, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&MPATH_DMI_01);
+	will_return(__wrap_dm_task_get_uuid, MPATH_UUID_01);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .uuid = uuid });
+	assert_int_equal(rc, DMP_OK);
+	assert_true(!strcmp(uuid, MPATH_UUID_01));
+}
+
+/* If size is set, libmp_mapinfo needs to do a DM_DEVICE_STATUS ioctl */
+static void test_mapinfo_good_size(void **state)
+{
+	int rc;
+	unsigned long long size;
+
+	mock_mapinfo_name_1(DM_DEVICE_STATUS, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&MPATH_DMI_01);
+	mock_dm_get_next_target(12345, NULL, MPATH_TARGET_01, NULL);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .size = &size });
+	assert_int_equal(rc, DMP_OK);
+	assert_int_equal(size, 12345);
+}
+
+static void test_mapinfo_bad_next_target_01(void **state)
+{
+	int rc;
+	unsigned long long size;
+
+	mock_mapinfo_name_1(DM_DEVICE_STATUS, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&MPATH_DMI_01);
+	/* multiple targets */
+	mock_dm_get_next_target(12345, NULL, MPATH_STATUS_01, (void *)1);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .size = &size });
+	assert_int_equal(rc, DMP_NOT_FOUND);
+}
+
+static void test_mapinfo_bad_next_target_02(void **state)
+{
+	int rc;
+	unsigned long long size;
+
+	mock_mapinfo_name_1(DM_DEVICE_STATUS, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&MPATH_DMI_01);
+	/* no targets */
+	mock_dm_get_next_target(12345, NULL, NULL, NULL);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .size = &size });
+	assert_int_equal(rc, DMP_NOT_FOUND);
+}
+
+/* If tgt_type is set, libmp_mapinfo needs to do a DM_DEVICE_STATUS ioctl */
+static void test_mapinfo_bad_target_type_01(void **state)
+{
+	int rc;
+
+	mock_mapinfo_name_1(DM_DEVICE_STATUS, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&MPATH_DMI_01);
+	mock_dm_get_next_target(12345, "linear", MPATH_STATUS_01, NULL);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .tgt_type = TGT_MPATH });
+	assert_int_equal(rc, DMP_NO_MATCH);
+}
+
+static void test_mapinfo_bad_target_type_02(void **state)
+{
+	int rc;
+
+	mock_mapinfo_name_1(DM_DEVICE_STATUS, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&MPATH_DMI_01);
+	mock_dm_get_next_target(12345, TGT_MPATH, MPATH_STATUS_01, NULL);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .tgt_type = TGT_PART });
+	assert_int_equal(rc, DMP_NO_MATCH);
+}
+
+static void test_mapinfo_bad_target_type_03(void **state)
+{
+	int rc;
+	struct dm_info dmi = { .suspended = 0 };
+	char name[WWID_SIZE] = { 0 };
+	char uuid[DM_UUID_LEN] = { 0 };
+
+	mock_mapinfo_name_1(DM_DEVICE_STATUS, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&MPATH_DMI_01);
+	mock_dm_get_next_target(12345, TGT_PART, MPATH_STATUS_01, NULL);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .tgt_type = TGT_MPATH, .dmi = &dmi,
+				   .name = name, .uuid = uuid });
+	assert_int_equal(rc, DMP_NO_MATCH);
+	/* make sure memory content is not changed */
+	assert_memory_equal(&dmi, &((struct dm_info) { .exists = 0 }), sizeof(dmi));
+	assert_memory_equal(&name, &((char[WWID_SIZE]) { 0 }), WWID_SIZE);
+	assert_memory_equal(&uuid, &((char[DM_UUID_LEN]) { 0 }), DM_UUID_LEN);
+}
+
+static void test_mapinfo_bad_target_type_04(void **state)
+{
+	int rc;
+	char __attribute__((cleanup(cleanup_charp))) *status = NULL;
+
+	mock_mapinfo_name_1(DM_DEVICE_STATUS, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&MPATH_DMI_01);
+	mock_dm_get_next_target(12345, TGT_MPATH, MPATH_STATUS_01, NULL);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .status = &status, .tgt_type = TGT_PART });
+	assert_int_equal(rc, DMP_NO_MATCH);
+	assert_null(status);
+}
+
+static void test_mapinfo_bad_target_type_05(void **state)
+{
+	int rc;
+	char __attribute__((cleanup(cleanup_charp))) *target = NULL;
+
+	mock_mapinfo_name_1(DM_DEVICE_TABLE, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&MPATH_DMI_01);
+	mock_dm_get_next_target(12345, TGT_MPATH, MPATH_STATUS_01, NULL);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .target = &target, .tgt_type = TGT_PART });
+	assert_int_equal(rc, DMP_NO_MATCH);
+	assert_null(target);
+}
+
+static void test_mapinfo_good_target_type_01(void **state)
+{
+	int rc;
+
+	mock_mapinfo_name_1(DM_DEVICE_STATUS, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&MPATH_DMI_01);
+	mock_dm_get_next_target(12345, TGT_MPATH, MPATH_STATUS_01, NULL);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .tgt_type = TGT_MPATH });
+	assert_int_equal(rc, DMP_OK);
+}
+
+static void test_mapinfo_good_target_type_02(void **state)
+{
+	int rc;
+
+	mock_mapinfo_name_1(DM_DEVICE_STATUS, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&MPATH_DMI_01);
+	mock_dm_get_next_target(12345, TGT_PART, MPATH_STATUS_01, NULL);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .tgt_type = TGT_PART });
+	assert_int_equal(rc, DMP_OK);
+}
+
+static void test_mapinfo_good_target_type_03(void **state)
+{
+	int rc;
+	struct dm_info dmi = { .suspended = 0 };
+
+	mock_mapinfo_name_1(DM_DEVICE_STATUS, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&MPATH_DMI_01);
+	mock_dm_get_next_target(12345, TGT_MPATH, MPATH_STATUS_01, NULL);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .tgt_type = TGT_MPATH, .dmi = &dmi });
+	assert_int_equal(rc, DMP_OK);
+	assert_memory_equal(&dmi, &MPATH_DMI_01, sizeof(dmi));
+}
+
+/* test for returning multiple parameters */
+static void test_mapinfo_good_target_type_04(void **state)
+{
+	int rc;
+	struct dm_info dmi = { .suspended = 0 };
+	char name[WWID_SIZE] = { 0 };
+	char uuid[DM_UUID_LEN] = { 0 };
+
+	mock_mapinfo_name_1(DM_DEVICE_STATUS, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&MPATH_DMI_01);
+	mock_dm_get_next_target(12345, TGT_MPATH, MPATH_STATUS_01, NULL);
+	will_return(__wrap_dm_task_get_name, MPATH_NAME_01);
+	will_return(__wrap_dm_task_get_uuid, MPATH_UUID_01);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .tgt_type = TGT_MPATH, .dmi = &dmi,
+				   .name = name, .uuid = uuid });
+	assert_int_equal(rc, DMP_OK);
+	assert_memory_equal(&dmi, &MPATH_DMI_01, sizeof(dmi));
+	assert_true(!strcmp(name, MPATH_NAME_01));
+	assert_true(!strcmp(uuid, MPATH_UUID_01));
+}
+
+static void test_mapinfo_good_status_01(void **state)
+{
+	int rc;
+	char __attribute__((cleanup(cleanup_charp))) *status = NULL;
+
+	mock_mapinfo_name_1(DM_DEVICE_STATUS, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&MPATH_DMI_01);
+	mock_dm_get_next_target(12345, TGT_MPATH, MPATH_STATUS_01, NULL);
+	will_return(__wrap_strdup, 1);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .status = &status });
+	assert_int_equal(rc, DMP_OK);
+	assert_non_null(status);
+	assert_true(!strcmp(status, MPATH_STATUS_01));
+}
+
+static void test_mapinfo_bad_strdup_01(void **state)
+{
+	int rc;
+	char __attribute__((cleanup(cleanup_charp))) *status = NULL;
+	char name[WWID_SIZE] = { 0 };
+	char uuid[DM_UUID_LEN] = { 0 };
+
+	mock_mapinfo_name_1(DM_DEVICE_STATUS, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&MPATH_DMI_01);
+	mock_dm_get_next_target(12345, TGT_MPATH, MPATH_STATUS_01, NULL);
+	will_return(__wrap_dm_task_get_name, MPATH_NAME_01);
+	will_return(__wrap_dm_task_get_uuid, MPATH_UUID_01);
+	will_return(__wrap_strdup, 0);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .status = &status, .uuid = uuid, .name = name });
+	assert_int_equal(rc, DMP_ERR);
+	assert_null(status);
+	assert_memory_equal(&name, &((char[WWID_SIZE]) { 0 }), WWID_SIZE);
+	assert_memory_equal(&uuid, &((char[DM_UUID_LEN]) { 0 }), DM_UUID_LEN);
+
+}
+
+static void test_mapinfo_bad_get_name_01(void **state)
+{
+	int rc;
+	char __attribute__((cleanup(cleanup_charp))) *status = NULL;
+	char name[WWID_SIZE] = { 0 };
+	char uuid[DM_UUID_LEN] = { 0 };
+
+	mock_mapinfo_name_1(DM_DEVICE_STATUS, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&MPATH_DMI_01);
+	mock_dm_get_next_target(12345, TGT_MPATH, MPATH_STATUS_01, NULL);
+	will_return(__wrap_dm_task_get_name, NULL);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .status = &status, .uuid = uuid, .name = name });
+	assert_int_equal(rc, DMP_ERR);
+	assert_null(status);
+	assert_memory_equal(&name, &((char[WWID_SIZE]) { 0 }), WWID_SIZE);
+	assert_memory_equal(&uuid, &((char[DM_UUID_LEN]) { 0 }), DM_UUID_LEN);
+
+}
+
+static void test_mapinfo_bad_get_uuid_01(void **state)
+{
+	int rc;
+	char __attribute__((cleanup(cleanup_charp))) *status = NULL;
+	char name[WWID_SIZE] = { 0 };
+	char uuid[DM_UUID_LEN] = { 0 };
+
+	mock_mapinfo_name_1(DM_DEVICE_STATUS, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&MPATH_DMI_01);
+	mock_dm_get_next_target(12345, TGT_MPATH, MPATH_STATUS_01, NULL);
+	will_return(__wrap_dm_task_get_name, MPATH_NAME_01);
+	will_return(__wrap_dm_task_get_uuid, NULL);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .status = &status, .uuid = uuid, .name = name });
+	assert_int_equal(rc, DMP_ERR);
+	assert_null(status);
+	assert_memory_equal(&name, &((char[WWID_SIZE]) { 0 }), WWID_SIZE);
+	assert_memory_equal(&uuid, &((char[DM_UUID_LEN]) { 0 }), DM_UUID_LEN);
+
+}
+
+static void test_mapinfo_bad_task_run_11(void **state)
+{
+	int rc;
+	char *params = NULL, *status = NULL;
+
+	mock_mapinfo_name_1(DM_DEVICE_TABLE, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&MPATH_DMI_01);
+	mock_dm_get_next_target(12345, NULL, MPATH_TARGET_01, NULL);
+	will_return(__wrap_strdup, 1);
+	/* error in 2nd dm_task_run */
+	mock_mapinfo_name_1(DM_DEVICE_STATUS, 1, "foo", 1, 0, EINVAL);
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) { .target = &params, .status = &status });
+	assert_int_equal(rc, DMP_ERR);
+	assert_ptr_equal(params, NULL);
+	assert_ptr_equal(status, NULL);
+}
+
+static void test_mapinfo_bad_get_name_02(void **state)
+{
+	int rc;
+	char *target = NULL, *status = NULL;
+	char name[WWID_SIZE] = { 0 };
+	char uuid[DM_UUID_LEN] = { 0 };
+	struct dm_info dmi = { .suspended = 0 };
+
+	mock_mapinfo_name_1(DM_DEVICE_TABLE, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&MPATH_DMI_01);
+	mock_dm_get_next_target(12345, TGT_MPATH, MPATH_TARGET_01, NULL);
+	will_return(__wrap_strdup, 1);
+	/* 2nd ioctl */
+	mock_mapinfo_name_1(DM_DEVICE_STATUS, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&MPATH_DMI_01);
+	mock_dm_get_next_target(12345, TGT_MPATH, MPATH_STATUS_01, NULL);
+	will_return(__wrap_dm_task_get_name, NULL);
+
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) {
+				   .target = &target, .status = &status,
+				   .uuid = uuid, .name = name, .dmi = &dmi });
+	assert_int_equal(rc, DMP_ERR);
+	assert_null(status);
+	assert_null(target);
+	assert_memory_equal(&dmi, &((struct dm_info) { .suspended = 0 }), sizeof(dmi));
+	assert_memory_equal(&name, &((char[WWID_SIZE]) { 0 }), WWID_SIZE);
+	assert_memory_equal(&uuid, &((char[DM_UUID_LEN]) { 0 }), DM_UUID_LEN);
+}
+
+static void test_mapinfo_bad_get_uuid_02(void **state)
+{
+	int rc;
+	char *target = NULL, *status = NULL;
+	char name[WWID_SIZE] = { 0 };
+	char uuid[DM_UUID_LEN] = { 0 };
+	struct dm_info dmi = { .suspended = 0 };
+
+	mock_mapinfo_name_1(DM_DEVICE_TABLE, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&MPATH_DMI_01);
+	mock_dm_get_next_target(12345, TGT_MPATH, MPATH_TARGET_01, NULL);
+	will_return(__wrap_strdup, 1);
+	/* 2nd ioctl */
+	mock_mapinfo_name_1(DM_DEVICE_STATUS, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&MPATH_DMI_01);
+	mock_dm_get_next_target(12345, TGT_MPATH, MPATH_STATUS_01, NULL);
+	will_return(__wrap_dm_task_get_name, MPATH_NAME_01);
+	will_return(__wrap_dm_task_get_uuid, NULL);
+
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) {
+				   .target = &target, .status = &status,
+				   .uuid = uuid, .name = name, .dmi = &dmi });
+	assert_int_equal(rc, DMP_ERR);
+	assert_null(status);
+	assert_null(target);
+	assert_memory_equal(&dmi, &((struct dm_info) { .suspended = 0 }), sizeof(dmi));
+	assert_memory_equal(&name, &((char[WWID_SIZE]) { 0 }), WWID_SIZE);
+	assert_memory_equal(&uuid, &((char[DM_UUID_LEN]) { 0 }), DM_UUID_LEN);
+}
+
+static void test_mapinfo_bad_strdup_02(void **state)
+{
+	int rc;
+	char *target = NULL, *status = NULL;
+	char name[WWID_SIZE] = { 0 };
+	char uuid[DM_UUID_LEN] = { 0 };
+	struct dm_info dmi = { .suspended = 0 };
+
+	mock_mapinfo_name_1(DM_DEVICE_TABLE, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&MPATH_DMI_01);
+	mock_dm_get_next_target(12345, TGT_MPATH, MPATH_TARGET_01, NULL);
+	will_return(__wrap_strdup, 1);
+	/* 2nd ioctl */
+	mock_mapinfo_name_1(DM_DEVICE_STATUS, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&MPATH_DMI_01);
+	mock_dm_get_next_target(12345, TGT_MPATH, MPATH_STATUS_01, NULL);
+	will_return(__wrap_dm_task_get_name, MPATH_NAME_01);
+	will_return(__wrap_dm_task_get_uuid, MPATH_UUID_01);
+	will_return(__wrap_strdup, 0);
+
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) {
+				   .target = &target, .status = &status,
+				   .uuid = uuid, .name = name, .dmi = &dmi });
+	assert_int_equal(rc, DMP_ERR);
+	assert_null(status);
+	assert_null(target);
+	assert_memory_equal(&dmi, &((struct dm_info) { .suspended = 0 }), sizeof(dmi));
+	assert_memory_equal(&name, &((char[WWID_SIZE]) { 0 }), WWID_SIZE);
+	assert_memory_equal(&uuid, &((char[DM_UUID_LEN]) { 0 }), DM_UUID_LEN);
+}
+
+static void test_mapinfo_bad_strdup_03(void **state)
+{
+	int rc;
+	char *target = NULL, *status = NULL;
+	char name[WWID_SIZE] = { 0 };
+	char uuid[DM_UUID_LEN] = { 0 };
+	struct dm_info dmi = { .suspended = 0 };
+
+	mock_mapinfo_name_1(DM_DEVICE_TABLE, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&MPATH_DMI_01);
+	mock_dm_get_next_target(12345, TGT_MPATH, MPATH_TARGET_01, NULL);
+	will_return(__wrap_strdup, 0);
+	/* No 2nd ioctl, as there was an error in the 1st */
+
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) {
+				   .target = &target, .status = &status,
+				   .uuid = uuid, .name = name, .dmi = &dmi });
+	assert_int_equal(rc, DMP_ERR);
+	assert_null(status);
+	assert_null(target);
+	assert_memory_equal(&dmi, &((struct dm_info) { .suspended = 0 }), sizeof(dmi));
+	assert_memory_equal(&name, &((char[WWID_SIZE]) { 0 }), WWID_SIZE);
+	assert_memory_equal(&uuid, &((char[DM_UUID_LEN]) { 0 }), DM_UUID_LEN);
+}
+
+static void test_mapinfo_good_all_01(void **state)
+{
+	int rc;
+	char __attribute__((cleanup(cleanup_charp))) *target = NULL;
+	char __attribute__((cleanup(cleanup_charp))) *status = NULL;
+	char name[WWID_SIZE] = { 0 };
+	char uuid[DM_UUID_LEN] = { 0 };
+	struct dm_info dmi = { .suspended = 0 };
+	unsigned long long size;
+
+	mock_mapinfo_name_1(DM_DEVICE_TABLE, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&MPATH_DMI_01);
+	mock_dm_get_next_target(12345, TGT_MPATH, MPATH_TARGET_01, NULL);
+	will_return(__wrap_strdup, 1);
+	/* 2nd ioctl */
+	mock_mapinfo_name_1(DM_DEVICE_STATUS, 1, "foo", 1, 1, 0);
+	WRAP_DM_TASK_GET_INFO(1);
+	WRAP_DM_TASK_GET_INFO(&MPATH_DMI_01);
+	mock_dm_get_next_target(12345, TGT_MPATH, MPATH_STATUS_01, NULL);
+	will_return(__wrap_dm_task_get_name, MPATH_NAME_01);
+	will_return(__wrap_dm_task_get_uuid, MPATH_UUID_01);
+	will_return(__wrap_strdup, 1);
+
+	rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			   (mapid_t) { .str = "foo", },
+			   (mapinfo_t) {
+				   .target = &target, .status = &status,
+				   .uuid = uuid, .name = name,
+				   .dmi = &dmi, .size = &size });
+	assert_int_equal(rc, DMP_OK);
+	assert_non_null(status);
+	assert_non_null(target);
+	assert_int_equal(size, 12345);
+	assert_memory_equal(&dmi, &MPATH_DMI_01, sizeof(dmi));
+	assert_true(!strcmp(target, MPATH_TARGET_01));
+	assert_true(!strcmp(status, MPATH_STATUS_01));
+	assert_true(!strcmp(name, MPATH_NAME_01));
+	assert_true(!strcmp(uuid, MPATH_UUID_01));
+}
+
+static int test_mapinfo(void)
+{
+	const struct CMUnitTest tests[] = {
+		cmocka_unit_test(test_mapinfo_bad_task_create_01),
+		cmocka_unit_test(test_mapinfo_bad_mapid),
+		cmocka_unit_test(test_mapinfo_bad_set_name),
+		cmocka_unit_test(test_mapinfo_bad_task_run_01),
+		cmocka_unit_test(test_mapinfo_bad_task_run_02),
+		cmocka_unit_test(test_mapinfo_bad_task_run_03),
+		cmocka_unit_test(test_mapinfo_bad_task_run_04),
+		cmocka_unit_test(test_mapinfo_bad_task_run_05),
+		cmocka_unit_test(test_mapinfo_bad_task_run_06),
+		cmocka_unit_test(test_mapinfo_bad_task_run_07),
+		cmocka_unit_test(test_mapinfo_bad_task_run_08),
+		cmocka_unit_test(test_mapinfo_bad_task_run_09),
+		cmocka_unit_test(test_mapinfo_bad_task_run_10),
+		cmocka_unit_test(test_mapinfo_bad_task_run_11),
+		cmocka_unit_test(test_mapinfo_bad_get_info_01),
+		cmocka_unit_test(test_mapinfo_bad_get_info_02),
+		cmocka_unit_test(test_mapinfo_bad_get_info_03),
+		cmocka_unit_test(test_mapinfo_bad_get_info_04),
+		cmocka_unit_test(test_mapinfo_good_exists),
+		cmocka_unit_test(test_mapinfo_bad_set_uuid),
+		cmocka_unit_test(test_mapinfo_bad_set_dev_01),
+		cmocka_unit_test(test_mapinfo_bad_set_dev_02),
+		cmocka_unit_test(test_mapinfo_good_info),
+		cmocka_unit_test(test_mapinfo_good_by_uuid_info),
+		cmocka_unit_test(test_mapinfo_good_by_dev_info),
+		cmocka_unit_test(test_mapinfo_bad_name),
+		cmocka_unit_test(test_mapinfo_good_name),
+		cmocka_unit_test(test_mapinfo_bad_uuid),
+		cmocka_unit_test(test_mapinfo_good_uuid),
+		cmocka_unit_test(test_mapinfo_good_size),
+		cmocka_unit_test(test_mapinfo_bad_next_target_01),
+		cmocka_unit_test(test_mapinfo_bad_next_target_02),
+		cmocka_unit_test(test_mapinfo_bad_target_type_01),
+		cmocka_unit_test(test_mapinfo_bad_target_type_02),
+		cmocka_unit_test(test_mapinfo_bad_target_type_03),
+		cmocka_unit_test(test_mapinfo_bad_target_type_04),
+		cmocka_unit_test(test_mapinfo_bad_target_type_05),
+		cmocka_unit_test(test_mapinfo_good_target_type_01),
+		cmocka_unit_test(test_mapinfo_good_target_type_02),
+		cmocka_unit_test(test_mapinfo_good_target_type_03),
+		cmocka_unit_test(test_mapinfo_good_target_type_04),
+		cmocka_unit_test(test_mapinfo_good_status_01),
+		cmocka_unit_test(test_mapinfo_bad_get_name_01),
+		cmocka_unit_test(test_mapinfo_bad_get_uuid_01),
+		cmocka_unit_test(test_mapinfo_bad_strdup_01),
+		cmocka_unit_test(test_mapinfo_bad_get_name_02),
+		cmocka_unit_test(test_mapinfo_bad_get_uuid_02),
+		cmocka_unit_test(test_mapinfo_bad_strdup_02),
+		cmocka_unit_test(test_mapinfo_bad_strdup_03),
+		cmocka_unit_test(test_mapinfo_good_all_01),
+	};
+	return cmocka_run_group_tests(tests, NULL, NULL);
+}
+
+int main(void)
+{
+	int ret = 0;
+
+	init_test_verbosity(4);
+	skip_libmp_dm_init();
+	ret += test_mapinfo();
+	return ret;
+}
-- 
2.45.2


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

* [PATCH 19/44] libmultipath: implement dm_get_info() and dm_map_present() with new API
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (17 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 18/44] libmultipath tests: add tests for libmp_mapinfo() Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-09 21:39 ` [PATCH 20/44] libmultipath: remove dm_get_prefixed_uuid() Martin Wilck
                   ` (25 subsequent siblings)
  44 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmultipath/devmapper.c          | 54 ++++---------------------------
 libmultipath/devmapper.h          | 16 +++++++--
 libmultipath/libmultipath.version |  2 --
 multipathd/main.c                 |  4 +--
 4 files changed, 23 insertions(+), 53 deletions(-)

diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index 5c9f9d8..bdeba48 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -783,45 +783,6 @@ int libmp_mapinfo(int flags, mapid_t id, mapinfo_t info)
 			       libmp_map_identifier(flags, id, idbuf));
 }
 
-int
-dm_get_info(const char *name, struct dm_info *info)
-{
-	int r = -1;
-	struct dm_task *dmt;
-
-	if (!name || !info)
-		return r;
-
-	if (!(dmt = libmp_dm_task_create(DM_DEVICE_INFO)))
-		return r;
-
-	if (!dm_task_set_name(dmt, name))
-		goto out;
-
-	if (!libmp_dm_task_run(dmt)) {
-		dm_log_error(3, DM_DEVICE_INFO, dmt);
-		goto out;
-	}
-
-	if (!dm_task_get_info(dmt, info))
-		goto out;
-
-	if (!info->exists)
-		goto out;
-
-	r = 0;
-out:
-	dm_task_destroy(dmt);
-	return r;
-}
-
-int dm_map_present(const char * str)
-{
-	struct dm_info info;
-
-	return (dm_get_info(str, &info) == 0);
-}
-
 int dm_get_map(const char *name, unsigned long long *size, char **outparams)
 {
 	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
@@ -1120,15 +1081,14 @@ out:
 	return r;
 }
 
-static int
-dm_dev_t (const char * mapname, char * dev_t, int len)
+static int dm_dev_t (const char *mapname, char *dev_t, int len)
 {
 	struct dm_info info;
 
-	if (dm_get_info(mapname, &info) != 0)
+	if (dm_get_info(mapname, &info) != DMP_OK)
 		return 1;
 
-	if (snprintf(dev_t, len, "%i:%i", info.major, info.minor) > len)
+	if (safe_snprintf(dev_t, len, "%i:%i", info.major, info.minor))
 		return 1;
 
 	return 0;
@@ -1169,7 +1129,7 @@ dm_get_major_minor(const char *name, int *major, int *minor)
 {
 	struct dm_info info;
 
-	if (dm_get_info(name, &info) != 0)
+	if (dm_get_info(name, &info) != DMP_OK)
 		return -1;
 
 	*major = info.major;
@@ -1515,7 +1475,7 @@ dm_geteventnr (const char *name)
 {
 	struct dm_info info;
 
-	if (dm_get_info(name, &info) != 0)
+	if (dm_get_info(name, &info) != DMP_OK)
 		return -1;
 
 	return info.event_nr;
@@ -1526,7 +1486,7 @@ dm_is_suspended(const char *name)
 {
 	struct dm_info info;
 
-	if (dm_get_info(name, &info) != 0)
+	if (dm_get_info(name, &info) != DMP_OK)
 		return -1;
 
 	return info.suspended;
@@ -1678,7 +1638,7 @@ dm_get_deferred_remove (const char * mapname)
 {
 	struct dm_info info;
 
-	if (dm_get_info(mapname, &info) != 0)
+	if (dm_get_info(mapname, &info) != DMP_OK)
 		return -1;
 
 	return info.deferred_remove;
diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h
index 269389b..0cdd757 100644
--- a/libmultipath/devmapper.h
+++ b/libmultipath/devmapper.h
@@ -99,6 +99,20 @@ typedef struct libmp_map_info {
  */
 int libmp_mapinfo(int flags, mapid_t id, mapinfo_t info);
 
+static inline int dm_get_info(const char *mapname, struct dm_info *info)
+{
+	return libmp_mapinfo(DM_MAP_BY_NAME,
+			     (mapid_t) { .str = mapname },
+			     (mapinfo_t) { .dmi = info });
+}
+
+static inline int dm_map_present(const char *mapname)
+{
+	return libmp_mapinfo(DM_MAP_BY_NAME,
+			     (mapid_t) { .str = mapname },
+			     (mapinfo_t) { .name = NULL }) == DMP_OK;
+}
+
 int dm_prereq(unsigned int *v);
 void skip_libmp_dm_init(void);
 void libmp_dm_exit(void);
@@ -108,7 +122,6 @@ int dm_simplecmd_flush (int task, const char *name, uint16_t udev_flags);
 int dm_simplecmd_noflush (int task, const char *name, uint16_t udev_flags);
 int dm_addmap_create (struct multipath *mpp, char *params);
 int dm_addmap_reload (struct multipath *mpp, char *params, int flush);
-int dm_map_present (const char *name);
 int dm_map_present_by_uuid(const char *uuid);
 int dm_get_map(const char *name, unsigned long long *size, char **outparams);
 int dm_get_status(const char *name, char **outstatus);
@@ -159,7 +172,6 @@ int dm_get_major_minor (const char *name, int *major, int *minor);
 char * dm_mapname(int major, int minor);
 int dm_get_uuid(const char *name, char *uuid, int uuid_len);
 bool has_dm_info(const struct multipath *mpp);
-int dm_get_info (const char * mapname, struct dm_info *dmi);
 int dm_rename (const char * old, char * new, char * delim, int skip_kpartx);
 int dm_reassign(const char * mapname);
 int dm_reassign_table(const char *name, char *old, char *new);
diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version
index 48c2b67..7a50349 100644
--- a/libmultipath/libmultipath.version
+++ b/libmultipath/libmultipath.version
@@ -78,14 +78,12 @@ global:
 	dm_flush_map_nopaths;
 	dm_flush_maps;
 	dm_geteventnr;
-	dm_get_info;
 	dm_get_major_minor;
 	dm_get_maps;
 	dm_get_multipath;
 	dm_get_uuid;
 	dm_is_mpath;
 	dm_mapname;
-	dm_map_present;
 	dm_prereq;
 	dm_queue_if_no_path;
 	dm_reassign;
diff --git a/multipathd/main.c b/multipathd/main.c
index 132bb2e..394ca7d 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -502,7 +502,7 @@ remove_maps_and_stop_waiters(struct vectors *vecs)
 
 int refresh_multipath(struct vectors *vecs, struct multipath *mpp)
 {
-	if (dm_get_info(mpp->alias, &mpp->dmi)) {
+	if (dm_get_info(mpp->alias, &mpp->dmi) != DMP_OK) {
 		/* Error accessing table */
 		condlog(2, "%s: cannot access table", mpp->alias);
 		goto out;
@@ -722,7 +722,7 @@ add_map_without_path (struct vectors *vecs, const char *alias)
 
 	mpp->alias = strdup(alias);
 
-	if (dm_get_info(mpp->alias, &mpp->dmi)) {
+	if (dm_get_info(mpp->alias, &mpp->dmi) != DMP_OK) {
 		condlog(3, "%s: cannot access table", mpp->alias);
 		goto out;
 	}
-- 
2.45.2


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

* [PATCH 20/44] libmultipath: remove dm_get_prefixed_uuid()
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (18 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 19/44] libmultipath: implement dm_get_info() and dm_map_present() with new API Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-09 21:39 ` [PATCH 21/44] libmultipath: is_mpath_part(): improve parsing Martin Wilck
                   ` (24 subsequent siblings)
  44 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

... and replace it by calls to the new API.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmultipath/devmapper.c | 53 +++++++++-------------------------------
 1 file changed, 11 insertions(+), 42 deletions(-)

diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index bdeba48..56157af 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -783,6 +783,13 @@ int libmp_mapinfo(int flags, mapid_t id, mapinfo_t info)
 			       libmp_map_identifier(flags, id, idbuf));
 }
 
+static int dm_get_dm_uuid(const char *mapname, char uuid[DM_UUID_LEN])
+{
+	return libmp_mapinfo(DM_MAP_BY_NAME,
+			     (mapid_t) { .str = mapname },
+			     (mapinfo_t) { .uuid = uuid });
+}
+
 int dm_get_map(const char *name, unsigned long long *size, char **outparams)
 {
 	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
@@ -822,48 +829,11 @@ int dm_get_map(const char *name, unsigned long long *size, char **outparams)
 	}
 }
 
-static int
-dm_get_prefixed_uuid(const char *name, char *uuid, int uuid_len)
-{
-	struct dm_task *dmt;
-	const char *uuidtmp;
-	struct dm_info info;
-	int r = 1;
-
-	dmt = libmp_dm_task_create(DM_DEVICE_INFO);
-	if (!dmt)
-		return 1;
-
-	if (uuid_len > 0)
-		uuid[0] = '\0';
-
-	if (!dm_task_set_name (dmt, name))
-		goto uuidout;
-
-	if (!libmp_dm_task_run(dmt)) {
-		dm_log_error(3, DM_DEVICE_INFO, dmt);
-		goto uuidout;
-	}
-
-	if (!dm_task_get_info(dmt, &info) ||
-	    !info.exists)
-		goto uuidout;
-
-	uuidtmp = dm_task_get_uuid(dmt);
-	if (uuidtmp)
-		strlcpy(uuid, uuidtmp, uuid_len);
-
-	r = 0;
-uuidout:
-	dm_task_destroy(dmt);
-	return r;
-}
-
 int dm_get_uuid(const char *name, char *uuid, int uuid_len)
 {
 	char tmp[DM_UUID_LEN];
 
-	if (dm_get_prefixed_uuid(name, tmp, sizeof(tmp)))
+	if (dm_get_dm_uuid(name, tmp) != DMP_OK)
 		return 1;
 
 	if (!strncmp(tmp, UUID_PREFIX, UUID_PREFIX_LEN))
@@ -874,16 +844,15 @@ int dm_get_uuid(const char *name, char *uuid, int uuid_len)
 	return 0;
 }
 
-static int
-is_mpath_part(const char *part_name, const char *map_name)
+static int is_mpath_part(const char *part_name, const char *map_name)
 {
 	char *p;
 	char part_uuid[DM_UUID_LEN], map_uuid[DM_UUID_LEN];
 
-	if (dm_get_prefixed_uuid(part_name, part_uuid, sizeof(part_uuid)))
+	if (dm_get_dm_uuid(part_name, part_uuid) != DMP_OK)
 		return 0;
 
-	if (dm_get_prefixed_uuid(map_name, map_uuid, sizeof(map_uuid)))
+	if (dm_get_dm_uuid(map_name, map_uuid) != DMP_OK)
 		return 0;
 
 	if (strncmp(part_uuid, "part", 4) != 0)
-- 
2.45.2


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

* [PATCH 21/44] libmultipath: is_mpath_part(): improve parsing
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (19 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 20/44] libmultipath: remove dm_get_prefixed_uuid() Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-10 22:54   ` Benjamin Marzinski
  2024-07-09 21:39 ` [PATCH 22/44] libmultipath: rename dm_get_uuid() -> dm_get_wwid() Martin Wilck
                   ` (23 subsequent siblings)
  44 siblings, 1 reply; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

Use sscanf to make the parsing of the UUID more robust.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmultipath/devmapper.c | 17 +++++++----------
 1 file changed, 7 insertions(+), 10 deletions(-)

diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index 56157af..d62a7dd 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -846,23 +846,20 @@ int dm_get_uuid(const char *name, char *uuid, int uuid_len)
 
 static int is_mpath_part(const char *part_name, const char *map_name)
 {
-	char *p;
-	char part_uuid[DM_UUID_LEN], map_uuid[DM_UUID_LEN];
+	char part_uuid[DM_UUID_LEN], map_uuid[DM_UUID_LEN], c;
+	int np, nc;
 
 	if (dm_get_dm_uuid(part_name, part_uuid) != DMP_OK)
 		return 0;
 
+	if (2 != sscanf(part_uuid, "part%d-%n" UUID_PREFIX "%c", &np, &nc, &c)
+	    || np <= 0)
+		return 0;
+
 	if (dm_get_dm_uuid(map_name, map_uuid) != DMP_OK)
 		return 0;
 
-	if (strncmp(part_uuid, "part", 4) != 0)
-		return 0;
-
-	p = strstr(part_uuid, UUID_PREFIX);
-	if (p && !strcmp(p, map_uuid))
-		return 1;
-
-	return 0;
+	return !strcmp(part_uuid + nc, map_uuid);
 }
 
 int dm_get_status(const char *name, char **outstatus)
-- 
2.45.2


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

* [PATCH 22/44] libmultipath: rename dm_get_uuid() -> dm_get_wwid()
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (20 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 21/44] libmultipath: is_mpath_part(): improve parsing Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-09 21:39 ` [PATCH 23/44] libmultipath: improve dm_get_wwid() return value logic Martin Wilck
                   ` (22 subsequent siblings)
  44 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

... to make the distinction between WWID (multipath) and
UUID (device mapper) a little more obvious.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmultipath/alias.c              |  2 +-
 libmultipath/configure.c          |  4 ++--
 libmultipath/devmapper.c          |  4 ++--
 libmultipath/devmapper.h          |  2 +-
 libmultipath/libmultipath.version |  2 +-
 libmultipath/wwids.c              |  2 +-
 multipathd/main.c                 |  2 +-
 tests/alias.c                     | 30 +++++++++++++++---------------
 8 files changed, 24 insertions(+), 24 deletions(-)

diff --git a/libmultipath/alias.c b/libmultipath/alias.c
index a54616c..10e58a7 100644
--- a/libmultipath/alias.c
+++ b/libmultipath/alias.c
@@ -410,7 +410,7 @@ static bool alias_already_taken(const char *alias, const char *map_wwid)
 	char wwid[WWID_SIZE];
 
 	/* If the map doesn't exist, it's fine */
-	if (dm_get_uuid(alias, wwid, sizeof(wwid)) != 0)
+	if (dm_get_wwid(alias, wwid, sizeof(wwid)) != 0)
 		return false;
 
 	/* If both the name and the wwid match, it's fine.*/
diff --git a/libmultipath/configure.c b/libmultipath/configure.c
index b5c701f..666d4e8 100644
--- a/libmultipath/configure.c
+++ b/libmultipath/configure.c
@@ -846,7 +846,7 @@ int domap(struct multipath *mpp, char *params, int is_daemon)
 	if (mpp->action == ACT_CREATE && dm_map_present(mpp->alias)) {
 		char wwid[WWID_SIZE];
 
-		if (dm_get_uuid(mpp->alias, wwid, sizeof(wwid)) == 0) {
+		if (dm_get_wwid(mpp->alias, wwid, sizeof(wwid)) == 0) {
 			if (!strncmp(mpp->wwid, wwid, sizeof(wwid))) {
 				condlog(3, "%s: map already present",
 					mpp->alias);
@@ -1320,7 +1320,7 @@ static int _get_refwwid(enum mpath_cmds cmd, const char *dev,
 		break;
 
 	case DEV_DEVMAP:
-		if (((dm_get_uuid(dev, tmpwwid, WWID_SIZE)) == 0)
+		if (((dm_get_wwid(dev, tmpwwid, WWID_SIZE)) == 0)
 		    && (strlen(tmpwwid)))
 			refwwid = tmpwwid;
 
diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index d62a7dd..94ef369 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -829,7 +829,7 @@ int dm_get_map(const char *name, unsigned long long *size, char **outparams)
 	}
 }
 
-int dm_get_uuid(const char *name, char *uuid, int uuid_len)
+int dm_get_wwid(const char *name, char *uuid, int uuid_len)
 {
 	char tmp[DM_UUID_LEN];
 
@@ -1377,7 +1377,7 @@ struct multipath *dm_get_multipath(const char *name)
 	if (dm_get_map(name, &mpp->size, NULL) != DMP_OK)
 		goto out;
 
-	if (dm_get_uuid(name, mpp->wwid, WWID_SIZE) != 0)
+	if (dm_get_wwid(name, mpp->wwid, WWID_SIZE) != 0)
 		condlog(2, "%s: failed to get uuid for %s", __func__, name);
 	if (dm_get_info(name, &mpp->dmi) != 0)
 		condlog(2, "%s: failed to get info for %s", __func__, name);
diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h
index 0cdd757..0043812 100644
--- a/libmultipath/devmapper.h
+++ b/libmultipath/devmapper.h
@@ -170,7 +170,7 @@ int dm_geteventnr (const char *name);
 int dm_is_suspended(const char *name);
 int dm_get_major_minor (const char *name, int *major, int *minor);
 char * dm_mapname(int major, int minor);
-int dm_get_uuid(const char *name, char *uuid, int uuid_len);
+int dm_get_wwid(const char *name, char *uuid, int uuid_len);
 bool has_dm_info(const struct multipath *mpp);
 int dm_rename (const char * old, char * new, char * delim, int skip_kpartx);
 int dm_reassign(const char * mapname);
diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version
index 7a50349..7d3ff63 100644
--- a/libmultipath/libmultipath.version
+++ b/libmultipath/libmultipath.version
@@ -81,7 +81,7 @@ global:
 	dm_get_major_minor;
 	dm_get_maps;
 	dm_get_multipath;
-	dm_get_uuid;
+	dm_get_wwid;
 	dm_is_mpath;
 	dm_mapname;
 	dm_prereq;
diff --git a/libmultipath/wwids.c b/libmultipath/wwids.c
index 591cd09..7a4cb74 100644
--- a/libmultipath/wwids.c
+++ b/libmultipath/wwids.c
@@ -295,7 +295,7 @@ should_multipath(struct path *pp1, vector pathvec, vector mpvec)
 		struct multipath *mp = find_mp_by_wwid(mpvec, pp1->wwid);
 
 		if (mp != NULL &&
-		    dm_get_uuid(mp->alias, tmp_wwid, WWID_SIZE) == 0 &&
+		    dm_get_wwid(mp->alias, tmp_wwid, WWID_SIZE) == 0 &&
 		    !strncmp(tmp_wwid, pp1->wwid, WWID_SIZE)) {
 			condlog(3, "wwid %s is already multipathed, keeping it",
 				pp1->wwid);
diff --git a/multipathd/main.c b/multipathd/main.c
index 394ca7d..442a154 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -727,7 +727,7 @@ add_map_without_path (struct vectors *vecs, const char *alias)
 		goto out;
 	}
 	if (!strlen(mpp->wwid))
-		dm_get_uuid(mpp->alias, mpp->wwid, WWID_SIZE);
+		dm_get_wwid(mpp->alias, mpp->wwid, WWID_SIZE);
 	if (!strlen(mpp->wwid))
 		condlog(1, "%s: adding map with empty WWID", mpp->alias);
 	conf = get_multipath_config();
diff --git a/tests/alias.c b/tests/alias.c
index 95ce994..1f78656 100644
--- a/tests/alias.c
+++ b/tests/alias.c
@@ -76,7 +76,7 @@ int WRAP_FUNC(mkstemp)(char *template)
 	return 10;
 }
 
-int __wrap_dm_get_uuid(const char *name, char *uuid, int uuid_len)
+int __wrap_dm_get_wwid(const char *name, char *uuid, int uuid_len)
 {
 	int ret;
 
@@ -436,17 +436,17 @@ static int test_scan_devname(void)
 
 static void mock_unused_alias(const char *alias)
 {
-	expect_string(__wrap_dm_get_uuid, name, alias);
-	expect_value(__wrap_dm_get_uuid, uuid_len, WWID_SIZE);
-	will_return(__wrap_dm_get_uuid, 1);
+	expect_string(__wrap_dm_get_wwid, name, alias);
+	expect_value(__wrap_dm_get_wwid, uuid_len, WWID_SIZE);
+	will_return(__wrap_dm_get_wwid, 1);
 }
 
 static void mock_self_alias(const char *alias, const char *wwid)
 {
-	expect_string(__wrap_dm_get_uuid, name, alias);
-	expect_value(__wrap_dm_get_uuid, uuid_len, WWID_SIZE);
-	will_return(__wrap_dm_get_uuid, 0);
-	will_return(__wrap_dm_get_uuid, wwid);
+	expect_string(__wrap_dm_get_wwid, name, alias);
+	expect_value(__wrap_dm_get_wwid, uuid_len, WWID_SIZE);
+	will_return(__wrap_dm_get_wwid, 0);
+	will_return(__wrap_dm_get_wwid, wwid);
 }
 
 #define USED_STR(alias_str, wwid_str) wwid_str ": alias '" alias_str "' already taken, reselecting alias\n"
@@ -469,17 +469,17 @@ static void mock_self_alias(const char *alias, const char *wwid)
 
 #define mock_failed_alias(alias, wwid)					\
 	do {								\
-		expect_string(__wrap_dm_get_uuid, name, alias);		\
-		expect_value(__wrap_dm_get_uuid, uuid_len, WWID_SIZE);	\
-		will_return(__wrap_dm_get_uuid, 1);			\
+		expect_string(__wrap_dm_get_wwid, name, alias);		\
+		expect_value(__wrap_dm_get_wwid, uuid_len, WWID_SIZE);	\
+		will_return(__wrap_dm_get_wwid, 1);			\
 	} while (0)
 
 #define mock_used_alias(alias, wwid)					\
 	do {								\
-		expect_string(__wrap_dm_get_uuid, name, alias);		\
-		expect_value(__wrap_dm_get_uuid, uuid_len, WWID_SIZE);	\
-		will_return(__wrap_dm_get_uuid, 0);			\
-		will_return(__wrap_dm_get_uuid, "WWID_USED");		\
+		expect_string(__wrap_dm_get_wwid, name, alias);		\
+		expect_value(__wrap_dm_get_wwid, uuid_len, WWID_SIZE);	\
+		will_return(__wrap_dm_get_wwid, 0);			\
+		will_return(__wrap_dm_get_wwid, "WWID_USED");		\
 		expect_condlog(3, USED_STR(alias, wwid));		\
 	} while(0)
 
-- 
2.45.2


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

* [PATCH 23/44] libmultipath: improve dm_get_wwid() return value logic
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (21 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 22/44] libmultipath: rename dm_get_uuid() -> dm_get_wwid() Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-10 23:34   ` Benjamin Marzinski
  2024-07-09 21:39 ` [PATCH 24/44] libmultipath: reimplement dm_map_name() with new API Martin Wilck
                   ` (21 subsequent siblings)
  44 siblings, 1 reply; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

Make dm_get_wwid() return different status codes for non-existing maps,
maps that exists but are not multipath maps, and generic error case,
and handle these return codes appropriately in callers.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmultipath/alias.c     |  5 +++--
 libmultipath/configure.c | 23 +++++++++++------------
 libmultipath/devmapper.c | 21 ++++++++++++++++-----
 libmultipath/wwids.c     |  2 +-
 tests/alias.c            | 10 +++++-----
 5 files changed, 36 insertions(+), 25 deletions(-)

diff --git a/libmultipath/alias.c b/libmultipath/alias.c
index 10e58a7..2ab9499 100644
--- a/libmultipath/alias.c
+++ b/libmultipath/alias.c
@@ -408,13 +408,14 @@ static bool alias_already_taken(const char *alias, const char *map_wwid)
 {
 
 	char wwid[WWID_SIZE];
+	int rc = dm_get_wwid(alias, wwid, sizeof(wwid));
 
 	/* If the map doesn't exist, it's fine */
-	if (dm_get_wwid(alias, wwid, sizeof(wwid)) != 0)
+	if (rc == DMP_NOT_FOUND)
 		return false;
 
 	/* If both the name and the wwid match, it's fine.*/
-	if (strncmp(map_wwid, wwid, sizeof(wwid)) == 0)
+	if (rc == DMP_OK && strncmp(map_wwid, wwid, sizeof(wwid)) == 0)
 		return false;
 
 	condlog(3, "%s: alias '%s' already taken, reselecting alias",
diff --git a/libmultipath/configure.c b/libmultipath/configure.c
index 666d4e8..565ea5c 100644
--- a/libmultipath/configure.c
+++ b/libmultipath/configure.c
@@ -845,18 +845,17 @@ int domap(struct multipath *mpp, char *params, int is_daemon)
 
 	if (mpp->action == ACT_CREATE && dm_map_present(mpp->alias)) {
 		char wwid[WWID_SIZE];
+		int rc = dm_get_wwid(mpp->alias, wwid, sizeof(wwid));
 
-		if (dm_get_wwid(mpp->alias, wwid, sizeof(wwid)) == 0) {
-			if (!strncmp(mpp->wwid, wwid, sizeof(wwid))) {
-				condlog(3, "%s: map already present",
-					mpp->alias);
-				mpp->action = ACT_RELOAD;
-			} else {
-				condlog(0, "%s: map \"%s\" already present with WWID %s, skipping",
-					mpp->wwid, mpp->alias, wwid);
-				condlog(0, "please check alias settings in config and bindings file");
-				mpp->action = ACT_REJECT;
-			}
+		if (rc == DMP_OK && !strncmp(mpp->wwid, wwid, sizeof(wwid))) {
+			condlog(3, "%s: map already present",
+				mpp->alias);
+			mpp->action = ACT_RELOAD;
+		} else if (rc == DMP_OK || rc == DMP_NO_MATCH) {
+			condlog(1, "%s: map \"%s\" already present with WWID \"%s\", skipping\n"
+				   "please check alias settings in config and bindings file",
+				mpp->wwid, mpp->alias, wwid);
+			mpp->action = ACT_REJECT;
 		}
 	}
 
@@ -1320,7 +1319,7 @@ static int _get_refwwid(enum mpath_cmds cmd, const char *dev,
 		break;
 
 	case DEV_DEVMAP:
-		if (((dm_get_wwid(dev, tmpwwid, WWID_SIZE)) == 0)
+		if (((dm_get_wwid(dev, tmpwwid, WWID_SIZE)) == DMP_OK)
 		    && (strlen(tmpwwid)))
 			refwwid = tmpwwid;
 
diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index 94ef369..1eebcb5 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -829,19 +829,30 @@ int dm_get_map(const char *name, unsigned long long *size, char **outparams)
 	}
 }
 
+/**
+ * dm_get_wwid(): return WWID for a multipath map
+ * @returns:
+ *    DMP_OK if successful
+ *    DMP_NOT_FOUND if the map doesn't exist
+ *    DMP_NO_MATCH if the map exists but is not a multipath map
+ *    DMP_ERR for other errors
+ */
 int dm_get_wwid(const char *name, char *uuid, int uuid_len)
 {
 	char tmp[DM_UUID_LEN];
+	int rc = dm_get_dm_uuid(name, tmp);
 
-	if (dm_get_dm_uuid(name, tmp) != DMP_OK)
-		return 1;
+	if (rc != DMP_OK)
+		return rc;
 
 	if (!strncmp(tmp, UUID_PREFIX, UUID_PREFIX_LEN))
 		strlcpy(uuid, tmp + UUID_PREFIX_LEN, uuid_len);
-	else
+	else {
 		uuid[0] = '\0';
+		return DMP_NO_MATCH;
+	}
 
-	return 0;
+	return DMP_OK;
 }
 
 static int is_mpath_part(const char *part_name, const char *map_name)
@@ -1377,7 +1388,7 @@ struct multipath *dm_get_multipath(const char *name)
 	if (dm_get_map(name, &mpp->size, NULL) != DMP_OK)
 		goto out;
 
-	if (dm_get_wwid(name, mpp->wwid, WWID_SIZE) != 0)
+	if (dm_get_wwid(name, mpp->wwid, WWID_SIZE) != DMP_OK)
 		condlog(2, "%s: failed to get uuid for %s", __func__, name);
 	if (dm_get_info(name, &mpp->dmi) != 0)
 		condlog(2, "%s: failed to get info for %s", __func__, name);
diff --git a/libmultipath/wwids.c b/libmultipath/wwids.c
index 7a4cb74..aac18c0 100644
--- a/libmultipath/wwids.c
+++ b/libmultipath/wwids.c
@@ -295,7 +295,7 @@ should_multipath(struct path *pp1, vector pathvec, vector mpvec)
 		struct multipath *mp = find_mp_by_wwid(mpvec, pp1->wwid);
 
 		if (mp != NULL &&
-		    dm_get_wwid(mp->alias, tmp_wwid, WWID_SIZE) == 0 &&
+		    dm_get_wwid(mp->alias, tmp_wwid, WWID_SIZE) == DMP_OK &&
 		    !strncmp(tmp_wwid, pp1->wwid, WWID_SIZE)) {
 			condlog(3, "wwid %s is already multipathed, keeping it",
 				pp1->wwid);
diff --git a/tests/alias.c b/tests/alias.c
index 1f78656..a95b308 100644
--- a/tests/alias.c
+++ b/tests/alias.c
@@ -84,7 +84,7 @@ int __wrap_dm_get_wwid(const char *name, char *uuid, int uuid_len)
 	check_expected(uuid_len);
 	assert_non_null(uuid);
 	ret = mock_type(int);
-	if (ret == 0)
+	if (ret == DMP_OK)
 		strcpy(uuid, mock_ptr_type(char *));
 	return ret;
 }
@@ -438,14 +438,14 @@ static void mock_unused_alias(const char *alias)
 {
 	expect_string(__wrap_dm_get_wwid, name, alias);
 	expect_value(__wrap_dm_get_wwid, uuid_len, WWID_SIZE);
-	will_return(__wrap_dm_get_wwid, 1);
+	will_return(__wrap_dm_get_wwid, DMP_NOT_FOUND);
 }
 
 static void mock_self_alias(const char *alias, const char *wwid)
 {
 	expect_string(__wrap_dm_get_wwid, name, alias);
 	expect_value(__wrap_dm_get_wwid, uuid_len, WWID_SIZE);
-	will_return(__wrap_dm_get_wwid, 0);
+	will_return(__wrap_dm_get_wwid, DMP_OK);
 	will_return(__wrap_dm_get_wwid, wwid);
 }
 
@@ -471,14 +471,14 @@ static void mock_self_alias(const char *alias, const char *wwid)
 	do {								\
 		expect_string(__wrap_dm_get_wwid, name, alias);		\
 		expect_value(__wrap_dm_get_wwid, uuid_len, WWID_SIZE);	\
-		will_return(__wrap_dm_get_wwid, 1);			\
+		will_return(__wrap_dm_get_wwid, DMP_NOT_FOUND);		\
 	} while (0)
 
 #define mock_used_alias(alias, wwid)					\
 	do {								\
 		expect_string(__wrap_dm_get_wwid, name, alias);		\
 		expect_value(__wrap_dm_get_wwid, uuid_len, WWID_SIZE);	\
-		will_return(__wrap_dm_get_wwid, 0);			\
+		will_return(__wrap_dm_get_wwid, DMP_OK);		\
 		will_return(__wrap_dm_get_wwid, "WWID_USED");		\
 		expect_condlog(3, USED_STR(alias, wwid));		\
 	} while(0)
-- 
2.45.2


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

* [PATCH 24/44] libmultipath: reimplement dm_map_name() with new API
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (22 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 23/44] libmultipath: improve dm_get_wwid() return value logic Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-10 23:41   ` Benjamin Marzinski
  2024-07-09 21:39 ` [PATCH 25/44] libmultipath: reimplement dm_map_present_by_uuid() Martin Wilck
                   ` (20 subsequent siblings)
  44 siblings, 1 reply; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmultipath/devmapper.c | 34 ++++++----------------------------
 1 file changed, 6 insertions(+), 28 deletions(-)

diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index 1eebcb5..caa8385 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -1469,37 +1469,15 @@ dm_is_suspended(const char *name)
 	return info.suspended;
 }
 
-char *
-dm_mapname(int major, int minor)
+char *dm_mapname(int major, int minor)
 {
-	char * response = NULL;
-	const char *map;
-	struct dm_task *dmt;
-	int r;
+	char name[WWID_SIZE];
 
-	if (!(dmt = libmp_dm_task_create(DM_DEVICE_INFO)))
+	if (libmp_mapinfo(DM_MAP_BY_DEV,
+			  (mapid_t) { ._u = { major, minor } },
+			  (mapinfo_t) { .name = name }) != DMP_OK)
 		return NULL;
-
-	if (!dm_task_set_major(dmt, major) ||
-	    !dm_task_set_minor(dmt, minor))
-		goto bad;
-
-	r = libmp_dm_task_run(dmt);
-	if (!r) {
-		dm_log_error(2, DM_DEVICE_INFO, dmt);
-		goto bad;
-	}
-
-	map = dm_task_get_name(dmt);
-	if (map && strlen(map))
-		response = strdup((const char *)map);
-
-	dm_task_destroy(dmt);
-	return response;
-bad:
-	dm_task_destroy(dmt);
-	condlog(0, "%i:%i: error fetching map name", major, minor);
-	return NULL;
+	return strdup(name);
 }
 
 static int
-- 
2.45.2


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

* [PATCH 25/44] libmultipath: reimplement dm_map_present_by_uuid()
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (23 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 24/44] libmultipath: reimplement dm_map_name() with new API Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-09 21:39 ` [PATCH 26/44] libmultipath: reimplement dm_get_opencount() with new API Martin Wilck
                   ` (19 subsequent siblings)
  44 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

... and rename it to dm_map_present_by_wwid().

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmultipath/devmapper.c | 47 ++++++----------------------------------
 libmultipath/devmapper.h |  2 +-
 libmultipath/valid.c     |  2 +-
 tests/valid.c            | 10 ++++-----
 4 files changed, 14 insertions(+), 47 deletions(-)

diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index caa8385..8a0578e 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -1013,49 +1013,16 @@ out:
 	return r;
 }
 
-/*
- * Return
- *   1 : map with uuid exists
- *   0 : map with uuid doesn't exist
- *  -1 : error
- */
-int
-dm_map_present_by_uuid(const char *uuid)
+int dm_map_present_by_wwid(const char *wwid)
 {
-	struct dm_task *dmt;
-	struct dm_info info;
-	char prefixed_uuid[WWID_SIZE + UUID_PREFIX_LEN];
-	int r = -1;
+	char tmp[DM_UUID_LEN];
 
-	if (!uuid || uuid[0] == '\0')
-		return 0;
+	if (safe_sprintf(tmp, UUID_PREFIX "%s", wwid))
+		return DMP_ERR;
 
-	if (safe_sprintf(prefixed_uuid, UUID_PREFIX "%s", uuid))
-		goto out;
-
-	if (!(dmt = libmp_dm_task_create(DM_DEVICE_INFO)))
-		goto out;
-
-	if (!dm_task_set_uuid(dmt, prefixed_uuid))
-		goto out_task;
-
-	if (!libmp_dm_task_run(dmt)) {
-		dm_log_error(3, DM_DEVICE_INFO, dmt);
-		goto out_task;
-	}
-
-	if (!dm_task_get_info(dmt, &info))
-		goto out_task;
-
-	r = !!info.exists;
-
-out_task:
-	dm_task_destroy(dmt);
-out:
-	if (r < 0)
-		condlog(3, "%s: dm command failed in %s: %s", uuid,
-			__FUNCTION__, strerror(errno));
-	return r;
+	return libmp_mapinfo(DM_MAP_BY_UUID,
+			     (mapid_t) { .str = tmp },
+			     (mapinfo_t) { .name = NULL });
 }
 
 static int dm_dev_t (const char *mapname, char *dev_t, int len)
diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h
index 0043812..db5c5fd 100644
--- a/libmultipath/devmapper.h
+++ b/libmultipath/devmapper.h
@@ -122,7 +122,7 @@ int dm_simplecmd_flush (int task, const char *name, uint16_t udev_flags);
 int dm_simplecmd_noflush (int task, const char *name, uint16_t udev_flags);
 int dm_addmap_create (struct multipath *mpp, char *params);
 int dm_addmap_reload (struct multipath *mpp, char *params, int flush);
-int dm_map_present_by_uuid(const char *uuid);
+int dm_map_present_by_wwid(const char *uuid);
 int dm_get_map(const char *name, unsigned long long *size, char **outparams);
 int dm_get_status(const char *name, char **outstatus);
 
diff --git a/libmultipath/valid.c b/libmultipath/valid.c
index f223778..9267cef 100644
--- a/libmultipath/valid.c
+++ b/libmultipath/valid.c
@@ -360,7 +360,7 @@ is_path_valid(const char *name, struct config *conf, struct path *pp,
 	if (check_wwids_file(pp->wwid, 0) == 0)
 		return PATH_IS_VALID_NO_CHECK;
 
-	if (dm_map_present_by_uuid(pp->wwid) == 1)
+	if (dm_map_present_by_wwid(pp->wwid) == DMP_OK)
 		return PATH_IS_VALID;
 
 	/* all these act like FIND_MULTIPATHS_STRICT for finding if a
diff --git a/tests/valid.c b/tests/valid.c
index 18a5a7b..a93bbe5 100644
--- a/tests/valid.c
+++ b/tests/valid.c
@@ -189,7 +189,7 @@ int __wrap_check_wwids_file(char *wwid, int write_wwid)
 		return -1;
 }
 
-int __wrap_dm_map_present_by_uuid(const char *uuid)
+int __wrap_dm_map_present_by_wwid(const char *uuid)
 {
 	int ret = mock_type(int);
 	assert_string_equal(uuid, mock_ptr_type(char *));
@@ -271,8 +271,8 @@ static void setup_passing(char *name, char *wwid, unsigned int check_multipathd,
 	will_return(__wrap_check_wwids_file, wwid);
 	if (stage == STAGE_CHECK_WWIDS)
 		return;
-	will_return(__wrap_dm_map_present_by_uuid, 0);
-	will_return(__wrap_dm_map_present_by_uuid, wwid);
+	will_return(__wrap_dm_map_present_by_wwid, 0);
+	will_return(__wrap_dm_map_present_by_wwid, wwid);
 }
 
 static void test_bad_arguments(void **state)
@@ -516,8 +516,8 @@ static void test_check_uuid_present(void **state)
 	memset(&pp, 0, sizeof(pp));
 	conf.find_multipaths = FIND_MULTIPATHS_STRICT;
 	setup_passing(name, wwid, CHECK_MPATHD_RUNNING, STAGE_CHECK_WWIDS);
-	will_return(__wrap_dm_map_present_by_uuid, 1);
-	will_return(__wrap_dm_map_present_by_uuid, wwid);
+	will_return(__wrap_dm_map_present_by_wwid, 1);
+	will_return(__wrap_dm_map_present_by_wwid, wwid);
 	assert_int_equal(is_path_valid(name, &conf, &pp, true),
 			 PATH_IS_VALID);
 	assert_string_equal(pp.dev, name);
-- 
2.45.2


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

* [PATCH 26/44] libmultipath: reimplement dm_get_opencount() with new API
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (24 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 25/44] libmultipath: reimplement dm_map_present_by_uuid() Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-09 21:39 ` [PATCH 27/44] libmpathpersist: skip redundant dm_map_present() call Martin Wilck
                   ` (18 subsequent siblings)
  44 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmultipath/devmapper.c | 28 ++++------------------------
 1 file changed, 4 insertions(+), 24 deletions(-)

diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index 8a0578e..859a861 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -1038,34 +1038,14 @@ static int dm_dev_t (const char *mapname, char *dev_t, int len)
 	return 0;
 }
 
-int
-dm_get_opencount (const char * mapname)
+int dm_get_opencount (const char *mapname)
 {
-	int r = -1;
-	struct dm_task *dmt;
 	struct dm_info info;
 
-	if (!(dmt = libmp_dm_task_create(DM_DEVICE_INFO)))
-		return 0;
+	if (dm_get_info(mapname, &info) != 0)
+		return -1;
 
-	if (!dm_task_set_name(dmt, mapname))
-		goto out;
-
-	if (!libmp_dm_task_run(dmt)) {
-		dm_log_error(3, DM_DEVICE_INFO, dmt);
-		goto out;
-	}
-
-	if (!dm_task_get_info(dmt, &info))
-		goto out;
-
-	if (!info.exists)
-		goto out;
-
-	r = info.open_count;
-out:
-	dm_task_destroy(dmt);
-	return r;
+	return info.open_count;
 }
 
 int
-- 
2.45.2


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

* [PATCH 27/44] libmpathpersist: skip redundant dm_map_present() call
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (25 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 26/44] libmultipath: reimplement dm_get_opencount() with new API Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-09 21:39 ` [PATCH 28/44] libmultipath: implement dm_is_mpath() with new API Martin Wilck
                   ` (17 subsequent siblings)
  44 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

dm_is_mpath() returns 0 if the map does not exist, the additional
dm_map_present() call is not necessary.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmpathpersist/mpath_persist_int.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
index 6da0401..5a5ac3b 100644
--- a/libmpathpersist/mpath_persist_int.c
+++ b/libmpathpersist/mpath_persist_int.c
@@ -185,7 +185,7 @@ static int mpath_get_map(vector curmp, vector pathvec, int fd, char **palias,
 
 	condlog(3, "alias = %s", alias);
 
-	if (dm_map_present(alias) && dm_is_mpath(alias) != DM_IS_MPATH_YES) {
+	if (dm_is_mpath(alias) != DM_IS_MPATH_YES) {
 		condlog(3, "%s: not a multipath device.", alias);
 		goto out;
 	}
-- 
2.45.2


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

* [PATCH 28/44] libmultipath: implement dm_is_mpath() with new API
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (26 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 27/44] libmpathpersist: skip redundant dm_map_present() call Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-11  0:21   ` Benjamin Marzinski
  2024-07-09 21:39 ` [PATCH 29/44] libmultipath: implement dm_get_multipath() " Martin Wilck
                   ` (16 subsequent siblings)
  44 siblings, 1 reply; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmultipath/devmapper.c | 53 ++++++----------------------------------
 1 file changed, 8 insertions(+), 45 deletions(-)

diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index 859a861..6276041 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -965,52 +965,15 @@ static int dm_type_match(const char *name, char *type)
 
 int dm_is_mpath(const char *name)
 {
-	int r = DM_IS_MPATH_ERR;
-	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
-	struct dm_info info;
-	uint64_t start, length;
-	char *target_type = NULL;
-	char *params;
-	const char *uuid;
+	char uuid[DM_UUID_LEN];
+	int rc = libmp_mapinfo(DM_MAP_BY_NAME,
+			       (mapid_t) { .str = name },
+			       (mapinfo_t) { .uuid = uuid, .tgt_type = TGT_MPATH });
 
-	if (!(dmt = libmp_dm_task_create(DM_DEVICE_TABLE)))
-		goto out;
-
-	if (!dm_task_set_name(dmt, name))
-		goto out;
-
-	if (!libmp_dm_task_run(dmt)) {
-		dm_log_error(3, DM_DEVICE_TABLE, dmt);
-		goto out;
-	}
-
-	if (!dm_task_get_info(dmt, &info))
-		goto out;
-
-	r = DM_IS_MPATH_NO;
-
-	if (!info.exists)
-		goto out;
-
-	uuid = dm_task_get_uuid(dmt);
-
-	if (!uuid || strncmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN) != 0)
-		goto out;
-
-	/* Fetch 1st target */
-	if (dm_get_next_target(dmt, NULL, &start, &length, &target_type,
-			       &params) != NULL)
-		/* multiple targets */
-		goto out;
-
-	if (!target_type || strcmp(target_type, TGT_MPATH) != 0)
-		goto out;
-
-	r = DM_IS_MPATH_YES;
-out:
-	if (r < 0)
-		condlog(3, "%s: dm command failed in %s: %s", name, __func__, strerror(errno));
-	return r;
+	if (rc != DMP_OK || strncmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN))
+		return DM_IS_MPATH_NO;
+	else
+		return DM_IS_MPATH_YES;
 }
 
 int dm_map_present_by_wwid(const char *wwid)
-- 
2.45.2


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

* [PATCH 29/44] libmultipath: implement dm_get_multipath() with new API
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (27 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 28/44] libmultipath: implement dm_is_mpath() with new API Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-09 21:39 ` [PATCH 30/44] libmultipath: use libmp_mapinfo() in _dm_flush_map() Martin Wilck
                   ` (15 subsequent siblings)
  44 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmultipath/devmapper.c | 28 ++++++++++++++++------------
 1 file changed, 16 insertions(+), 12 deletions(-)

diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index 6276041..bfe202a 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -1284,7 +1284,8 @@ dm_disablegroup(const char * mapname, int index)
 
 struct multipath *dm_get_multipath(const char *name)
 {
-	struct multipath *mpp = NULL;
+	struct multipath __attribute((cleanup(cleanup_multipath))) *mpp = NULL;
+	char uuid[DM_UUID_LEN];
 
 	mpp = alloc_multipath();
 	if (!mpp)
@@ -1293,20 +1294,23 @@ struct multipath *dm_get_multipath(const char *name)
 	mpp->alias = strdup(name);
 
 	if (!mpp->alias)
-		goto out;
+		return NULL;
 
-	if (dm_get_map(name, &mpp->size, NULL) != DMP_OK)
-		goto out;
+	if (libmp_mapinfo(DM_MAP_BY_NAME,
+			  (mapid_t) { .str = name },
+			  (mapinfo_t) {
+				  .size = &mpp->size,
+				  .uuid = uuid,
+				  .dmi = &mpp->dmi,
+				  .tgt_type = TGT_MPATH
+			  }) != DMP_OK)
+		return NULL;
 
-	if (dm_get_wwid(name, mpp->wwid, WWID_SIZE) != DMP_OK)
-		condlog(2, "%s: failed to get uuid for %s", __func__, name);
-	if (dm_get_info(name, &mpp->dmi) != 0)
-		condlog(2, "%s: failed to get info for %s", __func__, name);
+	if (strncmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN))
+		return NULL;
 
-	return mpp;
-out:
-	free_multipath(mpp, KEEP_PATHS);
-	return NULL;
+	strlcpy(mpp->wwid, uuid + UUID_PREFIX_LEN, sizeof(mpp->wwid));
+	return steal_ptr(mpp);
 }
 
 int dm_get_maps(vector mp)
-- 
2.45.2


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

* [PATCH 30/44] libmultipath: use libmp_mapinfo() in _dm_flush_map()
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (28 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 29/44] libmultipath: implement dm_get_multipath() " Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-09 21:39 ` [PATCH 31/44] libmultipath: add is_mpath_uuid() helper Martin Wilck
                   ` (14 subsequent siblings)
  44 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

We can spare one dm ioctl here.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmultipath/devmapper.c | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index bfe202a..806ffb8 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -1056,10 +1056,16 @@ int _dm_flush_map (const char *mapname, int flags, int retries)
 	int r;
 	int queue_if_no_path = 0;
 	int udev_flags = 0;
-	unsigned long long mapsize;
-	char *params = NULL;
+	char *params __attribute__((cleanup(cleanup_charp))) = NULL;
+	char uuid[DM_UUID_LEN];
 
-	if (dm_is_mpath(mapname) != DM_IS_MPATH_YES)
+	if (libmp_mapinfo(DM_MAP_BY_NAME,
+			  (mapid_t) { .str = mapname },
+			  (mapinfo_t) {
+				  .uuid = uuid,
+				  .tgt_type = TGT_MPATH,
+				  .target = &params }) != DMP_OK
+	    || strncmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN))
 		return DM_FLUSH_OK; /* nothing to do */
 
 	/* if the device currently has no partitions, do not
@@ -1073,7 +1079,6 @@ int _dm_flush_map (const char *mapname, int flags, int retries)
 			return DM_FLUSH_BUSY;
 
 	if ((flags & DMFL_SUSPEND) &&
-	    dm_get_map(mapname, &mapsize, &params) == DMP_OK &&
 	    strstr(params, "queue_if_no_path")) {
 		if (!_dm_queue_if_no_path(mapname, 0))
 			queue_if_no_path = 1;
@@ -1081,8 +1086,6 @@ int _dm_flush_map (const char *mapname, int flags, int retries)
 			/* Leave queue_if_no_path alone if unset failed */
 			queue_if_no_path = -1;
 	}
-	free(params);
-	params = NULL;
 
 	if ((r = dm_remove_partmaps(mapname, flags)))
 		return r;
-- 
2.45.2


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

* [PATCH 31/44] libmultipath: add is_mpath_uuid() helper
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (29 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 30/44] libmultipath: use libmp_mapinfo() in _dm_flush_map() Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-11  3:38   ` Benjamin Marzinski
  2024-07-09 21:39 ` [PATCH 32/44] libmultipath: add is_mpath_part_uuid() helper Martin Wilck
                   ` (13 subsequent siblings)
  44 siblings, 1 reply; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

Export it, as it will be used by multipathd and libmpathpersist.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmultipath/devmapper.c          | 13 +++++++++----
 libmultipath/devmapper.h          |  2 ++
 libmultipath/libmultipath.version |  1 +
 3 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index 806ffb8..5f6c0c8 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -829,6 +829,11 @@ int dm_get_map(const char *name, unsigned long long *size, char **outparams)
 	}
 }
 
+bool is_mpath_uuid(const char uuid[DM_UUID_LEN])
+{
+	return !strncmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN);
+}
+
 /**
  * dm_get_wwid(): return WWID for a multipath map
  * @returns:
@@ -845,7 +850,7 @@ int dm_get_wwid(const char *name, char *uuid, int uuid_len)
 	if (rc != DMP_OK)
 		return rc;
 
-	if (!strncmp(tmp, UUID_PREFIX, UUID_PREFIX_LEN))
+	if (is_mpath_uuid(tmp))
 		strlcpy(uuid, tmp + UUID_PREFIX_LEN, uuid_len);
 	else {
 		uuid[0] = '\0';
@@ -970,7 +975,7 @@ int dm_is_mpath(const char *name)
 			       (mapid_t) { .str = name },
 			       (mapinfo_t) { .uuid = uuid, .tgt_type = TGT_MPATH });
 
-	if (rc != DMP_OK || strncmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN))
+	if (rc != DMP_OK || !is_mpath_uuid(uuid))
 		return DM_IS_MPATH_NO;
 	else
 		return DM_IS_MPATH_YES;
@@ -1065,7 +1070,7 @@ int _dm_flush_map (const char *mapname, int flags, int retries)
 				  .uuid = uuid,
 				  .tgt_type = TGT_MPATH,
 				  .target = &params }) != DMP_OK
-	    || strncmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN))
+	    || !is_mpath_uuid(uuid))
 		return DM_FLUSH_OK; /* nothing to do */
 
 	/* if the device currently has no partitions, do not
@@ -1309,7 +1314,7 @@ struct multipath *dm_get_multipath(const char *name)
 			  }) != DMP_OK)
 		return NULL;
 
-	if (strncmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN))
+	if (!is_mpath_uuid(uuid))
 		return NULL;
 
 	strlcpy(mpp->wwid, uuid + UUID_PREFIX_LEN, sizeof(mpp->wwid));
diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h
index db5c5fd..a2b2837 100644
--- a/libmultipath/devmapper.h
+++ b/libmultipath/devmapper.h
@@ -131,6 +131,8 @@ enum {
 	DM_IS_MPATH_YES,
 	DM_IS_MPATH_ERR,
 };
+
+bool is_mpath_uuid(const char uuid[DM_UUID_LEN]);
 int dm_is_mpath(const char *name);
 
 enum {
diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version
index 7d3ff63..5b8f9e0 100644
--- a/libmultipath/libmultipath.version
+++ b/libmultipath/libmultipath.version
@@ -127,6 +127,7 @@ global:
 	init_foreign;
 	init_prio;
 	io_err_stat_handle_pathfail;
+	is_mpath_uuid;
 	is_path_valid;
 	libmp_dm_task_create;
 	libmp_get_version;
-- 
2.45.2


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

* [PATCH 32/44] libmultipath: add is_mpath_part_uuid() helper
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (30 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 31/44] libmultipath: add is_mpath_uuid() helper Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-09 21:39 ` [PATCH 33/44] libmultipath: add dmp_errstr() helper Martin Wilck
                   ` (12 subsequent siblings)
  44 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmultipath/devmapper.c | 28 ++++++++++++++++++----------
 1 file changed, 18 insertions(+), 10 deletions(-)

diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index 5f6c0c8..d321041 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -860,21 +860,15 @@ int dm_get_wwid(const char *name, char *uuid, int uuid_len)
 	return DMP_OK;
 }
 
-static int is_mpath_part(const char *part_name, const char *map_name)
+static bool is_mpath_part_uuid(const char part_uuid[DM_UUID_LEN],
+			       const char map_uuid[DM_UUID_LEN])
 {
-	char part_uuid[DM_UUID_LEN], map_uuid[DM_UUID_LEN], c;
+	char c;
 	int np, nc;
 
-	if (dm_get_dm_uuid(part_name, part_uuid) != DMP_OK)
-		return 0;
-
 	if (2 != sscanf(part_uuid, "part%d-%n" UUID_PREFIX "%c", &np, &nc, &c)
 	    || np <= 0)
-		return 0;
-
-	if (dm_get_dm_uuid(map_name, map_uuid) != DMP_OK)
-		return 0;
-
+		return false;
 	return !strcmp(part_uuid + nc, map_uuid);
 }
 
@@ -968,6 +962,20 @@ static int dm_type_match(const char *name, char *type)
 		return DM_TYPE_NOMATCH;
 }
 
+static bool is_mpath_part(const char *part_name, const char *map_name)
+{
+	char part_uuid[DM_UUID_LEN], map_uuid[DM_UUID_LEN];
+
+	if (dm_get_dm_uuid(map_name, map_uuid) != DMP_OK
+	    || !is_mpath_uuid(map_uuid))
+		return false;
+
+	if (dm_get_dm_uuid(part_name, part_uuid) != DMP_OK)
+		return false;
+
+	return is_mpath_part_uuid(part_uuid, map_uuid);
+}
+
 int dm_is_mpath(const char *name)
 {
 	char uuid[DM_UUID_LEN];
-- 
2.45.2


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

* [PATCH 33/44] libmultipath: add dmp_errstr() helper
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (31 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 32/44] libmultipath: add is_mpath_part_uuid() helper Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-09 21:39 ` [PATCH 34/44] libmultipath: use libmp_mapinfo() in do_foreach_partmaps() Martin Wilck
                   ` (11 subsequent siblings)
  44 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmultipath/devmapper.c | 14 ++++++++++++++
 libmultipath/devmapper.h |  3 +++
 2 files changed, 17 insertions(+)

diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index d321041..f7ad7a8 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -79,6 +79,20 @@ static void libmp_udev_wait(unsigned int c)
 }
 #endif
 
+const char *dmp_errstr(int rc)
+{
+	static const char *str[] = {
+		[DMP_ERR] = "generic error",
+		[DMP_OK] = "success",
+		[DMP_NOT_FOUND] = "not found",
+		[DMP_NO_MATCH] = "target type mismatch",
+		[__DMP_LAST__] = "**invalid**",
+	};
+	if (rc < 0 || rc > __DMP_LAST__)
+		rc = __DMP_LAST__;
+	return str[rc];
+}
+
 int libmp_dm_task_run(struct dm_task *dmt)
 {
 	int r;
diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h
index a2b2837..ed5e866 100644
--- a/libmultipath/devmapper.h
+++ b/libmultipath/devmapper.h
@@ -33,8 +33,11 @@ enum {
 	DMP_OK,
 	DMP_NOT_FOUND,
 	DMP_NO_MATCH,
+	__DMP_LAST__,
 };
 
+const char* dmp_errstr(int rc);
+
 /**
  * enum mapinfo_flags: input flags for libmp_mapinfo()
  */
-- 
2.45.2


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

* [PATCH 34/44] libmultipath: use libmp_mapinfo() in do_foreach_partmaps()
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (32 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 33/44] libmultipath: add dmp_errstr() helper Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-09 21:39 ` [PATCH 35/44] libmultipath: use libmp_pathinfo() in update_multipath_table() Martin Wilck
                   ` (10 subsequent siblings)
  44 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

Also, simplify the if statement a bit.
drop is_mpath_part() and dm_type_match, because do_foreach_partmaps() was the
last user of these functions.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmultipath/devmapper.c | 102 +++++++++++----------------------------
 1 file changed, 28 insertions(+), 74 deletions(-)

diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index f7ad7a8..185c76b 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -936,60 +936,6 @@ out:
 	return r;
 }
 
-enum {
-	DM_TYPE_NOMATCH = 0,
-	DM_TYPE_MATCH,
-	/* more than 1 target */
-	DM_TYPE_MULTI,
-	/* empty map */
-	DM_TYPE_EMPTY,
-	DM_TYPE_ERR,
-};
-static int dm_type_match(const char *name, char *type)
-{
-	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
-	uint64_t start, length;
-	char *target_type = NULL;
-	char *params;
-
-	if (!(dmt = libmp_dm_task_create(DM_DEVICE_TABLE)))
-		return DM_TYPE_ERR;
-
-	if (!dm_task_set_name(dmt, name))
-		return DM_TYPE_ERR;
-
-	if (!libmp_dm_task_run(dmt)) {
-		dm_log_error(3, DM_DEVICE_TABLE, dmt);
-		return DM_TYPE_ERR;
-	}
-
-	/* Fetch 1st target */
-	if (dm_get_next_target(dmt, NULL, &start, &length,
-			       &target_type, &params) != NULL)
-		/* multiple targets */
-		return DM_TYPE_MULTI;
-	else if (!target_type)
-		return DM_TYPE_EMPTY;
-	else if (!strcmp(target_type, type))
-		return DM_TYPE_MATCH;
-	else
-		return DM_TYPE_NOMATCH;
-}
-
-static bool is_mpath_part(const char *part_name, const char *map_name)
-{
-	char part_uuid[DM_UUID_LEN], map_uuid[DM_UUID_LEN];
-
-	if (dm_get_dm_uuid(map_name, map_uuid) != DMP_OK
-	    || !is_mpath_uuid(map_uuid))
-		return false;
-
-	if (dm_get_dm_uuid(part_name, part_uuid) != DMP_OK)
-		return false;
-
-	return is_mpath_part_uuid(part_uuid, map_uuid);
-}
-
 int dm_is_mpath(const char *name)
 {
 	char uuid[DM_UUID_LEN];
@@ -1425,7 +1371,7 @@ char *dm_mapname(int major, int minor)
 }
 
 static int
-do_foreach_partmaps (const char * mapname,
+do_foreach_partmaps (const char *mapname,
 		     int (*partmap_func)(const char *, void *),
 		     void *data)
 {
@@ -1433,10 +1379,20 @@ do_foreach_partmaps (const char * mapname,
 	char __attribute__((cleanup(cleanup_charp))) *params = NULL;
 	struct dm_names *names;
 	unsigned next = 0;
-	unsigned long long size;
-	char dev_t[32];
+	char dev_t[BLK_DEV_SIZE];
 	int r = 1;
 	char *p;
+	char map_uuid[DM_UUID_LEN];
+	struct dm_info info;
+
+	if (libmp_mapinfo(DM_MAP_BY_NAME,
+			  (mapid_t) { .str = mapname },
+			  (mapinfo_t) { .uuid = map_uuid, .dmi = &info }) != DMP_OK
+	    || !is_mpath_uuid(map_uuid))
+		return 1;
+
+	if (safe_sprintf(dev_t, "%i:%i", info.major, info.minor))
+		return 1;
 
 	if (!(dmt = libmp_dm_task_create(DM_DEVICE_LIST)))
 		return 1;
@@ -1451,41 +1407,39 @@ do_foreach_partmaps (const char * mapname,
 		/* this is perfectly valid */
 		return 0;
 
-	if (dm_dev_t(mapname, &dev_t[0], 32))
-		return 1;
-
 	do {
+		char part_uuid[DM_UUID_LEN];
+
 		if (
 		    /*
 		     * if there is only a single "linear" target
 		     */
-		    (dm_type_match(names->name, TGT_PART) == DM_TYPE_MATCH) &&
-
+		    libmp_mapinfo(DM_MAP_BY_NAME,
+				  (mapid_t) { .str = names->name },
+				  (mapinfo_t) {
+					  .tgt_type = TGT_PART,
+					  .uuid = part_uuid,
+					  .target = &params,
+				  }) == DMP_OK &&
 		    /*
 		     * and the uuid of the target is a partition of the
 		     * uuid of the multipath device
 		     */
-		    is_mpath_part(names->name, mapname) &&
-
-		    /*
-		     * and we can fetch the map table from the kernel
-		     */
-		    dm_get_map(names->name, &size, &params) == DMP_OK &&
+		    is_mpath_part_uuid(part_uuid, map_uuid) &&
 
 		    /*
 		     * and the table maps over the multipath map
 		     */
 		    (p = strstr(params, dev_t)) &&
-		    !isdigit(*(p + strlen(dev_t)))
-		   ) {
-			if ((r = partmap_func(names->name, data)) != 0)
-				return 1;
-		}
+		    !isdigit(*(p + strlen(dev_t))) &&
+
+		    (r = partmap_func(names->name, data)) != 0)
+			return 1;
 
 		free(params);
 		params = NULL;
 		next = names->next;
-		names = (void *) names + next;
+		names = (void*) names + next;
 	} while (next);
 
 	return 0;
-- 
2.45.2


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

* [PATCH 35/44] libmultipath: use libmp_pathinfo() in update_multipath_table()
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (33 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 34/44] libmultipath: use libmp_mapinfo() in do_foreach_partmaps() Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-11  5:16   ` Benjamin Marzinski
  2024-07-09 21:39 ` [PATCH 36/44] libmultipath: update mpp->dmi " Martin Wilck
                   ` (9 subsequent siblings)
  44 siblings, 1 reply; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

This allows us to remove dm_get_status(), and dm_get_map(), of which
update_multipath_table() was the last caller.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmultipath/devmapper.c   | 89 --------------------------------------
 libmultipath/devmapper.h   |  2 -
 libmultipath/structs_vec.c | 22 +++++-----
 3 files changed, 12 insertions(+), 101 deletions(-)

diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index 185c76b..105e838 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -804,45 +804,6 @@ static int dm_get_dm_uuid(const char *mapname, char uuid[DM_UUID_LEN])
 			     (mapinfo_t) { .uuid = uuid });
 }
 
-int dm_get_map(const char *name, unsigned long long *size, char **outparams)
-{
-	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
-	uint64_t start, length;
-	char *target_type = NULL;
-	char *params = NULL;
-
-	if (!(dmt = libmp_dm_task_create(DM_DEVICE_TABLE)))
-		return DMP_ERR;
-
-	if (!dm_task_set_name(dmt, name))
-		return DMP_ERR;
-
-	errno = 0;
-	if (!libmp_dm_task_run(dmt)) {
-		dm_log_error(3, DM_DEVICE_TABLE, dmt);
-		if (dm_task_get_errno(dmt) == ENXIO)
-			return DMP_NOT_FOUND;
-		else
-			return DMP_ERR;
-	}
-
-	/* Fetch 1st target */
-	if (dm_get_next_target(dmt, NULL, &start, &length,
-			       &target_type, &params) != NULL || !params)
-		/* more than one target or not found target */
-		return DMP_NOT_FOUND;
-
-	if (size)
-		*size = length;
-
-	if (!outparams)
-		return DMP_OK;
-	else {
-		*outparams = strdup(params);
-		return *outparams ? DMP_OK : DMP_ERR;
-	}
-}
-
 bool is_mpath_uuid(const char uuid[DM_UUID_LEN])
 {
 	return !strncmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN);
@@ -886,56 +847,6 @@ static bool is_mpath_part_uuid(const char part_uuid[DM_UUID_LEN],
 	return !strcmp(part_uuid + nc, map_uuid);
 }
 
-int dm_get_status(const char *name, char **outstatus)
-{
-	int r = DMP_ERR;
-	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
-	uint64_t start, length;
-	char *target_type = NULL;
-	char *status = NULL;
-
-	if (!(dmt = libmp_dm_task_create(DM_DEVICE_STATUS)))
-		return r;
-
-	if (!dm_task_set_name(dmt, name))
-		goto out;
-
-	errno = 0;
-	if (!libmp_dm_task_run(dmt)) {
-		dm_log_error(3, DM_DEVICE_STATUS, dmt);
-		if (dm_task_get_errno(dmt) == ENXIO)
-			r = DMP_NOT_FOUND;
-		goto out;
-	}
-
-	r = DMP_NOT_FOUND;
-	/* Fetch 1st target */
-	if (dm_get_next_target(dmt, NULL, &start, &length,
-			       &target_type, &status) != NULL)
-		goto out;
-
-	if (!target_type || strcmp(target_type, TGT_MPATH) != 0)
-		goto out;
-
-	if (!status) {
-		condlog(2, "got null status.");
-		goto out;
-	}
-
-	if (!outstatus)
-		r = DMP_OK;
-	else {
-		*outstatus = strdup(status);
-		r = *outstatus ? DMP_OK : DMP_ERR;
-	}
-out:
-	if (r != DMP_OK)
-		condlog(0, "%s: %s: error getting map status string: %d",
-			__func__, name, r);
-
-	return r;
-}
-
 int dm_is_mpath(const char *name)
 {
 	char uuid[DM_UUID_LEN];
diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h
index ed5e866..cb5151e 100644
--- a/libmultipath/devmapper.h
+++ b/libmultipath/devmapper.h
@@ -126,8 +126,6 @@ int dm_simplecmd_noflush (int task, const char *name, uint16_t udev_flags);
 int dm_addmap_create (struct multipath *mpp, char *params);
 int dm_addmap_reload (struct multipath *mpp, char *params, int flush);
 int dm_map_present_by_wwid(const char *uuid);
-int dm_get_map(const char *name, unsigned long long *size, char **outparams);
-int dm_get_status(const char *name, char **outstatus);
 
 enum {
 	DM_IS_MPATH_NO,
diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
index ccc4efc..770e498 100644
--- a/libmultipath/structs_vec.c
+++ b/libmultipath/structs_vec.c
@@ -484,30 +484,32 @@ int
 update_multipath_table (struct multipath *mpp, vector pathvec, int flags)
 {
 	int r = DMP_ERR;
-	char *params = NULL;
+	char __attribute__((cleanup(cleanup_charp))) *params = NULL;
+	char __attribute__((cleanup(cleanup_charp))) *status = NULL;
 
 	if (!mpp)
 		return r;
 
-	r = dm_get_map(mpp->alias, &mpp->size, &params);
+	r = libmp_mapinfo(DM_MAP_BY_NAME,
+			  (mapid_t) { .str = mpp->alias },
+			  (mapinfo_t) {
+				  .target = &params,
+				  .status = &status,
+				  .tgt_type = TGT_MPATH
+			  });
+
 	if (r != DMP_OK) {
-		condlog(2, "%s: %s", mpp->alias, (r == DMP_ERR)? "error getting table" : "map not present");
+		condlog(2, "%s: %s", mpp->alias, dmp_errstr(r));
 		return r;
 	}
 
 	if (disassemble_map(pathvec, params, mpp)) {
 		condlog(2, "%s: cannot disassemble map", mpp->alias);
-		free(params);
 		return DMP_ERR;
 	}
 
-	free(params);
-	params = NULL;
-	if (dm_get_status(mpp->alias, &params) != DMP_OK)
-		condlog(2, "%s: %s", mpp->alias, (r == DMP_ERR)? "error getting status" : "map not present");
-	else if (disassemble_status(params, mpp))
+	if (disassemble_status(status, mpp))
 		condlog(2, "%s: cannot disassemble status", mpp->alias);
-	free(params);
 
 	/* FIXME: we should deal with the return value here */
 	update_pathvec_from_dm(pathvec, mpp, flags);
-- 
2.45.2


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

* [PATCH 36/44] libmultipath: update mpp->dmi in update_multipath_table()
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (34 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 35/44] libmultipath: use libmp_pathinfo() in update_multipath_table() Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-09 21:39 ` [PATCH 37/44] libmultipath: drop extra call to dm_map_present() in domap() Martin Wilck
                   ` (8 subsequent siblings)
  44 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

This comes almost for free now.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmultipath/structs_vec.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
index 770e498..fb3aa79 100644
--- a/libmultipath/structs_vec.c
+++ b/libmultipath/structs_vec.c
@@ -495,6 +495,7 @@ update_multipath_table (struct multipath *mpp, vector pathvec, int flags)
 			  (mapinfo_t) {
 				  .target = &params,
 				  .status = &status,
+				  .dmi = &mpp->dmi,
 				  .tgt_type = TGT_MPATH
 			  });
 
-- 
2.45.2


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

* [PATCH 37/44] libmultipath: drop extra call to dm_map_present() in domap()
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (35 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 36/44] libmultipath: update mpp->dmi " Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-09 21:39 ` [PATCH 38/44] libmultipath: split off update_multipath_table__() Martin Wilck
                   ` (7 subsequent siblings)
  44 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

dm_get_wwid() will return DMP_NOT_FOUND if the map doesn't exist.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmultipath/configure.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libmultipath/configure.c b/libmultipath/configure.c
index 565ea5c..29c11ad 100644
--- a/libmultipath/configure.c
+++ b/libmultipath/configure.c
@@ -834,6 +834,7 @@ int domap(struct multipath *mpp, char *params, int is_daemon)
 {
 	int r = DOMAP_FAIL;
 	struct config *conf;
+	char wwid[WWID_SIZE];
 
 	/*
 	 * last chance to quit before touching the devmaps
@@ -843,8 +844,7 @@ int domap(struct multipath *mpp, char *params, int is_daemon)
 		return DOMAP_DRY;
 	}
 
-	if (mpp->action == ACT_CREATE && dm_map_present(mpp->alias)) {
-		char wwid[WWID_SIZE];
+	if (mpp->action == ACT_CREATE) {
 		int rc = dm_get_wwid(mpp->alias, wwid, sizeof(wwid));
 
 		if (rc == DMP_OK && !strncmp(mpp->wwid, wwid, sizeof(wwid))) {
-- 
2.45.2


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

* [PATCH 38/44] libmultipath: split off update_multipath_table__()
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (36 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 37/44] libmultipath: drop extra call to dm_map_present() in domap() Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-09 21:39 ` [PATCH 39/44] multipath: implement check_usable_paths() with libmp_pathinfo() Martin Wilck
                   ` (6 subsequent siblings)
  44 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

Split off the part of the function that does the disassembly
from the part calling libmp_mapinfo(). This makes it possible
to call the function from a context where the map info is already
available.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmultipath/libmultipath.version |  1 +
 libmultipath/structs_vec.c        | 31 +++++++++++++++++++------------
 libmultipath/structs_vec.h        |  2 ++
 3 files changed, 22 insertions(+), 12 deletions(-)

diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version
index 5b8f9e0..54b5a23 100644
--- a/libmultipath/libmultipath.version
+++ b/libmultipath/libmultipath.version
@@ -206,6 +206,7 @@ global:
 	uninit_config;
 	update_mpp_paths;
 	update_multipath_strings;
+	update_multipath_table__;
 	update_multipath_table;
 	update_queue_mode_add_path;
 	update_queue_mode_del_path;
diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
index fb3aa79..fb74923 100644
--- a/libmultipath/structs_vec.c
+++ b/libmultipath/structs_vec.c
@@ -480,6 +480,24 @@ done:
 		condlog(2, "%s: no hwe found", mpp->alias);
 }
 
+int
+update_multipath_table__ (struct multipath *mpp, vector pathvec, int flags,
+			  const char *params, const char *status)
+{
+	if (disassemble_map(pathvec, params, mpp)) {
+		condlog(2, "%s: cannot disassemble map", mpp->alias);
+		return DMP_ERR;
+	}
+
+	if (disassemble_status(status, mpp))
+		condlog(2, "%s: cannot disassemble status", mpp->alias);
+
+	/* FIXME: we should deal with the return value here */
+	update_pathvec_from_dm(pathvec, mpp, flags);
+
+	return DMP_OK;
+}
+
 int
 update_multipath_table (struct multipath *mpp, vector pathvec, int flags)
 {
@@ -504,18 +522,7 @@ update_multipath_table (struct multipath *mpp, vector pathvec, int flags)
 		return r;
 	}
 
-	if (disassemble_map(pathvec, params, mpp)) {
-		condlog(2, "%s: cannot disassemble map", mpp->alias);
-		return DMP_ERR;
-	}
-
-	if (disassemble_status(status, mpp))
-		condlog(2, "%s: cannot disassemble status", mpp->alias);
-
-	/* FIXME: we should deal with the return value here */
-	update_pathvec_from_dm(pathvec, mpp, flags);
-
-	return DMP_OK;
+	return update_multipath_table__(mpp, pathvec, flags, params, status);
 }
 
 static struct path *find_devt_in_pathgroups(const struct multipath *mpp,
diff --git a/libmultipath/structs_vec.h b/libmultipath/structs_vec.h
index dbc4305..01f5dc4 100644
--- a/libmultipath/structs_vec.h
+++ b/libmultipath/structs_vec.h
@@ -33,6 +33,8 @@ struct multipath * add_map_with_path (struct vectors * vecs,
 				      const struct multipath *current_mpp);
 void update_queue_mode_del_path(struct multipath *mpp);
 void update_queue_mode_add_path(struct multipath *mpp);
+int update_multipath_table__ (struct multipath *mpp, vector pathvec, int flags,
+			      const char *params, const char *status);
 int update_multipath_table (struct multipath *mpp, vector pathvec, int flags);
 int update_multipath_status (struct multipath *mpp);
 vector get_used_hwes(const struct _vector *pathvec);
-- 
2.45.2


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

* [PATCH 39/44] multipath: implement check_usable_paths() with libmp_pathinfo()
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (37 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 38/44] libmultipath: split off update_multipath_table__() Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-11  5:38   ` Benjamin Marzinski
  2024-07-09 21:39 ` [PATCH 40/44] multipathd: implement add_map_without_path() with libmp_mapinfo() Martin Wilck
                   ` (5 subsequent siblings)
  44 siblings, 1 reply; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

... and use cleanup attributes. We need to call the disassemble...()
functions from multipath directly now, but we fetch exactly the data
we need from the kernel.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 multipath/main.c | 58 ++++++++++++++++++++++++++----------------------
 1 file changed, 31 insertions(+), 27 deletions(-)

diff --git a/multipath/main.c b/multipath/main.c
index c82bc86..b3b6c81 100644
--- a/multipath/main.c
+++ b/multipath/main.c
@@ -222,12 +222,14 @@ get_dm_mpvec (enum mpath_cmds cmd, vector curmp, vector pathvec, char * refwwid)
 static int check_usable_paths(struct config *conf,
 			      const char *devpath, enum devtypes dev_type)
 {
-	struct udev_device *ud = NULL;
-	struct multipath *mpp = NULL;
+	struct udev_device __attribute__((cleanup(cleanup_udev_device))) *ud = NULL;
+	struct multipath __attribute__((cleanup(cleanup_multipath_and_paths))) *mpp = NULL;
 	struct pathgroup *pg;
 	struct path *pp;
-	char *mapname;
-	vector pathvec = NULL;
+	char __attribute__((cleanup(cleanup_charp))) *params = NULL;
+	char __attribute__((cleanup(cleanup_charp))) *status = NULL;
+	vector __attribute((cleanup(cleanup_vector))) pathvec = NULL;
+	char uuid[DM_UUID_LEN];
 	dev_t devt;
 	int r = 1, i, j;
 
@@ -238,31 +240,39 @@ static int check_usable_paths(struct config *conf,
 	devt = udev_device_get_devnum(ud);
 	if (!dm_is_dm_major(major(devt))) {
 		condlog(1, "%s is not a dm device", devpath);
-		goto out;
+		return r;
 	}
 
-	mapname = dm_mapname(major(devt), minor(devt));
-	if (mapname == NULL) {
-		condlog(1, "dm device not found: %s", devpath);
-		goto out;
-	}
-
-	if (dm_is_mpath(mapname) != DM_IS_MPATH_YES) {
-		condlog(1, "%s is not a multipath map", devpath);
-		goto free;
-	}
+	mpp = alloc_multipath();
+	if (!mpp)
+		return r;
+	if (!(mpp->alias = malloc(WWID_SIZE)))
+		return r;
 
 	/* pathvec is needed for disassemble_map */
 	pathvec = vector_alloc();
 	if (pathvec == NULL)
-		goto free;
+		return r;
 
-	mpp = dm_get_multipath(mapname);
-	if (mpp == NULL)
-		goto free;
+	if (libmp_mapinfo(DM_MAP_BY_DEV,
+			  (mapid_t) { ._u = { major(devt), minor(devt) } },
+			  (mapinfo_t) {
+			      .name = mpp->alias,
+			      .uuid = uuid,
+			      .dmi = &mpp->dmi,
+			      .tgt_type = TGT_MPATH,
+			      .target = &params,
+			      .status = &status,
+		      }) != DMP_OK)
+		return r;
 
-	if (update_multipath_table(mpp, pathvec, 0) != DMP_OK)
-		    goto free;
+	if (!is_mpath_uuid(uuid))
+		return r;
+
+	strlcpy(mpp->wwid, uuid + UUID_PREFIX_LEN, sizeof(mpp->wwid));
+
+	if (update_multipath_table__(mpp, pathvec, 0, params, status) != DMP_OK)
+		return r;
 
 	vector_foreach_slot (mpp->pg, pg, i) {
 		vector_foreach_slot (pg->paths, pp, j) {
@@ -284,12 +294,6 @@ static int check_usable_paths(struct config *conf,
 found:
 	condlog(r == 0 ? 3 : 2, "%s:%s usable paths found",
 		devpath, r == 0 ? "" : " no");
-free:
-	free(mapname);
-	free_multipath(mpp, FREE_PATHS);
-	vector_free(pathvec);
-out:
-	udev_device_unref(ud);
 	return r;
 }
 
-- 
2.45.2


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

* [PATCH 40/44] multipathd: implement add_map_without_path() with libmp_mapinfo()
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (38 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 39/44] multipath: implement check_usable_paths() with libmp_pathinfo() Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-11  6:11   ` Benjamin Marzinski
  2024-07-09 21:39 ` [PATCH 41/44] libmultipath: simplify dm_get_maps() Martin Wilck
                   ` (4 subsequent siblings)
  44 siblings, 1 reply; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

Also, change the return value to int, as this is more expressive and
the returned struct multipath isn't used by the caller.

Note: this removes the call to remove_map() at the end of the function,
which doesn't make sense anyway, because update_multipath_table()
would not return error unless the table disassembly failed, in which
case nothing would have been added the the mpvec or pathvec yet.
It should be sufficient to just cleanup the local data structures when
add_map_without_path() fails.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 multipathd/main.c | 69 ++++++++++++++++++++++++-----------------------
 1 file changed, 36 insertions(+), 33 deletions(-)

diff --git a/multipathd/main.c b/multipathd/main.c
index 442a154..9e82188 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -707,48 +707,53 @@ fail:
 	return 0;
 }
 
-static struct multipath *
-add_map_without_path (struct vectors *vecs, const char *alias)
+static int add_map_without_path (struct vectors *vecs, const char *alias)
 {
-	struct multipath * mpp = alloc_multipath();
+	struct multipath __attribute__((cleanup(cleanup_multipath_and_paths)))
+		*mpp = alloc_multipath();
+	char __attribute__((cleanup(cleanup_charp))) *params = NULL;
+	char __attribute__((cleanup(cleanup_charp))) *status = NULL;
 	struct config *conf;
+	char uuid[DM_UUID_LEN];
+	int rc = DMP_ERR;
 
-	if (!mpp)
-		return NULL;
-	if (!alias) {
-		free(mpp);
-		return NULL;
-	}
+	if (!mpp || !(mpp->alias = strdup(alias)))
+		return DMP_ERR;
 
-	mpp->alias = strdup(alias);
+	if ((rc = libmp_mapinfo(DM_MAP_BY_NAME,
+				(mapid_t) { .str = mpp->alias },
+				(mapinfo_t) {
+					.uuid = uuid,
+					.tgt_type = TGT_MPATH,
+					.dmi = &mpp->dmi,
+					.target = &params,
+					.status = &status,
+				})) != DMP_OK)
+		return rc;
+
+	if (!is_mpath_uuid(uuid))
+		return DMP_NO_MATCH;
+	else
+		strlcpy(mpp->wwid, uuid + UUID_PREFIX_LEN, sizeof(mpp->wwid));
 
-	if (dm_get_info(mpp->alias, &mpp->dmi) != DMP_OK) {
-		condlog(3, "%s: cannot access table", mpp->alias);
-		goto out;
-	}
-	if (!strlen(mpp->wwid))
-		dm_get_wwid(mpp->alias, mpp->wwid, WWID_SIZE);
 	if (!strlen(mpp->wwid))
 		condlog(1, "%s: adding map with empty WWID", mpp->alias);
+
 	conf = get_multipath_config();
 	mpp->mpe = find_mpe(conf->mptable, mpp->wwid);
 	put_multipath_config(conf);
 
-	if (update_multipath_table(mpp, vecs->pathvec, 0) != DMP_OK)
-		goto out;
+	if ((rc = update_multipath_table__(mpp, vecs->pathvec, 0, params, status)) != DMP_OK)
+		return DMP_ERR;
 
 	if (!vector_alloc_slot(vecs->mpvec))
-		goto out;
-
-	vector_set_slot(vecs->mpvec, mpp);
+		return DMP_ERR;
+	vector_set_slot(vecs->mpvec, steal_ptr(mpp));
 
 	if (update_map(mpp, vecs, 1) != 0) /* map removed */
-		return NULL;
+		return DMP_ERR;
 
-	return mpp;
-out:
-	remove_map(mpp, vecs->pathvec, vecs->mpvec);
-	return NULL;
+	return DMP_OK;
 }
 
 static int
@@ -862,14 +867,9 @@ int
 ev_add_map (char * dev, const char * alias, struct vectors * vecs)
 {
 	struct multipath * mpp;
-	int reassign_maps;
+	int reassign_maps, rc;
 	struct config *conf;
 
-	if (dm_is_mpath(alias) != DM_IS_MPATH_YES) {
-		condlog(4, "%s: not a multipath map", alias);
-		return 0;
-	}
-
 	mpp = find_mp_by_alias(vecs->mpvec, alias);
 
 	if (mpp) {
@@ -907,10 +907,13 @@ ev_add_map (char * dev, const char * alias, struct vectors * vecs)
 	/*
 	 * now we can register the map
 	 */
-	if ((mpp = add_map_without_path(vecs, alias))) {
+	if ((rc = add_map_without_path(vecs, alias)) == DMP_OK) {
 		sync_map_state(mpp);
 		condlog(2, "%s: devmap %s registered", alias, dev);
 		return 0;
+	} else if (rc == DMP_NO_MATCH) {
+		condlog(4, "%s: not a multipath map", alias);
+		return 0;
 	} else {
 		condlog(2, "%s: ev_add_map failed", dev);
 		return 1;
-- 
2.45.2


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

* [PATCH 41/44] libmultipath: simplify dm_get_maps()
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (39 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 40/44] multipathd: implement add_map_without_path() with libmp_mapinfo() Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-09 21:39 ` [PATCH 42/44] llibmultipath: fix return code check for dm_is_suspended() Martin Wilck
                   ` (3 subsequent siblings)
  44 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

Make dm_get_multipath() return a distinct error code for non-multipath
targets. This way the extra call to dm_is_mpath() is not necessary any
more. As dm_get_maps() is the only caller of dm_get_multipath(), transform
it into a static function.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmultipath/devmapper.c | 44 +++++++++++++++++++++-------------------
 libmultipath/devmapper.h |  1 -
 2 files changed, 23 insertions(+), 22 deletions(-)

diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index 105e838..e653ca6 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -1169,40 +1169,43 @@ dm_disablegroup(const char * mapname, int index)
 	return dm_groupmsg("disable", mapname, index);
 }
 
-struct multipath *dm_get_multipath(const char *name)
+static int dm_get_multipath(const char *name, struct multipath **pmpp)
 {
 	struct multipath __attribute((cleanup(cleanup_multipath))) *mpp = NULL;
 	char uuid[DM_UUID_LEN];
+	int rc;
 
 	mpp = alloc_multipath();
 	if (!mpp)
-		return NULL;
+		return DMP_ERR;
 
 	mpp->alias = strdup(name);
 
 	if (!mpp->alias)
-		return NULL;
+		return DMP_ERR;
 
-	if (libmp_mapinfo(DM_MAP_BY_NAME,
+	if ((rc = libmp_mapinfo(DM_MAP_BY_NAME,
 			  (mapid_t) { .str = name },
 			  (mapinfo_t) {
 				  .size = &mpp->size,
 				  .uuid = uuid,
 				  .dmi = &mpp->dmi,
 				  .tgt_type = TGT_MPATH
-			  }) != DMP_OK)
-		return NULL;
+			  })) != DMP_OK)
+		return rc;
 
 	if (!is_mpath_uuid(uuid))
-		return NULL;
+		return DMP_NO_MATCH;
 
 	strlcpy(mpp->wwid, uuid + UUID_PREFIX_LEN, sizeof(mpp->wwid));
-	return steal_ptr(mpp);
+	*pmpp = steal_ptr(mpp);
+
+	return DMP_OK;
 }
 
 int dm_get_maps(vector mp)
 {
-	struct multipath * mpp;
+	struct multipath *mpp = NULL;
 	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
 	struct dm_names *names;
 	unsigned next = 0;
@@ -1227,20 +1230,19 @@ int dm_get_maps(vector mp)
 	}
 
 	do {
-		if (dm_is_mpath(names->name) != DM_IS_MPATH_YES)
-			goto next;
-
-		mpp = dm_get_multipath(names->name);
-		if (!mpp)
-			return 1;
-
-		if (!vector_alloc_slot(mp)) {
-			free_multipath(mpp, KEEP_PATHS);
+		switch (dm_get_multipath(names->name, &mpp)) {
+		case DMP_OK:
+			if (!vector_alloc_slot(mp)) {
+				free_multipath(mpp, KEEP_PATHS);
+				return 1;
+			}
+			vector_set_slot(mp, mpp);
+			break;
+		case DMP_NO_MATCH:
+			break;
+		default:
 			return 1;
 		}
-
-		vector_set_slot(mp, mpp);
-next:
 		next = names->next;
 		names = (void *) names + next;
 	} while (next);
diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h
index cb5151e..d9e9bcc 100644
--- a/libmultipath/devmapper.h
+++ b/libmultipath/devmapper.h
@@ -179,7 +179,6 @@ int dm_rename (const char * old, char * new, char * delim, int skip_kpartx);
 int dm_reassign(const char * mapname);
 int dm_reassign_table(const char *name, char *old, char *new);
 int dm_setgeometry(struct multipath *mpp);
-struct multipath *dm_get_multipath(const char *name);
 
 #define VERSION_GE(v, minv) ( \
 	(v[0] > minv[0]) || \
-- 
2.45.2


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

* [PATCH 42/44] llibmultipath: fix return code check for dm_is_suspended()
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (40 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 41/44] libmultipath: simplify dm_get_maps() Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-11  6:27   ` Benjamin Marzinski
  2024-07-09 21:39 ` [PATCH 43/44] libmpathpersist: use libmp_mapinfo() in get_mpvec() Martin Wilck
                   ` (2 subsequent siblings)
  44 siblings, 1 reply; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

dm_is_suspended returns non-null if it failed to obtain the device
information. It's wrong to assume in this case that the device is suspended.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmultipath/devmapper.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index e653ca6..e9a0103 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -604,7 +604,7 @@ int dm_addmap_reload(struct multipath *mpp, char *params, int flush)
 	/* If the resume failed, dm will leave the device suspended, and
 	 * drop the new table, so doing a second resume will try using
 	 * the original table */
-	if (dm_is_suspended(mpp->alias))
+	if (dm_is_suspended(mpp->alias) == 1)
 		dm_simplecmd(DM_DEVICE_RESUME, mpp->alias,
 			     DMFL_NEED_SYNC | (flush ? 0 : DMFL_NO_FLUSH),
 			     udev_flags);
-- 
2.45.2


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

* [PATCH 43/44] libmpathpersist: use libmp_mapinfo() in get_mpvec()
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (41 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 42/44] llibmultipath: fix return code check for dm_is_suspended() Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-11  6:43   ` Benjamin Marzinski
  2024-07-09 21:39 ` [PATCH 44/44] libmpathpersist: use mpp->alias in do_mpath_persistent_reserve_out() Martin Wilck
  2024-07-11  6:55 ` [PATCH 00/44] multipath-tools: devmapper API refactored Benjamin Marzinski
  44 siblings, 1 reply; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

When obtaining the map name, make sure right away that the map is a multipath
device. This saves an ioctl and slightly simplifies the function.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmpathpersist/mpath_persist_int.c | 51 ++++++++++++++---------------
 1 file changed, 24 insertions(+), 27 deletions(-)

diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
index 5a5ac3b..a3e7bd8 100644
--- a/libmpathpersist/mpath_persist_int.c
+++ b/libmpathpersist/mpath_persist_int.c
@@ -157,10 +157,9 @@ static int get_mpvec(vector curmp, vector pathvec, char *refwwid)
 static int mpath_get_map(vector curmp, vector pathvec, int fd, char **palias,
 			 struct multipath **pmpp)
 {
-	int ret = MPATH_PR_DMMP_ERROR;
+	int rc;
 	struct stat info;
-	int major, minor;
-	char *alias;
+	char alias[WWID_SIZE], uuid[DM_UUID_LEN];
 	struct multipath *mpp;
 
 	if (fstat(fd, &info) != 0){
@@ -172,47 +171,45 @@ static int mpath_get_map(vector curmp, vector pathvec, int fd, char **palias,
 		return MPATH_PR_FILE_ERROR;
 	}
 
-	major = major(info.st_rdev);
-	minor = minor(info.st_rdev);
-	condlog(4, "Device  %d:%d", major, minor);
-
 	/* get alias from major:minor*/
-	alias = dm_mapname(major, minor);
-	if (!alias){
-		condlog(0, "%d:%d failed to get device alias.", major, minor);
+	rc = libmp_mapinfo(DM_MAP_BY_DEV,
+			   (mapid_t) { ._u = { major(info.st_rdev), minor(info.st_rdev) } },
+			   (mapinfo_t) {
+				   .name = alias,
+				   .uuid = uuid,
+				   .tgt_type = TGT_MPATH,
+			   });
+
+	if (rc == DMP_NO_MATCH || !is_mpath_uuid(uuid)) {
+		condlog(3, "%s: not a multipath device.", alias);
+		return MPATH_PR_DMMP_ERROR;
+	} else if (rc != DMP_OK) {
+		condlog(1, "%d:%d failed to get device alias.",
+			major(info.st_rdev), minor(info.st_rdev));
 		return MPATH_PR_DMMP_ERROR;
 	}
 
-	condlog(3, "alias = %s", alias);
-
-	if (dm_is_mpath(alias) != DM_IS_MPATH_YES) {
-		condlog(3, "%s: not a multipath device.", alias);
-		goto out;
-	}
+	condlog(4, "alias = %s", alias);
 
 	/* get info of all paths from the dm device     */
-	if (get_mpvec(curmp, pathvec, alias)){
+	if (get_mpvec(curmp, pathvec, alias)) {
 		condlog(0, "%s: failed to get device info.", alias);
-		goto out;
+		return MPATH_PR_DMMP_ERROR;
 	}
 
 	mpp = find_mp_by_alias(curmp, alias);
 
 	if (!mpp) {
 		condlog(0, "%s: devmap not registered.", alias);
-		goto out;
+		return MPATH_PR_DMMP_ERROR;
 	}
 
-	ret = MPATH_PR_SUCCESS;
 	if (pmpp)
 		*pmpp = mpp;
-	if (palias) {
-		*palias = alias;
-		alias = NULL;
-	}
-out:
-	free(alias);
-	return ret;
+	if (palias && (*palias = strdup(alias)) == NULL)
+		return MPATH_PR_DMMP_ERROR;
+
+	return MPATH_PR_SUCCESS;
 }
 
 int do_mpath_persistent_reserve_in(vector curmp, vector pathvec,
-- 
2.45.2


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

* [PATCH 44/44] libmpathpersist: use mpp->alias in do_mpath_persistent_reserve_out()
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (42 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 43/44] libmpathpersist: use libmp_mapinfo() in get_mpvec() Martin Wilck
@ 2024-07-09 21:39 ` Martin Wilck
  2024-07-11  6:55 ` [PATCH 00/44] multipath-tools: devmapper API refactored Benjamin Marzinski
  44 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-09 21:39 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

The extra pointer "alias" isn't necessary. The mp vector is initialized
by dm_get_maps(), which will allocate mpp->alias for every map, thus we
can use it in do_mpath_persistent_reserve_out(). This allows us to simplify
both this function itself and mpath_get_map().

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmpathpersist/mpath_persist_int.c | 38 ++++++++++++-----------------
 1 file changed, 15 insertions(+), 23 deletions(-)

diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
index a3e7bd8..d215543 100644
--- a/libmpathpersist/mpath_persist_int.c
+++ b/libmpathpersist/mpath_persist_int.c
@@ -154,8 +154,7 @@ static int get_mpvec(vector curmp, vector pathvec, char *refwwid)
 	return MPATH_PR_SUCCESS ;
 }
 
-static int mpath_get_map(vector curmp, vector pathvec, int fd, char **palias,
-			 struct multipath **pmpp)
+static int mpath_get_map(vector curmp, vector pathvec, int fd, struct multipath **pmpp)
 {
 	int rc;
 	struct stat info;
@@ -206,8 +205,6 @@ static int mpath_get_map(vector curmp, vector pathvec, int fd, char **palias,
 
 	if (pmpp)
 		*pmpp = mpp;
-	if (palias && (*palias = strdup(alias)) == NULL)
-		return MPATH_PR_DMMP_ERROR;
 
 	return MPATH_PR_SUCCESS;
 }
@@ -219,7 +216,7 @@ int do_mpath_persistent_reserve_in(vector curmp, vector pathvec,
 	struct multipath *mpp;
 	int ret;
 
-	ret = mpath_get_map(curmp, pathvec, fd, NULL, &mpp);
+	ret = mpath_get_map(curmp, pathvec, fd, &mpp);
 	if (ret != MPATH_PR_SUCCESS)
 		return ret;
 
@@ -650,12 +647,11 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
 				    struct prout_param_descriptor *paramp, int noisy)
 {
 	struct multipath *mpp;
-	char *alias;
 	int ret;
 	uint64_t prkey;
 	struct config *conf;
 
-	ret = mpath_get_map(curmp, pathvec, fd, &alias, &mpp);
+	ret = mpath_get_map(curmp, pathvec, fd, &mpp);
 	if (ret != MPATH_PR_SUCCESS)
 		return ret;
 
@@ -671,21 +667,20 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
 	      (!get_be64(mpp->reservation_key) ||
 	       memcmp(paramp->key, &mpp->reservation_key, 8) == 0)))) {
 		memcpy(&mpp->reservation_key, paramp->sa_key, 8);
-		if (update_prkey_flags(alias, get_be64(mpp->reservation_key),
+		if (update_prkey_flags(mpp->alias, get_be64(mpp->reservation_key),
 				       paramp->sa_flags)) {
 			condlog(0, "%s: failed to set prkey for multipathd.",
-				alias);
-			ret = MPATH_PR_DMMP_ERROR;
-			goto out1;
+				mpp->alias);
+			return MPATH_PR_DMMP_ERROR;
 		}
 	}
 
 	if (memcmp(paramp->key, &mpp->reservation_key, 8) &&
 	    memcmp(paramp->sa_key, &mpp->reservation_key, 8) &&
 	    (prkey || rq_servact != MPATH_PROUT_REG_IGN_SA)) {
-		condlog(0, "%s: configured reservation key doesn't match: 0x%" PRIx64, alias, get_be64(mpp->reservation_key));
-		ret = MPATH_PR_SYNTAX_ERROR;
-		goto out1;
+		condlog(0, "%s: configured reservation key doesn't match: 0x%" PRIx64,
+			mpp->alias, get_be64(mpp->reservation_key));
+		return MPATH_PR_SYNTAX_ERROR;
 	}
 
 	switch(rq_servact)
@@ -704,24 +699,21 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
 		ret = mpath_prout_rel(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
 		break;
 	default:
-		ret = MPATH_PR_OTHER;
-		goto out1;
+		return MPATH_PR_OTHER;
 	}
 
 	if ((ret == MPATH_PR_SUCCESS) && ((rq_servact == MPATH_PROUT_REG_SA) ||
 				(rq_servact ==  MPATH_PROUT_REG_IGN_SA)))
 	{
 		if (prkey == 0) {
-			update_prflag(alias, 0);
-			update_prkey(alias, 0);
+			update_prflag(mpp->alias, 0);
+			update_prkey(mpp->alias, 0);
 		} else
-			update_prflag(alias, 1);
+			update_prflag(mpp->alias, 1);
 	} else if ((ret == MPATH_PR_SUCCESS) && (rq_servact == MPATH_PROUT_CLEAR_SA)) {
-		update_prflag(alias, 0);
-		update_prkey(alias, 0);
+		update_prflag(mpp->alias, 0);
+		update_prkey(mpp->alias, 0);
 	}
-out1:
-	free(alias);
 	return ret;
 }
 
-- 
2.45.2


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

* Re: [PATCH 01/44] multipath-tools CI: more fixes for arm/v7
  2024-07-09 21:38 ` [PATCH 01/44] multipath-tools CI: more fixes for arm/v7 Martin Wilck
@ 2024-07-10  7:06   ` Martin Wilck
  0 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-10  7:06 UTC (permalink / raw)
  To: Christophe Varoqui, Benjamin Marzinski; +Cc: dm-devel

This patch needs another fix on top, which got lost during my final
rebase for the submitted series:

diff --git a/tests/wrap64.h b/tests/wrap64.h
index 890fae8..af6cc2b 100644
--- a/tests/wrap64.h
+++ b/tests/wrap64.h
@@ -2,6 +2,8 @@
 #define _WRAP64_H 1
 #include <syscall.h>
 #include <linux/types.h>
+/* The following include is required for LIBAIO_REDIRECT */
+#include <libaio.h>
 #include "util.h"
 



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

* Re: [PATCH 06/44] kpartx.rules: use @BINDIR@ to locate kpartx
  2024-07-09 21:38 ` [PATCH 06/44] kpartx.rules: use @BINDIR@ to locate kpartx Martin Wilck
@ 2024-07-10 16:30   ` Benjamin Marzinski
  2024-07-10 20:15     ` Martin Wilck
  0 siblings, 1 reply; 75+ messages in thread
From: Benjamin Marzinski @ 2024-07-10 16:30 UTC (permalink / raw)
  To: Martin Wilck; +Cc: Christophe Varoqui, dm-devel

On Tue, Jul 09, 2024 at 11:38:57PM +0200, Martin Wilck wrote:
> The path for kpartx should match the installed binary.
> 
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
>  .gitignore                               | 1 +
>  kpartx/Makefile                          | 4 ++--
>  kpartx/{kpartx.rules => kpartx.rules.in} | 2 +-
>  3 files changed, 4 insertions(+), 3 deletions(-)
>  rename kpartx/{kpartx.rules => kpartx.rules.in} (96%)
> 
> diff --git a/.gitignore b/.gitignore
> index 049ffe8..355ddbb 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -12,6 +12,7 @@ config.mk
>  cscope.files
>  cscope.out
>  kpartx/kpartx
> +kpartx/kpartx.rules
>  multipath/multipath
>  multipath/multipath.8
>  multipath/multipath.conf.5
> diff --git a/kpartx/Makefile b/kpartx/Makefile
> index 7720a74..0d4c798 100644
> --- a/kpartx/Makefile
> +++ b/kpartx/Makefile

Shouldn't we have

all: $(EXEC) kpartx.rules

so that kpartx.rules gets create when running "make", like happens in the
other makefiles?

-Ben

> @@ -19,7 +19,7 @@ $(EXEC): $(OBJS)
>  	@echo building $@ because of $?
>  	$(Q)$(CC) $(CFLAGS) $(OBJS) -o $(EXEC) $(LDFLAGS) $(LIBDEPS)
>  
> -install: $(EXEC) $(EXEC).8
> +install: $(EXEC) $(EXEC).8 kpartx.rules
>  	$(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir)
>  	$(Q)$(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)
>  	$(Q)$(INSTALL_PROGRAM) -d $(DESTDIR)$(libudevdir)
> @@ -41,7 +41,7 @@ uninstall:
>  	$(Q)$(RM) $(DESTDIR)$(libudevdir)/rules.d/68-del-part-nodes.rules
>  
>  clean: dep_clean
> -	$(Q)$(RM) core *.o $(EXEC)
> +	$(Q)$(RM) core *.o $(EXEC) kpartx.rules
>  
>  include $(wildcard $(OBJS:.o=.d))
>  
> diff --git a/kpartx/kpartx.rules b/kpartx/kpartx.rules.in
> similarity index 96%
> rename from kpartx/kpartx.rules
> rename to kpartx/kpartx.rules.in
> index 8dd3369..9d87960 100644
> --- a/kpartx/kpartx.rules
> +++ b/kpartx/kpartx.rules.in
> @@ -39,6 +39,6 @@ LABEL="mpath_kpartx_end"
>  GOTO="kpartx_end"
>  
>  LABEL="run_kpartx"
> -RUN+="/sbin/kpartx -un -p -part /dev/$name"
> +RUN+="@BINDIR@/kpartx -un -p -part /dev/$name"
>  
>  LABEL="kpartx_end"
> -- 
> 2.45.2


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

* Re: [PATCH 16/44] libmultipath: add cleanup_dm_task(), and use it in devmapper.c
  2024-07-09 21:39 ` [PATCH 16/44] libmultipath: add cleanup_dm_task(), and use it in devmapper.c Martin Wilck
@ 2024-07-10 20:12   ` Benjamin Marzinski
  2024-07-10 20:18     ` Martin Wilck
  0 siblings, 1 reply; 75+ messages in thread
From: Benjamin Marzinski @ 2024-07-10 20:12 UTC (permalink / raw)
  To: Martin Wilck; +Cc: Christophe Varoqui, dm-devel

On Tue, Jul 09, 2024 at 11:39:07PM +0200, Martin Wilck wrote:
> This allows us to get rid of a lot of goto statements, and generally
> obtain cleaner code.
> 
> Additional small changes:
> 
>  - simplify the logic of dm_tgt_version(); the only caller isn't interested
>    in the nature of the error if the version couldn't be obtained.
>  - libmultipath: rename dm_type() to the more fitting dm_type_match()
>  - use symbolic return values in dm_is_mpath()
> 
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
>  libmpathpersist/mpath_persist_int.c |   2 +-
>  libmultipath/devmapper.c            | 315 ++++++++++++----------------
>  libmultipath/devmapper.h            |   7 +-
>  multipath/main.c                    |   4 +-
>  multipathd/dmevents.c               |   4 +-
>  multipathd/main.c                   |   2 +-
>  6 files changed, 145 insertions(+), 189 deletions(-)
> 
> diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
> index 178c2f5..6da0401 100644
> --- a/libmpathpersist/mpath_persist_int.c
> +++ b/libmpathpersist/mpath_persist_int.c
> @@ -185,7 +185,7 @@ static int mpath_get_map(vector curmp, vector pathvec, int fd, char **palias,
>  
>  	condlog(3, "alias = %s", alias);
>  
> -	if (dm_map_present(alias) && dm_is_mpath(alias) != 1){
> +	if (dm_map_present(alias) && dm_is_mpath(alias) != DM_IS_MPATH_YES) {
>  		condlog(3, "%s: not a multipath device.", alias);
>  		goto out;
>  	}
> diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
> index 8996c1d..3685ef7 100644
> --- a/libmultipath/devmapper.c
> +++ b/libmultipath/devmapper.c
> @@ -91,6 +91,12 @@ int libmp_dm_task_run(struct dm_task *dmt)
>  	return r;
>  }
>  
> +static void cleanup_dm_task(struct dm_task **pdmt)
> +{
> +	if (*pdmt)
> +		dm_task_destroy(*pdmt);
> +}
> +
>  __attribute__((format(printf, 4, 5))) static void
>  dm_write_log (int level, const char *file, int line, const char *f, ...)
>  {
> @@ -203,8 +209,8 @@ static void init_dm_drv_version(void)
>  
>  static int dm_tgt_version (unsigned int *version, char *str)
>  {
> -	int r = 2;
> -	struct dm_task *dmt;
> +	bool found = false;
> +	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
>  	struct dm_versions *target;
>  	struct dm_versions *last_target;
>  	unsigned int *v;
> @@ -220,31 +226,28 @@ static int dm_tgt_version (unsigned int *version, char *str)
>  	if (!libmp_dm_task_run(dmt)) {
>  		dm_log_error(2, DM_DEVICE_LIST_VERSIONS, dmt);
>  		condlog(0, "Cannot communicate with kernel DM");
> -		goto out;
> +		return 1;
>  	}
>  	target = dm_task_get_versions(dmt);
>  
>  	do {
>  		last_target = target;
>  		if (!strncmp(str, target->name, strlen(str))) {
> -			r = 1;
> +			found = true;
>  			break;
>  		}
>  		target = (void *) target + target->next;
>  	} while (last_target != target);
>  
> -	if (r == 2) {
> +	if (!found) {
>  		condlog(0, "DM %s kernel driver not loaded", str);
> -		goto out;
> +		return 1;
>  	}
>  	v = target->version;
>  	version[0] = v[0];
>  	version[1] = v[1];
>  	version[2] = v[2];
> -	r = 0;
> -out:
> -	dm_task_destroy(dmt);
> -	return r;
> +	return 0;
>  }
>  
>  static void init_dm_mpath_version(void)
> @@ -383,18 +386,18 @@ libmp_dm_task_create(int task)
>  
>  static int
>  dm_simplecmd (int task, const char *name, int flags, uint16_t udev_flags) {
> -	int r = 0;
> +	int r;
>  	int udev_wait_flag = (((flags & DMFL_NEED_SYNC) || udev_flags) &&
>  			      (task == DM_DEVICE_RESUME ||
>  			       task == DM_DEVICE_REMOVE));
>  	uint32_t cookie = 0;
> -	struct dm_task *dmt;
> +	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
>  
>  	if (!(dmt = libmp_dm_task_create (task)))
>  		return 0;
>  
>  	if (!dm_task_set_name (dmt, name))
> -		goto out;
> +		return 0;
>  
>  	dm_task_skip_lockfs(dmt);	/* for DM_DEVICE_RESUME */
>  #ifdef LIBDM_API_FLUSH
> @@ -408,7 +411,7 @@ dm_simplecmd (int task, const char *name, int flags, uint16_t udev_flags) {
>  	if (udev_wait_flag &&
>  	    !dm_task_set_cookie(dmt, &cookie,
>  				DM_UDEV_DISABLE_LIBRARY_FALLBACK | udev_flags))
> -		goto out;
> +		return 0;
>  
>  	r = libmp_dm_task_run (dmt);
>  	if (!r)
> @@ -416,8 +419,6 @@ dm_simplecmd (int task, const char *name, int flags, uint16_t udev_flags) {
>  
>  	if (udev_wait_flag)
>  			libmp_udev_wait(cookie);
> -out:
> -	dm_task_destroy (dmt);
>  	return r;
>  }
>  
> @@ -440,8 +441,9 @@ static int
>  dm_addmap (int task, const char *target, struct multipath *mpp,
>  	   char * params, int ro, uint16_t udev_flags) {
>  	int r = 0;
> -	struct dm_task *dmt;
> -	char *prefixed_uuid = NULL;
> +	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
> +	char __attribute__((cleanup(cleanup_charp))) *prefixed_uuid = NULL;
> +
>  	uint32_t cookie = 0;
>  
>  	if (task == DM_DEVICE_CREATE && strlen(mpp->wwid) == 0) {
> @@ -457,10 +459,10 @@ dm_addmap (int task, const char *target, struct multipath *mpp,
>  		return 0;
>  
>  	if (!dm_task_set_name (dmt, mpp->alias))
> -		goto addout;
> +		return 0;
>  
>  	if (!dm_task_add_target (dmt, 0, mpp->size, target, params))
> -		goto addout;
> +		return 0;
>  
>  	if (ro)
>  		dm_task_set_ro(dmt);
> @@ -469,10 +471,10 @@ dm_addmap (int task, const char *target, struct multipath *mpp,
>  		if (asprintf(&prefixed_uuid, UUID_PREFIX "%s", mpp->wwid) < 0) {
>  			condlog(0, "cannot create prefixed uuid : %s",
>  				strerror(errno));
> -			goto addout;
> +			return 0;
>  		}
>  		if (!dm_task_set_uuid(dmt, prefixed_uuid))
> -			goto freeout;
> +			return 0;
>  		dm_task_skip_lockfs(dmt);
>  #ifdef LIBDM_API_FLUSH
>  		dm_task_no_flush(dmt);
> @@ -481,33 +483,28 @@ dm_addmap (int task, const char *target, struct multipath *mpp,
>  
>  	if (mpp->attribute_flags & (1 << ATTR_MODE) &&
>  	    !dm_task_set_mode(dmt, mpp->mode))
> -		goto freeout;
> +		return 0;
>  	if (mpp->attribute_flags & (1 << ATTR_UID) &&
>  	    !dm_task_set_uid(dmt, mpp->uid))
> -		goto freeout;
> +		return 0;
>  	if (mpp->attribute_flags & (1 << ATTR_GID) &&
>  	    !dm_task_set_gid(dmt, mpp->gid))
> -		goto freeout;
> +		return 0;
> +
>  	condlog(2, "%s: %s [0 %llu %s %s]", mpp->alias,
>  		task == DM_DEVICE_RELOAD ? "reload" : "addmap", mpp->size,
>  		target, params);
>  
>  	if (task == DM_DEVICE_CREATE &&
>  	    !dm_task_set_cookie(dmt, &cookie, udev_flags))
> -		goto freeout;
> +		return 0;
>  
>  	r = libmp_dm_task_run (dmt);
>  	if (!r)
>  		dm_log_error(2, task, dmt);
>  
>  	if (task == DM_DEVICE_CREATE)
> -			libmp_udev_wait(cookie);
> -freeout:
> -	if (prefixed_uuid)
> -		free(prefixed_uuid);
> -
> -addout:
> -	dm_task_destroy (dmt);
> +		libmp_udev_wait(cookie);
>  
>  	if (r)
>  		mpp->need_reload = false;
> @@ -648,46 +645,41 @@ int dm_map_present(const char * str)
>  
>  int dm_get_map(const char *name, unsigned long long *size, char **outparams)
>  {
> -	int r = DMP_ERR;
> -	struct dm_task *dmt;
> +	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
>  	uint64_t start, length;
>  	char *target_type = NULL;
>  	char *params = NULL;
>  
>  	if (!(dmt = libmp_dm_task_create(DM_DEVICE_TABLE)))
> -		return r;
> +		return DMP_ERR;
>  
>  	if (!dm_task_set_name(dmt, name))
> -		goto out;
> +		return DMP_ERR;
>  
>  	errno = 0;
>  	if (!libmp_dm_task_run(dmt)) {
>  		dm_log_error(3, DM_DEVICE_TABLE, dmt);
>  		if (dm_task_get_errno(dmt) == ENXIO)
> -			r = DMP_NOT_FOUND;
> -		goto out;
> +			return DMP_NOT_FOUND;
> +		else
> +			return DMP_ERR;
>  	}
>  
> -	r = DMP_NOT_FOUND;
>  	/* Fetch 1st target */
>  	if (dm_get_next_target(dmt, NULL, &start, &length,
>  			       &target_type, &params) != NULL || !params)
>  		/* more than one target or not found target */
> -		goto out;
> +		return DMP_NOT_FOUND;
>  
>  	if (size)
>  		*size = length;
>  
>  	if (!outparams)
> -		r = DMP_OK;
> +		return DMP_OK;
>  	else {
>  		*outparams = strdup(params);
> -		r = *outparams ? DMP_OK : DMP_ERR;
> +		return *outparams ? DMP_OK : DMP_ERR;
>  	}
> -
> -out:
> -	dm_task_destroy(dmt);
> -	return r;
>  }
>  
>  static int
> @@ -767,7 +759,7 @@ is_mpath_part(const char *part_name, const char *map_name)
>  int dm_get_status(const char *name, char **outstatus)
>  {
>  	int r = DMP_ERR;
> -	struct dm_task *dmt;
> +	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
>  	uint64_t start, length;
>  	char *target_type = NULL;
>  	char *status = NULL;
> @@ -796,7 +788,7 @@ int dm_get_status(const char *name, char **outstatus)
>  		goto out;
>  
>  	if (!status) {
> -		condlog(2, "get null status.");
> +		condlog(2, "got null status.");
>  		goto out;
>  	}
>  
> @@ -808,62 +800,56 @@ int dm_get_status(const char *name, char **outstatus)
>  	}
>  out:
>  	if (r != DMP_OK)
> -		condlog(0, "%s: error getting map status string", name);
> +		condlog(0, "%s: %s: error getting map status string: %d",
> +			__func__, name, r);
>  
> -	dm_task_destroy(dmt);
>  	return r;
>  }
>  
> -/*
> - * returns:
> - *    1 : match
> - *    0 : no match
> - *   -1 : empty map, or more than 1 target
> - */
> -int dm_type(const char *name, char *type)
> +enum {
> +	DM_TYPE_NOMATCH = 0,
> +	DM_TYPE_MATCH,
> +	/* more than 1 target */
> +	DM_TYPE_MULTI,
> +	/* empty map */
> +	DM_TYPE_EMPTY,
> +	DM_TYPE_ERR,
> +};
> +static int dm_type_match(const char *name, char *type)
>  {
> -	int r = 0;
> -	struct dm_task *dmt;
> +	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
>  	uint64_t start, length;
>  	char *target_type = NULL;
>  	char *params;
>  
>  	if (!(dmt = libmp_dm_task_create(DM_DEVICE_TABLE)))
> -		return 0;
> +		return DM_TYPE_ERR;
>  
>  	if (!dm_task_set_name(dmt, name))
> -		goto out;
> +		return DM_TYPE_ERR;
>  
>  	if (!libmp_dm_task_run(dmt)) {
>  		dm_log_error(3, DM_DEVICE_TABLE, dmt);
> -		goto out;
> +		return DM_TYPE_ERR;
>  	}
>  
>  	/* Fetch 1st target */
>  	if (dm_get_next_target(dmt, NULL, &start, &length,
>  			       &target_type, &params) != NULL)
>  		/* multiple targets */
> -		r = -1;
> +		return DM_TYPE_MULTI;
>  	else if (!target_type)
> -		r = -1;
> +		return DM_TYPE_EMPTY;
>  	else if (!strcmp(target_type, type))
> -		r = 1;
> -
> -out:
> -	dm_task_destroy(dmt);
> -	return r;
> +		return DM_TYPE_MATCH;
> +	else
> +		return DM_TYPE_NOMATCH;
>  }
>  
> -/*
> - * returns:
> - * 1  : is multipath device
> - * 0  : is not multipath device
> - * -1 : error
> - */
>  int dm_is_mpath(const char *name)
>  {
> -	int r = -1;
> -	struct dm_task *dmt;
> +	int r = DM_IS_MPATH_ERR;
> +	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
>  	struct dm_info info;
>  	uint64_t start, length;
>  	char *target_type = NULL;
> @@ -874,41 +860,39 @@ int dm_is_mpath(const char *name)
>  		goto out;
>  
>  	if (!dm_task_set_name(dmt, name))
> -		goto out_task;
> +		goto out;
>  
>  	if (!libmp_dm_task_run(dmt)) {
>  		dm_log_error(3, DM_DEVICE_TABLE, dmt);
> -		goto out_task;
> +		goto out;
>  	}
>  
>  	if (!dm_task_get_info(dmt, &info))
> -		goto out_task;
> +		goto out;
>  
> -	r = 0;
> +	r = DM_IS_MPATH_NO;
>  
>  	if (!info.exists)
> -		goto out_task;
> +		goto out;
>  
>  	uuid = dm_task_get_uuid(dmt);
>  
>  	if (!uuid || strncmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN) != 0)
> -		goto out_task;
> +		goto out;
>  
>  	/* Fetch 1st target */
>  	if (dm_get_next_target(dmt, NULL, &start, &length, &target_type,
>  			       &params) != NULL)
>  		/* multiple targets */
> -		goto out_task;
> +		goto out;
>  
>  	if (!target_type || strcmp(target_type, TGT_MPATH) != 0)
> -		goto out_task;
> +		goto out;
>  
> -	r = 1;
> -out_task:
> -	dm_task_destroy(dmt);
> +	r = DM_IS_MPATH_YES;
>  out:
>  	if (r < 0)
> -		condlog(3, "%s: dm command failed in %s: %s", name, __FUNCTION__, strerror(errno));
> +		condlog(3, "%s: dm command failed in %s: %s", name, __func__, strerror(errno));
>  	return r;
>  }
>  
> @@ -1049,7 +1033,7 @@ int _dm_flush_map (const char *mapname, int flags, int retries)
>  	unsigned long long mapsize;
>  	char *params = NULL;
>  
> -	if (dm_is_mpath(mapname) != 1)
> +	if (dm_is_mpath(mapname) != DM_IS_MPATH_YES)
>  		return DM_FLUSH_OK; /* nothing to do */
>  
>  	/* if the device currently has no partitions, do not
> @@ -1096,7 +1080,7 @@ int _dm_flush_map (const char *mapname, int flags, int retries)
>  			}
>  			condlog(4, "multipath map %s removed", mapname);
>  			return DM_FLUSH_OK;
> -		} else if (dm_is_mpath(mapname) != 1) {
> +		} else if (dm_is_mpath(mapname) != DM_IS_MPATH_YES) {
>  			condlog(4, "multipath map %s removed externally",
>  				mapname);
>  			return DM_FLUSH_OK; /* raced. someone else removed it */
> @@ -1131,10 +1115,10 @@ dm_flush_map_nopaths(const char *mapname, int deferred_remove __DR_UNUSED__)
>  	return _dm_flush_map(mapname, flags, 0);
>  }
>  
> -int dm_flush_maps (int retries)
> +int dm_flush_maps(int retries)
>  {
>  	int r = DM_FLUSH_FAIL;
> -	struct dm_task *dmt;
> +	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
>  	struct dm_names *names;
>  	unsigned next = 0;
>  
> @@ -1143,15 +1127,15 @@ int dm_flush_maps (int retries)
>  
>  	if (!libmp_dm_task_run (dmt)) {
>  		dm_log_error(3, DM_DEVICE_LIST, dmt);
> -		goto out;
> +		return r;
>  	}
>  
>  	if (!(names = dm_task_get_names (dmt)))
> -		goto out;
> +		return r;
>  
>  	r = DM_FLUSH_OK;
>  	if (!names->dev)
> -		goto out;
> +		return r;
>  
>  	do {
>  		int ret;
> @@ -1163,16 +1147,13 @@ int dm_flush_maps (int retries)
>  		names = (void *) names + next;
>  	} while (next);
>  
> -out:
> -	dm_task_destroy (dmt);
>  	return r;
>  }
>  
>  int
>  dm_message(const char * mapname, char * message)
>  {
> -	int r = 1;
> -	struct dm_task *dmt;
> +	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
>  
>  	if (!(dmt = libmp_dm_task_create(DM_DEVICE_TARGET_MSG)))
>  		return 1;
> @@ -1191,13 +1172,10 @@ dm_message(const char * mapname, char * message)
>  		goto out;
>  	}
>  
> -	r = 0;
> +	return 0;
>  out:
> -	if (r)
> -		condlog(0, "DM message failed [%s]", message);
> -
> -	dm_task_destroy(dmt);
> -	return r;
> +	condlog(0, "DM message failed [%s]", message);
> +	return 1;
>  }
>  
>  int
> @@ -1305,12 +1283,10 @@ out:
>  	return NULL;
>  }
>  
> -int
> -dm_get_maps (vector mp)
> +int dm_get_maps(vector mp)
>  {
>  	struct multipath * mpp;
> -	int r = 1;
> -	struct dm_task *dmt;
> +	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
>  	struct dm_names *names;
>  	unsigned next = 0;
>  
> @@ -1322,28 +1298,28 @@ dm_get_maps (vector mp)
>  
>  	if (!libmp_dm_task_run(dmt)) {
>  		dm_log_error(3, DM_DEVICE_LIST, dmt);
> -		goto out;
> +		return 1;
>  	}
>  
>  	if (!(names = dm_task_get_names(dmt)))
> -		goto out;
> +		return 1;
>  
>  	if (!names->dev) {
> -		r = 0; /* this is perfectly valid */
> -		goto out;
> +		/* this is perfectly valid */
> +		return 0;
>  	}
>  
>  	do {
> -		if (dm_is_mpath(names->name) != 1)
> +		if (dm_is_mpath(names->name) != DM_IS_MPATH_YES)
>  			goto next;
>  
>  		mpp = dm_get_multipath(names->name);
>  		if (!mpp)
> -			goto out;
> +			return 1;
>  
>  		if (!vector_alloc_slot(mp)) {
>  			free_multipath(mpp, KEEP_PATHS);
> -			goto out;
> +			return 1;
>  		}
>  
>  		vector_set_slot(mp, mpp);
> @@ -1352,11 +1328,7 @@ next:
>  		names = (void *) names + next;
>  	} while (next);
>  
> -	r = 0;
> -	goto out;
> -out:
> -	dm_task_destroy (dmt);
> -	return r;
> +	return 0;
>  }
>  
>  int
> @@ -1419,10 +1391,10 @@ do_foreach_partmaps (const char * mapname,
>  		     int (*partmap_func)(const char *, void *),
>  		     void *data)
>  {
> -	struct dm_task *dmt;
> +	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
> +	char __attribute__((cleanup(cleanup_charp))) *params = NULL;
>  	struct dm_names *names;
>  	unsigned next = 0;
> -	char *params = NULL;
>  	unsigned long long size;
>  	char dev_t[32];
>  	int r = 1;
> @@ -1431,28 +1403,25 @@ do_foreach_partmaps (const char * mapname,
>  	if (!(dmt = libmp_dm_task_create(DM_DEVICE_LIST)))
>  		return 1;
>  
> -	if (!libmp_dm_task_run(dmt)) {
> -		dm_log_error(3, DM_DEVICE_LIST, dmt);
> -		goto out;
> -	}
> +	if (!libmp_dm_task_run(dmt))
> +		return 1;
>  
>  	if (!(names = dm_task_get_names(dmt)))
> -		goto out;
> +		return 1;
>  
> -	if (!names->dev) {
> -		r = 0; /* this is perfectly valid */
> -		goto out;
> -	}
> +	if (!names->dev)
> +		/* this is perfectly valid */
> +		return 0;
>  
>  	if (dm_dev_t(mapname, &dev_t[0], 32))
> -		goto out;
> +		return 1;
>  
>  	do {
>  		if (
>  		    /*
>  		     * if there is only a single "linear" target
>  		     */
> -		    (dm_type(names->name, TGT_PART) == 1) &&
> +		    (dm_type_match(names->name, TGT_PART) == DM_TYPE_MATCH) &&
>  
>  		    /*
>  		     * and the uuid of the target is a partition of the
> @@ -1472,7 +1441,7 @@ do_foreach_partmaps (const char * mapname,
>  		    !isdigit(*(p + strlen(dev_t)))
>  		   ) {
>  			if ((r = partmap_func(names->name, data)) != 0)
> -				goto out;
> +				return 1;
>  		}
>  
>  		free(params);
> @@ -1481,11 +1450,7 @@ do_foreach_partmaps (const char * mapname,
>  		names = (void *) names + next;
>  	} while (next);
>  
> -	r = 0;
> -out:
> -	free(params);
> -	dm_task_destroy (dmt);
> -	return r;
> +	return 0;
>  }
>  
>  struct remove_data {
> @@ -1623,7 +1588,7 @@ int
>  dm_rename (const char * old, char * new, char *delim, int skip_kpartx)
>  {
>  	int r = 0;
> -	struct dm_task *dmt;
> +	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
>  	uint32_t cookie = 0;
>  	uint16_t udev_flags = DM_UDEV_DISABLE_LIBRARY_FALLBACK | ((skip_kpartx == SKIP_KPARTX_ON)? MPATH_UDEV_NO_KPARTX_FLAG : 0);
>  
> @@ -1634,22 +1599,19 @@ dm_rename (const char * old, char * new, char *delim, int skip_kpartx)
>  		return r;
>  
>  	if (!dm_task_set_name(dmt, old))
> -		goto out;
> +		return r;
>  
>  	if (!dm_task_set_newname(dmt, new))
> -		goto out;
> +		return r;
>  
>  	if (!dm_task_set_cookie(dmt, &cookie, udev_flags))
> -		goto out;
> +		return r;
> +
>  	r = libmp_dm_task_run(dmt);
>  	if (!r)
>  		dm_log_error(2, DM_DEVICE_RENAME, dmt);
>  
>  	libmp_udev_wait(cookie);
> -
> -out:
> -	dm_task_destroy(dmt);
> -
>  	return r;
>  }
>  
> @@ -1672,9 +1634,10 @@ void dm_reassign_deps(char *table, const char *dep, const char *newdep)
>  
>  int dm_reassign_table(const char *name, char *old, char *new)
>  {
> -	int r = 0, modified = 0;
> +	int modified = 0;
>  	uint64_t start, length;
> -	struct dm_task *dmt, *reload_dmt;
> +	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
> +	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *reload_dmt = NULL;
>  	char *target, *params = NULL;
>  	char *buff;
>  	void *next = NULL;
> @@ -1683,16 +1646,16 @@ int dm_reassign_table(const char *name, char *old, char *new)
>  		return 0;
>  
>  	if (!dm_task_set_name(dmt, name))
> -		goto out;
> +		return 0;
>  
>  	if (!libmp_dm_task_run(dmt)) {
>  		dm_log_error(3, DM_DEVICE_TABLE, dmt);
> -		goto out;
> +		return 0;
>  	}
>  	if (!(reload_dmt = libmp_dm_task_create(DM_DEVICE_RELOAD)))
> -		goto out;
> +		return 0;
>  	if (!dm_task_set_name(reload_dmt, name))
> -		goto out_reload;
> +		return 0;
>  
>  	do {
>  		next = dm_get_next_target(dmt, next, &start, &length,
> @@ -1705,13 +1668,13 @@ int dm_reassign_table(const char *name, char *old, char *new)
>  			 */
>  			condlog(1, "%s: invalid target found in map %s",
>  				__func__, name);
> -			goto out_reload;
> +			return 0;
>  		}
>  		buff = strdup(params);
>  		if (!buff) {
>  			condlog(3, "%s: failed to replace target %s, "
>  				"out of memory", name, target);
> -			goto out_reload;
> +			return 0;
>  		}
>  		if (strcmp(target, TGT_MPATH) && strstr(params, old)) {
>  			condlog(3, "%s: replace target %s %s",
> @@ -1729,18 +1692,12 @@ int dm_reassign_table(const char *name, char *old, char *new)
>  		if (!libmp_dm_task_run(reload_dmt)) {
>  			dm_log_error(3, DM_DEVICE_RELOAD, reload_dmt);
>  			condlog(3, "%s: failed to reassign targets", name);
> -			goto out_reload;
> +			return 0;
>  		}
>  		dm_simplecmd_noflush(DM_DEVICE_RESUME, name,
>  				     MPATH_UDEV_RELOAD_FLAG);
>  	}
> -	r = 1;
> -
> -out_reload:
> -	dm_task_destroy(reload_dmt);
> -out:
> -	dm_task_destroy(dmt);
> -	return r;
> +	return 1;
>  }
>  
>  
> @@ -1752,10 +1709,9 @@ out:
>  int dm_reassign(const char *mapname)
>  {
>  	struct dm_deps *deps;
> -	struct dm_task *dmt;
> +	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
>  	struct dm_info info;
>  	char dev_t[32], dm_dep[32];
> -	int r = 0;
>  	unsigned int i;
>  
>  	if (dm_dev_t(mapname, &dev_t[0], 32)) {
> @@ -1769,21 +1725,21 @@ int dm_reassign(const char *mapname)
>  	}
>  
>  	if (!dm_task_set_name(dmt, mapname))
> -		goto out;
> +		return 0;
>  
>  	if (!libmp_dm_task_run(dmt)) {
>  		dm_log_error(3, DM_DEVICE_DEPS, dmt);
> -		goto out;
> +		return 0;
>  	}
>  
>  	if (!dm_task_get_info(dmt, &info))
> -		goto out;
> +		return 0;
>  
>  	if (!(deps = dm_task_get_deps(dmt)))
> -		goto out;
> +		return 0;
>  
>  	if (!info.exists)
> -		goto out;
> +		return 0;
>  
>  	for (i = 0; i < deps->count; i++) {
>  		sprintf(dm_dep, "%d:%d",
> @@ -1792,15 +1748,12 @@ int dm_reassign(const char *mapname)
>  		sysfs_check_holders(dm_dep, dev_t);
>  	}
>  
> -	r = 1;
> -out:
> -	dm_task_destroy (dmt);
> -	return r;
> +	return 1;
>  }
>  
>  int dm_setgeometry(struct multipath *mpp)
>  {
> -	struct dm_task *dmt;
> +	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
>  	struct path *pp;
>  	char heads[4], sectors[4];
>  	char cylinders[10], start[32];
> @@ -1825,7 +1778,7 @@ int dm_setgeometry(struct multipath *mpp)
>  		return 0;
>  
>  	if (!dm_task_set_name(dmt, mpp->alias))
> -		goto out;
> +		return 0;
>  
>  	/* What a sick interface ... */
>  	snprintf(heads, 4, "%u", pp->geom.heads);
> @@ -1834,14 +1787,12 @@ int dm_setgeometry(struct multipath *mpp)
>  	snprintf(start, 32, "%lu", pp->geom.start);
>  	if (!dm_task_set_geometry(dmt, cylinders, heads, sectors, start)) {
>  		condlog(3, "%s: Failed to set geometry", mpp->alias);
> -		goto out;
> +		return 0;
>  	}
>  
>  	r = libmp_dm_task_run(dmt);
>  	if (!r)
>  		dm_log_error(3, DM_DEVICE_SET_GEOMETRY, dmt);
> -out:
> -	dm_task_destroy(dmt);
>  
>  	return r;
>  }
> diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h
> index 19b79c5..9438c2d 100644
> --- a/libmultipath/devmapper.h
> +++ b/libmultipath/devmapper.h
> @@ -46,7 +46,12 @@ int dm_map_present (const char *name);
>  int dm_map_present_by_uuid(const char *uuid);
>  int dm_get_map(const char *name, unsigned long long *size, char **outparams);
>  int dm_get_status(const char *name, char **outstatus);
> -int dm_type(const char *name, char *type);
> +
> +enum {
> +	DM_IS_MPATH_NO,
> +	DM_IS_MPATH_YES,
> +	DM_IS_MPATH_ERR,
> +};
>  int dm_is_mpath(const char *name);
>  
>  enum {
> diff --git a/multipath/main.c b/multipath/main.c
> index ce702e7..c82bc86 100644
> --- a/multipath/main.c
> +++ b/multipath/main.c
> @@ -247,7 +247,7 @@ static int check_usable_paths(struct config *conf,
>  		goto out;
>  	}
>  
> -	if (dm_is_mpath(mapname) != 1) {
> +	if (dm_is_mpath(mapname) != DM_IS_MPATH_YES) {
>  		condlog(1, "%s is not a multipath map", devpath);
>  		goto free;
>  	}
> @@ -1080,7 +1080,7 @@ main (int argc, char *argv[])
>  		goto out;
>  	}
>  	if (cmd == CMD_FLUSH_ONE) {
> -		if (dm_is_mpath(dev) != 1) {
> +		if (dm_is_mpath(dev) != DM_IS_MPATH_YES) {
>  			condlog(0, "%s is not a multipath device", dev);
>  			r = RTVL_FAIL;
>  			goto out;
> diff --git a/multipathd/dmevents.c b/multipathd/dmevents.c
> index 3fbdc55..605219e 100644
> --- a/multipathd/dmevents.c
> +++ b/multipathd/dmevents.c
> @@ -170,7 +170,7 @@ static int dm_get_events(void)
>  
>  		/* Don't delete device if dm_is_mpath() fails without
>  		 * checking the device type */

Like the comments says, this check is only supposed to remove a multipath
device from the list of devices if dm_is_mpath() returns DM_IS_MPATH_NO.

See 9050cd5a1 ("libmultipath: fix false removes in dmevents polling
code")

> -		if (dm_is_mpath(names->name) == 0)
> +		if (dm_is_mpath(names->name) != DM_IS_MPATH_YES)
>  			goto next;
>  
>  		event_nr = dm_event_nr(names);
> @@ -208,7 +208,7 @@ int watch_dmevents(char *name)
>  
>  	/* We know that this is a multipath device, so only fail if
>  	 * device-mapper tells us that we're wrong */

Same here.

-Ben

> -	if (dm_is_mpath(name) == 0) {
> +	if (dm_is_mpath(name) != DM_IS_MPATH_YES) {
>  		condlog(0, "%s: not a multipath device. can't watch events",
>  			name);
>  		return -1;
> diff --git a/multipathd/main.c b/multipathd/main.c
> index 58afe14..132bb2e 100644
> --- a/multipathd/main.c
> +++ b/multipathd/main.c
> @@ -865,7 +865,7 @@ ev_add_map (char * dev, const char * alias, struct vectors * vecs)
>  	int reassign_maps;
>  	struct config *conf;
>  
> -	if (dm_is_mpath(alias) != 1) {
> +	if (dm_is_mpath(alias) != DM_IS_MPATH_YES) {
>  		condlog(4, "%s: not a multipath map", alias);
>  		return 0;
>  	}
> -- 
> 2.45.2


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

* Re: [PATCH 06/44] kpartx.rules: use @BINDIR@ to locate kpartx
  2024-07-10 16:30   ` Benjamin Marzinski
@ 2024-07-10 20:15     ` Martin Wilck
  0 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-10 20:15 UTC (permalink / raw)
  To: Benjamin Marzinski; +Cc: Christophe Varoqui, dm-devel

On Wed, 2024-07-10 at 12:30 -0400, Benjamin Marzinski wrote:
> On Tue, Jul 09, 2024 at 11:38:57PM +0200, Martin Wilck wrote:
> > The path for kpartx should match the installed binary.
> > 
> > Signed-off-by: Martin Wilck <mwilck@suse.com>
> > ---
> >  .gitignore                               | 1 +
> >  kpartx/Makefile                          | 4 ++--
> >  kpartx/{kpartx.rules => kpartx.rules.in} | 2 +-
> >  3 files changed, 4 insertions(+), 3 deletions(-)
> >  rename kpartx/{kpartx.rules => kpartx.rules.in} (96%)
> > 
> > diff --git a/.gitignore b/.gitignore
> > index 049ffe8..355ddbb 100644
> > --- a/.gitignore
> > +++ b/.gitignore
> > @@ -12,6 +12,7 @@ config.mk
> >  cscope.files
> >  cscope.out
> >  kpartx/kpartx
> > +kpartx/kpartx.rules
> >  multipath/multipath
> >  multipath/multipath.8
> >  multipath/multipath.conf.5
> > diff --git a/kpartx/Makefile b/kpartx/Makefile
> > index 7720a74..0d4c798 100644
> > --- a/kpartx/Makefile
> > +++ b/kpartx/Makefile
> 
> Shouldn't we have
> 
> all: $(EXEC) kpartx.rules
> 
> so that kpartx.rules gets create when running "make", like happens in
> the
> other makefiles?
> 

Good catch, thanks!
Martin


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

* Re: [PATCH 16/44] libmultipath: add cleanup_dm_task(), and use it in devmapper.c
  2024-07-10 20:12   ` Benjamin Marzinski
@ 2024-07-10 20:18     ` Martin Wilck
  0 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-10 20:18 UTC (permalink / raw)
  To: Benjamin Marzinski; +Cc: Christophe Varoqui, dm-devel

On Wed, 2024-07-10 at 16:12 -0400, Benjamin Marzinski wrote:
> On Tue, Jul 09, 2024 at 11:39:07PM +0200, Martin Wilck wrote:
> > This allows us to get rid of a lot of goto statements, and
> > generally
> > obtain cleaner code.
> > 
> > Additional small changes:
> > 
> >  - simplify the logic of dm_tgt_version(); the only caller isn't
> > interested
> >    in the nature of the error if the version couldn't be obtained.
> >  - libmultipath: rename dm_type() to the more fitting
> > dm_type_match()
> >  - use symbolic return values in dm_is_mpath()
> > 
> > Signed-off-by: Martin Wilck <mwilck@suse.com>
> > ---
> >  libmpathpersist/mpath_persist_int.c |   2 +-
> >  libmultipath/devmapper.c            | 315 ++++++++++++------------
> > ----
> >  libmultipath/devmapper.h            |   7 +-
> >  multipath/main.c                    |   4 +-
> >  multipathd/dmevents.c               |   4 +-
> >  multipathd/main.c                   |   2 +-
> >  6 files changed, 145 insertions(+), 189 deletions(-)
> > 
> > diff --git a/libmpathpersist/mpath_persist_int.c
> > b/libmpathpersist/mpath_persist_int.c
> > index 178c2f5..6da0401 100644
> > --- a/libmpathpersist/mpath_persist_int.c
> > +++ b/libmpathpersist/mpath_persist_int.c
> > @@ -185,7 +185,7 @@ static int mpath_get_map(vector curmp, vector
> > pathvec, int fd, char **palias,
> >  
> >  	condlog(3, "alias = %s", alias);
> >  
> > -	if (dm_map_present(alias) && dm_is_mpath(alias) != 1){
> > +	if (dm_map_present(alias) && dm_is_mpath(alias) !=
> > DM_IS_MPATH_YES) {
> >  		condlog(3, "%s: not a multipath device.", alias);
> >  		goto out;
> >  	}
> > diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
> > index 8996c1d..3685ef7 100644
> > --- a/libmultipath/devmapper.c
> > +++ b/libmultipath/devmapper.c
> > @@ -91,6 +91,12 @@ int libmp_dm_task_run(struct dm_task *dmt)
> >  	return r;
> >  }
> >  
> > +static void cleanup_dm_task(struct dm_task **pdmt)
> > +{
> > +	if (*pdmt)
> > +		dm_task_destroy(*pdmt);
> > +}
> > +
> >  __attribute__((format(printf, 4, 5))) static void
> >  dm_write_log (int level, const char *file, int line, const char
> > *f, ...)
> >  {
> > @@ -203,8 +209,8 @@ static void init_dm_drv_version(void)
> >  
> >  static int dm_tgt_version (unsigned int *version, char *str)
> >  {
> > -	int r = 2;
> > -	struct dm_task *dmt;
> > +	bool found = false;
> > +	struct dm_task __attribute__((cleanup(cleanup_dm_task)))
> > *dmt = NULL;
> >  	struct dm_versions *target;
> >  	struct dm_versions *last_target;
> >  	unsigned int *v;
> > @@ -220,31 +226,28 @@ static int dm_tgt_version (unsigned int
> > *version, char *str)
> >  	if (!libmp_dm_task_run(dmt)) {
> >  		dm_log_error(2, DM_DEVICE_LIST_VERSIONS, dmt);
> >  		condlog(0, "Cannot communicate with kernel DM");
> > -		goto out;
> > +		return 1;
> >  	}
> >  	target = dm_task_get_versions(dmt);
> >  
> >  	do {
> >  		last_target = target;
> >  		if (!strncmp(str, target->name, strlen(str))) {
> > -			r = 1;
> > +			found = true;
> >  			break;
> >  		}
> >  		target = (void *) target + target->next;
> >  	} while (last_target != target);
> >  
> > -	if (r == 2) {
> > +	if (!found) {
> >  		condlog(0, "DM %s kernel driver not loaded", str);
> > -		goto out;
> > +		return 1;
> >  	}
> >  	v = target->version;
> >  	version[0] = v[0];
> >  	version[1] = v[1];
> >  	version[2] = v[2];
> > -	r = 0;
> > -out:
> > -	dm_task_destroy(dmt);
> > -	return r;
> > +	return 0;
> >  }
> >  
> >  static void init_dm_mpath_version(void)
> > @@ -383,18 +386,18 @@ libmp_dm_task_create(int task)
> >  
> >  static int
> >  dm_simplecmd (int task, const char *name, int flags, uint16_t
> > udev_flags) {
> > -	int r = 0;
> > +	int r;
> >  	int udev_wait_flag = (((flags & DMFL_NEED_SYNC) ||
> > udev_flags) &&
> >  			      (task == DM_DEVICE_RESUME ||
> >  			       task == DM_DEVICE_REMOVE));
> >  	uint32_t cookie = 0;
> > -	struct dm_task *dmt;
> > +	struct dm_task __attribute__((cleanup(cleanup_dm_task)))
> > *dmt = NULL;
> >  
> >  	if (!(dmt = libmp_dm_task_create (task)))
> >  		return 0;
> >  
> >  	if (!dm_task_set_name (dmt, name))
> > -		goto out;
> > +		return 0;
> >  
> >  	dm_task_skip_lockfs(dmt);	/* for DM_DEVICE_RESUME */
> >  #ifdef LIBDM_API_FLUSH
> > @@ -408,7 +411,7 @@ dm_simplecmd (int task, const char *name, int
> > flags, uint16_t udev_flags) {
> >  	if (udev_wait_flag &&
> >  	    !dm_task_set_cookie(dmt, &cookie,
> >  				DM_UDEV_DISABLE_LIBRARY_FALLBACK |
> > udev_flags))
> > -		goto out;
> > +		return 0;
> >  
> >  	r = libmp_dm_task_run (dmt);
> >  	if (!r)
> > @@ -416,8 +419,6 @@ dm_simplecmd (int task, const char *name, int
> > flags, uint16_t udev_flags) {
> >  
> >  	if (udev_wait_flag)
> >  			libmp_udev_wait(cookie);
> > -out:
> > -	dm_task_destroy (dmt);
> >  	return r;
> >  }
> >  
> > @@ -440,8 +441,9 @@ static int
> >  dm_addmap (int task, const char *target, struct multipath *mpp,
> >  	   char * params, int ro, uint16_t udev_flags) {
> >  	int r = 0;
> > -	struct dm_task *dmt;
> > -	char *prefixed_uuid = NULL;
> > +	struct dm_task __attribute__((cleanup(cleanup_dm_task)))
> > *dmt = NULL;
> > +	char __attribute__((cleanup(cleanup_charp)))
> > *prefixed_uuid = NULL;
> > +
> >  	uint32_t cookie = 0;
> >  
> >  	if (task == DM_DEVICE_CREATE && strlen(mpp->wwid) == 0) {
> > @@ -457,10 +459,10 @@ dm_addmap (int task, const char *target,
> > struct multipath *mpp,
> >  		return 0;
> >  
> >  	if (!dm_task_set_name (dmt, mpp->alias))
> > -		goto addout;
> > +		return 0;
> >  
> >  	if (!dm_task_add_target (dmt, 0, mpp->size, target,
> > params))
> > -		goto addout;
> > +		return 0;
> >  
> >  	if (ro)
> >  		dm_task_set_ro(dmt);
> > @@ -469,10 +471,10 @@ dm_addmap (int task, const char *target,
> > struct multipath *mpp,
> >  		if (asprintf(&prefixed_uuid, UUID_PREFIX "%s",
> > mpp->wwid) < 0) {
> >  			condlog(0, "cannot create prefixed uuid :
> > %s",
> >  				strerror(errno));
> > -			goto addout;
> > +			return 0;
> >  		}
> >  		if (!dm_task_set_uuid(dmt, prefixed_uuid))
> > -			goto freeout;
> > +			return 0;
> >  		dm_task_skip_lockfs(dmt);
> >  #ifdef LIBDM_API_FLUSH
> >  		dm_task_no_flush(dmt);
> > @@ -481,33 +483,28 @@ dm_addmap (int task, const char *target,
> > struct multipath *mpp,
> >  
> >  	if (mpp->attribute_flags & (1 << ATTR_MODE) &&
> >  	    !dm_task_set_mode(dmt, mpp->mode))
> > -		goto freeout;
> > +		return 0;
> >  	if (mpp->attribute_flags & (1 << ATTR_UID) &&
> >  	    !dm_task_set_uid(dmt, mpp->uid))
> > -		goto freeout;
> > +		return 0;
> >  	if (mpp->attribute_flags & (1 << ATTR_GID) &&
> >  	    !dm_task_set_gid(dmt, mpp->gid))
> > -		goto freeout;
> > +		return 0;
> > +
> >  	condlog(2, "%s: %s [0 %llu %s %s]", mpp->alias,
> >  		task == DM_DEVICE_RELOAD ? "reload" : "addmap",
> > mpp->size,
> >  		target, params);
> >  
> >  	if (task == DM_DEVICE_CREATE &&
> >  	    !dm_task_set_cookie(dmt, &cookie, udev_flags))
> > -		goto freeout;
> > +		return 0;
> >  
> >  	r = libmp_dm_task_run (dmt);
> >  	if (!r)
> >  		dm_log_error(2, task, dmt);
> >  
> >  	if (task == DM_DEVICE_CREATE)
> > -			libmp_udev_wait(cookie);
> > -freeout:
> > -	if (prefixed_uuid)
> > -		free(prefixed_uuid);
> > -
> > -addout:
> > -	dm_task_destroy (dmt);
> > +		libmp_udev_wait(cookie);
> >  
> >  	if (r)
> >  		mpp->need_reload = false;
> > @@ -648,46 +645,41 @@ int dm_map_present(const char * str)
> >  
> >  int dm_get_map(const char *name, unsigned long long *size, char
> > **outparams)
> >  {
> > -	int r = DMP_ERR;
> > -	struct dm_task *dmt;
> > +	struct dm_task __attribute__((cleanup(cleanup_dm_task)))
> > *dmt = NULL;
> >  	uint64_t start, length;
> >  	char *target_type = NULL;
> >  	char *params = NULL;
> >  
> >  	if (!(dmt = libmp_dm_task_create(DM_DEVICE_TABLE)))
> > -		return r;
> > +		return DMP_ERR;
> >  
> >  	if (!dm_task_set_name(dmt, name))
> > -		goto out;
> > +		return DMP_ERR;
> >  
> >  	errno = 0;
> >  	if (!libmp_dm_task_run(dmt)) {
> >  		dm_log_error(3, DM_DEVICE_TABLE, dmt);
> >  		if (dm_task_get_errno(dmt) == ENXIO)
> > -			r = DMP_NOT_FOUND;
> > -		goto out;
> > +			return DMP_NOT_FOUND;
> > +		else
> > +			return DMP_ERR;
> >  	}
> >  
> > -	r = DMP_NOT_FOUND;
> >  	/* Fetch 1st target */
> >  	if (dm_get_next_target(dmt, NULL, &start, &length,
> >  			       &target_type, &params) != NULL ||
> > !params)
> >  		/* more than one target or not found target */
> > -		goto out;
> > +		return DMP_NOT_FOUND;
> >  
> >  	if (size)
> >  		*size = length;
> >  
> >  	if (!outparams)
> > -		r = DMP_OK;
> > +		return DMP_OK;
> >  	else {
> >  		*outparams = strdup(params);
> > -		r = *outparams ? DMP_OK : DMP_ERR;
> > +		return *outparams ? DMP_OK : DMP_ERR;
> >  	}
> > -
> > -out:
> > -	dm_task_destroy(dmt);
> > -	return r;
> >  }
> >  
> >  static int
> > @@ -767,7 +759,7 @@ is_mpath_part(const char *part_name, const char
> > *map_name)
> >  int dm_get_status(const char *name, char **outstatus)
> >  {
> >  	int r = DMP_ERR;
> > -	struct dm_task *dmt;
> > +	struct dm_task __attribute__((cleanup(cleanup_dm_task)))
> > *dmt = NULL;
> >  	uint64_t start, length;
> >  	char *target_type = NULL;
> >  	char *status = NULL;
> > @@ -796,7 +788,7 @@ int dm_get_status(const char *name, char
> > **outstatus)
> >  		goto out;
> >  
> >  	if (!status) {
> > -		condlog(2, "get null status.");
> > +		condlog(2, "got null status.");
> >  		goto out;
> >  	}
> >  
> > @@ -808,62 +800,56 @@ int dm_get_status(const char *name, char
> > **outstatus)
> >  	}
> >  out:
> >  	if (r != DMP_OK)
> > -		condlog(0, "%s: error getting map status string",
> > name);
> > +		condlog(0, "%s: %s: error getting map status
> > string: %d",
> > +			__func__, name, r);
> >  
> > -	dm_task_destroy(dmt);
> >  	return r;
> >  }
> >  
> > -/*
> > - * returns:
> > - *    1 : match
> > - *    0 : no match
> > - *   -1 : empty map, or more than 1 target
> > - */
> > -int dm_type(const char *name, char *type)
> > +enum {
> > +	DM_TYPE_NOMATCH = 0,
> > +	DM_TYPE_MATCH,
> > +	/* more than 1 target */
> > +	DM_TYPE_MULTI,
> > +	/* empty map */
> > +	DM_TYPE_EMPTY,
> > +	DM_TYPE_ERR,
> > +};
> > +static int dm_type_match(const char *name, char *type)
> >  {
> > -	int r = 0;
> > -	struct dm_task *dmt;
> > +	struct dm_task __attribute__((cleanup(cleanup_dm_task)))
> > *dmt = NULL;
> >  	uint64_t start, length;
> >  	char *target_type = NULL;
> >  	char *params;
> >  
> >  	if (!(dmt = libmp_dm_task_create(DM_DEVICE_TABLE)))
> > -		return 0;
> > +		return DM_TYPE_ERR;
> >  
> >  	if (!dm_task_set_name(dmt, name))
> > -		goto out;
> > +		return DM_TYPE_ERR;
> >  
> >  	if (!libmp_dm_task_run(dmt)) {
> >  		dm_log_error(3, DM_DEVICE_TABLE, dmt);
> > -		goto out;
> > +		return DM_TYPE_ERR;
> >  	}
> >  
> >  	/* Fetch 1st target */
> >  	if (dm_get_next_target(dmt, NULL, &start, &length,
> >  			       &target_type, &params) != NULL)
> >  		/* multiple targets */
> > -		r = -1;
> > +		return DM_TYPE_MULTI;
> >  	else if (!target_type)
> > -		r = -1;
> > +		return DM_TYPE_EMPTY;
> >  	else if (!strcmp(target_type, type))
> > -		r = 1;
> > -
> > -out:
> > -	dm_task_destroy(dmt);
> > -	return r;
> > +		return DM_TYPE_MATCH;
> > +	else
> > +		return DM_TYPE_NOMATCH;
> >  }
> >  
> > -/*
> > - * returns:
> > - * 1  : is multipath device
> > - * 0  : is not multipath device
> > - * -1 : error
> > - */
> >  int dm_is_mpath(const char *name)
> >  {
> > -	int r = -1;
> > -	struct dm_task *dmt;
> > +	int r = DM_IS_MPATH_ERR;
> > +	struct dm_task __attribute__((cleanup(cleanup_dm_task)))
> > *dmt = NULL;
> >  	struct dm_info info;
> >  	uint64_t start, length;
> >  	char *target_type = NULL;
> > @@ -874,41 +860,39 @@ int dm_is_mpath(const char *name)
> >  		goto out;
> >  
> >  	if (!dm_task_set_name(dmt, name))
> > -		goto out_task;
> > +		goto out;
> >  
> >  	if (!libmp_dm_task_run(dmt)) {
> >  		dm_log_error(3, DM_DEVICE_TABLE, dmt);
> > -		goto out_task;
> > +		goto out;
> >  	}
> >  
> >  	if (!dm_task_get_info(dmt, &info))
> > -		goto out_task;
> > +		goto out;
> >  
> > -	r = 0;
> > +	r = DM_IS_MPATH_NO;
> >  
> >  	if (!info.exists)
> > -		goto out_task;
> > +		goto out;
> >  
> >  	uuid = dm_task_get_uuid(dmt);
> >  
> >  	if (!uuid || strncmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN)
> > != 0)
> > -		goto out_task;
> > +		goto out;
> >  
> >  	/* Fetch 1st target */
> >  	if (dm_get_next_target(dmt, NULL, &start, &length,
> > &target_type,
> >  			       &params) != NULL)
> >  		/* multiple targets */
> > -		goto out_task;
> > +		goto out;
> >  
> >  	if (!target_type || strcmp(target_type, TGT_MPATH) != 0)
> > -		goto out_task;
> > +		goto out;
> >  
> > -	r = 1;
> > -out_task:
> > -	dm_task_destroy(dmt);
> > +	r = DM_IS_MPATH_YES;
> >  out:
> >  	if (r < 0)
> > -		condlog(3, "%s: dm command failed in %s: %s",
> > name, __FUNCTION__, strerror(errno));
> > +		condlog(3, "%s: dm command failed in %s: %s",
> > name, __func__, strerror(errno));
> >  	return r;
> >  }
> >  
> > @@ -1049,7 +1033,7 @@ int _dm_flush_map (const char *mapname, int
> > flags, int retries)
> >  	unsigned long long mapsize;
> >  	char *params = NULL;
> >  
> > -	if (dm_is_mpath(mapname) != 1)
> > +	if (dm_is_mpath(mapname) != DM_IS_MPATH_YES)
> >  		return DM_FLUSH_OK; /* nothing to do */
> >  
> >  	/* if the device currently has no partitions, do not
> > @@ -1096,7 +1080,7 @@ int _dm_flush_map (const char *mapname, int
> > flags, int retries)
> >  			}
> >  			condlog(4, "multipath map %s removed",
> > mapname);
> >  			return DM_FLUSH_OK;
> > -		} else if (dm_is_mpath(mapname) != 1) {
> > +		} else if (dm_is_mpath(mapname) !=
> > DM_IS_MPATH_YES) {
> >  			condlog(4, "multipath map %s removed
> > externally",
> >  				mapname);
> >  			return DM_FLUSH_OK; /* raced. someone else
> > removed it */
> > @@ -1131,10 +1115,10 @@ dm_flush_map_nopaths(const char *mapname,
> > int deferred_remove __DR_UNUSED__)
> >  	return _dm_flush_map(mapname, flags, 0);
> >  }
> >  
> > -int dm_flush_maps (int retries)
> > +int dm_flush_maps(int retries)
> >  {
> >  	int r = DM_FLUSH_FAIL;
> > -	struct dm_task *dmt;
> > +	struct dm_task __attribute__((cleanup(cleanup_dm_task)))
> > *dmt = NULL;
> >  	struct dm_names *names;
> >  	unsigned next = 0;
> >  
> > @@ -1143,15 +1127,15 @@ int dm_flush_maps (int retries)
> >  
> >  	if (!libmp_dm_task_run (dmt)) {
> >  		dm_log_error(3, DM_DEVICE_LIST, dmt);
> > -		goto out;
> > +		return r;
> >  	}
> >  
> >  	if (!(names = dm_task_get_names (dmt)))
> > -		goto out;
> > +		return r;
> >  
> >  	r = DM_FLUSH_OK;
> >  	if (!names->dev)
> > -		goto out;
> > +		return r;
> >  
> >  	do {
> >  		int ret;
> > @@ -1163,16 +1147,13 @@ int dm_flush_maps (int retries)
> >  		names = (void *) names + next;
> >  	} while (next);
> >  
> > -out:
> > -	dm_task_destroy (dmt);
> >  	return r;
> >  }
> >  
> >  int
> >  dm_message(const char * mapname, char * message)
> >  {
> > -	int r = 1;
> > -	struct dm_task *dmt;
> > +	struct dm_task __attribute__((cleanup(cleanup_dm_task)))
> > *dmt = NULL;
> >  
> >  	if (!(dmt = libmp_dm_task_create(DM_DEVICE_TARGET_MSG)))
> >  		return 1;
> > @@ -1191,13 +1172,10 @@ dm_message(const char * mapname, char *
> > message)
> >  		goto out;
> >  	}
> >  
> > -	r = 0;
> > +	return 0;
> >  out:
> > -	if (r)
> > -		condlog(0, "DM message failed [%s]", message);
> > -
> > -	dm_task_destroy(dmt);
> > -	return r;
> > +	condlog(0, "DM message failed [%s]", message);
> > +	return 1;
> >  }
> >  
> >  int
> > @@ -1305,12 +1283,10 @@ out:
> >  	return NULL;
> >  }
> >  
> > -int
> > -dm_get_maps (vector mp)
> > +int dm_get_maps(vector mp)
> >  {
> >  	struct multipath * mpp;
> > -	int r = 1;
> > -	struct dm_task *dmt;
> > +	struct dm_task __attribute__((cleanup(cleanup_dm_task)))
> > *dmt = NULL;
> >  	struct dm_names *names;
> >  	unsigned next = 0;
> >  
> > @@ -1322,28 +1298,28 @@ dm_get_maps (vector mp)
> >  
> >  	if (!libmp_dm_task_run(dmt)) {
> >  		dm_log_error(3, DM_DEVICE_LIST, dmt);
> > -		goto out;
> > +		return 1;
> >  	}
> >  
> >  	if (!(names = dm_task_get_names(dmt)))
> > -		goto out;
> > +		return 1;
> >  
> >  	if (!names->dev) {
> > -		r = 0; /* this is perfectly valid */
> > -		goto out;
> > +		/* this is perfectly valid */
> > +		return 0;
> >  	}
> >  
> >  	do {
> > -		if (dm_is_mpath(names->name) != 1)
> > +		if (dm_is_mpath(names->name) != DM_IS_MPATH_YES)
> >  			goto next;
> >  
> >  		mpp = dm_get_multipath(names->name);
> >  		if (!mpp)
> > -			goto out;
> > +			return 1;
> >  
> >  		if (!vector_alloc_slot(mp)) {
> >  			free_multipath(mpp, KEEP_PATHS);
> > -			goto out;
> > +			return 1;
> >  		}
> >  
> >  		vector_set_slot(mp, mpp);
> > @@ -1352,11 +1328,7 @@ next:
> >  		names = (void *) names + next;
> >  	} while (next);
> >  
> > -	r = 0;
> > -	goto out;
> > -out:
> > -	dm_task_destroy (dmt);
> > -	return r;
> > +	return 0;
> >  }
> >  
> >  int
> > @@ -1419,10 +1391,10 @@ do_foreach_partmaps (const char * mapname,
> >  		     int (*partmap_func)(const char *, void *),
> >  		     void *data)
> >  {
> > -	struct dm_task *dmt;
> > +	struct dm_task __attribute__((cleanup(cleanup_dm_task)))
> > *dmt = NULL;
> > +	char __attribute__((cleanup(cleanup_charp))) *params =
> > NULL;
> >  	struct dm_names *names;
> >  	unsigned next = 0;
> > -	char *params = NULL;
> >  	unsigned long long size;
> >  	char dev_t[32];
> >  	int r = 1;
> > @@ -1431,28 +1403,25 @@ do_foreach_partmaps (const char * mapname,
> >  	if (!(dmt = libmp_dm_task_create(DM_DEVICE_LIST)))
> >  		return 1;
> >  
> > -	if (!libmp_dm_task_run(dmt)) {
> > -		dm_log_error(3, DM_DEVICE_LIST, dmt);
> > -		goto out;
> > -	}
> > +	if (!libmp_dm_task_run(dmt))
> > +		return 1;
> >  
> >  	if (!(names = dm_task_get_names(dmt)))
> > -		goto out;
> > +		return 1;
> >  
> > -	if (!names->dev) {
> > -		r = 0; /* this is perfectly valid */
> > -		goto out;
> > -	}
> > +	if (!names->dev)
> > +		/* this is perfectly valid */
> > +		return 0;
> >  
> >  	if (dm_dev_t(mapname, &dev_t[0], 32))
> > -		goto out;
> > +		return 1;
> >  
> >  	do {
> >  		if (
> >  		    /*
> >  		     * if there is only a single "linear" target
> >  		     */
> > -		    (dm_type(names->name, TGT_PART) == 1) &&
> > +		    (dm_type_match(names->name, TGT_PART) ==
> > DM_TYPE_MATCH) &&
> >  
> >  		    /*
> >  		     * and the uuid of the target is a partition
> > of the
> > @@ -1472,7 +1441,7 @@ do_foreach_partmaps (const char * mapname,
> >  		    !isdigit(*(p + strlen(dev_t)))
> >  		   ) {
> >  			if ((r = partmap_func(names->name, data))
> > != 0)
> > -				goto out;
> > +				return 1;
> >  		}
> >  
> >  		free(params);
> > @@ -1481,11 +1450,7 @@ do_foreach_partmaps (const char * mapname,
> >  		names = (void *) names + next;
> >  	} while (next);
> >  
> > -	r = 0;
> > -out:
> > -	free(params);
> > -	dm_task_destroy (dmt);
> > -	return r;
> > +	return 0;
> >  }
> >  
> >  struct remove_data {
> > @@ -1623,7 +1588,7 @@ int
> >  dm_rename (const char * old, char * new, char *delim, int
> > skip_kpartx)
> >  {
> >  	int r = 0;
> > -	struct dm_task *dmt;
> > +	struct dm_task __attribute__((cleanup(cleanup_dm_task)))
> > *dmt = NULL;
> >  	uint32_t cookie = 0;
> >  	uint16_t udev_flags = DM_UDEV_DISABLE_LIBRARY_FALLBACK |
> > ((skip_kpartx == SKIP_KPARTX_ON)? MPATH_UDEV_NO_KPARTX_FLAG : 0);
> >  
> > @@ -1634,22 +1599,19 @@ dm_rename (const char * old, char * new,
> > char *delim, int skip_kpartx)
> >  		return r;
> >  
> >  	if (!dm_task_set_name(dmt, old))
> > -		goto out;
> > +		return r;
> >  
> >  	if (!dm_task_set_newname(dmt, new))
> > -		goto out;
> > +		return r;
> >  
> >  	if (!dm_task_set_cookie(dmt, &cookie, udev_flags))
> > -		goto out;
> > +		return r;
> > +
> >  	r = libmp_dm_task_run(dmt);
> >  	if (!r)
> >  		dm_log_error(2, DM_DEVICE_RENAME, dmt);
> >  
> >  	libmp_udev_wait(cookie);
> > -
> > -out:
> > -	dm_task_destroy(dmt);
> > -
> >  	return r;
> >  }
> >  
> > @@ -1672,9 +1634,10 @@ void dm_reassign_deps(char *table, const
> > char *dep, const char *newdep)
> >  
> >  int dm_reassign_table(const char *name, char *old, char *new)
> >  {
> > -	int r = 0, modified = 0;
> > +	int modified = 0;
> >  	uint64_t start, length;
> > -	struct dm_task *dmt, *reload_dmt;
> > +	struct dm_task __attribute__((cleanup(cleanup_dm_task)))
> > *dmt = NULL;
> > +	struct dm_task __attribute__((cleanup(cleanup_dm_task)))
> > *reload_dmt = NULL;
> >  	char *target, *params = NULL;
> >  	char *buff;
> >  	void *next = NULL;
> > @@ -1683,16 +1646,16 @@ int dm_reassign_table(const char *name,
> > char *old, char *new)
> >  		return 0;
> >  
> >  	if (!dm_task_set_name(dmt, name))
> > -		goto out;
> > +		return 0;
> >  
> >  	if (!libmp_dm_task_run(dmt)) {
> >  		dm_log_error(3, DM_DEVICE_TABLE, dmt);
> > -		goto out;
> > +		return 0;
> >  	}
> >  	if (!(reload_dmt =
> > libmp_dm_task_create(DM_DEVICE_RELOAD)))
> > -		goto out;
> > +		return 0;
> >  	if (!dm_task_set_name(reload_dmt, name))
> > -		goto out_reload;
> > +		return 0;
> >  
> >  	do {
> >  		next = dm_get_next_target(dmt, next, &start,
> > &length,
> > @@ -1705,13 +1668,13 @@ int dm_reassign_table(const char *name,
> > char *old, char *new)
> >  			 */
> >  			condlog(1, "%s: invalid target found in
> > map %s",
> >  				__func__, name);
> > -			goto out_reload;
> > +			return 0;
> >  		}
> >  		buff = strdup(params);
> >  		if (!buff) {
> >  			condlog(3, "%s: failed to replace target
> > %s, "
> >  				"out of memory", name, target);
> > -			goto out_reload;
> > +			return 0;
> >  		}
> >  		if (strcmp(target, TGT_MPATH) && strstr(params,
> > old)) {
> >  			condlog(3, "%s: replace target %s %s",
> > @@ -1729,18 +1692,12 @@ int dm_reassign_table(const char *name,
> > char *old, char *new)
> >  		if (!libmp_dm_task_run(reload_dmt)) {
> >  			dm_log_error(3, DM_DEVICE_RELOAD,
> > reload_dmt);
> >  			condlog(3, "%s: failed to reassign
> > targets", name);
> > -			goto out_reload;
> > +			return 0;
> >  		}
> >  		dm_simplecmd_noflush(DM_DEVICE_RESUME, name,
> >  				     MPATH_UDEV_RELOAD_FLAG);
> >  	}
> > -	r = 1;
> > -
> > -out_reload:
> > -	dm_task_destroy(reload_dmt);
> > -out:
> > -	dm_task_destroy(dmt);
> > -	return r;
> > +	return 1;
> >  }
> >  
> >  
> > @@ -1752,10 +1709,9 @@ out:
> >  int dm_reassign(const char *mapname)
> >  {
> >  	struct dm_deps *deps;
> > -	struct dm_task *dmt;
> > +	struct dm_task __attribute__((cleanup(cleanup_dm_task)))
> > *dmt = NULL;
> >  	struct dm_info info;
> >  	char dev_t[32], dm_dep[32];
> > -	int r = 0;
> >  	unsigned int i;
> >  
> >  	if (dm_dev_t(mapname, &dev_t[0], 32)) {
> > @@ -1769,21 +1725,21 @@ int dm_reassign(const char *mapname)
> >  	}
> >  
> >  	if (!dm_task_set_name(dmt, mapname))
> > -		goto out;
> > +		return 0;
> >  
> >  	if (!libmp_dm_task_run(dmt)) {
> >  		dm_log_error(3, DM_DEVICE_DEPS, dmt);
> > -		goto out;
> > +		return 0;
> >  	}
> >  
> >  	if (!dm_task_get_info(dmt, &info))
> > -		goto out;
> > +		return 0;
> >  
> >  	if (!(deps = dm_task_get_deps(dmt)))
> > -		goto out;
> > +		return 0;
> >  
> >  	if (!info.exists)
> > -		goto out;
> > +		return 0;
> >  
> >  	for (i = 0; i < deps->count; i++) {
> >  		sprintf(dm_dep, "%d:%d",
> > @@ -1792,15 +1748,12 @@ int dm_reassign(const char *mapname)
> >  		sysfs_check_holders(dm_dep, dev_t);
> >  	}
> >  
> > -	r = 1;
> > -out:
> > -	dm_task_destroy (dmt);
> > -	return r;
> > +	return 1;
> >  }
> >  
> >  int dm_setgeometry(struct multipath *mpp)
> >  {
> > -	struct dm_task *dmt;
> > +	struct dm_task __attribute__((cleanup(cleanup_dm_task)))
> > *dmt = NULL;
> >  	struct path *pp;
> >  	char heads[4], sectors[4];
> >  	char cylinders[10], start[32];
> > @@ -1825,7 +1778,7 @@ int dm_setgeometry(struct multipath *mpp)
> >  		return 0;
> >  
> >  	if (!dm_task_set_name(dmt, mpp->alias))
> > -		goto out;
> > +		return 0;
> >  
> >  	/* What a sick interface ... */
> >  	snprintf(heads, 4, "%u", pp->geom.heads);
> > @@ -1834,14 +1787,12 @@ int dm_setgeometry(struct multipath *mpp)
> >  	snprintf(start, 32, "%lu", pp->geom.start);
> >  	if (!dm_task_set_geometry(dmt, cylinders, heads, sectors,
> > start)) {
> >  		condlog(3, "%s: Failed to set geometry", mpp-
> > >alias);
> > -		goto out;
> > +		return 0;
> >  	}
> >  
> >  	r = libmp_dm_task_run(dmt);
> >  	if (!r)
> >  		dm_log_error(3, DM_DEVICE_SET_GEOMETRY, dmt);
> > -out:
> > -	dm_task_destroy(dmt);
> >  
> >  	return r;
> >  }
> > diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h
> > index 19b79c5..9438c2d 100644
> > --- a/libmultipath/devmapper.h
> > +++ b/libmultipath/devmapper.h
> > @@ -46,7 +46,12 @@ int dm_map_present (const char *name);
> >  int dm_map_present_by_uuid(const char *uuid);
> >  int dm_get_map(const char *name, unsigned long long *size, char
> > **outparams);
> >  int dm_get_status(const char *name, char **outstatus);
> > -int dm_type(const char *name, char *type);
> > +
> > +enum {
> > +	DM_IS_MPATH_NO,
> > +	DM_IS_MPATH_YES,
> > +	DM_IS_MPATH_ERR,
> > +};
> >  int dm_is_mpath(const char *name);
> >  
> >  enum {
> > diff --git a/multipath/main.c b/multipath/main.c
> > index ce702e7..c82bc86 100644
> > --- a/multipath/main.c
> > +++ b/multipath/main.c
> > @@ -247,7 +247,7 @@ static int check_usable_paths(struct config
> > *conf,
> >  		goto out;
> >  	}
> >  
> > -	if (dm_is_mpath(mapname) != 1) {
> > +	if (dm_is_mpath(mapname) != DM_IS_MPATH_YES) {
> >  		condlog(1, "%s is not a multipath map", devpath);
> >  		goto free;
> >  	}
> > @@ -1080,7 +1080,7 @@ main (int argc, char *argv[])
> >  		goto out;
> >  	}
> >  	if (cmd == CMD_FLUSH_ONE) {
> > -		if (dm_is_mpath(dev) != 1) {
> > +		if (dm_is_mpath(dev) != DM_IS_MPATH_YES) {
> >  			condlog(0, "%s is not a multipath device",
> > dev);
> >  			r = RTVL_FAIL;
> >  			goto out;
> > diff --git a/multipathd/dmevents.c b/multipathd/dmevents.c
> > index 3fbdc55..605219e 100644
> > --- a/multipathd/dmevents.c
> > +++ b/multipathd/dmevents.c
> > @@ -170,7 +170,7 @@ static int dm_get_events(void)
> >  
> >  		/* Don't delete device if dm_is_mpath() fails
> > without
> >  		 * checking the device type */
> 
> Like the comments says, this check is only supposed to remove a
> multipath
> device from the list of devices if dm_is_mpath() returns
> DM_IS_MPATH_NO.
> 
> See 9050cd5a1 ("libmultipath: fix false removes in dmevents polling
> code")

I saw these comments, but I didn't get the message, and failed to
lookup the history which I ususally do in cases like this.

Thanks for pointing it out, and for reading through this large
patch all the way to the bottom.

Martin


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

* Re: [PATCH 17/44] libmultipath: add libmp_mapinfo()
  2024-07-09 21:39 ` [PATCH 17/44] libmultipath: add libmp_mapinfo() Martin Wilck
@ 2024-07-10 22:53   ` Benjamin Marzinski
  2024-07-11 11:00     ` Martin Wilck
  0 siblings, 1 reply; 75+ messages in thread
From: Benjamin Marzinski @ 2024-07-10 22:53 UTC (permalink / raw)
  To: Martin Wilck; +Cc: Christophe Varoqui, dm-devel

On Tue, Jul 09, 2024 at 11:39:08PM +0200, Martin Wilck wrote:

This is a great idea! I just have a few minor issues.

> libmp_mapinfo() is intended as a generic abstraction for retrieving information from
> the kernel device-mapper driver. It retrieves the information that the caller
> needs, with a minimal set of DM ioctls, and never more then 2 ioctl calls.
> 
> libdm's DM_DEVICE_TABLE and DM_DEVICE_STATUS calls map to the kernel's
> DM_TABLE_STATUS ioctl, with or without the DM_STATUS_TABLE_FLAG set,
> respectively. DM_TABLE_STATUS always retrieves the basic map status (struct
> dm_info) and the map UUID and name, too.
> 
> Note: I'd prefer to use an unnamed struct instead of _u in
> union libmp_map_identifer. But doing using an unnamed struct and and
> initializing the union like this in a function argument:
> 
>   func((mapid_t) { .major = major, .minor = minor })

This is a nitpick, but instead of using _u, couldn't you just pass the
major and minor as a dev_t? If you're working with an actual major and
minor, you would need to do something like:

(mapid_t) { .dev = makedev(major, minor) }

but we are often already dealing with a dev_t, so instead of doing:

(mapid_t) { ._u = { major(dev), minor(dev) } }

we could just do:

(mapid_t) { .dev = dev }

To get the major and minor out in the libmp_mapinfo() you would need to
use major(id.dev) and minor(id.dev), instead of id._u.major and
id._u.minor, but I think first set is more readable anyway.

> 
> is not part of C99, and not supported in gcc 4.8, which we still support.
> 
> Likewise, the following syntax for initializing an empty struct:
> 
>   (mapinfo_t) { 0 }
> 
> is not supported on all architectures we support (notably clang 3.5 under
> Debian Jessie).
> 
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
>  libmultipath/devmapper.c          | 181 +++++++++++++++++++++++++++++-
>  libmultipath/devmapper.h          |  66 +++++++++++
>  libmultipath/libmultipath.version |   3 +-
>  3 files changed, 248 insertions(+), 2 deletions(-)
> 
> diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
> index 3685ef7..5c9f9d8 100644
> --- a/libmultipath/devmapper.c
> +++ b/libmultipath/devmapper.c
> @@ -14,7 +14,6 @@
>  #include <errno.h>
>  #include <syslog.h>
>  #include <sys/sysmacros.h>
> -#include <linux/dm-ioctl.h>
>  
>  #include "util.h"
>  #include "vector.h"
> @@ -604,6 +603,186 @@ has_dm_info(const struct multipath *mpp)
>  	return (mpp && mpp->dmi.exists != 0);
>  }
>  
> +static int libmp_set_map_identifier(int flags, mapid_t id, struct dm_task *dmt)
> +{
> +	switch (flags & __DM_MAP_BY_MASK) {
> +	case DM_MAP_BY_UUID:
> +		if (!id.str || !(*id.str))
> +			return 0;
> +		return dm_task_set_uuid(dmt, id.str);
> +	case DM_MAP_BY_NAME:
> +		if (!id.str || !(*id.str))
> +			return 0;
> +		return dm_task_set_name(dmt, id.str);
> +	case DM_MAP_BY_DEV:
> +		if (!dm_task_set_major(dmt, id._u.major))
> +			return 0;
> +		return  dm_task_set_minor(dmt, id._u.minor);
> +	default:
> +		condlog(0, "%s: invalid by_id", __func__);
> +		return 0;
> +	}
> +}
> +
> +static int libmp_mapinfo__(int flags, mapid_t id, mapinfo_t info, const char *map_id)
> +{
> +	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
> +	struct dm_info dmi;
> +	int rc, ioctl_nr;
> +	uint64_t start, length = 0;
> +	char *target_type = NULL, *params = NULL;
> +	const char *name = NULL, *uuid = NULL;
> +	char __attribute__((cleanup(cleanup_charp))) *tmp_target = NULL;
> +	char __attribute__((cleanup(cleanup_charp))) *tmp_status = NULL;
> +	bool tgt_set = false;
> +
> +	/*
> +	 * If both info.target and info.status are set, we need two
> +	 * ioctls. Call this function recursively.
> +	 * If successful, tmp_target will be non-NULL.
> +	 */
> +	if (info.target && info.status) {
> +		rc = libmp_mapinfo__(flags, id,
> +				     (mapinfo_t) {
> +					     .target = &tmp_target,
> +					     .tgt_type = info.tgt_type,
> +				     },
> +				     map_id);
> +		if (rc != DMP_OK)
> +			return rc;
> +		tgt_set = true;
> +	}
> +
> +	/*
> +	 * The DM_DEVICE_TABLE and DM_DEVICE_STATUS ioctls both fetch the basic
> +	 * information from DM_DEVICE_INFO, too.
> +	 * Choose the most lightweight ioctl to fetch all requested info.
> +	 */
> +	if (info.target && !info.status)
> +		ioctl_nr = DM_DEVICE_TABLE;
> +	else if (info.status || info.size || info.tgt_type)
> +		ioctl_nr = DM_DEVICE_STATUS;
> +	else
> +		ioctl_nr = DM_DEVICE_INFO;
> +
> +	if (!(dmt = libmp_dm_task_create(ioctl_nr)))
> +		return DMP_ERR;
> +
> +	if (!libmp_set_map_identifier(flags, id, dmt)) {
> +		condlog(2, "%s: failed to set map identifier to %s", __func__, map_id);
> +		return DMP_ERR;
> +	}
> +
> +	if (!libmp_dm_task_run(dmt)) {
> +		dm_log_error(3, ioctl_nr, dmt);
> +		if (dm_task_get_errno(dmt) == ENXIO) {
> +			condlog(2, "%s: map %s not found", __func__, map_id);
> +			return DMP_NOT_FOUND;
> +		} else
> +			return DMP_ERR;
> +	}
> +
> +	condlog(4, "%s: DM ioctl %d succeeded for %s",
> +		__func__, ioctl_nr, map_id);
> +
> +	if (!dm_task_get_info(dmt, &dmi) || !dmi.exists) {
> +		condlog(2, "%s: map %s doesn't exist", __func__, map_id);
> +		return DMP_NOT_FOUND;
> +	}
> +
> +	if (info.target || info.status || info.size || info.tgt_type) {
> +		if (dm_get_next_target(dmt, NULL, &start, &length,
> +				       &target_type, &params) != NULL) {
> +			condlog(2, "%s: map %s has multiple targets", __func__, map_id);
> +			return DMP_NOT_FOUND;
> +		}
> +		if (!params) {
> +			condlog(2, "%s: map %s has no targets", __func__, map_id);
> +			return DMP_NOT_FOUND;
> +		}
> +		if (info.tgt_type && strcmp(info.tgt_type, target_type)) {
> +			condlog(3, "%s: target type mismatch: \"%s\" != \"%s\"",
> +				__func__, info.tgt_type, target_type);
> +			return DMP_NO_MATCH;
> +		}
> +	}
> +
> +	/*
> +	 * Check possible error conditions.
> +	 * If error is returned, don't touch any output parameters.
> +	 */
> +	if ((info.name && !(name = dm_task_get_name(dmt)))
> +	    || (info.uuid && !(uuid = dm_task_get_uuid(dmt)))
> +	    || (info.status && !(tmp_status = strdup(params)))
> +	    || (info.target && !tmp_target && !(tmp_target = strdup(params))))
> +		return DMP_ERR;
> +
> +	if (info.name) {
> +		strlcpy(info.name, name, WWID_SIZE);
> +		condlog(4, "%s: %s: name: \"%s\"", __func__, map_id, info.name);
> +	}
> +	if (info.uuid) {
> +		strlcpy(info.uuid, uuid, DM_UUID_LEN);
> +		condlog(4, "%s: %s: uuid: \"%s\"", __func__, map_id, info.uuid);
> +	}
> +
> +	if (info.size) {
> +		*info.size = length;
> +		condlog(4, "%s: %s: size: %lld", __func__, map_id, *info.size);
> +	}
> +
> +	if (info.dmi) {
> +		memcpy(info.dmi, &dmi, sizeof(*info.dmi));
> +		condlog(4, "%s: %s %d:%d, %d targets, %s table, %s, %s, %d opened, %u events",
> +			__func__, map_id,
> +			info.dmi->major, info.dmi->minor,
> +			info.dmi->target_count,
> +			info.dmi->live_table ? "live" :
> +				info.dmi->inactive_table ? "inactive" : "no",
> +			info.dmi->suspended ? "suspended" : "active",
> +			info.dmi->read_only ? "ro" : "rw",
> +			info.dmi->open_count,
> +			info.dmi->event_nr);
> +	}
> +
> +	if (info.target) {
> +		*info.target = steal_ptr(tmp_target);
> +		if (!tgt_set)
> +			condlog(4, "%s: %s: target: \"%s\"", __func__, map_id, *info.target);
> +	}
> +
> +	if (info.status) {
> +		*info.status = steal_ptr(tmp_status);
> +		condlog(4, "%s: %s: status: \"%s\"", __func__, map_id, *info.status);
> +	}
> +
> +	return DMP_OK;
> +}
> +
> +/* Helper: format a string describing the map for log messages */
> +static const char* libmp_map_identifier(int flags, mapid_t id, char buf[BLK_DEV_SIZE])
> +{
> +	switch (flags & __DM_MAP_BY_MASK) {
> +	case DM_MAP_BY_NAME:
> +	case DM_MAP_BY_UUID:
> +		return id.str;
> +	case DM_MAP_BY_DEV:
> +		safe_snprintf(buf, BLK_DEV_SIZE, "%d:%d", id._u.major, id._u.minor);
> +		return buf;
> +	default:
> +		safe_snprintf(buf, BLK_DEV_SIZE, "*invalid*");
> +		return buf;
> +	}
> +}
> +
> +int libmp_mapinfo(int flags, mapid_t id, mapinfo_t info)
> +{
> +	char idbuf[BLK_DEV_SIZE];
> +
> +	return libmp_mapinfo__(flags, id, info,
> +			       libmp_map_identifier(flags, id, idbuf));
> +}
> +
>  int
>  dm_get_info(const char *name, struct dm_info *info)
>  {
> diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h
> index 9438c2d..269389b 100644
> --- a/libmultipath/devmapper.h
> +++ b/libmultipath/devmapper.h
> @@ -1,5 +1,6 @@
>  #ifndef _DEVMAPPER_H
>  #define _DEVMAPPER_H
> +#include <linux/dm-ioctl.h>
>  #include "autoconfig.h"
>  #include "structs.h"
>  
> @@ -31,8 +32,73 @@ enum {
>  	DMP_ERR,
>  	DMP_OK,
>  	DMP_NOT_FOUND,
> +	DMP_NO_MATCH,
>  };
>  
> +/**
> + * enum mapinfo_flags: input flags for libmp_mapinfo()
> + */
> +enum __mapinfo_flags {
> +	/** DM_MAP_BY_NAME: identify map by device-mapper name from @name */
> +	DM_MAP_BY_NAME      = 0,
> +	/** DM_MAP_BY_UUID: identify map by device-mapper UUID from @uuid */
> +	DM_MAP_BY_UUID,
> +	/** DM_MAP_BY_DEV: identify map by major/minor number from @dmi */
> +	DM_MAP_BY_DEV,
> +	__DM_MAP_BY_MASK    = (1 << 3) - 1,

I assume you orignally indented these to be flags, but they aren't
really, so __DM_MAP_BY_MASK would just be 3, since the values are 0, 1,
and 2.

> +};
> +
> +typedef union libmp_map_identifier {
> +	const char *str;

Like I said before, I would just use

        dev_t dev;

instead of the struct. But I don't have stong feelings about this if you
prefer keeping major and minor separate.

> +	struct {
> +		int major;
> +		int minor;
> +	} _u;
> +} mapid_t;
> +
> +typedef struct libmp_map_info {
> +	/** @name: name of the map.
> +	 * If non-NULL, it must point to an array of WWID_SIZE bytes
> +	 */
> +	char *name;
> +	/** @uuid: UUID of the map.
> +	 * If non-NULL it must point to an array of DM_UUID_LEN bytes
> +	 */
> +	char *uuid;
> +	/** @dmi: Basic info, must point to a valid dm_info buffer if non-NULL */
> +	struct dm_info *dmi;
> +	/** @target: target params, *@target will be allocated if @target is non-NULL*/
> +	char **target;
> +	/** @size: target size. Will be ignored if @target is NULL */
> +	unsigned long long *size;
> +	/** @status: target status, *@status will be allocated if @status is non-NULL */
> +	char **status;
> +	/** @tgt_type: (input) set to a target type, e.g. "multipath" to limit
> +	 * successful return to just this target type in libmp_mapinfo().
> +	 */
> +	const char *tgt_type;
> +} mapinfo_t;
> +
> +/**
> + * libmp_mapinfo(): obtain information about a map from the kernel
> + * @param flags: see __mapinfo_flags above.
> + *     Exactly one of DM_MAP_BY_NAME, DM_MAP_BY_UUID, and DM_MAP_BY_DEV must be set.

Again, you can't really set multiple values, so this comment doesn't
make sense.

-Ben

> + * @param id: string or major/minor to identify the map to query
> + * @param info: output parameters, see above. Non-NULL elements will be filled in.
> + * @returns:
> + *     DMP_OK if successful.
> + *     DMP_NOT_FOUND if the map wasn't found, or has no or multiple targets.
> + *     DMP_NO_MATCH if the map didn't match @tgt_type (see above).
> + *     DMP_ERR if some other error occurred.
> + *
> + * This function obtains the requested information for the device-mapper map
> + * identified by the input parameters.
> + * Output parameters are only filled in if the return value is DMP_OK.
> + * For target / status / size information, the  map's table should contain
> + * only one target (usually multipath or linear).
> + */
> +int libmp_mapinfo(int flags, mapid_t id, mapinfo_t info);
> +
>  int dm_prereq(unsigned int *v);
>  void skip_libmp_dm_init(void);
>  void libmp_dm_exit(void);
> diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version
> index f58cb1d..48c2b67 100644
> --- a/libmultipath/libmultipath.version
> +++ b/libmultipath/libmultipath.version
> @@ -43,7 +43,7 @@ LIBMPATHCOMMON_1.0.0 {
>  	put_multipath_config;
>  };
>  
> -LIBMULTIPATH_24.0.0 {
> +LIBMULTIPATH_25.0.0 {
>  global:
>  	/* symbols referenced by multipath and multipathd */
>  	add_foreign;
> @@ -134,6 +134,7 @@ global:
>  	libmp_get_version;
>  	libmp_get_multipath_config;
>  	libmp_dm_task_run;
> +	libmp_mapinfo;
>  	libmp_put_multipath_config;
>  	libmp_udev_set_sync_support;
>  	libmultipath_exit;
> -- 
> 2.45.2


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

* Re: [PATCH 21/44] libmultipath: is_mpath_part(): improve parsing
  2024-07-09 21:39 ` [PATCH 21/44] libmultipath: is_mpath_part(): improve parsing Martin Wilck
@ 2024-07-10 22:54   ` Benjamin Marzinski
  2024-07-11 11:08     ` Martin Wilck
  0 siblings, 1 reply; 75+ messages in thread
From: Benjamin Marzinski @ 2024-07-10 22:54 UTC (permalink / raw)
  To: Martin Wilck; +Cc: Christophe Varoqui, dm-devel

On Tue, Jul 09, 2024 at 11:39:12PM +0200, Martin Wilck wrote:
> Use sscanf to make the parsing of the UUID more robust.
> 
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
>  libmultipath/devmapper.c | 17 +++++++----------
>  1 file changed, 7 insertions(+), 10 deletions(-)
> 
> diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
> index 56157af..d62a7dd 100644
> --- a/libmultipath/devmapper.c
> +++ b/libmultipath/devmapper.c
> @@ -846,23 +846,20 @@ int dm_get_uuid(const char *name, char *uuid, int uuid_len)
>  
>  static int is_mpath_part(const char *part_name, const char *map_name)
>  {
> -	char *p;
> -	char part_uuid[DM_UUID_LEN], map_uuid[DM_UUID_LEN];
> +	char part_uuid[DM_UUID_LEN], map_uuid[DM_UUID_LEN], c;
> +	int np, nc;
>  
>  	if (dm_get_dm_uuid(part_name, part_uuid) != DMP_OK)
>  		return 0;
>  
> +	if (2 != sscanf(part_uuid, "part%d-%n" UUID_PREFIX "%c", &np, &nc, &c)

we should probably use "part%u-%n" so we can't match a "-" before the
number.

-Ben

> +	    || np <= 0)
> +		return 0;
> +
>  	if (dm_get_dm_uuid(map_name, map_uuid) != DMP_OK)
>  		return 0;
>  
> -	if (strncmp(part_uuid, "part", 4) != 0)
> -		return 0;
> -
> -	p = strstr(part_uuid, UUID_PREFIX);
> -	if (p && !strcmp(p, map_uuid))
> -		return 1;
> -
> -	return 0;
> +	return !strcmp(part_uuid + nc, map_uuid);
>  }
>  
>  int dm_get_status(const char *name, char **outstatus)
> -- 
> 2.45.2


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

* Re: [PATCH 23/44] libmultipath: improve dm_get_wwid() return value logic
  2024-07-09 21:39 ` [PATCH 23/44] libmultipath: improve dm_get_wwid() return value logic Martin Wilck
@ 2024-07-10 23:34   ` Benjamin Marzinski
  2024-07-11 12:25     ` Martin Wilck
  0 siblings, 1 reply; 75+ messages in thread
From: Benjamin Marzinski @ 2024-07-10 23:34 UTC (permalink / raw)
  To: Martin Wilck; +Cc: Christophe Varoqui, dm-devel

On Tue, Jul 09, 2024 at 11:39:14PM +0200, Martin Wilck wrote:
> Make dm_get_wwid() return different status codes for non-existing maps,
> maps that exists but are not multipath maps, and generic error case,
> and handle these return codes appropriately in callers.
> 
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
>  libmultipath/alias.c     |  5 +++--
>  libmultipath/configure.c | 23 +++++++++++------------
>  libmultipath/devmapper.c | 21 ++++++++++++++++-----
>  libmultipath/wwids.c     |  2 +-
>  tests/alias.c            | 10 +++++-----
>  5 files changed, 36 insertions(+), 25 deletions(-)
> 
> diff --git a/libmultipath/alias.c b/libmultipath/alias.c
> index 10e58a7..2ab9499 100644
> --- a/libmultipath/alias.c
> +++ b/libmultipath/alias.c
> @@ -408,13 +408,14 @@ static bool alias_already_taken(const char *alias, const char *map_wwid)
>  {
>  
>  	char wwid[WWID_SIZE];
> +	int rc = dm_get_wwid(alias, wwid, sizeof(wwid));
>  
>  	/* If the map doesn't exist, it's fine */
> -	if (dm_get_wwid(alias, wwid, sizeof(wwid)) != 0)

We used to assume the alias was not taken if dm_get_wwid() failed with
an error. Now we assume that the alias is taken. I think we should
continue to assume we can use the alias if we get DM_ERR.

> +	if (rc == DMP_NOT_FOUND)
>  		return false;
>  
>  	/* If both the name and the wwid match, it's fine.*/
> -	if (strncmp(map_wwid, wwid, sizeof(wwid)) == 0)
> +	if (rc == DMP_OK && strncmp(map_wwid, wwid, sizeof(wwid)) == 0)
>  		return false;
>  
>  	condlog(3, "%s: alias '%s' already taken, reselecting alias",
> diff --git a/libmultipath/configure.c b/libmultipath/configure.c
> index 666d4e8..565ea5c 100644
> --- a/libmultipath/configure.c
> +++ b/libmultipath/configure.c
> @@ -845,18 +845,17 @@ int domap(struct multipath *mpp, char *params, int is_daemon)
>  
>  	if (mpp->action == ACT_CREATE && dm_map_present(mpp->alias)) {
>  		char wwid[WWID_SIZE];
> +		int rc = dm_get_wwid(mpp->alias, wwid, sizeof(wwid));
>  
> -		if (dm_get_wwid(mpp->alias, wwid, sizeof(wwid)) == 0) {
> -			if (!strncmp(mpp->wwid, wwid, sizeof(wwid))) {
> -				condlog(3, "%s: map already present",
> -					mpp->alias);
> -				mpp->action = ACT_RELOAD;
> -			} else {
> -				condlog(0, "%s: map \"%s\" already present with WWID %s, skipping",
> -					mpp->wwid, mpp->alias, wwid);
> -				condlog(0, "please check alias settings in config and bindings file");
> -				mpp->action = ACT_REJECT;
> -			}
> +		if (rc == DMP_OK && !strncmp(mpp->wwid, wwid, sizeof(wwid))) {
> +			condlog(3, "%s: map already present",
> +				mpp->alias);
> +			mpp->action = ACT_RELOAD;

If we return DMP_NO_MATCH, we'll tell the user that the device is already
present will a WWID of "". This is the same as before, but perhaps it
would be better to tell the user that the alias is in use by a
non-multipath device.

> +		} else if (rc == DMP_OK || rc == DMP_NO_MATCH) {
> +			condlog(1, "%s: map \"%s\" already present with WWID \"%s\", skipping\n"
> +				   "please check alias settings in config and bindings file",
> +				mpp->wwid, mpp->alias, wwid);
> +			mpp->action = ACT_REJECT;
>  		}
>  	}
>  
> @@ -1320,7 +1319,7 @@ static int _get_refwwid(enum mpath_cmds cmd, const char *dev,
>  		break;
>  
>  	case DEV_DEVMAP:
> -		if (((dm_get_wwid(dev, tmpwwid, WWID_SIZE)) == 0)
> +		if (((dm_get_wwid(dev, tmpwwid, WWID_SIZE)) == DMP_OK)
>  		    && (strlen(tmpwwid)))
>  			refwwid = tmpwwid;
>  
> diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
> index 94ef369..1eebcb5 100644
> --- a/libmultipath/devmapper.c
> +++ b/libmultipath/devmapper.c
> @@ -829,19 +829,30 @@ int dm_get_map(const char *name, unsigned long long *size, char **outparams)
>  	}
>  }
>  
> +/**
> + * dm_get_wwid(): return WWID for a multipath map
> + * @returns:
> + *    DMP_OK if successful
> + *    DMP_NOT_FOUND if the map doesn't exist
> + *    DMP_NO_MATCH if the map exists but is not a multipath map
> + *    DMP_ERR for other errors
> + */
>  int dm_get_wwid(const char *name, char *uuid, int uuid_len)
>  {
>  	char tmp[DM_UUID_LEN];
> +	int rc = dm_get_dm_uuid(name, tmp);
>  
> -	if (dm_get_dm_uuid(name, tmp) != DMP_OK)
> -		return 1;
> +	if (rc != DMP_OK)
> +		return rc;
>  
>  	if (!strncmp(tmp, UUID_PREFIX, UUID_PREFIX_LEN))
>  		strlcpy(uuid, tmp + UUID_PREFIX_LEN, uuid_len);
> -	else
> +	else {

This seems a little inconsistent with the change in our returns.
Before, if we found a device but it wasn't multipath device,
dm_get_wwid() would exit with 0 but set uuid to an empty string. Now we
return DMP_NO_MATCH in this case but we still clear uuid. It seems like
perhaps we should either set uuid to an empty string for all cases
except DM_OK or we should not touch it for all cases except DM_OK.
Alternatively, perhaps I'm over-thinking this.

-Ben 

>  		uuid[0] = '\0';
> +		return DMP_NO_MATCH;
> +	}
>  
> -	return 0;
> +	return DMP_OK;
>  }
>  
>  static int is_mpath_part(const char *part_name, const char *map_name)
> @@ -1377,7 +1388,7 @@ struct multipath *dm_get_multipath(const char *name)
>  	if (dm_get_map(name, &mpp->size, NULL) != DMP_OK)
>  		goto out;
>  
> -	if (dm_get_wwid(name, mpp->wwid, WWID_SIZE) != 0)
> +	if (dm_get_wwid(name, mpp->wwid, WWID_SIZE) != DMP_OK)
>  		condlog(2, "%s: failed to get uuid for %s", __func__, name);
>  	if (dm_get_info(name, &mpp->dmi) != 0)
>  		condlog(2, "%s: failed to get info for %s", __func__, name);
> diff --git a/libmultipath/wwids.c b/libmultipath/wwids.c
> index 7a4cb74..aac18c0 100644
> --- a/libmultipath/wwids.c
> +++ b/libmultipath/wwids.c
> @@ -295,7 +295,7 @@ should_multipath(struct path *pp1, vector pathvec, vector mpvec)
>  		struct multipath *mp = find_mp_by_wwid(mpvec, pp1->wwid);
>  
>  		if (mp != NULL &&
> -		    dm_get_wwid(mp->alias, tmp_wwid, WWID_SIZE) == 0 &&
> +		    dm_get_wwid(mp->alias, tmp_wwid, WWID_SIZE) == DMP_OK &&
>  		    !strncmp(tmp_wwid, pp1->wwid, WWID_SIZE)) {
>  			condlog(3, "wwid %s is already multipathed, keeping it",
>  				pp1->wwid);
> diff --git a/tests/alias.c b/tests/alias.c
> index 1f78656..a95b308 100644
> --- a/tests/alias.c
> +++ b/tests/alias.c
> @@ -84,7 +84,7 @@ int __wrap_dm_get_wwid(const char *name, char *uuid, int uuid_len)
>  	check_expected(uuid_len);
>  	assert_non_null(uuid);
>  	ret = mock_type(int);
> -	if (ret == 0)
> +	if (ret == DMP_OK)
>  		strcpy(uuid, mock_ptr_type(char *));
>  	return ret;
>  }
> @@ -438,14 +438,14 @@ static void mock_unused_alias(const char *alias)
>  {
>  	expect_string(__wrap_dm_get_wwid, name, alias);
>  	expect_value(__wrap_dm_get_wwid, uuid_len, WWID_SIZE);
> -	will_return(__wrap_dm_get_wwid, 1);
> +	will_return(__wrap_dm_get_wwid, DMP_NOT_FOUND);
>  }
>  
>  static void mock_self_alias(const char *alias, const char *wwid)
>  {
>  	expect_string(__wrap_dm_get_wwid, name, alias);
>  	expect_value(__wrap_dm_get_wwid, uuid_len, WWID_SIZE);
> -	will_return(__wrap_dm_get_wwid, 0);
> +	will_return(__wrap_dm_get_wwid, DMP_OK);
>  	will_return(__wrap_dm_get_wwid, wwid);
>  }
>  
> @@ -471,14 +471,14 @@ static void mock_self_alias(const char *alias, const char *wwid)
>  	do {								\
>  		expect_string(__wrap_dm_get_wwid, name, alias);		\
>  		expect_value(__wrap_dm_get_wwid, uuid_len, WWID_SIZE);	\
> -		will_return(__wrap_dm_get_wwid, 1);			\
> +		will_return(__wrap_dm_get_wwid, DMP_NOT_FOUND);		\
>  	} while (0)
>  
>  #define mock_used_alias(alias, wwid)					\
>  	do {								\
>  		expect_string(__wrap_dm_get_wwid, name, alias);		\
>  		expect_value(__wrap_dm_get_wwid, uuid_len, WWID_SIZE);	\
> -		will_return(__wrap_dm_get_wwid, 0);			\
> +		will_return(__wrap_dm_get_wwid, DMP_OK);		\
>  		will_return(__wrap_dm_get_wwid, "WWID_USED");		\
>  		expect_condlog(3, USED_STR(alias, wwid));		\
>  	} while(0)
> -- 
> 2.45.2


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

* Re: [PATCH 24/44] libmultipath: reimplement dm_map_name() with new API
  2024-07-09 21:39 ` [PATCH 24/44] libmultipath: reimplement dm_map_name() with new API Martin Wilck
@ 2024-07-10 23:41   ` Benjamin Marzinski
  0 siblings, 0 replies; 75+ messages in thread
From: Benjamin Marzinski @ 2024-07-10 23:41 UTC (permalink / raw)
  To: Martin Wilck; +Cc: Christophe Varoqui, dm-devel

On Tue, Jul 09, 2024 at 11:39:15PM +0200, Martin Wilck wrote:
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
>  libmultipath/devmapper.c | 34 ++++++----------------------------
>  1 file changed, 6 insertions(+), 28 deletions(-)
> 
> diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
> index 1eebcb5..caa8385 100644
> --- a/libmultipath/devmapper.c
> +++ b/libmultipath/devmapper.c
> @@ -1469,37 +1469,15 @@ dm_is_suspended(const char *name)
>  	return info.suspended;
>  }
>  
> -char *
> -dm_mapname(int major, int minor)
> +char *dm_mapname(int major, int minor)
>  {
> -	char * response = NULL;
> -	const char *map;
> -	struct dm_task *dmt;
> -	int r;
> +	char name[WWID_SIZE];
>  
> -	if (!(dmt = libmp_dm_task_create(DM_DEVICE_INFO)))
> +	if (libmp_mapinfo(DM_MAP_BY_DEV,
> +			  (mapid_t) { ._u = { major, minor } },

Again, I'd prefer:

			  (mapid_t) { .dev = makedev(major, minor) },

But you can feel free to ignore me if you'd rather keep it how it is.

-Ben

> +			  (mapinfo_t) { .name = name }) != DMP_OK)
>  		return NULL;
> -
> -	if (!dm_task_set_major(dmt, major) ||
> -	    !dm_task_set_minor(dmt, minor))
> -		goto bad;
> -
> -	r = libmp_dm_task_run(dmt);
> -	if (!r) {
> -		dm_log_error(2, DM_DEVICE_INFO, dmt);
> -		goto bad;
> -	}
> -
> -	map = dm_task_get_name(dmt);
> -	if (map && strlen(map))
> -		response = strdup((const char *)map);
> -
> -	dm_task_destroy(dmt);
> -	return response;
> -bad:
> -	dm_task_destroy(dmt);
> -	condlog(0, "%i:%i: error fetching map name", major, minor);
> -	return NULL;
> +	return strdup(name);
>  }
>  
>  static int
> -- 
> 2.45.2


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

* Re: [PATCH 28/44] libmultipath: implement dm_is_mpath() with new API
  2024-07-09 21:39 ` [PATCH 28/44] libmultipath: implement dm_is_mpath() with new API Martin Wilck
@ 2024-07-11  0:21   ` Benjamin Marzinski
  2024-07-11 12:32     ` Martin Wilck
  0 siblings, 1 reply; 75+ messages in thread
From: Benjamin Marzinski @ 2024-07-11  0:21 UTC (permalink / raw)
  To: Martin Wilck; +Cc: Christophe Varoqui, dm-devel

On Tue, Jul 09, 2024 at 11:39:19PM +0200, Martin Wilck wrote:
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
>  libmultipath/devmapper.c | 53 ++++++----------------------------------
>  1 file changed, 8 insertions(+), 45 deletions(-)
> 
> diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
> index 859a861..6276041 100644
> --- a/libmultipath/devmapper.c
> +++ b/libmultipath/devmapper.c
> @@ -965,52 +965,15 @@ static int dm_type_match(const char *name, char *type)
>  
>  int dm_is_mpath(const char *name)
>  {
> -	int r = DM_IS_MPATH_ERR;
> -	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
> -	struct dm_info info;
> -	uint64_t start, length;
> -	char *target_type = NULL;
> -	char *params;
> -	const char *uuid;
> +	char uuid[DM_UUID_LEN];
> +	int rc = libmp_mapinfo(DM_MAP_BY_NAME,
> +			       (mapid_t) { .str = name },
> +			       (mapinfo_t) { .uuid = uuid, .tgt_type = TGT_MPATH });
>  
> -	if (!(dmt = libmp_dm_task_create(DM_DEVICE_TABLE)))
> -		goto out;
> -
> -	if (!dm_task_set_name(dmt, name))
> -		goto out;
> -
> -	if (!libmp_dm_task_run(dmt)) {
> -		dm_log_error(3, DM_DEVICE_TABLE, dmt);
> -		goto out;
> -	}
> -
> -	if (!dm_task_get_info(dmt, &info))
> -		goto out;
> -
> -	r = DM_IS_MPATH_NO;
> -
> -	if (!info.exists)
> -		goto out;
> -
> -	uuid = dm_task_get_uuid(dmt);
> -
> -	if (!uuid || strncmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN) != 0)
> -		goto out;
> -
> -	/* Fetch 1st target */
> -	if (dm_get_next_target(dmt, NULL, &start, &length, &target_type,
> -			       &params) != NULL)
> -		/* multiple targets */
> -		goto out;
> -
> -	if (!target_type || strcmp(target_type, TGT_MPATH) != 0)
> -		goto out;
> -
> -	r = DM_IS_MPATH_YES;
> -out:
> -	if (r < 0)
> -		condlog(3, "%s: dm command failed in %s: %s", name, __func__, strerror(errno));
> -	return r;

Since dm_get_events() and watch_dmevents() need to differentiate between
DM_IS_MPATH_NO and DM_IS_MPATH_ERR, this function needs to return
DM_IS_MPATH_ERR if libmp_mapinfo() returns DM_ERR.

Looking over this function, I did notice one thing.  It returns
DM_IS_MPATH_ERR if dm_task_get_info() fails, while libmp_mapinfo__()
returns DMP_NOT_FOUND if dm_task_get_info() fails. Looking at the
current lvm code, I can't see a way for dm_task_get_info() to fail
if we just called libmp_dm_task_run() and it succeeded. On the other
hand dm_task_get_info() failing does seem to be an error, not a
a sign that the device doesn't exist, so perhaps ibmp_mapinfo__()
should treat it like one. Although most of our code doesn't, and like I
said, I don't see how it could fail unless dm_task_run() already failed
(or wasn't called).

Any thoughts?

-Ben


> +	if (rc != DMP_OK || strncmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN))
> +		return DM_IS_MPATH_NO;
> +	else
> +		return DM_IS_MPATH_YES;
>  }
>  
>  int dm_map_present_by_wwid(const char *wwid)
> -- 
> 2.45.2


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

* Re: [PATCH 31/44] libmultipath: add is_mpath_uuid() helper
  2024-07-09 21:39 ` [PATCH 31/44] libmultipath: add is_mpath_uuid() helper Martin Wilck
@ 2024-07-11  3:38   ` Benjamin Marzinski
  2024-07-11 12:56     ` Martin Wilck
  0 siblings, 1 reply; 75+ messages in thread
From: Benjamin Marzinski @ 2024-07-11  3:38 UTC (permalink / raw)
  To: Martin Wilck; +Cc: Christophe Varoqui, dm-devel

On Tue, Jul 09, 2024 at 11:39:22PM +0200, Martin Wilck wrote:
> Export it, as it will be used by multipathd and libmpathpersist.
> 

This is fine. But I was thinking that if you wanted to actually add
some optional flags to the flags argument of libmp_mapinfo(), this would
be a good use. You could have a flag like DM_MAP_MPATH_WWID, which would
verify that the device had a multipath UUID_PREFIX (and possibly force a
check for a multipath target type) and then return the wwid without the
multipath uuid prefix.

Just a thought.

-Ben

> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
>  libmultipath/devmapper.c          | 13 +++++++++----
>  libmultipath/devmapper.h          |  2 ++
>  libmultipath/libmultipath.version |  1 +
>  3 files changed, 12 insertions(+), 4 deletions(-)
> 
> diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
> index 806ffb8..5f6c0c8 100644
> --- a/libmultipath/devmapper.c
> +++ b/libmultipath/devmapper.c
> @@ -829,6 +829,11 @@ int dm_get_map(const char *name, unsigned long long *size, char **outparams)
>  	}
>  }
>  
> +bool is_mpath_uuid(const char uuid[DM_UUID_LEN])
> +{
> +	return !strncmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN);
> +}
> +
>  /**
>   * dm_get_wwid(): return WWID for a multipath map
>   * @returns:
> @@ -845,7 +850,7 @@ int dm_get_wwid(const char *name, char *uuid, int uuid_len)
>  	if (rc != DMP_OK)
>  		return rc;
>  
> -	if (!strncmp(tmp, UUID_PREFIX, UUID_PREFIX_LEN))
> +	if (is_mpath_uuid(tmp))
>  		strlcpy(uuid, tmp + UUID_PREFIX_LEN, uuid_len);
>  	else {
>  		uuid[0] = '\0';
> @@ -970,7 +975,7 @@ int dm_is_mpath(const char *name)
>  			       (mapid_t) { .str = name },
>  			       (mapinfo_t) { .uuid = uuid, .tgt_type = TGT_MPATH });
>  
> -	if (rc != DMP_OK || strncmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN))
> +	if (rc != DMP_OK || !is_mpath_uuid(uuid))
>  		return DM_IS_MPATH_NO;
>  	else
>  		return DM_IS_MPATH_YES;
> @@ -1065,7 +1070,7 @@ int _dm_flush_map (const char *mapname, int flags, int retries)
>  				  .uuid = uuid,
>  				  .tgt_type = TGT_MPATH,
>  				  .target = &params }) != DMP_OK
> -	    || strncmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN))
> +	    || !is_mpath_uuid(uuid))
>  		return DM_FLUSH_OK; /* nothing to do */
>  
>  	/* if the device currently has no partitions, do not
> @@ -1309,7 +1314,7 @@ struct multipath *dm_get_multipath(const char *name)
>  			  }) != DMP_OK)
>  		return NULL;
>  
> -	if (strncmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN))
> +	if (!is_mpath_uuid(uuid))
>  		return NULL;
>  
>  	strlcpy(mpp->wwid, uuid + UUID_PREFIX_LEN, sizeof(mpp->wwid));
> diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h
> index db5c5fd..a2b2837 100644
> --- a/libmultipath/devmapper.h
> +++ b/libmultipath/devmapper.h
> @@ -131,6 +131,8 @@ enum {
>  	DM_IS_MPATH_YES,
>  	DM_IS_MPATH_ERR,
>  };
> +
> +bool is_mpath_uuid(const char uuid[DM_UUID_LEN]);
>  int dm_is_mpath(const char *name);
>  
>  enum {
> diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version
> index 7d3ff63..5b8f9e0 100644
> --- a/libmultipath/libmultipath.version
> +++ b/libmultipath/libmultipath.version
> @@ -127,6 +127,7 @@ global:
>  	init_foreign;
>  	init_prio;
>  	io_err_stat_handle_pathfail;
> +	is_mpath_uuid;
>  	is_path_valid;
>  	libmp_dm_task_create;
>  	libmp_get_version;
> -- 
> 2.45.2


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

* Re: [PATCH 35/44] libmultipath: use libmp_pathinfo() in update_multipath_table()
  2024-07-09 21:39 ` [PATCH 35/44] libmultipath: use libmp_pathinfo() in update_multipath_table() Martin Wilck
@ 2024-07-11  5:16   ` Benjamin Marzinski
  2024-07-11 15:29     ` Martin Wilck
  0 siblings, 1 reply; 75+ messages in thread
From: Benjamin Marzinski @ 2024-07-11  5:16 UTC (permalink / raw)
  To: Martin Wilck; +Cc: Christophe Varoqui, dm-devel

On Tue, Jul 09, 2024 at 11:39:26PM +0200, Martin Wilck wrote:
> This allows us to remove dm_get_status(), and dm_get_map(), of which
> update_multipath_table() was the last caller.
> 
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
>  libmultipath/devmapper.c   | 89 --------------------------------------
>  libmultipath/devmapper.h   |  2 -
>  libmultipath/structs_vec.c | 22 +++++-----
>  3 files changed, 12 insertions(+), 101 deletions(-)
> 
> diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
> index 185c76b..105e838 100644
> --- a/libmultipath/devmapper.c
> +++ b/libmultipath/devmapper.c
> @@ -804,45 +804,6 @@ static int dm_get_dm_uuid(const char *mapname, char uuid[DM_UUID_LEN])
>  			     (mapinfo_t) { .uuid = uuid });
>  }
>  
> -int dm_get_map(const char *name, unsigned long long *size, char **outparams)
> -{
> -	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
> -	uint64_t start, length;
> -	char *target_type = NULL;
> -	char *params = NULL;
> -
> -	if (!(dmt = libmp_dm_task_create(DM_DEVICE_TABLE)))
> -		return DMP_ERR;
> -
> -	if (!dm_task_set_name(dmt, name))
> -		return DMP_ERR;
> -
> -	errno = 0;
> -	if (!libmp_dm_task_run(dmt)) {
> -		dm_log_error(3, DM_DEVICE_TABLE, dmt);
> -		if (dm_task_get_errno(dmt) == ENXIO)
> -			return DMP_NOT_FOUND;
> -		else
> -			return DMP_ERR;
> -	}
> -
> -	/* Fetch 1st target */
> -	if (dm_get_next_target(dmt, NULL, &start, &length,
> -			       &target_type, &params) != NULL || !params)
> -		/* more than one target or not found target */
> -		return DMP_NOT_FOUND;
> -
> -	if (size)
> -		*size = length;
> -
> -	if (!outparams)
> -		return DMP_OK;
> -	else {
> -		*outparams = strdup(params);
> -		return *outparams ? DMP_OK : DMP_ERR;
> -	}
> -}
> -
>  bool is_mpath_uuid(const char uuid[DM_UUID_LEN])
>  {
>  	return !strncmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN);
> @@ -886,56 +847,6 @@ static bool is_mpath_part_uuid(const char part_uuid[DM_UUID_LEN],
>  	return !strcmp(part_uuid + nc, map_uuid);
>  }
>  
> -int dm_get_status(const char *name, char **outstatus)
> -{
> -	int r = DMP_ERR;
> -	struct dm_task __attribute__((cleanup(cleanup_dm_task))) *dmt = NULL;
> -	uint64_t start, length;
> -	char *target_type = NULL;
> -	char *status = NULL;
> -
> -	if (!(dmt = libmp_dm_task_create(DM_DEVICE_STATUS)))
> -		return r;
> -
> -	if (!dm_task_set_name(dmt, name))
> -		goto out;
> -
> -	errno = 0;
> -	if (!libmp_dm_task_run(dmt)) {
> -		dm_log_error(3, DM_DEVICE_STATUS, dmt);
> -		if (dm_task_get_errno(dmt) == ENXIO)
> -			r = DMP_NOT_FOUND;
> -		goto out;
> -	}
> -
> -	r = DMP_NOT_FOUND;
> -	/* Fetch 1st target */
> -	if (dm_get_next_target(dmt, NULL, &start, &length,
> -			       &target_type, &status) != NULL)
> -		goto out;
> -
> -	if (!target_type || strcmp(target_type, TGT_MPATH) != 0)
> -		goto out;
> -
> -	if (!status) {
> -		condlog(2, "got null status.");
> -		goto out;
> -	}
> -
> -	if (!outstatus)
> -		r = DMP_OK;
> -	else {
> -		*outstatus = strdup(status);
> -		r = *outstatus ? DMP_OK : DMP_ERR;
> -	}
> -out:
> -	if (r != DMP_OK)
> -		condlog(0, "%s: %s: error getting map status string: %d",
> -			__func__, name, r);
> -
> -	return r;
> -}
> -
>  int dm_is_mpath(const char *name)
>  {
>  	char uuid[DM_UUID_LEN];
> diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h
> index ed5e866..cb5151e 100644
> --- a/libmultipath/devmapper.h
> +++ b/libmultipath/devmapper.h
> @@ -126,8 +126,6 @@ int dm_simplecmd_noflush (int task, const char *name, uint16_t udev_flags);
>  int dm_addmap_create (struct multipath *mpp, char *params);
>  int dm_addmap_reload (struct multipath *mpp, char *params, int flush);
>  int dm_map_present_by_wwid(const char *uuid);
> -int dm_get_map(const char *name, unsigned long long *size, char **outparams);
> -int dm_get_status(const char *name, char **outstatus);
>  
>  enum {
>  	DM_IS_MPATH_NO,
> diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
> index ccc4efc..770e498 100644
> --- a/libmultipath/structs_vec.c
> +++ b/libmultipath/structs_vec.c
> @@ -484,30 +484,32 @@ int
>  update_multipath_table (struct multipath *mpp, vector pathvec, int flags)
>  {
>  	int r = DMP_ERR;
> -	char *params = NULL;
> +	char __attribute__((cleanup(cleanup_charp))) *params = NULL;
> +	char __attribute__((cleanup(cleanup_charp))) *status = NULL;
>  
>  	if (!mpp)
>  		return r;
>  
> -	r = dm_get_map(mpp->alias, &mpp->size, &params);

Shouldn't we update mpp->size like we were with dm_get_map()?

-Ben

> +	r = libmp_mapinfo(DM_MAP_BY_NAME,
> +			  (mapid_t) { .str = mpp->alias },
> +			  (mapinfo_t) {
> +				  .target = &params,
> +				  .status = &status,
> +				  .tgt_type = TGT_MPATH
> +			  });
> +
>  	if (r != DMP_OK) {
> -		condlog(2, "%s: %s", mpp->alias, (r == DMP_ERR)? "error getting table" : "map not present");
> +		condlog(2, "%s: %s", mpp->alias, dmp_errstr(r));
>  		return r;
>  	}
>  
>  	if (disassemble_map(pathvec, params, mpp)) {
>  		condlog(2, "%s: cannot disassemble map", mpp->alias);
> -		free(params);
>  		return DMP_ERR;
>  	}
>  
> -	free(params);
> -	params = NULL;
> -	if (dm_get_status(mpp->alias, &params) != DMP_OK)
> -		condlog(2, "%s: %s", mpp->alias, (r == DMP_ERR)? "error getting status" : "map not present");
> -	else if (disassemble_status(params, mpp))
> +	if (disassemble_status(status, mpp))
>  		condlog(2, "%s: cannot disassemble status", mpp->alias);
> -	free(params);
>  
>  	/* FIXME: we should deal with the return value here */
>  	update_pathvec_from_dm(pathvec, mpp, flags);
> -- 
> 2.45.2


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

* Re: [PATCH 39/44] multipath: implement check_usable_paths() with libmp_pathinfo()
  2024-07-09 21:39 ` [PATCH 39/44] multipath: implement check_usable_paths() with libmp_pathinfo() Martin Wilck
@ 2024-07-11  5:38   ` Benjamin Marzinski
  0 siblings, 0 replies; 75+ messages in thread
From: Benjamin Marzinski @ 2024-07-11  5:38 UTC (permalink / raw)
  To: Martin Wilck; +Cc: Christophe Varoqui, dm-devel

On Tue, Jul 09, 2024 at 11:39:30PM +0200, Martin Wilck wrote:
> ... and use cleanup attributes. We need to call the disassemble...()
> functions from multipath directly now, but we fetch exactly the data
> we need from the kernel.
> 
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
>  multipath/main.c | 58 ++++++++++++++++++++++++++----------------------
>  1 file changed, 31 insertions(+), 27 deletions(-)
> 
> diff --git a/multipath/main.c b/multipath/main.c
> index c82bc86..b3b6c81 100644
> --- a/multipath/main.c
> +++ b/multipath/main.c
> @@ -222,12 +222,14 @@ get_dm_mpvec (enum mpath_cmds cmd, vector curmp, vector pathvec, char * refwwid)
>  static int check_usable_paths(struct config *conf,
>  			      const char *devpath, enum devtypes dev_type)
>  {
> -	struct udev_device *ud = NULL;
> -	struct multipath *mpp = NULL;
> +	struct udev_device __attribute__((cleanup(cleanup_udev_device))) *ud = NULL;
> +	struct multipath __attribute__((cleanup(cleanup_multipath_and_paths))) *mpp = NULL;
>  	struct pathgroup *pg;
>  	struct path *pp;
> -	char *mapname;
> -	vector pathvec = NULL;
> +	char __attribute__((cleanup(cleanup_charp))) *params = NULL;
> +	char __attribute__((cleanup(cleanup_charp))) *status = NULL;
> +	vector __attribute((cleanup(cleanup_vector))) pathvec = NULL;
> +	char uuid[DM_UUID_LEN];
>  	dev_t devt;
>  	int r = 1, i, j;
>  
> @@ -238,31 +240,39 @@ static int check_usable_paths(struct config *conf,
>  	devt = udev_device_get_devnum(ud);
>  	if (!dm_is_dm_major(major(devt))) {
>  		condlog(1, "%s is not a dm device", devpath);
> -		goto out;
> +		return r;
>  	}
>  
> -	mapname = dm_mapname(major(devt), minor(devt));
> -	if (mapname == NULL) {
> -		condlog(1, "dm device not found: %s", devpath);
> -		goto out;
> -	}
> -
> -	if (dm_is_mpath(mapname) != DM_IS_MPATH_YES) {
> -		condlog(1, "%s is not a multipath map", devpath);
> -		goto free;
> -	}
> +	mpp = alloc_multipath();
> +	if (!mpp)
> +		return r;
> +	if (!(mpp->alias = malloc(WWID_SIZE)))
> +		return r;
>  
>  	/* pathvec is needed for disassemble_map */
>  	pathvec = vector_alloc();
>  	if (pathvec == NULL)
> -		goto free;
> +		return r;
>  
> -	mpp = dm_get_multipath(mapname);
> -	if (mpp == NULL)
> -		goto free;

I can't see any thing that could go wrong, but we used to be setting
mpp->size in dm_get_multipath() and we no longer are, and setting
mpp->size is cheap and risk-free.

-Ben

> +	if (libmp_mapinfo(DM_MAP_BY_DEV,
> +			  (mapid_t) { ._u = { major(devt), minor(devt) } },
> +			  (mapinfo_t) {
> +			      .name = mpp->alias,
> +			      .uuid = uuid,
> +			      .dmi = &mpp->dmi,
> +			      .tgt_type = TGT_MPATH,
> +			      .target = &params,
> +			      .status = &status,
> +		      }) != DMP_OK)
> +		return r;
>  
> -	if (update_multipath_table(mpp, pathvec, 0) != DMP_OK)
> -		    goto free;
> +	if (!is_mpath_uuid(uuid))
> +		return r;
> +
> +	strlcpy(mpp->wwid, uuid + UUID_PREFIX_LEN, sizeof(mpp->wwid));
> +
> +	if (update_multipath_table__(mpp, pathvec, 0, params, status) != DMP_OK)
> +		return r;
>  
>  	vector_foreach_slot (mpp->pg, pg, i) {
>  		vector_foreach_slot (pg->paths, pp, j) {
> @@ -284,12 +294,6 @@ static int check_usable_paths(struct config *conf,
>  found:
>  	condlog(r == 0 ? 3 : 2, "%s:%s usable paths found",
>  		devpath, r == 0 ? "" : " no");
> -free:
> -	free(mapname);
> -	free_multipath(mpp, FREE_PATHS);
> -	vector_free(pathvec);
> -out:
> -	udev_device_unref(ud);
>  	return r;
>  }
>  
> -- 
> 2.45.2


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

* Re: [PATCH 40/44] multipathd: implement add_map_without_path() with libmp_mapinfo()
  2024-07-09 21:39 ` [PATCH 40/44] multipathd: implement add_map_without_path() with libmp_mapinfo() Martin Wilck
@ 2024-07-11  6:11   ` Benjamin Marzinski
  0 siblings, 0 replies; 75+ messages in thread
From: Benjamin Marzinski @ 2024-07-11  6:11 UTC (permalink / raw)
  To: Martin Wilck; +Cc: Christophe Varoqui, dm-devel

On Tue, Jul 09, 2024 at 11:39:31PM +0200, Martin Wilck wrote:
> Also, change the return value to int, as this is more expressive and
> the returned struct multipath isn't used by the caller.
> 
> Note: this removes the call to remove_map() at the end of the function,
> which doesn't make sense anyway, because update_multipath_table()
> would not return error unless the table disassembly failed, in which
> case nothing would have been added the the mpvec or pathvec yet.
> It should be sufficient to just cleanup the local data structures when
> add_map_without_path() fails.
> 
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
>  multipathd/main.c | 69 ++++++++++++++++++++++++-----------------------
>  1 file changed, 36 insertions(+), 33 deletions(-)
> 
> diff --git a/multipathd/main.c b/multipathd/main.c
> index 442a154..9e82188 100644
> --- a/multipathd/main.c
> +++ b/multipathd/main.c
> @@ -707,48 +707,53 @@ fail:
>  	return 0;
>  }
>  
> -static struct multipath *
> -add_map_without_path (struct vectors *vecs, const char *alias)
> +static int add_map_without_path (struct vectors *vecs, const char *alias)
>  {
> -	struct multipath * mpp = alloc_multipath();
> +	struct multipath __attribute__((cleanup(cleanup_multipath_and_paths)))
> +		*mpp = alloc_multipath();
> +	char __attribute__((cleanup(cleanup_charp))) *params = NULL;
> +	char __attribute__((cleanup(cleanup_charp))) *status = NULL;
>  	struct config *conf;
> +	char uuid[DM_UUID_LEN];
> +	int rc = DMP_ERR;
>  
> -	if (!mpp)
> -		return NULL;
> -	if (!alias) {
> -		free(mpp);
> -		return NULL;
> -	}
> +	if (!mpp || !(mpp->alias = strdup(alias)))
> +		return DMP_ERR;
>  
> -	mpp->alias = strdup(alias);

This again doesn't set mpp->size, when it previously did. Am I missing
something about why this is unnecessary? I get that it can be set by
a path, but if it is already set, it can be used the verity that the
path belongs.

> +	if ((rc = libmp_mapinfo(DM_MAP_BY_NAME,
> +				(mapid_t) { .str = mpp->alias },
> +				(mapinfo_t) {
> +					.uuid = uuid,
> +					.tgt_type = TGT_MPATH,
> +					.dmi = &mpp->dmi,
> +					.target = &params,
> +					.status = &status,
> +				})) != DMP_OK)
> +		return rc;
> +
> +	if (!is_mpath_uuid(uuid))
> +		return DMP_NO_MATCH;
> +	else
> +		strlcpy(mpp->wwid, uuid + UUID_PREFIX_LEN, sizeof(mpp->wwid));
>  
> -	if (dm_get_info(mpp->alias, &mpp->dmi) != DMP_OK) {
> -		condlog(3, "%s: cannot access table", mpp->alias);
> -		goto out;
> -	}
> -	if (!strlen(mpp->wwid))
> -		dm_get_wwid(mpp->alias, mpp->wwid, WWID_SIZE);
>  	if (!strlen(mpp->wwid))
>  		condlog(1, "%s: adding map with empty WWID", mpp->alias);
> +
>  	conf = get_multipath_config();
>  	mpp->mpe = find_mpe(conf->mptable, mpp->wwid);
>  	put_multipath_config(conf);
>  
> -	if (update_multipath_table(mpp, vecs->pathvec, 0) != DMP_OK)
> -		goto out;
> +	if ((rc = update_multipath_table__(mpp, vecs->pathvec, 0, params, status)) != DMP_OK)
> +		return DMP_ERR;
>  
>  	if (!vector_alloc_slot(vecs->mpvec))
> -		goto out;
> -
> -	vector_set_slot(vecs->mpvec, mpp);
> +		return DMP_ERR;
> +	vector_set_slot(vecs->mpvec, steal_ptr(mpp));
>  
>  	if (update_map(mpp, vecs, 1) != 0) /* map removed */
> -		return NULL;
> +		return DMP_ERR;
>  
> -	return mpp;
> -out:
> -	remove_map(mpp, vecs->pathvec, vecs->mpvec);
> -	return NULL;
> +	return DMP_OK;
>  }
>  
>  static int
> @@ -862,14 +867,9 @@ int
>  ev_add_map (char * dev, const char * alias, struct vectors * vecs)
>  {
>  	struct multipath * mpp;
> -	int reassign_maps;
> +	int reassign_maps, rc;
>  	struct config *conf;
>  
> -	if (dm_is_mpath(alias) != DM_IS_MPATH_YES) {
> -		condlog(4, "%s: not a multipath map", alias);
> -		return 0;
> -	}
> -
>  	mpp = find_mp_by_alias(vecs->mpvec, alias);
>  
>  	if (mpp) {
> @@ -907,10 +907,13 @@ ev_add_map (char * dev, const char * alias, struct vectors * vecs)
>  	/*
>  	 * now we can register the map
>  	 */
> -	if ((mpp = add_map_without_path(vecs, alias))) {
> +	if ((rc = add_map_without_path(vecs, alias)) == DMP_OK) {

sync_map_state() is called with an uninitialized mpp, however the call is
unnecssary, since add_map_without_path() will call update_map() which will
call sync_map_state(). 

-Ben

>  		sync_map_state(mpp);
>  		condlog(2, "%s: devmap %s registered", alias, dev);
>  		return 0;
> +	} else if (rc == DMP_NO_MATCH) {
> +		condlog(4, "%s: not a multipath map", alias);
> +		return 0;
>  	} else {
>  		condlog(2, "%s: ev_add_map failed", dev);
>  		return 1;
> -- 
> 2.45.2


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

* Re: [PATCH 42/44] llibmultipath: fix return code check for dm_is_suspended()
  2024-07-09 21:39 ` [PATCH 42/44] llibmultipath: fix return code check for dm_is_suspended() Martin Wilck
@ 2024-07-11  6:27   ` Benjamin Marzinski
  2024-07-11 15:35     ` Martin Wilck
  0 siblings, 1 reply; 75+ messages in thread
From: Benjamin Marzinski @ 2024-07-11  6:27 UTC (permalink / raw)
  To: Martin Wilck; +Cc: Christophe Varoqui, dm-devel

On Tue, Jul 09, 2024 at 11:39:33PM +0200, Martin Wilck wrote:
> dm_is_suspended returns non-null if it failed to obtain the device
> information. It's wrong to assume in this case that the device is suspended.

I'm kinda torn on this one. Sure we don't know if the device is
suspended, and most likely if this failed, the device got removed.  But
on the other hand, it could have failed for another reason, and resuming
a device that isn't suspended (or doesn't exist) causes no harm.

I could go either way on this.

-Ben

> 
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
>  libmultipath/devmapper.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
> index e653ca6..e9a0103 100644
> --- a/libmultipath/devmapper.c
> +++ b/libmultipath/devmapper.c
> @@ -604,7 +604,7 @@ int dm_addmap_reload(struct multipath *mpp, char *params, int flush)
>  	/* If the resume failed, dm will leave the device suspended, and
>  	 * drop the new table, so doing a second resume will try using
>  	 * the original table */
> -	if (dm_is_suspended(mpp->alias))
> +	if (dm_is_suspended(mpp->alias) == 1)
>  		dm_simplecmd(DM_DEVICE_RESUME, mpp->alias,
>  			     DMFL_NEED_SYNC | (flush ? 0 : DMFL_NO_FLUSH),
>  			     udev_flags);
> -- 
> 2.45.2


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

* Re: [PATCH 43/44] libmpathpersist: use libmp_mapinfo() in get_mpvec()
  2024-07-09 21:39 ` [PATCH 43/44] libmpathpersist: use libmp_mapinfo() in get_mpvec() Martin Wilck
@ 2024-07-11  6:43   ` Benjamin Marzinski
  0 siblings, 0 replies; 75+ messages in thread
From: Benjamin Marzinski @ 2024-07-11  6:43 UTC (permalink / raw)
  To: Martin Wilck; +Cc: Christophe Varoqui, dm-devel

On Tue, Jul 09, 2024 at 11:39:34PM +0200, Martin Wilck wrote:

In the subject, you mean mpath_get_map(), not get_mpvec(). But the code looks
fine.

-Ben

> When obtaining the map name, make sure right away that the map is a multipath
> device. This saves an ioctl and slightly simplifies the function.
> 
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
>  libmpathpersist/mpath_persist_int.c | 51 ++++++++++++++---------------
>  1 file changed, 24 insertions(+), 27 deletions(-)
> 
> diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c
> index 5a5ac3b..a3e7bd8 100644
> --- a/libmpathpersist/mpath_persist_int.c
> +++ b/libmpathpersist/mpath_persist_int.c
> @@ -157,10 +157,9 @@ static int get_mpvec(vector curmp, vector pathvec, char *refwwid)
>  static int mpath_get_map(vector curmp, vector pathvec, int fd, char **palias,
>  			 struct multipath **pmpp)
>  {
> -	int ret = MPATH_PR_DMMP_ERROR;
> +	int rc;
>  	struct stat info;
> -	int major, minor;
> -	char *alias;
> +	char alias[WWID_SIZE], uuid[DM_UUID_LEN];
>  	struct multipath *mpp;
>  
>  	if (fstat(fd, &info) != 0){
> @@ -172,47 +171,45 @@ static int mpath_get_map(vector curmp, vector pathvec, int fd, char **palias,
>  		return MPATH_PR_FILE_ERROR;
>  	}
>  
> -	major = major(info.st_rdev);
> -	minor = minor(info.st_rdev);
> -	condlog(4, "Device  %d:%d", major, minor);
> -
>  	/* get alias from major:minor*/
> -	alias = dm_mapname(major, minor);
> -	if (!alias){
> -		condlog(0, "%d:%d failed to get device alias.", major, minor);
> +	rc = libmp_mapinfo(DM_MAP_BY_DEV,
> +			   (mapid_t) { ._u = { major(info.st_rdev), minor(info.st_rdev) } },
> +			   (mapinfo_t) {
> +				   .name = alias,
> +				   .uuid = uuid,
> +				   .tgt_type = TGT_MPATH,
> +			   });
> +
> +	if (rc == DMP_NO_MATCH || !is_mpath_uuid(uuid)) {
> +		condlog(3, "%s: not a multipath device.", alias);
> +		return MPATH_PR_DMMP_ERROR;
> +	} else if (rc != DMP_OK) {
> +		condlog(1, "%d:%d failed to get device alias.",
> +			major(info.st_rdev), minor(info.st_rdev));
>  		return MPATH_PR_DMMP_ERROR;
>  	}
>  
> -	condlog(3, "alias = %s", alias);
> -
> -	if (dm_is_mpath(alias) != DM_IS_MPATH_YES) {
> -		condlog(3, "%s: not a multipath device.", alias);
> -		goto out;
> -	}
> +	condlog(4, "alias = %s", alias);
>  
>  	/* get info of all paths from the dm device     */
> -	if (get_mpvec(curmp, pathvec, alias)){
> +	if (get_mpvec(curmp, pathvec, alias)) {
>  		condlog(0, "%s: failed to get device info.", alias);
> -		goto out;
> +		return MPATH_PR_DMMP_ERROR;
>  	}
>  
>  	mpp = find_mp_by_alias(curmp, alias);
>  
>  	if (!mpp) {
>  		condlog(0, "%s: devmap not registered.", alias);
> -		goto out;
> +		return MPATH_PR_DMMP_ERROR;
>  	}
>  
> -	ret = MPATH_PR_SUCCESS;
>  	if (pmpp)
>  		*pmpp = mpp;
> -	if (palias) {
> -		*palias = alias;
> -		alias = NULL;
> -	}
> -out:
> -	free(alias);
> -	return ret;
> +	if (palias && (*palias = strdup(alias)) == NULL)
> +		return MPATH_PR_DMMP_ERROR;
> +
> +	return MPATH_PR_SUCCESS;
>  }
>  
>  int do_mpath_persistent_reserve_in(vector curmp, vector pathvec,
> -- 
> 2.45.2


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

* Re: [PATCH 00/44] multipath-tools: devmapper API refactored
  2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
                   ` (43 preceding siblings ...)
  2024-07-09 21:39 ` [PATCH 44/44] libmpathpersist: use mpp->alias in do_mpath_persistent_reserve_out() Martin Wilck
@ 2024-07-11  6:55 ` Benjamin Marzinski
  44 siblings, 0 replies; 75+ messages in thread
From: Benjamin Marzinski @ 2024-07-11  6:55 UTC (permalink / raw)
  To: Martin Wilck; +Cc: Christophe Varoqui, dm-devel

On Tue, Jul 09, 2024 at 11:38:51PM +0200, Martin Wilck wrote:

For all the patches that I didn't reply to:
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>

> Patch 1-9 are generic cleanups, partly targeting the previously reported
> issues with multipath-tools installation on NixOS by removing hard-coded
> paths as much as possible.
> 
> Patch 10-16 are basic cleanups for the devmapper code.
> 
> Patch 17 is the heart of this patch set, introducing the function
> libmp_mapinfo(), which is supposed to serve as general API for fetching
> information about maps from libdevmapper. It can work with arbitrary
> input for identifying a map, and produce any combination of desired
> outputs, with the most lightweight (combination of) ioctls possible.
> This part of the set removes some code that had been changed
> in patch 10-16. This is sort of suboptimal, but IMO it improves
> the readability of the set as  a whole.
> 
> Patch 18 adds unit tests for this function.
> 
> Patch 19-44 change the libmultipath code to use the new API everywhere,
> and add some additional minor improvements and fixes.
> 
> The code is pushed to https://github.com/openSUSE/multipath-tools/tree/tip.
> 
> Comments and reviews welcome.
> 
> Martin Wilck (44):
>   multipath-tools CI: more fixes for arm/v7
>   multipath-tools CI: fix dmevents test for Debian Sid, arm/v7
>   create-config.mk: use printf instead of /bin/echo
>   multipathd.service.in: use @BINDIR@ instead of /sbin
>   Makefile.inc: replace @BINDIR@ with $(TGTDIR)/$(bindir)
>   kpartx.rules: use @BINDIR@ to locate kpartx
>   multipath-tools: Remove hard-coded paths to executables
>   multipath-tools: compile_commands.json fixes
>   multipath-tools: .gitignore: ignore o.wrap files for CI helpers
>   libmultipath: remove unused includes in devmapper.h
>   libmultipath: use DM_DEVICE_INFO in dm_mapname()
>   multipath-tools: don't call dm_task_no_open_count()
>   libmpathutil: export cleanup_udev_device()
>   libmpathutil: add cleanup_vector()
>   libmultipath: add cleanup helpers for struct multipath
>   libmultipath: add cleanup_dm_task(), and use it in devmapper.c
>   libmultipath: add libmp_mapinfo()
>   libmultipath tests: add tests for libmp_mapinfo()
>   libmultipath: implement dm_get_info() and dm_map_present() with new
>     API
>   libmultipath: remove dm_get_prefixed_uuid()
>   libmultipath: is_mpath_part(): improve parsing
>   libmultipath: rename dm_get_uuid() -> dm_get_wwid()
>   libmultipath: improve dm_get_wwid() return value logic
>   libmultipath: reimplement dm_map_name() with new API
>   libmultipath: reimplement dm_map_present_by_uuid()
>   libmultipath: reimplement dm_get_opencount() with new API
>   libmpathpersist: skip redundant dm_map_present() call
>   libmultipath: implement dm_is_mpath() with new API
>   libmultipath: implement dm_get_multipath() with new API
>   libmultipath: use libmp_mapinfo() in _dm_flush_map()
>   libmultipath: add is_mpath_uuid() helper
>   libmultipath: add is_mpath_part_uuid() helper
>   libmultipath: add dmp_errstr() helper
>   libmultipath: use libmp_mapinfo() in do_foreach_partmaps()
>   libmultipath: use libmp_pathinfo() in update_multipath_table()
>   libmultipath: update mpp->dmi in update_multipath_table()
>   libmultipath: drop extra call to dm_map_present() in domap()
>   libmultipath: split off update_multipath_table__()
>   multipath: implement check_usable_paths() with libmp_pathinfo()
>   multipathd: implement add_map_without_path() with libmp_mapinfo()
>   libmultipath: simplify dm_get_maps()
>   llibmultipath: fix return code check for dm_is_suspended()
>   libmpathpersist: use libmp_mapinfo() in get_mpvec()
>   libmpathpersist: use mpp->alias in do_mpath_persistent_reserve_out()
> 
>  .gitignore                               |    4 +
>  Makefile                                 |    4 +-
>  Makefile.inc                             |   29 +-
>  create-config.mk                         |    4 +-
>  kpartx/Makefile                          |    4 +-
>  kpartx/devmapper.c                       |   15 -
>  kpartx/{kpartx.rules => kpartx.rules.in} |    2 +-
>  kpartx/kpartx_id                         |    8 +-
>  libmpathpersist/mpath_persist_int.c      |   85 +-
>  libmpathutil/libmpathutil.version        |    5 +
>  libmpathutil/util.c                      |    6 +
>  libmpathutil/util.h                      |    3 +
>  libmpathutil/vector.c                    |    6 +
>  libmpathutil/vector.h                    |    1 +
>  libmultipath/alias.c                     |    5 +-
>  libmultipath/configure.c                 |   27 +-
>  libmultipath/devmapper.c                 | 1020 ++++++++------------
>  libmultipath/devmapper.h                 |  101 +-
>  libmultipath/libmultipath.version        |   10 +-
>  libmultipath/print.c                     |    6 -
>  libmultipath/structs.c                   |   12 +
>  libmultipath/structs.h                   |    2 +
>  libmultipath/structs_vec.c               |   50 +-
>  libmultipath/structs_vec.h               |    2 +
>  libmultipath/valid.c                     |    2 +-
>  libmultipath/wwids.c                     |    2 +-
>  multipath/11-dm-mpath.rules.in           |    4 +-
>  multipath/main.c                         |   60 +-
>  multipath/multipath.rules.in             |    6 +-
>  multipathd/dmevents.c                    |    6 +-
>  multipathd/main.c                        |   71 +-
>  multipathd/multipathd.service.in         |    4 +-
>  multipathd/waiter.c                      |    2 -
>  tests/Makefile                           |    5 +-
>  tests/alias.c                            |   32 +-
>  tests/dmevents.c                         |   34 +-
>  tests/mapinfo.c                          | 1121 ++++++++++++++++++++++
>  tests/valid.c                            |   10 +-
>  tests/wrap64.h                           |    9 +-
>  39 files changed, 1916 insertions(+), 863 deletions(-)
>  rename kpartx/{kpartx.rules => kpartx.rules.in} (96%)
>  create mode 100644 tests/mapinfo.c
> 
> -- 
> 2.45.2


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

* Re: [PATCH 17/44] libmultipath: add libmp_mapinfo()
  2024-07-10 22:53   ` Benjamin Marzinski
@ 2024-07-11 11:00     ` Martin Wilck
  0 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-11 11:00 UTC (permalink / raw)
  To: Benjamin Marzinski; +Cc: Christophe Varoqui, dm-devel

On Wed, 2024-07-10 at 18:53 -0400, Benjamin Marzinski wrote:
> On Tue, Jul 09, 2024 at 11:39:08PM +0200, Martin Wilck wrote:
> 
> This is a great idea! I just have a few minor issues.
> 
> > libmp_mapinfo() is intended as a generic abstraction for retrieving
> > information from
> > the kernel device-mapper driver. It retrieves the information that
> > the caller
> > needs, with a minimal set of DM ioctls, and never more then 2 ioctl
> > calls.
> > 
> > libdm's DM_DEVICE_TABLE and DM_DEVICE_STATUS calls map to the
> > kernel's
> > DM_TABLE_STATUS ioctl, with or without the DM_STATUS_TABLE_FLAG
> > set,
> > respectively. DM_TABLE_STATUS always retrieves the basic map status
> > (struct
> > dm_info) and the map UUID and name, too.
> > 
> > Note: I'd prefer to use an unnamed struct instead of _u in
> > union libmp_map_identifer. But doing using an unnamed struct and
> > and
> > initializing the union like this in a function argument:
> > 
> >   func((mapid_t) { .major = major, .minor = minor })
> 
> This is a nitpick, but instead of using _u, couldn't you just pass
> the
> major and minor as a dev_t? If you're working with an actual major
> and
> minor, you would need to do something like:
> 
> (mapid_t) { .dev = makedev(major, minor) }
> 
> but we are often already dealing with a dev_t, so instead of doing:
> 
> (mapid_t) { ._u = { major(dev), minor(dev) } }
> 
> we could just do:
> 
> (mapid_t) { .dev = dev }
> 
> To get the major and minor out in the libmp_mapinfo() you would need
> to
> use major(id.dev) and minor(id.dev), instead of id._u.major and
> id._u.minor, but I think first set is more readable anyway.

Nice idea. I wonder if I should add this as an additional option, or
replace the current approach.

Martin


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

* Re: [PATCH 21/44] libmultipath: is_mpath_part(): improve parsing
  2024-07-10 22:54   ` Benjamin Marzinski
@ 2024-07-11 11:08     ` Martin Wilck
  2024-07-11 17:01       ` Benjamin Marzinski
  0 siblings, 1 reply; 75+ messages in thread
From: Martin Wilck @ 2024-07-11 11:08 UTC (permalink / raw)
  To: Benjamin Marzinski; +Cc: Christophe Varoqui, dm-devel

On Wed, 2024-07-10 at 18:54 -0400, Benjamin Marzinski wrote:
> On Tue, Jul 09, 2024 at 11:39:12PM +0200, Martin Wilck wrote:
> > Use sscanf to make the parsing of the UUID more robust.
> > 
> > Signed-off-by: Martin Wilck <mwilck@suse.com>
> > ---
> >  libmultipath/devmapper.c | 17 +++++++----------
> >  1 file changed, 7 insertions(+), 10 deletions(-)
> > 
> > diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
> > index 56157af..d62a7dd 100644
> > --- a/libmultipath/devmapper.c
> > +++ b/libmultipath/devmapper.c
> > @@ -846,23 +846,20 @@ int dm_get_uuid(const char *name, char *uuid,
> > int uuid_len)
> >  
> >  static int is_mpath_part(const char *part_name, const char
> > *map_name)
> >  {
> > -	char *p;
> > -	char part_uuid[DM_UUID_LEN], map_uuid[DM_UUID_LEN];
> > +	char part_uuid[DM_UUID_LEN], map_uuid[DM_UUID_LEN], c;
> > +	int np, nc;
> >  
> >  	if (dm_get_dm_uuid(part_name, part_uuid) != DMP_OK)
> >  		return 0;
> >  
> > +	if (2 != sscanf(part_uuid, "part%d-%n" UUID_PREFIX "%c",
> > &np, &nc, &c)
> 
> we should probably use "part%u-%n" so we can't match a "-" before the
> number.

That doesn't work, %u accepts negative numbers, too
(https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf)
That's why I use int and check whether the result is positive.

Martin


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

* Re: [PATCH 23/44] libmultipath: improve dm_get_wwid() return value logic
  2024-07-10 23:34   ` Benjamin Marzinski
@ 2024-07-11 12:25     ` Martin Wilck
  2024-07-11 16:38       ` Benjamin Marzinski
  2024-07-11 22:00       ` Martin Wilck
  0 siblings, 2 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-11 12:25 UTC (permalink / raw)
  To: Benjamin Marzinski; +Cc: Christophe Varoqui, dm-devel

On Wed, 2024-07-10 at 19:34 -0400, Benjamin Marzinski wrote:
> On Tue, Jul 09, 2024 at 11:39:14PM +0200, Martin Wilck wrote:
> > Make dm_get_wwid() return different status codes for non-existing
> > maps,
> > maps that exists but are not multipath maps, and generic error
> > case,
> > and handle these return codes appropriately in callers.
> > 
> > Signed-off-by: Martin Wilck <mwilck@suse.com>
> > ---
> >  libmultipath/alias.c     |  5 +++--
> >  libmultipath/configure.c | 23 +++++++++++------------
> >  libmultipath/devmapper.c | 21 ++++++++++++++++-----
> >  libmultipath/wwids.c     |  2 +-
> >  tests/alias.c            | 10 +++++-----
> >  5 files changed, 36 insertions(+), 25 deletions(-)
> > 
> > diff --git a/libmultipath/alias.c b/libmultipath/alias.c
> > index 10e58a7..2ab9499 100644
> > --- a/libmultipath/alias.c
> > +++ b/libmultipath/alias.c
> > @@ -408,13 +408,14 @@ static bool alias_already_taken(const char
> > *alias, const char *map_wwid)
> >  {
> >  
> >  	char wwid[WWID_SIZE];
> > +	int rc = dm_get_wwid(alias, wwid, sizeof(wwid));
> >  
> >  	/* If the map doesn't exist, it's fine */
> > -	if (dm_get_wwid(alias, wwid, sizeof(wwid)) != 0)
> 
> We used to assume the alias was not taken if dm_get_wwid() failed
> with
> an error. Now we assume that the alias is taken. I think we should
> continue to assume we can use the alias if we get DM_ERR.

I am not sure about this. but I can change it. I guess it's a corner
case anyway, where there's no obvious right or wrong behavior. 

A DM_DEVICE_INFO call with this map name failed with an error other
than ENXIO. By going on with this map name, we clearly risk that future
failures will happen when we try to create or reload the map in
question.


> 
> > +	if (rc == DMP_NOT_FOUND)
> >  		return false;
> >  
> >  	/* If both the name and the wwid match, it's fine.*/
> > -	if (strncmp(map_wwid, wwid, sizeof(wwid)) == 0)
> > +	if (rc == DMP_OK && strncmp(map_wwid, wwid, sizeof(wwid))
> > == 0)
> >  		return false;
> >  
> >  	condlog(3, "%s: alias '%s' already taken, reselecting
> > alias",
> > diff --git a/libmultipath/configure.c b/libmultipath/configure.c
> > index 666d4e8..565ea5c 100644
> > --- a/libmultipath/configure.c
> > +++ b/libmultipath/configure.c
> > @@ -845,18 +845,17 @@ int domap(struct multipath *mpp, char
> > *params, int is_daemon)
> >  
> >  	if (mpp->action == ACT_CREATE && dm_map_present(mpp-
> > >alias)) {
> >  		char wwid[WWID_SIZE];
> > +		int rc = dm_get_wwid(mpp->alias, wwid,
> > sizeof(wwid));
> >  
> > -		if (dm_get_wwid(mpp->alias, wwid, sizeof(wwid)) ==
> > 0) {
> > -			if (!strncmp(mpp->wwid, wwid,
> > sizeof(wwid))) {
> > -				condlog(3, "%s: map already
> > present",
> > -					mpp->alias);
> > -				mpp->action = ACT_RELOAD;
> > -			} else {
> > -				condlog(0, "%s: map \"%s\" already
> > present with WWID %s, skipping",
> > -					mpp->wwid, mpp->alias,
> > wwid);
> > -				condlog(0, "please check alias
> > settings in config and bindings file");
> > -				mpp->action = ACT_REJECT;
> > -			}
> > +		if (rc == DMP_OK && !strncmp(mpp->wwid, wwid,
> > sizeof(wwid))) {
> > +			condlog(3, "%s: map already present",
> > +				mpp->alias);
> > +			mpp->action = ACT_RELOAD;
> 
> If we return DMP_NO_MATCH, we'll tell the user that the device is
> already
> present will a WWID of "". This is the same as before, but perhaps it
> would be better to tell the user that the alias is in use by a
> non-multipath device.

Ok.

> 
> > +		} else if (rc == DMP_OK || rc == DMP_NO_MATCH) {
> > +			condlog(1, "%s: map \"%s\" already present
> > with WWID \"%s\", skipping\n"
> > +				   "please check alias settings in
> > config and bindings file",
> > +				mpp->wwid, mpp->alias, wwid);
> > +			mpp->action = ACT_REJECT;
> >  		}
> >  	}
> >  
> > @@ -1320,7 +1319,7 @@ static int _get_refwwid(enum mpath_cmds cmd,
> > const char *dev,
> >  		break;
> >  
> >  	case DEV_DEVMAP:
> > -		if (((dm_get_wwid(dev, tmpwwid, WWID_SIZE)) == 0)
> > +		if (((dm_get_wwid(dev, tmpwwid, WWID_SIZE)) ==
> > DMP_OK)
> >  		    && (strlen(tmpwwid)))
> >  			refwwid = tmpwwid;
> >  
> > diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
> > index 94ef369..1eebcb5 100644
> > --- a/libmultipath/devmapper.c
> > +++ b/libmultipath/devmapper.c
> > @@ -829,19 +829,30 @@ int dm_get_map(const char *name, unsigned
> > long long *size, char **outparams)
> >  	}
> >  }
> >  
> > +/**
> > + * dm_get_wwid(): return WWID for a multipath map
> > + * @returns:
> > + *    DMP_OK if successful
> > + *    DMP_NOT_FOUND if the map doesn't exist
> > + *    DMP_NO_MATCH if the map exists but is not a multipath map
> > + *    DMP_ERR for other errors
> > + */
> >  int dm_get_wwid(const char *name, char *uuid, int uuid_len)
> >  {
> >  	char tmp[DM_UUID_LEN];
> > +	int rc = dm_get_dm_uuid(name, tmp);
> >  
> > -	if (dm_get_dm_uuid(name, tmp) != DMP_OK)
> > -		return 1;
> > +	if (rc != DMP_OK)
> > +		return rc;
> >  
> >  	if (!strncmp(tmp, UUID_PREFIX, UUID_PREFIX_LEN))
> >  		strlcpy(uuid, tmp + UUID_PREFIX_LEN, uuid_len);
> > -	else
> > +	else {
> 
> This seems a little inconsistent with the change in our returns.
> Before, if we found a device but it wasn't multipath device,
> dm_get_wwid() would exit with 0 but set uuid to an empty string. Now
> we
> return DMP_NO_MATCH in this case but we still clear uuid. It seems
> like
> perhaps we should either set uuid to an empty string for all cases
> except DM_OK or we should not touch it for all cases except DM_OK.
> Alternatively, perhaps I'm over-thinking this.

Right. In libmp_mapinfo(), I followed the idea that no output should be
touched if any errors happened. Here, I wanted to preserve the behavior
but didn't do it correctly.

I tend to think that "don't touch output in error case" is the correct
behavior, but we'd need to review the callers and make sure that they
don't assume the WWID will be automatically 0-terminated.

I'll do that.

Martin




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

* Re: [PATCH 28/44] libmultipath: implement dm_is_mpath() with new API
  2024-07-11  0:21   ` Benjamin Marzinski
@ 2024-07-11 12:32     ` Martin Wilck
  0 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-11 12:32 UTC (permalink / raw)
  To: Benjamin Marzinski; +Cc: Christophe Varoqui, dm-devel

On Wed, 2024-07-10 at 20:21 -0400, Benjamin Marzinski wrote:
> On Tue, Jul 09, 2024 at 11:39:19PM +0200, Martin Wilck wrote:
> > Signed-off-by: Martin Wilck <mwilck@suse.com>
> > ---
> >  libmultipath/devmapper.c | 53 ++++++------------------------------
> > ----
> >  1 file changed, 8 insertions(+), 45 deletions(-)
> > 
> > diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
> > index 859a861..6276041 100644
> > --- a/libmultipath/devmapper.c
> > +++ b/libmultipath/devmapper.c
> > @@ -965,52 +965,15 @@ static int dm_type_match(const char *name,
> > char *type)
> >  
> >  int dm_is_mpath(const char *name)
> >  {
> > -	int r = DM_IS_MPATH_ERR;
> > -	struct dm_task __attribute__((cleanup(cleanup_dm_task)))
> > *dmt = NULL;
> > -	struct dm_info info;
> > -	uint64_t start, length;
> > -	char *target_type = NULL;
> > -	char *params;
> > -	const char *uuid;
> > +	char uuid[DM_UUID_LEN];
> > +	int rc = libmp_mapinfo(DM_MAP_BY_NAME,
> > +			       (mapid_t) { .str = name },
> > +			       (mapinfo_t) { .uuid = uuid,
> > .tgt_type = TGT_MPATH });
> >  
> > -	if (!(dmt = libmp_dm_task_create(DM_DEVICE_TABLE)))
> > -		goto out;
> > -
> > -	if (!dm_task_set_name(dmt, name))
> > -		goto out;
> > -
> > -	if (!libmp_dm_task_run(dmt)) {
> > -		dm_log_error(3, DM_DEVICE_TABLE, dmt);
> > -		goto out;
> > -	}
> > -
> > -	if (!dm_task_get_info(dmt, &info))
> > -		goto out;
> > -
> > -	r = DM_IS_MPATH_NO;
> > -
> > -	if (!info.exists)
> > -		goto out;
> > -
> > -	uuid = dm_task_get_uuid(dmt);
> > -
> > -	if (!uuid || strncmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN)
> > != 0)
> > -		goto out;
> > -
> > -	/* Fetch 1st target */
> > -	if (dm_get_next_target(dmt, NULL, &start, &length,
> > &target_type,
> > -			       &params) != NULL)
> > -		/* multiple targets */
> > -		goto out;
> > -
> > -	if (!target_type || strcmp(target_type, TGT_MPATH) != 0)
> > -		goto out;
> > -
> > -	r = DM_IS_MPATH_YES;
> > -out:
> > -	if (r < 0)
> > -		condlog(3, "%s: dm command failed in %s: %s",
> > name, __func__, strerror(errno));
> > -	return r;
> 
> Since dm_get_events() and watch_dmevents() need to differentiate
> between
> DM_IS_MPATH_NO and DM_IS_MPATH_ERR, this function needs to return
> DM_IS_MPATH_ERR if libmp_mapinfo() returns DM_ERR.
> 
> Looking over this function, I did notice one thing.  It returns
> DM_IS_MPATH_ERR if dm_task_get_info() fails, while libmp_mapinfo__()
> returns DMP_NOT_FOUND if dm_task_get_info() fails.
>  Looking at the
> current lvm code, I can't see a way for dm_task_get_info() to fail
> if we just called libmp_dm_task_run() and it succeeded. On the other
> hand dm_task_get_info() failing does seem to be an error, not a
> a sign that the device doesn't exist, so perhaps ibmp_mapinfo__()
> should treat it like one. Although most of our code doesn't, and like
> I
> said, I don't see how it could fail unless dm_task_run() already
> failed
> (or wasn't called).

Right. I also looked at the lvm code, and dm_task_get_XYZ functions
hardly ever fail if running the task succeeded, and they probably never
will. But we shouldn't make any assumptions about libdevmapper in
libmultipath. I will change libmp_mapinfo() to return DMP_ERR in this
case.

Thanks,
Martin


> 
> Any thoughts?
> 
> -Ben
> 
> 
> > +	if (rc != DMP_OK || strncmp(uuid, UUID_PREFIX,
> > UUID_PREFIX_LEN))
> > +		return DM_IS_MPATH_NO;
> > +	else
> > +		return DM_IS_MPATH_YES;
> >  }
> >  
> >  int dm_map_present_by_wwid(const char *wwid)
> > -- 
> > 2.45.2
> 


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

* Re: [PATCH 31/44] libmultipath: add is_mpath_uuid() helper
  2024-07-11  3:38   ` Benjamin Marzinski
@ 2024-07-11 12:56     ` Martin Wilck
  2024-07-11 18:39       ` Benjamin Marzinski
  0 siblings, 1 reply; 75+ messages in thread
From: Martin Wilck @ 2024-07-11 12:56 UTC (permalink / raw)
  To: Benjamin Marzinski; +Cc: Christophe Varoqui, dm-devel

On Wed, 2024-07-10 at 23:38 -0400, Benjamin Marzinski wrote:
> On Tue, Jul 09, 2024 at 11:39:22PM +0200, Martin Wilck wrote:
> > Export it, as it will be used by multipathd and libmpathpersist.
> > 
> 
> This is fine. But I was thinking that if you wanted to actually add
> some optional flags to the flags argument of libmp_mapinfo(), this
> would
> be a good use. You could have a flag like DM_MAP_MPATH_WWID, which
> would
> verify that the device had a multipath UUID_PREFIX (and possibly
> force a
> check for a multipath target type) and then return the wwid without
> the
> multipath uuid prefix.
> 
> Just a thought.

Interesting idea. My thinking was that libmp_mapinfo() should only be
an interface to libdevmapper, and should not interpret the data it
returns in any way.

The only exception is the target type. In theory, the function could
just have returned the target type, and left the interpretation to the
caller. But then, it would have to perform several strdup()s for the
results, and the caller would have to free() the data it wasn't
interested in, which would lead to clumsy and inefficent code in the
frequent case that we're just interested in "multipath" or "linear"
targets. That's why I decided to pass the tgt_type field in, and return
DMP_NO_MATCH if it didn't match, even though it's arguably odd in the
mapinfo_t structure, which is otherwise only used for output fields.

Your flag idea would work, too (an earlier version of this patch set
used flags to indicate which output fields should be filled in; I
discarded that because it was duplicated information, and more elegant
to simply check it the respective output field was non-NULL).

Instead of tgt_type, we could also pass a "filter" callback function
with which the caller could determine whether or not it was interested
in a given map. But I wonder if that'd be over-engineered.

Whatever we eventually do, I think the is_mpath_uuid() helper will be
useful. I am not sure whether we can unexport it even if we implement
more sophisticated "filtering" in libmp_mapinfo().

In general, I wonder what multipath-tools should do if it encounters a
map that has "multipath" target type, but the WWID of which doesn't
conform to the mpath-XYZ convention, or vice versa. This can only
happen if another tool like dmsetup had been used to create the map.
IMO, if multipathd encounters such a situation, it should warn about it
and keep its fingers off the map in question. But we might also play it
simple and just assume that multipath maps always adhere to our
convention. I don't think we currently behave consistently in this
respect.

AFAIU, both the WWID and the target type are immutable and can't be
altered without destroying the map completely (because "multipath" is
an "immutable target" in DM). Thus it should be sufficient to check the
WWID when a map is first encountered.

Thoughts?

Martin

> -Ben
> 
> > Signed-off-by: Martin Wilck <mwilck@suse.com>
> > ---
> >  libmultipath/devmapper.c          | 13 +++++++++----
> >  libmultipath/devmapper.h          |  2 ++
> >  libmultipath/libmultipath.version |  1 +
> >  3 files changed, 12 insertions(+), 4 deletions(-)
> > 
> > diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
> > index 806ffb8..5f6c0c8 100644
> > --- a/libmultipath/devmapper.c
> > +++ b/libmultipath/devmapper.c
> > @@ -829,6 +829,11 @@ int dm_get_map(const char *name, unsigned long
> > long *size, char **outparams)
> >  	}
> >  }
> >  
> > +bool is_mpath_uuid(const char uuid[DM_UUID_LEN])
> > +{
> > +	return !strncmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN);
> > +}
> > +
> >  /**
> >   * dm_get_wwid(): return WWID for a multipath map
> >   * @returns:
> > @@ -845,7 +850,7 @@ int dm_get_wwid(const char *name, char *uuid,
> > int uuid_len)
> >  	if (rc != DMP_OK)
> >  		return rc;
> >  
> > -	if (!strncmp(tmp, UUID_PREFIX, UUID_PREFIX_LEN))
> > +	if (is_mpath_uuid(tmp))
> >  		strlcpy(uuid, tmp + UUID_PREFIX_LEN, uuid_len);
> >  	else {
> >  		uuid[0] = '\0';
> > @@ -970,7 +975,7 @@ int dm_is_mpath(const char *name)
> >  			       (mapid_t) { .str = name },
> >  			       (mapinfo_t) { .uuid = uuid,
> > .tgt_type = TGT_MPATH });
> >  
> > -	if (rc != DMP_OK || strncmp(uuid, UUID_PREFIX,
> > UUID_PREFIX_LEN))
> > +	if (rc != DMP_OK || !is_mpath_uuid(uuid))
> >  		return DM_IS_MPATH_NO;
> >  	else
> >  		return DM_IS_MPATH_YES;
> > @@ -1065,7 +1070,7 @@ int _dm_flush_map (const char *mapname, int
> > flags, int retries)
> >  				  .uuid = uuid,
> >  				  .tgt_type = TGT_MPATH,
> >  				  .target = &params }) != DMP_OK
> > -	    || strncmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN))
> > +	    || !is_mpath_uuid(uuid))
> >  		return DM_FLUSH_OK; /* nothing to do */
> >  
> >  	/* if the device currently has no partitions, do not
> > @@ -1309,7 +1314,7 @@ struct multipath *dm_get_multipath(const char
> > *name)
> >  			  }) != DMP_OK)
> >  		return NULL;
> >  
> > -	if (strncmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN))
> > +	if (!is_mpath_uuid(uuid))
> >  		return NULL;
> >  
> >  	strlcpy(mpp->wwid, uuid + UUID_PREFIX_LEN, sizeof(mpp-
> > >wwid));
> > diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h
> > index db5c5fd..a2b2837 100644
> > --- a/libmultipath/devmapper.h
> > +++ b/libmultipath/devmapper.h
> > @@ -131,6 +131,8 @@ enum {
> >  	DM_IS_MPATH_YES,
> >  	DM_IS_MPATH_ERR,
> >  };
> > +
> > +bool is_mpath_uuid(const char uuid[DM_UUID_LEN]);
> >  int dm_is_mpath(const char *name);
> >  
> >  enum {
> > diff --git a/libmultipath/libmultipath.version
> > b/libmultipath/libmultipath.version
> > index 7d3ff63..5b8f9e0 100644
> > --- a/libmultipath/libmultipath.version
> > +++ b/libmultipath/libmultipath.version
> > @@ -127,6 +127,7 @@ global:
> >  	init_foreign;
> >  	init_prio;
> >  	io_err_stat_handle_pathfail;
> > +	is_mpath_uuid;
> >  	is_path_valid;
> >  	libmp_dm_task_create;
> >  	libmp_get_version;
> > -- 
> > 2.45.2
> 


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

* Re: [PATCH 35/44] libmultipath: use libmp_pathinfo() in update_multipath_table()
  2024-07-11  5:16   ` Benjamin Marzinski
@ 2024-07-11 15:29     ` Martin Wilck
  0 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-11 15:29 UTC (permalink / raw)
  To: Benjamin Marzinski; +Cc: Christophe Varoqui, dm-devel

On Thu, 2024-07-11 at 01:16 -0400, Benjamin Marzinski wrote:
> On Tue, Jul 09, 2024 at 11:39:26PM +0200, Martin Wilck wrote:
> > This allows us to remove dm_get_status(), and dm_get_map(), of
> > which
> > update_multipath_table() was the last caller.
> > 
> > Signed-off-by: Martin Wilck <mwilck@suse.com>
> > ---
> >  libmultipath/devmapper.c   | 89 ----------------------------------
> > ----
> >  libmultipath/devmapper.h   |  2 -
> >  libmultipath/structs_vec.c | 22 +++++-----
> >  3 files changed, 12 insertions(+), 101 deletions(-)
> > 
> > diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
> > index 185c76b..105e838 100644
> > --- a/libmultipath/devmapper.c
> > +++ b/libmultipath/devmapper.c
> > @@ -804,45 +804,6 @@ static int dm_get_dm_uuid(const char *mapname,
> > char uuid[DM_UUID_LEN])
> >  			     (mapinfo_t) { .uuid = uuid });
> >  }
> >  
> > -int dm_get_map(const char *name, unsigned long long *size, char
> > **outparams)
> > -{
> > -	struct dm_task __attribute__((cleanup(cleanup_dm_task)))
> > *dmt = NULL;
> > -	uint64_t start, length;
> > -	char *target_type = NULL;
> > -	char *params = NULL;
> > -
> > -	if (!(dmt = libmp_dm_task_create(DM_DEVICE_TABLE)))
> > -		return DMP_ERR;
> > -
> > -	if (!dm_task_set_name(dmt, name))
> > -		return DMP_ERR;
> > -
> > -	errno = 0;
> > -	if (!libmp_dm_task_run(dmt)) {
> > -		dm_log_error(3, DM_DEVICE_TABLE, dmt);
> > -		if (dm_task_get_errno(dmt) == ENXIO)
> > -			return DMP_NOT_FOUND;
> > -		else
> > -			return DMP_ERR;
> > -	}
> > -
> > -	/* Fetch 1st target */
> > -	if (dm_get_next_target(dmt, NULL, &start, &length,
> > -			       &target_type, &params) != NULL ||
> > !params)
> > -		/* more than one target or not found target */
> > -		return DMP_NOT_FOUND;
> > -
> > -	if (size)
> > -		*size = length;
> > -
> > -	if (!outparams)
> > -		return DMP_OK;
> > -	else {
> > -		*outparams = strdup(params);
> > -		return *outparams ? DMP_OK : DMP_ERR;
> > -	}
> > -}
> > -
> >  bool is_mpath_uuid(const char uuid[DM_UUID_LEN])
> >  {
> >  	return !strncmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN);
> > @@ -886,56 +847,6 @@ static bool is_mpath_part_uuid(const char
> > part_uuid[DM_UUID_LEN],
> >  	return !strcmp(part_uuid + nc, map_uuid);
> >  }
> >  
> > -int dm_get_status(const char *name, char **outstatus)
> > -{
> > -	int r = DMP_ERR;
> > -	struct dm_task __attribute__((cleanup(cleanup_dm_task)))
> > *dmt = NULL;
> > -	uint64_t start, length;
> > -	char *target_type = NULL;
> > -	char *status = NULL;
> > -
> > -	if (!(dmt = libmp_dm_task_create(DM_DEVICE_STATUS)))
> > -		return r;
> > -
> > -	if (!dm_task_set_name(dmt, name))
> > -		goto out;
> > -
> > -	errno = 0;
> > -	if (!libmp_dm_task_run(dmt)) {
> > -		dm_log_error(3, DM_DEVICE_STATUS, dmt);
> > -		if (dm_task_get_errno(dmt) == ENXIO)
> > -			r = DMP_NOT_FOUND;
> > -		goto out;
> > -	}
> > -
> > -	r = DMP_NOT_FOUND;
> > -	/* Fetch 1st target */
> > -	if (dm_get_next_target(dmt, NULL, &start, &length,
> > -			       &target_type, &status) != NULL)
> > -		goto out;
> > -
> > -	if (!target_type || strcmp(target_type, TGT_MPATH) != 0)
> > -		goto out;
> > -
> > -	if (!status) {
> > -		condlog(2, "got null status.");
> > -		goto out;
> > -	}
> > -
> > -	if (!outstatus)
> > -		r = DMP_OK;
> > -	else {
> > -		*outstatus = strdup(status);
> > -		r = *outstatus ? DMP_OK : DMP_ERR;
> > -	}
> > -out:
> > -	if (r != DMP_OK)
> > -		condlog(0, "%s: %s: error getting map status
> > string: %d",
> > -			__func__, name, r);
> > -
> > -	return r;
> > -}
> > -
> >  int dm_is_mpath(const char *name)
> >  {
> >  	char uuid[DM_UUID_LEN];
> > diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h
> > index ed5e866..cb5151e 100644
> > --- a/libmultipath/devmapper.h
> > +++ b/libmultipath/devmapper.h
> > @@ -126,8 +126,6 @@ int dm_simplecmd_noflush (int task, const char
> > *name, uint16_t udev_flags);
> >  int dm_addmap_create (struct multipath *mpp, char *params);
> >  int dm_addmap_reload (struct multipath *mpp, char *params, int
> > flush);
> >  int dm_map_present_by_wwid(const char *uuid);
> > -int dm_get_map(const char *name, unsigned long long *size, char
> > **outparams);
> > -int dm_get_status(const char *name, char **outstatus);
> >  
> >  enum {
> >  	DM_IS_MPATH_NO,
> > diff --git a/libmultipath/structs_vec.c
> > b/libmultipath/structs_vec.c
> > index ccc4efc..770e498 100644
> > --- a/libmultipath/structs_vec.c
> > +++ b/libmultipath/structs_vec.c
> > @@ -484,30 +484,32 @@ int
> >  update_multipath_table (struct multipath *mpp, vector pathvec, int
> > flags)
> >  {
> >  	int r = DMP_ERR;
> > -	char *params = NULL;
> > +	char __attribute__((cleanup(cleanup_charp))) *params =
> > NULL;
> > +	char __attribute__((cleanup(cleanup_charp))) *status =
> > NULL;
> >  
> >  	if (!mpp)
> >  		return r;
> >  
> > -	r = dm_get_map(mpp->alias, &mpp->size, &params);
> 
> Shouldn't we update mpp->size like we were with dm_get_map()?

Yes. Thanks for catching this.
Although if we do we should probably check whether it changed...

Martin


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

* Re: [PATCH 42/44] llibmultipath: fix return code check for dm_is_suspended()
  2024-07-11  6:27   ` Benjamin Marzinski
@ 2024-07-11 15:35     ` Martin Wilck
  0 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-11 15:35 UTC (permalink / raw)
  To: Benjamin Marzinski; +Cc: Christophe Varoqui, dm-devel

On Thu, 2024-07-11 at 02:27 -0400, Benjamin Marzinski wrote:
> On Tue, Jul 09, 2024 at 11:39:33PM +0200, Martin Wilck wrote:
> > dm_is_suspended returns non-null if it failed to obtain the device
> > information. It's wrong to assume in this case that the device is
> > suspended.
> 
> I'm kinda torn on this one. Sure we don't know if the device is
> suspended, and most likely if this failed, the device got removed. 
> But
> on the other hand, it could have failed for another reason, and
> resuming
> a device that isn't suspended (or doesn't exist) causes no harm.

In theory, a resume operation might swap the live and inactive table.
But it practice, that can't happen. It's a corner case anyway.

I'll drop this one.

Martin


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

* Re: [PATCH 23/44] libmultipath: improve dm_get_wwid() return value logic
  2024-07-11 12:25     ` Martin Wilck
@ 2024-07-11 16:38       ` Benjamin Marzinski
  2024-07-11 22:00       ` Martin Wilck
  1 sibling, 0 replies; 75+ messages in thread
From: Benjamin Marzinski @ 2024-07-11 16:38 UTC (permalink / raw)
  To: Martin Wilck; +Cc: Christophe Varoqui, dm-devel

On Thu, Jul 11, 2024 at 02:25:54PM +0200, Martin Wilck wrote:
> On Wed, 2024-07-10 at 19:34 -0400, Benjamin Marzinski wrote:
> > On Tue, Jul 09, 2024 at 11:39:14PM +0200, Martin Wilck wrote:
> > > Make dm_get_wwid() return different status codes for non-existing
> > > maps,
> > > maps that exists but are not multipath maps, and generic error
> > > case,
> > > and handle these return codes appropriately in callers.
> > > 
> > > Signed-off-by: Martin Wilck <mwilck@suse.com>
> > > ---
> > >  libmultipath/alias.c     |  5 +++--
> > >  libmultipath/configure.c | 23 +++++++++++------------
> > >  libmultipath/devmapper.c | 21 ++++++++++++++++-----
> > >  libmultipath/wwids.c     |  2 +-
> > >  tests/alias.c            | 10 +++++-----
> > >  5 files changed, 36 insertions(+), 25 deletions(-)
> > > 
> > > diff --git a/libmultipath/alias.c b/libmultipath/alias.c
> > > index 10e58a7..2ab9499 100644
> > > --- a/libmultipath/alias.c
> > > +++ b/libmultipath/alias.c
> > > @@ -408,13 +408,14 @@ static bool alias_already_taken(const char
> > > *alias, const char *map_wwid)
> > >  {
> > >  
> > >  	char wwid[WWID_SIZE];
> > > +	int rc = dm_get_wwid(alias, wwid, sizeof(wwid));
> > >  
> > >  	/* If the map doesn't exist, it's fine */
> > > -	if (dm_get_wwid(alias, wwid, sizeof(wwid)) != 0)
> > 
> > We used to assume the alias was not taken if dm_get_wwid() failed
> > with
> > an error. Now we assume that the alias is taken. I think we should
> > continue to assume we can use the alias if we get DM_ERR.
> 
> I am not sure about this. but I can change it. I guess it's a corner
> case anyway, where there's no obvious right or wrong behavior. 
> 
> A DM_DEVICE_INFO call with this map name failed with an error other
> than ENXIO. By going on with this map name, we clearly risk that future
> failures will happen when we try to create or reload the map in
> question.

Fair enough. The worst that could happen if we keep your method is that
we skip a usable name, which would get used by a future device anyway.
I'm dropping my objection.

-Ben


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

* Re: [PATCH 21/44] libmultipath: is_mpath_part(): improve parsing
  2024-07-11 11:08     ` Martin Wilck
@ 2024-07-11 17:01       ` Benjamin Marzinski
  2024-07-11 17:41         ` Martin Wilck
  0 siblings, 1 reply; 75+ messages in thread
From: Benjamin Marzinski @ 2024-07-11 17:01 UTC (permalink / raw)
  To: Martin Wilck; +Cc: Christophe Varoqui, dm-devel

On Thu, Jul 11, 2024 at 01:08:39PM +0200, Martin Wilck wrote:
> On Wed, 2024-07-10 at 18:54 -0400, Benjamin Marzinski wrote:
> > On Tue, Jul 09, 2024 at 11:39:12PM +0200, Martin Wilck wrote:
> > > Use sscanf to make the parsing of the UUID more robust.
> > > 
> > > Signed-off-by: Martin Wilck <mwilck@suse.com>
> > > ---
> > >  libmultipath/devmapper.c | 17 +++++++----------
> > >  1 file changed, 7 insertions(+), 10 deletions(-)
> > > 
> > > diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
> > > index 56157af..d62a7dd 100644
> > > --- a/libmultipath/devmapper.c
> > > +++ b/libmultipath/devmapper.c
> > > @@ -846,23 +846,20 @@ int dm_get_uuid(const char *name, char *uuid,
> > > int uuid_len)
> > >  
> > >  static int is_mpath_part(const char *part_name, const char
> > > *map_name)
> > >  {
> > > -	char *p;
> > > -	char part_uuid[DM_UUID_LEN], map_uuid[DM_UUID_LEN];
> > > +	char part_uuid[DM_UUID_LEN], map_uuid[DM_UUID_LEN], c;
> > > +	int np, nc;
> > >  
> > >  	if (dm_get_dm_uuid(part_name, part_uuid) != DMP_OK)
> > >  		return 0;
> > >  
> > > +	if (2 != sscanf(part_uuid, "part%d-%n" UUID_PREFIX "%c",
> > > &np, &nc, &c)
> > 
> > we should probably use "part%u-%n" so we can't match a "-" before the
> > number.
> 
> That doesn't work, %u accepts negative numbers, too
> (https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf)
> That's why I use int and check whether the result is positive.

Huh? I learned something new. I actually find that kind of annoying,
since you could get the same result by just using %d and casting a
unsigned int to a signed one for the assignment, and it seems like
people would often not want to match a dash at the start.

At any rate, you're correct.

Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>

> 
> Martin


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

* Re: [PATCH 21/44] libmultipath: is_mpath_part(): improve parsing
  2024-07-11 17:01       ` Benjamin Marzinski
@ 2024-07-11 17:41         ` Martin Wilck
  0 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-11 17:41 UTC (permalink / raw)
  To: Benjamin Marzinski; +Cc: Christophe Varoqui, dm-devel

On Thu, 2024-07-11 at 13:01 -0400, Benjamin Marzinski wrote:
> On Thu, Jul 11, 2024 at 01:08:39PM +0200, Martin Wilck wrote:
> > On Wed, 2024-07-10 at 18:54 -0400, Benjamin Marzinski wrote:
> > > 
> > > we should probably use "part%u-%n" so we can't match a "-" before
> > > the
> > > number.
> > 
> > That doesn't work, %u accepts negative numbers, too
> > (https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf)
> > That's why I use int and check whether the result is positive.
> 
> Huh? I learned something new. I actually find that kind of annoying,

I know, I was also surprised when I found out. But strtoul() behaves
like this, too. In C, it's perfectly ok to write

        unsigned int n = -1;

Maybe that's how we should look at it.

Martin


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

* Re: [PATCH 31/44] libmultipath: add is_mpath_uuid() helper
  2024-07-11 12:56     ` Martin Wilck
@ 2024-07-11 18:39       ` Benjamin Marzinski
  2024-07-11 18:59         ` Martin Wilck
  0 siblings, 1 reply; 75+ messages in thread
From: Benjamin Marzinski @ 2024-07-11 18:39 UTC (permalink / raw)
  To: Martin Wilck; +Cc: Christophe Varoqui, dm-devel

On Thu, Jul 11, 2024 at 02:56:05PM +0200, Martin Wilck wrote:
> On Wed, 2024-07-10 at 23:38 -0400, Benjamin Marzinski wrote:
> > On Tue, Jul 09, 2024 at 11:39:22PM +0200, Martin Wilck wrote:
> > > Export it, as it will be used by multipathd and libmpathpersist.
> > > 
> > 
> > This is fine. But I was thinking that if you wanted to actually add
> > some optional flags to the flags argument of libmp_mapinfo(), this
> > would
> > be a good use. You could have a flag like DM_MAP_MPATH_WWID, which
> > would
> > verify that the device had a multipath UUID_PREFIX (and possibly
> > force a
> > check for a multipath target type) and then return the wwid without
> > the
> > multipath uuid prefix.
> > 
> > Just a thought.
> 
> Interesting idea. My thinking was that libmp_mapinfo() should only be
> an interface to libdevmapper, and should not interpret the data it
> returns in any way.
> 
> The only exception is the target type. In theory, the function could
> just have returned the target type, and left the interpretation to the
> caller. But then, it would have to perform several strdup()s for the
> results, and the caller would have to free() the data it wasn't
> interested in, which would lead to clumsy and inefficent code in the
> frequent case that we're just interested in "multipath" or "linear"
> targets. That's why I decided to pass the tgt_type field in, and return
> DMP_NO_MATCH if it didn't match, even though it's arguably odd in the
> mapinfo_t structure, which is otherwise only used for output fields.

I did wonder if it would make more sense to just pass a struct to
libmp_mapinfo() that contained all the input data, with the flags and
the identifiers (tgt_type just being an additional optional identier)
grouped together.  But I'm fine with the exiting interface so it didn't
seem worth commenting on.
 
> Your flag idea would work, too (an earlier version of this patch set
> used flags to indicate which output fields should be filled in; I
> discarded that because it was duplicated information, and more elegant
> to simply check it the respective output field was non-NULL).
> 
> Instead of tgt_type, we could also pass a "filter" callback function
> with which the caller could determine whether or not it was interested
> in a given map. But I wonder if that'd be over-engineered.
> 
> Whatever we eventually do, I think the is_mpath_uuid() helper will be
> useful. I am not sure whether we can unexport it even if we implement
> more sophisticated "filtering" in libmp_mapinfo().
> 
> In general, I wonder what multipath-tools should do if it encounters a
> map that has "multipath" target type, but the WWID of which doesn't
> conform to the mpath-XYZ convention, or vice versa. This can only
> happen if another tool like dmsetup had been used to create the map.
> IMO, if multipathd encounters such a situation, it should warn about it
> and keep its fingers off the map in question. But we might also play it
> simple and just assume that multipath maps always adhere to our
> convention. I don't think we currently behave consistently in this
> respect.

There was a time when there were users of the kernel multipath target
outside of the multipath-tools. To deal with them, the idea was that
multipathd would only manage devices that had a uuid with UUID_PREFIX.
That was a while ago, and we likely have been violating that condition,
but I haven't heard of any complaints. It might be worth auditing the
code to see if/where we aren't verifying new devices.

Obviously if we find a dm device that isn't a multipath target, we
shouldn't do anything with it, regardless of its UUID.
 
> AFAIU, both the WWID and the target type are immutable and can't be
> altered without destroying the map completely (because "multipath" is
> an "immutable target" in DM). Thus it should be sufficient to check the
> WWID when a map is first encountered.

Probably. Obviously, a multipath device could get removed outside of
multipathd and another device added with the same identifier that we're
using. There would be a window before we got the remove event where we
would be looking at the wrong device. But I can't really come up with
a way for this to happen that doesn't involve very creative stupidity on
the user's part, and since you need to be root to do this, I don't see
any security issues here.

This isn't exactly what you're asking about but the results are worse,
and I don't think there is a way to guarantee the following can't happen:

1. multipathd decides in needs to reload a multipath device that is not in
use and grabs the vecs lock so no events will get processed
2. user removes that device outside of multipathd (and likely outside of
multipath which should delegate the remove).
3. user creates a new multipath device outside of mulitpathd that has the
same name as the removed device. For this to happen by running multipath,
they either needed to be using user_friendly_names and haved removed the old
mapping from the bindings file, or they need to have editted multipath.conf
to set the alias of the new device to the alias of the old one.
4. multipathd reloads the table of the new device to point to old paths
5. user writes data to these old paths
6. multipathd gets the event and removes the device.

This results in data corruption, and there's no guarantee that
rechecking anything will always catch this. At some point we need to
just say "Sorry. You shot yourself in the foot."

But if we are just grabbing information about a device we already know
about, and it has switched so that its no longer a multipath device,
then multipathd can't really mess with it. All of our ioctls will fail,
and we will shortly clean it up anyway.

It's possible that we want to be more careful validating the WWID of
devices that we are looking up by major:minor, since it's much more
likely that a device got removed and a completey different dm device got
created and reused the same minor number, but I don't know why we would
ever be looking up a device we already know about by major:minor. So we
should always be checking these devices to verify that they are
multipath devices, and we currently are. 

> Thoughts?
> 
> Martin
> 
> > -Ben
> > 
> > > Signed-off-by: Martin Wilck <mwilck@suse.com>
> > > ---
> > >  libmultipath/devmapper.c          | 13 +++++++++----
> > >  libmultipath/devmapper.h          |  2 ++
> > >  libmultipath/libmultipath.version |  1 +
> > >  3 files changed, 12 insertions(+), 4 deletions(-)
> > > 
> > > diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
> > > index 806ffb8..5f6c0c8 100644
> > > --- a/libmultipath/devmapper.c
> > > +++ b/libmultipath/devmapper.c
> > > @@ -829,6 +829,11 @@ int dm_get_map(const char *name, unsigned long
> > > long *size, char **outparams)
> > >  	}
> > >  }
> > >  
> > > +bool is_mpath_uuid(const char uuid[DM_UUID_LEN])
> > > +{
> > > +	return !strncmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN);
> > > +}
> > > +
> > >  /**
> > >   * dm_get_wwid(): return WWID for a multipath map
> > >   * @returns:
> > > @@ -845,7 +850,7 @@ int dm_get_wwid(const char *name, char *uuid,
> > > int uuid_len)
> > >  	if (rc != DMP_OK)
> > >  		return rc;
> > >  
> > > -	if (!strncmp(tmp, UUID_PREFIX, UUID_PREFIX_LEN))
> > > +	if (is_mpath_uuid(tmp))
> > >  		strlcpy(uuid, tmp + UUID_PREFIX_LEN, uuid_len);
> > >  	else {
> > >  		uuid[0] = '\0';
> > > @@ -970,7 +975,7 @@ int dm_is_mpath(const char *name)
> > >  			       (mapid_t) { .str = name },
> > >  			       (mapinfo_t) { .uuid = uuid,
> > > .tgt_type = TGT_MPATH });
> > >  
> > > -	if (rc != DMP_OK || strncmp(uuid, UUID_PREFIX,
> > > UUID_PREFIX_LEN))
> > > +	if (rc != DMP_OK || !is_mpath_uuid(uuid))
> > >  		return DM_IS_MPATH_NO;
> > >  	else
> > >  		return DM_IS_MPATH_YES;
> > > @@ -1065,7 +1070,7 @@ int _dm_flush_map (const char *mapname, int
> > > flags, int retries)
> > >  				  .uuid = uuid,
> > >  				  .tgt_type = TGT_MPATH,
> > >  				  .target = &params }) != DMP_OK
> > > -	    || strncmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN))
> > > +	    || !is_mpath_uuid(uuid))
> > >  		return DM_FLUSH_OK; /* nothing to do */
> > >  
> > >  	/* if the device currently has no partitions, do not
> > > @@ -1309,7 +1314,7 @@ struct multipath *dm_get_multipath(const char
> > > *name)
> > >  			  }) != DMP_OK)
> > >  		return NULL;
> > >  
> > > -	if (strncmp(uuid, UUID_PREFIX, UUID_PREFIX_LEN))
> > > +	if (!is_mpath_uuid(uuid))
> > >  		return NULL;
> > >  
> > >  	strlcpy(mpp->wwid, uuid + UUID_PREFIX_LEN, sizeof(mpp-
> > > >wwid));
> > > diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h
> > > index db5c5fd..a2b2837 100644
> > > --- a/libmultipath/devmapper.h
> > > +++ b/libmultipath/devmapper.h
> > > @@ -131,6 +131,8 @@ enum {
> > >  	DM_IS_MPATH_YES,
> > >  	DM_IS_MPATH_ERR,
> > >  };
> > > +
> > > +bool is_mpath_uuid(const char uuid[DM_UUID_LEN]);
> > >  int dm_is_mpath(const char *name);
> > >  
> > >  enum {
> > > diff --git a/libmultipath/libmultipath.version
> > > b/libmultipath/libmultipath.version
> > > index 7d3ff63..5b8f9e0 100644
> > > --- a/libmultipath/libmultipath.version
> > > +++ b/libmultipath/libmultipath.version
> > > @@ -127,6 +127,7 @@ global:
> > >  	init_foreign;
> > >  	init_prio;
> > >  	io_err_stat_handle_pathfail;
> > > +	is_mpath_uuid;
> > >  	is_path_valid;
> > >  	libmp_dm_task_create;
> > >  	libmp_get_version;
> > > -- 
> > > 2.45.2
> > 


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

* Re: [PATCH 31/44] libmultipath: add is_mpath_uuid() helper
  2024-07-11 18:39       ` Benjamin Marzinski
@ 2024-07-11 18:59         ` Martin Wilck
  0 siblings, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-11 18:59 UTC (permalink / raw)
  To: Benjamin Marzinski; +Cc: Christophe Varoqui, dm-devel

On Thu, 2024-07-11 at 14:39 -0400, Benjamin Marzinski wrote:
> On Thu, Jul 11, 2024 at 02:56:05PM +0200, Martin Wilck wrote:
> > On Wed, 2024-07-10 at 23:38 -0400, Benjamin Marzinski wrote:
> > > On Tue, Jul 09, 2024 at 11:39:22PM +0200, Martin Wilck wrote:
> > > > Export it, as it will be used by multipathd and
> > > > libmpathpersist.
> > > > 
> > > 
> > > This is fine. But I was thinking that if you wanted to actually
> > > add
> > > some optional flags to the flags argument of libmp_mapinfo(),
> > > this
> > > would
> > > be a good use. You could have a flag like DM_MAP_MPATH_WWID,
> > > which
> > > would
> > > verify that the device had a multipath UUID_PREFIX (and possibly
> > > force a
> > > check for a multipath target type) and then return the wwid
> > > without
> > > the
> > > multipath uuid prefix.
> > > 
> > > Just a thought.
> > 
> > Interesting idea. My thinking was that libmp_mapinfo() should only
> > be
> > an interface to libdevmapper, and should not interpret the data it
> > returns in any way.
> > 
> > The only exception is the target type. In theory, the function
> > could
> > just have returned the target type, and left the interpretation to
> > the
> > caller. But then, it would have to perform several strdup()s for
> > the
> > results, and the caller would have to free() the data it wasn't
> > interested in, which would lead to clumsy and inefficent code in
> > the
> > frequent case that we're just interested in "multipath" or "linear"
> > targets. That's why I decided to pass the tgt_type field in, and
> > return
> > DMP_NO_MATCH if it didn't match, even though it's arguably odd in
> > the
> > mapinfo_t structure, which is otherwise only used for output
> > fields.
> 
> I did wonder if it would make more sense to just pass a struct to
> libmp_mapinfo() that contained all the input data, with the flags and
> the identifiers (tgt_type just being an additional optional identier)
> grouped together.  But I'm fine with the exiting interface so it
> didn't
> seem worth commenting on.
>  
> > Your flag idea would work, too (an earlier version of this patch
> > set
> > used flags to indicate which output fields should be filled in; I
> > discarded that because it was duplicated information, and more
> > elegant
> > to simply check it the respective output field was non-NULL).
> > 
> > Instead of tgt_type, we could also pass a "filter" callback
> > function
> > with which the caller could determine whether or not it was
> > interested
> > in a given map. But I wonder if that'd be over-engineered.
> > 
> > Whatever we eventually do, I think the is_mpath_uuid() helper will
> > be
> > useful. I am not sure whether we can unexport it even if we
> > implement
> > more sophisticated "filtering" in libmp_mapinfo().
> > 
> > In general, I wonder what multipath-tools should do if it
> > encounters a
> > map that has "multipath" target type, but the WWID of which doesn't
> > conform to the mpath-XYZ convention, or vice versa. This can only
> > happen if another tool like dmsetup had been used to create the
> > map.
> > IMO, if multipathd encounters such a situation, it should warn
> > about it
> > and keep its fingers off the map in question. But we might also
> > play it
> > simple and just assume that multipath maps always adhere to our
> > convention. I don't think we currently behave consistently in this
> > respect.
> 
> There was a time when there were users of the kernel multipath target
> outside of the multipath-tools. To deal with them, the idea was that
> multipathd would only manage devices that had a uuid with
> UUID_PREFIX.
> That was a while ago, and we likely have been violating that
> condition,
> but I haven't heard of any complaints. It might be worth auditing the
> code to see if/where we aren't verifying new devices.
> 
> Obviously if we find a dm device that isn't a multipath target, we
> shouldn't do anything with it, regardless of its UUID.
>  
> > AFAIU, both the WWID and the target type are immutable and can't be
> > altered without destroying the map completely (because "multipath"
> > is
> > an "immutable target" in DM). Thus it should be sufficient to check
> > the
> > WWID when a map is first encountered.
> 
> Probably. Obviously, a multipath device could get removed outside of
> multipathd and another device added with the same identifier that
> we're
> using. There would be a window before we got the remove event where
> we
> would be looking at the wrong device. But I can't really come up with
> a way for this to happen that doesn't involve very creative stupidity
> on
> the user's part, and since you need to be root to do this, I don't
> see
> any security issues here.
> 
> This isn't exactly what you're asking about but the results are
> worse,
> and I don't think there is a way to guarantee the following can't
> happen:
> 
> 1. multipathd decides in needs to reload a multipath device that is
> not in
> use and grabs the vecs lock so no events will get processed
> 2. user removes that device outside of multipathd (and likely outside
> of
> multipath which should delegate the remove).
> 3. user creates a new multipath device outside of mulitpathd that has
> the
> same name as the removed device. For this to happen by running
> multipath,
> they either needed to be using user_friendly_names and haved removed
> the old
> mapping from the bindings file, or they need to have editted
> multipath.conf
> to set the alias of the new device to the alias of the old one.
> 4. multipathd reloads the table of the new device to point to old
> paths
> 5. user writes data to these old paths
> 6. multipathd gets the event and removes the device.
> 
> This results in data corruption, and there's no guarantee that
> rechecking anything will always catch this. At some point we need to
> just say "Sorry. You shot yourself in the foot."

Right.

One thing we might consider is to use the DM UUID as primary identifier
for maps, rather than the name/alias. That wouldn't completely prevent
a scenario like the above, but the user would have to mess with
uid_attribute to make it happen. Instead of the WWID, we could actually
have a dm_uuid field in struct multipath.

Martin


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

* Re: [PATCH 23/44] libmultipath: improve dm_get_wwid() return value logic
  2024-07-11 12:25     ` Martin Wilck
  2024-07-11 16:38       ` Benjamin Marzinski
@ 2024-07-11 22:00       ` Martin Wilck
  1 sibling, 0 replies; 75+ messages in thread
From: Martin Wilck @ 2024-07-11 22:00 UTC (permalink / raw)
  To: Benjamin Marzinski; +Cc: Christophe Varoqui, dm-devel

On Thu, 2024-07-11 at 14:25 +0200, Martin Wilck wrote:
> On Wed, 2024-07-10 at 19:34 -0400, Benjamin Marzinski wrote:
> > On Tue, Jul 09, 2024 at 11:39:14PM +0200, Martin Wilck wrote:
> > > 
> > >  
> > > +/**
> > > + * dm_get_wwid(): return WWID for a multipath map
> > > + * @returns:
> > > + *    DMP_OK if successful
> > > + *    DMP_NOT_FOUND if the map doesn't exist
> > > + *    DMP_NO_MATCH if the map exists but is not a multipath map
> > > + *    DMP_ERR for other errors
> > > + */
> > >  int dm_get_wwid(const char *name, char *uuid, int uuid_len)
> > >  {
> > >  	char tmp[DM_UUID_LEN];
> > > +	int rc = dm_get_dm_uuid(name, tmp);
> > >  
> > > -	if (dm_get_dm_uuid(name, tmp) != DMP_OK)
> > > -		return 1;
> > > +	if (rc != DMP_OK)
> > > +		return rc;
> > >  
> > >  	if (!strncmp(tmp, UUID_PREFIX, UUID_PREFIX_LEN))
> > >  		strlcpy(uuid, tmp + UUID_PREFIX_LEN, uuid_len);
> > > -	else
> > > +	else {
> > 
> > This seems a little inconsistent with the change in our returns.
> > Before, if we found a device but it wasn't multipath device,
> > dm_get_wwid() would exit with 0 but set uuid to an empty string.
> > Now
> > we
> > return DMP_NO_MATCH in this case but we still clear uuid. It seems
> > like
> > perhaps we should either set uuid to an empty string for all cases
> > except DM_OK or we should not touch it for all cases except DM_OK.
> > Alternatively, perhaps I'm over-thinking this.
> 
> Right. In libmp_mapinfo(), I followed the idea that no output should
> be
> touched if any errors happened. Here, I wanted to preserve the
> behavior
> but didn't do it correctly.
> 
> I tend to think that "don't touch output in error case" is the
> correct
> behavior, but we'd need to review the callers and make sure that they
> don't assume the WWID will be automatically 0-terminated.
> 
> I'll do that.

Turns out that the callers that need changes because of the changed
semantics of dm_get_wwid() will be changed later on anyway, and the
respective modifications of the callers will be removed again. But I'll
do this anyway, to make the patch set consistent.

Martin


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

end of thread, other threads:[~2024-07-11 22:00 UTC | newest]

Thread overview: 75+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-07-09 21:38 [PATCH 00/44] multipath-tools: devmapper API refactored Martin Wilck
2024-07-09 21:38 ` [PATCH 01/44] multipath-tools CI: more fixes for arm/v7 Martin Wilck
2024-07-10  7:06   ` Martin Wilck
2024-07-09 21:38 ` [PATCH 02/44] multipath-tools CI: fix dmevents test for Debian Sid, arm/v7 Martin Wilck
2024-07-09 21:38 ` [PATCH 03/44] create-config.mk: use printf instead of /bin/echo Martin Wilck
2024-07-09 21:38 ` [PATCH 04/44] multipathd.service.in: use @BINDIR@ instead of /sbin Martin Wilck
2024-07-09 21:38 ` [PATCH 05/44] Makefile.inc: replace @BINDIR@ with $(TGTDIR)/$(bindir) Martin Wilck
2024-07-09 21:38 ` [PATCH 06/44] kpartx.rules: use @BINDIR@ to locate kpartx Martin Wilck
2024-07-10 16:30   ` Benjamin Marzinski
2024-07-10 20:15     ` Martin Wilck
2024-07-09 21:38 ` [PATCH 07/44] multipath-tools: Remove hard-coded paths to executables Martin Wilck
2024-07-09 21:38 ` [PATCH 08/44] multipath-tools: compile_commands.json fixes Martin Wilck
2024-07-09 21:39 ` [PATCH 09/44] multipath-tools: .gitignore: ignore o.wrap files for CI helpers Martin Wilck
2024-07-09 21:39 ` [PATCH 10/44] libmultipath: remove unused includes in devmapper.h Martin Wilck
2024-07-09 21:39 ` [PATCH 11/44] libmultipath: use DM_DEVICE_INFO in dm_mapname() Martin Wilck
2024-07-09 21:39 ` [PATCH 12/44] multipath-tools: don't call dm_task_no_open_count() Martin Wilck
2024-07-09 21:39 ` [PATCH 13/44] libmpathutil: export cleanup_udev_device() Martin Wilck
2024-07-09 21:39 ` [PATCH 14/44] libmpathutil: add cleanup_vector() Martin Wilck
2024-07-09 21:39 ` [PATCH 15/44] libmultipath: add cleanup helpers for struct multipath Martin Wilck
2024-07-09 21:39 ` [PATCH 16/44] libmultipath: add cleanup_dm_task(), and use it in devmapper.c Martin Wilck
2024-07-10 20:12   ` Benjamin Marzinski
2024-07-10 20:18     ` Martin Wilck
2024-07-09 21:39 ` [PATCH 17/44] libmultipath: add libmp_mapinfo() Martin Wilck
2024-07-10 22:53   ` Benjamin Marzinski
2024-07-11 11:00     ` Martin Wilck
2024-07-09 21:39 ` [PATCH 18/44] libmultipath tests: add tests for libmp_mapinfo() Martin Wilck
2024-07-09 21:39 ` [PATCH 19/44] libmultipath: implement dm_get_info() and dm_map_present() with new API Martin Wilck
2024-07-09 21:39 ` [PATCH 20/44] libmultipath: remove dm_get_prefixed_uuid() Martin Wilck
2024-07-09 21:39 ` [PATCH 21/44] libmultipath: is_mpath_part(): improve parsing Martin Wilck
2024-07-10 22:54   ` Benjamin Marzinski
2024-07-11 11:08     ` Martin Wilck
2024-07-11 17:01       ` Benjamin Marzinski
2024-07-11 17:41         ` Martin Wilck
2024-07-09 21:39 ` [PATCH 22/44] libmultipath: rename dm_get_uuid() -> dm_get_wwid() Martin Wilck
2024-07-09 21:39 ` [PATCH 23/44] libmultipath: improve dm_get_wwid() return value logic Martin Wilck
2024-07-10 23:34   ` Benjamin Marzinski
2024-07-11 12:25     ` Martin Wilck
2024-07-11 16:38       ` Benjamin Marzinski
2024-07-11 22:00       ` Martin Wilck
2024-07-09 21:39 ` [PATCH 24/44] libmultipath: reimplement dm_map_name() with new API Martin Wilck
2024-07-10 23:41   ` Benjamin Marzinski
2024-07-09 21:39 ` [PATCH 25/44] libmultipath: reimplement dm_map_present_by_uuid() Martin Wilck
2024-07-09 21:39 ` [PATCH 26/44] libmultipath: reimplement dm_get_opencount() with new API Martin Wilck
2024-07-09 21:39 ` [PATCH 27/44] libmpathpersist: skip redundant dm_map_present() call Martin Wilck
2024-07-09 21:39 ` [PATCH 28/44] libmultipath: implement dm_is_mpath() with new API Martin Wilck
2024-07-11  0:21   ` Benjamin Marzinski
2024-07-11 12:32     ` Martin Wilck
2024-07-09 21:39 ` [PATCH 29/44] libmultipath: implement dm_get_multipath() " Martin Wilck
2024-07-09 21:39 ` [PATCH 30/44] libmultipath: use libmp_mapinfo() in _dm_flush_map() Martin Wilck
2024-07-09 21:39 ` [PATCH 31/44] libmultipath: add is_mpath_uuid() helper Martin Wilck
2024-07-11  3:38   ` Benjamin Marzinski
2024-07-11 12:56     ` Martin Wilck
2024-07-11 18:39       ` Benjamin Marzinski
2024-07-11 18:59         ` Martin Wilck
2024-07-09 21:39 ` [PATCH 32/44] libmultipath: add is_mpath_part_uuid() helper Martin Wilck
2024-07-09 21:39 ` [PATCH 33/44] libmultipath: add dmp_errstr() helper Martin Wilck
2024-07-09 21:39 ` [PATCH 34/44] libmultipath: use libmp_mapinfo() in do_foreach_partmaps() Martin Wilck
2024-07-09 21:39 ` [PATCH 35/44] libmultipath: use libmp_pathinfo() in update_multipath_table() Martin Wilck
2024-07-11  5:16   ` Benjamin Marzinski
2024-07-11 15:29     ` Martin Wilck
2024-07-09 21:39 ` [PATCH 36/44] libmultipath: update mpp->dmi " Martin Wilck
2024-07-09 21:39 ` [PATCH 37/44] libmultipath: drop extra call to dm_map_present() in domap() Martin Wilck
2024-07-09 21:39 ` [PATCH 38/44] libmultipath: split off update_multipath_table__() Martin Wilck
2024-07-09 21:39 ` [PATCH 39/44] multipath: implement check_usable_paths() with libmp_pathinfo() Martin Wilck
2024-07-11  5:38   ` Benjamin Marzinski
2024-07-09 21:39 ` [PATCH 40/44] multipathd: implement add_map_without_path() with libmp_mapinfo() Martin Wilck
2024-07-11  6:11   ` Benjamin Marzinski
2024-07-09 21:39 ` [PATCH 41/44] libmultipath: simplify dm_get_maps() Martin Wilck
2024-07-09 21:39 ` [PATCH 42/44] llibmultipath: fix return code check for dm_is_suspended() Martin Wilck
2024-07-11  6:27   ` Benjamin Marzinski
2024-07-11 15:35     ` Martin Wilck
2024-07-09 21:39 ` [PATCH 43/44] libmpathpersist: use libmp_mapinfo() in get_mpvec() Martin Wilck
2024-07-11  6:43   ` Benjamin Marzinski
2024-07-09 21:39 ` [PATCH 44/44] libmpathpersist: use mpp->alias in do_mpath_persistent_reserve_out() Martin Wilck
2024-07-11  6:55 ` [PATCH 00/44] multipath-tools: devmapper API refactored Benjamin Marzinski

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.