Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 36e59e0d authored by Oliver Neukum's avatar Oliver Neukum Committed by Greg Kroah-Hartman
Browse files

cdc-acm: fix race between callback and unthrottle



Abn URB may be may marked free only after the buffer has been
processed or there is a small window during which it could
be submitted on another CPU and overwrite an unprocessed buffer

Signed-off-by: default avatarOliver Neukum <oneukum@suse.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent c0ab6bb0
Loading
Loading
Loading
Loading
+10 −2
Original line number Original line Diff line number Diff line
@@ -417,25 +417,33 @@ static void acm_read_bulk_callback(struct urb *urb)
	struct acm_rb *rb = urb->context;
	struct acm_rb *rb = urb->context;
	struct acm *acm = rb->instance;
	struct acm *acm = rb->instance;
	unsigned long flags;
	unsigned long flags;
	int status = urb->status;


	dev_vdbg(&acm->data->dev, "%s - urb %d, len %d\n", __func__,
	dev_vdbg(&acm->data->dev, "%s - urb %d, len %d\n", __func__,
					rb->index, urb->actual_length);
					rb->index, urb->actual_length);
	set_bit(rb->index, &acm->read_urbs_free);


	if (!acm->dev) {
	if (!acm->dev) {
		set_bit(rb->index, &acm->read_urbs_free);
		dev_dbg(&acm->data->dev, "%s - disconnected\n", __func__);
		dev_dbg(&acm->data->dev, "%s - disconnected\n", __func__);
		return;
		return;
	}
	}


	if (urb->status) {
	if (urb->status) {
		set_bit(rb->index, &acm->read_urbs_free);
		dev_dbg(&acm->data->dev, "%s - non-zero urb status: %d\n",
		dev_dbg(&acm->data->dev, "%s - non-zero urb status: %d\n",
							__func__, urb->status);
							__func__, status);
		return;
		return;
	}
	}


	usb_mark_last_busy(acm->dev);
	usb_mark_last_busy(acm->dev);


	acm_process_read_urb(acm, urb);
	acm_process_read_urb(acm, urb);
	/*
	 * Unthrottle may run on another CPU which needs to see events
	 * in the same order. Submission has an implict barrier
	 */
	smp_mb__before_atomic();
	set_bit(rb->index, &acm->read_urbs_free);


	/* throttle device if requested by tty */
	/* throttle device if requested by tty */
	spin_lock_irqsave(&acm->read_lock, flags);
	spin_lock_irqsave(&acm->read_lock, flags);