From: Ivo van Doorn <ivdoorn@gmail.com>
To: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Cc: John Linville <linville@tuxdriver.com>,
linux-wireless@vger.kernel.org, Dmitry Torokhov <dtor@mail.ru>
Subject: Re: [PATCH 5/5] rfkill: rate-limit rfkill-input workqueue usage (v3)
Date: Sat, 11 Oct 2008 15:53:52 +0200 [thread overview]
Message-ID: <200810111553.52856.IvDoorn@gmail.com> (raw)
In-Reply-To: <1223586933-17753-6-git-send-email-hmh@hmh.eng.br>
On Thursday 09 October 2008, Henrique de Moraes Holschuh wrote:
> Limit the number of "expensive" rfkill workqueue operations per second, in
> order to not hog system resources too much when faced with a rogue source
> of rfkill input events.
>
> The old rfkill-input code (before it was refactored) had such a limit in
> place. It used to drop new events that were past the rate limit. This
> behaviour was not implemented as an anti-DoS measure, but rather as an
> attempt to work around deficiencies in input device drivers which would
> issue multiple KEY_FOO events too soon for a given key FOO (i.e. ones that
> do not implement mechanical debouncing properly).
>
> However, we can't really expect such issues to be worked around by every
> input handler out there, and also by every userspace client of input
> devices. It is the input device driver's responsability to do debouncing
> instead of spamming the input layer with bogus events.
>
> The new limiter code is focused only on anti-DoS behaviour, and tries to
> not lose events (instead, it coalesces them when possible).
>
> The transmitters are updated once every 200ms, maximum. Care is taken not
> to delay a request to _enter_ rfkill transmitter Emergency Power Off (EPO)
> mode.
>
> If mistriggered (e.g. by a jiffies counter wrap), the code delays processing
> *once* by 200ms.
>
> Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
> Cc: Ivo van Doorn <IvDoorn@gmail.com>
> Cc: Dmitry Torokhov <dtor@mail.ru>
Acked-by: Ivo van Doorn <IvDoorn@gmail.com>
> ---
> net/rfkill/rfkill-input.c | 49 +++++++++++++++++++++++++++++++++++++-------
> 1 files changed, 41 insertions(+), 8 deletions(-)
>
> diff --git a/net/rfkill/rfkill-input.c b/net/rfkill/rfkill-input.c
> index 4ea4e68..6ddf3ce 100644
> --- a/net/rfkill/rfkill-input.c
> +++ b/net/rfkill/rfkill-input.c
> @@ -30,6 +30,9 @@ enum rfkill_input_master_mode {
> RFKILL_INPUT_MASTER_MAX, /* marker */
> };
>
> +/* Delay (in ms) between consecutive switch ops */
> +#define RFKILL_OPS_DELAY 200
> +
> static enum rfkill_input_master_mode rfkill_master_switch_mode =
> RFKILL_INPUT_MASTER_UNBLOCKALL;
> module_param_named(master_switch_mode, rfkill_master_switch_mode, uint, 0);
> @@ -50,7 +53,7 @@ enum rfkill_global_sched_op {
> */
>
> struct rfkill_task {
> - struct work_struct work;
> + struct delayed_work dwork;
>
> /* ensures that task is serialized */
> struct mutex mutex;
> @@ -74,6 +77,9 @@ struct rfkill_task {
>
> bool global_op_pending;
> enum rfkill_global_sched_op op;
> +
> + /* last time it was scheduled */
> + unsigned long last_scheduled;
> };
>
> static void __rfkill_handle_global_op(enum rfkill_global_sched_op op)
> @@ -137,8 +143,8 @@ static void __rfkill_handle_normal_op(const enum rfkill_type type,
>
> static void rfkill_task_handler(struct work_struct *work)
> {
> - struct rfkill_task *task =
> - container_of(work, struct rfkill_task, work);
> + struct rfkill_task *task = container_of(work,
> + struct rfkill_task, dwork.work);
> bool doit = true;
>
> mutex_lock(&task->mutex);
> @@ -193,12 +199,27 @@ static void rfkill_task_handler(struct work_struct *work)
> }
>
> static struct rfkill_task rfkill_task = {
> - .work = __WORK_INITIALIZER(rfkill_task.work,
> + .dwork = __DELAYED_WORK_INITIALIZER(rfkill_task.dwork,
> rfkill_task_handler),
> .mutex = __MUTEX_INITIALIZER(rfkill_task.mutex),
> .lock = __SPIN_LOCK_UNLOCKED(rfkill_task.lock),
> };
>
> +static unsigned long rfkill_ratelimit(const unsigned long last)
> +{
> + const unsigned long delay = msecs_to_jiffies(RFKILL_OPS_DELAY);
> + return (time_after(jiffies, last + delay)) ? 0 : delay;
> +}
> +
> +static void rfkill_schedule_ratelimited(void)
> +{
> + if (!delayed_work_pending(&rfkill_task.dwork)) {
> + schedule_delayed_work(&rfkill_task.dwork,
> + rfkill_ratelimit(rfkill_task.last_scheduled));
> + rfkill_task.last_scheduled = jiffies;
> + }
> +}
> +
> static void rfkill_schedule_global_op(enum rfkill_global_sched_op op)
> {
> unsigned long flags;
> @@ -206,7 +227,13 @@ static void rfkill_schedule_global_op(enum rfkill_global_sched_op op)
> spin_lock_irqsave(&rfkill_task.lock, flags);
> rfkill_task.op = op;
> rfkill_task.global_op_pending = true;
> - schedule_work(&rfkill_task.work);
> + if (op == RFKILL_GLOBAL_OP_EPO && !rfkill_is_epo_lock_active()) {
> + /* bypass the limiter for EPO */
> + cancel_delayed_work(&rfkill_task.dwork);
> + schedule_delayed_work(&rfkill_task.dwork, 0);
> + rfkill_task.last_scheduled = jiffies;
> + } else
> + rfkill_schedule_ratelimited();
> spin_unlock_irqrestore(&rfkill_task.lock, flags);
> }
>
> @@ -230,7 +257,7 @@ static void rfkill_schedule_set(enum rfkill_type type,
> set_bit(type, rfkill_task.sw_newstate);
> else
> clear_bit(type, rfkill_task.sw_newstate);
> - schedule_work(&rfkill_task.work);
> + rfkill_schedule_ratelimited();
> }
> spin_unlock_irqrestore(&rfkill_task.lock, flags);
> }
> @@ -247,7 +274,7 @@ static void rfkill_schedule_toggle(enum rfkill_type type)
> if (!rfkill_task.global_op_pending) {
> set_bit(type, rfkill_task.sw_pending);
> change_bit(type, rfkill_task.sw_togglestate);
> - schedule_work(&rfkill_task.work);
> + rfkill_schedule_ratelimited();
> }
> spin_unlock_irqrestore(&rfkill_task.lock, flags);
> }
> @@ -411,13 +438,19 @@ static int __init rfkill_handler_init(void)
> if (rfkill_master_switch_mode >= RFKILL_INPUT_MASTER_MAX)
> return -EINVAL;
>
> + /*
> + * The penalty to not doing this is a possible RFKILL_OPS_DELAY delay
> + * at the first use. Acceptable, but if we can avoid it, why not?
> + */
> + rfkill_task.last_scheduled =
> + jiffies - msecs_to_jiffies(RFKILL_OPS_DELAY) - 1;
> return input_register_handler(&rfkill_handler);
> }
>
> static void __exit rfkill_handler_exit(void)
> {
> input_unregister_handler(&rfkill_handler);
> - flush_scheduled_work();
> + cancel_delayed_work_sync(&rfkill_task.dwork);
> rfkill_remove_epo_lock();
> }
>
next prev parent reply other threads:[~2008-10-11 13:54 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-10-09 21:15 [GIT PATCH] rfkill updates Henrique de Moraes Holschuh
2008-10-09 21:15 ` [PATCH 1/5] rfkill: use killable locks instead of interruptible Henrique de Moraes Holschuh
2008-10-11 13:53 ` Ivo van Doorn
2008-10-09 21:15 ` [PATCH 2/5] rfkill: export global states to rfkill-input Henrique de Moraes Holschuh
2008-10-11 13:53 ` Ivo van Doorn
2008-10-09 21:15 ` [PATCH 3/5] rfkill: add master_switch_mode and EPO lock to rfkill and rfkill-input Henrique de Moraes Holschuh
2008-10-09 21:20 ` Henrique de Moraes Holschuh
2008-10-10 0:49 ` Henrique de Moraes Holschuh
2008-10-11 13:53 ` Ivo van Doorn
2008-10-12 1:44 ` Henrique de Moraes Holschuh
2008-10-09 21:15 ` [PATCH 4/5] rfkill: honour EPO state when resuming a rfkill controller Henrique de Moraes Holschuh
2008-10-11 13:53 ` Ivo van Doorn
2008-10-09 21:15 ` [PATCH 5/5] rfkill: rate-limit rfkill-input workqueue usage (v3) Henrique de Moraes Holschuh
2008-10-11 13:53 ` Ivo van Doorn [this message]
2008-10-11 13:53 ` [GIT PATCH] rfkill updates Ivo van Doorn
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=200810111553.52856.IvDoorn@gmail.com \
--to=ivdoorn@gmail.com \
--cc=dtor@mail.ru \
--cc=hmh@hmh.eng.br \
--cc=linux-wireless@vger.kernel.org \
--cc=linville@tuxdriver.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).