Re: [PATCH v6 03/27] libmultipath: Add path selection support
John Garry <[email protected]> Wed, 29 Jul 2026 12:41:53 +0100
| Newsgroups | dev.linux.lists.sashiko-reviews,org.kernel.vger.linux-scsi |
|---|---|
| Organization | Oracle Corporation |
| Message-ID | <[email protected]> |
On 29/07/2026 12:33, [email protected] wrote: > Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider: > > New issues: > - [High] Round-robin path selection behaves as reverse round-robin for non-optimized paths due to a missing loop break. > - [High] Unsafe and logically flawed use of `list_is_singular` on an RCU-protected list routes I/O to a removed device. > > Pre-existing issues: > - [High] mpath_head_uninit() blocks indefinitely waiting for user-space to close the block device. > -- > > --- Patch [3]: [PATCH v6 03/27] libmultipath: Add path selection support --- > commit 70a41be1b0a598af8cbd34732b889f79118d17ac > Author: John Garry <[email protected]> > > libmultipath: Add path selection support > > This commit adds code for path selection support in libmultipath. It abstracts > NVMe ANA into mpath_access_state to allow SCSI ALUA usage and adds round-robin, > NUMA, and queue-depth selection modes. It also introduces functions to set and > get the default I/O policy. > >> diff --git a/lib/multipath.c b/lib/multipath.c >> index 1cf20b0f62d07..26714116023a3 100644 >> --- a/lib/multipath.c >> +++ b/lib/multipath.c > > [ ... ] > >> @@ -7,8 +7,245 @@ >> +static struct mpath_device *mpath_round_robin_path( >> + struct mpath_head *mpath_head) >> +{ >> + struct mpath_device *mpath_device, *found = NULL; >> + int node = numa_node_id(); >> + enum mpath_access_state access_state_old; >> + struct mpath_device *old = >> + srcu_dereference(mpath_head->current_path[node], >> + &mpath_head->srcu); >> + >> + if (unlikely(!old)) >> + return __mpath_find_path(mpath_head, node); >> + >> + if (list_is_singular(&mpath_head->dev_list)) { > > [Severity: High] > Does using list_is_singular() here on an SRCU-protected list introduce a data > race on head->prev? locking is added later > > Additionally, if old is concurrently removed and exactly one other active > device remains in the list, list_is_singular() evaluates to true. Will this > cause the function to return the unlinked old path instead of the valid > active path? as above > >> + if (mpath_path_is_disabled(mpath_head, old)) >> + return NULL; >> + return old; >> + } >> + >> + for (mpath_device = mpath_next_dev(mpath_head, old); >> + mpath_device && mpath_device != old; >> + mpath_device = mpath_next_dev(mpath_head, mpath_device)) { >> + >> + if (mpath_path_is_disabled(mpath_head, mpath_device)) >> + continue; >> + if (mpath_device->access_state == MPATH_STATE_OPTIMIZED) { >> + found = mpath_device; >> + goto out; >> + } >> + if (mpath_device->access_state == MPATH_STATE_NONOPTIMIZED) >> + found = mpath_device; > > [Severity: High] > For the MPATH_STATE_NONOPTIMIZED case, found is overwritten unconditionally. > Because there is no loop break or check like if (!found), will this > evaluate multiple non-optimized paths and incorrectly select the last > available one rather than the next available one? I think so, but no one cares about non-optimized. Again, this is same as NVMe code. > >> + } > > [ ... ] > > [Severity: High] > This is a pre-existing issue, but I noticed a potential problem during > teardown in mpath_head_uninit(): > > lib/multipath.c:mpath_head_uninit() { > ... > if (!refcount_dec_and_test(refcount)) > wait_var_event(refcount, !refcount_read(refcount)); > } > > Since a reference is taken for every user-space open, can wait_var_event() > block indefinitely if a user process holds the device open while the > driver is unbound or the device is hot-unplugged? yes, but that is just the way it is - userspace needs to drop the ref >