From: sashiko-bot@kernel.org
To: "John Garry" <john.g.garry@oracle.com>
Cc: linux-scsi@vger.kernel.org
Subject: Re: [PATCH v3 03/13] libmultipath: Add path selection support
Date: Fri, 03 Jul 2026 10:45:55 +0000 [thread overview]
Message-ID: <20260703104556.AC6B71F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260703102918.3723667-4-john.g.garry@oracle.com>
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
- [High] `mpath_round_robin_path` enters an infinite loop if the current cached path (`old`) is concurrently removed.
- [High] Unsafe usage of `list_is_singular()` on an RCU list leads to data races and routes I/O to a removed path.
- [High] `mpath_numa_path` fails to verify if the cached path is disabled before returning it, potentially routing I/O to a disabled path.
- [High] `mpath_alloc_head_disk` leaves an ERR_PTR in `mpath_head->disk` on failure, causing cleanup paths to crash.
- [Medium] NULL pointer dereference in `mpath_queue_depth_path` if a device does not provide `nr_active`.
- [Medium] The `.get_access_state` callback is missing from `struct mpath_head_template`, violating the documented API intent.
--
commit e941f797884516dd9568e0b668984eb3c895248a
Author: John Garry <john.g.garry@oracle.com>
libmultipath: Add path selection support
Add code for path selection.
> NVMe ANA is abstracted into enum mpath_access_state. The motivation here is
> so that SCSI ALUA can be used. Callbacks .is_disabled, .is_optimized,
> .get_access_state are added to get the path access state.
[Severity: Medium]
The commit message mentions adding a .get_access_state callback, but it appears
to be missing from struct mpath_head_template. Is this intentional, or should
it be included in the struct definition to avoid requiring drivers to directly
modify the access_state field?
[ ... ]
> diff --git a/lib/multipath.c b/lib/multipath.c
> index 79be84d3d4f75..21f7ffdb22d60 100644
> --- a/lib/multipath.c
> +++ b/lib/multipath.c
[ ... ]
> +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)) {
> + if (mpath_path_is_disabled(mpath_head, old))
> + return NULL;
> + return old;
> + }
[Severity: High]
Could using list_is_singular() here lead to data races? Since this list is
managed with RCU, and list_is_singular() evaluates head->next == head->prev,
it might read inconsistent prev pointers during concurrent updates. Also, if old
was concurrently removed and only one valid path remains, would this return
the removed old path instead of the new remaining path?
> +
> + for (mpath_device = mpath_next_dev(mpath_head, old);
> + mpath_device && mpath_device != old;
> + mpath_device = mpath_next_dev(mpath_head, mpath_device)) {
[Severity: High]
Does this loop terminate safely if old has been concurrently removed from the list?
If old is unlinked via list_del_rcu(), mpath_device != old will always be true.
Could this result in an infinite loop wrapping around the active elements
indefinitely, leading to a lockup if no path is MPATH_STATE_OPTIMIZED?
> +
> + if (mpath_path_is_disabled(mpath_head, mpath_device))
> + continue;
[ ... ]
> +static struct mpath_device *mpath_queue_depth_path(
> + struct mpath_head *mpath_head)
> +{
> + struct mpath_device *best_opt = NULL, *mpath_device;
> + struct mpath_device *best_nonopt = NULL;
> + unsigned int min_depth_opt = UINT_MAX, min_depth_nonopt = UINT_MAX;
> + unsigned int depth;
> +
> + list_for_each_entry_srcu(mpath_device, &mpath_head->dev_list, siblings,
> + srcu_read_lock_held(&mpath_head->srcu)) {
> +
> + if (mpath_path_is_disabled(mpath_head, mpath_device))
> + continue;
> +
> + depth = atomic_read(mpath_device->nr_active);
[Severity: Medium]
Could this dereference a NULL pointer if a device was added without providing
an nr_active atomic counter during mpath_add_device()? If userspace sets the
I/O policy to 'queue-depth' via sysfs, would it crash here?
> +
> + switch (mpath_device->access_state) {
[ ... ]
> +static struct mpath_device *mpath_numa_path(struct mpath_head *mpath_head)
> +{
> + int node = numa_node_id();
> + struct mpath_device *mpath_device;
> +
> + mpath_device = srcu_dereference(mpath_head->current_path[node],
> + &mpath_head->srcu);
> + if (unlikely(!mpath_device))
> + return __mpath_find_path(mpath_head, node);
> + if (unlikely(!mpath_path_is_optimized(mpath_head, mpath_device)))
> + return __mpath_find_path(mpath_head, node);
> + return mpath_device;
> +}
[Severity: High]
Does this correctly validate the cached path before returning it? Unlike other
path selection functions, this omits checking mpath_path_is_disabled().
If a path transitions to a disabled state but remains marked as optimized, could
mpath_numa_path() incorrectly continue to route I/O to it?
[ ... ]
> @@ -103,7 +339,8 @@ EXPORT_SYMBOL_GPL(mpath_put_disk);
> int mpath_alloc_head_disk(struct mpath_head *mpath_head,
> struct queue_limits *lim, int numa_node)
> {
> - if (!mpath_head->disk_groups || !mpath_head->parent)
> + if (!mpath_head->disk_groups || !mpath_head->parent ||
> + !mpath_head->iopolicy)
> return -EINVAL;
>
> mpath_head->disk = blk_alloc_disk(lim, numa_node);
[Severity: High]
If blk_alloc_disk() fails, it returns an ERR_PTR. If this is assigned directly
to mpath_head->disk and an error is returned without setting mpath_head->disk
back to NULL, could this cause subsequent cleanup paths (like mpath_put_disk())
to crash when they check if (mpath_head->disk) and attempt to put an ERR_PTR?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260703102918.3723667-1-john.g.garry@oracle.com?part=3
next prev parent reply other threads:[~2026-07-03 10:45 UTC|newest]
Thread overview: 33+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-03 10:29 [PATCH v3 00/13] libmultipath: a generic multipath lib for block drivers John Garry
2026-07-03 10:29 ` [PATCH v3 01/13] libmultipath: Add initial framework John Garry
2026-07-03 10:43 ` sashiko-bot
2026-07-03 14:06 ` John Garry
2026-07-03 10:29 ` [PATCH v3 02/13] libmultipath: Add basic gendisk support John Garry
2026-07-03 10:51 ` sashiko-bot
2026-07-03 14:19 ` John Garry
2026-07-03 10:29 ` [PATCH v3 03/13] libmultipath: Add path selection support John Garry
2026-07-03 10:45 ` sashiko-bot [this message]
2026-07-03 14:37 ` John Garry
2026-07-03 10:29 ` [PATCH v3 04/13] libmultipath: Add bio handling John Garry
2026-07-03 10:49 ` sashiko-bot
2026-07-03 14:48 ` John Garry
2026-07-03 10:29 ` [PATCH v3 05/13] libmultipath: Add support for mpath_device management John Garry
2026-07-03 10:29 ` [PATCH v3 06/13] libmultipath: Add delayed removal support John Garry
2026-07-03 10:45 ` sashiko-bot
2026-07-03 15:18 ` John Garry
2026-07-03 10:29 ` [PATCH v3 07/13] libmultipath: Add cdev support John Garry
2026-07-03 10:48 ` sashiko-bot
2026-07-06 10:26 ` John Garry
2026-07-03 10:29 ` [PATCH v3 08/13] libmultipath: Add sysfs helpers John Garry
2026-07-03 10:44 ` sashiko-bot
2026-07-06 13:57 ` John Garry
2026-07-03 10:29 ` [PATCH v3 09/13] libmultipath: Add PR support John Garry
2026-07-03 10:48 ` sashiko-bot
2026-07-06 14:12 ` John Garry
2026-07-03 10:29 ` [PATCH v3 10/13] libmultipath: Add mpath_bdev_report_zones() John Garry
2026-07-03 10:29 ` [PATCH v3 11/13] libmultipath: Add support for block device IOCTL John Garry
2026-07-03 10:56 ` sashiko-bot
2026-07-06 14:16 ` John Garry
2026-07-03 10:29 ` [PATCH v3 12/13] libmultipath: Add mpath_bdev_getgeo() John Garry
2026-07-03 10:54 ` sashiko-bot
2026-07-03 10:29 ` [PATCH v3 13/13] libmultipath: Add mpath_bdev_get_unique_id() John Garry
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260703104556.AC6B71F000E9@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=john.g.garry@oracle.com \
--cc=linux-scsi@vger.kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.