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

Commit fb9d114f authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "usb: misc: diag_bridge: Fix races between delete and read/write"

parents aafa440f acae8fd6
Loading
Loading
Loading
Loading
+23 −11
Original line number Diff line number Diff line
@@ -41,7 +41,6 @@ struct diag_bridge {
	__u8			out_epAddr;
	int			err;
	struct kref		kref;
	struct mutex		ifc_mutex;
	struct diag_bridge_ops	*ops;
	struct platform_device	*pdev;
	unsigned int		default_autosusp_delay;
@@ -59,6 +58,7 @@ struct diag_bridge {
	unsigned int		drop_count;
};
struct diag_bridge *__dev[MAX_DIAG_BRIDGE_DEVS];
static struct mutex diag_bridge_mutex[MAX_DIAG_BRIDGE_DEVS];

int diag_bridge_open(int id, struct diag_bridge_ops *ops)
{
@@ -106,11 +106,13 @@ static void diag_bridge_delete(struct kref *kref)
	int id = dev->id;

	dev_dbg(&dev->ifc->dev, "%s\n", __func__);
	mutex_lock(&diag_bridge_mutex[id]);
	usb_set_intfdata(ifc, NULL);
	usb_put_intf(ifc);
	usb_put_dev(dev->udev);
	__dev[id] = 0;
	kfree(dev);
	mutex_unlock(&diag_bridge_mutex[id]);
}

void diag_bridge_close(int id)
@@ -185,13 +187,14 @@ int diag_bridge_read(int id, char *data, int size)

	pr_debug("reading %d bytes\n", size);

	mutex_lock(&diag_bridge_mutex[id]);
	dev = __dev[id];
	if (!dev) {
		pr_err("device is disconnected\n");
		return -ENODEV;
		ret = -ENODEV;
		goto error;
	}

	mutex_lock(&dev->ifc_mutex);
	if (!dev->ifc) {
		pr_err("device is disconnected\n");
		ret = -ENODEV;
@@ -257,7 +260,7 @@ int diag_bridge_read(int id, char *data, int size)

	usb_autopm_put_interface(dev->ifc);
	usb_free_urb(urb);
	mutex_unlock(&dev->ifc_mutex);
	mutex_unlock(&diag_bridge_mutex[id]);
	return ret;

free_error:
@@ -266,7 +269,7 @@ int diag_bridge_read(int id, char *data, int size)
	/* If URB submit successful, this is done in the completion handler */
	kref_put(&dev->kref, diag_bridge_delete);
error:
	mutex_unlock(&dev->ifc_mutex);
	mutex_unlock(&diag_bridge_mutex[id]);
	return ret;
}
EXPORT_SYMBOL(diag_bridge_read);
@@ -309,13 +312,14 @@ int diag_bridge_write(int id, char *data, int size)

	pr_debug("writing %d bytes\n", size);

	mutex_lock(&diag_bridge_mutex[id]);
	dev = __dev[id];
	if (!dev) {
		pr_err("device is disconnected\n");
		return -ENODEV;
		ret = -ENODEV;
		goto error;
	}

	mutex_lock(&dev->ifc_mutex);
	if (!dev->ifc) {
		pr_err("device is disconnected\n");
		ret = -ENODEV;
@@ -373,7 +377,7 @@ int diag_bridge_write(int id, char *data, int size)
	}

	usb_free_urb(urb);
	mutex_unlock(&dev->ifc_mutex);
	mutex_unlock(&diag_bridge_mutex[id]);
	return ret;

free_error:
@@ -382,7 +386,7 @@ int diag_bridge_write(int id, char *data, int size)
	/* If URB submit successful, this is done in the completion handler */
	kref_put(&dev->kref, diag_bridge_delete);
error:
	mutex_unlock(&dev->ifc_mutex);
	mutex_unlock(&diag_bridge_mutex[id]);
	return ret;
}
EXPORT_SYMBOL(diag_bridge_write);
@@ -505,7 +509,6 @@ diag_bridge_probe(struct usb_interface *ifc, const struct usb_device_id *id)
	dev->udev = usb_get_dev(interface_to_usbdev(ifc));
	dev->ifc = usb_get_intf(ifc);
	kref_init(&dev->kref);
	mutex_init(&dev->ifc_mutex);
	init_usb_anchor(&dev->submitted);

	ifc_desc = ifc->cur_altsetting;
@@ -656,11 +659,16 @@ static struct usb_driver diag_bridge_driver = {

static int __init diag_bridge_init(void)
{
	int ret;
	int ret, i;

	for (i = 0; i < MAX_DIAG_BRIDGE_DEVS; i++)
		mutex_init(&diag_bridge_mutex[i]);

	ret = usb_register(&diag_bridge_driver);
	if (ret) {
		pr_err("unable to register diag driver\n");
		for (i = 0; i < MAX_DIAG_BRIDGE_DEVS; i++)
			mutex_destroy(&diag_bridge_mutex[i]);
		return ret;
	}

@@ -669,7 +677,11 @@ static int __init diag_bridge_init(void)

static void __exit diag_bridge_exit(void)
{
	int i;

	usb_deregister(&diag_bridge_driver);
	for (i = 0; i < MAX_DIAG_BRIDGE_DEVS; i++)
		mutex_destroy(&diag_bridge_mutex[i]);
}

module_init(diag_bridge_init);