linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
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();
>  }
>  



  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).