* FAILED: patch "[PATCH] usb: gadget: f_hid: Use spinlock instead of mutex" failed to apply to 4.4-stable tree
@ 2017-03-10 8:21 gregkh
0 siblings, 0 replies; only message in thread
From: gregkh @ 2017-03-10 8:21 UTC (permalink / raw)
To: kopasiak90, david, felipe.balbi, k.opasiak; +Cc: stable
The patch below does not apply to the 4.4-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable@vger.kernel.org>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
>From 33e4c1a9987a1fc3b42c3b534100b5b006d55c61 Mon Sep 17 00:00:00 2001
From: Krzysztof Opasiak <kopasiak90@gmail.com>
Date: Thu, 19 Jan 2017 18:55:29 +0100
Subject: [PATCH] usb: gadget: f_hid: Use spinlock instead of mutex
As IN request has to be allocated in set_alt() and released in
disable() we cannot use mutex to protect it as we cannot sleep
in those funcitons. Let's replace this mutex with a spinlock.
Cc: stable@vger.kernel.org
Tested-by: David Lechner <david@lechnology.com>
Signed-off-by: Krzysztof Opasiak <k.opasiak@samsung.com>
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c
index 4ab74204efe2..b62e69d036c1 100644
--- a/drivers/usb/gadget/function/f_hid.c
+++ b/drivers/usb/gadget/function/f_hid.c
@@ -50,12 +50,12 @@ struct f_hidg {
/* recv report */
struct list_head completed_out_req;
- spinlock_t spinlock;
+ spinlock_t read_spinlock;
wait_queue_head_t read_queue;
unsigned int qlen;
/* send report */
- struct mutex lock;
+ spinlock_t write_spinlock;
bool write_pending;
wait_queue_head_t write_queue;
struct usb_request *req;
@@ -258,20 +258,20 @@ static ssize_t f_hidg_read(struct file *file, char __user *buffer,
if (!access_ok(VERIFY_WRITE, buffer, count))
return -EFAULT;
- spin_lock_irqsave(&hidg->spinlock, flags);
+ spin_lock_irqsave(&hidg->read_spinlock, flags);
#define READ_COND (!list_empty(&hidg->completed_out_req))
/* wait for at least one buffer to complete */
while (!READ_COND) {
- spin_unlock_irqrestore(&hidg->spinlock, flags);
+ spin_unlock_irqrestore(&hidg->read_spinlock, flags);
if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
if (wait_event_interruptible(hidg->read_queue, READ_COND))
return -ERESTARTSYS;
- spin_lock_irqsave(&hidg->spinlock, flags);
+ spin_lock_irqsave(&hidg->read_spinlock, flags);
}
/* pick the first one */
@@ -286,7 +286,7 @@ static ssize_t f_hidg_read(struct file *file, char __user *buffer,
req = list->req;
count = min_t(unsigned int, count, req->actual - list->pos);
- spin_unlock_irqrestore(&hidg->spinlock, flags);
+ spin_unlock_irqrestore(&hidg->read_spinlock, flags);
/* copy to user outside spinlock */
count -= copy_to_user(buffer, req->buf + list->pos, count);
@@ -308,9 +308,9 @@ static ssize_t f_hidg_read(struct file *file, char __user *buffer,
return ret;
}
} else {
- spin_lock_irqsave(&hidg->spinlock, flags);
+ spin_lock_irqsave(&hidg->read_spinlock, flags);
list_add(&list->list, &hidg->completed_out_req);
- spin_unlock_irqrestore(&hidg->spinlock, flags);
+ spin_unlock_irqrestore(&hidg->read_spinlock, flags);
wake_up(&hidg->read_queue);
}
@@ -321,13 +321,16 @@ static ssize_t f_hidg_read(struct file *file, char __user *buffer,
static void f_hidg_req_complete(struct usb_ep *ep, struct usb_request *req)
{
struct f_hidg *hidg = (struct f_hidg *)ep->driver_data;
+ unsigned long flags;
if (req->status != 0) {
ERROR(hidg->func.config->cdev,
"End Point Request ERROR: %d\n", req->status);
}
+ spin_lock_irqsave(&hidg->write_spinlock, flags);
hidg->write_pending = 0;
+ spin_unlock_irqrestore(&hidg->write_spinlock, flags);
wake_up(&hidg->write_queue);
}
@@ -335,18 +338,19 @@ static ssize_t f_hidg_write(struct file *file, const char __user *buffer,
size_t count, loff_t *offp)
{
struct f_hidg *hidg = file->private_data;
+ unsigned long flags;
ssize_t status = -ENOMEM;
if (!access_ok(VERIFY_READ, buffer, count))
return -EFAULT;
- mutex_lock(&hidg->lock);
+ spin_lock_irqsave(&hidg->write_spinlock, flags);
#define WRITE_COND (!hidg->write_pending)
/* write queue */
while (!WRITE_COND) {
- mutex_unlock(&hidg->lock);
+ spin_unlock_irqrestore(&hidg->write_spinlock, flags);
if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
@@ -354,17 +358,20 @@ static ssize_t f_hidg_write(struct file *file, const char __user *buffer,
hidg->write_queue, WRITE_COND))
return -ERESTARTSYS;
- mutex_lock(&hidg->lock);
+ spin_lock_irqsave(&hidg->write_spinlock, flags);
}
+ hidg->write_pending = 1;
count = min_t(unsigned, count, hidg->report_length);
+
+ spin_unlock_irqrestore(&hidg->write_spinlock, flags);
status = copy_from_user(hidg->req->buf, buffer, count);
if (status != 0) {
ERROR(hidg->func.config->cdev,
"copy_from_user error\n");
- mutex_unlock(&hidg->lock);
- return -EINVAL;
+ status = -EINVAL;
+ goto release_write_pending;
}
hidg->req->status = 0;
@@ -372,19 +379,23 @@ static ssize_t f_hidg_write(struct file *file, const char __user *buffer,
hidg->req->length = count;
hidg->req->complete = f_hidg_req_complete;
hidg->req->context = hidg;
- hidg->write_pending = 1;
status = usb_ep_queue(hidg->in_ep, hidg->req, GFP_ATOMIC);
if (status < 0) {
ERROR(hidg->func.config->cdev,
"usb_ep_queue error on int endpoint %zd\n", status);
- hidg->write_pending = 0;
- wake_up(&hidg->write_queue);
+ goto release_write_pending;
} else {
status = count;
}
- mutex_unlock(&hidg->lock);
+ return status;
+release_write_pending:
+ spin_lock_irqsave(&hidg->write_spinlock, flags);
+ hidg->write_pending = 0;
+ spin_unlock_irqrestore(&hidg->write_spinlock, flags);
+
+ wake_up(&hidg->write_queue);
return status;
}
@@ -451,9 +462,9 @@ static void hidg_set_report_complete(struct usb_ep *ep, struct usb_request *req)
req_list->req = req;
- spin_lock_irqsave(&hidg->spinlock, flags);
+ spin_lock_irqsave(&hidg->read_spinlock, flags);
list_add_tail(&req_list->list, &hidg->completed_out_req);
- spin_unlock_irqrestore(&hidg->spinlock, flags);
+ spin_unlock_irqrestore(&hidg->read_spinlock, flags);
wake_up(&hidg->read_queue);
break;
@@ -577,13 +588,13 @@ static void hidg_disable(struct usb_function *f)
usb_ep_disable(hidg->in_ep);
usb_ep_disable(hidg->out_ep);
- spin_lock_irqsave(&hidg->spinlock, flags);
+ spin_lock_irqsave(&hidg->read_spinlock, flags);
list_for_each_entry_safe(list, next, &hidg->completed_out_req, list) {
free_ep_req(hidg->out_ep, list->req);
list_del(&list->list);
kfree(list);
}
- spin_unlock_irqrestore(&hidg->spinlock, flags);
+ spin_unlock_irqrestore(&hidg->read_spinlock, flags);
}
static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
@@ -743,8 +754,8 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
if (status)
goto fail;
- mutex_init(&hidg->lock);
- spin_lock_init(&hidg->spinlock);
+ spin_lock_init(&hidg->write_spinlock);
+ spin_lock_init(&hidg->read_spinlock);
init_waitqueue_head(&hidg->write_queue);
init_waitqueue_head(&hidg->read_queue);
INIT_LIST_HEAD(&hidg->completed_out_req);
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2017-03-10 8:23 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-03-10 8:21 FAILED: patch "[PATCH] usb: gadget: f_hid: Use spinlock instead of mutex" failed to apply to 4.4-stable tree gregkh
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).