usb: usbip: Fix possible deadlocks reported by lockdep
commit 21619792d1eca7e772ca190ba68588e57f29595b upstream. 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=109351 Signed-off-by: Andrew Goodbody <andrew.goodbody@cambrionix.com> Signed-off-by: Shuah Khan <shuahkh@osg.samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
9af7500349
commit
18e905a839
5 changed files with 91 additions and 65 deletions
|
@ -117,11 +117,12 @@ EXPORT_SYMBOL_GPL(usbip_event_add);
|
||||||
int usbip_event_happened(struct usbip_device *ud)
|
int usbip_event_happened(struct usbip_device *ud)
|
||||||
{
|
{
|
||||||
int happened = 0;
|
int happened = 0;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock(&ud->lock);
|
spin_lock_irqsave(&ud->lock, flags);
|
||||||
if (ud->event != 0)
|
if (ud->event != 0)
|
||||||
happened = 1;
|
happened = 1;
|
||||||
spin_unlock(&ud->lock);
|
spin_unlock_irqrestore(&ud->lock, flags);
|
||||||
|
|
||||||
return happened;
|
return happened;
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,9 +121,11 @@ static void dump_port_status_diff(u32 prev_status, u32 new_status)
|
||||||
|
|
||||||
void rh_port_connect(int rhport, enum usb_device_speed speed)
|
void rh_port_connect(int rhport, enum usb_device_speed speed)
|
||||||
{
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
usbip_dbg_vhci_rh("rh_port_connect %d\n", rhport);
|
usbip_dbg_vhci_rh("rh_port_connect %d\n", rhport);
|
||||||
|
|
||||||
spin_lock(&the_controller->lock);
|
spin_lock_irqsave(&the_controller->lock, flags);
|
||||||
|
|
||||||
the_controller->port_status[rhport] |= USB_PORT_STAT_CONNECTION
|
the_controller->port_status[rhport] |= USB_PORT_STAT_CONNECTION
|
||||||
| (1 << USB_PORT_FEAT_C_CONNECTION);
|
| (1 << USB_PORT_FEAT_C_CONNECTION);
|
||||||
|
@ -139,22 +141,24 @@ void rh_port_connect(int rhport, enum usb_device_speed speed)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock(&the_controller->lock);
|
spin_unlock_irqrestore(&the_controller->lock, flags);
|
||||||
|
|
||||||
usb_hcd_poll_rh_status(vhci_to_hcd(the_controller));
|
usb_hcd_poll_rh_status(vhci_to_hcd(the_controller));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rh_port_disconnect(int rhport)
|
static void rh_port_disconnect(int rhport)
|
||||||
{
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
usbip_dbg_vhci_rh("rh_port_disconnect %d\n", rhport);
|
usbip_dbg_vhci_rh("rh_port_disconnect %d\n", rhport);
|
||||||
|
|
||||||
spin_lock(&the_controller->lock);
|
spin_lock_irqsave(&the_controller->lock, flags);
|
||||||
|
|
||||||
the_controller->port_status[rhport] &= ~USB_PORT_STAT_CONNECTION;
|
the_controller->port_status[rhport] &= ~USB_PORT_STAT_CONNECTION;
|
||||||
the_controller->port_status[rhport] |=
|
the_controller->port_status[rhport] |=
|
||||||
(1 << USB_PORT_FEAT_C_CONNECTION);
|
(1 << USB_PORT_FEAT_C_CONNECTION);
|
||||||
|
|
||||||
spin_unlock(&the_controller->lock);
|
spin_unlock_irqrestore(&the_controller->lock, flags);
|
||||||
usb_hcd_poll_rh_status(vhci_to_hcd(the_controller));
|
usb_hcd_poll_rh_status(vhci_to_hcd(the_controller));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,13 +186,14 @@ static int vhci_hub_status(struct usb_hcd *hcd, char *buf)
|
||||||
int retval;
|
int retval;
|
||||||
int rhport;
|
int rhport;
|
||||||
int changed = 0;
|
int changed = 0;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
retval = DIV_ROUND_UP(VHCI_NPORTS + 1, 8);
|
retval = DIV_ROUND_UP(VHCI_NPORTS + 1, 8);
|
||||||
memset(buf, 0, retval);
|
memset(buf, 0, retval);
|
||||||
|
|
||||||
vhci = hcd_to_vhci(hcd);
|
vhci = hcd_to_vhci(hcd);
|
||||||
|
|
||||||
spin_lock(&vhci->lock);
|
spin_lock_irqsave(&vhci->lock, flags);
|
||||||
if (!HCD_HW_ACCESSIBLE(hcd)) {
|
if (!HCD_HW_ACCESSIBLE(hcd)) {
|
||||||
usbip_dbg_vhci_rh("hw accessible flag not on?\n");
|
usbip_dbg_vhci_rh("hw accessible flag not on?\n");
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -209,7 +214,7 @@ static int vhci_hub_status(struct usb_hcd *hcd, char *buf)
|
||||||
usb_hcd_resume_root_hub(hcd);
|
usb_hcd_resume_root_hub(hcd);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
spin_unlock(&vhci->lock);
|
spin_unlock_irqrestore(&vhci->lock, flags);
|
||||||
return changed ? retval : 0;
|
return changed ? retval : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,6 +241,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
||||||
struct vhci_hcd *dum;
|
struct vhci_hcd *dum;
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
int rhport;
|
int rhport;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
u32 prev_port_status[VHCI_NPORTS];
|
u32 prev_port_status[VHCI_NPORTS];
|
||||||
|
|
||||||
|
@ -254,7 +260,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
||||||
|
|
||||||
dum = hcd_to_vhci(hcd);
|
dum = hcd_to_vhci(hcd);
|
||||||
|
|
||||||
spin_lock(&dum->lock);
|
spin_lock_irqsave(&dum->lock, flags);
|
||||||
|
|
||||||
/* store old status and compare now and old later */
|
/* store old status and compare now and old later */
|
||||||
if (usbip_dbg_flag_vhci_rh) {
|
if (usbip_dbg_flag_vhci_rh) {
|
||||||
|
@ -408,7 +414,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
||||||
}
|
}
|
||||||
usbip_dbg_vhci_rh(" bye\n");
|
usbip_dbg_vhci_rh(" bye\n");
|
||||||
|
|
||||||
spin_unlock(&dum->lock);
|
spin_unlock_irqrestore(&dum->lock, flags);
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
@ -431,6 +437,7 @@ static void vhci_tx_urb(struct urb *urb)
|
||||||
{
|
{
|
||||||
struct vhci_device *vdev = get_vdev(urb->dev);
|
struct vhci_device *vdev = get_vdev(urb->dev);
|
||||||
struct vhci_priv *priv;
|
struct vhci_priv *priv;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
if (!vdev) {
|
if (!vdev) {
|
||||||
pr_err("could not get virtual device");
|
pr_err("could not get virtual device");
|
||||||
|
@ -443,7 +450,7 @@ static void vhci_tx_urb(struct urb *urb)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock(&vdev->priv_lock);
|
spin_lock_irqsave(&vdev->priv_lock, flags);
|
||||||
|
|
||||||
priv->seqnum = atomic_inc_return(&the_controller->seqnum);
|
priv->seqnum = atomic_inc_return(&the_controller->seqnum);
|
||||||
if (priv->seqnum == 0xffff)
|
if (priv->seqnum == 0xffff)
|
||||||
|
@ -457,7 +464,7 @@ static void vhci_tx_urb(struct urb *urb)
|
||||||
list_add_tail(&priv->list, &vdev->priv_tx);
|
list_add_tail(&priv->list, &vdev->priv_tx);
|
||||||
|
|
||||||
wake_up(&vdev->waitq_tx);
|
wake_up(&vdev->waitq_tx);
|
||||||
spin_unlock(&vdev->priv_lock);
|
spin_unlock_irqrestore(&vdev->priv_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
|
static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
|
||||||
|
@ -466,15 +473,16 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
|
||||||
struct device *dev = &urb->dev->dev;
|
struct device *dev = &urb->dev->dev;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct vhci_device *vdev;
|
struct vhci_device *vdev;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
/* patch to usb_sg_init() is in 2.5.60 */
|
/* patch to usb_sg_init() is in 2.5.60 */
|
||||||
BUG_ON(!urb->transfer_buffer && urb->transfer_buffer_length);
|
BUG_ON(!urb->transfer_buffer && urb->transfer_buffer_length);
|
||||||
|
|
||||||
spin_lock(&the_controller->lock);
|
spin_lock_irqsave(&the_controller->lock, flags);
|
||||||
|
|
||||||
if (urb->status != -EINPROGRESS) {
|
if (urb->status != -EINPROGRESS) {
|
||||||
dev_err(dev, "URB already unlinked!, status %d\n", urb->status);
|
dev_err(dev, "URB already unlinked!, status %d\n", urb->status);
|
||||||
spin_unlock(&the_controller->lock);
|
spin_unlock_irqrestore(&the_controller->lock, flags);
|
||||||
return urb->status;
|
return urb->status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -486,7 +494,7 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
|
||||||
vdev->ud.status == VDEV_ST_ERROR) {
|
vdev->ud.status == VDEV_ST_ERROR) {
|
||||||
dev_err(dev, "enqueue for inactive port %d\n", vdev->rhport);
|
dev_err(dev, "enqueue for inactive port %d\n", vdev->rhport);
|
||||||
spin_unlock(&vdev->ud.lock);
|
spin_unlock(&vdev->ud.lock);
|
||||||
spin_unlock(&the_controller->lock);
|
spin_unlock_irqrestore(&the_controller->lock, flags);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
spin_unlock(&vdev->ud.lock);
|
spin_unlock(&vdev->ud.lock);
|
||||||
|
@ -559,14 +567,14 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
|
||||||
|
|
||||||
out:
|
out:
|
||||||
vhci_tx_urb(urb);
|
vhci_tx_urb(urb);
|
||||||
spin_unlock(&the_controller->lock);
|
spin_unlock_irqrestore(&the_controller->lock, flags);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
no_need_xmit:
|
no_need_xmit:
|
||||||
usb_hcd_unlink_urb_from_ep(hcd, urb);
|
usb_hcd_unlink_urb_from_ep(hcd, urb);
|
||||||
no_need_unlink:
|
no_need_unlink:
|
||||||
spin_unlock(&the_controller->lock);
|
spin_unlock_irqrestore(&the_controller->lock, flags);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
usb_hcd_giveback_urb(vhci_to_hcd(the_controller),
|
usb_hcd_giveback_urb(vhci_to_hcd(the_controller),
|
||||||
urb, urb->status);
|
urb, urb->status);
|
||||||
|
@ -623,14 +631,15 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
|
||||||
{
|
{
|
||||||
struct vhci_priv *priv;
|
struct vhci_priv *priv;
|
||||||
struct vhci_device *vdev;
|
struct vhci_device *vdev;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock(&the_controller->lock);
|
spin_lock_irqsave(&the_controller->lock, flags);
|
||||||
|
|
||||||
priv = urb->hcpriv;
|
priv = urb->hcpriv;
|
||||||
if (!priv) {
|
if (!priv) {
|
||||||
/* URB was never linked! or will be soon given back by
|
/* URB was never linked! or will be soon given back by
|
||||||
* vhci_rx. */
|
* vhci_rx. */
|
||||||
spin_unlock(&the_controller->lock);
|
spin_unlock_irqrestore(&the_controller->lock, flags);
|
||||||
return -EIDRM;
|
return -EIDRM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -639,7 +648,7 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
|
||||||
|
|
||||||
ret = usb_hcd_check_unlink_urb(hcd, urb, status);
|
ret = usb_hcd_check_unlink_urb(hcd, urb, status);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
spin_unlock(&the_controller->lock);
|
spin_unlock_irqrestore(&the_controller->lock, flags);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -664,10 +673,10 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
|
||||||
*/
|
*/
|
||||||
usb_hcd_unlink_urb_from_ep(hcd, urb);
|
usb_hcd_unlink_urb_from_ep(hcd, urb);
|
||||||
|
|
||||||
spin_unlock(&the_controller->lock);
|
spin_unlock_irqrestore(&the_controller->lock, flags);
|
||||||
usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb,
|
usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb,
|
||||||
urb->status);
|
urb->status);
|
||||||
spin_lock(&the_controller->lock);
|
spin_lock_irqsave(&the_controller->lock, flags);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
/* tcp connection is alive */
|
/* tcp connection is alive */
|
||||||
|
@ -679,7 +688,7 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
|
||||||
unlink = kzalloc(sizeof(struct vhci_unlink), GFP_ATOMIC);
|
unlink = kzalloc(sizeof(struct vhci_unlink), GFP_ATOMIC);
|
||||||
if (!unlink) {
|
if (!unlink) {
|
||||||
spin_unlock(&vdev->priv_lock);
|
spin_unlock(&vdev->priv_lock);
|
||||||
spin_unlock(&the_controller->lock);
|
spin_unlock_irqrestore(&the_controller->lock, flags);
|
||||||
usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_MALLOC);
|
usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_MALLOC);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
@ -698,7 +707,7 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
|
||||||
spin_unlock(&vdev->priv_lock);
|
spin_unlock(&vdev->priv_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock(&the_controller->lock);
|
spin_unlock_irqrestore(&the_controller->lock, flags);
|
||||||
|
|
||||||
usbip_dbg_vhci_hc("leave\n");
|
usbip_dbg_vhci_hc("leave\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -707,8 +716,9 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
|
||||||
static void vhci_device_unlink_cleanup(struct vhci_device *vdev)
|
static void vhci_device_unlink_cleanup(struct vhci_device *vdev)
|
||||||
{
|
{
|
||||||
struct vhci_unlink *unlink, *tmp;
|
struct vhci_unlink *unlink, *tmp;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock(&the_controller->lock);
|
spin_lock_irqsave(&the_controller->lock, flags);
|
||||||
spin_lock(&vdev->priv_lock);
|
spin_lock(&vdev->priv_lock);
|
||||||
|
|
||||||
list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) {
|
list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) {
|
||||||
|
@ -742,19 +752,19 @@ static void vhci_device_unlink_cleanup(struct vhci_device *vdev)
|
||||||
list_del(&unlink->list);
|
list_del(&unlink->list);
|
||||||
|
|
||||||
spin_unlock(&vdev->priv_lock);
|
spin_unlock(&vdev->priv_lock);
|
||||||
spin_unlock(&the_controller->lock);
|
spin_unlock_irqrestore(&the_controller->lock, flags);
|
||||||
|
|
||||||
usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb,
|
usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb,
|
||||||
urb->status);
|
urb->status);
|
||||||
|
|
||||||
spin_lock(&the_controller->lock);
|
spin_lock_irqsave(&the_controller->lock, flags);
|
||||||
spin_lock(&vdev->priv_lock);
|
spin_lock(&vdev->priv_lock);
|
||||||
|
|
||||||
kfree(unlink);
|
kfree(unlink);
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock(&vdev->priv_lock);
|
spin_unlock(&vdev->priv_lock);
|
||||||
spin_unlock(&the_controller->lock);
|
spin_unlock_irqrestore(&the_controller->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -821,8 +831,9 @@ static void vhci_shutdown_connection(struct usbip_device *ud)
|
||||||
static void vhci_device_reset(struct usbip_device *ud)
|
static void vhci_device_reset(struct usbip_device *ud)
|
||||||
{
|
{
|
||||||
struct vhci_device *vdev = container_of(ud, struct vhci_device, ud);
|
struct vhci_device *vdev = container_of(ud, struct vhci_device, ud);
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock(&ud->lock);
|
spin_lock_irqsave(&ud->lock, flags);
|
||||||
|
|
||||||
vdev->speed = 0;
|
vdev->speed = 0;
|
||||||
vdev->devid = 0;
|
vdev->devid = 0;
|
||||||
|
@ -836,14 +847,16 @@ static void vhci_device_reset(struct usbip_device *ud)
|
||||||
}
|
}
|
||||||
ud->status = VDEV_ST_NULL;
|
ud->status = VDEV_ST_NULL;
|
||||||
|
|
||||||
spin_unlock(&ud->lock);
|
spin_unlock_irqrestore(&ud->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vhci_device_unusable(struct usbip_device *ud)
|
static void vhci_device_unusable(struct usbip_device *ud)
|
||||||
{
|
{
|
||||||
spin_lock(&ud->lock);
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&ud->lock, flags);
|
||||||
ud->status = VDEV_ST_ERROR;
|
ud->status = VDEV_ST_ERROR;
|
||||||
spin_unlock(&ud->lock);
|
spin_unlock_irqrestore(&ud->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vhci_device_init(struct vhci_device *vdev)
|
static void vhci_device_init(struct vhci_device *vdev)
|
||||||
|
@ -933,12 +946,13 @@ static int vhci_get_frame_number(struct usb_hcd *hcd)
|
||||||
static int vhci_bus_suspend(struct usb_hcd *hcd)
|
static int vhci_bus_suspend(struct usb_hcd *hcd)
|
||||||
{
|
{
|
||||||
struct vhci_hcd *vhci = hcd_to_vhci(hcd);
|
struct vhci_hcd *vhci = hcd_to_vhci(hcd);
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__);
|
dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__);
|
||||||
|
|
||||||
spin_lock(&vhci->lock);
|
spin_lock_irqsave(&vhci->lock, flags);
|
||||||
hcd->state = HC_STATE_SUSPENDED;
|
hcd->state = HC_STATE_SUSPENDED;
|
||||||
spin_unlock(&vhci->lock);
|
spin_unlock_irqrestore(&vhci->lock, flags);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -947,15 +961,16 @@ static int vhci_bus_resume(struct usb_hcd *hcd)
|
||||||
{
|
{
|
||||||
struct vhci_hcd *vhci = hcd_to_vhci(hcd);
|
struct vhci_hcd *vhci = hcd_to_vhci(hcd);
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__);
|
dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__);
|
||||||
|
|
||||||
spin_lock(&vhci->lock);
|
spin_lock_irqsave(&vhci->lock, flags);
|
||||||
if (!HCD_HW_ACCESSIBLE(hcd))
|
if (!HCD_HW_ACCESSIBLE(hcd))
|
||||||
rc = -ESHUTDOWN;
|
rc = -ESHUTDOWN;
|
||||||
else
|
else
|
||||||
hcd->state = HC_STATE_RUNNING;
|
hcd->state = HC_STATE_RUNNING;
|
||||||
spin_unlock(&vhci->lock);
|
spin_unlock_irqrestore(&vhci->lock, flags);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -1053,17 +1068,18 @@ static int vhci_hcd_suspend(struct platform_device *pdev, pm_message_t state)
|
||||||
int rhport = 0;
|
int rhport = 0;
|
||||||
int connected = 0;
|
int connected = 0;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
hcd = platform_get_drvdata(pdev);
|
hcd = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
spin_lock(&the_controller->lock);
|
spin_lock_irqsave(&the_controller->lock, flags);
|
||||||
|
|
||||||
for (rhport = 0; rhport < VHCI_NPORTS; rhport++)
|
for (rhport = 0; rhport < VHCI_NPORTS; rhport++)
|
||||||
if (the_controller->port_status[rhport] &
|
if (the_controller->port_status[rhport] &
|
||||||
USB_PORT_STAT_CONNECTION)
|
USB_PORT_STAT_CONNECTION)
|
||||||
connected += 1;
|
connected += 1;
|
||||||
|
|
||||||
spin_unlock(&the_controller->lock);
|
spin_unlock_irqrestore(&the_controller->lock, flags);
|
||||||
|
|
||||||
if (connected > 0) {
|
if (connected > 0) {
|
||||||
dev_info(&pdev->dev,
|
dev_info(&pdev->dev,
|
||||||
|
|
|
@ -71,10 +71,11 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev,
|
||||||
{
|
{
|
||||||
struct usbip_device *ud = &vdev->ud;
|
struct usbip_device *ud = &vdev->ud;
|
||||||
struct urb *urb;
|
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);
|
urb = pickup_urb_and_free_priv(vdev, pdu->base.seqnum);
|
||||||
spin_unlock(&vdev->priv_lock);
|
spin_unlock_irqrestore(&vdev->priv_lock, flags);
|
||||||
|
|
||||||
if (!urb) {
|
if (!urb) {
|
||||||
pr_err("cannot find a urb of seqnum %u max seqnum %d\n",
|
pr_err("cannot find a urb of seqnum %u max seqnum %d\n",
|
||||||
|
@ -103,9 +104,9 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev,
|
||||||
|
|
||||||
usbip_dbg_vhci_rx("now giveback urb %u\n", pdu->base.seqnum);
|
usbip_dbg_vhci_rx("now giveback urb %u\n", pdu->base.seqnum);
|
||||||
|
|
||||||
spin_lock(&the_controller->lock);
|
spin_lock_irqsave(&the_controller->lock, flags);
|
||||||
usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb);
|
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);
|
usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, urb->status);
|
||||||
|
|
||||||
|
@ -116,8 +117,9 @@ static struct vhci_unlink *dequeue_pending_unlink(struct vhci_device *vdev,
|
||||||
struct usbip_header *pdu)
|
struct usbip_header *pdu)
|
||||||
{
|
{
|
||||||
struct vhci_unlink *unlink, *tmp;
|
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) {
|
list_for_each_entry_safe(unlink, tmp, &vdev->unlink_rx, list) {
|
||||||
pr_info("unlink->seqnum %lu\n", unlink->seqnum);
|
pr_info("unlink->seqnum %lu\n", unlink->seqnum);
|
||||||
|
@ -126,12 +128,12 @@ static struct vhci_unlink *dequeue_pending_unlink(struct vhci_device *vdev,
|
||||||
unlink->seqnum);
|
unlink->seqnum);
|
||||||
list_del(&unlink->list);
|
list_del(&unlink->list);
|
||||||
|
|
||||||
spin_unlock(&vdev->priv_lock);
|
spin_unlock_irqrestore(&vdev->priv_lock, flags);
|
||||||
return unlink;
|
return unlink;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock(&vdev->priv_lock);
|
spin_unlock_irqrestore(&vdev->priv_lock, flags);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -141,6 +143,7 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev,
|
||||||
{
|
{
|
||||||
struct vhci_unlink *unlink;
|
struct vhci_unlink *unlink;
|
||||||
struct urb *urb;
|
struct urb *urb;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
usbip_dump_header(pdu);
|
usbip_dump_header(pdu);
|
||||||
|
|
||||||
|
@ -151,9 +154,9 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock(&vdev->priv_lock);
|
spin_lock_irqsave(&vdev->priv_lock, flags);
|
||||||
urb = pickup_urb_and_free_priv(vdev, unlink->unlink_seqnum);
|
urb = pickup_urb_and_free_priv(vdev, unlink->unlink_seqnum);
|
||||||
spin_unlock(&vdev->priv_lock);
|
spin_unlock_irqrestore(&vdev->priv_lock, flags);
|
||||||
|
|
||||||
if (!urb) {
|
if (!urb) {
|
||||||
/*
|
/*
|
||||||
|
@ -170,9 +173,9 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev,
|
||||||
urb->status = pdu->u.ret_unlink.status;
|
urb->status = pdu->u.ret_unlink.status;
|
||||||
pr_info("urb->status %d\n", urb->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);
|
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,
|
usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb,
|
||||||
urb->status);
|
urb->status);
|
||||||
|
@ -184,10 +187,11 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev,
|
||||||
static int vhci_priv_tx_empty(struct vhci_device *vdev)
|
static int vhci_priv_tx_empty(struct vhci_device *vdev)
|
||||||
{
|
{
|
||||||
int empty = 0;
|
int empty = 0;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock(&vdev->priv_lock);
|
spin_lock_irqsave(&vdev->priv_lock, flags);
|
||||||
empty = list_empty(&vdev->priv_rx);
|
empty = list_empty(&vdev->priv_rx);
|
||||||
spin_unlock(&vdev->priv_lock);
|
spin_unlock_irqrestore(&vdev->priv_lock, flags);
|
||||||
|
|
||||||
return empty;
|
return empty;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,10 +32,11 @@ static ssize_t status_show(struct device *dev, struct device_attribute *attr,
|
||||||
{
|
{
|
||||||
char *s = out;
|
char *s = out;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
BUG_ON(!the_controller || !out);
|
BUG_ON(!the_controller || !out);
|
||||||
|
|
||||||
spin_lock(&the_controller->lock);
|
spin_lock_irqsave(&the_controller->lock, flags);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* output example:
|
* output example:
|
||||||
|
@ -74,7 +75,7 @@ static ssize_t status_show(struct device *dev, struct device_attribute *attr,
|
||||||
spin_unlock(&vdev->ud.lock);
|
spin_unlock(&vdev->ud.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock(&the_controller->lock);
|
spin_unlock_irqrestore(&the_controller->lock, flags);
|
||||||
|
|
||||||
return out - s;
|
return out - s;
|
||||||
}
|
}
|
||||||
|
@ -84,11 +85,12 @@ static DEVICE_ATTR_RO(status);
|
||||||
static int vhci_port_disconnect(__u32 rhport)
|
static int vhci_port_disconnect(__u32 rhport)
|
||||||
{
|
{
|
||||||
struct vhci_device *vdev;
|
struct vhci_device *vdev;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
usbip_dbg_vhci_sysfs("enter\n");
|
usbip_dbg_vhci_sysfs("enter\n");
|
||||||
|
|
||||||
/* lock */
|
/* lock */
|
||||||
spin_lock(&the_controller->lock);
|
spin_lock_irqsave(&the_controller->lock, flags);
|
||||||
|
|
||||||
vdev = port_to_vdev(rhport);
|
vdev = port_to_vdev(rhport);
|
||||||
|
|
||||||
|
@ -98,14 +100,14 @@ static int vhci_port_disconnect(__u32 rhport)
|
||||||
|
|
||||||
/* unlock */
|
/* unlock */
|
||||||
spin_unlock(&vdev->ud.lock);
|
spin_unlock(&vdev->ud.lock);
|
||||||
spin_unlock(&the_controller->lock);
|
spin_unlock_irqrestore(&the_controller->lock, flags);
|
||||||
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* unlock */
|
/* unlock */
|
||||||
spin_unlock(&vdev->ud.lock);
|
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);
|
usbip_event_add(&vdev->ud, VDEV_EVENT_DOWN);
|
||||||
|
|
||||||
|
@ -181,6 +183,7 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr,
|
||||||
int sockfd = 0;
|
int sockfd = 0;
|
||||||
__u32 rhport = 0, devid = 0, speed = 0;
|
__u32 rhport = 0, devid = 0, speed = 0;
|
||||||
int err;
|
int err;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @rhport: port number of vhci_hcd
|
* @rhport: port number of vhci_hcd
|
||||||
|
@ -206,14 +209,14 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr,
|
||||||
/* now need lock until setting vdev status as used */
|
/* now need lock until setting vdev status as used */
|
||||||
|
|
||||||
/* begin a lock */
|
/* begin a lock */
|
||||||
spin_lock(&the_controller->lock);
|
spin_lock_irqsave(&the_controller->lock, flags);
|
||||||
vdev = port_to_vdev(rhport);
|
vdev = port_to_vdev(rhport);
|
||||||
spin_lock(&vdev->ud.lock);
|
spin_lock(&vdev->ud.lock);
|
||||||
|
|
||||||
if (vdev->ud.status != VDEV_ST_NULL) {
|
if (vdev->ud.status != VDEV_ST_NULL) {
|
||||||
/* end of the lock */
|
/* end of the lock */
|
||||||
spin_unlock(&vdev->ud.lock);
|
spin_unlock(&vdev->ud.lock);
|
||||||
spin_unlock(&the_controller->lock);
|
spin_unlock_irqrestore(&the_controller->lock, flags);
|
||||||
|
|
||||||
sockfd_put(socket);
|
sockfd_put(socket);
|
||||||
|
|
||||||
|
@ -232,7 +235,7 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr,
|
||||||
vdev->ud.status = VDEV_ST_NOTASSIGNED;
|
vdev->ud.status = VDEV_ST_NOTASSIGNED;
|
||||||
|
|
||||||
spin_unlock(&vdev->ud.lock);
|
spin_unlock(&vdev->ud.lock);
|
||||||
spin_unlock(&the_controller->lock);
|
spin_unlock_irqrestore(&the_controller->lock, flags);
|
||||||
/* end the lock */
|
/* end the lock */
|
||||||
|
|
||||||
vdev->ud.tcp_rx = kthread_get_run(vhci_rx_loop, &vdev->ud, "vhci_rx");
|
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)
|
static struct vhci_priv *dequeue_from_priv_tx(struct vhci_device *vdev)
|
||||||
{
|
{
|
||||||
struct vhci_priv *priv, *tmp;
|
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_for_each_entry_safe(priv, tmp, &vdev->priv_tx, list) {
|
||||||
list_move_tail(&priv->list, &vdev->priv_rx);
|
list_move_tail(&priv->list, &vdev->priv_rx);
|
||||||
spin_unlock(&vdev->priv_lock);
|
spin_unlock_irqrestore(&vdev->priv_lock, flags);
|
||||||
return priv;
|
return priv;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock(&vdev->priv_lock);
|
spin_unlock_irqrestore(&vdev->priv_lock, flags);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -137,16 +138,17 @@ static int vhci_send_cmd_submit(struct vhci_device *vdev)
|
||||||
static struct vhci_unlink *dequeue_from_unlink_tx(struct vhci_device *vdev)
|
static struct vhci_unlink *dequeue_from_unlink_tx(struct vhci_device *vdev)
|
||||||
{
|
{
|
||||||
struct vhci_unlink *unlink, *tmp;
|
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_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) {
|
||||||
list_move_tail(&unlink->list, &vdev->unlink_rx);
|
list_move_tail(&unlink->list, &vdev->unlink_rx);
|
||||||
spin_unlock(&vdev->priv_lock);
|
spin_unlock_irqrestore(&vdev->priv_lock, flags);
|
||||||
return unlink;
|
return unlink;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock(&vdev->priv_lock);
|
spin_unlock_irqrestore(&vdev->priv_lock, flags);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue