* [PATCH] Bluetooth: hidp: Stop I/O on shutdown @ 2011-08-26 12:06 David Herrmann [not found] ` <1314360362-24580-1-git-send-email-dh.herrmann-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org> 0 siblings, 1 reply; 3+ messages in thread From: David Herrmann @ 2011-08-26 12:06 UTC (permalink / raw) To: linux-bluetooth; +Cc: padovan, linux-input, David Herrmann Current hidp driver purges the in/out queue on HID shutdown, but does not prevent further I/O. If a driver uses hidp_output_raw_report or hidp_get_raw_report during shutdown, the driver hangs for 5 or 10 seconds per call until it gets a timeout. That is, if the output queue of an HID driver has 10 messages pending, it will take 50s until hid_destroy_device() will return. The hidp_session_sem semaphore is held during shutdown so no other HID device may be added/removed during this time. This patch makes hidp_output_raw_report and hidp_get_raw_report fail if session->terminate is true. Also hidp_session will wakeup all current calls to these functions to cancel the current operations. We already purge the current I/O queues on hidp_stop(), so this data loss does not change the behaviour of the HID drivers. Signed-off-by: David Herrmann <dh.herrmann@googlemail.com> --- net/bluetooth/hidp/core.c | 40 ++++++++++++++++++++++++++-------------- 1 files changed, 26 insertions(+), 14 deletions(-) diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 4423e3a..e134528 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -255,6 +255,9 @@ static int __hidp_send_ctrl_message(struct hidp_session *session, BT_DBG("session %p data %p size %d", session, data, size); + if (atomic_read(&session->terminate)) + return -EIO; + skb = alloc_skb(size + 1, GFP_ATOMIC); if (!skb) { BT_ERR("Can't allocate memory for new frame"); @@ -320,6 +323,13 @@ static int hidp_send_report(struct hidp_session *session, struct hid_report *rep return hidp_queue_report(session, buf, rsize); } +static void hidp_wakeup_reportq(struct hidp_session *session) +{ + clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags); + clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags); + wake_up_interruptible(&session->report_queue); +} + static int hidp_get_raw_report(struct hid_device *hid, unsigned char report_number, unsigned char *data, size_t count, @@ -329,6 +339,7 @@ static int hidp_get_raw_report(struct hid_device *hid, struct sk_buff *skb; size_t len; int numbered_reports = hid->report_enum[report_type].numbered; + int ret; switch (report_type) { case HID_FEATURE_REPORT: @@ -352,8 +363,9 @@ static int hidp_get_raw_report(struct hid_device *hid, session->waiting_report_number = numbered_reports ? report_number : -1; set_bit(HIDP_WAITING_FOR_RETURN, &session->flags); data[0] = report_number; - if (hidp_send_ctrl_message(hid->driver_data, report_type, data, 1)) - goto err_eio; + ret = hidp_send_ctrl_message(hid->driver_data, report_type, data, 1); + if (ret) + goto err; /* Wait for the return of the report. The returned report gets put in session->report_return. */ @@ -365,11 +377,13 @@ static int hidp_get_raw_report(struct hid_device *hid, 5*HZ); if (res == 0) { /* timeout */ - goto err_eio; + ret = -EIO; + goto err; } if (res < 0) { /* signal */ - goto err_restartsys; + ret = -ERESTARTSYS; + goto err; } } @@ -390,14 +404,10 @@ static int hidp_get_raw_report(struct hid_device *hid, return len; -err_restartsys: - clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags); - mutex_unlock(&session->report_mutex); - return -ERESTARTSYS; -err_eio: +err: clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags); mutex_unlock(&session->report_mutex); - return -EIO; + return ret; } static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count, @@ -422,11 +432,10 @@ static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, s /* Set up our wait, and send the report request to the device. */ set_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags); - if (hidp_send_ctrl_message(hid->driver_data, report_type, - data, count)) { - ret = -ENOMEM; + ret = hidp_send_ctrl_message(hid->driver_data, report_type, data, + count); + if (ret) goto err; - } /* Wait for the ACK from the device. */ while (test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags)) { @@ -733,6 +742,9 @@ static int hidp_session(void *arg) remove_wait_queue(sk_sleep(intr_sk), &intr_wait); remove_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait); + atomic_inc(&session->terminate); + hidp_wakeup_reportq(session); + down_write(&hidp_session_sem); hidp_del_timer(session); -- 1.7.6 ^ permalink raw reply related [flat|nested] 3+ messages in thread
[parent not found: <1314360362-24580-1-git-send-email-dh.herrmann-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>]
* Re: [PATCH] Bluetooth: hidp: Stop I/O on shutdown [not found] ` <1314360362-24580-1-git-send-email-dh.herrmann-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org> @ 2011-10-07 1:11 ` Gustavo Padovan 2011-10-07 1:15 ` Gustavo Padovan 0 siblings, 1 reply; 3+ messages in thread From: Gustavo Padovan @ 2011-10-07 1:11 UTC (permalink / raw) To: David Herrmann Cc: linux-bluetooth-u79uwXL29TY76Z2rM5mHXA, linux-input-u79uwXL29TY76Z2rM5mHXA Hi David, Sorry for the big delay to respond to this. * David Herrmann <dh.herrmann-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org> [2011-08-26 14:06:02 +0200]: > Current hidp driver purges the in/out queue on HID shutdown, but does > not prevent further I/O. If a driver uses hidp_output_raw_report or > hidp_get_raw_report during shutdown, the driver hangs for 5 or 10 > seconds per call until it gets a timeout. > That is, if the output queue of an HID driver has 10 messages pending, > it will take 50s until hid_destroy_device() will return. The > hidp_session_sem semaphore is held during shutdown so no other HID > device may be added/removed during this time. > > This patch makes hidp_output_raw_report and hidp_get_raw_report fail if > session->terminate is true. Also hidp_session will wakeup all current > calls to these functions to cancel the current operations. > > We already purge the current I/O queues on hidp_stop(), so this data loss > does not change the behaviour of the HID drivers. > > Signed-off-by: David Herrmann <dh.herrmann-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org> > --- > net/bluetooth/hidp/core.c | 40 ++++++++++++++++++++++++++-------------- > 1 files changed, 26 insertions(+), 14 deletions(-) > > diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c > index 4423e3a..e134528 100644 > --- a/net/bluetooth/hidp/core.c > +++ b/net/bluetooth/hidp/core.c > @@ -255,6 +255,9 @@ static int __hidp_send_ctrl_message(struct hidp_session *session, > > BT_DBG("session %p data %p size %d", session, data, size); > > + if (atomic_read(&session->terminate)) > + return -EIO; > + > skb = alloc_skb(size + 1, GFP_ATOMIC); > if (!skb) { > BT_ERR("Can't allocate memory for new frame"); > @@ -320,6 +323,13 @@ static int hidp_send_report(struct hidp_session *session, struct hid_report *rep > return hidp_queue_report(session, buf, rsize); > } > > +static void hidp_wakeup_reportq(struct hidp_session *session) > +{ > + clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags); > + clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags); > + wake_up_interruptible(&session->report_queue); > +} > + > static int hidp_get_raw_report(struct hid_device *hid, > unsigned char report_number, > unsigned char *data, size_t count, > @@ -329,6 +339,7 @@ static int hidp_get_raw_report(struct hid_device *hid, > struct sk_buff *skb; > size_t len; > int numbered_reports = hid->report_enum[report_type].numbered; > + int ret; > > switch (report_type) { > case HID_FEATURE_REPORT: > @@ -352,8 +363,9 @@ static int hidp_get_raw_report(struct hid_device *hid, > session->waiting_report_number = numbered_reports ? report_number : -1; > set_bit(HIDP_WAITING_FOR_RETURN, &session->flags); > data[0] = report_number; > - if (hidp_send_ctrl_message(hid->driver_data, report_type, data, 1)) > - goto err_eio; > + ret = hidp_send_ctrl_message(hid->driver_data, report_type, data, 1); > + if (ret) > + goto err; > > /* Wait for the return of the report. The returned report > gets put in session->report_return. */ > @@ -365,11 +377,13 @@ static int hidp_get_raw_report(struct hid_device *hid, > 5*HZ); > if (res == 0) { > /* timeout */ > - goto err_eio; > + ret = -EIO; > + goto err; > } > if (res < 0) { > /* signal */ > - goto err_restartsys; > + ret = -ERESTARTSYS; > + goto err; > } > } > > @@ -390,14 +404,10 @@ static int hidp_get_raw_report(struct hid_device *hid, > > return len; > > -err_restartsys: > - clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags); > - mutex_unlock(&session->report_mutex); > - return -ERESTARTSYS; > -err_eio: > +err: > clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags); > mutex_unlock(&session->report_mutex); > - return -EIO; > + return ret; > } > > static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count, > @@ -422,11 +432,10 @@ static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, s > > /* Set up our wait, and send the report request to the device. */ > set_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags); > - if (hidp_send_ctrl_message(hid->driver_data, report_type, > - data, count)) { > - ret = -ENOMEM; > + ret = hidp_send_ctrl_message(hid->driver_data, report_type, data, > + count); > + if (ret) > goto err; > - } > > /* Wait for the ACK from the device. */ > while (test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags)) { > @@ -733,6 +742,9 @@ static int hidp_session(void *arg) > remove_wait_queue(sk_sleep(intr_sk), &intr_wait); > remove_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait); > > + atomic_inc(&session->terminate); At this point seeems that terminate is already > 1. > + hidp_wakeup_reportq(session); just inline hidp_wakeup_reportq here, no need to create a function for this. Gustavo ^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] Bluetooth: hidp: Stop I/O on shutdown 2011-10-07 1:11 ` Gustavo Padovan @ 2011-10-07 1:15 ` Gustavo Padovan 0 siblings, 0 replies; 3+ messages in thread From: Gustavo Padovan @ 2011-10-07 1:15 UTC (permalink / raw) To: David Herrmann; +Cc: linux-bluetooth, linux-input * Gustavo Padovan <padovan@profusion.mobi> [2011-10-06 22:11:38 -0300]: > Hi David, > > Sorry for the big delay to respond to this. > > * David Herrmann <dh.herrmann@googlemail.com> [2011-08-26 14:06:02 +0200]: > > > Current hidp driver purges the in/out queue on HID shutdown, but does > > not prevent further I/O. If a driver uses hidp_output_raw_report or > > hidp_get_raw_report during shutdown, the driver hangs for 5 or 10 > > seconds per call until it gets a timeout. > > That is, if the output queue of an HID driver has 10 messages pending, > > it will take 50s until hid_destroy_device() will return. The > > hidp_session_sem semaphore is held during shutdown so no other HID > > device may be added/removed during this time. > > > > This patch makes hidp_output_raw_report and hidp_get_raw_report fail if > > session->terminate is true. Also hidp_session will wakeup all current > > calls to these functions to cancel the current operations. > > > > We already purge the current I/O queues on hidp_stop(), so this data loss > > does not change the behaviour of the HID drivers. > > > > Signed-off-by: David Herrmann <dh.herrmann@googlemail.com> > > --- > > net/bluetooth/hidp/core.c | 40 ++++++++++++++++++++++++++-------------- > > 1 files changed, 26 insertions(+), 14 deletions(-) > > > > diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c > > index 4423e3a..e134528 100644 > > --- a/net/bluetooth/hidp/core.c > > +++ b/net/bluetooth/hidp/core.c > > @@ -255,6 +255,9 @@ static int __hidp_send_ctrl_message(struct hidp_session *session, > > > > BT_DBG("session %p data %p size %d", session, data, size); > > > > + if (atomic_read(&session->terminate)) > > + return -EIO; > > + > > skb = alloc_skb(size + 1, GFP_ATOMIC); > > if (!skb) { > > BT_ERR("Can't allocate memory for new frame"); > > @@ -320,6 +323,13 @@ static int hidp_send_report(struct hidp_session *session, struct hid_report *rep > > return hidp_queue_report(session, buf, rsize); > > } > > > > +static void hidp_wakeup_reportq(struct hidp_session *session) > > +{ > > + clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags); > > + clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags); > > + wake_up_interruptible(&session->report_queue); > > +} > > + > > static int hidp_get_raw_report(struct hid_device *hid, > > unsigned char report_number, > > unsigned char *data, size_t count, > > @@ -329,6 +339,7 @@ static int hidp_get_raw_report(struct hid_device *hid, > > struct sk_buff *skb; > > size_t len; > > int numbered_reports = hid->report_enum[report_type].numbered; > > + int ret; > > > > switch (report_type) { > > case HID_FEATURE_REPORT: > > @@ -352,8 +363,9 @@ static int hidp_get_raw_report(struct hid_device *hid, > > session->waiting_report_number = numbered_reports ? report_number : -1; > > set_bit(HIDP_WAITING_FOR_RETURN, &session->flags); > > data[0] = report_number; > > - if (hidp_send_ctrl_message(hid->driver_data, report_type, data, 1)) > > - goto err_eio; > > + ret = hidp_send_ctrl_message(hid->driver_data, report_type, data, 1); > > + if (ret) > > + goto err; > > > > /* Wait for the return of the report. The returned report > > gets put in session->report_return. */ > > @@ -365,11 +377,13 @@ static int hidp_get_raw_report(struct hid_device *hid, > > 5*HZ); > > if (res == 0) { > > /* timeout */ > > - goto err_eio; > > + ret = -EIO; > > + goto err; > > } > > if (res < 0) { > > /* signal */ > > - goto err_restartsys; > > + ret = -ERESTARTSYS; > > + goto err; > > } > > } > > > > @@ -390,14 +404,10 @@ static int hidp_get_raw_report(struct hid_device *hid, > > > > return len; > > > > -err_restartsys: > > - clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags); > > - mutex_unlock(&session->report_mutex); > > - return -ERESTARTSYS; > > -err_eio: > > +err: > > clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags); > > mutex_unlock(&session->report_mutex); > > - return -EIO; > > + return ret; > > } > > > > static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count, > > @@ -422,11 +432,10 @@ static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, s > > > > /* Set up our wait, and send the report request to the device. */ > > set_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags); > > - if (hidp_send_ctrl_message(hid->driver_data, report_type, > > - data, count)) { > > - ret = -ENOMEM; > > + ret = hidp_send_ctrl_message(hid->driver_data, report_type, data, > > + count); > > + if (ret) > > goto err; > > - } > > > > /* Wait for the ACK from the device. */ > > while (test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags)) { > > @@ -733,6 +742,9 @@ static int hidp_session(void *arg) > > remove_wait_queue(sk_sleep(intr_sk), &intr_wait); > > remove_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait); > > > > + atomic_inc(&session->terminate); > > At this point seeems that terminate is already > 1. > > > + hidp_wakeup_reportq(session); > > just inline hidp_wakeup_reportq here, no need to create a function for this. Nevermind, I fixed it for you. Patch is now applied. Thanks. Gustavo ^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2011-10-07 1:14 UTC | newest] Thread overview: 3+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2011-08-26 12:06 [PATCH] Bluetooth: hidp: Stop I/O on shutdown David Herrmann [not found] ` <1314360362-24580-1-git-send-email-dh.herrmann-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org> 2011-10-07 1:11 ` Gustavo Padovan 2011-10-07 1:15 ` Gustavo Padovan
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).