Merge "usb: gadget: diag: fix read/write race with unbind"

This commit is contained in:
Linux Build Service Account 2014-04-30 02:34:45 -07:00 committed by Gerrit - the friendly Code Review server
commit 8b000bf25c

View file

@ -422,6 +422,7 @@ int usb_diag_read(struct usb_diag_ch *ch, struct diag_request *d_req)
struct diag_context *ctxt = ch->priv_usb;
unsigned long flags;
struct usb_request *req;
struct usb_ep *out;
static DEFINE_RATELIMIT_STATE(rl, 10*HZ, 1);
if (!ctxt)
@ -429,11 +430,13 @@ int usb_diag_read(struct usb_diag_ch *ch, struct diag_request *d_req)
spin_lock_irqsave(&ctxt->lock, flags);
if (!ctxt->configured) {
if (!ctxt->configured || !ctxt->out) {
spin_unlock_irqrestore(&ctxt->lock, flags);
return -EIO;
}
out = ctxt->out;
if (list_empty(&ctxt->read_pool)) {
spin_unlock_irqrestore(&ctxt->lock, flags);
ERROR(ctxt->cdev, "%s: no requests available\n", __func__);
@ -447,7 +450,14 @@ int usb_diag_read(struct usb_diag_ch *ch, struct diag_request *d_req)
req->buf = d_req->buf;
req->length = d_req->length;
req->context = d_req;
if (usb_ep_queue(ctxt->out, req, GFP_ATOMIC)) {
/* make sure context is still valid after releasing lock */
if (ctxt != ch->priv_usb) {
usb_ep_free_request(out, req);
return -EIO;
}
if (usb_ep_queue(out, req, GFP_ATOMIC)) {
/* If error add the link to linked list again*/
spin_lock_irqsave(&ctxt->lock, flags);
list_add_tail(&req->list, &ctxt->read_pool);
@ -481,6 +491,7 @@ int usb_diag_write(struct usb_diag_ch *ch, struct diag_request *d_req)
struct diag_context *ctxt = ch->priv_usb;
unsigned long flags;
struct usb_request *req = NULL;
struct usb_ep *in;
static DEFINE_RATELIMIT_STATE(rl, 10*HZ, 1);
if (!ctxt)
@ -488,11 +499,13 @@ int usb_diag_write(struct usb_diag_ch *ch, struct diag_request *d_req)
spin_lock_irqsave(&ctxt->lock, flags);
if (!ctxt->configured) {
if (!ctxt->configured || !ctxt->in) {
spin_unlock_irqrestore(&ctxt->lock, flags);
return -EIO;
}
in = ctxt->in;
if (list_empty(&ctxt->write_pool)) {
spin_unlock_irqrestore(&ctxt->lock, flags);
ERROR(ctxt->cdev, "%s: no requests available\n", __func__);
@ -506,7 +519,14 @@ int usb_diag_write(struct usb_diag_ch *ch, struct diag_request *d_req)
req->buf = d_req->buf;
req->length = d_req->length;
req->context = d_req;
if (usb_ep_queue(ctxt->in, req, GFP_ATOMIC)) {
/* make sure context is still valid after releasing lock */
if (ctxt != ch->priv_usb) {
usb_ep_free_request(in, req);
return -EIO;
}
if (usb_ep_queue(in, req, GFP_ATOMIC)) {
/* If error add the link to linked list again*/
spin_lock_irqsave(&ctxt->lock, flags);
list_add_tail(&req->list, &ctxt->write_pool);