Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/actions/spelling/patterns.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
\b0x[0-9a-f]{8}\b
\b0x[0-9a-f]{16}\b

# Commit SHAs
\b[0-9a-f]{7}\b

# WWNN/WWPN (NAA identifiers)
\b(?:0x)?10[0-9a-f]{14}\b
\b(?:0x|3)?[25][0-9a-f]{15}\b
Expand Down
17 changes: 17 additions & 0 deletions .github/workflows/spelling.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,23 @@ on:
- 'opened'
- 'reopened'
- 'synchronize'
paths:
- '.github/workflows/spelling.yml'
- 'README*'
- 'NEWS.md'
- '**.3'
- '**.5'
- '**.8'
- '**.8'
- '**.in'
- '**.service'
- '**.socket'
- '**.rules'
- '**/libdmmp.h'
- '**/mpath_valid.h'
- '**/mpath_cmd.h'
- '**/mpath_persist.h'
- '.github/actions/spelling/*'

jobs:
spelling:
Expand Down
22 changes: 22 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,28 @@ release. These bug fixes will be tracked in stable branches.

See [README.md](README.md) for additional information.

## multipath-tools 0.14.1, 2026/01

### Bug fixes

* kpartx: Fix freeing static buffer when operating on regular files.
Fixes 0.14.0. Commit fab5d44.
Fixes [#139](https://github.com/opensvc/multipath-tools/issues/139).
* Fix initialization of paths that were offline during path detection.
Commit 1942fb1.
* Fix printing the "path offline" log message for offline paths that don't
have a path checker configured. Commit 1a364a1.

### Other changes

* If path devices that are members of multipath maps aren't detected during
multipathd startup or `reconfigure`, don't add them to newly created maps
in the first place. In previous versions, such paths would be added to the
maps, only to be removed later. Commit a04be55.
* Improve the detection of "busy" state in the `show status` command, such
that reading udev events from udevd is also counted as busy.
Commit 7fdd93b.

## multipath-tools 0.14.0, 2026/01

### User-visible changes
Expand Down
16 changes: 8 additions & 8 deletions kpartx/devmapper.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2004, 2005 Christophe Varoqui
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Expand Down Expand Up @@ -699,14 +700,13 @@ int dm_find_part(const char *parent, const char *delim, int part,

char *nondm_create_uuid(dev_t devt)
{
#define NONDM_UUID_BUFLEN (34 + sizeof(NONDM_UUID_PREFIX) + \
sizeof(NONDM_UUID_SUFFIX))
static char uuid_buf[NONDM_UUID_BUFLEN];
snprintf(uuid_buf, sizeof(uuid_buf), "%s_%u:%u_%s",
NONDM_UUID_PREFIX, major(devt), minor(devt),
NONDM_UUID_SUFFIX);
uuid_buf[NONDM_UUID_BUFLEN-1] = '\0';
return uuid_buf;
char *uuid;

if (asprintf(&uuid, "%s_%u:%u_%s", NONDM_UUID_PREFIX, major(devt),
minor(devt), NONDM_UUID_SUFFIX) >= 0)
return uuid;
else
return NULL;
}

int nondm_parse_uuid(const char *uuid, unsigned int *major, unsigned int *minor)
Expand Down
5 changes: 4 additions & 1 deletion kpartx/kpartx.c
Original file line number Diff line number Diff line change
Expand Up @@ -334,8 +334,11 @@ main(int argc, char **argv){
* This allows deletion of partitions created with older kpartx
* versions which didn't use the fake UUID during creation.
*/
if (!uuid && !(what == DELETE && force_devmap))
if (!uuid && !(what == DELETE && force_devmap)) {
uuid = nondm_create_uuid(buf.st_rdev);
if (!uuid)
exit(1);
}

if (delim == NULL) {
delim = xmalloc(DELIM_SIZE);
Expand Down
12 changes: 11 additions & 1 deletion libmultipath/configure.c
Original file line number Diff line number Diff line change
Expand Up @@ -1113,7 +1113,17 @@ int coalesce_paths (struct vectors *vecs, vector mpvec, char *refwwid,
continue;
}

/* 4. path is out of scope */
/*
* 4. The path wasn't found in path_discovery. It only exists
* in an old map.
*/
if (pp1->initialized == INIT_PARTIAL ||
pp1->initialized == INIT_REMOVED) {
orphan_path(pp1, "path not found");
continue;
}

/* 5. path is out of scope */
if (refwwid && strncmp(pp1->wwid, refwwid, WWID_SIZE - 1))
continue;

Expand Down
2 changes: 2 additions & 0 deletions libmultipath/discovery.c
Original file line number Diff line number Diff line change
Expand Up @@ -2585,6 +2585,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);

Expand Down
3 changes: 2 additions & 1 deletion libmultipath/structs_vec.c
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,8 @@ int adopt_paths(vector pathvec, struct multipath *mpp,
pp->dev, mpp->alias);
continue;
}
if (pp->initialized == INIT_REMOVED)
if (pp->initialized == INIT_REMOVED ||
pp->initialized == INIT_PARTIAL)
continue;
if (mpp->queue_mode == QUEUE_MODE_RQ &&
pp->bus == SYSFS_BUS_NVME &&
Expand Down
9 changes: 7 additions & 2 deletions libmultipath/uevent.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ static pthread_cond_t *uev_condp = &uev_cond;
static uev_trigger *my_uev_trigger;
static void *my_trigger_data;
static int servicing_uev;
static int adding_uev; /* uatomic access only */

struct uevent_filter_state {
struct list_head uevq;
Expand All @@ -70,13 +71,14 @@ static void reset_filter_state(struct uevent_filter_state *st)

int is_uevent_busy(void)
{
int empty, servicing;
int empty, servicing, adding;

pthread_mutex_lock(uevq_lockp);
empty = list_empty(&uevq);
servicing = servicing_uev;
adding = uatomic_read(&adding_uev);
pthread_mutex_unlock(uevq_lockp);
return (!empty || servicing);
return (!empty || servicing || adding);
}

struct uevent * alloc_uevent (void)
Expand Down Expand Up @@ -730,6 +732,7 @@ int uevent_listen(struct udev *udev)
int fdcount, events;
struct pollfd ev_poll = { .fd = fd, .events = POLLIN, };

uatomic_set(&adding_uev, 0);
fdcount = poll(&ev_poll, 1, -1);
if (fdcount < 0) {
if (errno == EINTR)
Expand All @@ -739,6 +742,8 @@ int uevent_listen(struct udev *udev)
err = -errno;
break;
}
uatomic_set(&adding_uev, 1);

events = uevent_receive_events(fd, &uevlisten_tmp, monitor);
if (events <= 0)
continue;
Expand Down
4 changes: 2 additions & 2 deletions libmultipath/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
#ifndef VERSION_H_INCLUDED
#define VERSION_H_INCLUDED

#define VERSION_CODE 0x000E00
#define VERSION_CODE 0x000E01
/* MMDDYY, in hex */
#define DATE_CODE 0x01101A
#define DATE_CODE 0x01171A

#define PROG "multipath-tools"

Expand Down
60 changes: 49 additions & 11 deletions multipathd/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,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); \
\
Expand Down Expand Up @@ -2572,6 +2571,26 @@ static int sync_mpp(struct vectors *vecs, struct multipath *mpp, unsigned int ti
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)
{
Expand Down Expand Up @@ -2601,14 +2620,33 @@ update_path_state (struct vectors * vecs, struct path * pp)
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)) {
Expand Down
Loading