mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Vitalii Demianets <vitas@nppfactor.kiev.ua>
To: "Hans J. Koch" <hjk@hansjkoch.de>
Cc: Cong Ding <dinggnu@gmail.com>,
	linux-kernel@vger.kernel.org,
	"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>
Subject: Re: [PATCH v2] drivers/uio/uio_pdrv_genirq.c: Fix memory freeing issues
Date: Fri, 7 Dec 2012 17:00:54 +0200	[thread overview]
Message-ID: <201212071700.54367.vitas@nppfactor.kiev.ua> (raw)
In-Reply-To: <201212071551.02974.vitas@nppfactor.kiev.ua>

On Friday 07 December 2012 15:51:02 Vitalii Demianets wrote:
> On Friday 07 December 2012 11:41:45 Vitalii Demianets wrote:
> > On Friday 07 December 2012 00:15:59 Hans J. Koch wrote:
> > > On Thu, Dec 06, 2012 at 11:11:38AM +0200, Vitalii Demianets wrote:
> > > > On Thursday 06 December 2012 04:41:01 Hans J. Koch wrote:
> > > > > > @@ -63,7 +68,7 @@ static irqreturn_t uio_pdrv_genirq_handler(int
> > > > > > irq,
> > > >
> > > > struct uio_info *dev_info)
> > > >
> > > > > >  	 * remember the state so we can allow user space to enable it
> > > > > > later. */
> > > > > >
> > > > > > -	if (!test_and_set_bit(0, &priv->flags))
> > > > > > +	if (!test_and_set_bit(UIO_IRQ_DISABLED, &priv->flags))
> > > > > >  		disable_irq_nosync(irq);
> > > > >
> > > > > That is not safe. That flag can only be changed by userspace, and
> > > > > if the userspace part is not running, the CPU on which the irq is
> > > > > pending will hang.
> > > > > The handler has to disable the interrupt in any case.
> > > > > (The original version had the same problem, I know...)
> > > >
> > > > Perhaps I'm missing something here, but I don't see your point. If
> > > > userspace is not (implicitly) calling uio_pdrv_genirq_irqcontrol() by
> > > > writing to the device file, then on the first invocation of interrupt
> > > > handler that IRQ is disabled by disable_irq_nosync() and that's the
> > > > end of story - no more irqs, no problems. Until userspace writes
> > > > non-zero to the device file, of course.
> > >
> > > If you run into the irq handler, the interrupt was obviously enabled.
> > > Since irq sharing is not supported by this driver, you ALWAYS have to
> > > disable it because it IS your interrupt. Storing the enabled/disabled
> > > status in a variable is not needed at all here. Or am I missing
> > > something?
> >
> > Good point. I agree that having UIO_IRQ_DISABLED flag is redundant.
> > Inside the irq handler we know for sure that irq is enabled. In
> > uio_pdrv_genirq_irqcontrol() this knowledge is not mandatory, we could
> > enable/disable irq unconditionally.
>
> On second thought, we can't call enable_irq()/disable_irq() unconditionally
> because of the potential disable counter (irq_desc->depth) disbalance.
> That's why we need UIO_IRQ_DISABLED flag, and that's why we should check it
> in uio_pdrv_genirq_irqcontrol().
> On the other hand, you are right in that we don't need to check it inside
> irq handler. Inside irq handler we can disable irq and set the flag
> unconditionally, because:
> a) We know for sure that irqs are enabled, because we are inside
> (not-shared) irq handler;
>  and
> b) We are guarded from potential race conditions by spin_lock_irqsave()
> call in uio_pdrv_genirq_irqcontrol().
>
> So,yes, we can get rid of costly atomic call to
> test_and_set_bit(UIO_IRQ_DISABLED,..) inside irq handler. But I still don't
> like the idea of mixing this optimization with bug fixes in a single patch.

On the third thought, we can't ;)
Imagine the SMP system where uio_pdrv_genirq_irqcontrol() is being executed on 
CPU0 and irq handler is running concurrently on CPU1. To protect from 
disable_irq counter disbalance we must first check current irq status, and in 
atomic manner. Thus we prevent  double-disable, one from 
uio_pdrv_genirq_irqcontrol() running on CPU0 and another form irq handler 
running on CPU1.
Above consideration justifies current code.

But it seems we have potential concurrency problem here anyway. Here is 
theoretical scenario:
1) Initial state: irq is enabled, uio_pdrv_genirq_irqcontrol() starts being 
executed on CPU0 with irq_on=1 and at the same time, concurrently, irq 
handler starts being executed on CPU1;
2) irq handler executes line
   if (!test_and_set_bit(UIO_IRQ_DISABLED, &priv->flags))
as irq was enabled, the condition holds. And now UIO_IRQ_DISABLED is set.
3) uio_pdrv_genirq_irqcontrol() executes line
   if (test_and_clear_bit(UIO_IRQ_DISABLED, &priv->flags))
as UIO_IRQ_DISABLED was set by CPU1, the condition holds. And now 
UIO_IRQ_DISABLED is cleared.
4) CPU0 executes enable_irq() . IRQ is enabled. "Unbalanced enable for 
IRQ %d\n" warning is issued.
5) irq handler on CPU1 executes disable_irq_nosync(). IRQ is disabled.

And now we are in situation where IRQ is disabled, but UIO_IRQ_DISABLED is 
cleared. Bad.

The above scenario is purely theoretical, I have no means to check it in 
hardware.
The (theoretical) solution is to guard UIO_IRQ_DISABLED test and actual irq 
disabling inside irq handler by priv->lock.

What do you think about it? Is it worth worrying about?

  reply	other threads:[~2012-12-07 15:00 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-11-27 17:29 [PATCH] drivers/uio/uio_pdrv_genirq.c: Fix memory leak & confusing labels Vitalii Demianets
2012-11-27 23:07 ` Hans J. Koch
2012-11-28  0:07   ` Cong Ding
2012-11-28  0:37     ` Hans J. Koch
2012-11-28  9:29       ` Cong Ding
2012-11-28 21:09         ` Hans J. Koch
2012-11-28  9:37       ` Vitalii Demianets
2012-11-28 21:14         ` Hans J. Koch
2012-11-29 11:47           ` [PATCH] drivers/uio/uio_pdrv_genirq.c: Fix memory freeing issues Vitalii Demianets
2012-12-04 21:04             ` Hans J. Koch
2012-12-05  9:22               ` [PATCH v2] " Vitalii Demianets
2012-12-06  2:41                 ` Hans J. Koch
2012-12-06  9:11                   ` Vitalii Demianets
2012-12-06 22:15                     ` Hans J. Koch
2012-12-07  9:41                       ` Vitalii Demianets
2012-12-07 13:51                         ` Vitalii Demianets
2012-12-07 15:00                           ` Vitalii Demianets [this message]
2012-12-07 23:47                             ` Hans J. Koch
2012-12-10  9:03                               ` Vitalii Demianets
2012-12-10  9:52                                 ` Hans J. Koch
2012-12-10 10:24                                   ` Vitalii Demianets
2012-12-10 22:37                                     ` Hans J. Koch
2012-12-11 10:47                                       ` Vitalii Demianets
2012-12-13 17:11                                         ` Hans J. Koch
2012-12-13 17:23                                           ` Vitalii Demianets
2012-12-13 17:34                                             ` Hans J. Koch
2012-12-13 18:00                                               ` Vitalii Demianets

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=201212071700.54367.vitas@nppfactor.kiev.ua \
    --to=vitas@nppfactor.kiev.ua \
    --cc=dinggnu@gmail.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=hjk@hansjkoch.de \
    --cc=linux-kernel@vger.kernel.org \
    /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

all inboxes | Powered by JetHome®