All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Shuai Liu" <847807867@qq.com>
Cc: linux-usb@vger.kernel.org
Subject: Re: [PATCH v2] usb: storage: don't hold dev_mutex across the max_lun control transfer
Date: Mon, 09 Nov 2026 00:13:15 +0000	[thread overview]
Message-ID: <sashiko-outbox-204202@kernel.org> (raw)
In-Reply-To: <tencent_5A9A9E45415EADE916B7558C66A2C4DD4F05@qq.com>

Thank you for your contribution! Sashiko AI review found 1 potential
issue to consider:
- [High] usb: storage: unlocked usb_stor_Bulk_max_lun() races with reset
  and I/O
--

commit f8913af4317f2585b6b4e25b82f0040382c7198c
Author: Shuai Liu <847807867@qq.com>

usb: storage: don't hold dev_mutex across the max_lun control transfer

This commit changes usb_stor_Bulk_max_lun() to use usb_control_msg_recv()
and calls it outside us->dev_mutex in usb_stor_scan_dwork().

> diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
> index 823a4b2e9033b..d973bfd0f23d1 100644
> --- a/drivers/usb/storage/usb.c
> +++ b/drivers/usb/storage/usb.c
> @@ -980,19 +980,26 @@ static void usb_stor_scan_dwork(struct work_struct *work)
>  
>  	dev_dbg(dev, "starting scan\n");
>  
> -	/* For bulk-only devices, determine the max LUN value */
> +	/*
> +	 * For bulk-only devices, determine the max LUN value.
> +	 * usb_stor_Bulk_max_lun() sleeps in a synchronous transfer, so it
> +	 * must not run under us->dev_mutex (the reset path takes dev_mutex
> +	 * while holding the device lock).  Lock only to publish the result.
> +	 */
>  	if (us->protocol == USB_PR_BULK &&
>  	    !(us->fflags & US_FL_SINGLE_LUN) &&
>  	    !(us->fflags & US_FL_SCM_MULT_TARG)) {
> +		int max_lun = usb_stor_Bulk_max_lun(us);
> +
>  		mutex_lock(&us->dev_mutex);
> -		us->max_lun = usb_stor_Bulk_max_lun(us);
> +		us->max_lun = max_lun;
>  		/*
>  		 * Allow proper scanning of devices that present more than 8 LUNs
>  		 * While not affecting other devices that may need the previous
>  		 * behavior
>  		 */
> -		if (us->max_lun >= 8)
> -			us_to_host(us)->max_lun = us->max_lun+1;
> +		if (max_lun >= 8)
> +			us_to_host(us)->max_lun = max_lun + 1;
>  		mutex_unlock(&us->dev_mutex);
>  	}

[Severity: High]
Does calling usb_stor_Bulk_max_lun() without us->dev_mutex break the
quiescence contract of usb_stor_pre_reset() and usb_stor_suspend(), and
race with concurrent resets or SCSI commands?

usb_stor_pre_reset() and usb_stor_suspend() take us->dev_mutex to ensure
all driver URBs have completed and no new URBs are submitted during reset
or suspend:

drivers/usb/storage/usb.c:usb_stor_pre_reset() {
	struct us_data *us = usb_get_intfdata(iface);

	/* Make sure no command runs during the reset */
	mutex_lock(&us->dev_mutex);
	return 0;
}

With usb_stor_Bulk_max_lun() unlocked:

CPU0 (scan_dwork)                 CPU1 (usb_reset_device)
usb_stor_scan_dwork()
                                  usb_stor_pre_reset()
                                    mutex_lock(&us->dev_mutex)
                                  usb_reset_and_verify_device()
                                    hub_port_reset()
  usb_stor_Bulk_max_lun()
    usb_control_msg_recv()  <-- EP0 transfer runs during reset and fails
                                  usb_stor_post_reset()
                                    mutex_unlock(&us->dev_mutex)
  mutex_lock(&us->dev_mutex)
  us->max_lun = 0;          <-- LUNs > 0 permanently lost

Instead of waiting on us->dev_mutex for usb_stor_post_reset() to finish,
usb_control_msg_recv() runs during port reset and EP0 re-enumeration,
fails, and causes usb_stor_Bulk_max_lun() to return 0, hiding all LUNs
above 0 on multi-LUN devices.  Because scsi_add_host() is called in
usb_stor_probe2() before scan_dwork runs, an unlocked GET_MAX_LUN can also
run concurrently on the device with Bulk-Only transfers and resets in
usb_stor_control_thread() and device_reset().

Also, is the ABBA deadlock described in the comment and commit message
possible?  Neither usb_stor_control_msg() nor usb_submit_urb() acquires
udev->dev.mutex, and quiesce_and_remove_host() never takes us->dev_mutex
either; it waits in cancel_delayed_work_sync(&us->scan_dwork) for the work
item to finish, while switching from usb_stor_control_msg() to
usb_control_msg_recv() makes the 10-second wait uninterruptible and no
longer abortable via US_FLIDX_ABORTING.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/tencent_5A9A9E45415EADE916B7558C66A2C4DD4F05@qq.com?part=1

  reply	other threads:[~2026-11-09  0:13 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-08 23:53 [PATCH v2] usb: storage: don't hold dev_mutex across the max_lun control transfer Shuai Liu
2026-11-09  0:13 ` sashiko-bot [this message]
2026-11-09  2:10 ` [usb-storage] " Alan Stern
2026-11-09 11:06   ` Shuai Liu

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=sashiko-outbox-204202@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=847807867@qq.com \
    --cc=linux-usb@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.