From fa990d1ba4aabb8bea188d5ecdf0874510880249 Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Thu, 6 Nov 2025 20:08:14 -0500 Subject: [PATCH 01/42] multipathd: Fix race while registering PR key When libmpathpersist registers a key, It first checks which paths are active, then registers the key on those paths, and then tells multipathd that the key has been registered, and it should start tracking it. If a path comes up after libmpathpersist checks for active paths, but before it tells multipathd that the key has been registered, multipathd will not register a key no that path (since it hasn't been told to that the device has a registered key yet). This can leave the device with a path that is missing a key. To solve this, when multipathd is told that a key has been registered, it checks if there are the same number of registered keys as active paths. If there aren't, it registers keys on all the paths (at least until the number of registered keys and active paths are equal). To avoid doing a bunch of unnecessary PR work, pr_register_active_paths() has a new option to track the number of active paths, and mpath_pr_event_handle() now takes the number of keys to expect. The first time it's called, when there is an unknown number of keys, if the number of keys it finds matches the number of active_paths, it and pr_register_active_paths() exit early, since there is no registering work to do. Signed-off-by: Benjamin Marzinski Reviewed-by: Martin Wilck (cherry picked from commit f7d6cd175f789056d1faa34d88ab908f71d6a837) --- multipathd/cli_handlers.c | 6 ++++- multipathd/main.c | 57 ++++++++++++++++++++++++++++----------- multipathd/main.h | 1 + 3 files changed, 48 insertions(+), 16 deletions(-) diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c index 7f572fb44..2812d01eb 100644 --- a/multipathd/cli_handlers.c +++ b/multipathd/cli_handlers.c @@ -1291,7 +1291,11 @@ cli_setprstatus(void * v, struct strbuf *reply, void * data) if (mpp->prflag != PR_SET) { set_pr(mpp); - condlog(2, "%s: prflag set", param); + pr_register_active_paths(mpp, true); + if (mpp->prflag == PR_SET) + condlog(2, "%s: prflag set", param); + else + condlog(0, "%s: Failed to set prflag", param); } memset(&mpp->old_pr_key, 0, 8); diff --git a/multipathd/main.c b/multipathd/main.c index d11a8576c..4c86f31ee 100644 --- a/multipathd/main.c +++ b/multipathd/main.c @@ -90,7 +90,8 @@ #define MSG_SIZE 32 static unsigned int -mpath_pr_event_handle(struct path *pp, unsigned int nr_keys_needed); +mpath_pr_event_handle(struct path *pp, unsigned int nr_keys_needed, + unsigned int nr_keys_wanted); #define LOG_MSG(lvl, pp) \ do { \ @@ -629,19 +630,28 @@ flush_map_nopaths(struct multipath *mpp, struct vectors *vecs) { return true; } -static void -pr_register_active_paths(struct multipath *mpp) +void pr_register_active_paths(struct multipath *mpp, bool check_nr_active) { unsigned int i, j, nr_keys = 0; + unsigned int nr_active = 0; struct path *pp; struct pathgroup *pgp; + if (check_nr_active) { + nr_active = count_active_paths(mpp); + if (!nr_active) + return; + } + vector_foreach_slot (mpp->pg, pgp, i) { vector_foreach_slot (pgp->paths, pp, j) { if (mpp->prflag == PR_UNSET) return; - if ((pp->state == PATH_UP) || (pp->state == PATH_GHOST)) - nr_keys = mpath_pr_event_handle(pp, nr_keys); + if (pp->state == PATH_UP || pp->state == PATH_GHOST) { + nr_keys = mpath_pr_event_handle(pp, nr_keys, nr_active); + if (check_nr_active && nr_keys == nr_active) + return; + } } } } @@ -729,7 +739,7 @@ update_map (struct multipath *mpp, struct vectors *vecs, int new_map) sync_map_state(mpp, false); - pr_register_active_paths(mpp); + pr_register_active_paths(mpp, false); if (VECTOR_SIZE(offline_paths) != 0) handle_orphaned_offline_paths(offline_paths); @@ -1319,7 +1329,7 @@ ev_add_path (struct path * pp, struct vectors * vecs, int need_do_map) verify_paths(mpp); mpp->action = ACT_RELOAD; prflag = mpp->prflag; - mpath_pr_event_handle(pp, 0); + mpath_pr_event_handle(pp, 0, 0); } else { if (!should_multipath(pp, vecs->pathvec, vecs->mpvec)) { orphan_path(pp, "only one path"); @@ -1403,7 +1413,7 @@ ev_add_path (struct path * pp, struct vectors * vecs, int need_do_map) if (retries >= 0) { if ((mpp->prflag == PR_SET && prflag != PR_SET) || start_waiter) - pr_register_active_paths(mpp); + pr_register_active_paths(mpp, false); condlog(2, "%s [%s]: path added to devmap %s", pp->dev, pp->dev_t, mpp->alias); return 0; @@ -2646,9 +2656,9 @@ update_path_state (struct vectors * vecs, struct path * pp) */ condlog(2, "%s: checking persistent " "reservation registration", pp->dev); - mpath_pr_event_handle(pp, 0); + mpath_pr_event_handle(pp, 0, 0); if (pp->mpp->prflag == PR_SET && prflag != PR_SET) - pr_register_active_paths(pp->mpp); + pr_register_active_paths(pp->mpp, false); } /* @@ -3309,7 +3319,7 @@ configure (struct vectors * vecs, enum force_reload_types reload_type) vector_foreach_slot(mpvec, mpp, i){ if (remember_wwid(mpp->wwid) == 1) trigger_paths_udev_change(mpp, true); - pr_register_active_paths(mpp); + pr_register_active_paths(mpp, false); } /* @@ -4267,7 +4277,8 @@ void unset_pr(struct multipath *mpp) * * The number of found keys must be at least as large as *nr_keys, * and if MPATH_PR_SUCCESS is returned and mpp->prflag is PR_SET after - * the call, *nr_keys will be set to the number of found keys. + * the call, *nr_keys will be set to the number of found keys. Otherwise + * it will be set to 0. */ static int update_map_pr(struct multipath *mpp, struct path *pp, unsigned int *nr_keys) { @@ -4277,8 +4288,10 @@ static int update_map_pr(struct multipath *mpp, struct path *pp, unsigned int *n bool was_set = (mpp->prflag == PR_SET); /* If pr is explicitly unset, it must be manually set */ - if (mpp->prflag == PR_UNSET) + if (mpp->prflag == PR_UNSET) { + *nr_keys = 0; return MPATH_PR_SUCCESS; + } if (!get_be64(mpp->reservation_key)) { /* Nothing to do. Assuming pr mgmt feature is disabled*/ @@ -4286,6 +4299,7 @@ static int update_map_pr(struct multipath *mpp, struct path *pp, unsigned int *n condlog(was_set ? 2 : 4, "%s: reservation_key not set in multipath.conf", mpp->alias); + *nr_keys = 0; return MPATH_PR_SUCCESS; } @@ -4297,6 +4311,7 @@ static int update_map_pr(struct multipath *mpp, struct path *pp, unsigned int *n unset_pr(mpp); condlog(0, "%s : pr in read keys service action failed Error=%d", mpp->alias, ret); + *nr_keys = 0; return ret; } @@ -4335,22 +4350,32 @@ static int update_map_pr(struct multipath *mpp, struct path *pp, unsigned int *n condlog(was_set ? 1 : 3, "%s: %u keys found. needed %u. prflag unset.", mpp->alias, nr_found, *nr_keys); + *nr_keys = 0; } return MPATH_PR_SUCCESS; } /* - * This function is called with the number of registered keys that should be + * This function is called with two numbers + * + * nr_keys_needed: the number of registered keys that should be * seen for this device to know that the key has not been preempted while the * path was getting registered. If 0 is passed in, update_mpath_pr is called * before registering the key to figure out the number, assuming that at * least one key must exist. * + * nr_keys_wanted: Only used if nr_keys_needed is 0, so we don't know how + * many keys we currently have. If nr_keys_wanted in non-zero and the + * number of keys found by the initial call to update_map_pr() matches it, + * exit early, since we have all the keys we are expecting. + * * The function returns the number of keys that are registered or 0 if * it's unknown. */ -static unsigned int mpath_pr_event_handle(struct path *pp, unsigned int nr_keys_needed) +static unsigned int +mpath_pr_event_handle(struct path *pp, unsigned int nr_keys_needed, + unsigned int nr_keys_wanted) { struct multipath *mpp = pp->mpp; int ret; @@ -4366,6 +4391,8 @@ static unsigned int mpath_pr_event_handle(struct path *pp, unsigned int nr_keys_ nr_keys_needed = 1; if (update_map_pr(mpp, pp, &nr_keys_needed) != MPATH_PR_SUCCESS) return 0; + if (nr_keys_wanted && nr_keys_wanted == nr_keys_needed) + return nr_keys_needed; } check_prhold(mpp, pp); diff --git a/multipathd/main.h b/multipathd/main.h index 29b57e3de..6d60ee815 100644 --- a/multipathd/main.h +++ b/multipathd/main.h @@ -54,4 +54,5 @@ int resize_map(struct multipath *mpp, unsigned long long size, struct vectors *vecs); void set_pr(struct multipath *mpp); void unset_pr(struct multipath *mpp); +void pr_register_active_paths(struct multipath *mpp, bool check_active_nr); #endif /* MAIN_H_INCLUDED */ From 5e2fb542b54c4183133ca8006523b509b653de5c Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Tue, 11 Nov 2025 15:52:53 -0500 Subject: [PATCH 02/42] mpathpersist: Fix REPORT CAPABILITIES output mpathpersist was incorrectly parsing the REPORT CAPABILITES service action output. In reality, the type mask is two bytes where the type information is stored in bits 7, 6, 5, 3, & 1 (0xea) of the first byte and bit 0 (0x01) of the second byte. libmpathpersist was treating these two bytes as a big endian 16 bit number, but mpathpersist was looking for bits in that number as if it was little endian number. Ideally, libmpathpersist would treat prin_capdescr.pr_type_mask as two bytes, like it does for the flags. But we already expose this as a 16 bit number, where we treated the input bytes as a big endian number. There's no great reason to mess with the libmpathpersist API, when we can just make mpathpersist treat this data like libmpathpersist provides it. So, fix mpathpersist to print the data out correctly. Additionally, instead of printing a 1 or a 0 to indicate if a type was supported or not, it was printing the value of the type flag. Also, Persist Through Power Loss Capable (PTPL_C) was being reported if any bit in flags[0] was set. Fix these as well. Reformat all of the capability printing lines, since it is less confusing than only reformatting some of them. Fixes: ae4e8a6 ("mpathpersist: Add new utility for managing persistent reservation on dm multipath device") Signed-off-by: Benjamin Marzinski Reviewed-by: Martin Wilck (cherry picked from commit c8ed5e6eea98244745904adaaa4aef83a8722fb0) --- libmpathpersist/mpath_persist.h | 4 ++- mpathpersist/main.c | 43 +++++++++++++++++++++++---------- 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/libmpathpersist/mpath_persist.h b/libmpathpersist/mpath_persist.h index 449e2825a..a4edb83be 100644 --- a/libmpathpersist/mpath_persist.h +++ b/libmpathpersist/mpath_persist.h @@ -113,7 +113,9 @@ struct prin_capdescr { uint16_t length; uint8_t flags[2]; - uint16_t pr_type_mask; + uint16_t pr_type_mask; /* The two bytes of the type mask are treated + as a single big-endian number. So the valid + type bits are 0xea01 */ uint16_t _reserved; }; diff --git a/mpathpersist/main.c b/mpathpersist/main.c index 97fd5a43f..fea5a9cbf 100644 --- a/mpathpersist/main.c +++ b/mpathpersist/main.c @@ -748,25 +748,42 @@ void mpath_print_buf_readcap( struct prin_resp *pr_buff) printf("Report capabilities response:\n"); - printf(" Compatible Reservation Handling(CRH): %d\n", !!(pr_buff->prin_descriptor.prin_readcap.flags[0] & 0x10)); - printf(" Specify Initiator Ports Capable(SIP_C): %d\n",!!(pr_buff->prin_descriptor.prin_readcap.flags[0] & 0x8)); - printf(" All Target Ports Capable(ATP_C): %d\n",!!(pr_buff->prin_descriptor.prin_readcap.flags[0] & 0x4 )); - printf(" Persist Through Power Loss Capable(PTPL_C): %d\n",!!(pr_buff->prin_descriptor.prin_readcap.flags[0])); - printf(" Type Mask Valid(TMV): %d\n", !!(pr_buff->prin_descriptor.prin_readcap.flags[1] & 0x80)); - printf(" Allow Commands: %d\n", !!(( pr_buff->prin_descriptor.prin_readcap.flags[1] >> 4) & 0x7)); + printf(" Compatible Reservation Handling(CRH): %d\n", + !!(pr_buff->prin_descriptor.prin_readcap.flags[0] & 0x10)); + printf(" Specify Initiator Ports Capable(SIP_C): %d\n", + !!(pr_buff->prin_descriptor.prin_readcap.flags[0] & 0x8)); + printf(" All Target Ports Capable(ATP_C): %d\n", + !!(pr_buff->prin_descriptor.prin_readcap.flags[0] & 0x4)); + printf(" Persist Through Power Loss Capable(PTPL_C): %d\n", + !!(pr_buff->prin_descriptor.prin_readcap.flags[0] & 0x1)); + printf(" Type Mask Valid(TMV): %d\n", + !!(pr_buff->prin_descriptor.prin_readcap.flags[1] & 0x80)); + printf(" Allow Commands: %d\n", + !!((pr_buff->prin_descriptor.prin_readcap.flags[1] >> 4) & 0x7)); printf(" Persist Through Power Loss Active(PTPL_A): %d\n", - !!(pr_buff->prin_descriptor.prin_readcap.flags[1] & 0x1)); + !!(pr_buff->prin_descriptor.prin_readcap.flags[1] & 0x1)); if(pr_buff->prin_descriptor.prin_readcap.flags[1] & 0x80) { printf(" Support indicated in Type mask:\n"); - printf(" %s: %d\n", pr_type_strs[7], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x80); - printf(" %s: %d\n", pr_type_strs[6], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x40); - printf(" %s: %d\n", pr_type_strs[5], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x20); - printf(" %s: %d\n", pr_type_strs[3], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x8); - printf(" %s: %d\n", pr_type_strs[1], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x2); - printf(" %s: %d\n", pr_type_strs[8], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x100); + printf(" %s: %d\n", pr_type_strs[7], + !!(pr_buff->prin_descriptor.prin_readcap.pr_type_mask & + 0x8000)); + printf(" %s: %d\n", pr_type_strs[6], + !!(pr_buff->prin_descriptor.prin_readcap.pr_type_mask & + 0x4000)); + printf(" %s: %d\n", pr_type_strs[5], + !!(pr_buff->prin_descriptor.prin_readcap.pr_type_mask & + 0x2000)); + printf(" %s: %d\n", pr_type_strs[3], + !!(pr_buff->prin_descriptor.prin_readcap.pr_type_mask & + 0x800)); + printf(" %s: %d\n", pr_type_strs[1], + !!(pr_buff->prin_descriptor.prin_readcap.pr_type_mask & + 0x200)); + printf(" %s: %d\n", pr_type_strs[8], + !!(pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x1)); } } From beb63209350290caa2792b936599b7097053df44 Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Mon, 27 Oct 2025 21:17:15 +0100 Subject: [PATCH 03/42] GitHub Workflows: abi-stable: fix PARENT_TAG logic for pull request Signed-off-by: Martin Wilck (cherry picked from commit 866f343bafbc4dfb8ddb3ba6d8edeb9f0f04927a) --- .github/workflows/abi-stable.yaml | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/.github/workflows/abi-stable.yaml b/.github/workflows/abi-stable.yaml index 8a045b05c..238a06bf3 100644 --- a/.github/workflows/abi-stable.yaml +++ b/.github/workflows/abi-stable.yaml @@ -17,10 +17,16 @@ jobs: reference-abi: runs-on: ubuntu-22.04 steps: - - name: get parent tag + - name: get parent tag (push) run: > echo ${{ github.ref }} | sed -E 's,refs/heads/stable-([0-9]\.[0-9]*)\.y,PARENT_TAG=\1.0,' >> $GITHUB_ENV + if: ${{ github.event_name == 'push' }} + - name: get parent tag (PR) + run: > + echo ${{ github.base_ref }} | + sed -E 's,stable-([0-9]\.[0-9]*)\.y,PARENT_TAG=\1.0,' >> $GITHUB_ENV + if: ${{ github.event_name == 'pull_request' }} - name: assert parent tag run: /bin/false if: ${{ env.PARENT_TAG == '' }} @@ -48,17 +54,23 @@ jobs: runs-on: ubuntu-22.04 needs: reference-abi steps: - - name: get parent tag + - name: get parent tag (push) run: > echo ${{ github.ref }} | sed -E 's,refs/heads/stable-([0-9]\.[0-9]*)\.y,PARENT_TAG=\1.0,' >> $GITHUB_ENV + if: ${{ github.event_name == 'push' }} + - name: get parent tag (PR) + run: > + echo ${{ github.base_ref }} | + sed -E 's,stable-([0-9]\.[0-9]*)\.y,PARENT_TAG=\1.0,' >> $GITHUB_ENV + if: ${{ github.event_name == 'pull_request' }} - name: assert parent tag run: /bin/false if: ${{ env.PARENT_TAG == '' }} - - name: checkout ${{ env.PARENT_TAG }} + - name: checkout ${{ github.ref }} uses: actions/checkout@v4 with: - ref: ${{ env.PARENT_TAG }} + ref: ${{ github.ref }} - name: download ABI for ${{ env.PARENT_TAG }} id: download_abi uses: actions/download-artifact@v4 From 20d0d1d174b829e24e0de1cb3d2a7c4385b53aa2 Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Fri, 14 Nov 2025 12:12:46 +0100 Subject: [PATCH 04/42] GitHub workflows: Update runners to ubuntu-24.04 Signed-off-by: Martin Wilck (cherry picked from commit 541e36e5e5f9394e9aa4a5af3d70ffbaaff8eeff) --- .github/workflows/abi-stable.yaml | 4 ++-- .github/workflows/abi.yaml | 3 ++- .github/workflows/build-and-unittest.yaml | 2 +- .github/workflows/coverity.yaml | 2 +- .github/workflows/foreign.yaml | 6 +++--- .github/workflows/multiarch-stable.yaml | 2 +- .github/workflows/multiarch.yaml | 2 +- .github/workflows/native.yaml | 6 +++--- .github/workflows/rolling.yaml | 2 +- 9 files changed, 15 insertions(+), 14 deletions(-) diff --git a/.github/workflows/abi-stable.yaml b/.github/workflows/abi-stable.yaml index 238a06bf3..8b2c83a85 100644 --- a/.github/workflows/abi-stable.yaml +++ b/.github/workflows/abi-stable.yaml @@ -15,7 +15,7 @@ on: jobs: reference-abi: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - name: get parent tag (push) run: > @@ -51,7 +51,7 @@ jobs: path: abi check-abi: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 needs: reference-abi steps: - name: get parent tag (push) diff --git a/.github/workflows/abi.yaml b/.github/workflows/abi.yaml index b1282493f..70ceb89df 100644 --- a/.github/workflows/abi.yaml +++ b/.github/workflows/abi.yaml @@ -18,7 +18,7 @@ env: jobs: save-and-test-ABI: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - name: set ABI branch if: ${{ env.ABI_BRANCH == '' }} @@ -42,6 +42,7 @@ jobs: gcc make pkg-config abigail-tools libdevmapper-dev libreadline-dev libaio-dev libsystemd-dev libudev-dev libjson-c-dev liburcu-dev libcmocka-dev libedit-dev + libmount-dev - name: create ABI run: make -Orecurse -j$(grep -c ^processor /proc/cpuinfo) abi.tar.gz - name: save ABI diff --git a/.github/workflows/build-and-unittest.yaml b/.github/workflows/build-and-unittest.yaml index 4f568131c..a3ee7d8e7 100644 --- a/.github/workflows/build-and-unittest.yaml +++ b/.github/workflows/build-and-unittest.yaml @@ -13,7 +13,7 @@ on: - 'stable-*' jobs: jammy: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: fail-fast: false matrix: diff --git a/.github/workflows/coverity.yaml b/.github/workflows/coverity.yaml index 678d0d2a3..3ade6771b 100644 --- a/.github/workflows/coverity.yaml +++ b/.github/workflows/coverity.yaml @@ -6,7 +6,7 @@ on: jobs: upload-coverity-scan: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - name: checkout uses: actions/checkout@v4 diff --git a/.github/workflows/foreign.yaml b/.github/workflows/foreign.yaml index a25179710..47affb7ac 100644 --- a/.github/workflows/foreign.yaml +++ b/.github/workflows/foreign.yaml @@ -27,7 +27,7 @@ on: jobs: cross-build: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: fail-fast: false matrix: @@ -52,7 +52,7 @@ jobs: overwrite: true test: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 needs: cross-build strategy: fail-fast: false @@ -94,7 +94,7 @@ jobs: pull-params: "--platform linux/${{ env.CONTAINER_ARCH }}" root-test: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 needs: cross-build strategy: fail-fast: false diff --git a/.github/workflows/multiarch-stable.yaml b/.github/workflows/multiarch-stable.yaml index 2a30a8605..4c4bf95c0 100644 --- a/.github/workflows/multiarch-stable.yaml +++ b/.github/workflows/multiarch-stable.yaml @@ -26,7 +26,7 @@ on: jobs: build-old: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: fail-fast: false matrix: diff --git a/.github/workflows/multiarch.yaml b/.github/workflows/multiarch.yaml index c453446a6..c94f19ee6 100644 --- a/.github/workflows/multiarch.yaml +++ b/.github/workflows/multiarch.yaml @@ -30,7 +30,7 @@ on: jobs: build-current: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: fail-fast: false matrix: diff --git a/.github/workflows/native.yaml b/.github/workflows/native.yaml index 6b38fa712..7b7e8c64a 100644 --- a/.github/workflows/native.yaml +++ b/.github/workflows/native.yaml @@ -26,7 +26,7 @@ on: jobs: stable: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: fail-fast: false matrix: @@ -85,7 +85,7 @@ jobs: overwrite: true clang: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: fail-fast: false matrix: @@ -117,7 +117,7 @@ jobs: command: -j -Orecurse READLINE=libreadline test root-test: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 needs: stable strategy: fail-fast: false diff --git a/.github/workflows/rolling.yaml b/.github/workflows/rolling.yaml index 503625e04..b5ff4f516 100644 --- a/.github/workflows/rolling.yaml +++ b/.github/workflows/rolling.yaml @@ -29,7 +29,7 @@ on: jobs: rolling: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: fail-fast: false matrix: From f6b0403e904b1e198b43c4d872dc6a6a80ad2879 Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Fri, 14 Nov 2025 13:02:50 +0100 Subject: [PATCH 05/42] GitHub workflows: native.yaml: add fedora-43 Signed-off-by: Martin Wilck (cherry picked from commit 1dbc6ff522fdb188d750abb97b7fc714ded54c95) --- .github/workflows/native.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/native.yaml b/.github/workflows/native.yaml index 7b7e8c64a..dbe701f0f 100644 --- a/.github/workflows/native.yaml +++ b/.github/workflows/native.yaml @@ -36,7 +36,7 @@ jobs: - debian-bullseye - debian-bookworm - debian-trixie - - fedora-42 + - fedora-43 - opensuse-leap steps: - name: checkout @@ -95,7 +95,7 @@ jobs: - debian-bullseye - debian-bookworm - debian-trixie - - fedora-42 + - fedora-43 - opensuse-leap steps: - name: checkout @@ -128,7 +128,7 @@ jobs: - debian-bullseye - debian-bookworm - debian-trixie - - fedora-42 + - fedora-43 - opensuse-leap steps: - name: mpath From 5108e1a1f9cb58db46fd6b8465d4dd612ddb4931 Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Fri, 14 Nov 2025 13:03:15 +0100 Subject: [PATCH 06/42] GitHub workflows: native.yaml: add openSUSE Leap 16.0 and 15.6 "opensuse-leap" would use 15.6 already, but make this explicit. Signed-off-by: Martin Wilck (cherry picked from commit 6e09ca12218621589e2dfe7c59ef62d55bc4279d) --- .github/workflows/native.yaml | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/.github/workflows/native.yaml b/.github/workflows/native.yaml index dbe701f0f..f6ee8699f 100644 --- a/.github/workflows/native.yaml +++ b/.github/workflows/native.yaml @@ -37,7 +37,8 @@ jobs: - debian-bookworm - debian-trixie - fedora-43 - - opensuse-leap + - opensuse-leap-15.6 + - opensuse-leap-16.0 steps: - name: checkout uses: actions/checkout@v4 @@ -45,10 +46,10 @@ jobs: - name: set archive name # Leap containers have cpio but not tar run: echo ARCHIVE_TGT=test-progs.cpio >> $GITHUB_ENV - if: ${{ matrix.os == 'opensuse-leap' }} + if: ${{ startswith(matrix.os, 'opensuse-leap-15') }} - name: set archive name run: echo ARCHIVE_TGT=test-progs.tar >> $GITHUB_ENV - if: ${{ matrix.os != 'opensuse-leap' }} + if: ${{ !startswith(matrix.os, 'opensuse-leap-15') }} - name: build and test if: ${{ matrix.os != 'debian-jessie' }} @@ -96,7 +97,8 @@ jobs: - debian-bookworm - debian-trixie - fedora-43 - - opensuse-leap + - opensuse-leap-15.6 + - opensuse-leap-16.0 steps: - name: checkout uses: actions/checkout@v4 @@ -129,7 +131,8 @@ jobs: - debian-bookworm - debian-trixie - fedora-43 - - opensuse-leap + - opensuse-leap-15.6 + - opensuse-leap-16.0 steps: - name: mpath run: sudo modprobe dm_multipath @@ -145,10 +148,10 @@ jobs: name: native-${{ matrix.os }} - name: unpack binary archive run: cpio -idv < test-progs.cpio - if: ${{ matrix.os == 'opensuse-leap' }} + if: ${{ startswith(matrix.os, 'opensuse-leap-15') }} - name: unpack binary archive run: tar xfmv test-progs.tar - if: ${{ matrix.os != 'opensuse-leap' }} + if: ${{ !startswith(matrix.os, 'opensuse-leap-15') }} - name: run root tests uses: mosteo-actions/docker-run@v1 From 5222c4a8be0f7d17a4878f20364d5ac62e1bd707 Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Fri, 14 Nov 2025 14:38:52 +0100 Subject: [PATCH 07/42] GitHub workflows: run arm64 tests on native runner GitHub provides arm64 runners now [1]. Use them. The workflows don't seem to run faster than before, but the tests should be more realistic. [1] https://github.blog/changelog/2025-01-16-linux-arm64-hosted-runners-now-available-for-free-in-public-repositories-public-preview/ Signed-off-by: Martin Wilck (cherry picked from commit 00cdcbc43e149aa41c1d81022350a74c9d2b4d69) --- .github/workflows/multiarch-stable.yaml | 4 ---- .github/workflows/multiarch.yaml | 5 +++- .github/workflows/native.yaml | 31 ++++++++++++++++++++----- .github/workflows/rolling.yaml | 13 +++++++++-- 4 files changed, 40 insertions(+), 13 deletions(-) diff --git a/.github/workflows/multiarch-stable.yaml b/.github/workflows/multiarch-stable.yaml index 4c4bf95c0..76ff1026d 100644 --- a/.github/workflows/multiarch-stable.yaml +++ b/.github/workflows/multiarch-stable.yaml @@ -37,14 +37,10 @@ jobs: - ubuntu-trusty arch: [386, arm/v7] include: - - os: debian-trixie - arch: aarch64 - os: debian-trixie arch: s390x - os: debian-trixie arch: ppc64le - - os: debian-bookworm - arch: aarch64 - os: debian-bookworm arch: s390x - os: debian-bookworm diff --git a/.github/workflows/multiarch.yaml b/.github/workflows/multiarch.yaml index c94f19ee6..b11ba06d5 100644 --- a/.github/workflows/multiarch.yaml +++ b/.github/workflows/multiarch.yaml @@ -39,12 +39,15 @@ jobs: - debian-sid - fedora-rawhide - opensuse-tumbleweed - arch: [amd64, ppc64le, aarch64, s390x, 386, arm/v7] + arch: [ppc64le, s390x, 386, arm/v7] exclude: - os: fedora-rawhide arch: 386 - os: fedora-rawhide arch: arm/v7 + include: + - os: alpine + arch: aarch64 steps: - name: checkout uses: actions/checkout@v4 diff --git a/.github/workflows/native.yaml b/.github/workflows/native.yaml index f6ee8699f..93eed5ff6 100644 --- a/.github/workflows/native.yaml +++ b/.github/workflows/native.yaml @@ -26,7 +26,6 @@ on: jobs: stable: - runs-on: ubuntu-24.04 strategy: fail-fast: false matrix: @@ -39,6 +38,12 @@ jobs: - fedora-43 - opensuse-leap-15.6 - opensuse-leap-16.0 + variant: + - arch: x86_64 + runner: ubuntu-24.04 + - arch: aarch64 + runner: ubuntu-24.04-arm + runs-on: ${{ matrix.variant.runner }} steps: - name: checkout uses: actions/checkout@v4 @@ -81,17 +86,15 @@ jobs: - name: upload binary archive uses: actions/upload-artifact@v4 with: - name: native-${{ matrix.os }} + name: native-${{ matrix.os }}-${{ matrix.variant.arch }} path: ${{ env.ARCHIVE_TGT }} overwrite: true clang: - runs-on: ubuntu-24.04 strategy: fail-fast: false matrix: os: - - debian-jessie - debian-buster - debian-bullseye - debian-bookworm @@ -99,6 +102,17 @@ jobs: - fedora-43 - opensuse-leap-15.6 - opensuse-leap-16.0 + variant: + - arch: x86_64 + runner: ubuntu-24.04 + - arch: aarch64 + runner: ubuntu-24.04-arm + include: + - os: debian-jessie + variant: + arch: x86_64 + runner: ubuntu-24.04 + runs-on: ${{ matrix.variant.runner }} steps: - name: checkout uses: actions/checkout@v4 @@ -119,7 +133,6 @@ jobs: command: -j -Orecurse READLINE=libreadline test root-test: - runs-on: ubuntu-24.04 needs: stable strategy: fail-fast: false @@ -133,6 +146,12 @@ jobs: - fedora-43 - opensuse-leap-15.6 - opensuse-leap-16.0 + variant: + - arch: x86_64 + runner: ubuntu-24.04 + - arch: aarch64 + runner: ubuntu-24.04-arm + runs-on: ${{ matrix.variant.runner }} steps: - name: mpath run: sudo modprobe dm_multipath @@ -145,7 +164,7 @@ jobs: - name: download binary archive uses: actions/download-artifact@v4 with: - name: native-${{ matrix.os }} + name: native-${{ matrix.os }}-${{ matrix.variant.arch }} - name: unpack binary archive run: cpio -idv < test-progs.cpio if: ${{ startswith(matrix.os, 'opensuse-leap-15') }} diff --git a/.github/workflows/rolling.yaml b/.github/workflows/rolling.yaml index b5ff4f516..a4b67a0ef 100644 --- a/.github/workflows/rolling.yaml +++ b/.github/workflows/rolling.yaml @@ -29,15 +29,24 @@ on: jobs: rolling: - runs-on: ubuntu-24.04 strategy: fail-fast: false matrix: os: - debian-sid - - alpine - opensuse-tumbleweed - fedora-rawhide + variant: + - arch: x86_64 + runner: ubuntu-24.04 + - arch: aarch64 + runner: ubuntu-24.04-arm + include: + - os: alpine + variant: + arch: x86_64 + runner: ubuntu-24.04 + runs-on: ${{ matrix.variant.runner }} container: ghcr.io/mwilck/multipath-build-${{ matrix.os }} steps: - name: checkout From 10377bc79a6bf6b74c411de05ce51804efa56e92 Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Mon, 17 Nov 2025 13:07:57 +0100 Subject: [PATCH 08/42] GitHub workflows: rolling: upload binaries on error This will allow debugging CI failures (to some extent, as we compile with optimization by default). Signed-off-by: Martin Wilck (cherry picked from commit aee2310bb6e8671e8311ea098df581bbf1acfdcb) --- .github/workflows/rolling.yaml | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/.github/workflows/rolling.yaml b/.github/workflows/rolling.yaml index a4b67a0ef..34efcff68 100644 --- a/.github/workflows/rolling.yaml +++ b/.github/workflows/rolling.yaml @@ -41,21 +41,38 @@ jobs: runner: ubuntu-24.04 - arch: aarch64 runner: ubuntu-24.04-arm + compiler: + - gcc + - clang include: - os: alpine variant: arch: x86_64 runner: ubuntu-24.04 + compiler: gcc + - os: alpine + variant: + arch: x86_64 + runner: ubuntu-24.04 + compiler: clang runs-on: ${{ matrix.variant.runner }} container: ghcr.io/mwilck/multipath-build-${{ matrix.os }} steps: - name: checkout uses: actions/checkout@v4 - name: build and test - run: make READLINE=libreadline -j -Orecurse test - - name: clean - run: make -j -Orecurse clean - - name: clang - env: - CC: clang - run: make READLINE=libedit -j -Orecurse test + id: test + run: make CC=${{ matrix.compiler }} READLINE=libreadline -j -Orecurse test + continue-on-error: true + - name: create binary archive + run: make test-progs.tar + if: steps.test.outcome != 'success' + - name: upload binary archive + uses: actions/upload-artifact@v4 + with: + name: binaries-${{ matrix.os }}-${{ matrix.variant.arch }}-${{ matrix.compiler }} + path: test-progs.tar + if: steps.test.outcome != 'success' + - name: fail + run: /bin/false + if: steps.test.outcome != 'success' From adb4cfe4a96204ca6644cc23f6d74ec712d241c9 Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Mon, 17 Nov 2025 13:31:25 +0100 Subject: [PATCH 09/42] GitHub workflows: multiarch-stable: upload binaries on error Signed-off-by: Martin Wilck (cherry picked from commit 34746cd08af6fa4969b0bc062d62d92750bef6f8) --- .github/workflows/multiarch-stable.yaml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/.github/workflows/multiarch-stable.yaml b/.github/workflows/multiarch-stable.yaml index 76ff1026d..b8c770e40 100644 --- a/.github/workflows/multiarch-stable.yaml +++ b/.github/workflows/multiarch-stable.yaml @@ -53,6 +53,7 @@ jobs: with: image: tonistiigi/binfmt:latest - name: compile and run unit tests + id: test uses: mosteo-actions/docker-run@v1 with: image: ghcr.io/mwilck/multipath-build-${{ matrix.os }} @@ -61,3 +62,23 @@ jobs: command: test params: "--platform linux/${{ matrix.arch }}" pull-params: "--platform linux/${{ matrix.arch }}" + continue-on-error: true + - name: create binary archive + uses: mosteo-actions/docker-run@v1 + with: + image: ghcr.io/mwilck/multipath-build-${{ matrix.os }} + guest-dir: /build + host-dir: ${{ github.workspace }} + command: test-progs.tar + params: "--platform linux/${{ matrix.arch }}" + pull-params: "--platform linux/${{ matrix.arch }}" + if: steps.test.outcome != 'success' + - name: upload binary archive + uses: actions/upload-artifact@v4 + with: + name: binaries-${{ matrix.os }}-${{ matrix.arch }} + path: test-progs.tar + if: steps.test.outcome != 'success' + - name: fail + run: /bin/false + if: steps.test.outcome != 'success' From 718e3faee660c80520b4d2e3124d0fec3aecd121 Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Mon, 17 Nov 2025 13:31:47 +0100 Subject: [PATCH 10/42] GitHub workflows: native: upload binaries on error Signed-off-by: Martin Wilck (cherry picked from commit f3bdfef8f63b9647de0cf9d65fbbe2c9b31751cd) --- .github/workflows/native.yaml | 67 +++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/.github/workflows/native.yaml b/.github/workflows/native.yaml index 93eed5ff6..94e5ef22d 100644 --- a/.github/workflows/native.yaml +++ b/.github/workflows/native.yaml @@ -57,18 +57,23 @@ jobs: if: ${{ !startswith(matrix.os, 'opensuse-leap-15') }} - name: build and test + id: test if: ${{ matrix.os != 'debian-jessie' }} uses: mosteo-actions/docker-run@v1 with: image: ghcr.io/mwilck/multipath-build-${{ matrix.os }} command: -j -Orecurse test + continue-on-error: true + - name: build and test (jessie) + id: test_jessie # On jessie, we use libreadline 5 (no licensing issue) if: ${{ matrix.os == 'debian-jessie' }} uses: mosteo-actions/docker-run@v1 with: image: ghcr.io/mwilck/multipath-build-${{ matrix.os }} command: -j -Orecurse READLINE=libreadline test + continue-on-error: true - name: create ${{ env.ARCHIVE_TGT }} if: ${{ matrix.os != 'debian-jessie' }} @@ -90,6 +95,13 @@ jobs: path: ${{ env.ARCHIVE_TGT }} overwrite: true + - name: fail + run: /bin/false + if: >- + ${{ ( matrix.os == 'debian-jessie' && + steps.test_jessie.outcome != 'success' ) || + ( matrix.os != 'debian-jessie' && + steps.test.outcome != 'success' ) }} clang: strategy: fail-fast: false @@ -117,20 +129,75 @@ jobs: - name: checkout uses: actions/checkout@v4 + - name: set archive name + # Leap containers have cpio but not tar + run: echo ARCHIVE_TGT=test-progs.cpio >> $GITHUB_ENV + if: ${{ startswith(matrix.os, 'opensuse-leap-15') }} + - name: set archive name + run: echo ARCHIVE_TGT=test-progs.tar >> $GITHUB_ENV + if: ${{ !startswith(matrix.os, 'opensuse-leap-15') }} + - name: clang + id: test if: ${{ matrix.os != 'debian-jessie' }} uses: mosteo-actions/docker-run@v1 with: image: ghcr.io/mwilck/multipath-build-${{ matrix.os }} params: -e CC=clang command: -j -Orecurse test + continue-on-error: true - name: clang (jessie) + id: test_jessie if: ${{ matrix.os == 'debian-jessie' }} uses: mosteo-actions/docker-run@v1 with: image: ghcr.io/mwilck/multipath-build-${{ matrix.os }} params: -e CC=clang command: -j -Orecurse READLINE=libreadline test + continue-on-error: true + + - name: create ${{ env.ARCHIVE_TGT }} + if: ${{ matrix.os != 'debian-jessie' }} + uses: mosteo-actions/docker-run@v1 + with: + image: ghcr.io/mwilck/multipath-build-${{ matrix.os }} + command: ${{ env.ARCHIVE_TGT }} + if: >- + ${{ ( matrix.os == 'debian-jessie' && + steps.test_jessie.outcome != 'success' ) || + ( matrix.os != 'debian-jessie' && + steps.test.outcome != 'success' ) }} + - name: create ${{ env.ARCHIVE_TGT }} (jessie) + if: ${{ matrix.os == 'debian-jessie' }} + uses: mosteo-actions/docker-run@v1 + with: + image: ghcr.io/mwilck/multipath-build-${{ matrix.os }} + command: READLINE=libreadline ${{ env.ARCHIVE_TGT }} + if: >- + ${{ ( matrix.os == 'debian-jessie' && + steps.test_jessie.outcome != 'success' ) || + ( matrix.os != 'debian-jessie' && + steps.test.outcome != 'success' ) }} + + - name: upload binary archive + uses: actions/upload-artifact@v4 + with: + name: clang-${{ matrix.os }}-${{ matrix.variant.arch }} + path: ${{ env.ARCHIVE_TGT }} + overwrite: true + if: >- + ${{ ( matrix.os == 'debian-jessie' && + steps.test_jessie.outcome != 'success' ) || + ( matrix.os != 'debian-jessie' && + steps.test.outcome != 'success' ) }} + + - name: fail + run: /bin/false + if: >- + ${{ ( matrix.os == 'debian-jessie' && + steps.test_jessie.outcome != 'success' ) || + ( matrix.os != 'debian-jessie' && + steps.test.outcome != 'success' ) }} root-test: needs: stable From 8a5aa0345caf7155b180033416f27484bea59e18 Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Mon, 17 Nov 2025 13:35:08 +0100 Subject: [PATCH 11/42] GitHub workflows: multiarch: upload binaries on error Signed-off-by: Martin Wilck (cherry picked from commit b854c7b9208d3fffff7cfb5fabb18d5e8db4770f) --- .github/workflows/multiarch.yaml | 22 +++++++++++++++++++++- .github/workflows/native.yaml | 2 -- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/.github/workflows/multiarch.yaml b/.github/workflows/multiarch.yaml index b11ba06d5..806275a13 100644 --- a/.github/workflows/multiarch.yaml +++ b/.github/workflows/multiarch.yaml @@ -56,6 +56,7 @@ jobs: with: image: tonistiigi/binfmt:latest - name: compile and run unit tests + id: test uses: mosteo-actions/docker-run@v1 with: image: ghcr.io/mwilck/multipath-build-${{ matrix.os }} @@ -64,4 +65,23 @@ jobs: command: test params: "--platform linux/${{ matrix.arch }}" pull-params: "--platform linux/${{ matrix.arch }}" - + continue-on-error: true + - name: create binary archive + uses: mosteo-actions/docker-run@v1 + with: + image: ghcr.io/mwilck/multipath-build-${{ matrix.os }} + guest-dir: /build + host-dir: ${{ github.workspace }} + command: test-progs.tar + params: "--platform linux/${{ matrix.arch }}" + pull-params: "--platform linux/${{ matrix.arch }}" + if: steps.test.outcome != 'success' + - name: upload binary archive + uses: actions/upload-artifact@v4 + with: + name: binaries-${{ matrix.os }}-${{ matrix.arch }} + path: test-progs.tar + if: steps.test.outcome != 'success' + - name: fail + run: /bin/false + if: steps.test.outcome != 'success' diff --git a/.github/workflows/native.yaml b/.github/workflows/native.yaml index 94e5ef22d..7baded415 100644 --- a/.github/workflows/native.yaml +++ b/.github/workflows/native.yaml @@ -157,7 +157,6 @@ jobs: continue-on-error: true - name: create ${{ env.ARCHIVE_TGT }} - if: ${{ matrix.os != 'debian-jessie' }} uses: mosteo-actions/docker-run@v1 with: image: ghcr.io/mwilck/multipath-build-${{ matrix.os }} @@ -168,7 +167,6 @@ jobs: ( matrix.os != 'debian-jessie' && steps.test.outcome != 'success' ) }} - name: create ${{ env.ARCHIVE_TGT }} (jessie) - if: ${{ matrix.os == 'debian-jessie' }} uses: mosteo-actions/docker-run@v1 with: image: ghcr.io/mwilck/multipath-build-${{ matrix.os }} From 82a739d65db55695725f1dc20e3944df2332231d Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Mon, 17 Nov 2025 15:05:47 +0100 Subject: [PATCH 12/42] GitHub workflows: use -j$(nproc) consistently The workflow files were using make's -j flag inconsistently. Fix it. Signed-off-by: Martin Wilck (cherry picked from commit f24aca35628371c25d92d14f8067b71972d16a00) --- .github/workflows/abi-stable.yaml | 4 ++-- .github/workflows/abi.yaml | 2 +- .github/workflows/build-and-unittest.yaml | 12 ++++++------ .github/workflows/coverity.yaml | 2 +- .github/workflows/foreign.yaml | 2 +- .github/workflows/native.yaml | 8 ++++---- .github/workflows/rolling.yaml | 2 +- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/abi-stable.yaml b/.github/workflows/abi-stable.yaml index 8b2c83a85..1ba9e7fa6 100644 --- a/.github/workflows/abi-stable.yaml +++ b/.github/workflows/abi-stable.yaml @@ -43,7 +43,7 @@ jobs: with: ref: ${{ env.PARENT_TAG }} - name: build ABI for ${{ env.PARENT_TAG }} - run: make -j$(grep -c ^processor /proc/cpuinfo) -Orecurse abi + run: make -j$(nproc) -Orecurse abi - name: save ABI uses: actions/upload-artifact@v4 with: @@ -88,7 +88,7 @@ jobs: libudev-dev libjson-c-dev liburcu-dev libcmocka-dev libedit-dev - name: check ABI of ${{ github.ref }} against ${{ env.PARENT_TAG }} id: check_abi - run: make -j$(grep -c ^processor /proc/cpuinfo) -Orecurse abi-test + run: make -j$(nproc) -Orecurse abi-test continue-on-error: true - name: save differences if: ${{ steps.check_abi.outcome != 'success' }} diff --git a/.github/workflows/abi.yaml b/.github/workflows/abi.yaml index 70ceb89df..adc2081f1 100644 --- a/.github/workflows/abi.yaml +++ b/.github/workflows/abi.yaml @@ -44,7 +44,7 @@ jobs: libudev-dev libjson-c-dev liburcu-dev libcmocka-dev libedit-dev libmount-dev - name: create ABI - run: make -Orecurse -j$(grep -c ^processor /proc/cpuinfo) abi.tar.gz + run: make -Orecurse -j$(nproc) abi.tar.gz - name: save ABI uses: actions/upload-artifact@v4 with: diff --git a/.github/workflows/build-and-unittest.yaml b/.github/workflows/build-and-unittest.yaml index a3ee7d8e7..2fb5327d4 100644 --- a/.github/workflows/build-and-unittest.yaml +++ b/.github/workflows/build-and-unittest.yaml @@ -46,16 +46,16 @@ jobs: if: ${{ matrix.cc == 'clang' }} - name: build run: > - make -Orecurse -j$(grep -c ^processor /proc/cpuinfo) + make -Orecurse -j$(nproc) READLINE=${{ matrix.rl }} OPTFLAGS="$OPT" - name: test run: > - make -Orecurse -j$(grep -c ^processor /proc/cpuinfo) + make -Orecurse -j$(nproc) OPTFLAGS="$OPT" test - name: valgrind-test id: valgrind run: > - make -Orecurse -j$(grep -c ^processor /proc/cpuinfo) + make -Orecurse -j$(nproc) OPTFLAGS="$OPT" valgrind-test continue-on-error: true - name: valgrind-results @@ -92,12 +92,12 @@ jobs: - name: set CC run: echo CC=${{ matrix.cc }} >> $GITHUB_ENV - name: build - run: make -Orecurse -j$(grep -c ^processor /proc/cpuinfo) READLINE=${{ matrix.rl }} + run: make -Orecurse -j$(nproc) READLINE=${{ matrix.rl }} - name: test - run: make -Orecurse -j$(grep -c ^processor /proc/cpuinfo) test + run: make -Orecurse -j$(nproc) test - name: valgrind-test id: valgrind - run: make -Orecurse -j$(grep -c ^processor /proc/cpuinfo) valgrind-test + run: make -Orecurse -j$(nproc) valgrind-test continue-on-error: true - name: valgrind-results run: cat tests/*.vgr diff --git a/.github/workflows/coverity.yaml b/.github/workflows/coverity.yaml index 3ade6771b..3c04c2124 100644 --- a/.github/workflows/coverity.yaml +++ b/.github/workflows/coverity.yaml @@ -32,7 +32,7 @@ jobs: - name: build with cov-build run: > PATH="$PWD/coverity/bin:$PATH" - cov-build --dir cov-int make -Orecurse -j"$(grep -c ^processor /proc/cpuinfo)" + cov-build --dir cov-int make -Orecurse -j"$(nproc)" - name: pack results run: tar cfz multipath-tools.tgz cov-int - name: submit results diff --git a/.github/workflows/foreign.yaml b/.github/workflows/foreign.yaml index 47affb7ac..b232b60c1 100644 --- a/.github/workflows/foreign.yaml +++ b/.github/workflows/foreign.yaml @@ -43,7 +43,7 @@ jobs: - name: checkout uses: actions/checkout@v4 - name: build - run: make -j -Orecurse test-progs.tar + run: make -j$(nproc) -Orecurse test-progs.tar - name: upload binary archive uses: actions/upload-artifact@v4 with: diff --git a/.github/workflows/native.yaml b/.github/workflows/native.yaml index 7baded415..9e89780b1 100644 --- a/.github/workflows/native.yaml +++ b/.github/workflows/native.yaml @@ -62,7 +62,7 @@ jobs: uses: mosteo-actions/docker-run@v1 with: image: ghcr.io/mwilck/multipath-build-${{ matrix.os }} - command: -j -Orecurse test + command: -j$(nproc) -Orecurse test continue-on-error: true - name: build and test (jessie) @@ -72,7 +72,7 @@ jobs: uses: mosteo-actions/docker-run@v1 with: image: ghcr.io/mwilck/multipath-build-${{ matrix.os }} - command: -j -Orecurse READLINE=libreadline test + command: -j$(nproc) -Orecurse READLINE=libreadline test continue-on-error: true - name: create ${{ env.ARCHIVE_TGT }} @@ -144,7 +144,7 @@ jobs: with: image: ghcr.io/mwilck/multipath-build-${{ matrix.os }} params: -e CC=clang - command: -j -Orecurse test + command: -j$(nproc) -Orecurse test continue-on-error: true - name: clang (jessie) id: test_jessie @@ -153,7 +153,7 @@ jobs: with: image: ghcr.io/mwilck/multipath-build-${{ matrix.os }} params: -e CC=clang - command: -j -Orecurse READLINE=libreadline test + command: -j$(nproc) -Orecurse READLINE=libreadline test continue-on-error: true - name: create ${{ env.ARCHIVE_TGT }} diff --git a/.github/workflows/rolling.yaml b/.github/workflows/rolling.yaml index 34efcff68..a4706e52e 100644 --- a/.github/workflows/rolling.yaml +++ b/.github/workflows/rolling.yaml @@ -62,7 +62,7 @@ jobs: uses: actions/checkout@v4 - name: build and test id: test - run: make CC=${{ matrix.compiler }} READLINE=libreadline -j -Orecurse test + run: make CC=${{ matrix.compiler }} READLINE=libreadline -j$(nproc) -Orecurse test continue-on-error: true - name: create binary archive run: make test-progs.tar From 547f94ef2f68d8e49c44b1f34103504e4dab2298 Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Mon, 17 Nov 2025 16:37:07 +0100 Subject: [PATCH 13/42] GitHub workflows: install libmount-dev on Ubuntu Without it, the workflows will fail. Signed-off-by: Martin Wilck (cherry picked from commit 2c872a7e4c56ac1550f2bba7c14a65df7bb0f9a9) --- .github/workflows/abi-stable.yaml | 2 ++ .github/workflows/coverity.yaml | 1 + 2 files changed, 3 insertions(+) diff --git a/.github/workflows/abi-stable.yaml b/.github/workflows/abi-stable.yaml index 1ba9e7fa6..8f9a9dbf3 100644 --- a/.github/workflows/abi-stable.yaml +++ b/.github/workflows/abi-stable.yaml @@ -38,6 +38,7 @@ jobs: gcc make pkg-config abigail-tools libdevmapper-dev libreadline-dev libaio-dev libsystemd-dev libudev-dev libjson-c-dev liburcu-dev libcmocka-dev libedit-dev + libmount-dev - name: checkout ${{ env.PARENT_TAG }} uses: actions/checkout@v4 with: @@ -86,6 +87,7 @@ jobs: gcc make pkg-config abigail-tools libdevmapper-dev libreadline-dev libaio-dev libsystemd-dev libudev-dev libjson-c-dev liburcu-dev libcmocka-dev libedit-dev + libmount-dev - name: check ABI of ${{ github.ref }} against ${{ env.PARENT_TAG }} id: check_abi run: make -j$(nproc) -Orecurse abi-test diff --git a/.github/workflows/coverity.yaml b/.github/workflows/coverity.yaml index 3c04c2124..30e5471d3 100644 --- a/.github/workflows/coverity.yaml +++ b/.github/workflows/coverity.yaml @@ -16,6 +16,7 @@ jobs: gcc make pkg-config libdevmapper-dev libreadline-dev libaio-dev libsystemd-dev libudev-dev libjson-c-dev liburcu-dev libcmocka-dev libedit-dev + libmount-dev - name: download coverity run: > curl -o cov-analysis-linux64.tar.gz From 83bd049c9c6ebe035ecff8a29d61767d84155842 Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Fri, 21 Nov 2025 12:16:52 +0100 Subject: [PATCH 14/42] libdmmp: update man page time stamps c78cf64 ("multipath-tools: replace FSF licences boilerplate with a SPDX-License-Identifier") updated libdmmp.h. This will cause the multipath build process to update it as well, even though the man page content doesn't change. Avoid that by updating the time stamps. Signed-off-by: Martin Wilck (cherry picked from commit 196b3d14682401e0b2e6aa5fbf34d03eb4bfac6e) --- libdmmp/docs/man/dmmp_context_free.3 | 2 +- libdmmp/docs/man/dmmp_context_log_func_set.3 | 2 +- libdmmp/docs/man/dmmp_context_log_priority_get.3 | 2 +- libdmmp/docs/man/dmmp_context_log_priority_set.3 | 2 +- libdmmp/docs/man/dmmp_context_new.3 | 2 +- libdmmp/docs/man/dmmp_context_timeout_get.3 | 2 +- libdmmp/docs/man/dmmp_context_timeout_set.3 | 2 +- libdmmp/docs/man/dmmp_context_userdata_get.3 | 2 +- libdmmp/docs/man/dmmp_context_userdata_set.3 | 2 +- libdmmp/docs/man/dmmp_flush_mpath.3 | 2 +- libdmmp/docs/man/dmmp_last_error_msg.3 | 2 +- libdmmp/docs/man/dmmp_log_priority_str.3 | 2 +- libdmmp/docs/man/dmmp_mpath_array_free.3 | 2 +- libdmmp/docs/man/dmmp_mpath_array_get.3 | 2 +- libdmmp/docs/man/dmmp_mpath_kdev_name_get.3 | 2 +- libdmmp/docs/man/dmmp_mpath_name_get.3 | 2 +- libdmmp/docs/man/dmmp_mpath_wwid_get.3 | 2 +- libdmmp/docs/man/dmmp_path_array_get.3 | 2 +- libdmmp/docs/man/dmmp_path_blk_name_get.3 | 2 +- libdmmp/docs/man/dmmp_path_group_array_get.3 | 2 +- libdmmp/docs/man/dmmp_path_group_id_get.3 | 2 +- libdmmp/docs/man/dmmp_path_group_priority_get.3 | 2 +- libdmmp/docs/man/dmmp_path_group_selector_get.3 | 2 +- libdmmp/docs/man/dmmp_path_group_status_get.3 | 2 +- libdmmp/docs/man/dmmp_path_group_status_str.3 | 2 +- libdmmp/docs/man/dmmp_path_status_get.3 | 2 +- libdmmp/docs/man/dmmp_path_status_str.3 | 2 +- libdmmp/docs/man/dmmp_reconfig.3 | 2 +- libdmmp/docs/man/dmmp_strerror.3 | 2 +- 29 files changed, 29 insertions(+), 29 deletions(-) diff --git a/libdmmp/docs/man/dmmp_context_free.3 b/libdmmp/docs/man/dmmp_context_free.3 index 2a9bbb10f..ce74cfb00 100644 --- a/libdmmp/docs/man/dmmp_context_free.3 +++ b/libdmmp/docs/man/dmmp_context_free.3 @@ -1,4 +1,4 @@ -.TH "dmmp_context_free" 3 "dmmp_context_free" "August 2024" "Device Mapper Multipath API - libdmmp Manual" +.TH "dmmp_context_free" 3 "dmmp_context_free" "June 2025" "Device Mapper Multipath API - libdmmp Manual" .SH NAME dmmp_context_free \- Release the memory of struct dmmp_context. .SH SYNOPSIS diff --git a/libdmmp/docs/man/dmmp_context_log_func_set.3 b/libdmmp/docs/man/dmmp_context_log_func_set.3 index f593eb57b..05b1cd0f1 100644 --- a/libdmmp/docs/man/dmmp_context_log_func_set.3 +++ b/libdmmp/docs/man/dmmp_context_log_func_set.3 @@ -1,4 +1,4 @@ -.TH "dmmp_context_log_func_set" 3 "dmmp_context_log_func_set" "August 2024" "Device Mapper Multipath API - libdmmp Manual" +.TH "dmmp_context_log_func_set" 3 "dmmp_context_log_func_set" "June 2025" "Device Mapper Multipath API - libdmmp Manual" .SH NAME dmmp_context_log_func_set \- Set log handler function. .SH SYNOPSIS diff --git a/libdmmp/docs/man/dmmp_context_log_priority_get.3 b/libdmmp/docs/man/dmmp_context_log_priority_get.3 index 6f7c3204f..62f671ff2 100644 --- a/libdmmp/docs/man/dmmp_context_log_priority_get.3 +++ b/libdmmp/docs/man/dmmp_context_log_priority_get.3 @@ -1,4 +1,4 @@ -.TH "dmmp_context_log_priority_get" 3 "dmmp_context_log_priority_get" "August 2024" "Device Mapper Multipath API - libdmmp Manual" +.TH "dmmp_context_log_priority_get" 3 "dmmp_context_log_priority_get" "June 2025" "Device Mapper Multipath API - libdmmp Manual" .SH NAME dmmp_context_log_priority_get \- Get log priority. .SH SYNOPSIS diff --git a/libdmmp/docs/man/dmmp_context_log_priority_set.3 b/libdmmp/docs/man/dmmp_context_log_priority_set.3 index c1ff3715e..991d5bf92 100644 --- a/libdmmp/docs/man/dmmp_context_log_priority_set.3 +++ b/libdmmp/docs/man/dmmp_context_log_priority_set.3 @@ -1,4 +1,4 @@ -.TH "dmmp_context_log_priority_set" 3 "dmmp_context_log_priority_set" "August 2024" "Device Mapper Multipath API - libdmmp Manual" +.TH "dmmp_context_log_priority_set" 3 "dmmp_context_log_priority_set" "June 2025" "Device Mapper Multipath API - libdmmp Manual" .SH NAME dmmp_context_log_priority_set \- Set log priority. .SH SYNOPSIS diff --git a/libdmmp/docs/man/dmmp_context_new.3 b/libdmmp/docs/man/dmmp_context_new.3 index 487ccde8c..25ce6ad9c 100644 --- a/libdmmp/docs/man/dmmp_context_new.3 +++ b/libdmmp/docs/man/dmmp_context_new.3 @@ -1,4 +1,4 @@ -.TH "dmmp_context_new" 3 "dmmp_context_new" "August 2024" "Device Mapper Multipath API - libdmmp Manual" +.TH "dmmp_context_new" 3 "dmmp_context_new" "June 2025" "Device Mapper Multipath API - libdmmp Manual" .SH NAME dmmp_context_new \- Create struct dmmp_context. .SH SYNOPSIS diff --git a/libdmmp/docs/man/dmmp_context_timeout_get.3 b/libdmmp/docs/man/dmmp_context_timeout_get.3 index b738fb97b..317b3f4c8 100644 --- a/libdmmp/docs/man/dmmp_context_timeout_get.3 +++ b/libdmmp/docs/man/dmmp_context_timeout_get.3 @@ -1,4 +1,4 @@ -.TH "dmmp_context_timeout_get" 3 "dmmp_context_timeout_get" "August 2024" "Device Mapper Multipath API - libdmmp Manual" +.TH "dmmp_context_timeout_get" 3 "dmmp_context_timeout_get" "June 2025" "Device Mapper Multipath API - libdmmp Manual" .SH NAME dmmp_context_timeout_get \- Get IPC timeout. .SH SYNOPSIS diff --git a/libdmmp/docs/man/dmmp_context_timeout_set.3 b/libdmmp/docs/man/dmmp_context_timeout_set.3 index af84be94d..9db1d2591 100644 --- a/libdmmp/docs/man/dmmp_context_timeout_set.3 +++ b/libdmmp/docs/man/dmmp_context_timeout_set.3 @@ -1,4 +1,4 @@ -.TH "dmmp_context_timeout_set" 3 "dmmp_context_timeout_set" "August 2024" "Device Mapper Multipath API - libdmmp Manual" +.TH "dmmp_context_timeout_set" 3 "dmmp_context_timeout_set" "June 2025" "Device Mapper Multipath API - libdmmp Manual" .SH NAME dmmp_context_timeout_set \- Set IPC timeout. .SH SYNOPSIS diff --git a/libdmmp/docs/man/dmmp_context_userdata_get.3 b/libdmmp/docs/man/dmmp_context_userdata_get.3 index 23e1da41d..ef5755e8e 100644 --- a/libdmmp/docs/man/dmmp_context_userdata_get.3 +++ b/libdmmp/docs/man/dmmp_context_userdata_get.3 @@ -1,4 +1,4 @@ -.TH "dmmp_context_userdata_get" 3 "dmmp_context_userdata_get" "August 2024" "Device Mapper Multipath API - libdmmp Manual" +.TH "dmmp_context_userdata_get" 3 "dmmp_context_userdata_get" "June 2025" "Device Mapper Multipath API - libdmmp Manual" .SH NAME dmmp_context_userdata_get \- Get user data pointer. .SH SYNOPSIS diff --git a/libdmmp/docs/man/dmmp_context_userdata_set.3 b/libdmmp/docs/man/dmmp_context_userdata_set.3 index 8a4a76561..cd21644a3 100644 --- a/libdmmp/docs/man/dmmp_context_userdata_set.3 +++ b/libdmmp/docs/man/dmmp_context_userdata_set.3 @@ -1,4 +1,4 @@ -.TH "dmmp_context_userdata_set" 3 "dmmp_context_userdata_set" "August 2024" "Device Mapper Multipath API - libdmmp Manual" +.TH "dmmp_context_userdata_set" 3 "dmmp_context_userdata_set" "June 2025" "Device Mapper Multipath API - libdmmp Manual" .SH NAME dmmp_context_userdata_set \- Set user data pointer. .SH SYNOPSIS diff --git a/libdmmp/docs/man/dmmp_flush_mpath.3 b/libdmmp/docs/man/dmmp_flush_mpath.3 index e5690edb2..f8cb83e8d 100644 --- a/libdmmp/docs/man/dmmp_flush_mpath.3 +++ b/libdmmp/docs/man/dmmp_flush_mpath.3 @@ -1,4 +1,4 @@ -.TH "dmmp_flush_mpath" 3 "dmmp_flush_mpath" "August 2024" "Device Mapper Multipath API - libdmmp Manual" +.TH "dmmp_flush_mpath" 3 "dmmp_flush_mpath" "June 2025" "Device Mapper Multipath API - libdmmp Manual" .SH NAME dmmp_flush_mpath \- Flush specified multipath device map if unused. .SH SYNOPSIS diff --git a/libdmmp/docs/man/dmmp_last_error_msg.3 b/libdmmp/docs/man/dmmp_last_error_msg.3 index 548e1a75a..7aa980bdf 100644 --- a/libdmmp/docs/man/dmmp_last_error_msg.3 +++ b/libdmmp/docs/man/dmmp_last_error_msg.3 @@ -1,4 +1,4 @@ -.TH "dmmp_last_error_msg" 3 "dmmp_last_error_msg" "August 2024" "Device Mapper Multipath API - libdmmp Manual" +.TH "dmmp_last_error_msg" 3 "dmmp_last_error_msg" "June 2025" "Device Mapper Multipath API - libdmmp Manual" .SH NAME dmmp_last_error_msg \- Retrieves the last error message. .SH SYNOPSIS diff --git a/libdmmp/docs/man/dmmp_log_priority_str.3 b/libdmmp/docs/man/dmmp_log_priority_str.3 index cf3155642..1252e17c8 100644 --- a/libdmmp/docs/man/dmmp_log_priority_str.3 +++ b/libdmmp/docs/man/dmmp_log_priority_str.3 @@ -1,4 +1,4 @@ -.TH "dmmp_log_priority_str" 3 "dmmp_log_priority_str" "August 2024" "Device Mapper Multipath API - libdmmp Manual" +.TH "dmmp_log_priority_str" 3 "dmmp_log_priority_str" "June 2025" "Device Mapper Multipath API - libdmmp Manual" .SH NAME dmmp_log_priority_str \- Convert log priority to string. .SH SYNOPSIS diff --git a/libdmmp/docs/man/dmmp_mpath_array_free.3 b/libdmmp/docs/man/dmmp_mpath_array_free.3 index 8d2090e64..2a1f1aee8 100644 --- a/libdmmp/docs/man/dmmp_mpath_array_free.3 +++ b/libdmmp/docs/man/dmmp_mpath_array_free.3 @@ -1,4 +1,4 @@ -.TH "dmmp_mpath_array_free" 3 "dmmp_mpath_array_free" "August 2024" "Device Mapper Multipath API - libdmmp Manual" +.TH "dmmp_mpath_array_free" 3 "dmmp_mpath_array_free" "June 2025" "Device Mapper Multipath API - libdmmp Manual" .SH NAME dmmp_mpath_array_free \- Free 'struct dmmp_mpath' pointer array. .SH SYNOPSIS diff --git a/libdmmp/docs/man/dmmp_mpath_array_get.3 b/libdmmp/docs/man/dmmp_mpath_array_get.3 index 4191571ee..2bb7b186e 100644 --- a/libdmmp/docs/man/dmmp_mpath_array_get.3 +++ b/libdmmp/docs/man/dmmp_mpath_array_get.3 @@ -1,4 +1,4 @@ -.TH "dmmp_mpath_array_get" 3 "dmmp_mpath_array_get" "August 2024" "Device Mapper Multipath API - libdmmp Manual" +.TH "dmmp_mpath_array_get" 3 "dmmp_mpath_array_get" "June 2025" "Device Mapper Multipath API - libdmmp Manual" .SH NAME dmmp_mpath_array_get \- Query all existing multipath devices. .SH SYNOPSIS diff --git a/libdmmp/docs/man/dmmp_mpath_kdev_name_get.3 b/libdmmp/docs/man/dmmp_mpath_kdev_name_get.3 index 261bea6a9..f368cc294 100644 --- a/libdmmp/docs/man/dmmp_mpath_kdev_name_get.3 +++ b/libdmmp/docs/man/dmmp_mpath_kdev_name_get.3 @@ -1,4 +1,4 @@ -.TH "dmmp_mpath_kdev_name_get" 3 "dmmp_mpath_kdev_name_get" "August 2024" "Device Mapper Multipath API - libdmmp Manual" +.TH "dmmp_mpath_kdev_name_get" 3 "dmmp_mpath_kdev_name_get" "June 2025" "Device Mapper Multipath API - libdmmp Manual" .SH NAME dmmp_mpath_kdev_name_get \- Retrieve kernel DEVNAME of certain mpath. .SH SYNOPSIS diff --git a/libdmmp/docs/man/dmmp_mpath_name_get.3 b/libdmmp/docs/man/dmmp_mpath_name_get.3 index 894d318f8..20cc09b6d 100644 --- a/libdmmp/docs/man/dmmp_mpath_name_get.3 +++ b/libdmmp/docs/man/dmmp_mpath_name_get.3 @@ -1,4 +1,4 @@ -.TH "dmmp_mpath_name_get" 3 "dmmp_mpath_name_get" "August 2024" "Device Mapper Multipath API - libdmmp Manual" +.TH "dmmp_mpath_name_get" 3 "dmmp_mpath_name_get" "June 2025" "Device Mapper Multipath API - libdmmp Manual" .SH NAME dmmp_mpath_name_get \- Retrieve name(alias) of certain mpath. .SH SYNOPSIS diff --git a/libdmmp/docs/man/dmmp_mpath_wwid_get.3 b/libdmmp/docs/man/dmmp_mpath_wwid_get.3 index e6afcb1a8..09c79aa6a 100644 --- a/libdmmp/docs/man/dmmp_mpath_wwid_get.3 +++ b/libdmmp/docs/man/dmmp_mpath_wwid_get.3 @@ -1,4 +1,4 @@ -.TH "dmmp_mpath_wwid_get" 3 "dmmp_mpath_wwid_get" "August 2024" "Device Mapper Multipath API - libdmmp Manual" +.TH "dmmp_mpath_wwid_get" 3 "dmmp_mpath_wwid_get" "June 2025" "Device Mapper Multipath API - libdmmp Manual" .SH NAME dmmp_mpath_wwid_get \- Retrieve WWID of certain mpath. .SH SYNOPSIS diff --git a/libdmmp/docs/man/dmmp_path_array_get.3 b/libdmmp/docs/man/dmmp_path_array_get.3 index de29c9d1e..7bd19e709 100644 --- a/libdmmp/docs/man/dmmp_path_array_get.3 +++ b/libdmmp/docs/man/dmmp_path_array_get.3 @@ -1,4 +1,4 @@ -.TH "dmmp_path_array_get" 3 "dmmp_path_array_get" "August 2024" "Device Mapper Multipath API - libdmmp Manual" +.TH "dmmp_path_array_get" 3 "dmmp_path_array_get" "June 2025" "Device Mapper Multipath API - libdmmp Manual" .SH NAME dmmp_path_array_get \- Retrieve path pointer array. .SH SYNOPSIS diff --git a/libdmmp/docs/man/dmmp_path_blk_name_get.3 b/libdmmp/docs/man/dmmp_path_blk_name_get.3 index 167e81c31..984ae9d4c 100644 --- a/libdmmp/docs/man/dmmp_path_blk_name_get.3 +++ b/libdmmp/docs/man/dmmp_path_blk_name_get.3 @@ -1,4 +1,4 @@ -.TH "dmmp_path_blk_name_get" 3 "dmmp_path_blk_name_get" "August 2024" "Device Mapper Multipath API - libdmmp Manual" +.TH "dmmp_path_blk_name_get" 3 "dmmp_path_blk_name_get" "June 2025" "Device Mapper Multipath API - libdmmp Manual" .SH NAME dmmp_path_blk_name_get \- Retrieve block name. .SH SYNOPSIS diff --git a/libdmmp/docs/man/dmmp_path_group_array_get.3 b/libdmmp/docs/man/dmmp_path_group_array_get.3 index b9b663f67..7faa89c90 100644 --- a/libdmmp/docs/man/dmmp_path_group_array_get.3 +++ b/libdmmp/docs/man/dmmp_path_group_array_get.3 @@ -1,4 +1,4 @@ -.TH "dmmp_path_group_array_get" 3 "dmmp_path_group_array_get" "August 2024" "Device Mapper Multipath API - libdmmp Manual" +.TH "dmmp_path_group_array_get" 3 "dmmp_path_group_array_get" "June 2025" "Device Mapper Multipath API - libdmmp Manual" .SH NAME dmmp_path_group_array_get \- Retrieve path groups pointer array. .SH SYNOPSIS diff --git a/libdmmp/docs/man/dmmp_path_group_id_get.3 b/libdmmp/docs/man/dmmp_path_group_id_get.3 index 67ba5c00e..fb3cea644 100644 --- a/libdmmp/docs/man/dmmp_path_group_id_get.3 +++ b/libdmmp/docs/man/dmmp_path_group_id_get.3 @@ -1,4 +1,4 @@ -.TH "dmmp_path_group_id_get" 3 "dmmp_path_group_id_get" "August 2024" "Device Mapper Multipath API - libdmmp Manual" +.TH "dmmp_path_group_id_get" 3 "dmmp_path_group_id_get" "June 2025" "Device Mapper Multipath API - libdmmp Manual" .SH NAME dmmp_path_group_id_get \- Retrieve path group ID. .SH SYNOPSIS diff --git a/libdmmp/docs/man/dmmp_path_group_priority_get.3 b/libdmmp/docs/man/dmmp_path_group_priority_get.3 index 09cbea9c5..ae8a08aa5 100644 --- a/libdmmp/docs/man/dmmp_path_group_priority_get.3 +++ b/libdmmp/docs/man/dmmp_path_group_priority_get.3 @@ -1,4 +1,4 @@ -.TH "dmmp_path_group_priority_get" 3 "dmmp_path_group_priority_get" "August 2024" "Device Mapper Multipath API - libdmmp Manual" +.TH "dmmp_path_group_priority_get" 3 "dmmp_path_group_priority_get" "June 2025" "Device Mapper Multipath API - libdmmp Manual" .SH NAME dmmp_path_group_priority_get \- Retrieve path group priority. .SH SYNOPSIS diff --git a/libdmmp/docs/man/dmmp_path_group_selector_get.3 b/libdmmp/docs/man/dmmp_path_group_selector_get.3 index dc73fa82e..8fae07360 100644 --- a/libdmmp/docs/man/dmmp_path_group_selector_get.3 +++ b/libdmmp/docs/man/dmmp_path_group_selector_get.3 @@ -1,4 +1,4 @@ -.TH "dmmp_path_group_selector_get" 3 "dmmp_path_group_selector_get" "August 2024" "Device Mapper Multipath API - libdmmp Manual" +.TH "dmmp_path_group_selector_get" 3 "dmmp_path_group_selector_get" "June 2025" "Device Mapper Multipath API - libdmmp Manual" .SH NAME dmmp_path_group_selector_get \- Retrieve path group selector. .SH SYNOPSIS diff --git a/libdmmp/docs/man/dmmp_path_group_status_get.3 b/libdmmp/docs/man/dmmp_path_group_status_get.3 index a7662b634..6adfeba65 100644 --- a/libdmmp/docs/man/dmmp_path_group_status_get.3 +++ b/libdmmp/docs/man/dmmp_path_group_status_get.3 @@ -1,4 +1,4 @@ -.TH "dmmp_path_group_status_get" 3 "dmmp_path_group_status_get" "August 2024" "Device Mapper Multipath API - libdmmp Manual" +.TH "dmmp_path_group_status_get" 3 "dmmp_path_group_status_get" "June 2025" "Device Mapper Multipath API - libdmmp Manual" .SH NAME dmmp_path_group_status_get \- Retrieve path group status. .SH SYNOPSIS diff --git a/libdmmp/docs/man/dmmp_path_group_status_str.3 b/libdmmp/docs/man/dmmp_path_group_status_str.3 index 160c8a7ed..a2d654348 100644 --- a/libdmmp/docs/man/dmmp_path_group_status_str.3 +++ b/libdmmp/docs/man/dmmp_path_group_status_str.3 @@ -1,4 +1,4 @@ -.TH "dmmp_path_group_status_str" 3 "dmmp_path_group_status_str" "August 2024" "Device Mapper Multipath API - libdmmp Manual" +.TH "dmmp_path_group_status_str" 3 "dmmp_path_group_status_str" "June 2025" "Device Mapper Multipath API - libdmmp Manual" .SH NAME dmmp_path_group_status_str \- Convert path group status to string. .SH SYNOPSIS diff --git a/libdmmp/docs/man/dmmp_path_status_get.3 b/libdmmp/docs/man/dmmp_path_status_get.3 index 92e64331b..33d103f70 100644 --- a/libdmmp/docs/man/dmmp_path_status_get.3 +++ b/libdmmp/docs/man/dmmp_path_status_get.3 @@ -1,4 +1,4 @@ -.TH "dmmp_path_status_get" 3 "dmmp_path_status_get" "August 2024" "Device Mapper Multipath API - libdmmp Manual" +.TH "dmmp_path_status_get" 3 "dmmp_path_status_get" "June 2025" "Device Mapper Multipath API - libdmmp Manual" .SH NAME dmmp_path_status_get \- Retrieve the path status. .SH SYNOPSIS diff --git a/libdmmp/docs/man/dmmp_path_status_str.3 b/libdmmp/docs/man/dmmp_path_status_str.3 index 456cf24e2..e69c8be69 100644 --- a/libdmmp/docs/man/dmmp_path_status_str.3 +++ b/libdmmp/docs/man/dmmp_path_status_str.3 @@ -1,4 +1,4 @@ -.TH "dmmp_path_status_str" 3 "dmmp_path_status_str" "August 2024" "Device Mapper Multipath API - libdmmp Manual" +.TH "dmmp_path_status_str" 3 "dmmp_path_status_str" "June 2025" "Device Mapper Multipath API - libdmmp Manual" .SH NAME dmmp_path_status_str \- Convert path status to string. .SH SYNOPSIS diff --git a/libdmmp/docs/man/dmmp_reconfig.3 b/libdmmp/docs/man/dmmp_reconfig.3 index 413a3e6fc..b17c2d689 100644 --- a/libdmmp/docs/man/dmmp_reconfig.3 +++ b/libdmmp/docs/man/dmmp_reconfig.3 @@ -1,4 +1,4 @@ -.TH "dmmp_reconfig" 3 "dmmp_reconfig" "August 2024" "Device Mapper Multipath API - libdmmp Manual" +.TH "dmmp_reconfig" 3 "dmmp_reconfig" "June 2025" "Device Mapper Multipath API - libdmmp Manual" .SH NAME dmmp_reconfig \- Instruct multipathd daemon to do reconfiguration. .SH SYNOPSIS diff --git a/libdmmp/docs/man/dmmp_strerror.3 b/libdmmp/docs/man/dmmp_strerror.3 index 202941c9c..c1f80d315 100644 --- a/libdmmp/docs/man/dmmp_strerror.3 +++ b/libdmmp/docs/man/dmmp_strerror.3 @@ -1,4 +1,4 @@ -.TH "dmmp_strerror" 3 "dmmp_strerror" "August 2024" "Device Mapper Multipath API - libdmmp Manual" +.TH "dmmp_strerror" 3 "dmmp_strerror" "June 2025" "Device Mapper Multipath API - libdmmp Manual" .SH NAME dmmp_strerror \- Convert error code to string. .SH SYNOPSIS From 3beaa90cf7c0c4a945f9c6af8f8ad2f9b364a6ba Mon Sep 17 00:00:00 2001 From: Xose Vazquez Perez Date: Sat, 15 Nov 2025 15:50:10 +0100 Subject: [PATCH 15/42] multipath-tools: add Seagate Exos and Nytro series to hwtable Config from, #102: https://www.seagate.com/content/dam/seagate/migrated-assets/www-content/support-content/raid-storage-systems/corvault/_shared/files/205042000-01-B_CORVAULT_SMG.pdf Cc: Martin Wilck Cc: Benjamin Marzinski Cc: Christophe Varoqui Cc: DM_DEVEL-ML Signed-off-by: Xose Vazquez Perez Reviewed-by: Martin Wilck (cherry picked from commit 9889faee3ad2453a3976caaec50646aea1f4a798) --- libmultipath/hwtable.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/libmultipath/hwtable.c b/libmultipath/hwtable.c index 925230422..2734b78ea 100644 --- a/libmultipath/hwtable.c +++ b/libmultipath/hwtable.c @@ -1326,6 +1326,15 @@ static struct hwentry default_hw[] = { .prio_name = PRIO_ALUA, .no_path_retry = 30, }, + { + // Exos / Nytro series + .vendor = "SEAGATE", + .product = "^[456]", + .pgpolicy = GROUP_BY_PRIO, + .pgfailback = -FAILBACK_IMMEDIATE, + .prio_name = PRIO_ALUA, + .no_path_retry = 30, + }, /* * AccelStor */ From c3cc3a9c9d3708420c15230ff675a8b98a0d1d72 Mon Sep 17 00:00:00 2001 From: Xose Vazquez Perez Date: Sun, 16 Nov 2025 15:20:19 +0100 Subject: [PATCH 16/42] multipath-tools: identify more Storwize models multipath is also supported by V3500 and V3700 Cc: Martin Wilck Cc: Benjamin Marzinski Cc: Christophe Varoqui Cc: DM_DEVEL-ML Signed-off-by: Xose Vazquez Perez Reviewed-by: Martin Wilck (cherry picked from commit 5bdafa5f299a34fa418b24bb9c4f24f3c495b564) --- libmultipath/hwtable.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmultipath/hwtable.c b/libmultipath/hwtable.c index 2734b78ea..23c549335 100644 --- a/libmultipath/hwtable.c +++ b/libmultipath/hwtable.c @@ -682,7 +682,7 @@ static struct hwentry default_hw[] = { .pgfailback = -FAILBACK_IMMEDIATE, }, { - // Storwize V5000/V7000 lines / SAN Volume Controller (SVC) + // Storwize V3x00/V5000/V7000 lines / SAN Volume Controller (SVC) // Flex System V7000 / FlashSystem V840/V9000 and 5x00/7x00/9x00/Cx00 .vendor = "IBM", .product = "^2145", From 2643e57cdf2390975395d8e9a69204ad85b82449 Mon Sep 17 00:00:00 2001 From: Itxaka Date: Fri, 5 Dec 2025 09:28:06 +0100 Subject: [PATCH 17/42] multipathd: Dont pthread_join twice Currently it seems that urcu would already call pthread_join when calling call_rcu_data_free since a couple of years ago (since version v0.14.0)[0] so calling pthread_join on the just released one is problematic under musl systems. It seems like under glibc this has several checks in place before trying to dereference the thread but under musl it has nothing in place to validate so this causes a coredump on program shutdown. This is currently present in all version when compiled under musl, running multipathd -d and sending a SIGTERM to it, you can see the coredump happening at this point in the code. The patch runs only the old behaviour in urcu older than 0.14.0 to maintain the same bahaviour. In higher versions its not neccesary so we skip it. [0] https://github.com/urcu/userspace-rcu/commit/1cf55ba47342156cdf25335264b9774a16e0bb2d Signed-off-by: Itxaka Reviewed-by: Martin Wilck (cherry picked from commit 5835dca56c7fe0b06aad99183de4e8e179e3c56b) --- multipathd/main.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/multipathd/main.c b/multipathd/main.c index 4c86f31ee..989888261 100644 --- a/multipathd/main.c +++ b/multipathd/main.c @@ -3749,18 +3749,21 @@ static struct call_rcu_data *mp_rcu_data; static void cleanup_rcu(void) { - pthread_t rcu_thread; - /* Wait for any pending RCU calls */ rcu_barrier(); if (mp_rcu_data != NULL) { +#if (URCU_VERSION < 0x000E00) + pthread_t rcu_thread; rcu_thread = get_call_rcu_thread(mp_rcu_data); +#endif /* detach this thread from the RCU thread */ set_thread_call_rcu_data(NULL); synchronize_rcu(); /* tell RCU thread to exit */ call_rcu_data_free(mp_rcu_data); +#if (URCU_VERSION < 0x000E00) pthread_join(rcu_thread, NULL); +#endif } rcu_unregister_thread(); } From 8408e0c0d040f6db7282e23f5fe55c54ca7b6551 Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Fri, 21 Nov 2025 13:09:57 +0100 Subject: [PATCH 18/42] GitHub actions: spelling: ignore generic hex number patterns Fix the spelling CI complaints about "0xea01". Signed-off-by: Martin Wilck --- .github/actions/spelling/patterns.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/actions/spelling/patterns.txt b/.github/actions/spelling/patterns.txt index f2ef14240..55d4742eb 100644 --- a/.github/actions/spelling/patterns.txt +++ b/.github/actions/spelling/patterns.txt @@ -10,6 +10,11 @@ #commit \b[0-9a-f]{7}\b +# Generic Hex numbers +\b0x[0-9a-f]{4}\b +\b0x[0-9a-f]{8}\b +\b0x[0-9a-f]{16}\b + # WWNN/WWPN (NAA identifiers) \b(?:0x)?10[0-9a-f]{14}\b \b(?:0x|3)?[25][0-9a-f]{15}\b From 747323e84107ca60c760461ef5cbfb433ea745ff Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Mon, 1 Dec 2025 22:02:10 -0500 Subject: [PATCH 19/42] libmpathpersist: fix register retry status checking If there libmpathpersist failed to create a thread to retry the register and ignore command, mpath_prout_reg should fail. Instead, the code was simply ignoring the failed threads. Fix that. Fixes: 2a4ca250 ("libmpathpersist: change how reservation conflicts are handled") Signed-off-by: Benjamin Marzinski Reviewed-by: Martin Wilck (cherry picked from commit c971036761a2d11bf011c0aa499927edfd0207bc) --- libmpathpersist/mpath_persist_int.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c index ea8d65ea1..91c534190 100644 --- a/libmpathpersist/mpath_persist_int.c +++ b/libmpathpersist/mpath_persist_int.c @@ -536,19 +536,19 @@ static int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope, } } for (i = 0; i < count; i++) { - if (thread[i].param.status != MPATH_PR_SKIP && - thread[i].param.status != MPATH_PR_THREAD_ERROR) { + if (thread[i].param.status == MPATH_PR_SKIP) + continue; + if (thread[i].param.status != MPATH_PR_THREAD_ERROR) { rc = pthread_join(thread[i].id, NULL); if (rc) { condlog(3, "%s: failed to join thread while retrying %d", mpp->wwid, i); } - if (thread[i].param.status == - MPATH_PR_RETRYABLE_ERROR) - retryable_error = true; - else if (status == MPATH_PR_SUCCESS) - status = thread[i].param.status; } + if (thread[i].param.status == MPATH_PR_RETRYABLE_ERROR) + retryable_error = true; + else if (status == MPATH_PR_SUCCESS) + status = thread[i].param.status; } need_retry = false; } From d57251befe978ca99c2171538856bcd97d9d0fc6 Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Mon, 1 Dec 2025 22:02:11 -0500 Subject: [PATCH 20/42] multipath-tools man pages: fix multipathd commands keyword ordering multipathd now has a fixed ordering of the keywords. Specifically, verbs must come first. Fix the man page to reflect the ordering. Fixes: f812466f6 ("multipathd: more robust command parsing") Signed-off-by: Benjamin Marzinski Reviewed-by: Martin Wilck (cherry picked from commit f3ba2e719567d5f21076e90aea9ba10b04004abd) --- multipathd/multipathd.8.in | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/multipathd/multipathd.8.in b/multipathd/multipathd.8.in index 8815e099f..7ffb8d4c4 100644 --- a/multipathd/multipathd.8.in +++ b/multipathd/multipathd.8.in @@ -344,48 +344,48 @@ will not be disabled when the daemon stops. Restores configured queue_without_daemon mode. . .TP -.B map|multipath $map setprstatus +.B setprstatus map|multipath $map Enable persistent reservation management on $map. . .TP -.B map|multipath $map unsetprstatus +.B unsetprstatus map|multipath $map Disable persistent reservation management on $map. . .TP -.B map|multipath $map getprstatus +.B getprstatus map|multipath $map Get the current persistent reservation management status of $map. . .TP -.B map|multipath $map getprkey +.B getprkey map|multipath $map Get the current persistent reservation key associated with $map. . .TP -.B map|multipath $map setprkey key $key +.B setprkey map|multipath $map key $key Set the persistent reservation key associated with $map to $key in the \fIprkeys_file\fR. This key will only be used by multipathd if \fIreservation_key\fR is set to \fBfile\fR in \fI@CONFIGFILE@\fR. . .TP -.B map|multipath $map unsetprkey +.B unsetprkey map|multipath $map Remove the persistent reservation key associated with $map from the \fIprkeys_file\fR. This will only unset the key used by multipathd if \fIreservation_key\fR is set to \fBfile\fR in \fI@CONFIGFILE@\fR. . .TP -.B path $path setmarginal +.B setmarginal path $path move $path to a marginal pathgroup. The path will remain in the marginal path group until \fIunsetmarginal\fR is called. This command will only work if \fImarginal_pathgroups\fR is enabled and there is no Shaky paths detection method configured (see the multipath.conf man page for details). . .TP -.B path $path unsetmarginal +.B unsetmarginal path $path return marginal path $path to its normal pathgroup. This command will only work if \fImarginal_pathgroups\fR is enabled and there is no Shaky paths detection method configured (see the multipath.conf man page for details). . .TP -.B map $map unsetmarginal +.B unsetmarginal map $map return all marginal paths in $map to their normal pathgroups. This command will only work if \fImarginal_pathgroups\fR is enabled and there is no Shaky paths detection method configured (see the multipath.conf man page for details). From 114c923cf39d60cecdb9f1b11b3a503de116d17b Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Mon, 1 Dec 2025 22:02:12 -0500 Subject: [PATCH 21/42] multipathd: remember number of registered keys when ioctl fails If prin_do_scsi_ioctl() fails in update_map_pr() for some reason other than Persistent Reservations not being supported, It shouldn't clear the number of registered keys, since there's no reason to think that it has changed. Similarly, if update_map_pr() fails in mpath_pr_event_handle(), don't assume that the nr_keys_needed was cleared. Just return whatever the value is now. This saves multipathd from doing pointless calls to update_map_pr(), if one of the paths is failing. Signed-off-by: Benjamin Marzinski Reviewed-by: Martin Wilck (cherry picked from commit c46a4f2c5e54ba5c4cf6abf4920bd65b1e8feb0d) --- multipathd/main.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/multipathd/main.c b/multipathd/main.c index 989888261..567a75489 100644 --- a/multipathd/main.c +++ b/multipathd/main.c @@ -4281,7 +4281,9 @@ void unset_pr(struct multipath *mpp) * The number of found keys must be at least as large as *nr_keys, * and if MPATH_PR_SUCCESS is returned and mpp->prflag is PR_SET after * the call, *nr_keys will be set to the number of found keys. Otherwise - * it will be set to 0. + * if mpp->prflag is PR_UNSET it will be set to 0. If MPATH_PR_SUCCESS + * is not returned and mpp->prflag is not PR_UNSET, nr_keys will not be + * changed. */ static int update_map_pr(struct multipath *mpp, struct path *pp, unsigned int *nr_keys) { @@ -4310,11 +4312,12 @@ static int update_map_pr(struct multipath *mpp, struct path *pp, unsigned int *n ret = prin_do_scsi_ioctl(pp->dev, MPATH_PRIN_RKEY_SA, &resp, 0); if (ret != MPATH_PR_SUCCESS) { - if (ret == MPATH_PR_ILLEGAL_REQ) + if (ret == MPATH_PR_ILLEGAL_REQ) { unset_pr(mpp); + *nr_keys = 0; + } condlog(0, "%s : pr in read keys service action failed Error=%d", mpp->alias, ret); - *nr_keys = 0; return ret; } @@ -4430,7 +4433,7 @@ mpath_pr_event_handle(struct path *pp, unsigned int nr_keys_needed, clear_reg ? "Clearing" : "Setting", pp->dev, ret); } else if (!clear_reg) { if (update_map_pr(mpp, pp, &nr_keys_needed) != MPATH_PR_SUCCESS) - return 0; + return nr_keys_needed; if (mpp->prflag != PR_SET) { memset(¶m, 0, sizeof(param)); clear_reg = true; From 824f8e8df0a0e71b1e11736d369fbb3268e8360c Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Mon, 15 Dec 2025 15:29:58 -0500 Subject: [PATCH 22/42] libmpathpersist: fix code for skipping multipathd path registration When libmpathpersist notifies multipathd that a key has been registered, cli_setprstatus() calls pr_register_active_paths() with a flag to let it know that the paths are likely already registered, and it can skip re-registering them, as long as the number of active paths matches the number of registered keys. This shortcut can fail, causing multipathd to not register needed paths, if either a path becomes usable and another becomes unusable while libmpathpersist is running or if there already were registered keys for I_T Nexus's that don't correspond to path devices. To make this shortcut work in cases like that, this commit adds a new multipathd command "setprstatus map pathlist ", where is a quoted, whitespace separated list of scsi path devices. libmpathpersist will send out the list of paths it registered the key on. pr_register_active_paths() will skip calling mpath_pr_event_handle() for paths on that list. In order to deal with the possiblity of a preempt occuring while libmpathpersist was running, the code still needs to check that it has the expected number of keys. Fixes: f7d6cd17 ("multipathd: Fix race while registering PR key") Signed-off-by: Benjamin Marzinski Reviewed-by: Martin Wilck (cherry picked from commit 4f3036bae8ff25889d07ec1fc7d5f047f0078622) --- .github/actions/spelling/expect.txt | 1 + libmpathpersist/mpath_persist_int.c | 6 +-- libmpathpersist/mpath_updatepr.c | 47 +++++++++++++++++----- libmpathpersist/mpathpr.h | 4 +- multipathd/callbacks.c | 2 + multipathd/cli.c | 1 + multipathd/cli.h | 2 + multipathd/cli_handlers.c | 35 ++++++++++++++-- multipathd/main.c | 62 +++++++++++++++++++---------- multipathd/main.h | 4 +- multipathd/multipathd.8.in | 6 +++ 11 files changed, 129 insertions(+), 41 deletions(-) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index a5856bcc8..a3e38d8d1 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -157,6 +157,7 @@ OPTFLAGS paramp partx pathgroup +pathlist petabytes pgpolicy plugindir diff --git a/libmpathpersist/mpath_persist_int.c b/libmpathpersist/mpath_persist_int.c index 91c534190..14f7ba830 100644 --- a/libmpathpersist/mpath_persist_int.c +++ b/libmpathpersist/mpath_persist_int.c @@ -1001,12 +1001,12 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd, case MPATH_PROUT_REG_SA: case MPATH_PROUT_REG_IGN_SA: if (unregistering) - update_prflag(mpp->alias, 0); + update_prflag(mpp, 0); else - update_prflag(mpp->alias, 1); + update_prflag(mpp, 1); break; case MPATH_PROUT_CLEAR_SA: - update_prflag(mpp->alias, 0); + update_prflag(mpp, 0); if (mpp->prkey_source == PRKEY_SOURCE_FILE) update_prkey(mpp->alias, 0); break; diff --git a/libmpathpersist/mpath_updatepr.c b/libmpathpersist/mpath_updatepr.c index bd8ed2be9..c925dcedf 100644 --- a/libmpathpersist/mpath_updatepr.c +++ b/libmpathpersist/mpath_updatepr.c @@ -20,8 +20,9 @@ #include "uxsock.h" #include "mpathpr.h" #include "structs.h" +#include "strbuf.h" -static char *do_pr(char *alias, char *str) +static char *do_pr(char *alias, const char *str) { int fd; char *reply; @@ -51,24 +52,26 @@ static char *do_pr(char *alias, char *str) return reply; } -static int do_update_pr(char *alias, char *cmd, char *key) +static int do_update_pr(char *alias, char *cmd, const char *data) { - char str[256]; + STRBUF_ON_STACK(buf); char *reply = NULL; int ret = -1; - if (key) - snprintf(str, sizeof(str), "%s map %s key %s", cmd, alias, key); + if (data) + print_strbuf(&buf, "%s map %s %s %s", cmd, alias, + strcmp(cmd, "setprkey") ? "pathlist" : "key", data); else - snprintf(str, sizeof(str), "%s map %s", cmd, alias); + print_strbuf(&buf, "%s map %s", cmd, alias); - reply = do_pr(alias, str); + reply = do_pr(alias, get_strbuf_str(&buf)); if (reply) { if (strncmp(reply, "ok", 2) == 0) ret = 0; else ret = -1; - condlog(ret ? 0 : 4, "%s: message=%s reply=%s", alias, str, reply); + condlog(ret ? 0 : 4, "%s: message=%s reply=%s", alias, + get_strbuf_str(&buf), reply); } free(reply); @@ -106,9 +109,31 @@ int get_prhold(char *mapname) return do_get_pr(mapname, "getprhold"); } -int update_prflag(char *mapname, int set) { - return do_update_pr(mapname, (set)? "setprstatus" : "unsetprstatus", - NULL); +int update_prflag(struct multipath *mpp, int set) +{ + STRBUF_ON_STACK(buf); + int i, j; + bool first = true; + struct pathgroup *pgp = NULL; + struct path *pp = NULL; + + if (!set) + return do_update_pr(mpp->alias, "unsetprstatus", NULL); + + append_strbuf_str(&buf, "\""); + vector_foreach_slot (mpp->pg, pgp, j) { + vector_foreach_slot (pgp->paths, pp, i) { + if (pp->state == PATH_UP || pp->state == PATH_GHOST) { + if (first) { + append_strbuf_str(&buf, pp->dev); + first = false; + } else + print_strbuf(&buf, " %s", pp->dev_t); + } + } + } + append_strbuf_str(&buf, "\""); + return do_update_pr(mpp->alias, "setprstatus", get_strbuf_str(&buf)); } int update_prhold(char *mapname, bool set) diff --git a/libmpathpersist/mpathpr.h b/libmpathpersist/mpathpr.h index 99d6b82ff..adbfc8653 100644 --- a/libmpathpersist/mpathpr.h +++ b/libmpathpersist/mpathpr.h @@ -1,12 +1,14 @@ #ifndef MPATHPR_H_INCLUDED #define MPATHPR_H_INCLUDED +#include "structs.h" + /* * This header file contains symbols that are only used by * libmpathpersist internally. */ -int update_prflag(char *mapname, int set); +int update_prflag(struct multipath *mpp, int set); int update_prkey_flags(char *mapname, uint64_t prkey, uint8_t sa_flags); int get_prflag(char *mapname); int get_prhold(char *mapname); diff --git a/multipathd/callbacks.c b/multipathd/callbacks.c index b6b57f458..2027c3a66 100644 --- a/multipathd/callbacks.c +++ b/multipathd/callbacks.c @@ -59,6 +59,8 @@ void init_handler_callbacks(void) set_unlocked_handler_callback(VRB_SHUTDOWN, HANDLER(cli_shutdown)); set_handler_callback(VRB_GETPRSTATUS | Q1_MAP, HANDLER(cli_getprstatus)); set_handler_callback(VRB_SETPRSTATUS | Q1_MAP, HANDLER(cli_setprstatus)); + set_handler_callback(VRB_SETPRSTATUS | Q1_MAP | Q2_PATHLIST, + HANDLER(cli_setprstatus_list)); set_handler_callback(VRB_UNSETPRSTATUS | Q1_MAP, HANDLER(cli_unsetprstatus)); set_handler_callback(VRB_FORCEQ | Q1_DAEMON, HANDLER(cli_force_no_daemon_q)); set_handler_callback(VRB_RESTOREQ | Q1_DAEMON, HANDLER(cli_restore_no_daemon_q)); diff --git a/multipathd/cli.c b/multipathd/cli.c index d0e6cebc9..0d679c867 100644 --- a/multipathd/cli.c +++ b/multipathd/cli.c @@ -227,6 +227,7 @@ load_keys (void) r += add_key(keys, "getprhold", VRB_GETPRHOLD, 0); r += add_key(keys, "setprhold", VRB_SETPRHOLD, 0); r += add_key(keys, "unsetprhold", VRB_UNSETPRHOLD, 0); + r += add_key(keys, "pathlist", KEY_PATHLIST, 1); if (r) { free_keys(keys); diff --git a/multipathd/cli.h b/multipathd/cli.h index 5a943a455..3e607389a 100644 --- a/multipathd/cli.h +++ b/multipathd/cli.h @@ -62,6 +62,7 @@ enum { KEY_LOCAL = 81, KEY_GROUP = 82, KEY_KEY = 83, + KEY_PATHLIST = 84, }; /* @@ -94,6 +95,7 @@ enum { Q2_LOCAL = KEY_LOCAL << 16, Q2_GROUP = KEY_GROUP << 16, Q2_KEY = KEY_KEY << 16, + Q2_PATHLIST = KEY_PATHLIST << 16, /* byte 3: qualifier 3 */ Q3_FMT = KEY_FMT << 24, diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c index 2812d01eb..53be68df4 100644 --- a/multipathd/cli_handlers.c +++ b/multipathd/cli_handlers.c @@ -31,6 +31,7 @@ #include "foreign.h" #include "strbuf.h" #include "cli_handlers.h" +#include static struct path * find_path_by_str(const struct vector_s *pathvec, const char *str, @@ -1276,8 +1277,8 @@ cli_getprstatus (void * v, struct strbuf *reply, void * data) return 0; } -static int -cli_setprstatus(void * v, struct strbuf *reply, void * data) +static int do_setprstatus(void *v, struct strbuf *reply, void *data, + const struct vector_s *registered_paths) { struct multipath * mpp; struct vectors * vecs = (struct vectors *)data; @@ -1291,7 +1292,7 @@ cli_setprstatus(void * v, struct strbuf *reply, void * data) if (mpp->prflag != PR_SET) { set_pr(mpp); - pr_register_active_paths(mpp, true); + pr_register_active_paths(mpp, registered_paths); if (mpp->prflag == PR_SET) condlog(2, "%s: prflag set", param); else @@ -1302,6 +1303,34 @@ cli_setprstatus(void * v, struct strbuf *reply, void * data) return 0; } +static int cli_setprstatus(void *v, struct strbuf *reply, void *data) +{ + return do_setprstatus(v, reply, data, NULL); +} + +static int cli_setprstatus_list(void *v, struct strbuf *reply, void *data) +{ + int r; + struct vector_s registered_paths_vec = {.allocated = 0}; + vector registered_paths + __attribute__((cleanup(cleanup_reset_vec))) = ®istered_paths_vec; + char *ptr = get_keyparam(v, KEY_PATHLIST); + + while (isspace(*ptr)) + ptr++; + while (*ptr) { + if (!vector_alloc_slot(registered_paths)) + return -ENOMEM; + vector_set_slot(registered_paths, ptr); + while (*ptr && !isspace(*ptr)) + ptr++; + while (isspace(*ptr)) + *ptr++ = '\0'; + } + r = do_setprstatus(v, reply, data, registered_paths); + return r; +} + static int cli_unsetprstatus(void * v, struct strbuf *reply, void * data) { diff --git a/multipathd/main.c b/multipathd/main.c index 567a75489..d3bf4d036 100644 --- a/multipathd/main.c +++ b/multipathd/main.c @@ -630,28 +630,47 @@ flush_map_nopaths(struct multipath *mpp, struct vectors *vecs) { return true; } -void pr_register_active_paths(struct multipath *mpp, bool check_nr_active) +/* + * If reg_paths in non-NULL, it is a vector of paths that libmpathpersist + * registered. If the number of registered keys is smaller than the number + * of registered paths, then likely a preempt that occurred while + * libmpathpersist was registering the key. As long as there are still some + * registered keys, treat the preempt as happening first, and make sure to + * register keys on all the paths. If the number of registered keys is at + * least as large as the number of registered paths, then no preempt happened, + * and multipathd does not need to re-register the paths that libmpathpersist + * handled + */ +void pr_register_active_paths(struct multipath *mpp, const struct vector_s *reg_paths) { - unsigned int i, j, nr_keys = 0; - unsigned int nr_active = 0; + unsigned int i, j, k, nr_keys = 0; + unsigned int wanted_nr = VECTOR_SIZE(reg_paths); struct path *pp; struct pathgroup *pgp; - - if (check_nr_active) { - nr_active = count_active_paths(mpp); - if (!nr_active) - return; - } + char *pathname; vector_foreach_slot (mpp->pg, pgp, i) { vector_foreach_slot (pgp->paths, pp, j) { if (mpp->prflag == PR_UNSET) return; - if (pp->state == PATH_UP || pp->state == PATH_GHOST) { - nr_keys = mpath_pr_event_handle(pp, nr_keys, nr_active); - if (check_nr_active && nr_keys == nr_active) - return; + if (pp->state != PATH_UP && pp->state != PATH_GHOST) + continue; + if (wanted_nr && nr_keys) { + vector_foreach_slot (reg_paths, pathname, k) { + if (strcmp(pp->dev_t, pathname) == 0) { + goto skip; + } + } } + nr_keys = mpath_pr_event_handle(pp, nr_keys, wanted_nr); + if (nr_keys && nr_keys < wanted_nr) { + /* + * Incorrect number of registered keys. Need + * to register all devices + */ + wanted_nr = 0; + } + skip:; /* a statement must follow a label on pre C23 clang */ } } } @@ -682,8 +701,7 @@ handle_orphaned_offline_paths(vector offline_paths) pp->add_when_online = true; } -static void -cleanup_reset_vec(struct vector_s **v) +void cleanup_reset_vec(struct vector_s **v) { vector_reset(*v); } @@ -739,7 +757,7 @@ update_map (struct multipath *mpp, struct vectors *vecs, int new_map) sync_map_state(mpp, false); - pr_register_active_paths(mpp, false); + pr_register_active_paths(mpp, NULL); if (VECTOR_SIZE(offline_paths) != 0) handle_orphaned_offline_paths(offline_paths); @@ -1413,7 +1431,7 @@ ev_add_path (struct path * pp, struct vectors * vecs, int need_do_map) if (retries >= 0) { if ((mpp->prflag == PR_SET && prflag != PR_SET) || start_waiter) - pr_register_active_paths(mpp, false); + pr_register_active_paths(mpp, NULL); condlog(2, "%s [%s]: path added to devmap %s", pp->dev, pp->dev_t, mpp->alias); return 0; @@ -2658,7 +2676,7 @@ update_path_state (struct vectors * vecs, struct path * pp) "reservation registration", pp->dev); mpath_pr_event_handle(pp, 0, 0); if (pp->mpp->prflag == PR_SET && prflag != PR_SET) - pr_register_active_paths(pp->mpp, false); + pr_register_active_paths(pp->mpp, NULL); } /* @@ -3319,7 +3337,7 @@ configure (struct vectors * vecs, enum force_reload_types reload_type) vector_foreach_slot(mpvec, mpp, i){ if (remember_wwid(mpp->wwid) == 1) trigger_paths_udev_change(mpp, true); - pr_register_active_paths(mpp, false); + pr_register_active_paths(mpp, NULL); } /* @@ -4373,8 +4391,8 @@ static int update_map_pr(struct multipath *mpp, struct path *pp, unsigned int *n * * nr_keys_wanted: Only used if nr_keys_needed is 0, so we don't know how * many keys we currently have. If nr_keys_wanted in non-zero and the - * number of keys found by the initial call to update_map_pr() matches it, - * exit early, since we have all the keys we are expecting. + * number of keys found by the initial call to update_map_pr() is at least + * as large as it, exit early, since we have all the keys we are expecting. * * The function returns the number of keys that are registered or 0 if * it's unknown. @@ -4397,7 +4415,7 @@ mpath_pr_event_handle(struct path *pp, unsigned int nr_keys_needed, nr_keys_needed = 1; if (update_map_pr(mpp, pp, &nr_keys_needed) != MPATH_PR_SUCCESS) return 0; - if (nr_keys_wanted && nr_keys_wanted == nr_keys_needed) + if (nr_keys_wanted && nr_keys_wanted <= nr_keys_needed) return nr_keys_needed; } diff --git a/multipathd/main.h b/multipathd/main.h index 6d60ee815..b66208ec5 100644 --- a/multipathd/main.h +++ b/multipathd/main.h @@ -54,5 +54,7 @@ int resize_map(struct multipath *mpp, unsigned long long size, struct vectors *vecs); void set_pr(struct multipath *mpp); void unset_pr(struct multipath *mpp); -void pr_register_active_paths(struct multipath *mpp, bool check_active_nr); +void pr_register_active_paths(struct multipath *mpp, + const struct vector_s *registered_paths); +void cleanup_reset_vec(struct vector_s **v); #endif /* MAIN_H_INCLUDED */ diff --git a/multipathd/multipathd.8.in b/multipathd/multipathd.8.in index 7ffb8d4c4..38a243e3e 100644 --- a/multipathd/multipathd.8.in +++ b/multipathd/multipathd.8.in @@ -348,6 +348,12 @@ Restores configured queue_without_daemon mode. Enable persistent reservation management on $map. . .TP +.B setprstatus map|multipath $map pathlist $pathlist +Enable persistent reservation management on $map, and notify multipathd of +the paths that have been registered, so it doesn't attempt to re-register +them. +. +.TP .B unsetprstatus map|multipath $map Disable persistent reservation management on $map. . From c81c4b54d27b09b914d28b41931070ae3f446ab2 Mon Sep 17 00:00:00 2001 From: Michal Rostecki Date: Wed, 7 Jan 2026 12:09:51 +0000 Subject: [PATCH 23/42] libmultipath: Remove the undefined symbol from the linker script dm_get_multipath() is a static function, not a symbol that can be exported. Clang is strict about not allowing undefined symbols in linker scripts and therefore its presence prevents clang from building libmultipath. It looks like it's a linker error and it's thrown only by lld. lld enabled --no-undefined-version as a default option [0]. Choice of a compiler (gcc, clang) shouldn't matter. One can reproduce the error on any system by specifying lld explicitly: $ make LDFLAGS="-fuse-ld=lld" Or by passing --no-undefined-version (and making the warning fatal), which throws an error wyth any linker: $ make LDFLAGS="-fuse-ld=mold -Wl,--no-undefined-version -Wl,--fatal-warnings". [0] https://reviews.llvm.org/D135402 Fixes: https://github.com/opensvc/multipath-tools/issues/132 Fixes: bf3a4ad ("libmultipath: simplify dm_get_maps()") Signed-off-by: Michal Rostecki Reviewed-by: Martin Wilck (cherry picked from commit a2986033c13de3b51002c6592dcfd59a6a8240dd) --- libmultipath/libmultipath.version | 1 - 1 file changed, 1 deletion(-) diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version index 89ae2a3c5..5017a54db 100644 --- a/libmultipath/libmultipath.version +++ b/libmultipath/libmultipath.version @@ -85,7 +85,6 @@ global: dm_geteventnr; dm_get_major_minor; dm_get_maps; - dm_get_multipath; dm_is_mpath; dm_mapname; dm_prereq; From 4a14ccb700fc3004fe67e0642b172b84c9527c1d Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Mon, 8 Dec 2025 15:18:01 +0100 Subject: [PATCH 24/42] multipath-tools: Fix ISO C23 errors with strchr() In ISO C23, memchr, strchr, strpbrk, strrchr and strstr become const-preserving macros [1], meaning that the return value inherits the const qualifier from the function argument. This has turned up a few glitches in our code. [1] https://gustedt.gitlabpages.inria.fr/c23-library/#memchr Signed-off-by: Martin Wilck Reviewed-by: Benjamin Marzinski (cherry picked from commit 9f611e2f10a4456477b6447641eea041ecee1019) --- libmpathutil/parser.c | 2 +- libmpathutil/util.c | 2 +- libmultipath/prkey.c | 2 +- libmultipath/prkey.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libmpathutil/parser.c b/libmpathutil/parser.c index 131a5ed03..bf7c411b8 100644 --- a/libmpathutil/parser.c +++ b/libmpathutil/parser.c @@ -144,7 +144,7 @@ snprint_keyword(struct strbuf *buff, const char *fmt, struct keyword *kw, const void *data) { int r = 0; - char *f; + const char *f; struct config *conf; STRBUF_ON_STACK(sbuf); diff --git a/libmpathutil/util.c b/libmpathutil/util.c index 38e984fc8..37412c662 100644 --- a/libmpathutil/util.c +++ b/libmpathutil/util.c @@ -38,7 +38,7 @@ strchop(char *str) */ const char *libmp_basename(const char *filename) { - char *p = strrchr(filename, '/'); + const char *p = strrchr(filename, '/'); return p ? p + 1 : filename; } diff --git a/libmultipath/prkey.c b/libmultipath/prkey.c index 4fbde5ad2..ebed0d090 100644 --- a/libmultipath/prkey.c +++ b/libmultipath/prkey.c @@ -50,7 +50,7 @@ static int parse_prkey(const char *ptr, uint64_t *prkey) return 0; } -int parse_prkey_flags(const char *ptr, uint64_t *prkey, uint8_t *flags) +int parse_prkey_flags(char *ptr, uint64_t *prkey, uint8_t *flags) { char *flagstr; diff --git a/libmultipath/prkey.h b/libmultipath/prkey.h index a89a617bd..806795ed3 100644 --- a/libmultipath/prkey.h +++ b/libmultipath/prkey.h @@ -15,7 +15,7 @@ int print_reservation_key(struct strbuf *buff, struct be64 key, uint8_t flags, int source); -int parse_prkey_flags(const char *ptr, uint64_t *prkey, uint8_t *flags); +int parse_prkey_flags(char *ptr, uint64_t *prkey, uint8_t *flags); int set_prkey(struct config *conf, struct multipath *mpp, uint64_t prkey, uint8_t sa_flags); int get_prkey(struct multipath *mpp, uint64_t *prkey, uint8_t *sa_flags); From 8bcd56de815d6b1fce9a87ee240e7d0c764266da Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Wed, 26 Nov 2025 22:16:21 +0100 Subject: [PATCH 25/42] libmultipath: don't access path members in free_pgvec() It can happen that a path group contains references to paths that are already freed. If we access pp->pgindex in such a case, a use-after-free occurs. In particular, this occurs if we call remove_map() from configure() -> coalesce_paths(), and some paths are freed in orphan_paths() because they are in INIT_PARTIAL or INIT_REMOVED state. The paths of the removed map may still be referenced by maps in the "old" mpvec in configure(). The UAF occurs when configure() calls remove_maps(vecs). This code has been introduced in cd912cf ("libmultipath: fix handling of pp->pgindex"). The commit message stated: "The hunk in group_paths is mostly redundant with the hunk in free_pgvec(), but because we're looping over pg->paths in the former and over pg->pgp in the latter, I think it's better too play safe". It turns out that it would have been better not to "play safe" here. No caller of free_pgvec() requires the pgindex to be reset. For the functions in pgpolicies.c, the reset of pgindex is redundant, as remarked in cd912cf. disassemble_map() will set the pgindex later anyway, and update_multipath_strings() will call disassemble_map(). The other callers remove the struct multipath, in which case the paths will eventually be orphaned or freed (except for the special case of coalesce_paths() mentioned above). Fixes: cd912cf ("libmultipath: fix handling of pp->pgindex") Signed-off-by: Martin Wilck Reviewed-by: Benjamin Marzinski (cherry picked from commit 7a07023b59065e301bde5e4c8cd405f7b95647f2) --- libmultipath/structs.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/libmultipath/structs.c b/libmultipath/structs.c index dfa547bb3..ee02b7aca 100644 --- a/libmultipath/structs.c +++ b/libmultipath/structs.c @@ -239,18 +239,8 @@ free_pgvec (vector pgvec, enum free_path_mode free_paths) if (!pgvec) return; - vector_foreach_slot(pgvec, pgp, i) { - - /* paths are going to be re-grouped, reset pgindex */ - if (free_paths != FREE_PATHS) { - struct path *pp; - int j; - - vector_foreach_slot(pgp->paths, pp, j) - pp->pgindex = 0; - } + vector_foreach_slot (pgvec, pgp, i) free_pathgroup(pgp, free_paths); - } vector_free(pgvec); } From c67aa02cdb085087172eed75386d379fa11e5de5 Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Wed, 10 Dec 2025 20:00:33 +0100 Subject: [PATCH 26/42] multipathd: join the init_unwinder dummy thread This closes a minor memory leak (thread-local storage of the dummy thread is never freed). Signed-off-by: Martin Wilck Reviewed-by: Benjamin Marzinski (cherry picked from commit 29f262b7c7ee4ba1b384eac76be956b3efbfe99f) --- multipathd/init_unwinder.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/multipathd/init_unwinder.c b/multipathd/init_unwinder.c index b1cd283d5..d39e4282f 100644 --- a/multipathd/init_unwinder.c +++ b/multipathd/init_unwinder.c @@ -34,5 +34,7 @@ int init_unwinder(void) pthread_mutex_unlock(&dummy_mtx); - return pthread_cancel(dummy); + rc = pthread_cancel(dummy); + pthread_join(dummy, NULL); + return rc; } From e8ca92aee55e71daca5f0cfa3175ebb56e3c552d Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Wed, 10 Dec 2025 23:39:02 +0100 Subject: [PATCH 27/42] kpartx: fix some memory leaks These leaks were reported by LeakSanitizer. Signed-off-by: Martin Wilck Reviewed-by: Benjamin Marzinski (cherry picked from commit 8c39e60cba6c6ce6f9153f3d219574fbdb8e6ea0) --- kpartx/kpartx.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/kpartx/kpartx.c b/kpartx/kpartx.c index a1495e55e..7ec89b479 100644 --- a/kpartx/kpartx.c +++ b/kpartx/kpartx.c @@ -227,6 +227,11 @@ xmalloc (size_t size) { return t; } +static void cleanup_charp(char **p) +{ + free(*p); +} + int main(int argc, char **argv){ int i, j, m, n, op, off, arg, c, d, ro=0; @@ -237,10 +242,10 @@ main(int argc, char **argv){ char *type, *diskdevice, *device, *progname; int verbose = 0; char partname[PARTNAME_SIZE], params[PARTNAME_SIZE + 16]; - char * loopdev = NULL; - char * delim = NULL; - char *uuid = NULL; - char *mapname = NULL; + char *loopdev __attribute__((cleanup(cleanup_charp))) = NULL; + char *delim __attribute__((cleanup(cleanup_charp))) = NULL; + char *uuid __attribute__((cleanup(cleanup_charp))) = NULL; + char *mapname __attribute__((cleanup(cleanup_charp))) = NULL; int hotplug = 0; int loopcreated = 0; struct stat buf; @@ -292,7 +297,9 @@ main(int argc, char **argv){ verbose = 1; break; case 'p': - delim = optarg; + delim = strdup(optarg); + if (!delim) + exit(1); break; case 'l': what = LIST; @@ -674,7 +681,6 @@ main(int argc, char **argv){ if (verbose) fprintf(stderr, "loop deleted : %s\n", device); } - end: dm_lib_exit(); From 1371674343a597aee15b3ad35671d66fe394b5cb Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Thu, 15 Jan 2026 23:08:39 +0100 Subject: [PATCH 28/42] kpartx: avoid double-free of mapname The variable mapname is sometimes allocated and sometimes not. To avoid double-free and still free allocated memory cleanly, introduce a helper pointer for storing possibly allocated memory. Signed-off-by: Martin Wilck Reviewed-by: Benjamin Marzinski (cherry picked from commit 02e0933b1ea022c24d4d4aa2233082324b2771a1) --- kpartx/kpartx.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/kpartx/kpartx.c b/kpartx/kpartx.c index 7ec89b479..6f2ec4ea0 100644 --- a/kpartx/kpartx.c +++ b/kpartx/kpartx.c @@ -245,7 +245,8 @@ main(int argc, char **argv){ char *loopdev __attribute__((cleanup(cleanup_charp))) = NULL; char *delim __attribute__((cleanup(cleanup_charp))) = NULL; char *uuid __attribute__((cleanup(cleanup_charp))) = NULL; - char *mapname __attribute__((cleanup(cleanup_charp))) = NULL; + char *_mapname __attribute__((cleanup(cleanup_charp))) = NULL; + char *mapname; int hotplug = 0; int loopcreated = 0; struct stat buf; @@ -388,11 +389,15 @@ main(int argc, char **argv){ off = find_devname_offset(device); if (!loopdev) { - mapname = dm_mapname(major(buf.st_rdev), minor(buf.st_rdev)); - if (mapname) - uuid = dm_mapuuid(mapname); + _mapname = dm_mapname(major(buf.st_rdev), minor(buf.st_rdev)); + if (_mapname) + uuid = dm_mapuuid(_mapname); } + mapname = _mapname; + if (!mapname) + mapname = device + off; + /* * We are called for a non-DM device. * Make up a fake UUID for the device, unless "-d -f" is given. @@ -402,9 +407,6 @@ main(int argc, char **argv){ if (!uuid && !(what == DELETE && force_devmap)) uuid = nondm_create_uuid(buf.st_rdev); - if (!mapname) - mapname = device + off; - if (delim == NULL) { delim = xmalloc(DELIM_SIZE); memset(delim, 0, DELIM_SIZE); From 103a9c6fa59eee510841b0ec0a81c062b1cf02af Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Fri, 9 Jan 2026 15:26:48 +0100 Subject: [PATCH 29/42] libmultipath: warn only once in scsi_tmo_error_msg() The intention of this code was to warn only once for each unsupported protocol. But the condition statement is missing. Fixes: 6ad77db ("libmultipath: Set the scsi timeout parameters by path") Signed-off-by: Martin Wilck Reviewed-by: Benjamin Marzinski (cherry picked from commit 958c826862d04779a7405349b7c75db8fd0ddad1) --- libmultipath/discovery.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c index 31db8758b..6d5fea635 100644 --- a/libmultipath/discovery.c +++ b/libmultipath/discovery.c @@ -880,6 +880,8 @@ scsi_tmo_error_msg(struct path *pp) STRBUF_ON_STACK(proto_buf); unsigned int proto_id = bus_protocol_id(pp); + if (is_bit_set_in_bitfield(proto_id, bf)) + return; snprint_path_protocol(&proto_buf, pp); condlog(2, "%s: setting scsi timeouts is unsupported for protocol %s", pp->dev, get_strbuf_str(&proto_buf)); From a5dc9450cd534518684ba4e7ffb9126e8fe529d5 Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Fri, 9 Jan 2026 18:23:52 +0100 Subject: [PATCH 30/42] multipath-tools: compile with -fno-strict-aliasing multipath-tools uses container_of() and similar macros, which imply casts between different types, which isn't stricly compliant with strict aliasing rules. The issue that lead to the previous commit "libmpathutil: use union for bitfield" was one example where this can fail. While that one could be fixed relatively easily, it shows that surprises can happen any time when we compile our code with strict aliasing enabled. This can be seen clearly when we compile with "-fstrict-aliasing -Wstrict-aliasing=1" (note that the bitfield problem is only reported by gcc with "-Wstrict-aliasing=1", other levels of aliasing detection miss it with gcc 15). Use -fno-strict-aliasing to disable it. The kernel does the same. Signed-off-by: Martin Wilck Reviewed-by: Benjamin Marzinski (cherry picked from commit 1ef540a323ab37993efba517ca150715e3ef42d7) --- Makefile.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.inc b/Makefile.inc index 9e3dc4661..1a13c62b6 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -122,7 +122,7 @@ CPPFLAGS := $(FORTIFY_OPT) $(CPPFLAGS) $(D_URCU_VERSION) \ -DWSTRINGOP_TRUNCATION=$(if $(WSTRINGOP_TRUNCATION),1,0) \ -MMD -MP CFLAGS := -std=$(C_STD) $(CFLAGS) $(OPTFLAGS) $(WARNFLAGS) -pipe \ - -fexceptions + -fexceptions -fno-strict-aliasing BIN_CFLAGS := -fPIE -DPIE LIB_CFLAGS := -fPIC SHARED_FLAGS := -shared From 46292af3be76ed0e73842171461c86f19d723328 Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Fri, 16 Jan 2026 11:44:55 +0100 Subject: [PATCH 31/42] multipathd: fix an uninitialized variable warning This isn't necessary in practice, but it fixes a compile warning. Signed-off-by: Martin Wilck Reviewed-by: Benjamin Marzinski (cherry picked from commit c032ba1e013283f1171817e8524b92d5f9814113) --- multipathd/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/multipathd/main.c b/multipathd/main.c index d3bf4d036..588bf2b99 100644 --- a/multipathd/main.c +++ b/multipathd/main.c @@ -3821,7 +3821,7 @@ child (__attribute__((unused)) void *param) int rc; struct config *conf; char *envp; - enum daemon_status state; + enum daemon_status state = DAEMON_INIT; int exit_code = 1; int fpin_marginal_paths = 0; From f65e254ac4ca1d5b4fc9b5df94fe6296da581244 Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Fri, 16 Jan 2026 11:37:41 +0100 Subject: [PATCH 32/42] Makefiles: add "ASAN=1" make parameter for AddressSanitizer It's now possible to enable AddressSanitizer by passing the parameter `ASAN=1` on the "make" command line. Signed-off-by: Martin Wilck Reviewed-by: Benjamin Marzinski (cherry picked from commit 5e5d2102f7a409d2cc9165605d0117457bc9fe41) --- .github/actions/spelling/expect.txt | 4 ++++ Makefile.inc | 7 +++++-- README.md | 3 +++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index a3e38d8d1..8510cc791 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -6,6 +6,7 @@ alloc alltgpt alua aptpl +ASAN ascq ata autoconfig @@ -77,6 +78,7 @@ getrlimit getuid github gitlab +google GPT hbtl hds @@ -194,6 +196,8 @@ rpmbuild rport rtpi rtprio +sanitizer +sanitizers sas sbp scsi diff --git a/Makefile.inc b/Makefile.inc index 1a13c62b6..ce018b8bf 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -9,6 +9,9 @@ # Uncomment to disable dmevents polling support # ENABLE_DMEVENTS_POLL = 0 # +# Use ASAN=1 on make command line to enable address sanitizer +ASAN := +# # Readline library to use, libedit, libreadline, or empty # Caution: Using libreadline may make the multipathd binary undistributable, # see https://github.com/opensvc/multipath-tools/issues/36 @@ -122,11 +125,11 @@ CPPFLAGS := $(FORTIFY_OPT) $(CPPFLAGS) $(D_URCU_VERSION) \ -DWSTRINGOP_TRUNCATION=$(if $(WSTRINGOP_TRUNCATION),1,0) \ -MMD -MP CFLAGS := -std=$(C_STD) $(CFLAGS) $(OPTFLAGS) $(WARNFLAGS) -pipe \ - -fexceptions -fno-strict-aliasing + -fexceptions -fno-strict-aliasing $(if $(ASAN),-fsanitize=address) BIN_CFLAGS := -fPIE -DPIE LIB_CFLAGS := -fPIC SHARED_FLAGS := -shared -LDFLAGS := $(LDFLAGS) -Wl,-z,relro -Wl,-z,now -Wl,-z,defs +LDFLAGS := $(LDFLAGS) -Wl,-z,relro -Wl,-z,now -Wl,-z,defs $(if $(ASAN),-lasan) BIN_LDFLAGS := -pie # Source code directories. Don't modify. diff --git a/README.md b/README.md index 530caed7d..8ff139c7a 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,9 @@ See "Passing standard compiler flags" below for an exception. The following variables can be passed to the `make` command line: * `V=1`: enable verbose build. + * `ASAN=1`: Enable + [AddressSanitizer](https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer) + during build for debugging memory allocation. This is off by default. * `plugindir="/some/path"`: directory where libmultipath plugins (path checkers, prioritizers, and foreign multipath support) will be looked up. This used to be the run-time option `multipath_dir` in earlier versions. From 2aa1005006603849064bdf4ee7cf718bdcbcd1d0 Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Fri, 16 Jan 2026 11:39:22 +0100 Subject: [PATCH 33/42] Makefiles: add "OPT=" make parameter Our OPTFLAGS variable contains stack protection options which are intended to be overridable by distribution build scripts. When developers just want to experiment with optimization levels, they often just want to modify the `-O` level. Introduce a variable `OPT` that allows to do just that by passing e.g. `OPT=-O0` to the `make` command line. Signed-off-by: Martin Wilck Reviewed-by: Benjamin Marzinski (cherry picked from commit c94c65cc7357ca609e46438bff84a1a4bd82268e) --- Makefile.inc | 5 ++++- README.md | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Makefile.inc b/Makefile.inc index ce018b8bf..620d13deb 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -12,6 +12,9 @@ # Use ASAN=1 on make command line to enable address sanitizer ASAN := # +# Override on make command line if desired +OPT := -O2 + # Readline library to use, libedit, libreadline, or empty # Caution: Using libreadline may make the multipathd binary undistributable, # see https://github.com/opensvc/multipath-tools/issues/36 @@ -105,7 +108,7 @@ SYSTEMD_LIBDEPS := $(if $(SYSTEMD),$(if $(shell test $(SYSTEMD) -gt 209 && echo 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 +OPTFLAGS := $(OPT) -g $(STACKPROT) --param=ssp-buffer-size=4 # Set WARN_ONLY=1 to avoid compilation erroring out due to warnings. Useful during development. WARN_ONLY := diff --git a/README.md b/README.md index 8ff139c7a..888998b7e 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,12 @@ See "Passing standard compiler flags" below for an exception. The following variables can be passed to the `make` command line: * `V=1`: enable verbose build. + * `OPT=`: set optimization flags. You may want to set `OPT="-O0"` for + debugging, for example. The default is `-O2`. Note that it is also + possible to set `OPTFLAGS`, which takes precedence over `OPT`. `OPTFLAGS` + sets additional options by default, which are intended for distribution + build environments to override. For quick customization of the optimization + level, use `OPT`. * `ASAN=1`: Enable [AddressSanitizer](https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer) during build for debugging memory allocation. This is off by default. From 6bfac748d20b2cdf460ac6fcb96f805400a1240d Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Mon, 19 Jan 2026 11:45:40 +0100 Subject: [PATCH 34/42] multipath-tools tests: suppress a compiler warning for vpd.c The following warning has been observed with gcc 15.2.1 on Fedora Rawhide: vpd.c: In function 'create_vpd83.constprop': vpd.c:265:55: error: '%s' directive output truncated writing 64 bytes into a region of size 40 [-Werror=format-truncation=] 265 | len = snprintf((char *)(desc + 4), maxlen, "%s%s", | ^~ In file included from /usr/include/stdio.h:974, from vpd.c:8: In function 'snprintf', inlined from 'create_scsi_string_desc' at vpd.c:265:8, inlined from 'create_vpd83.constprop' at vpd.c:313:7: /usr/include/bits/stdio2.h:68:10: note: '__builtin___snprintf_chk' output 65 or more bytes into a destination of size 40 68 | return __builtin___snprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1, | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 69 | __glibc_objsize (__s), __fmt, | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 70 | __va_arg_pack ()); | ~~~~~~~~~~~~~~~~~ cc1: all warnings being treated as errors Fix it. Signed-off-by: Martin Wilck (cherry picked from commit 888187ed1336cf6e938d625c59593661bb359882) --- tests/vpd.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/vpd.c b/tests/vpd.c index e3212e614..a72865337 100644 --- a/tests/vpd.c +++ b/tests/vpd.c @@ -262,8 +262,20 @@ static int create_scsi_string_desc(unsigned char *desc, assert_in_range(type, STR_EUI, STR_IQN); assert_true(maxlen % 4 == 0); +#if defined(__GNUC__) && __GNUC__ >= 15 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat-truncation=" + /* + * This is called from test_vpd_str_XYZ() functions, where + * we deliberately use the overlong input string test_id. + * So format truncation is expected here. + */ +#endif len = snprintf((char *)(desc + 4), maxlen, "%s%s", str_prefix[type], id); +#if defined(__GNUC__) && __GNUC__ >= 15 +#pragma GCC diagnostic pop +#endif if (len > maxlen) len = maxlen; /* zero-pad */ @@ -451,7 +463,6 @@ static void test_vpd_str_ ## typ ## _ ## len ## _ ## wlen(void **state) \ int n, ret; \ int exp_len; \ int type = typ & STR_MASK; \ - \ n = create_vpd83(vt->vpdbuf, sizeof(vt->vpdbuf), test_id, \ 8, typ, len); \ exp_len = len - strlen(str_prefix[type]); \ From 8901c17f589428f9106e8c51a4b6b16834716ea4 Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Tue, 16 Dec 2025 21:58:42 +0100 Subject: [PATCH 35/42] Makefile: fix CI build errors with cmocka 2.0 cmocka 2.0.0 introduces a couple of changes that require version-dependent code to be used. Add macros to determine the cmocka version. If the version can't be determined, assume 1.1.0. Use a different approach here than in the stable branch, because the fix there is rather large. Instead of replacing all deprecated macros, just treat the respective warnings as non-fatal by adding the compiler flag -Wno-error=deprecated-declarations for the CI code. cmocka 2.0.1 added a macro to suppress these warnings altogether, but we should also be able to build against 2.0.0. Fixes: https://github.com/opensvc/multipath-tools/issues/129 Signed-off-by: Martin Wilck --- Makefile.inc | 2 +- create-config.mk | 5 +++++ tests/Makefile | 3 ++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Makefile.inc b/Makefile.inc index 620d13deb..c6aa6eda2 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -118,7 +118,7 @@ WARNFLAGS := $(WERROR) -Wall -Wextra -Wformat=2 $(WFORMATOVERFLOW) -W$(ERROR)imp -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) \ +CPPFLAGS := $(FORTIFY_OPT) $(CPPFLAGS) $(D_URCU_VERSION) $(D_CMOCKA_VERSION) \ -D_FILE_OFFSET_BITS=64 \ -DBIN_DIR=\"$(bindir)\" -DMULTIPATH_DIR=\"$(TGTDIR)$(plugindir)\" \ -DRUNTIME_DIR=\"$(runtimedir)\" -DCONFIG_DIR=\"$(TGTDIR)$(configdir)\" \ diff --git a/create-config.mk b/create-config.mk index 3c3ba069e..2d6ade856 100644 --- a/create-config.mk +++ b/create-config.mk @@ -77,6 +77,10 @@ URCU_VERSION = $(shell \ $(PKG_CONFIG) --modversion liburcu 2>/dev/null | \ awk -F. '{ printf("-DURCU_VERSION=0x%06x", 256 * ( 256 * $$1 + $$2) + $$3); }') +CMOCKA_VERSION = $(shell \ + ($(PKG_CONFIG) --modversion cmocka 2>/dev/null || echo "1.1.0" ) | \ + awk -F. '{ printf("%d", 256 * ( 256 * $$1 + $$2) + $$3); }') + DEFINES := ifneq ($(call check_func,dm_task_no_flush,$(devmapper_incdir)/libdevmapper.h),0) @@ -185,6 +189,7 @@ $(TOPDIR)/config.mk: $(multipathdir)/autoconfig.h @echo "FPIN_SUPPORT := $(FPIN_SUPPORT)" >$@ @echo "FORTIFY_OPT := $(FORTIFY_OPT)" >>$@ @echo "D_URCU_VERSION := $(call URCU_VERSION)" >>$@ + @echo "CMOCKA_VERSION := $(call CMOCKA_VERSION)" >>$@ @echo "SYSTEMD := $(SYSTEMD)" >>$@ @echo "ANA_SUPPORT := $(ANA_SUPPORT)" >>$@ @echo "STACKPROT := $(call TEST_CC_OPTION,-fstack-protector-strong,-fstack-protector)" >>$@ diff --git a/tests/Makefile b/tests/Makefile index 28c00ad2d..0ec036ebd 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -5,7 +5,8 @@ TESTDIR := $(CURDIR) CPPFLAGS += -I$(multipathdir) -I$(mpathutildir) -I$(mpathcmddir) -I$(daemondir) \ -DTESTCONFDIR=\"$(TESTDIR)/conf.d\" -CFLAGS += $(BIN_CFLAGS) -Wno-unused-parameter $(W_MISSING_INITIALIZERS) +CFLAGS += $(BIN_CFLAGS) -Wno-unused-parameter $(W_MISSING_INITIALIZERS) \ + $(if $(shell [ $(CMOCKA_VERSION) -ge 131072 ] && echo yes),-Wno-error=deprecated-declarations) LIBDEPS += -L. -L $(mpathutildir) -L$(mpathcmddir) -lmultipath -lmpathutil -lmpathcmd -lcmocka TESTS := uevent parser util dmevents hwtable blacklist unaligned vpd pgpolicy \ From 2c6c68f3023f2242d464b80110f7b2af0625622e Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Fri, 21 Nov 2025 13:19:45 +0100 Subject: [PATCH 36/42] GitHub actions: spelling: fix warning about ignore expect variant "nvme" makes "NVMe" redundant. Signed-off-by: Martin Wilck --- .github/actions/spelling/expect.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index 8510cc791..cb43b5f25 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -147,7 +147,6 @@ NOLOG nompath NOSCAN Nosync -NVMe nvme NFINIDAT OBJDEPS From 49acb1b9da8bc9b5a373926fe21158084eecd3ae Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Mon, 19 Jan 2026 22:42:57 +0100 Subject: [PATCH 37/42] Spelling: Pull in changes from master branch Signed-off-by: Martin Wilck --- .github/actions/spelling/expect.txt | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index cb43b5f25..154430db3 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -14,6 +14,7 @@ autodetected autoresize barbie BINDIR +bitfield blkid bmarzins Bsymbolic @@ -59,14 +60,15 @@ EAGAIN ECKD emc Engenio -Equal EVPD +Exos failback failover fds fexceptions FFFFFFFF fge +fno followover forcequeueing fpin @@ -124,6 +126,7 @@ libudevdir liburcu linux LIO +lld lpthread Lun lvm @@ -143,12 +146,13 @@ multipathing multipaths multiqueue mwilck +NFINIDAT NOLOG nompath NOSCAN Nosync nvme -NFINIDAT +Nytro OBJDEPS oneshot ontap @@ -161,6 +165,7 @@ pathgroup pathlist petabytes pgpolicy +pgvec plugindir PNR ppc @@ -195,7 +200,6 @@ rpmbuild rport rtpi rtprio -sanitizer sanitizers sas sbp @@ -223,11 +227,11 @@ suse svg switchgroup sys +SYSDIR sysfs sysinit tcp terabytes -SYSDIR TESTDEPS testname tgill @@ -244,7 +248,6 @@ udevd uevent uid unitdir -unregistering unsetmarginal unsetprkey unsetprstatus @@ -267,6 +270,7 @@ weightedpath wholedisk Wilck wildcards +Wno workflows wrt wwid From c268fe11e2d936f36302901521398b71a335feae Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Tue, 20 Jan 2026 13:54:39 +0100 Subject: [PATCH 38/42] Update NEWS.md for 0.13.1 Signed-off-by: Martin Wilck --- NEWS.md | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/NEWS.md b/NEWS.md index 6f0018e67..39ef9c939 100644 --- a/NEWS.md +++ b/NEWS.md @@ -9,6 +9,44 @@ release. These bug fixes will be tracked in stable branches. See [README.md](README.md) for additional information. +## multipath-tools 0.13.1, 2026/01 + +### Bug fixes + +* Make sure multipathd registers keys all paths of a multipath map after + mpathpersist registered a key for a map. multipathd could fail to do so in + some cases, e.g. if paths become unavailable or available while the + registration was taking place. Fixes 0.13.0. +* Fix `mpathpersist --report-capabilities` output. Fixes 0.5.0. +* Improve error handling when retrying REGISTER AND IGNORE persistent + reservations commands. Fixes 0.13.0. +* Fix command descriptions in the multipathd man page. Fixes 0.9.2. +* Fix an undefined symbol error with the LLVM lld linker. + Fixes [#132](https://github.com/opensvc/multipath-tools/issues/132), 0.10.0. +* Fix ISO C23 compatibility issue causing errors with new compilers. +* Fix use-after-free error in free_pgvec(). + Fixes [#128](https://github.com/opensvc/multipath-tools/issues/128), 0.12.0. +* Fix memory leak caused by not joining the "init unwinder" thread. + Fixes 0.8.6. +* Fix memory leaks in kpartx. Fixes any version. +* Print the warning "setting scsi timeouts is unsupported for protocol" only + once per protocol. Fixes 0.9.0. +* Make sure multipath-tools is compiled with the compiler flag + `-fno-strict-aliasing`. This turns out to be necessary because our code + uses techniques like `container_of()` which don't work well with + strict aliasing rules. + Fixes [#130](https://github.com/opensvc/multipath-tools/issues/130). + +### Other changes + +* Hardware table: add Seagate Exos and Nytro series. +* Avoid joining threads twice with liburcu 0.14.0 and newer. +* CI updates (GitHub workflows). +* Fix CI for cmocka 2.0 by adding the `-Wno-error=deprecated-declarations` + compiler flag. + Fixes [#129](https://github.com/opensvc/multipath-tools/issues/129) +* Add the ASAN=1 and OPT= make variables (see README.md). + ## multipath-tools 0.13.0, 2025/10 ### Major rework of the SCSI Persistent Reservation code From b19582e505aa31aa2f2828b6a030ec77b4738ae5 Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Tue, 20 Jan 2026 13:55:29 +0100 Subject: [PATCH 39/42] libmultipath: bump version to 0.13.1 Signed-off-by: Martin Wilck --- libmultipath/version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libmultipath/version.h b/libmultipath/version.h index e8f9be00b..d543c9bab 100644 --- a/libmultipath/version.h +++ b/libmultipath/version.h @@ -11,9 +11,9 @@ #ifndef VERSION_H_INCLUDED #define VERSION_H_INCLUDED -#define VERSION_CODE 0x000D00 +#define VERSION_CODE 0x000D01 /* MMDDYY, in hex */ -#define DATE_CODE 0x0A0A19 +#define DATE_CODE 0x01141A #define PROG "multipath-tools" From 70addc2a5b87e87f70210d0530d9bf7ee4e937a6 Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Wed, 21 Jan 2026 16:03:11 -0500 Subject: [PATCH 40/42] multipathd: finish initalization of paths added while offline If a path in a mulitpath device is offline while multipathd is reconfigured, it will get added to the updated multipath device, just like it was in the old multipath device. However the device will still be in the INIT_NEW state because it can't get initilized while offline. This is different than the INIT_PARTIAL state because the path was discovered in path_discovery(). INIT_PARTIAL is for paths that multipathd did not discover in path_discovery() or receive a uevent for, but are part of a multipath device that was added, and which should receive a uevent shortly. There is no reason to expect a uevent for these offline paths. When the path comes back online, multipathd will run the checker and prioritizer on it. The only two pathinfo checks that won't happen are the DI_WWID and DI_IOCTL ones. Modify pathinfo() to make sure that if DI_IOCTL was skipped for offline paths, it gets called the next time pathinfo() is called after the fd can be opened. Also, make sure that when one of these offline paths becomes usable, its WWID is rechecked. With those changes, all the DI_ALL checks will be accounted for, and the path can be marked INIT_OK. Signed-off-by: Benjamin Marzinski Reviewed-by: Martin Wilck (cherry picked from commit 1942fb136a388c9bdd964741116ed0a89cf9e198) --- libmultipath/discovery.c | 2 ++ multipathd/main.c | 54 ++++++++++++++++++++++++++++++++++------ 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c index 6d5fea635..4da8ea4a9 100644 --- a/libmultipath/discovery.c +++ b/libmultipath/discovery.c @@ -2559,6 +2559,8 @@ int pathinfo(struct path *pp, struct config *conf, int mask) * Recoverable error, for example faulty or offline path */ pp->chkrstate = pp->state = PATH_DOWN; + if (mask & DI_IOCTL && pp->ioctl_info == IOCTL_INFO_NOT_REQUESTED) + pp->ioctl_info = IOCTL_INFO_SKIPPED; if (pp->initialized == INIT_NEW || pp->initialized == INIT_FAILED) memset(pp->wwid, 0, WWID_SIZE); diff --git a/multipathd/main.c b/multipathd/main.c index 588bf2b99..21d55f028 100644 --- a/multipathd/main.c +++ b/multipathd/main.c @@ -2545,6 +2545,26 @@ sync_mpp(struct vectors * vecs, struct multipath *mpp, unsigned int ticks) return do_sync_mpp(vecs, mpp); } +/* + * pp->wwid should never be empty when this function is called, but if it + * is, this function can set it. + */ +static bool new_path_wwid_changed(struct path *pp, int state) +{ + char wwid[WWID_SIZE]; + + strlcpy(wwid, pp->wwid, WWID_SIZE); + if (get_uid(pp, state, pp->udev, 1) != 0) { + strlcpy(pp->wwid, wwid, WWID_SIZE); + return false; + } + if (strlen(wwid) && strncmp(wwid, pp->wwid, WWID_SIZE) != 0) { + strlcpy(pp->wwid, wwid, WWID_SIZE); + return true; + } + return false; +} + static int update_path_state (struct vectors * vecs, struct path * pp) { @@ -2573,14 +2593,34 @@ update_path_state (struct vectors * vecs, struct path * pp) pp->tick = 1; return CHECK_PATH_SKIPPED; } - if (pp->recheck_wwid == RECHECK_WWID_ON && - (newstate == PATH_UP || newstate == PATH_GHOST) && + + if ((newstate == PATH_UP || newstate == PATH_GHOST) && ((pp->state != PATH_UP && pp->state != PATH_GHOST) || - pp->dmstate == PSTATE_FAILED) && - check_path_wwid_change(pp)) { - condlog(0, "%s: path wwid change detected. Removing", pp->dev); - return handle_path_wwid_change(pp, vecs)? CHECK_PATH_REMOVED : - CHECK_PATH_SKIPPED; + pp->dmstate == PSTATE_FAILED)) { + bool wwid_changed = false; + + if (pp->initialized == INIT_NEW) { + /* + * Path was added to map while offline, mark it as + * initialized. + * DI_SYSFS was checked when the path was added + * DI_IOCTL was checked when the checker was selected + * DI_CHECKER just got checked + * DI_WWID is about to be checked + * DI_PRIO will get checked at the end of this checker + * loop + */ + pp->initialized = INIT_OK; + wwid_changed = new_path_wwid_changed(pp, newstate); + } else if (pp->recheck_wwid == RECHECK_WWID_ON) + wwid_changed = check_path_wwid_change(pp); + if (wwid_changed) { + condlog(0, "%s: path wwid change detected. Removing", + pp->dev); + return handle_path_wwid_change(pp, vecs) + ? CHECK_PATH_REMOVED + : CHECK_PATH_SKIPPED; + } } if ((newstate != PATH_UP && newstate != PATH_GHOST && newstate != PATH_PENDING) && (pp->state == PATH_DELAYED)) { From acde27fd90eed921e2b9c4a1bc671367738f8509 Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Wed, 21 Jan 2026 16:03:13 -0500 Subject: [PATCH 41/42] multipathd: print path offline message even without a checker If a path has a checker selected and is offline, multipathd will print a "path offline" message. However if the checker isn't selected, for instance because multipathd was started or reconfigured while the path was offline, multipathd was not printing the "path offline" message. Fix that. Signed-off-by: Benjamin Marzinski Reviewed-by: Martin Wilck (cherry picked from commit 1a364a1699baec8cb886c0e82a5e4699142ac153) --- multipathd/main.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/multipathd/main.c b/multipathd/main.c index 21d55f028..64ba1fb8c 100644 --- a/multipathd/main.c +++ b/multipathd/main.c @@ -95,12 +95,11 @@ mpath_pr_event_handle(struct path *pp, unsigned int nr_keys_needed, #define LOG_MSG(lvl, pp) \ do { \ - if (pp->mpp && checker_selected(&pp->checker) && \ - lvl <= libmp_verbosity) { \ - if (pp->sysfs_state == PATH_DOWN) \ + if (pp->mpp && lvl <= libmp_verbosity) { \ + if (pp->sysfs_state != PATH_UP) \ condlog(lvl, "%s: %s - path offline", \ pp->mpp->alias, pp->dev); \ - else { \ + else if (checker_selected(&pp->checker)) { \ const char *__m = \ checker_message(&pp->checker); \ \ From 0ce6b0e98adf89b912dc535aec16c404f326ade2 Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Thu, 22 Jan 2026 20:53:17 +0100 Subject: [PATCH 42/42] update NEWS.md --- NEWS.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NEWS.md b/NEWS.md index 39ef9c939..b8a34b679 100644 --- a/NEWS.md +++ b/NEWS.md @@ -36,6 +36,9 @@ See [README.md](README.md) for additional information. uses techniques like `container_of()` which don't work well with strict aliasing rules. Fixes [#130](https://github.com/opensvc/multipath-tools/issues/130). +* Fix initialization of paths that were offline during path detection. +* Fix printing the "path offline" log message for offline paths that don't + have a path checker configured. ### Other changes