Commit 21619792 authored by Andrew Goodbody's avatar Andrew Goodbody Committed by Greg Kroah-Hartman

usb: usbip: Fix possible deadlocks reported by lockdep

Change spin_lock calls to spin_lock_irqsave to prevent
attmpted recursive lock taking in interrupt context.

This patch fixes Bug 109351
  https://bugzilla.kernel.org/show_bug.cgi?id=109351Signed-off-by: default avatarAndrew Goodbody <andrew.goodbody@cambrionix.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 46e3cafb
......@@ -117,11 +117,12 @@ EXPORT_SYMBOL_GPL(usbip_event_add);
int usbip_event_happened(struct usbip_device *ud)
{
int happened = 0;
unsigned long flags;
spin_lock(&ud->lock);
spin_lock_irqsave(&ud->lock, flags);
if (ud->event != 0)
happened = 1;
spin_unlock(&ud->lock);
spin_unlock_irqrestore(&ud->lock, flags);
return happened;
}
......
This diff is collapsed.
......@@ -72,10 +72,11 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev,
{
struct usbip_device *ud = &vdev->ud;
struct urb *urb;
unsigned long flags;
spin_lock(&vdev->priv_lock);
spin_lock_irqsave(&vdev->priv_lock, flags);
urb = pickup_urb_and_free_priv(vdev, pdu->base.seqnum);
spin_unlock(&vdev->priv_lock);
spin_unlock_irqrestore(&vdev->priv_lock, flags);
if (!urb) {
pr_err("cannot find a urb of seqnum %u\n", pdu->base.seqnum);
......@@ -104,9 +105,9 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev,
usbip_dbg_vhci_rx("now giveback urb %p\n", urb);
spin_lock(&the_controller->lock);
spin_lock_irqsave(&the_controller->lock, flags);
usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb);
spin_unlock(&the_controller->lock);
spin_unlock_irqrestore(&the_controller->lock, flags);
usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, urb->status);
......@@ -117,8 +118,9 @@ static struct vhci_unlink *dequeue_pending_unlink(struct vhci_device *vdev,
struct usbip_header *pdu)
{
struct vhci_unlink *unlink, *tmp;
unsigned long flags;
spin_lock(&vdev->priv_lock);
spin_lock_irqsave(&vdev->priv_lock, flags);
list_for_each_entry_safe(unlink, tmp, &vdev->unlink_rx, list) {
pr_info("unlink->seqnum %lu\n", unlink->seqnum);
......@@ -127,12 +129,12 @@ static struct vhci_unlink *dequeue_pending_unlink(struct vhci_device *vdev,
unlink->seqnum);
list_del(&unlink->list);
spin_unlock(&vdev->priv_lock);
spin_unlock_irqrestore(&vdev->priv_lock, flags);
return unlink;
}
}
spin_unlock(&vdev->priv_lock);
spin_unlock_irqrestore(&vdev->priv_lock, flags);
return NULL;
}
......@@ -142,6 +144,7 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev,
{
struct vhci_unlink *unlink;
struct urb *urb;
unsigned long flags;
usbip_dump_header(pdu);
......@@ -152,9 +155,9 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev,
return;
}
spin_lock(&vdev->priv_lock);
spin_lock_irqsave(&vdev->priv_lock, flags);
urb = pickup_urb_and_free_priv(vdev, unlink->unlink_seqnum);
spin_unlock(&vdev->priv_lock);
spin_unlock_irqrestore(&vdev->priv_lock, flags);
if (!urb) {
/*
......@@ -171,9 +174,9 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev,
urb->status = pdu->u.ret_unlink.status;
pr_info("urb->status %d\n", urb->status);
spin_lock(&the_controller->lock);
spin_lock_irqsave(&the_controller->lock, flags);
usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb);
spin_unlock(&the_controller->lock);
spin_unlock_irqrestore(&the_controller->lock, flags);
usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb,
urb->status);
......@@ -185,10 +188,11 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev,
static int vhci_priv_tx_empty(struct vhci_device *vdev)
{
int empty = 0;
unsigned long flags;
spin_lock(&vdev->priv_lock);
spin_lock_irqsave(&vdev->priv_lock, flags);
empty = list_empty(&vdev->priv_rx);
spin_unlock(&vdev->priv_lock);
spin_unlock_irqrestore(&vdev->priv_lock, flags);
return empty;
}
......
......@@ -32,10 +32,11 @@ static ssize_t status_show(struct device *dev, struct device_attribute *attr,
{
char *s = out;
int i = 0;
unsigned long flags;
BUG_ON(!the_controller || !out);
spin_lock(&the_controller->lock);
spin_lock_irqsave(&the_controller->lock, flags);
/*
* output example:
......@@ -70,7 +71,7 @@ static ssize_t status_show(struct device *dev, struct device_attribute *attr,
spin_unlock(&vdev->ud.lock);
}
spin_unlock(&the_controller->lock);
spin_unlock_irqrestore(&the_controller->lock, flags);
return out - s;
}
......@@ -80,11 +81,12 @@ static DEVICE_ATTR_RO(status);
static int vhci_port_disconnect(__u32 rhport)
{
struct vhci_device *vdev;
unsigned long flags;
usbip_dbg_vhci_sysfs("enter\n");
/* lock */
spin_lock(&the_controller->lock);
spin_lock_irqsave(&the_controller->lock, flags);
vdev = port_to_vdev(rhport);
......@@ -94,14 +96,14 @@ static int vhci_port_disconnect(__u32 rhport)
/* unlock */
spin_unlock(&vdev->ud.lock);
spin_unlock(&the_controller->lock);
spin_unlock_irqrestore(&the_controller->lock, flags);
return -EINVAL;
}
/* unlock */
spin_unlock(&vdev->ud.lock);
spin_unlock(&the_controller->lock);
spin_unlock_irqrestore(&the_controller->lock, flags);
usbip_event_add(&vdev->ud, VDEV_EVENT_DOWN);
......@@ -177,6 +179,7 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr,
int sockfd = 0;
__u32 rhport = 0, devid = 0, speed = 0;
int err;
unsigned long flags;
/*
* @rhport: port number of vhci_hcd
......@@ -202,14 +205,14 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr,
/* now need lock until setting vdev status as used */
/* begin a lock */
spin_lock(&the_controller->lock);
spin_lock_irqsave(&the_controller->lock, flags);
vdev = port_to_vdev(rhport);
spin_lock(&vdev->ud.lock);
if (vdev->ud.status != VDEV_ST_NULL) {
/* end of the lock */
spin_unlock(&vdev->ud.lock);
spin_unlock(&the_controller->lock);
spin_unlock_irqrestore(&the_controller->lock, flags);
sockfd_put(socket);
......@@ -227,7 +230,7 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr,
vdev->ud.status = VDEV_ST_NOTASSIGNED;
spin_unlock(&vdev->ud.lock);
spin_unlock(&the_controller->lock);
spin_unlock_irqrestore(&the_controller->lock, flags);
/* end the lock */
vdev->ud.tcp_rx = kthread_get_run(vhci_rx_loop, &vdev->ud, "vhci_rx");
......
......@@ -47,16 +47,17 @@ static void setup_cmd_submit_pdu(struct usbip_header *pdup, struct urb *urb)
static struct vhci_priv *dequeue_from_priv_tx(struct vhci_device *vdev)
{
struct vhci_priv *priv, *tmp;
unsigned long flags;
spin_lock(&vdev->priv_lock);
spin_lock_irqsave(&vdev->priv_lock, flags);
list_for_each_entry_safe(priv, tmp, &vdev->priv_tx, list) {
list_move_tail(&priv->list, &vdev->priv_rx);
spin_unlock(&vdev->priv_lock);
spin_unlock_irqrestore(&vdev->priv_lock, flags);
return priv;
}
spin_unlock(&vdev->priv_lock);
spin_unlock_irqrestore(&vdev->priv_lock, flags);
return NULL;
}
......@@ -136,16 +137,17 @@ static int vhci_send_cmd_submit(struct vhci_device *vdev)
static struct vhci_unlink *dequeue_from_unlink_tx(struct vhci_device *vdev)
{
struct vhci_unlink *unlink, *tmp;
unsigned long flags;
spin_lock(&vdev->priv_lock);
spin_lock_irqsave(&vdev->priv_lock, flags);
list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) {
list_move_tail(&unlink->list, &vdev->unlink_rx);
spin_unlock(&vdev->priv_lock);
spin_unlock_irqrestore(&vdev->priv_lock, flags);
return unlink;
}
spin_unlock(&vdev->priv_lock);
spin_unlock_irqrestore(&vdev->priv_lock, flags);
return NULL;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment