Linux SCSI subsystem development
 help / color / mirror / Atom feed
From: John Garry <john.garry@linux.dev>
To: sashiko-reviews@lists.linux.dev, John Garry <john.g.garry@oracle.com>
Cc: linux-scsi@vger.kernel.org
Subject: Re: [PATCH v8 03/27] libmultipath: Add path selection support
Date: Mon, 7 Sep 2026 13:00:13 +0100	[thread overview]
Message-ID: <a710c011-e85d-40f3-a6c5-d8344d608430@linux.dev> (raw)
In-Reply-To: <20260907110926.ED4271F00A3A@smtp.kernel.org>

On 9/7/26 12:09, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
> 
> New issues:
> - [High] Infinite loop in `mpath_round_robin_path()` if the current round-robin path is concurrently removed from the device list, causing an SRCU deadlock.
> - [High] `mpath_round_robin_path` fast-path incorrectly returns an unlinked path, breaking failover.
> - [Medium] Calling `list_is_singular()` on an RCU-protected list without holding the update lock causes a data race on `head->prev`.
> - [Medium] Path selection functions bypass the `.is_optimized` callback, violating the API contract and causing inconsistent path evaluation.
> - [Low] Missing bounds check on iopolicy index in `mpath_get_iopolicy`.
> 
> Pre-existing issues:
> - [Medium] `mpath_device_set_live()` silently swallows setup failures, leaving the driver unaware of the aborted initialization.
> --
> 
> commit 59f56cbf3b60a1ec3a1336f453b4cd772a005e7b
> Author: John Garry <john.garry@linux.dev>
> 
> libmultipath: Add path selection support
> 
> This commit adds path selection support to libmultipath, providing
> round-robin, NUMA, and queue-depth selection modes similar to NVMe. It also
> abstracts NVMe ANA into enum mpath_access_state to allow SCSI ALUA usage
> and introduces iopolicy management functions.
> 
>> diff --git a/lib/multipath.c b/lib/multipath.c
>> index 574868ce53381..3541357d07f8d 100644
>> --- a/lib/multipath.c
>> +++ b/lib/multipath.c
>> @@ -7,8 +7,245 @@
> 
> [ ... ]
> 
>> +int mpath_get_iopolicy(char *buf, int iopolicy)
>> +{
>> +	return sprintf(buf, "%s\n", mpath_iopolicy_names[iopolicy]);
>> +}
> 
> [Severity: Low]
> Does this code overflow mpath_iopolicy_names[] if a caller provides an
> uninitialized or out-of-bounds iopolicy value?

The caller should sanitize iopolicy

> 
> [ ... ]
> 
>> +static struct mpath_device *__mpath_find_path(struct mpath_head *mpath_head,
>> +					int node)
>> +{
>> +	int found_distance = INT_MAX, fallback_distance = INT_MAX, distance;
>> +	struct mpath_device *found = NULL, *fallback = NULL, *mpath_device;
>> +
>> +	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;
> 
> [ ... ]
> 
>> +		switch(mpath_device->access_state) {
>> +		case MPATH_STATE_OPTIMIZED:
> 
> [Severity: Medium]
> Does this code bypass the driver's dynamic state evaluation by accessing
> access_state directly instead of invoking the provided
> mpath_path_is_optimized() callback wrapper?
> 
> If a driver like SCSI ALUA dynamically changes state, this will read
> stale data.

ALUA support will be added later

> 
>> +		    if (distance < found_distance) {
>> +			    found_distance = distance;
>> +			    found = mpath_device;
>> +		    }
>> +		    break;
> 
> [ ... ]
> 
>> +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: Medium]
> Calling list_is_singular() on an RCU-protected list without holding the
> update lock causes a data race on head->prev. In RCU-protected lists,
> only next pointers are safely updated for lockless readers.

locking will be added later

> 
> [Severity: High]
> Does this fast-path blindly return old without verifying if it is actually
> the element present in the singular list?

as above

> 
> If the previously cached old path was concurrently removed from dev_list
> and exactly one valid path remains, list_is_singular() evaluates to true,
> causing the function to incorrectly return the unlinked path instead of
> the remaining valid path.
> 
>> +		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)) {
> 
> [Severity: High]
> Can this loop spin infinitely if old is concurrently removed from the
> RCU-protected list?

as above

> 
> The loop relies on reaching old again to terminate. If a concurrent writer
> unlinks old using list_del_rcu(), it is removed from the circular list but
> its next pointer remains intact. mpath_next_dev() follows old->next into
> the remaining list elements, wrapping around and circling the remaining
> elements indefinitely without ever evaluating mpath_device == old.
> 
> If all remaining paths are non-optimized or disabled, the loop never hits
> the break condition, spinning forever under the SRCU read lock and stalling
> any writer.
> 
>> +
>> +		if (mpath_path_is_disabled(mpath_head, mpath_device))
>> +			continue;
>> +		if (mpath_device->access_state == MPATH_STATE_OPTIMIZED) {
> 
> [Severity: Medium]
> Similar to __mpath_find_path(), does this bypass the driver's dynamic state
> evaluation by accessing access_state directly rather than calling the
> mpath_path_is_optimized() callback wrapper?
> 
>> +			found = mpath_device;
>> +			goto out;
>> +		}
>> +		if (mpath_device->access_state == MPATH_STATE_NONOPTIMIZED)
>> +			found = mpath_device;
>> +	}
> 
> [ ... ]
> 
>> @@ -133,6 +371,19 @@ void mpath_device_set_live(struct mpath_device *mpath_device)
>>   		}
>>   		queue_work(mpath_wq, &mpath_head->partition_scan_work);
>>   	}
> 
> [Severity: Medium]
> This is a pre-existing issue, but does mpath_device_set_live() silently
> swallow setup failures earlier in this function?

Yes, this just minics what NVMe does

> 
> If device_add_disk() fails, for example due to memory exhaustion, the
> function clears the MPATH_HEAD_DISK_LIVE flag and returns early, masking
> the failure from the caller and leaving the driver unaware of the aborted
> initialization.
> 
>> +
>> +	mutex_lock(&mpath_head->lock);
>> +	if (mpath_path_is_optimized(mpath_head, mpath_device)) {
>> +		int node, srcu_idx;
>> +
>> +		srcu_idx = srcu_read_lock(&mpath_head->srcu);
>> +		for_each_online_node(node)
>> +			__mpath_find_path(mpath_head, node);
>> +		srcu_read_unlock(&mpath_head->srcu, srcu_idx);
>> +	}
>> +	mutex_unlock(&mpath_head->lock);
>> +
>> +	mpath_synchronize(mpath_head);
>>   }
> 


  reply	other threads:[~2026-09-07 12:00 UTC|newest]

Thread overview: 48+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-07 10:49 [PATCH v8 00/27] Native SCSI Multipath support John Garry
2026-09-07 10:49 ` [PATCH v8 01/27] libmultipath: Add initial framework John Garry
2026-09-07 10:49 ` [PATCH v8 02/27] libmultipath: Add basic gendisk support John Garry
2026-09-07 10:49 ` [PATCH v8 03/27] libmultipath: Add path selection support John Garry
2026-09-07 11:09   ` sashiko-bot
2026-09-07 12:00     ` John Garry [this message]
2026-09-07 10:49 ` [PATCH v8 04/27] libmultipath: Add bio handling John Garry
2026-09-07 10:49 ` [PATCH v8 05/27] libmultipath: Add support for mpath_device management John Garry
2026-09-07 10:50 ` [PATCH v8 06/27] libmultipath: Add delayed removal support John Garry
2026-09-07 11:23   ` sashiko-bot
2026-09-07 12:01     ` John Garry
2026-09-07 10:50 ` [PATCH v8 07/27] libmultipath: Add sysfs helpers John Garry
2026-09-07 10:50 ` [PATCH v8 08/27] libmultipath: Add support for block device IOCTL John Garry
2026-09-07 10:50 ` [PATCH v8 09/27] libmultipath: Add mpath_bdev_getgeo() John Garry
2026-09-07 10:50 ` [PATCH v8 10/27] libmultipath: Add mpath_bdev_get_unique_id() John Garry
2026-09-07 10:50 ` [PATCH v8 11/27] scsi-multipath: introduce basic SCSI device support John Garry
2026-09-07 11:33   ` sashiko-bot
2026-09-07 12:06     ` John Garry
2026-09-07 10:50 ` [PATCH v8 12/27] scsi-multipath: introduce scsi_device head structure John Garry
2026-09-07 10:50 ` [PATCH v8 13/27] scsi-multipath: provide sysfs link from to scsi_device John Garry
2026-09-07 10:50 ` [PATCH v8 14/27] scsi-multipath: support iopolicy John Garry
2026-09-07 10:50 ` [PATCH v8 15/27] scsi-multipath: clone each bio John Garry
2026-09-07 11:45   ` sashiko-bot
2026-09-07 12:08     ` John Garry
2026-09-07 10:50 ` [PATCH v8 16/27] scsi-multipath: clear path when device is blocked John Garry
2026-09-07 11:49   ` sashiko-bot
2026-09-07 12:08     ` John Garry
2026-09-07 10:50 ` [PATCH v8 17/27] scsi-multipath: revalidate paths upon device unblock John Garry
2026-09-07 11:56   ` sashiko-bot
2026-09-07 12:10     ` John Garry
2026-09-07 10:50 ` [PATCH v8 18/27] scsi-multipath: failover handling John Garry
2026-09-07 12:02   ` sashiko-bot
2026-09-07 12:13     ` John Garry
2026-09-07 10:50 ` [PATCH v8 19/27] scsi-multipath: provide callbacks for path state John Garry
2026-09-07 12:03   ` sashiko-bot
2026-09-07 12:14     ` John Garry
2026-09-07 10:50 ` [PATCH v8 20/27] scsi-multipath: add scsi_mpath_{start,end}_request() John Garry
2026-09-07 12:09   ` sashiko-bot
2026-09-07 12:22     ` John Garry
2026-09-07 10:50 ` [PATCH v8 21/27] scsi-multipath: add delayed disk removal support John Garry
2026-09-07 10:50 ` [PATCH v8 22/27] scsi: sd: add multipath disk class John Garry
2026-09-07 10:50 ` [PATCH v8 23/27] scsi: sd: add multipath disk attr groups John Garry
2026-09-07 10:50 ` [PATCH v8 24/27] scsi: sd: support multipath disk John Garry
2026-09-07 12:25   ` sashiko-bot
2026-09-07 12:34     ` John Garry
2026-09-07 10:50 ` [PATCH v8 25/27] scsi: sd: add mpath_dev file John Garry
2026-09-07 10:50 ` [PATCH v8 26/27] scsi: sd: add mpath_numa_nodes dev attribute John Garry
2026-09-07 10:50 ` [PATCH v8 27/27] scsi: sd: add mpath_queue_depth " 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=a710c011-e85d-40f3-a6c5-d8344d608430@linux.dev \
    --to=john.garry@linux.dev \
    --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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox