Hi Hillf
Thanks for the heads up
On Tue, 3 Jan 2023 at 03:25, Hillf Danton hdanton@sina.com wrote:
On 02 Jan 2023 15:48:01 +0100 Ricardo Ribalda ribalda@chromium.org
--- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -1442,6 +1442,9 @@ static void uvc_ctrl_status_event_work(struct work_struct *work)
uvc_ctrl_status_event(w->chain, w->ctrl, w->data);
if (dev->flush_status)
return;
/* Resubmit the URB. */ w->urb->interval = dev->int_ep->desc.bInterval; ret = usb_submit_urb(w->urb, GFP_KERNEL);
diff --git a/drivers/media/usb/uvc/uvc_status.c b/drivers/media/usb/uvc/uvc_status.c index 7518ffce22ed..e457889345a3 100644 --- a/drivers/media/usb/uvc/uvc_status.c +++ b/drivers/media/usb/uvc/uvc_status.c @@ -6,6 +6,7 @@
Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*/
+#include <asm/barrier.h> #include <linux/kernel.h> #include <linux/input.h> #include <linux/slab.h> @@ -309,5 +310,44 @@ int uvc_status_start(struct uvc_device *dev, gfp_t flags)
void uvc_status_stop(struct uvc_device *dev) {
struct uvc_ctrl_work *w = &dev->async_ctrl;
/* Prevent the asynchronous control handler from requeing the URB */
dev->flush_status = true;
/*
* The barrier is needed so the flush_status change is visible to other
* CPUs running the asynchronous handler before usb_kill_urb() is
* called below.
*/
smp_mb();
Given unpaired mb, take a look at the release/acquire memory barrier pairing in c5b2cbdbdac5 ("ipc/mqueue.c: update/document memory barriers")
Would it work? to replace:
dev->flush_status = true; smp_mb();
with: smp_store_release(&dev->flush_status, 1);
and then read it always with:
smp_load_acquire(&dev->flush_status);
Thanks!
/* If there is any status event on the queue, process it. */
if (cancel_work_sync(&w->work))
uvc_ctrl_status_event(w->chain, w->ctrl, w->data);
/* Kill the urb. */ usb_kill_urb(dev->int_urb);
/*
* The URB completion handler may have queued asynchronous work. This
* won't resubmit the URB as flush_status is set, but it needs to be
* cancelled before returning or it could then race with a future
* uvc_status_start() call.
*/
if (cancel_work_sync(&w->work))
uvc_ctrl_status_event(w->chain, w->ctrl, w->data);
/*
* From this point, there are no events on the queue and the status URB
* is dead, this is, no events will be queued until uvc_status_start()
* is called.
*/
dev->flush_status = false;
/*
* Write to memory the value of flush_status before uvc_status_start()
* is called again.
*/
smp_mb();
}
linux-stable-mirror@lists.linaro.org