2019-04-05 11:37:27

by Nicolas Saenz Julienne

[permalink] [raw]
Subject: [PATCH 0/3] staging: vchiq: use interruptible waits

Hi,
this series tries to address an issue that came up in Raspbian's kernel
tree [1]. After pulling from upstream some changes that moved wait calls
from a custom implementation to the more standard killable family some
users complained that all the VCHIQ threads showed up in D state (which
is the expected behaviour).

The custom implementation we deleted tried to mimic the killable family
of functions, yet accepted more signals than the later. SIGKILL |
SIGINT | SIGQUIT | SIGTRAP | SIGSTOP | SIGCONT for the custom
implementation as opposed to plain old SIGKILL.

Raspbian maintainers decided roll back some of those changes and leave
the wait functions as interruptible. Hence creating some divergence
between both trees.

One could argue that not liking having the threads stuck in D state is
not really a software issue. It's more a cosmetic thing that can scare
people when they look at "uptime". On the other hand, if we are ever to
unstage this driver, we'd really need a proper justification for using
the killable family of functions. Which I think it's not really clear at
the moment.

As Raspbian's kernel has been working for a while with interruptible
waits I propose we follow through. If needed we can always go back to
killable. But at least we'll have a proper understanding on the actual
needs. In the end the driver is in staging, and the potential for errors
small.

Regards,
Nicolas

[1] https://github.com/raspberrypi/linux/issues/2881

---

Nicolas Saenz Julienne (3):
Revert "staging: vchiq_2835_arm: quit using custom
down_interruptible()"
Revert "staging: vchiq: switch to wait_for_completion_killable"
staging: vchiq: make wait events interruptible

.../interface/vchiq_arm/vchiq_2835_arm.c | 2 +-
.../interface/vchiq_arm/vchiq_arm.c | 21 +++++++++--------
.../interface/vchiq_arm/vchiq_core.c | 23 ++++++++++---------
.../interface/vchiq_arm/vchiq_util.c | 6 ++---
4 files changed, 27 insertions(+), 25 deletions(-)

--
2.21.0


2019-04-05 11:35:40

by Nicolas Saenz Julienne

[permalink] [raw]
Subject: [PATCH 2/3] Revert "staging: vchiq: switch to wait_for_completion_killable"

This reverts commit a772f116702e3f0afdd7e6acadc1b8fb3b20b9ff.
---
.../interface/vchiq_arm/vchiq_arm.c | 21 ++++++++++---------
.../interface/vchiq_arm/vchiq_core.c | 21 ++++++++++---------
.../interface/vchiq_arm/vchiq_util.c | 6 +++---
3 files changed, 25 insertions(+), 23 deletions(-)

diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
index 064d0db4c51e..ccfb8218b83c 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
@@ -560,7 +560,8 @@ add_completion(VCHIQ_INSTANCE_T instance, VCHIQ_REASON_T reason,
vchiq_log_trace(vchiq_arm_log_level,
"%s - completion queue full", __func__);
DEBUG_COUNT(COMPLETION_QUEUE_FULL_COUNT);
- if (wait_for_completion_killable( &instance->remove_event)) {
+ if (wait_for_completion_interruptible(
+ &instance->remove_event)) {
vchiq_log_info(vchiq_arm_log_level,
"service_callback interrupted");
return VCHIQ_RETRY;
@@ -671,7 +672,7 @@ service_callback(VCHIQ_REASON_T reason, struct vchiq_header *header,
}

DEBUG_TRACE(SERVICE_CALLBACK_LINE);
- if (wait_for_completion_killable(
+ if (wait_for_completion_interruptible(
&user_service->remove_event)
!= 0) {
vchiq_log_info(vchiq_arm_log_level,
@@ -1006,7 +1007,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
has been closed until the client library calls the
CLOSE_DELIVERED ioctl, signalling close_event. */
if (user_service->close_pending &&
- wait_for_completion_killable(
+ wait_for_completion_interruptible(
&user_service->close_event))
status = VCHIQ_RETRY;
break;
@@ -1182,7 +1183,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)

DEBUG_TRACE(AWAIT_COMPLETION_LINE);
mutex_unlock(&instance->completion_mutex);
- rc = wait_for_completion_killable(
+ rc = wait_for_completion_interruptible(
&instance->insert_event);
mutex_lock(&instance->completion_mutex);
if (rc != 0) {
@@ -1352,7 +1353,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
do {
spin_unlock(&msg_queue_spinlock);
DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
- if (wait_for_completion_killable(
+ if (wait_for_completion_interruptible(
&user_service->insert_event)) {
vchiq_log_info(vchiq_arm_log_level,
"DEQUEUE_MESSAGE interrupted");
@@ -2360,7 +2361,7 @@ vchiq_keepalive_thread_func(void *v)
while (1) {
long rc = 0, uc = 0;

- if (wait_for_completion_killable(&arm_state->ka_evt)
+ if (wait_for_completion_interruptible(&arm_state->ka_evt)
!= 0) {
vchiq_log_error(vchiq_susp_log_level,
"%s interrupted", __func__);
@@ -2611,7 +2612,7 @@ block_resume(struct vchiq_arm_state *arm_state)
write_unlock_bh(&arm_state->susp_res_lock);
vchiq_log_info(vchiq_susp_log_level, "%s wait for previously "
"blocked clients", __func__);
- if (wait_for_completion_killable_timeout(
+ if (wait_for_completion_interruptible_timeout(
&arm_state->blocked_blocker, timeout_val)
<= 0) {
vchiq_log_error(vchiq_susp_log_level, "%s wait for "
@@ -2637,7 +2638,7 @@ block_resume(struct vchiq_arm_state *arm_state)
write_unlock_bh(&arm_state->susp_res_lock);
vchiq_log_info(vchiq_susp_log_level, "%s wait for resume",
__func__);
- if (wait_for_completion_killable_timeout(
+ if (wait_for_completion_interruptible_timeout(
&arm_state->vc_resume_complete, timeout_val)
<= 0) {
vchiq_log_error(vchiq_susp_log_level, "%s wait for "
@@ -2844,7 +2845,7 @@ vchiq_arm_force_suspend(struct vchiq_state *state)
do {
write_unlock_bh(&arm_state->susp_res_lock);

- rc = wait_for_completion_killable_timeout(
+ rc = wait_for_completion_interruptible_timeout(
&arm_state->vc_suspend_complete,
msecs_to_jiffies(FORCE_SUSPEND_TIMEOUT_MS));

@@ -2940,7 +2941,7 @@ vchiq_arm_allow_resume(struct vchiq_state *state)
write_unlock_bh(&arm_state->susp_res_lock);

if (resume) {
- if (wait_for_completion_killable(
+ if (wait_for_completion_interruptible(
&arm_state->vc_resume_complete) < 0) {
vchiq_log_error(vchiq_susp_log_level,
"%s interrupted", __func__);
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c
index 53f5a1cb4636..50189223f05b 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c
@@ -590,7 +590,7 @@ reserve_space(struct vchiq_state *state, size_t space, int is_blocking)
remote_event_signal(&state->remote->trigger);

if (!is_blocking ||
- (wait_for_completion_killable(
+ (wait_for_completion_interruptible(
&state->slot_available_event)))
return NULL; /* No space available */
}
@@ -860,7 +860,7 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
spin_unlock(&quota_spinlock);
mutex_unlock(&state->slot_mutex);

- if (wait_for_completion_killable(
+ if (wait_for_completion_interruptible(
&state->data_quota_event))
return VCHIQ_RETRY;

@@ -891,7 +891,7 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
service_quota->slot_use_count);
VCHIQ_SERVICE_STATS_INC(service, quota_stalls);
mutex_unlock(&state->slot_mutex);
- if (wait_for_completion_killable(
+ if (wait_for_completion_interruptible(
&service_quota->quota_event))
return VCHIQ_RETRY;
if (service->closing)
@@ -1740,7 +1740,8 @@ parse_rx_slots(struct vchiq_state *state)
&service->bulk_rx : &service->bulk_tx;

DEBUG_TRACE(PARSE_LINE);
- if (mutex_lock_killable(&service->bulk_mutex)) {
+ if (mutex_lock_killable(
+ &service->bulk_mutex) != 0) {
DEBUG_TRACE(PARSE_LINE);
goto bail_not_ready;
}
@@ -2456,7 +2457,7 @@ vchiq_open_service_internal(struct vchiq_service *service, int client_id)
QMFLAGS_IS_BLOCKING);
if (status == VCHIQ_SUCCESS) {
/* Wait for the ACK/NAK */
- if (wait_for_completion_killable(&service->remove_event)) {
+ if (wait_for_completion_interruptible(&service->remove_event)) {
status = VCHIQ_RETRY;
vchiq_release_service_internal(service);
} else if ((service->srvstate != VCHIQ_SRVSTATE_OPEN) &&
@@ -2823,7 +2824,7 @@ vchiq_connect_internal(struct vchiq_state *state, VCHIQ_INSTANCE_T instance)
}

if (state->conn_state == VCHIQ_CONNSTATE_CONNECTING) {
- if (wait_for_completion_killable(&state->connect))
+ if (wait_for_completion_interruptible(&state->connect))
return VCHIQ_RETRY;

vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTED);
@@ -2922,7 +2923,7 @@ vchiq_close_service(VCHIQ_SERVICE_HANDLE_T handle)
}

while (1) {
- if (wait_for_completion_killable(&service->remove_event)) {
+ if (wait_for_completion_interruptible(&service->remove_event)) {
status = VCHIQ_RETRY;
break;
}
@@ -2983,7 +2984,7 @@ vchiq_remove_service(VCHIQ_SERVICE_HANDLE_T handle)
request_poll(service->state, service, VCHIQ_POLL_REMOVE);
}
while (1) {
- if (wait_for_completion_killable(&service->remove_event)) {
+ if (wait_for_completion_interruptible(&service->remove_event)) {
status = VCHIQ_RETRY;
break;
}
@@ -3066,7 +3067,7 @@ VCHIQ_STATUS_T vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle,
VCHIQ_SERVICE_STATS_INC(service, bulk_stalls);
do {
mutex_unlock(&service->bulk_mutex);
- if (wait_for_completion_killable(
+ if (wait_for_completion_interruptible(
&service->bulk_remove_event)) {
status = VCHIQ_RETRY;
goto error_exit;
@@ -3143,7 +3144,7 @@ VCHIQ_STATUS_T vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle,

if (bulk_waiter) {
bulk_waiter->bulk = bulk;
- if (wait_for_completion_killable(&bulk_waiter->event))
+ if (wait_for_completion_interruptible(&bulk_waiter->event))
status = VCHIQ_RETRY;
else if (bulk_waiter->actual == VCHIQ_BULK_ACTUAL_ABORTED)
status = VCHIQ_ERROR;
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.c
index 55c5fd82b911..30deea1b57f7 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.c
@@ -80,7 +80,7 @@ void vchiu_queue_push(struct vchiu_queue *queue, struct vchiq_header *header)
return;

while (queue->write == queue->read + queue->size) {
- if (wait_for_completion_killable(&queue->pop))
+ if (wait_for_completion_interruptible(&queue->pop))
flush_signals(current);
}

@@ -93,7 +93,7 @@ void vchiu_queue_push(struct vchiu_queue *queue, struct vchiq_header *header)
struct vchiq_header *vchiu_queue_peek(struct vchiu_queue *queue)
{
while (queue->write == queue->read) {
- if (wait_for_completion_killable(&queue->push))
+ if (wait_for_completion_interruptible(&queue->push))
flush_signals(current);
}

@@ -107,7 +107,7 @@ struct vchiq_header *vchiu_queue_pop(struct vchiu_queue *queue)
struct vchiq_header *header;

while (queue->write == queue->read) {
- if (wait_for_completion_killable(&queue->push))
+ if (wait_for_completion_interruptible(&queue->push))
flush_signals(current);
}

--
2.21.0

2019-04-05 11:35:48

by Nicolas Saenz Julienne

[permalink] [raw]
Subject: [PATCH 3/3] staging: vchiq: make wait events interruptible

The killable version of wait_event() is meant to be used on situations
where it's not meant to fail at all costs, but still have the convenience
of being able to kill it if really necessary. For instance it's used
while waiting on an page write on some file systems.

Wait events in VCHIQ don't fit this criteria, as it's mainly used as an
interface to V4L2 and ALSA devices.

Signed-off-by: Nicolas Saenz Julienne <[email protected]>
---
drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c
index 50189223f05b..41257a1df49d 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c
@@ -431,7 +431,7 @@ remote_event_wait(wait_queue_head_t *wq, struct remote_event *event)
if (!event->fired) {
event->armed = 1;
dsb(sy);
- if (wait_event_killable(*wq, event->fired)) {
+ if (wait_event_interruptible(*wq, event->fired)) {
event->armed = 0;
return 0;
}
--
2.21.0

2019-04-05 11:36:48

by Nicolas Saenz Julienne

[permalink] [raw]
Subject: [PATCH 1/3] Revert "staging: vchiq_2835_arm: quit using custom down_interruptible()"

This reverts commit ff5979ad86368425b7da3a25f4e84650b51ff5fd.
---
.../staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
index dd4898861b83..bfc064a5f884 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
@@ -541,7 +541,7 @@ create_pagelist(char __user *buf, size_t count, unsigned short type)
(g_cache_line_size - 1)))) {
char *fragments;

- if (down_killable(&g_free_fragments_sema)) {
+ if (down_interruptible(&g_free_fragments_sema) != 0) {
cleanup_pagelistinfo(pagelistinfo);
return NULL;
}
--
2.21.0

2019-04-05 12:04:11

by Dan Carpenter

[permalink] [raw]
Subject: Re: [PATCH 1/3] Revert "staging: vchiq_2835_arm: quit using custom down_interruptible()"

On Fri, Apr 05, 2019 at 01:34:20PM +0200, Nicolas Saenz Julienne wrote:
> This reverts commit ff5979ad86368425b7da3a25f4e84650b51ff5fd.
> ---

Git kind of sets you up for failure with reverts...

Fix the subject, add a commit message and a Signed off by etc. We need
all the regular stuff. See commit 75ae193626de ("dm: revert
8f50e358153d ("dm: limit the max bio size as BIO_MAX_PAGES *
PAGE_SIZE")") for an example of how to do it nicely.

regards,
dan carpenter

2019-04-05 12:24:55

by Nicolas Saenz Julienne

[permalink] [raw]
Subject: Re: [PATCH 1/3] Revert "staging: vchiq_2835_arm: quit using custom down_interruptible()"

On Fri, 2019-04-05 at 15:02 +0300, Dan Carpenter wrote:
> On Fri, Apr 05, 2019 at 01:34:20PM +0200, Nicolas Saenz Julienne wrote:
> > This reverts commit ff5979ad86368425b7da3a25f4e84650b51ff5fd.
> > ---
>
> Git kind of sets you up for failure with reverts...
>
> Fix the subject, add a commit message and a Signed off by etc. We need
> all the regular stuff. See commit 75ae193626de ("dm: revert
> 8f50e358153d ("dm: limit the max bio size as BIO_MAX_PAGES *
> PAGE_SIZE")") for an example of how to do it nicely.
>

Will do, Thanks!

> regards,
> dan carpenter
>


Attachments:
signature.asc (499.00 B)
This is a digitally signed message part

2019-04-05 12:43:00

by Stefan Wahren

[permalink] [raw]
Subject: Re: [PATCH 0/3] staging: vchiq: use interruptible waits

Hi Nicolas,

Am 05.04.19 um 13:34 schrieb Nicolas Saenz Julienne:
> Hi,
> this series tries to address an issue that came up in Raspbian's kernel
> tree [1]. After pulling from upstream some changes that moved wait calls
> from a custom implementation to the more standard killable family some
> users complained that all the VCHIQ threads showed up in D state (which
> is the expected behaviour).

this issue has already been noticed in mainline distributions [1],[2].

> The custom implementation we deleted tried to mimic the killable family
> of functions, yet accepted more signals than the later. SIGKILL |
> SIGINT | SIGQUIT | SIGTRAP | SIGSTOP | SIGCONT for the custom
> implementation as opposed to plain old SIGKILL.
>
> Raspbian maintainers decided roll back some of those changes and leave
> the wait functions as interruptible. Hence creating some divergence
> between both trees.
>
> One could argue that not liking having the threads stuck in D state is
> not really a software issue. It's more a cosmetic thing that can scare
> people when they look at "uptime". On the other hand, if we are ever to
> unstage this driver, we'd really need a proper justification for using
> the killable family of functions. Which I think it's not really clear at
> the moment.

I like to see this decision as a short comment in the code to prevent
other for doing this mistake again.

Thanks

Stefan

>
> As Raspbian's kernel has been working for a while with interruptible
> waits I propose we follow through. If needed we can always go back to
> killable. But at least we'll have a proper understanding on the actual
> needs. In the end the driver is in staging, and the potential for errors
> small.
>
> Regards,
> Nicolas
>
> [1] https://github.com/raspberrypi/linux/issues/2881
>
[1] - https://archlinuxarm.org/forum/viewtopic.php?f=65&t=13485

[2] -
https://lists.fedoraproject.org/archives/list/[email protected]/message/GBXGJ7DOV5CQQXFPOZCXTRD6W4BEPT4Q/

2019-04-05 12:48:25

by Stefan Wahren

[permalink] [raw]
Subject: Re: [PATCH 3/3] staging: vchiq: make wait events interruptible

Am 05.04.19 um 13:34 schrieb Nicolas Saenz Julienne:
> The killable version of wait_event() is meant to be used on situations
> where it's not meant to fail at all costs, but still have the convenience
> of being able to kill it if really necessary. For instance it's used
> while waiting on an page write on some file systems.
>
> Wait events in VCHIQ don't fit this criteria, as it's mainly used as an
> interface to V4L2 and ALSA devices.
>
> Signed-off-by: Nicolas Saenz Julienne <[email protected]>
Shouldn't this have a Fixes tag?