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

Commit a394115f authored by Elson Roy Serrao's avatar Elson Roy Serrao Committed by Mayank Rana
Browse files

usb: f_qdss: Handle async completion of requests during qdss_close



When qdss_close is called we try to dequeue the pending and started
requests and then free those requests. But when async completion is
enabled the completion callback could be called after freeing up
that request which may lead to list corruption. Handle this by
ensuring that the requests are freed only after the completion
callback is done for all the requests.

Change-Id: I3e5b1bad06f281422a71c84a617feb65027c2c84
Signed-off-by: default avatarElson Roy Serrao <eserrao@codeaurora.org>
Signed-off-by: default avatarMayank Rana <mrana@codeaurora.org>
parent c1b69818
Loading
Loading
Loading
Loading
+7 −6
Original line number Diff line number Diff line
@@ -242,6 +242,7 @@ static void qdss_write_complete(struct usb_ep *ep,
	if (!qdss->debug_inface_enabled)
		list_del(&req->list);
	list_add_tail(&req->list, list_pool);
	complete(&d_req->write_done);
	if (req->length != 0) {
		d_req->actual = req->actual;
		d_req->status = req->status;
@@ -943,10 +944,12 @@ int usb_qdss_write(struct usb_qdss_ch *ch, struct qdss_request *d_req)
	req->sg = d_req->sg;
	req->num_sgs = d_req->num_sgs;
	req->num_mapped_sgs = d_req->num_mapped_sgs;
	reinit_completion(&d_req->write_done);
	if (usb_ep_queue(qdss->port.data, req, GFP_ATOMIC)) {
		spin_lock_irqsave(&qdss->lock, flags);
		/* Remove from queued pool and add back to data pool */
		list_move_tail(&req->list, &qdss->data_write_pool);
		complete(&d_req->write_done);
		spin_unlock_irqrestore(&qdss->lock, flags);
		pr_err("qdss usb_ep_queue failed\n");
		return -EIO;
@@ -1011,7 +1014,7 @@ void usb_qdss_close(struct usb_qdss_ch *ch)
	unsigned long flags;
	int status;
	struct usb_request *req;

	struct qdss_request *d_req;

	pr_debug("%s\n", __func__);

@@ -1028,12 +1031,10 @@ void usb_qdss_close(struct usb_qdss_ch *ch)
	while (!list_empty(&qdss->queued_data_pool)) {
		req = list_first_entry(&qdss->queued_data_pool,
				struct usb_request, list);
		d_req = req->context;
		spin_unlock_irqrestore(&qdss_lock, flags);
		if (usb_ep_dequeue(qdss->port.data, req)) {
			spin_lock_irqsave(&qdss_lock, flags);
			list_move_tail(&req->list, &qdss->data_write_pool);
			spin_unlock_irqrestore(&qdss_lock, flags);
		}
		usb_ep_dequeue(qdss->port.data, req);
		wait_for_completion(&d_req->write_done);
		spin_lock_irqsave(&qdss_lock, flags);
	}

+2 −1
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2012-2013, 2017-2019 The Linux Foundation. All rights reserved.
 * Copyright (c) 2012-2013, 2017-2020 The Linux Foundation. All rights reserved.
 */

#ifndef __LINUX_USB_QDSS_H
@@ -22,6 +22,7 @@ struct qdss_request {
	struct scatterlist *sg;
	unsigned int num_sgs;
	unsigned int num_mapped_sgs;
	struct completion write_done;
};

struct usb_qdss_ch {