All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC] firmware loader: retry _nowait requests when userhelper is not yet available
@ 2012-03-03 20:22 Christian Lamparter
  2012-03-03 23:57 ` Alan Cox
  2012-03-05 20:12 ` Srivatsa S. Bhat
  0 siblings, 2 replies; 111+ messages in thread
From: Christian Lamparter @ 2012-03-03 20:22 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh, chunkeey

During resume, the userhelper might not be available. However for
drivers which use the request_firmware_nowait interface, this will
only lead to a pointless WARNING and a device which no longer works
after the resume [since it couldn't get the firmware, because the
userhelper was not available to take the request].

In order to solve this "chicken or egg" dilemma, the code now
retries _nowait requests at one second intervals until the
"loading_timeout" time is up.

---
I'm aware about the previous "request_firmware* in probe" discussions.
Unfortunately, the hardware needs firmware so there is no other way
around it. So please, I just wanted to know what the general opinion
about the idea behind this patch is.

Regards,
	Christian

BTW: I'm not on the list, so please keep the 'CC'.
---
 drivers/base/firmware_class.c |   24 +++++++++++++++++++++++-
 1 files changed, 23 insertions(+), 1 deletions(-)

diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 6c9387d..9f70096 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -19,6 +19,7 @@
 #include <linux/kthread.h>
 #include <linux/highmem.h>
 #include <linux/firmware.h>
+#include <linux/delay.h>
 #include <linux/slab.h>
 
 #define to_dev(obj) container_of(obj, struct device, kobj)
@@ -535,6 +536,11 @@ static int _request_firmware(const struct firmware **firmware_p,
 
 	read_lock_usermodehelper();
 
+	if (nowait && usermodehelper_is_disabled()) {
+		retval = -EBUSY;
+		goto out;
+	}
+
 	if (WARN_ON(usermodehelper_is_disabled())) {
 		dev_err(device, "firmware: %s will not be loaded\n", name);
 		retval = -EBUSY;
@@ -633,7 +639,7 @@ static int request_firmware_work_func(void *arg)
 {
 	struct firmware_work *fw_work = arg;
 	const struct firmware *fw;
-	int ret;
+	int ret, timeout = loading_timeout;
 
 	if (!arg) {
 		WARN_ON(1);
@@ -642,6 +648,22 @@ static int request_firmware_work_func(void *arg)
 
 	ret = _request_firmware(&fw, fw_work->name, fw_work->device,
 				fw_work->uevent, true);
+
+	while (ret == -EBUSY) {
+		/*
+		 * Try to retrieve the firmware within the loading timeout.
+		 * To stick with the loading timeout convention from above:
+		 *	loading_timeout = 0 means 'try forever' as well.
+		 */
+
+		msleep(1000);
+		ret = _request_firmware(&fw, fw_work->name, fw_work->device,
+					fw_work->uevent, true);
+
+		if (timeout != 0 && timeout-- == 1)
+			break;
+	};
+
 	fw_work->cont(fw, fw_work->context);
 
 	module_put(fw_work->module);
-- 
1.7.9.1


^ permalink raw reply related	[flat|nested] 111+ messages in thread

* Re: [RFC] firmware loader: retry _nowait requests when userhelper is not yet available
  2012-03-03 20:22 [RFC] firmware loader: retry _nowait requests when userhelper is not yet available Christian Lamparter
@ 2012-03-03 23:57 ` Alan Cox
  2012-03-04  1:50   ` Christian Lamparter
  2012-03-05 20:12 ` Srivatsa S. Bhat
  1 sibling, 1 reply; 111+ messages in thread
From: Alan Cox @ 2012-03-03 23:57 UTC (permalink / raw)
  To: Christian Lamparter; +Cc: linux-kernel, gregkh

On Sat, 3 Mar 2012 21:22:36 +0100
Christian Lamparter <chunkeey@googlemail.com> wrote:

> During resume, the userhelper might not be available. However for
> drivers which use the request_firmware_nowait interface, this will
> only lead to a pointless WARNING and a device which no longer works
> after the resume [since it couldn't get the firmware, because the
> userhelper was not available to take the request].

Can you not load the firmware on the suspend path ?

Alan

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [RFC] firmware loader: retry _nowait requests when userhelper is not yet available
  2012-03-03 23:57 ` Alan Cox
@ 2012-03-04  1:50   ` Christian Lamparter
  0 siblings, 0 replies; 111+ messages in thread
From: Christian Lamparter @ 2012-03-04  1:50 UTC (permalink / raw)
  To: Alan Cox; +Cc: linux-kernel, gregkh

On Sunday 04 March 2012 00:57:04 Alan Cox wrote:
> On Sat, 3 Mar 2012 21:22:36 +0100
> Christian Lamparter <chunkeey@googlemail.com> wrote:
> 
> > During resume, the userhelper might not be available. However for
> > drivers which use the request_firmware_nowait interface, this will
> > only lead to a pointless WARNING and a device which no longer works
> > after the resume [since it couldn't get the firmware, because the
> > userhelper was not available to take the request].
> 
> Can you not load the firmware on the suspend path ?
>
If I could, I would fetch the firmware "open" as it is supposed to be.
But, but the driver's "remove" op is called during resume by the "bus".
So, everything will vanish with it.

But see for yourself: In my case I have to deal with a pci-chip [isl3886,
p54pci driver] that comes on board of a cardbus card. The code that
does the "unbind/rebind" is in drivers/pcmcia/cs.c, function: socket_late_resume

>	if (skt->state & SOCKET_CARDBUS) {
>		/* We can't be sure the CardBus card is the same
>		 * as the one previously inserted. Therefore, remove
>		 * and re-add... */
>		cb_free(skt);
>		cb_alloc(skt);
>		return 0;
>	}
Of course cb_free(...) is just a elaborate way of saying:
	pci_remove_behind_bridge(pcmcia_socket);
[And cb_alloc obviously just re-"probe"s the device in the
cardbus socket again...]

Of course, in my case, I could tuck the firmware away in a some
static const struct firmware* somewhere within the driver code.
But then someone [like you :-D] will yell at me for hiding it in a
file-global stash of ugliness.

Regards,
	Christian

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [RFC] firmware loader: retry _nowait requests when userhelper is not yet available
  2012-03-03 20:22 [RFC] firmware loader: retry _nowait requests when userhelper is not yet available Christian Lamparter
  2012-03-03 23:57 ` Alan Cox
@ 2012-03-05 20:12 ` Srivatsa S. Bhat
  2012-03-09 22:30   ` [PATCH] firmware loader: don't cancel _nowait requests when helper " Christian Lamparter
  2012-03-16 22:19   ` [RFC] firmware loader: retry _nowait requests when userhelper " Rafael J. Wysocki
  1 sibling, 2 replies; 111+ messages in thread
From: Srivatsa S. Bhat @ 2012-03-05 20:12 UTC (permalink / raw)
  To: Christian Lamparter
  Cc: linux-kernel, gregkh, alan, Rafael J. Wysocki, Linus Torvalds,
	Linux PM mailing list


[ Adding more Cc's. ]

On 03/04/2012 01:52 AM, Christian Lamparter wrote:

> During resume, the userhelper might not be available. However for
> drivers which use the request_firmware_nowait interface, this will
> only lead to a pointless WARNING and a device which no longer works
> after the resume [since it couldn't get the firmware, because the
> userhelper was not available to take the request].
> 
> In order to solve this "chicken or egg" dilemma, the code now
> retries _nowait requests at one second intervals until the
> "loading_timeout" time is up.
> 
> ---
> I'm aware about the previous "request_firmware* in probe" discussions.
> Unfortunately, the hardware needs firmware so there is no other way
> around it. So please, I just wanted to know what the general opinion
> about the idea behind this patch is.
> 
> Regards,
> 	Christian
> 
> BTW: I'm not on the list, so please keep the 'CC'.
> ---
>  drivers/base/firmware_class.c |   24 +++++++++++++++++++++++-
>  1 files changed, 23 insertions(+), 1 deletions(-)
> 
> diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
> index 6c9387d..9f70096 100644
> --- a/drivers/base/firmware_class.c
> +++ b/drivers/base/firmware_class.c
> @@ -19,6 +19,7 @@
>  #include <linux/kthread.h>
>  #include <linux/highmem.h>
>  #include <linux/firmware.h>
> +#include <linux/delay.h>
>  #include <linux/slab.h>
> 
>  #define to_dev(obj) container_of(obj, struct device, kobj)
> @@ -535,6 +536,11 @@ static int _request_firmware(const struct firmware **firmware_p,
> 
>  	read_lock_usermodehelper();
> 
> +	if (nowait && usermodehelper_is_disabled()) {
> +		retval = -EBUSY;
> +		goto out;
> +	}
> +
>  	if (WARN_ON(usermodehelper_is_disabled())) {
>  		dev_err(device, "firmware: %s will not be loaded\n", name);
>  		retval = -EBUSY;
> @@ -633,7 +639,7 @@ static int request_firmware_work_func(void *arg)
>  {
>  	struct firmware_work *fw_work = arg;
>  	const struct firmware *fw;
> -	int ret;
> +	int ret, timeout = loading_timeout;
> 
>  	if (!arg) {
>  		WARN_ON(1);
> @@ -642,6 +648,22 @@ static int request_firmware_work_func(void *arg)
> 
>  	ret = _request_firmware(&fw, fw_work->name, fw_work->device,
>  				fw_work->uevent, true);
> +
> +	while (ret == -EBUSY) {
> +		/*
> +		 * Try to retrieve the firmware within the loading timeout.
> +		 * To stick with the loading timeout convention from above:
> +		 *	loading_timeout = 0 means 'try forever' as well.
> +		 */
> +
> +		msleep(1000);
> +		ret = _request_firmware(&fw, fw_work->name, fw_work->device,
> +					fw_work->uevent, true);
> +
> +		if (timeout != 0 && timeout-- == 1)

> +			break;

> +	};

> +

>  	fw_work->cont(fw, fw_work->context);
> 
>  	module_put(fw_work->module);


^ permalink raw reply	[flat|nested] 111+ messages in thread

* [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-05 20:12 ` Srivatsa S. Bhat
@ 2012-03-09 22:30   ` Christian Lamparter
  2012-03-09 23:36     ` Greg KH
  2012-03-16 22:19   ` [RFC] firmware loader: retry _nowait requests when userhelper " Rafael J. Wysocki
  1 sibling, 1 reply; 111+ messages in thread
From: Christian Lamparter @ 2012-03-09 22:30 UTC (permalink / raw)
  To: linux-kernel
  Cc: Srivatsa S. Bhat, gregkh, alan, Rafael J. Wysocki,
	Linus Torvalds, Linux PM mailing list

This patch fixes a regression which was introduced by:
"PM: Print a warning if firmware is requested when tasks are frozen"

request_firmware_nowait does not stall in any system resume paths.
Therefore, I think it is perfectly save to use request_firmware_nowait
from at least the ->complete() callback.

Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
---
 drivers/base/firmware_class.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 6c9387d..017e020 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -535,7 +535,7 @@ static int _request_firmware(const struct firmware **firmware_p,
 
 	read_lock_usermodehelper();
 
-	if (WARN_ON(usermodehelper_is_disabled())) {
+	if (WARN_ON(usermodehelper_is_disabled() && !(nowait && uevent))) {
 		dev_err(device, "firmware: %s will not be loaded\n", name);
 		retval = -EBUSY;
 		goto out;
-- 
1.7.9.1


^ permalink raw reply related	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-09 22:30   ` [PATCH] firmware loader: don't cancel _nowait requests when helper " Christian Lamparter
@ 2012-03-09 23:36     ` Greg KH
  2012-03-10  0:52       ` Christian Lamparter
  2012-03-11 11:56       ` Kay Sievers
  0 siblings, 2 replies; 111+ messages in thread
From: Greg KH @ 2012-03-09 23:36 UTC (permalink / raw)
  To: Christian Lamparter
  Cc: linux-kernel, Srivatsa S. Bhat, alan, Rafael J. Wysocki,
	Linus Torvalds, Linux PM mailing list

On Fri, Mar 09, 2012 at 11:30:24PM +0100, Christian Lamparter wrote:
> This patch fixes a regression which was introduced by:
> "PM: Print a warning if firmware is requested when tasks are frozen"
> 
> request_firmware_nowait does not stall in any system resume paths.
> Therefore, I think it is perfectly save to use request_firmware_nowait
> from at least the ->complete() callback.

Is there code somewhere in the kernel that wants to do this?  Has commit
a144c6a broken it somehow that this fix would resolve it?

> 
> Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
> ---
>  drivers/base/firmware_class.c |    2 +-
>  1 files changed, 1 insertions(+), 1 deletions(-)
> 
> diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
> index 6c9387d..017e020 100644
> --- a/drivers/base/firmware_class.c
> +++ b/drivers/base/firmware_class.c
> @@ -535,7 +535,7 @@ static int _request_firmware(const struct firmware **firmware_p,
>  
>  	read_lock_usermodehelper();
>  
> -	if (WARN_ON(usermodehelper_is_disabled())) {
> +	if (WARN_ON(usermodehelper_is_disabled() && !(nowait && uevent))) {

What does uevent have to do with things here?

greg k-h

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-09 23:36     ` Greg KH
@ 2012-03-10  0:52       ` Christian Lamparter
  2012-03-11 11:56       ` Kay Sievers
  1 sibling, 0 replies; 111+ messages in thread
From: Christian Lamparter @ 2012-03-10  0:52 UTC (permalink / raw)
  To: Greg KH
  Cc: linux-kernel, Srivatsa S. Bhat, alan, Rafael J. Wysocki,
	Linus Torvalds, Linux PM mailing list

On Saturday 10 March 2012 00:36:59 Greg KH wrote:
> On Fri, Mar 09, 2012 at 11:30:24PM +0100, Christian Lamparter wrote:
> > This patch fixes a regression which was introduced by:
> > "PM: Print a warning if firmware is requested when tasks are frozen"
> > 
> > request_firmware_nowait does not stall in any system resume paths.
> > Therefore, I think it is perfectly save to use request_firmware_nowait
> > from at least the ->complete() callback.
> 
> Is there code somewhere in the kernel that wants to do this?
uum, yes: The USB subsystem [Good thing, I'm already talking to you! :-D]

Take a look at drivers/usb/core/usb.c:

the ->complete callback is registered to usb_dev_complete(dev*), which
is just a lengthy wrapper for usb_resume(dev, PMSG_ON).

Now, let's switch to drivers/usb/core/driver.c:

usb_resume calls do_unbind_rebind(udev, DO_REBIND) and there we go...
So any usb driver which uses request_firmware_nowait in .probe is
a possible target for the warning.

The one I stumbled across is the pcmcia subsystem. Currently it
tries to rebind the devices during ->resume but I have already
sent a patch to postpone that till the ->complete callback comes in.
<http://lkml.org/lkml/2012/3/3/101>

> Has commit a144c6a broken it somehow that this fix would resolve it?
When I read the commit, it only talked only about broken drivers doing
"request_firmware" during .probe. But it does not mention what should
be done with "request_firmware_nowait" in such a case at all. I think
it was just an oversight from all involved parties that just got
noticed now.

> > Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
> > ---
> >  drivers/base/firmware_class.c |    2 +-
> >  1 files changed, 1 insertions(+), 1 deletions(-)
> > 
> > diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
> > index 6c9387d..017e020 100644
> > --- a/drivers/base/firmware_class.c
> > +++ b/drivers/base/firmware_class.c
> > @@ -535,7 +535,7 @@ static int _request_firmware(const struct firmware **firmware_p,
> >  
> >  	read_lock_usermodehelper();
> >  
> > -	if (WARN_ON(usermodehelper_is_disabled())) {
> > +	if (WARN_ON(usermodehelper_is_disabled() && !(nowait && uevent))) {
> 
> What does uevent have to do with things here?
I found this "useful" comment about uevent in request_firmware_nowait's kdocs:
 * @uevent: sends uevent to copy the firmware image if this flag
 *      is non-zero else the firmware copy must be done manually.
I think this flag controls whenever we want to sent a firmware request event
to the usermodehelper...
[No idea why this should ever be 'false', maybe there is a good use-case for
it when the firmware is built-in... But anyway let's just say I'm as ignorant
as everybody else and I haven't got a single clue about it.]

Regards,
	Christian

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-09 23:36     ` Greg KH
  2012-03-10  0:52       ` Christian Lamparter
@ 2012-03-11 11:56       ` Kay Sievers
  2012-03-13  9:37         ` Saravana Kannan
                           ` (2 more replies)
  1 sibling, 3 replies; 111+ messages in thread
From: Kay Sievers @ 2012-03-11 11:56 UTC (permalink / raw)
  To: Greg KH
  Cc: Christian Lamparter, linux-kernel, Srivatsa S. Bhat, alan,
	Rafael J. Wysocki, Linus Torvalds, Linux PM mailing list

On Sat, Mar 10, 2012 at 00:36, Greg KH <gregkh@linuxfoundation.org> wrote:
> On Fri, Mar 09, 2012 at 11:30:24PM +0100, Christian Lamparter wrote:
>> This patch fixes a regression which was introduced by:
>> "PM: Print a warning if firmware is requested when tasks are frozen"
>>
>> request_firmware_nowait does not stall in any system resume paths.
>> Therefore, I think it is perfectly save to use request_firmware_nowait
>> from at least the ->complete() callback.
>
> Is there code somewhere in the kernel that wants to do this?  Has commit
> a144c6a broken it somehow that this fix would resolve it?
>
>>
>> Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
>> ---
>>  drivers/base/firmware_class.c |    2 +-
>>  1 files changed, 1 insertions(+), 1 deletions(-)
>>
>> diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
>> index 6c9387d..017e020 100644
>> --- a/drivers/base/firmware_class.c
>> +++ b/drivers/base/firmware_class.c
>> @@ -535,7 +535,7 @@ static int _request_firmware(const struct firmware **firmware_p,
>>
>>       read_lock_usermodehelper();
>>
>> -     if (WARN_ON(usermodehelper_is_disabled())) {
>> +     if (WARN_ON(usermodehelper_is_disabled() && !(nowait && uevent))) {
>
> What does uevent have to do with things here?

I don't think that the firmware loader should care about the
usermodehelper at all, and that stuff fiddling should just be removed
from the firmware class.

Forking /sbin/hotplug is disabled by default, it is a broken concept,
and it cannot work reliably on today's systems.

Firmware is not loaded by /sbin/hotplug since many years, but by udev
or whatever service handles uevents, like ueventd on android.

Kay

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-11 11:56       ` Kay Sievers
@ 2012-03-13  9:37         ` Saravana Kannan
  2012-03-13  9:43         ` Saravana Kannan
  2012-03-13 19:42         ` Rafael J. Wysocki
  2 siblings, 0 replies; 111+ messages in thread
From: Saravana Kannan @ 2012-03-13  9:37 UTC (permalink / raw)
  To: Kay Sievers
  Cc: Greg KH, Christian Lamparter, linux-kernel, Srivatsa S. Bhat,
	alan, Rafael J. Wysocki, Linus Torvalds, Linux PM mailing list,
	Stephen Boyd, Saravana Kannan

On 01/-10/37 11:59, Kay Sievers wrote:
> On Sat, Mar 10, 2012 at 00:36, Greg KH<gregkh@linuxfoundation.org>  wrote:
>> On Fri, Mar 09, 2012 at 11:30:24PM +0100, Christian Lamparter wrote:
>>> This patch fixes a regression which was introduced by:
>>> "PM: Print a warning if firmware is requested when tasks are frozen"
>>>
>>> request_firmware_nowait does not stall in any system resume paths.
>>> Therefore, I think it is perfectly save to use request_firmware_nowait
>>> from at least the ->complete() callback.
>>
>> Is there code somewhere in the kernel that wants to do this?  Has commit
>> a144c6a broken it somehow that this fix would resolve it?
>>
>>>
>>> Signed-off-by: Christian Lamparter<chunkeey@googlemail.com>
>>> ---
>>>   drivers/base/firmware_class.c |    2 +-
>>>   1 files changed, 1 insertions(+), 1 deletions(-)
>>>
>>> diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
>>> index 6c9387d..017e020 100644
>>> --- a/drivers/base/firmware_class.c
>>> +++ b/drivers/base/firmware_class.c
>>> @@ -535,7 +535,7 @@ static int _request_firmware(const struct firmware **firmware_p,
>>>
>>>        read_lock_usermodehelper();
>>>
>>> -     if (WARN_ON(usermodehelper_is_disabled())) {
>>> +     if (WARN_ON(usermodehelper_is_disabled()&&  !(nowait&&  uevent))) {
>>
>> What does uevent have to do with things here?
>
> I don't think that the firmware loader should care about the
> usermodehelper at all, and that stuff fiddling should just be removed
> from the firmware class.
>
> Forking /sbin/hotplug is disabled by default, it is a broken concept,
> and it cannot work reliably on today's systems.
>
> Firmware is not loaded by /sbin/hotplug since many years, but by udev
> or whatever service handles uevents, like ueventd on android.

We (mach-msm) just happened to be looking at similar issues with 
request_firmware. The recent changes to request_firmware to check for 
usermodehelper_is_disabled() was preventing us from using 
request_firmware() in what I think is a valid use case. I will get to 
that later.

To first suggest a solution specific the problem this patch is trying to 
address, I think it would be better to do something like below. It's 
just a quick RFC to show what I mean -- haven't even compiled it. If 
there is an agreement on this suggestion, I can send out a cleaner patch.

firmware class: Check for usermode helper availability only
  when enabled.

Signed-off-by: Saravana Kannan <skannan@codeaurora.org>
---
  drivers/base/firmware_class.c |   15 ++++++++-------
  kernel/kmod.c                 |    2 +-
  2 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 06ed6b4..2a45bf7 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -534,12 +534,6 @@ static int _request_firmware(const struct firmware 
**firmware_p,
                 return 0;
         }

-       if (WARN_ON(usermodehelper_is_disabled())) {
-               dev_err(device, "firmware: %s will not be loaded\n", name);
-               retval = -EBUSY;
-               goto out;
-       }
-
         if (uevent)
                 dev_dbg(device, "firmware: requesting %s\n", name);

@@ -555,12 +549,19 @@ static int _request_firmware(const struct firmware 
**firmware_p,
                                   round_jiffies_up(jiffies +
                                                    loading_timeout * HZ));

-               kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD);
+               retval = kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD);
+               if (retval) {
+                       dev_err(device, "firmware: %s will not be 
loaded\n", name);
+                       set_bit(FW_STATUS_ABORT, &fw_priv->status);
+                       goto abort;
+               }
         }

         wait_for_completion(&fw_priv->completion);

         set_bit(FW_STATUS_DONE, &fw_priv->status);
+
+abort:
         del_timer_sync(&fw_priv->timeout);

         mutex_lock(&fw_lock);

diff --git a/kernel/kmod.c b/kernel/kmod.c
index 47613df..e733afe3 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -422,7 +422,7 @@ int call_usermodehelper_exec(struct subprocess_info 
*sub_info,
         if (sub_info->path[0] == '\0')
                 goto out;

-       if (!khelper_wq || usermodehelper_disabled) {
+       if (!khelper_wq || (uevent_helper[0] && usermodehelper_disabled)) {
                 retval = -EBUSY;
                 goto out;
         }
-- 


Now, getting to the issue we are facing -- the recent checks for 
usermode helper in request_firmare() is failing request_firmware() in a 
kthread that also activates a wake up source (or if you are familiar 
with Android terms -- grabs a wake lock). By activating a wakeup source, 
the kthread is properly indicating that a suspend shouldn't happen. So, 
I think it's a valid use case for request_firmware().

With the current checks, that doesn't seem to be sufficient since a 
kthread can coincidentally be running in parallel to the suspend 
sequence. The suspend sequence sets "usermodehelper_disabled" for the 
purpose of causing request_firmware() to fail immediately when called 
from the suspend ops. But that doesn't take into account that the 
kthread could also be running at the same time. If this check wasn't 
there, the suspend would be aborted (since the kthread has activated the 
wakeup source) and the request_firmware() would have succeeded.

I think the usermodehelper check in the request_firmware() flow is 
denying a wider swath of scenarios than it needs to. I think the real 
check should be to only disallow request_firmware() in all of the 
callbacks that are called from suspend_enter().

I was joking to my colleague (Stephen Boyd) about just walking up the 
stack to see if suspend_enter() is in the stack, but he seems to have 
ideas that would have a similar effect on the functionality without 
being insane code. I will leave it to him to present his ideas.

But while we are trying to figure out ways to immediately error out 
request_firmware() from suspend callbacks, I think we should remove the 
usermodehelper check in request_firmware() since it's actually 
preventing legitimate use cases.

Thanks,
Saravana

-- 
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

^ permalink raw reply related	[flat|nested] 111+ messages in thread

* Re: Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-11 11:56       ` Kay Sievers
  2012-03-13  9:37         ` Saravana Kannan
@ 2012-03-13  9:43         ` Saravana Kannan
  2012-03-13 20:14           ` Rafael J. Wysocki
  2012-03-13 19:42         ` Rafael J. Wysocki
  2 siblings, 1 reply; 111+ messages in thread
From: Saravana Kannan @ 2012-03-13  9:43 UTC (permalink / raw)
  To: Kay Sievers
  Cc: Greg KH, Christian Lamparter, linux-kernel, Srivatsa S. Bhat,
	alan, Rafael J. Wysocki, Linus Torvalds, Linux PM mailing list,
	Stephen Boyd, Saravana Kannan

On 01/-10/37 11:59, Kay Sievers wrote:
> On Sat, Mar 10, 2012 at 00:36, Greg KH<gregkh@linuxfoundation.org>  wrote:
>> On Fri, Mar 09, 2012 at 11:30:24PM +0100, Christian Lamparter wrote:
>>> This patch fixes a regression which was introduced by:
>>> "PM: Print a warning if firmware is requested when tasks are frozen"
>>>
>>> request_firmware_nowait does not stall in any system resume paths.
>>> Therefore, I think it is perfectly save to use request_firmware_nowait
>>> from at least the ->complete() callback.
>>
>> Is there code somewhere in the kernel that wants to do this?  Has commit
>> a144c6a broken it somehow that this fix would resolve it?
>>
>>>
>>> Signed-off-by: Christian Lamparter<chunkeey@googlemail.com>
>>> ---
>>>   drivers/base/firmware_class.c |    2 +-
>>>   1 files changed, 1 insertions(+), 1 deletions(-)
>>>
>>> diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
>>> index 6c9387d..017e020 100644
>>> --- a/drivers/base/firmware_class.c
>>> +++ b/drivers/base/firmware_class.c
>>> @@ -535,7 +535,7 @@ static int _request_firmware(const struct firmware **firmware_p,
>>>
>>>        read_lock_usermodehelper();
>>>
>>> -     if (WARN_ON(usermodehelper_is_disabled())) {
>>> +     if (WARN_ON(usermodehelper_is_disabled()&&  !(nowait&&  uevent))) {
>>
>> What does uevent have to do with things here?
>
> I don't think that the firmware loader should care about the
> usermodehelper at all, and that stuff fiddling should just be removed
> from the firmware class.
>
> Forking /sbin/hotplug is disabled by default, it is a broken concept,
> and it cannot work reliably on today's systems.
>
> Firmware is not loaded by /sbin/hotplug since many years, but by udev
> or whatever service handles uevents, like ueventd on android.
>

Resending again after fixing my stupid email formatting.

We (mach-msm) just happened to be looking at similar issues with 
request_firmware. The recent changes to request_firmware to check for 
usermodehelper_is_disabled() was preventing us from using 
request_firmware() in what I think is a valid use case. I will get to 
that later.

To first suggest a solution specific the problem this patch is trying to 
address, I think it would be better to do something like below. It's 
just a quick RFC to show what I mean -- haven't even compiled it. If 
there is an agreement on this suggestion, I can send out a cleaner patch.

firmware class: Check for usermode helper availability only
  when enabled.

Signed-off-by: Saravana Kannan <skannan@codeaurora.org>
---
  drivers/base/firmware_class.c |   15 ++++++++-------
  kernel/kmod.c                 |    2 +-
  2 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 06ed6b4..2a45bf7 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -534,12 +534,6 @@ static int _request_firmware(const struct firmware 
**firmware_p,
                 return 0;
         }

-       if (WARN_ON(usermodehelper_is_disabled())) {
-               dev_err(device, "firmware: %s will not be loaded\n", name);
-               retval = -EBUSY;
-               goto out;
-       }
-
         if (uevent)
                 dev_dbg(device, "firmware: requesting %s\n", name);

@@ -555,12 +549,19 @@ static int _request_firmware(const struct firmware 
**firmware_p,
                                   round_jiffies_up(jiffies +
                                                    loading_timeout * HZ));

-               kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD);
+               retval = kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD);
+               if (retval) {
+                       dev_err(device, "firmware: %s will not be 
loaded\n", name);
+                       set_bit(FW_STATUS_ABORT, &fw_priv->status);
+                       goto abort;
+               }
         }

         wait_for_completion(&fw_priv->completion);

         set_bit(FW_STATUS_DONE, &fw_priv->status);
+
+abort:
         del_timer_sync(&fw_priv->timeout);

         mutex_lock(&fw_lock);

diff --git a/kernel/kmod.c b/kernel/kmod.c
index 47613df..e733afe3 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -422,7 +422,7 @@ int call_usermodehelper_exec(struct subprocess_info 
*sub_info,
         if (sub_info->path[0] == '\0')
                 goto out;

-       if (!khelper_wq || usermodehelper_disabled) {
+       if (!khelper_wq || (uevent_helper[0] && usermodehelper_disabled)) {
                 retval = -EBUSY;
                 goto out;
         }

Now, getting to the issue we are facing -- the recent checks for 
usermode helper in request_firmare() is failing request_firmware() in a 
kthread that also activates a wake up source (or if you are familiar 
with Android terms -- grabs a wake lock). By activating a wakeup source, 
the kthread is properly indicating that a suspend shouldn't happen. So, 
I think it's a valid use case for request_firmware().

With the current checks, that doesn't seem to be sufficient since a 
kthread can coincidentally be running in parallel to the suspend 
sequence. The suspend sequence sets "usermodehelper_disabled" for the 
purpose of causing request_firmware() to fail immediately when called 
from the suspend ops. But that doesn't take into account that the 
kthread could also be running at the same time. If this check wasn't 
there, the suspend would be aborted (since the kthread has activated the 
wakeup source) and the request_firmware() would have succeeded.

I think the usermodehelper check in the request_firmware() flow is 
denying a wider swath of scenarios than it needs to. I think the real 
check should be to only disallow request_firmware() in all of the 
callbacks that are called from suspend_enter().

I was joking to my colleague (Stephen Boyd) about just walking up the 
stack to see if suspend_enter() is in the stack, but he seems to have 
ideas that would have a similar effect on the functionality without 
being insane code. I will leave it to him to present his ideas.

But while we are trying to figure out ways to immediately error out 
request_firmware() from suspend callbacks, I think we should remove the 
usermodehelper check in request_firmware() since it's actually 
preventing legitimate use cases.

Thanks,
Saravana

-- 
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

^ permalink raw reply related	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-11 11:56       ` Kay Sievers
  2012-03-13  9:37         ` Saravana Kannan
  2012-03-13  9:43         ` Saravana Kannan
@ 2012-03-13 19:42         ` Rafael J. Wysocki
  2012-03-13 23:25           ` Kay Sievers
  2 siblings, 1 reply; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-13 19:42 UTC (permalink / raw)
  To: Kay Sievers
  Cc: Greg KH, Christian Lamparter, linux-kernel, Srivatsa S. Bhat,
	alan, Linus Torvalds, Linux PM mailing list

On Sunday, March 11, 2012, Kay Sievers wrote:
> On Sat, Mar 10, 2012 at 00:36, Greg KH <gregkh@linuxfoundation.org> wrote:
> > On Fri, Mar 09, 2012 at 11:30:24PM +0100, Christian Lamparter wrote:
> >> This patch fixes a regression which was introduced by:
> >> "PM: Print a warning if firmware is requested when tasks are frozen"
> >>
> >> request_firmware_nowait does not stall in any system resume paths.
> >> Therefore, I think it is perfectly save to use request_firmware_nowait
> >> from at least the ->complete() callback.
> >
> > Is there code somewhere in the kernel that wants to do this?  Has commit
> > a144c6a broken it somehow that this fix would resolve it?
> >
> >>
> >> Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
> >> ---
> >>  drivers/base/firmware_class.c |    2 +-
> >>  1 files changed, 1 insertions(+), 1 deletions(-)
> >>
> >> diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
> >> index 6c9387d..017e020 100644
> >> --- a/drivers/base/firmware_class.c
> >> +++ b/drivers/base/firmware_class.c
> >> @@ -535,7 +535,7 @@ static int _request_firmware(const struct firmware **firmware_p,
> >>
> >>       read_lock_usermodehelper();
> >>
> >> -     if (WARN_ON(usermodehelper_is_disabled())) {
> >> +     if (WARN_ON(usermodehelper_is_disabled() && !(nowait && uevent))) {
> >
> > What does uevent have to do with things here?
> 
> I don't think that the firmware loader should care about the
> usermodehelper at all, and that stuff fiddling should just be removed
> from the firmware class.

It's there to warn people that their drivers do stupid things like
loading frimware during system resume, which is guaranteed not to work.

IOW, it's there very much on purpose.

> Forking /sbin/hotplug is disabled by default, it is a broken concept,
> and it cannot work reliably on today's systems.
> 
> Firmware is not loaded by /sbin/hotplug since many years, but by udev
> or whatever service handles uevents, like ueventd on android.

Which I'm not sure why is relevant here.

Thanks,
Rafael

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-13  9:43         ` Saravana Kannan
@ 2012-03-13 20:14           ` Rafael J. Wysocki
  2012-03-14 19:21             ` Stephen Boyd
  0 siblings, 1 reply; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-13 20:14 UTC (permalink / raw)
  To: Saravana Kannan
  Cc: Kay Sievers, Greg KH, Christian Lamparter, linux-kernel,
	Srivatsa S. Bhat, alan, Linus Torvalds, Linux PM mailing list,
	Stephen Boyd

On Tuesday, March 13, 2012, Saravana Kannan wrote:
> On 01/-10/37 11:59, Kay Sievers wrote:
> > On Sat, Mar 10, 2012 at 00:36, Greg KH<gregkh@linuxfoundation.org>  wrote:
> >> On Fri, Mar 09, 2012 at 11:30:24PM +0100, Christian Lamparter wrote:
> >>> This patch fixes a regression which was introduced by:
> >>> "PM: Print a warning if firmware is requested when tasks are frozen"
> >>>
> >>> request_firmware_nowait does not stall in any system resume paths.
> >>> Therefore, I think it is perfectly save to use request_firmware_nowait
> >>> from at least the ->complete() callback.
> >>
> >> Is there code somewhere in the kernel that wants to do this?  Has commit
> >> a144c6a broken it somehow that this fix would resolve it?
> >>
> >>>
> >>> Signed-off-by: Christian Lamparter<chunkeey@googlemail.com>
> >>> ---
> >>>   drivers/base/firmware_class.c |    2 +-
> >>>   1 files changed, 1 insertions(+), 1 deletions(-)
> >>>
> >>> diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
> >>> index 6c9387d..017e020 100644
> >>> --- a/drivers/base/firmware_class.c
> >>> +++ b/drivers/base/firmware_class.c
> >>> @@ -535,7 +535,7 @@ static int _request_firmware(const struct firmware **firmware_p,
> >>>
> >>>        read_lock_usermodehelper();
> >>>
> >>> -     if (WARN_ON(usermodehelper_is_disabled())) {
> >>> +     if (WARN_ON(usermodehelper_is_disabled()&&  !(nowait&&  uevent))) {
> >>
> >> What does uevent have to do with things here?
> >
> > I don't think that the firmware loader should care about the
> > usermodehelper at all, and that stuff fiddling should just be removed
> > from the firmware class.
> >
> > Forking /sbin/hotplug is disabled by default, it is a broken concept,
> > and it cannot work reliably on today's systems.
> >
> > Firmware is not loaded by /sbin/hotplug since many years, but by udev
> > or whatever service handles uevents, like ueventd on android.
> >
> 
> Resending again after fixing my stupid email formatting.
> 
> We (mach-msm) just happened to be looking at similar issues with 
> request_firmware. The recent changes to request_firmware to check for 
> usermodehelper_is_disabled() was preventing us from using 
> request_firmware() in what I think is a valid use case. I will get to 
> that later.
> 
> To first suggest a solution specific the problem this patch is trying to 
> address, I think it would be better to do something like below. It's 
> just a quick RFC to show what I mean -- haven't even compiled it. If 
> there is an agreement on this suggestion, I can send out a cleaner patch.
> 
> firmware class: Check for usermode helper availability only
>   when enabled.
> 
> Signed-off-by: Saravana Kannan <skannan@codeaurora.org>
> ---
>   drivers/base/firmware_class.c |   15 ++++++++-------
>   kernel/kmod.c                 |    2 +-
>   2 files changed, 9 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
> index 06ed6b4..2a45bf7 100644
> --- a/drivers/base/firmware_class.c
> +++ b/drivers/base/firmware_class.c
> @@ -534,12 +534,6 @@ static int _request_firmware(const struct firmware 
> **firmware_p,
>                  return 0;
>          }
> 
> -       if (WARN_ON(usermodehelper_is_disabled())) {
> -               dev_err(device, "firmware: %s will not be loaded\n", name);
> -               retval = -EBUSY;
> -               goto out;
> -       }
> -
>          if (uevent)
>                  dev_dbg(device, "firmware: requesting %s\n", name);
> 
> @@ -555,12 +549,19 @@ static int _request_firmware(const struct firmware 
> **firmware_p,
>                                    round_jiffies_up(jiffies +
>                                                     loading_timeout * HZ));
> 
> -               kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD);
> +               retval = kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD);
> +               if (retval) {
> +                       dev_err(device, "firmware: %s will not be 
> loaded\n", name);
> +                       set_bit(FW_STATUS_ABORT, &fw_priv->status);
> +                       goto abort;
> +               }
>          }
> 
>          wait_for_completion(&fw_priv->completion);
> 
>          set_bit(FW_STATUS_DONE, &fw_priv->status);
> +
> +abort:
>          del_timer_sync(&fw_priv->timeout);
> 
>          mutex_lock(&fw_lock);
> 
> diff --git a/kernel/kmod.c b/kernel/kmod.c
> index 47613df..e733afe3 100644
> --- a/kernel/kmod.c
> +++ b/kernel/kmod.c
> @@ -422,7 +422,7 @@ int call_usermodehelper_exec(struct subprocess_info 
> *sub_info,
>          if (sub_info->path[0] == '\0')
>                  goto out;
> 
> -       if (!khelper_wq || usermodehelper_disabled) {
> +       if (!khelper_wq || (uevent_helper[0] && usermodehelper_disabled)) {
>                  retval = -EBUSY;
>                  goto out;
>          }
> 
> Now, getting to the issue we are facing -- the recent checks for 
> usermode helper in request_firmare() is failing request_firmware() in a 
> kthread that also activates a wake up source (or if you are familiar 
> with Android terms -- grabs a wake lock). By activating a wakeup source, 
> the kthread is properly indicating that a suspend shouldn't happen. So, 
> I think it's a valid use case for request_firmware().

It isn't really, although it may seems so.  In the mainline there is no
guarantee that system suspend will be aborted when you activate a wakeup
source (the suspend process may choose to ignore wakeup sources).

> With the current checks, that doesn't seem to be sufficient since a 
> kthread can coincidentally be running in parallel to the suspend 
> sequence. The suspend sequence sets "usermodehelper_disabled" for the 
> purpose of causing request_firmware() to fail immediately when called 
> from the suspend ops.

No, it doesn't do that for this purpose.  It does that to prevent a race
between usermode helpers and the freezer from happening.  The failing of
request_firmware() when called during system suspend/resume is a consequence
of that, not the reason why it is done.

> But that doesn't take into account that the kthread could also be running at
> the same time.

Yes, it does.  User space is frozen and your kthread can't possibly use a
usermode helper at that time.

> If this check wasn't there, the suspend would be aborted (since the kthread
> has activated the wakeup source) and the request_firmware() would have
> succeeded.

It would have succeeded _eventually_, after user space had been thawed.

> I think the usermodehelper check in the request_firmware() flow is 
> denying a wider swath of scenarios than it needs to. I think the real 
> check should be to only disallow request_firmware() in all of the 
> callbacks that are called from suspend_enter().
> 
> I was joking to my colleague (Stephen Boyd) about just walking up the 
> stack to see if suspend_enter() is in the stack, but he seems to have 
> ideas that would have a similar effect on the functionality without 
> being insane code. I will leave it to him to present his ideas.
> 
> But while we are trying to figure out ways to immediately error out 
> request_firmware() from suspend callbacks, I think we should remove the 
> usermodehelper check in request_firmware() since it's actually 
> preventing legitimate use cases.

All of those use cases are in fact of the "wait for user space to be thawed
and then load the firmware" type, which I believe may be handled without
changing that code.

Why don't you make your kthread freezable, for one example?

Why don't you use a freezable workqueue instead?

Rafael

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-13 19:42         ` Rafael J. Wysocki
@ 2012-03-13 23:25           ` Kay Sievers
  2012-03-14  0:10             ` Rafael J. Wysocki
  0 siblings, 1 reply; 111+ messages in thread
From: Kay Sievers @ 2012-03-13 23:25 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Greg KH, Christian Lamparter, linux-kernel, Srivatsa S. Bhat,
	alan, Linus Torvalds, Linux PM mailing list

On Tue, Mar 13, 2012 at 20:42, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> On Sunday, March 11, 2012, Kay Sievers wrote:
>> On Sat, Mar 10, 2012 at 00:36, Greg KH <gregkh@linuxfoundation.org> wrote:

>> > What does uevent have to do with things here?
>>
>> I don't think that the firmware loader should care about the
>> usermodehelper at all, and that stuff fiddling should just be removed
>> from the firmware class.
>
> It's there to warn people that their drivers do stupid things like
> loading frimware during system resume, which is guaranteed not to work.
>
> IOW, it's there very much on purpose.

Using the /sbin/hotplug is no case that needs any warning. It' such a
broken model these days, that firmware loading is the least problem
that occurs with it.

>> Forking /sbin/hotplug is disabled by default, it is a broken concept,
>> and it cannot work reliably on today's systems.
>>
>> Firmware is not loaded by /sbin/hotplug since many years, but by udev
>> or whatever service handles uevents, like ueventd on android.
>
> Which I'm not sure why is relevant here.

It is relevant in the sense that the firmware loader should not even
know that a uevent *can* cause a usermodehelper exec() if it runs in
legacy mode. The firmware loader just has no business in fiddling with
the details of driver core legacy stuff. I don't think his warning
makes much sense.

Kay

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-13 23:25           ` Kay Sievers
@ 2012-03-14  0:10             ` Rafael J. Wysocki
  2012-03-14  0:14               ` Kay Sievers
  2012-03-14 15:07               ` Srivatsa S. Bhat
  0 siblings, 2 replies; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-14  0:10 UTC (permalink / raw)
  To: Kay Sievers
  Cc: Greg KH, Christian Lamparter, linux-kernel, Srivatsa S. Bhat,
	alan, Linus Torvalds, Linux PM mailing list

On Wednesday, March 14, 2012, Kay Sievers wrote:
> On Tue, Mar 13, 2012 at 20:42, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> > On Sunday, March 11, 2012, Kay Sievers wrote:
> >> On Sat, Mar 10, 2012 at 00:36, Greg KH <gregkh@linuxfoundation.org> wrote:
> 
> >> > What does uevent have to do with things here?
> >>
> >> I don't think that the firmware loader should care about the
> >> usermodehelper at all, and that stuff fiddling should just be removed
> >> from the firmware class.
> >
> > It's there to warn people that their drivers do stupid things like
> > loading frimware during system resume, which is guaranteed not to work.
> >
> > IOW, it's there very much on purpose.
> 
> Using the /sbin/hotplug is no case that needs any warning. It' such a
> broken model these days, that firmware loading is the least problem
> that occurs with it.
> 
> >> Forking /sbin/hotplug is disabled by default, it is a broken concept,
> >> and it cannot work reliably on today's systems.
> >>
> >> Firmware is not loaded by /sbin/hotplug since many years, but by udev
> >> or whatever service handles uevents, like ueventd on android.
> >
> > Which I'm not sure why is relevant here.
> 
> It is relevant in the sense that the firmware loader should not even
> know that a uevent *can* cause a usermodehelper exec() if it runs in
> legacy mode. The firmware loader just has no business in fiddling with
> the details of driver core legacy stuff. I don't think his warning
> makes much sense.

But that warning actually triggers for drivers that attempt to use
request_firmware() during system resume, even though /sbin/hotplug isn't
used any more.

usermodehelper_is_disabled() means "we are in the middle of system power
transition" rather than anything else (I agree it should be called
suspend_in_progress() or something similar these days).

Thanks,
Rafael

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-14  0:10             ` Rafael J. Wysocki
@ 2012-03-14  0:14               ` Kay Sievers
  2012-03-14  0:54                 ` Linus Torvalds
  2012-03-14 15:07               ` Srivatsa S. Bhat
  1 sibling, 1 reply; 111+ messages in thread
From: Kay Sievers @ 2012-03-14  0:14 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Greg KH, Christian Lamparter, linux-kernel, Srivatsa S. Bhat,
	alan, Linus Torvalds, Linux PM mailing list

On Wed, Mar 14, 2012 at 01:10, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> On Wednesday, March 14, 2012, Kay Sievers wrote:

>> It is relevant in the sense that the firmware loader should not even
>> know that a uevent *can* cause a usermodehelper exec() if it runs in
>> legacy mode. The firmware loader just has no business in fiddling with
>> the details of driver core legacy stuff. I don't think his warning
>> makes much sense.
>
> But that warning actually triggers for drivers that attempt to use
> request_firmware() during system resume, even though /sbin/hotplug isn't
> used any more.
>
> usermodehelper_is_disabled() means "we are in the middle of system power
> transition" rather than anything else (I agree it should be called
> suspend_in_progress() or something similar these days).

Yeah it's certainly useful to disable the exec() during suspend calls,
much more than using the exec() inhibit flag for the firmware loader
to throw a warning about suspend issues.

Such confusing hacks need at least a comment, that makes this very obvious. :)

Kay

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-14  0:14               ` Kay Sievers
@ 2012-03-14  0:54                 ` Linus Torvalds
  2012-03-14  1:43                   ` Kay Sievers
  0 siblings, 1 reply; 111+ messages in thread
From: Linus Torvalds @ 2012-03-14  0:54 UTC (permalink / raw)
  To: Kay Sievers
  Cc: Rafael J. Wysocki, Greg KH, Christian Lamparter, linux-kernel,
	Srivatsa S. Bhat, alan, Linux PM mailing list

On Tue, Mar 13, 2012 at 5:14 PM, Kay Sievers <kay@vrfy.org> wrote:
>
> Yeah it's certainly useful to disable the exec() during suspend calls,
> much more than using the exec() inhibit flag for the firmware loader
> to throw a warning about suspend issues.

Kay, just stop confusing the issue already.

It has *nothing* to do with exec. It has *nothing* to do with
/sbin/hotplug. Stop repeating that stupid mantra. It's totally and
utterly irrelevant.

You can't load firmware while the system is suspended. End of story.
You can't load it using /sbin/hotplug, you can't load it with dbus,
you cannot load it FULL STOP.

The filesystem you'd want to load it from may simply not be ready yet.

This has nothing to do with exec or anything else. It's very simple:
you cannot load firmware while the system isn't yet fully up.
Seriously.

You need to wait to load the firmware until everything is all done,
and things work.

Or you should - preferably - just have preloaded the damn thing.

           Linus

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-14  0:54                 ` Linus Torvalds
@ 2012-03-14  1:43                   ` Kay Sievers
  2012-03-14  1:51                     ` Linus Torvalds
  0 siblings, 1 reply; 111+ messages in thread
From: Kay Sievers @ 2012-03-14  1:43 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Rafael J. Wysocki, Greg KH, Christian Lamparter, linux-kernel,
	Srivatsa S. Bhat, alan, Linux PM mailing list

On Wed, Mar 14, 2012 at 01:54, Linus Torvalds
<torvalds@linux-foundation.org> wrote:
> On Tue, Mar 13, 2012 at 5:14 PM, Kay Sievers <kay@vrfy.org> wrote:
>>
>> Yeah it's certainly useful to disable the exec() during suspend calls,
>> much more than using the exec() inhibit flag for the firmware loader
>> to throw a warning about suspend issues.
>
> Kay, just stop confusing the issue already.
>
> It has *nothing* to do with exec. It has *nothing* to do with
> /sbin/hotplug. Stop repeating that stupid mantra. It's totally and
> utterly irrelevant.
>
> You can't load firmware while the system is suspended. End of story.
> You can't load it using /sbin/hotplug, you can't load it with dbus,
> you cannot load it FULL STOP.
>
> The filesystem you'd want to load it from may simply not be ready yet.
>
> This has nothing to do with exec or anything else. It's very simple:
> you cannot load firmware while the system isn't yet fully up.
> Seriously.
>
> You need to wait to load the firmware until everything is all done,
> and things work.
>
> Or you should - preferably - just have preloaded the damn thing.

usermodehelper_is_disabled() is a flag from kmod which is all about
exec(). That flag should not be used to decide if a firmware request
can be issued by a driver and queued up or not. There is no
usermodehelper involved at all in loading firmware today, hence we
should not use that flag.

Firmware requests are asynchronous like all other driver-core uevents
too, and they can be queued at any time. firmware is not special here.
The kernel has no real business in warning about that, or refusing a
request, just the same way it has no business to tell that other
events are queued but not directly delivered to userspace at that very
moment.

The firmware requests will travel into userspace just fine when stuff is ready.

Kay

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-14  1:43                   ` Kay Sievers
@ 2012-03-14  1:51                     ` Linus Torvalds
  2012-03-14  1:55                       ` Kay Sievers
  0 siblings, 1 reply; 111+ messages in thread
From: Linus Torvalds @ 2012-03-14  1:51 UTC (permalink / raw)
  To: Kay Sievers
  Cc: Rafael J. Wysocki, Greg KH, Christian Lamparter, linux-kernel,
	Srivatsa S. Bhat, alan, Linux PM mailing list

On Tue, Mar 13, 2012 at 6:43 PM, Kay Sievers <kay@vrfy.org> wrote:
>
> usermodehelper_is_disabled() is a flag from kmod which is all about
> exec(). That flag should not be used to decide if a firmware request
> can be issued by a driver and queued up or not.

Sorry, you're wrong. And Rafael *told* you why you are wrong, and you
ignored him and talked about "exec" some more.

So go back and read Rafael's email. The point is, you are focusing too
much on the name (which Rafael talked about and said is misleading).

But it's not the name that matters, it's the concept. Loading firmware
during the suspend process is broken (read Rafael's email about
suggested renaming).

AND IT HAS NOTHING TO DO WITH EXEC. It doesn't matter *how* you load
it. You could load it by reading a file directly from disk, AND IT
WOULD STILL BE WRONG FOR THE EXACT SAME DAMN REASON.

I outlined that reason too. The filesystem may not be up and running yet.

Get it?

So please, read the emails. People actually *agree* that the name may
be a bit misleading, but instead of harping on bogus issues, just read
the emails from people like Rafael about it.

So STOP with this idiocy already. It has nothing to do with exec.
Seriously. Get that through your head already.

           Linus

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-14  1:51                     ` Linus Torvalds
@ 2012-03-14  1:55                       ` Kay Sievers
  2012-03-14  2:00                         ` Kay Sievers
  2012-03-14  2:21                         ` Linus Torvalds
  0 siblings, 2 replies; 111+ messages in thread
From: Kay Sievers @ 2012-03-14  1:55 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Rafael J. Wysocki, Greg KH, Christian Lamparter, linux-kernel,
	Srivatsa S. Bhat, alan, Linux PM mailing list

On Wed, Mar 14, 2012 at 02:51, Linus Torvalds
<torvalds@linux-foundation.org> wrote:
> On Tue, Mar 13, 2012 at 6:43 PM, Kay Sievers <kay@vrfy.org> wrote:
>>
>> usermodehelper_is_disabled() is a flag from kmod which is all about
>> exec(). That flag should not be used to decide if a firmware request
>> can be issued by a driver and queued up or not.
>
> Sorry, you're wrong. And Rafael *told* you why you are wrong, and you
> ignored him and talked about "exec" some more.
>
> So go back and read Rafael's email. The point is, you are focusing too
> much on the name (which Rafael talked about and said is misleading).
>
> But it's not the name that matters, it's the concept. Loading firmware
> during the suspend process is broken (read Rafael's email about
> suggested renaming).
>
> AND IT HAS NOTHING TO DO WITH EXEC. It doesn't matter *how* you load
> it. You could load it by reading a file directly from disk, AND IT
> WOULD STILL BE WRONG FOR THE EXACT SAME DAMN REASON.
>
> I outlined that reason too. The filesystem may not be up and running yet.
>
> Get it?
>
> So please, read the emails. People actually *agree* that the name may
> be a bit misleading, but instead of harping on bogus issues, just read
> the emails from people like Rafael about it.
>
> So STOP with this idiocy already. It has nothing to do with exec.
> Seriously. Get that through your head already.

I do NOT talk about exec, I talk about a REQUEST which can be QUEUED
just fine, but which the kernel refuses to QUEUE, even when it will
not harm anything. That check and warning is wrong.

Kay

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-14  1:55                       ` Kay Sievers
@ 2012-03-14  2:00                         ` Kay Sievers
  2012-03-14  2:21                         ` Linus Torvalds
  1 sibling, 0 replies; 111+ messages in thread
From: Kay Sievers @ 2012-03-14  2:00 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Rafael J. Wysocki, Greg KH, Christian Lamparter, linux-kernel,
	Srivatsa S. Bhat, alan, Linux PM mailing list

On Wed, Mar 14, 2012 at 02:55, Kay Sievers <kay@vrfy.org> wrote:
> On Wed, Mar 14, 2012 at 02:51, Linus Torvalds
> <torvalds@linux-foundation.org> wrote:
>> On Tue, Mar 13, 2012 at 6:43 PM, Kay Sievers <kay@vrfy.org> wrote:
>>>
>>> usermodehelper_is_disabled() is a flag from kmod which is all about
>>> exec(). That flag should not be used to decide if a firmware request
>>> can be issued by a driver and queued up or not.
>>
>> Sorry, you're wrong. And Rafael *told* you why you are wrong, and you
>> ignored him and talked about "exec" some more.
>>
>> So go back and read Rafael's email. The point is, you are focusing too
>> much on the name (which Rafael talked about and said is misleading).
>>
>> But it's not the name that matters, it's the concept. Loading firmware
>> during the suspend process is broken (read Rafael's email about
>> suggested renaming).
>>
>> AND IT HAS NOTHING TO DO WITH EXEC. It doesn't matter *how* you load
>> it. You could load it by reading a file directly from disk, AND IT
>> WOULD STILL BE WRONG FOR THE EXACT SAME DAMN REASON.
>>
>> I outlined that reason too. The filesystem may not be up and running yet.
>>
>> Get it?
>>
>> So please, read the emails. People actually *agree* that the name may
>> be a bit misleading, but instead of harping on bogus issues, just read
>> the emails from people like Rafael about it.
>>
>> So STOP with this idiocy already. It has nothing to do with exec.
>> Seriously. Get that through your head already.
>
> I do NOT talk about exec, I talk about a REQUEST which can be QUEUED
> just fine, but which the kernel refuses to QUEUE, even when it will
> not harm anything. That check and warning is wrong.

In simpler words: request_firmware() does nothing but queue up an
asynchrounous uevent in a socket, that always workls, there is no need
to refuse that in the kernel and throw any warning at that point in
time.

Kay

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-14  1:55                       ` Kay Sievers
  2012-03-14  2:00                         ` Kay Sievers
@ 2012-03-14  2:21                         ` Linus Torvalds
  1 sibling, 0 replies; 111+ messages in thread
From: Linus Torvalds @ 2012-03-14  2:21 UTC (permalink / raw)
  To: Kay Sievers
  Cc: Rafael J. Wysocki, Greg KH, Christian Lamparter, linux-kernel,
	Srivatsa S. Bhat, alan, Linux PM mailing list

On Tue, Mar 13, 2012 at 6:55 PM, Kay Sievers <kay@vrfy.org> wrote:
>
> I do NOT talk about exec, I talk about a REQUEST which can be QUEUED
> just fine, but which the kernel refuses to QUEUE, even when it will
> not harm anything. That check and warning is wrong.

No. request_firmware() is synchronous. People call it, and then use
the loaded firmware immediately after success.

And no, it's not at all clear that you can just say "we'll just wait".
The device that wants the firmware may be something that can be
brought up asynchronously (so "wait until everything is ok" can work),
BUT IT IS NOT AT ALL GUARANTEED.

Seriously, you don't know what you are talking about. We *used* to
just wait, and have a thirty-second timeout etc instead of failing
aggressively. It often worked.

And then quite often it DID NOT WORK, and it caused 30-second delays
at resume time (maybe it was 60s, I forget). Because it turns out that
people were waiting for that device to get through its resume until
the resume was completed. And the system wasn't up. Deadlock.

So a 30-second "let's try delaying this" has been done. It didn't
work. Stop arguing for it, when you clearly don't know what the
problems were. The 30-second delay is when the user just says "resume
didn't work" and has long since pressed the power button.

So fail fast, fail hard. DO NOT REQUEST FIRMWARE WHILE THE SYSTEM IS SUSPENDED.

It really is that simple. Your "let's just queue it up" is crap. Stop
arguing for it, we used to do it, it "worked" much of the time, and
when it didn't work it killed the system.

Which is why it now fails with a big warning. EXACTLY SO THAT DRIVER
WRITERS WOULD KNOW NOT TO DO THAT BROKEN THING.

I'm shouting at you, because you are arguing from ignorance. Stop
doing it. "Works most of the time" just isn't good enough. It needs to
*always* work, and the way to do that is to just do firmware load when
the system is up and running, not when it is suspended.

If a driver is ok with being delayed for a firmware load, it should
just do its resume *without* doing the firmware load at all, and
schedule one serparately for later. But no, we can not just say "let's
delay request_firmware()", because we used to do that and it was shown
to not work.

Comprende?

              Linus

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-14  0:10             ` Rafael J. Wysocki
  2012-03-14  0:14               ` Kay Sievers
@ 2012-03-14 15:07               ` Srivatsa S. Bhat
  2012-03-14 22:54                 ` Rafael J. Wysocki
  1 sibling, 1 reply; 111+ messages in thread
From: Srivatsa S. Bhat @ 2012-03-14 15:07 UTC (permalink / raw)
  To: Kay Sievers
  Cc: Rafael J. Wysocki, Greg KH, Christian Lamparter, linux-kernel,
	alan, Linus Torvalds, Linux PM mailing list, skannan,
	Stephen Boyd

On 03/14/2012 05:40 AM, Rafael J. Wysocki wrote:

> On Wednesday, March 14, 2012, Kay Sievers wrote:
>> On Tue, Mar 13, 2012 at 20:42, Rafael J. Wysocki <rjw@sisk.pl> wrote:
>>> On Sunday, March 11, 2012, Kay Sievers wrote:
>>>> On Sat, Mar 10, 2012 at 00:36, Greg KH <gregkh@linuxfoundation.org> wrote:
>>
>>>>> What does uevent have to do with things here?
>>>>
>>>> I don't think that the firmware loader should care about the
>>>> usermodehelper at all, and that stuff fiddling should just be removed
>>>> from the firmware class.
>>>
>>> It's there to warn people that their drivers do stupid things like
>>> loading frimware during system resume, which is guaranteed not to work.
>>>
>>> IOW, it's there very much on purpose.
>>
>> Using the /sbin/hotplug is no case that needs any warning. It' such a
>> broken model these days, that firmware loading is the least problem
>> that occurs with it.
>>
>>>> Forking /sbin/hotplug is disabled by default, it is a broken concept,
>>>> and it cannot work reliably on today's systems.
>>>>
>>>> Firmware is not loaded by /sbin/hotplug since many years, but by udev
>>>> or whatever service handles uevents, like ueventd on android.
>>>
>>> Which I'm not sure why is relevant here.
>>
>> It is relevant in the sense that the firmware loader should not even
>> know that a uevent *can* cause a usermodehelper exec() if it runs in
>> legacy mode. The firmware loader just has no business in fiddling with
>> the details of driver core legacy stuff. I don't think his warning
>> makes much sense.
> 
> But that warning actually triggers for drivers that attempt to use
> request_firmware() during system resume, even though /sbin/hotplug isn't
> used any more.
> 


I agree with Rafael about why the warning and the bail out is required,
including the part about the races with freezer which he explained in his
other mail. These problems have already been well documented too.
(See Documentation/power/freezing-of-tasks.txt).

> usermodehelper_is_disabled() means "we are in the middle of system power
> transition" rather than anything else (I agree it should be called
> suspend_in_progress() or something similar these days).
> 


How about this patch then?

---

From: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
Subject: PM/firmware loader: Use better name for usermodehelper_is_disabled()

Rafael J. Wysocki <rjw@sisk.pl> wrote:

| usermodehelper_is_disabled() means "we are in the middle of system power
| transition" rather than anything else (I agree it should be called
| suspend_in_progress() or something similar these days).


But simply renaming usermodehelper_is_disabled() to suspend_in_progress()
isn't the best thing to do since that would be misleading because suspend
transitions are begun much before usermodehelpers are disabled.

Apart from that, we don't want people to suddenly start abusing this function
in future in a totally different context to check if suspend is in progress.

So, add an alias specific to firmware loaders alone, that will internally
call usermodehelpers_is_disabled().

Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
---

 drivers/base/firmware_class.c |   12 +++++++++++-
 1 files changed, 11 insertions(+), 1 deletions(-)

diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 6c9387d..9e401e1 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -510,6 +510,8 @@ static void fw_destroy_instance(struct firmware_priv *fw_priv)
 	device_unregister(f_dev);
 }
 
+#define suspend_in_progress()	usermodehelper_is_disabled()
+
 static int _request_firmware(const struct firmware **firmware_p,
 			     const char *name, struct device *device,
 			     bool uevent, bool nowait)
@@ -535,7 +537,15 @@ static int _request_firmware(const struct firmware **firmware_p,
 
 	read_lock_usermodehelper();
 
-	if (WARN_ON(usermodehelper_is_disabled())) {
+	/*
+	 * It is wrong to request firmware when the system is suspended,
+	 * because it simply won't work reliably. Also, it can cause races with
+	 * the freezer, leading to freezing failures. So check if the system is
+	 * in a state which is unsuitable for requesting firmware (because the
+	 * system is suspended or not yet fully resumed) and bail out early if
+	 * needed.
+	 */
+	if (WARN_ON(suspend_in_progress())) {
 		dev_err(device, "firmware: %s will not be loaded\n", name);
 		retval = -EBUSY;
 		goto out;



^ permalink raw reply related	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-13 20:14           ` Rafael J. Wysocki
@ 2012-03-14 19:21             ` Stephen Boyd
  2012-03-14 23:04               ` Rafael J. Wysocki
  0 siblings, 1 reply; 111+ messages in thread
From: Stephen Boyd @ 2012-03-14 19:21 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Saravana Kannan, Kay Sievers, Greg KH, Christian Lamparter,
	linux-kernel, Srivatsa S. Bhat, alan, Linus Torvalds,
	Linux PM mailing list

On 03/13/12 13:14, Rafael J. Wysocki wrote:
> All of those use cases are in fact of the "wait for user space to be thawed
> and then load the firmware" type, which I believe may be handled without
> changing that code.
>
> Why don't you make your kthread freezable, for one example?
>
> Why don't you use a freezable workqueue instead?
>

If we put it on the freezable workqueue or make it a freezable thread
will it work?

In my scenario a wakeup interrupt comes in that wakes us up from
suspend. Within that wakeup handler a work item is scheduled to the
freezable workqueue. That work item then calls request_firmware().

It looks like we call schedule() after thawing the workqueues and tasks
so the work item could run before usermodehelpers are enabled and then
request_firmware() would fail. Do we need something like this (ignore
the fact that we call usermodhelper_enable() twice)?

diff --git a/kernel/power/process.c b/kernel/power/process.c
index 7e42645..61bfa95 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -187,6 +187,7 @@ void thaw_processes(void)
        } while_each_thread(g, p);
        read_unlock(&tasklist_lock);
 
+       usermodehelper_enable();
        schedule();
        printk("done.\n");
 }


Is there a reason we disable usermodehelpers if
CONFIG_SUSPEND_FREEZER=n? Should we do this instead so that
usermodehelpers are only disabled if we freeze userspace? Also what is
that schedule() call in thaw_kernel_threads() for? It looks like we'll
call schedule between kernel thread thawing and userspace thawing. I
pushed out the schedule() call to the callers so that we don't call
schedule() until userspace is thawed.

diff --git a/kernel/power/process.c b/kernel/power/process.c
index 7e42645..8fae228 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -125,6 +125,7 @@ int freeze_processes(void)
 	if (!pm_freezing)
 		atomic_inc(&system_freezing_cnt);
 
+	usermodehelper_disable();
 	printk("Freezing user space processes ... ");
 	pm_freezing = true;
 	error = try_to_freeze_tasks(true);
@@ -187,6 +188,7 @@ void thaw_processes(void)
 	} while_each_thread(g, p);
 	read_unlock(&tasklist_lock);
 
+	usermodehelper_enable();
 	schedule();
 	printk("done.\n");
 }
@@ -207,6 +209,5 @@ void thaw_kernel_threads(void)
 	} while_each_thread(g, p);
 	read_unlock(&tasklist_lock);
 
-	schedule();
 	printk("done.\n");
 }
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index 4fd51be..1ab3e59 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -101,17 +101,12 @@ static int suspend_prepare(void)
 	if (error)
 		goto Finish;
 
-	error = usermodehelper_disable();
-	if (error)
-		goto Finish;
-
 	error = suspend_freeze_processes();
 	if (!error)
 		return 0;
 
 	suspend_stats.failed_freeze++;
 	dpm_save_failed_step(SUSPEND_FREEZE);
-	usermodehelper_enable();
  Finish:
 	pm_notifier_call_chain(PM_POST_SUSPEND);
 	pm_restore_console();
@@ -259,7 +254,6 @@ int suspend_devices_and_enter(suspend_state_t state)
 static void suspend_finish(void)
 {
 	suspend_thaw_processes();
-	usermodehelper_enable();
 	pm_notifier_call_chain(PM_POST_SUSPEND);
 	pm_restore_console();
 }
diff --git a/kernel/power/user.c b/kernel/power/user.c
index 3e10007..1a8fd6f 100644
--- a/kernel/power/user.c
+++ b/kernel/power/user.c
@@ -222,14 +222,8 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
 		sys_sync();
 		printk("done.\n");
 
-		error = usermodehelper_disable();
-		if (error)
-			break;
-
 		error = freeze_processes();
-		if (error)
-			usermodehelper_enable();
-		else
+		if (!error)
 			data->frozen = 1;
 		break;
 
@@ -238,7 +232,6 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
 			break;
 		pm_restore_gfp_mask();
 		thaw_processes();
-		usermodehelper_enable();
 		data->frozen = 0;
 		break;
 
@@ -251,6 +244,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
 		error = hibernation_snapshot(data->platform_support);
 		if (error) {
 			thaw_kernel_threads();
+			schedule();
 		} else {
 			error = put_user(in_suspend, (int __user *)arg);
 			if (!error && !freezer_test_done)
@@ -258,6 +252,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
 			if (freezer_test_done) {
 				freezer_test_done = false;
 				thaw_kernel_threads();
+				schedule();
 			}
 		}
 		break;
@@ -285,6 +280,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
 		 * might fail or even deadlock).
 		 */
 		thaw_kernel_threads();
+		schedule();
 		break;
 
 	case SNAPSHOT_PREF_IMAGE_SIZE:

-- 
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.


^ permalink raw reply related	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-14 15:07               ` Srivatsa S. Bhat
@ 2012-03-14 22:54                 ` Rafael J. Wysocki
  2012-03-16  7:14                   ` Srivatsa S. Bhat
  0 siblings, 1 reply; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-14 22:54 UTC (permalink / raw)
  To: Srivatsa S. Bhat
  Cc: Kay Sievers, Greg KH, Christian Lamparter, linux-kernel, alan,
	Linus Torvalds, Linux PM mailing list, skannan, Stephen Boyd

On Wednesday, March 14, 2012, Srivatsa S. Bhat wrote:
> On 03/14/2012 05:40 AM, Rafael J. Wysocki wrote:
> 
> > On Wednesday, March 14, 2012, Kay Sievers wrote:
> >> On Tue, Mar 13, 2012 at 20:42, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> >>> On Sunday, March 11, 2012, Kay Sievers wrote:
> >>>> On Sat, Mar 10, 2012 at 00:36, Greg KH <gregkh@linuxfoundation.org> wrote:
> >>
> >>>>> What does uevent have to do with things here?
> >>>>
> >>>> I don't think that the firmware loader should care about the
> >>>> usermodehelper at all, and that stuff fiddling should just be removed
> >>>> from the firmware class.
> >>>
> >>> It's there to warn people that their drivers do stupid things like
> >>> loading frimware during system resume, which is guaranteed not to work.
> >>>
> >>> IOW, it's there very much on purpose.
> >>
> >> Using the /sbin/hotplug is no case that needs any warning. It' such a
> >> broken model these days, that firmware loading is the least problem
> >> that occurs with it.
> >>
> >>>> Forking /sbin/hotplug is disabled by default, it is a broken concept,
> >>>> and it cannot work reliably on today's systems.
> >>>>
> >>>> Firmware is not loaded by /sbin/hotplug since many years, but by udev
> >>>> or whatever service handles uevents, like ueventd on android.
> >>>
> >>> Which I'm not sure why is relevant here.
> >>
> >> It is relevant in the sense that the firmware loader should not even
> >> know that a uevent *can* cause a usermodehelper exec() if it runs in
> >> legacy mode. The firmware loader just has no business in fiddling with
> >> the details of driver core legacy stuff. I don't think his warning
> >> makes much sense.
> > 
> > But that warning actually triggers for drivers that attempt to use
> > request_firmware() during system resume, even though /sbin/hotplug isn't
> > used any more.
> > 
> 
> 
> I agree with Rafael about why the warning and the bail out is required,
> including the part about the races with freezer which he explained in his
> other mail. These problems have already been well documented too.
> (See Documentation/power/freezing-of-tasks.txt).
> 
> > usermodehelper_is_disabled() means "we are in the middle of system power
> > transition" rather than anything else (I agree it should be called
> > suspend_in_progress() or something similar these days).
> > 
> 
> 
> How about this patch then?
> 
> ---
> 
> From: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
> Subject: PM/firmware loader: Use better name for usermodehelper_is_disabled()
> 
> Rafael J. Wysocki <rjw@sisk.pl> wrote:
> 
> | usermodehelper_is_disabled() means "we are in the middle of system power
> | transition" rather than anything else (I agree it should be called
> | suspend_in_progress() or something similar these days).
> 
> 
> But simply renaming usermodehelper_is_disabled() to suspend_in_progress()
> isn't the best thing to do since that would be misleading because suspend
> transitions are begun much before usermodehelpers are disabled.
> 
> Apart from that, we don't want people to suddenly start abusing this function
> in future in a totally different context to check if suspend is in progress.
> 
> So, add an alias specific to firmware loaders alone, that will internally
> call usermodehelpers_is_disabled().
> 
> Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
> ---
> 
>  drivers/base/firmware_class.c |   12 +++++++++++-
>  1 files changed, 11 insertions(+), 1 deletions(-)
> 
> diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
> index 6c9387d..9e401e1 100644
> --- a/drivers/base/firmware_class.c
> +++ b/drivers/base/firmware_class.c
> @@ -510,6 +510,8 @@ static void fw_destroy_instance(struct firmware_priv *fw_priv)
>  	device_unregister(f_dev);
>  }
>  
> +#define suspend_in_progress()	usermodehelper_is_disabled()

This looks like an overstretch to me.  I think a comment would be sufficient.

> +
>  static int _request_firmware(const struct firmware **firmware_p,
>  			     const char *name, struct device *device,
>  			     bool uevent, bool nowait)
> @@ -535,7 +537,15 @@ static int _request_firmware(const struct firmware **firmware_p,
>  
>  	read_lock_usermodehelper();
>  
> -	if (WARN_ON(usermodehelper_is_disabled())) {
> +	/*
> +	 * It is wrong to request firmware when the system is suspended,
> +	 * because it simply won't work reliably.

In fact, it won't work at all.

> +	 Also, it can cause races with
> +	 * the freezer, leading to freezing failures.

It actually is worse than that too.  It may cause a user space process
to run when we think we have frozen user space and _that_ may lead to
all kinds of interesting breakage.

> 	 * So check if the system is
> +	 * in a state which is unsuitable for requesting firmware (because the
> +	 * system is suspended or not yet fully resumed) and bail out early if
> +	 * needed.

And here I'd explain why usermodehelper_is_disabled() is used for that.

> +	 */
> +	if (WARN_ON(suspend_in_progress())) {
>  		dev_err(device, "firmware: %s will not be loaded\n", name);
>  		retval = -EBUSY;
>  		goto out;

Thanks,
Rafael

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-14 19:21             ` Stephen Boyd
@ 2012-03-14 23:04               ` Rafael J. Wysocki
  2012-03-14 23:13                 ` Rafael J. Wysocki
  2012-03-14 23:19                 ` [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available Rafael J. Wysocki
  0 siblings, 2 replies; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-14 23:04 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Saravana Kannan, Kay Sievers, Greg KH, Christian Lamparter,
	linux-kernel, Srivatsa S. Bhat, alan, Linus Torvalds,
	Linux PM mailing list

On Wednesday, March 14, 2012, Stephen Boyd wrote:
> On 03/13/12 13:14, Rafael J. Wysocki wrote:
> > All of those use cases are in fact of the "wait for user space to be thawed
> > and then load the firmware" type, which I believe may be handled without
> > changing that code.
> >
> > Why don't you make your kthread freezable, for one example?
> >
> > Why don't you use a freezable workqueue instead?
> >
> 
> If we put it on the freezable workqueue or make it a freezable thread
> will it work?

That depends on what exactly you want to achieve, which isn't entirely clear
to me at this point.

> In my scenario a wakeup interrupt comes in that wakes us up from
> suspend. Within that wakeup handler a work item is scheduled to the
> freezable workqueue. That work item then calls request_firmware().

That should work.

> It looks like we call schedule() after thawing the workqueues and tasks
> so the work item could run before usermodehelpers are enabled and then
> request_firmware() would fail. Do we need something like this (ignore
> the fact that we call usermodhelper_enable() twice)?
> 
> diff --git a/kernel/power/process.c b/kernel/power/process.c
> index 7e42645..61bfa95 100644
> --- a/kernel/power/process.c
> +++ b/kernel/power/process.c
> @@ -187,6 +187,7 @@ void thaw_processes(void)
>         } while_each_thread(g, p);
>         read_unlock(&tasklist_lock);
>  
> +       usermodehelper_enable();

That would be a reasonable change.

>         schedule();
>         printk("done.\n");
>  }
> 
> 
> Is there a reason we disable usermodehelpers if
> CONFIG_SUSPEND_FREEZER=n?

Not really, but CONFIG_SUSPEND_FREEZER=n can only work reliably in a
very limited set of cases, so I don't think it's even worth making the
general code depend on it.

I'd actually prefer to remove CONFIG_SUSPEND_FREEZER altogether,
because it's not very useful nowadays (probably isn't useful at all).

> Should we do this instead so that
> usermodehelpers are only disabled if we freeze userspace? Also what is
> that schedule() call in thaw_kernel_threads() for? It looks like we'll
> call schedule between kernel thread thawing and userspace thawing.

Which is OK, I think.

> I pushed out the schedule() call to the callers so that we don't call
> schedule() until userspace is thawed.

Why did you do that?

Rafael

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-14 23:04               ` Rafael J. Wysocki
@ 2012-03-14 23:13                 ` Rafael J. Wysocki
  2012-03-14 23:17                   ` Stephen Boyd
  2012-03-14 23:19                 ` [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available Rafael J. Wysocki
  1 sibling, 1 reply; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-14 23:13 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Saravana Kannan, Kay Sievers, Greg KH, Christian Lamparter,
	linux-kernel, Srivatsa S. Bhat, alan, Linus Torvalds,
	Linux PM mailing list

On Thursday, March 15, 2012, Rafael J. Wysocki wrote:
> On Wednesday, March 14, 2012, Stephen Boyd wrote:
> > On 03/13/12 13:14, Rafael J. Wysocki wrote:
> > > All of those use cases are in fact of the "wait for user space to be thawed
> > > and then load the firmware" type, which I believe may be handled without
> > > changing that code.
> > >
> > > Why don't you make your kthread freezable, for one example?
> > >
> > > Why don't you use a freezable workqueue instead?
> > >
> > 
> > If we put it on the freezable workqueue or make it a freezable thread
> > will it work?
> 
> That depends on what exactly you want to achieve, which isn't entirely clear
> to me at this point.
> 
> > In my scenario a wakeup interrupt comes in that wakes us up from
> > suspend. Within that wakeup handler a work item is scheduled to the
> > freezable workqueue. That work item then calls request_firmware().
> 
> That should work.
> 
> > It looks like we call schedule() after thawing the workqueues and tasks
> > so the work item could run before usermodehelpers are enabled and then
> > request_firmware() would fail. Do we need something like this (ignore
> > the fact that we call usermodhelper_enable() twice)?
> > 
> > diff --git a/kernel/power/process.c b/kernel/power/process.c
> > index 7e42645..61bfa95 100644
> > --- a/kernel/power/process.c
> > +++ b/kernel/power/process.c
> > @@ -187,6 +187,7 @@ void thaw_processes(void)
> >         } while_each_thread(g, p);
> >         read_unlock(&tasklist_lock);
> >  
> > +       usermodehelper_enable();
> 
> That would be a reasonable change.
> 
> >         schedule();
> >         printk("done.\n");
> >  }
> > 
> > 
> > Is there a reason we disable usermodehelpers if
> > CONFIG_SUSPEND_FREEZER=n?
> 
> Not really, but CONFIG_SUSPEND_FREEZER=n can only work reliably in a
> very limited set of cases, so I don't think it's even worth making the
> general code depend on it.
> 
> I'd actually prefer to remove CONFIG_SUSPEND_FREEZER altogether,
> because it's not very useful nowadays (probably isn't useful at all).
> 
> > Should we do this instead so that
> > usermodehelpers are only disabled if we freeze userspace? Also what is
> > that schedule() call in thaw_kernel_threads() for? It looks like we'll
> > call schedule between kernel thread thawing and userspace thawing.
> 
> Which is OK, I think.

Moreover, thaw_kernel_threads() is _only_ called by (a) freeze_kernel_threads()
on error and (b) user-space hibernate interface in kernel/power/user.c
(and please read the comment in there describing what it's there for, which
also explains why the schedule() call in there is necessary).

In all other cases, thaw_processes() is used to thaw kernel threads and user
space at the same time, so I believe we don't need the changes you're proposing
in that area.

Thanks,
Rafael

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-14 23:13                 ` Rafael J. Wysocki
@ 2012-03-14 23:17                   ` Stephen Boyd
  2012-03-14 23:34                     ` Rafael J. Wysocki
  0 siblings, 1 reply; 111+ messages in thread
From: Stephen Boyd @ 2012-03-14 23:17 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Saravana Kannan, Kay Sievers, Greg KH, Christian Lamparter,
	linux-kernel, Srivatsa S. Bhat, alan, Linus Torvalds,
	Linux PM mailing list

On 03/14/12 16:13, Rafael J. Wysocki wrote:
> On Thursday, March 15, 2012, Rafael J. Wysocki wrote:
>> On Wednesday, March 14, 2012, Stephen Boyd wrote:
>>> On 03/13/12 13:14, Rafael J. Wysocki wrote:
>>>> All of those use cases are in fact of the "wait for user space to be thawed
>>>> and then load the firmware" type, which I believe may be handled without
>>>> changing that code.
>>>>
>>>> Why don't you make your kthread freezable, for one example?
>>>>
>>>> Why don't you use a freezable workqueue instead?
>>>>
>>> If we put it on the freezable workqueue or make it a freezable thread
>>> will it work?
>> That depends on what exactly you want to achieve, which isn't entirely clear
>> to me at this point.
>>
>>> In my scenario a wakeup interrupt comes in that wakes us up from
>>> suspend. Within that wakeup handler a work item is scheduled to the
>>> freezable workqueue. That work item then calls request_firmware().
>> That should work.
>>
>>> It looks like we call schedule() after thawing the workqueues and tasks
>>> so the work item could run before usermodehelpers are enabled and then
>>> request_firmware() would fail. Do we need something like this (ignore
>>> the fact that we call usermodhelper_enable() twice)?
>>>
>>> diff --git a/kernel/power/process.c b/kernel/power/process.c
>>> index 7e42645..61bfa95 100644
>>> --- a/kernel/power/process.c
>>> +++ b/kernel/power/process.c
>>> @@ -187,6 +187,7 @@ void thaw_processes(void)
>>>         } while_each_thread(g, p);
>>>         read_unlock(&tasklist_lock);
>>>  
>>> +       usermodehelper_enable();
>> That would be a reasonable change.
>>
>>>         schedule();
>>>         printk("done.\n");
>>>  }
>>>
>>>
>>> Is there a reason we disable usermodehelpers if
>>> CONFIG_SUSPEND_FREEZER=n?
>> Not really, but CONFIG_SUSPEND_FREEZER=n can only work reliably in a
>> very limited set of cases, so I don't think it's even worth making the
>> general code depend on it.
>>
>> I'd actually prefer to remove CONFIG_SUSPEND_FREEZER altogether,
>> because it's not very useful nowadays (probably isn't useful at all).
>>
>>> Should we do this instead so that
>>> usermodehelpers are only disabled if we freeze userspace? Also what is
>>> that schedule() call in thaw_kernel_threads() for? It looks like we'll
>>> call schedule between kernel thread thawing and userspace thawing.
>> Which is OK, I think.
> Moreover, thaw_kernel_threads() is _only_ called by (a) freeze_kernel_threads()
> on error and (b) user-space hibernate interface in kernel/power/user.c
> (and please read the comment in there describing what it's there for, which
> also explains why the schedule() call in there is necessary).

Exactly. So in case (a) when the error occurs we'll have this call flow:

usermodehelpers_disable()
suspend_freeze_processes()
    freeze_processes()
    freeze_kernel_threads()
        try_to_freeze_tasks() <-- returns error
        thaw_kernel_threads()
            schedule()
    thaw_processes()
usermodehelpers_enable()

Shouldn't we schedule only after we thaw all processes (not just tasks)?
Otherwise we may run a kernel thread before userspace is thawed?

-- 
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.


^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-14 23:04               ` Rafael J. Wysocki
  2012-03-14 23:13                 ` Rafael J. Wysocki
@ 2012-03-14 23:19                 ` Rafael J. Wysocki
  1 sibling, 0 replies; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-14 23:19 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Saravana Kannan, Kay Sievers, Greg KH, Christian Lamparter,
	linux-kernel, Srivatsa S. Bhat, alan, Linus Torvalds,
	Linux PM mailing list

On Thursday, March 15, 2012, Rafael J. Wysocki wrote:
> On Wednesday, March 14, 2012, Stephen Boyd wrote:
> > On 03/13/12 13:14, Rafael J. Wysocki wrote:
> > > All of those use cases are in fact of the "wait for user space to be thawed
> > > and then load the firmware" type, which I believe may be handled without
> > > changing that code.
> > >
> > > Why don't you make your kthread freezable, for one example?
> > >
> > > Why don't you use a freezable workqueue instead?
> > >
> > 
> > If we put it on the freezable workqueue or make it a freezable thread
> > will it work?
> 
> That depends on what exactly you want to achieve, which isn't entirely clear
> to me at this point.
> 
> > In my scenario a wakeup interrupt comes in that wakes us up from
> > suspend. Within that wakeup handler a work item is scheduled to the
> > freezable workqueue. That work item then calls request_firmware().
> 
> That should work.

I would consider using suspend/resume notifiers, however.

Thanks,
Rafael

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-14 23:17                   ` Stephen Boyd
@ 2012-03-14 23:34                     ` Rafael J. Wysocki
  2012-03-14 23:38                       ` Stephen Boyd
  0 siblings, 1 reply; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-14 23:34 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Saravana Kannan, Kay Sievers, Greg KH, Christian Lamparter,
	linux-kernel, Srivatsa S. Bhat, alan, Linus Torvalds,
	Linux PM mailing list

On Thursday, March 15, 2012, Stephen Boyd wrote:
> On 03/14/12 16:13, Rafael J. Wysocki wrote:
> > On Thursday, March 15, 2012, Rafael J. Wysocki wrote:
> >> On Wednesday, March 14, 2012, Stephen Boyd wrote:
> >>> On 03/13/12 13:14, Rafael J. Wysocki wrote:
> >>>> All of those use cases are in fact of the "wait for user space to be thawed
> >>>> and then load the firmware" type, which I believe may be handled without
> >>>> changing that code.
> >>>>
> >>>> Why don't you make your kthread freezable, for one example?
> >>>>
> >>>> Why don't you use a freezable workqueue instead?
> >>>>
> >>> If we put it on the freezable workqueue or make it a freezable thread
> >>> will it work?
> >> That depends on what exactly you want to achieve, which isn't entirely clear
> >> to me at this point.
> >>
> >>> In my scenario a wakeup interrupt comes in that wakes us up from
> >>> suspend. Within that wakeup handler a work item is scheduled to the
> >>> freezable workqueue. That work item then calls request_firmware().
> >> That should work.
> >>
> >>> It looks like we call schedule() after thawing the workqueues and tasks
> >>> so the work item could run before usermodehelpers are enabled and then
> >>> request_firmware() would fail. Do we need something like this (ignore
> >>> the fact that we call usermodhelper_enable() twice)?
> >>>
> >>> diff --git a/kernel/power/process.c b/kernel/power/process.c
> >>> index 7e42645..61bfa95 100644
> >>> --- a/kernel/power/process.c
> >>> +++ b/kernel/power/process.c
> >>> @@ -187,6 +187,7 @@ void thaw_processes(void)
> >>>         } while_each_thread(g, p);
> >>>         read_unlock(&tasklist_lock);
> >>>  
> >>> +       usermodehelper_enable();
> >> That would be a reasonable change.
> >>
> >>>         schedule();
> >>>         printk("done.\n");
> >>>  }
> >>>
> >>>
> >>> Is there a reason we disable usermodehelpers if
> >>> CONFIG_SUSPEND_FREEZER=n?
> >> Not really, but CONFIG_SUSPEND_FREEZER=n can only work reliably in a
> >> very limited set of cases, so I don't think it's even worth making the
> >> general code depend on it.
> >>
> >> I'd actually prefer to remove CONFIG_SUSPEND_FREEZER altogether,
> >> because it's not very useful nowadays (probably isn't useful at all).
> >>
> >>> Should we do this instead so that
> >>> usermodehelpers are only disabled if we freeze userspace? Also what is
> >>> that schedule() call in thaw_kernel_threads() for? It looks like we'll
> >>> call schedule between kernel thread thawing and userspace thawing.
> >> Which is OK, I think.
> > Moreover, thaw_kernel_threads() is _only_ called by (a) freeze_kernel_threads()
> > on error and (b) user-space hibernate interface in kernel/power/user.c
> > (and please read the comment in there describing what it's there for, which
> > also explains why the schedule() call in there is necessary).
> 
> Exactly. So in case (a) when the error occurs we'll have this call flow:
> 
> usermodehelpers_disable()
> suspend_freeze_processes()
>     freeze_processes()
>     freeze_kernel_threads()
>         try_to_freeze_tasks() <-- returns error
>         thaw_kernel_threads()
>             schedule()
>     thaw_processes()
> usermodehelpers_enable()
> 
> Shouldn't we schedule only after we thaw all processes (not just tasks)?
> Otherwise we may run a kernel thread before userspace is thawed?

Yes, we may, but that isn't wrong, is it?

Only a few kernel threads are freezable, so definitely kernel threads
can run while user space is frozen.

Thanks,
Rafael

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-14 23:34                     ` Rafael J. Wysocki
@ 2012-03-14 23:38                       ` Stephen Boyd
  2012-03-15  0:11                         ` Rafael J. Wysocki
  0 siblings, 1 reply; 111+ messages in thread
From: Stephen Boyd @ 2012-03-14 23:38 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Saravana Kannan, Kay Sievers, Greg KH, Christian Lamparter,
	linux-kernel, Srivatsa S. Bhat, alan, Linus Torvalds,
	Linux PM mailing list

On 03/14/12 16:34, Rafael J. Wysocki wrote:
> On Thursday, March 15, 2012, Stephen Boyd wrote:
>> On 03/14/12 16:13, Rafael J. Wysocki wrote:
>>> On Thursday, March 15, 2012, Rafael J. Wysocki wrote:
>>>
>>>> Which is OK, I think.
>>> Moreover, thaw_kernel_threads() is _only_ called by (a) freeze_kernel_threads()
>>> on error and (b) user-space hibernate interface in kernel/power/user.c
>>> (and please read the comment in there describing what it's there for, which
>>> also explains why the schedule() call in there is necessary).
>> Exactly. So in case (a) when the error occurs we'll have this call flow:
>>
>> usermodehelpers_disable()
>> suspend_freeze_processes()
>>     freeze_processes()
>>     freeze_kernel_threads()
>>         try_to_freeze_tasks() <-- returns error
>>         thaw_kernel_threads()
>>             schedule()
>>     thaw_processes()
>> usermodehelpers_enable()
>>
>> Shouldn't we schedule only after we thaw all processes (not just tasks)?
>> Otherwise we may run a kernel thread before userspace is thawed?
> Yes, we may, but that isn't wrong, is it?
>
> Only a few kernel threads are freezable, so definitely kernel threads
> can run while user space is frozen.
>

Yes but if someone calls request_firmware() from a kthread then they
will hit the same problem where the thread runs and requests the
firmware and usermodehelpers are still disabled. Currently my code is
written with kthreads and that thread makes the request firmware call,
so this doesn't seem far fetched (although in my case I can probably fix
it). It looks like before 379e0be (PM / Freezer: Thaw only kernel
threads if freezing of kernel threads fails, 2012-02-03) schedule wasn't
called until userspace was thawed. It looks like that patch was about
hibernation and not suspend?

-- 
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.


^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-14 23:38                       ` Stephen Boyd
@ 2012-03-15  0:11                         ` Rafael J. Wysocki
  2012-03-15 19:50                           ` [PATCH] firmware_class: Move request_firmware_nowait() to workqueues Stephen Boyd
  2012-03-17  2:47                           ` [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available Stephen Boyd
  0 siblings, 2 replies; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-15  0:11 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Saravana Kannan, Kay Sievers, Greg KH, Christian Lamparter,
	linux-kernel, Srivatsa S. Bhat, alan, Linus Torvalds,
	Linux PM mailing list

On Thursday, March 15, 2012, Stephen Boyd wrote:
> On 03/14/12 16:34, Rafael J. Wysocki wrote:
> > On Thursday, March 15, 2012, Stephen Boyd wrote:
> >> On 03/14/12 16:13, Rafael J. Wysocki wrote:
> >>> On Thursday, March 15, 2012, Rafael J. Wysocki wrote:
> >>>
> >>>> Which is OK, I think.
> >>> Moreover, thaw_kernel_threads() is _only_ called by (a) freeze_kernel_threads()
> >>> on error and (b) user-space hibernate interface in kernel/power/user.c
> >>> (and please read the comment in there describing what it's there for, which
> >>> also explains why the schedule() call in there is necessary).
> >> Exactly. So in case (a) when the error occurs we'll have this call flow:
> >>
> >> usermodehelpers_disable()
> >> suspend_freeze_processes()
> >>     freeze_processes()
> >>     freeze_kernel_threads()
> >>         try_to_freeze_tasks() <-- returns error
> >>         thaw_kernel_threads()
> >>             schedule()
> >>     thaw_processes()
> >> usermodehelpers_enable()
> >>
> >> Shouldn't we schedule only after we thaw all processes (not just tasks)?
> >> Otherwise we may run a kernel thread before userspace is thawed?
> > Yes, we may, but that isn't wrong, is it?
> >
> > Only a few kernel threads are freezable, so definitely kernel threads
> > can run while user space is frozen.
> >
> 
> Yes but if someone calls request_firmware() from a kthread then they
> will hit the same problem where the thread runs and requests the
> firmware and usermodehelpers are still disabled. Currently my code is
> written with kthreads and that thread makes the request firmware call,
> so this doesn't seem far fetched (although in my case I can probably fix
> it).

So again, please consider using suspend/resume notifiers to synchronize
your kthread with system power transitions.

> It looks like before 379e0be (PM / Freezer: Thaw only kernel
> threads if freezing of kernel threads fails, 2012-02-03) schedule wasn't
> called until userspace was thawed. It looks like that patch was about
> hibernation and not suspend?

It was about hibernation and it fixed a real bug.

Thanks,
Rafael



^ permalink raw reply	[flat|nested] 111+ messages in thread

* [PATCH] firmware_class: Move request_firmware_nowait() to workqueues
  2012-03-15  0:11                         ` Rafael J. Wysocki
@ 2012-03-15 19:50                           ` Stephen Boyd
  2012-03-15 20:07                             ` Christian Lamparter
  2012-03-17  2:47                           ` [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available Stephen Boyd
  1 sibling, 1 reply; 111+ messages in thread
From: Stephen Boyd @ 2012-03-15 19:50 UTC (permalink / raw)
  To: linux-kernel
  Cc: Linux PM mailing list, Christian Lamparter, Srivatsa S. Bhat,
	alan, Linus Torvalds, Saravana Kannan, Greg Kroah-Hartman,
	Kay Sievers, Rafael J. Wysocki

Oddly enough a work_struct was already part of the firmware_work
structure but nobody was using it. Instead of creating a new
kthread for each request_firmware_nowait() just schedule the work
on the system workqueue. This should avoid some overhead in
forking new threads when they're not strictly necessary if
workqueues are available.

Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Kay Sievers <kay.sievers@vrfy.org>
Cc: Rafael J. Wysocki <rjw@sisk.pl>
---

I saw this while looking at this problem we're having.

 drivers/base/firmware_class.c |   29 +++++++----------------------
 1 file changed, 7 insertions(+), 22 deletions(-)

diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 6c9387d..1010c06 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -16,7 +16,7 @@
 #include <linux/interrupt.h>
 #include <linux/bitops.h>
 #include <linux/mutex.h>
-#include <linux/kthread.h>
+#include <linux/workqueue.h>
 #include <linux/highmem.h>
 #include <linux/firmware.h>
 #include <linux/slab.h>
@@ -629,25 +629,18 @@ struct firmware_work {
 	bool uevent;
 };
 
-static int request_firmware_work_func(void *arg)
+static void request_firmware_work_func(struct work_struct *work)
 {
-	struct firmware_work *fw_work = arg;
+	struct firmware_work *fw_work;
 	const struct firmware *fw;
-	int ret;
-
-	if (!arg) {
-		WARN_ON(1);
-		return 0;
-	}
+	fw_work = container_of(work, struct firmware_work, work);
 
-	ret = _request_firmware(&fw, fw_work->name, fw_work->device,
+	_request_firmware(&fw, fw_work->name, fw_work->device,
 				fw_work->uevent, true);
 	fw_work->cont(fw, fw_work->context);
 
 	module_put(fw_work->module);
 	kfree(fw_work);
-
-	return ret;
 }
 
 /**
@@ -673,7 +666,6 @@ request_firmware_nowait(
 	const char *name, struct device *device, gfp_t gfp, void *context,
 	void (*cont)(const struct firmware *fw, void *context))
 {
-	struct task_struct *task;
 	struct firmware_work *fw_work;
 
 	fw_work = kzalloc(sizeof (struct firmware_work), gfp);
@@ -692,15 +684,8 @@ request_firmware_nowait(
 		return -EFAULT;
 	}
 
-	task = kthread_run(request_firmware_work_func, fw_work,
-			    "firmware/%s", name);
-	if (IS_ERR(task)) {
-		fw_work->cont(NULL, fw_work->context);
-		module_put(fw_work->module);
-		kfree(fw_work);
-		return PTR_ERR(task);
-	}
-
+	INIT_WORK(&fw_work->work, request_firmware_work_func);
+	schedule_work(&fw_work->work);
 	return 0;
 }
 
-- 
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.


^ permalink raw reply related	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware_class: Move request_firmware_nowait() to workqueues
  2012-03-15 19:50                           ` [PATCH] firmware_class: Move request_firmware_nowait() to workqueues Stephen Boyd
@ 2012-03-15 20:07                             ` Christian Lamparter
  2012-03-15 20:12                               ` Stephen Boyd
  0 siblings, 1 reply; 111+ messages in thread
From: Christian Lamparter @ 2012-03-15 20:07 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: linux-kernel, Linux PM mailing list, Srivatsa S. Bhat, alan,
	Linus Torvalds, Saravana Kannan, Greg Kroah-Hartman, Kay Sievers,
	Rafael J. Wysocki

On Thursday, March 15, 2012 08:50:15 PM Stephen Boyd wrote:
> Oddly enough a work_struct was already part of the firmware_work
> structure but nobody was using it. Instead of creating a new
> kthread for each request_firmware_nowait() just schedule the work
> on the system workqueue. This should avoid some overhead in
> forking new threads when they're not strictly necessary if
> workqueues are available.
> 
> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Cc: Kay Sievers <kay.sievers@vrfy.org>
> Cc: Rafael J. Wysocki <rjw@sisk.pl>
> ---
> 
> I saw this while looking at this problem we're having.
Correct me if I'm wrong, but wouldn't that stall all other
global workqueue tasks for up to 60 seconds [in worst case]?

But I think we can get rid of the firmware_work work struct...

Regards,
	Chr



^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware_class: Move request_firmware_nowait() to workqueues
  2012-03-15 20:07                             ` Christian Lamparter
@ 2012-03-15 20:12                               ` Stephen Boyd
  2012-03-15 22:31                                 ` Rafael J. Wysocki
  0 siblings, 1 reply; 111+ messages in thread
From: Stephen Boyd @ 2012-03-15 20:12 UTC (permalink / raw)
  To: Christian Lamparter
  Cc: linux-kernel, Linux PM mailing list, Srivatsa S. Bhat, alan,
	Linus Torvalds, Saravana Kannan, Greg Kroah-Hartman, Kay Sievers,
	Rafael J. Wysocki

On 03/15/12 13:07, Christian Lamparter wrote:
> On Thursday, March 15, 2012 08:50:15 PM Stephen Boyd wrote:
>> Oddly enough a work_struct was already part of the firmware_work
>> structure but nobody was using it. Instead of creating a new
>> kthread for each request_firmware_nowait() just schedule the work
>> on the system workqueue. This should avoid some overhead in
>> forking new threads when they're not strictly necessary if
>> workqueues are available.
>>
>> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
>> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>> Cc: Kay Sievers <kay.sievers@vrfy.org>
>> Cc: Rafael J. Wysocki <rjw@sisk.pl>
>> ---
>>
>> I saw this while looking at this problem we're having.
> Correct me if I'm wrong, but wouldn't that stall all other
> global workqueue tasks for up to 60 seconds [in worst case]?
>
> But I think we can get rid of the firmware_work work struct...
>

My understanding is that with concurrency managed workqueues when the
work item blocks another will be scheduled to run almost immediately. So
before that change by Tejun workqueues would have been a bad idea
because it could have blocked up to 60 second but now it should be fine
because that work item will just be put to sleep and another request
will run.

-- 
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.


^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware_class: Move request_firmware_nowait() to workqueues
  2012-03-15 20:12                               ` Stephen Boyd
@ 2012-03-15 22:31                                 ` Rafael J. Wysocki
  2012-03-16  1:39                                   ` Stephen Boyd
  0 siblings, 1 reply; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-15 22:31 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Christian Lamparter, linux-kernel, Linux PM mailing list,
	Srivatsa S. Bhat, alan, Linus Torvalds, Saravana Kannan,
	Greg Kroah-Hartman, Kay Sievers

On Thursday, March 15, 2012, Stephen Boyd wrote:
> On 03/15/12 13:07, Christian Lamparter wrote:
> > On Thursday, March 15, 2012 08:50:15 PM Stephen Boyd wrote:
> >> Oddly enough a work_struct was already part of the firmware_work
> >> structure but nobody was using it. Instead of creating a new
> >> kthread for each request_firmware_nowait() just schedule the work
> >> on the system workqueue. This should avoid some overhead in
> >> forking new threads when they're not strictly necessary if
> >> workqueues are available.
> >>
> >> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
> >> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> >> Cc: Kay Sievers <kay.sievers@vrfy.org>
> >> Cc: Rafael J. Wysocki <rjw@sisk.pl>
> >> ---
> >>
> >> I saw this while looking at this problem we're having.
> > Correct me if I'm wrong, but wouldn't that stall all other
> > global workqueue tasks for up to 60 seconds [in worst case]?
> >
> > But I think we can get rid of the firmware_work work struct...
> >
> 
> My understanding is that with concurrency managed workqueues when the
> work item blocks another will be scheduled to run almost immediately. So
> before that change by Tejun workqueues would have been a bad idea
> because it could have blocked up to 60 second but now it should be fine
> because that work item will just be put to sleep and another request
> will run.

Please read the description of system_wq in workqueue.h.

You should have used either system_long_wq or system_nrt_wq (depending on
what you really need).

Thanks,
Rafael

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware_class: Move request_firmware_nowait() to workqueues
  2012-03-15 22:31                                 ` Rafael J. Wysocki
@ 2012-03-16  1:39                                   ` Stephen Boyd
  2012-03-16 20:19                                     ` Rafael J. Wysocki
  0 siblings, 1 reply; 111+ messages in thread
From: Stephen Boyd @ 2012-03-16  1:39 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Christian Lamparter, linux-kernel, Linux PM mailing list,
	Srivatsa S. Bhat, alan, Linus Torvalds, Saravana Kannan,
	Greg Kroah-Hartman, Kay Sievers

On 03/15/12 15:31, Rafael J. Wysocki wrote:
> On Thursday, March 15, 2012, Stephen Boyd wrote:
>> On 03/15/12 13:07, Christian Lamparter wrote:
>>> On Thursday, March 15, 2012 08:50:15 PM Stephen Boyd wrote:
>>>> Oddly enough a work_struct was already part of the firmware_work
>>>> structure but nobody was using it. Instead of creating a new
>>>> kthread for each request_firmware_nowait() just schedule the work
>>>> on the system workqueue. This should avoid some overhead in
>>>> forking new threads when they're not strictly necessary if
>>>> workqueues are available.
>>>>
>>>> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
>>>> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>>>> Cc: Kay Sievers <kay.sievers@vrfy.org>
>>>> Cc: Rafael J. Wysocki <rjw@sisk.pl>
>>>> ---
>>>>
>>>> I saw this while looking at this problem we're having.
>>> Correct me if I'm wrong, but wouldn't that stall all other
>>> global workqueue tasks for up to 60 seconds [in worst case]?
>>>
>>> But I think we can get rid of the firmware_work work struct...
>>>
>> My understanding is that with concurrency managed workqueues when the
>> work item blocks another will be scheduled to run almost immediately. So
>> before that change by Tejun workqueues would have been a bad idea
>> because it could have blocked up to 60 second but now it should be fine
>> because that work item will just be put to sleep and another request
>> will run.
> Please read the description of system_wq in workqueue.h.
>
> You should have used either system_long_wq or system_nrt_wq (depending on
> what you really need).
>
>

Thanks. I think we can use system_nrt_wq then? Or maybe even the
unbounded workqueue system_unbound_wq?

-- 
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.


^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-14 22:54                 ` Rafael J. Wysocki
@ 2012-03-16  7:14                   ` Srivatsa S. Bhat
  2012-03-16 20:23                     ` Rafael J. Wysocki
  0 siblings, 1 reply; 111+ messages in thread
From: Srivatsa S. Bhat @ 2012-03-16  7:14 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Kay Sievers, Greg KH, Christian Lamparter, linux-kernel, alan,
	Linus Torvalds, Linux PM mailing list, skannan, Stephen Boyd

On 03/15/2012 04:24 AM, Rafael J. Wysocki wrote:

> On Wednesday, March 14, 2012, Srivatsa S. Bhat wrote:
>> On 03/14/2012 05:40 AM, Rafael J. Wysocki wrote:
>>
>>> On Wednesday, March 14, 2012, Kay Sievers wrote:
>>>> On Tue, Mar 13, 2012 at 20:42, Rafael J. Wysocki <rjw@sisk.pl> wrote:
>>>>> On Sunday, March 11, 2012, Kay Sievers wrote:
>>>>>> On Sat, Mar 10, 2012 at 00:36, Greg KH <gregkh@linuxfoundation.org> wrote:
>>>>
>>>>>>> What does uevent have to do with things here?
>>>>>>
>>>>>> I don't think that the firmware loader should care about the
>>>>>> usermodehelper at all, and that stuff fiddling should just be removed
>>>>>> from the firmware class.
>>>>>
>>>>> It's there to warn people that their drivers do stupid things like
>>>>> loading frimware during system resume, which is guaranteed not to work.
>>>>>
>>>>> IOW, it's there very much on purpose.
>>>>
>>>> Using the /sbin/hotplug is no case that needs any warning. It' such a
>>>> broken model these days, that firmware loading is the least problem
>>>> that occurs with it.
>>>>
>>>>>> Forking /sbin/hotplug is disabled by default, it is a broken concept,
>>>>>> and it cannot work reliably on today's systems.
>>>>>>
>>>>>> Firmware is not loaded by /sbin/hotplug since many years, but by udev
>>>>>> or whatever service handles uevents, like ueventd on android.
>>>>>
>>>>> Which I'm not sure why is relevant here.
>>>>
>>>> It is relevant in the sense that the firmware loader should not even
>>>> know that a uevent *can* cause a usermodehelper exec() if it runs in
>>>> legacy mode. The firmware loader just has no business in fiddling with
>>>> the details of driver core legacy stuff. I don't think his warning
>>>> makes much sense.
>>>
>>> But that warning actually triggers for drivers that attempt to use
>>> request_firmware() during system resume, even though /sbin/hotplug isn't
>>> used any more.
>>>
>>
>>
>> I agree with Rafael about why the warning and the bail out is required,
>> including the part about the races with freezer which he explained in his
>> other mail. These problems have already been well documented too.
>> (See Documentation/power/freezing-of-tasks.txt).
>>
>>> usermodehelper_is_disabled() means "we are in the middle of system power
>>> transition" rather than anything else (I agree it should be called
>>> suspend_in_progress() or something similar these days).
>>>
>>
>>
>> How about this patch then?
>>
>> ---
>>
>> From: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
>> Subject: PM/firmware loader: Use better name for usermodehelper_is_disabled()
>>
>> Rafael J. Wysocki <rjw@sisk.pl> wrote:
>>
>> | usermodehelper_is_disabled() means "we are in the middle of system power
>> | transition" rather than anything else (I agree it should be called
>> | suspend_in_progress() or something similar these days).
>>
>>
>> But simply renaming usermodehelper_is_disabled() to suspend_in_progress()
>> isn't the best thing to do since that would be misleading because suspend
>> transitions are begun much before usermodehelpers are disabled.
>>
>> Apart from that, we don't want people to suddenly start abusing this function
>> in future in a totally different context to check if suspend is in progress.
>>
>> So, add an alias specific to firmware loaders alone, that will internally
>> call usermodehelpers_is_disabled().
>>
>> Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
>> ---
>>
>>  drivers/base/firmware_class.c |   12 +++++++++++-
>>  1 files changed, 11 insertions(+), 1 deletions(-)
>>
>> diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
>> index 6c9387d..9e401e1 100644
>> --- a/drivers/base/firmware_class.c
>> +++ b/drivers/base/firmware_class.c
>> @@ -510,6 +510,8 @@ static void fw_destroy_instance(struct firmware_priv *fw_priv)
>>  	device_unregister(f_dev);
>>  }
>>  
>> +#define suspend_in_progress()	usermodehelper_is_disabled()
> 
> This looks like an overstretch to me.  I think a comment would be sufficient.


On second thoughts... I agree, a comment is good enough.

> 
>> +
>>  static int _request_firmware(const struct firmware **firmware_p,
>>  			     const char *name, struct device *device,
>>  			     bool uevent, bool nowait)
>> @@ -535,7 +537,15 @@ static int _request_firmware(const struct firmware **firmware_p,
>>  
>>  	read_lock_usermodehelper();
>>  
>> -	if (WARN_ON(usermodehelper_is_disabled())) {
>> +	/*
>> +	 * It is wrong to request firmware when the system is suspended,
>> +	 * because it simply won't work reliably.
> 
> In fact, it won't work at all.
> 
>> +	 Also, it can cause races with
>> +	 * the freezer, leading to freezing failures.
> 
> It actually is worse than that too.  It may cause a user space process
> to run when we think we have frozen user space and _that_ may lead to
> all kinds of interesting breakage.
> 


Oh, yes! That would be really dreadful!

>> 	 * So check if the system is
>> +	 * in a state which is unsuitable for requesting firmware (because the
>> +	 * system is suspended or not yet fully resumed) and bail out early if
>> +	 * needed.
> 
> And here I'd explain why usermodehelper_is_disabled() is used for that.
>


OK
 

>> +	 */
>> +	if (WARN_ON(suspend_in_progress())) {
>>  		dev_err(device, "firmware: %s will not be loaded\n", name);
>>  		retval = -EBUSY;
>>  		goto out;
> 


So here is the updated patch:
(I know its a bit verbose, but given that it is causing a considerable amount of
confusion, may be a proper comment with good explanation is worthwhile).

---

From: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
Subject: PM/firmware loader: Explain why usermodehelper_is_disabled() check is used


Rafael J. Wysocki <rjw@sisk.pl> wrote:

| usermodehelper_is_disabled() means "we are in the middle of system power
| transition" rather than anything else (I agree it should be called
| suspend_in_progress() or something similar these days).

But instead of renaming usermodehelper_is_disabled(), add a comment
explaining its importance and also why the warning and bail out at
_request_firmware() makes sense.

Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
---

 drivers/base/firmware_class.c |   16 ++++++++++++++++
 1 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 6c9387d..9199e3e 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -535,6 +535,22 @@ static int _request_firmware(const struct firmware **firmware_p,
 
 	read_lock_usermodehelper();
 
+	/*
+	 * It is wrong to request firmware when the system is suspended,
+	 * because it simply won't work. Also, it can cause races with
+	 * the freezer, leading to freezing failures. Worse than that,
+	 * it may even cause a user space process to run when we think
+	 * we have frozen the user space! - and that can lead to all kinds
+	 * of interesting breakage..
+	 *
+	 * So check if the system is in a state which is unsuitable for
+	 * requesting firmware (because it is suspended or not yet fully
+	 * resumed) and bail out early if needed.
+	 * Usermodehelpers are disabled at the beginning of suspend, before
+	 * freezing tasks and re-enabled only towards the end of resume, after
+	 * thawing tasks, when it is safe. So all we need to do here is ensure
+	 * that we don't request firmware when usermodehelpers are disabled.
+	 */
 	if (WARN_ON(usermodehelper_is_disabled())) {
 		dev_err(device, "firmware: %s will not be loaded\n", name);
 		retval = -EBUSY;



^ permalink raw reply related	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware_class: Move request_firmware_nowait() to workqueues
  2012-03-16  1:39                                   ` Stephen Boyd
@ 2012-03-16 20:19                                     ` Rafael J. Wysocki
  2012-03-16 20:26                                       ` Stephen Boyd
  0 siblings, 1 reply; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-16 20:19 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Christian Lamparter, linux-kernel, Linux PM mailing list,
	Srivatsa S. Bhat, alan, Linus Torvalds, Saravana Kannan,
	Greg Kroah-Hartman, Kay Sievers

On Friday, March 16, 2012, Stephen Boyd wrote:
> On 03/15/12 15:31, Rafael J. Wysocki wrote:
> > On Thursday, March 15, 2012, Stephen Boyd wrote:
> >> On 03/15/12 13:07, Christian Lamparter wrote:
> >>> On Thursday, March 15, 2012 08:50:15 PM Stephen Boyd wrote:
> >>>> Oddly enough a work_struct was already part of the firmware_work
> >>>> structure but nobody was using it. Instead of creating a new
> >>>> kthread for each request_firmware_nowait() just schedule the work
> >>>> on the system workqueue. This should avoid some overhead in
> >>>> forking new threads when they're not strictly necessary if
> >>>> workqueues are available.
> >>>>
> >>>> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
> >>>> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> >>>> Cc: Kay Sievers <kay.sievers@vrfy.org>
> >>>> Cc: Rafael J. Wysocki <rjw@sisk.pl>
> >>>> ---
> >>>>
> >>>> I saw this while looking at this problem we're having.
> >>> Correct me if I'm wrong, but wouldn't that stall all other
> >>> global workqueue tasks for up to 60 seconds [in worst case]?
> >>>
> >>> But I think we can get rid of the firmware_work work struct...
> >>>
> >> My understanding is that with concurrency managed workqueues when the
> >> work item blocks another will be scheduled to run almost immediately. So
> >> before that change by Tejun workqueues would have been a bad idea
> >> because it could have blocked up to 60 second but now it should be fine
> >> because that work item will just be put to sleep and another request
> >> will run.
> > Please read the description of system_wq in workqueue.h.
> >
> > You should have used either system_long_wq or system_nrt_wq (depending on
> > what you really need).
> >
> >
> 
> Thanks. I think we can use system_nrt_wq then? Or maybe even the
> unbounded workqueue system_unbound_wq?

Hmm.  Can you please remind me what the exact role of that work item is?

It loads the device's firmware, but I'm not sure in what situations that's
supposed to happen.

Thanks,
Rafael

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-16  7:14                   ` Srivatsa S. Bhat
@ 2012-03-16 20:23                     ` Rafael J. Wysocki
  2012-03-16 21:14                       ` Christian Lamparter
  0 siblings, 1 reply; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-16 20:23 UTC (permalink / raw)
  To: Srivatsa S. Bhat
  Cc: Kay Sievers, Greg KH, Christian Lamparter, linux-kernel, alan,
	Linus Torvalds, Linux PM mailing list, skannan, Stephen Boyd

On Friday, March 16, 2012, Srivatsa S. Bhat wrote:
> On 03/15/2012 04:24 AM, Rafael J. Wysocki wrote:
> 
> > On Wednesday, March 14, 2012, Srivatsa S. Bhat wrote:
> >> On 03/14/2012 05:40 AM, Rafael J. Wysocki wrote:
> >>
> >>> On Wednesday, March 14, 2012, Kay Sievers wrote:
> >>>> On Tue, Mar 13, 2012 at 20:42, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> >>>>> On Sunday, March 11, 2012, Kay Sievers wrote:
> >>>>>> On Sat, Mar 10, 2012 at 00:36, Greg KH <gregkh@linuxfoundation.org> wrote:
> >>>>
> >>>>>>> What does uevent have to do with things here?
> >>>>>>
> >>>>>> I don't think that the firmware loader should care about the
> >>>>>> usermodehelper at all, and that stuff fiddling should just be removed
> >>>>>> from the firmware class.
> >>>>>
> >>>>> It's there to warn people that their drivers do stupid things like
> >>>>> loading frimware during system resume, which is guaranteed not to work.
> >>>>>
> >>>>> IOW, it's there very much on purpose.
> >>>>
> >>>> Using the /sbin/hotplug is no case that needs any warning. It' such a
> >>>> broken model these days, that firmware loading is the least problem
> >>>> that occurs with it.
> >>>>
> >>>>>> Forking /sbin/hotplug is disabled by default, it is a broken concept,
> >>>>>> and it cannot work reliably on today's systems.
> >>>>>>
> >>>>>> Firmware is not loaded by /sbin/hotplug since many years, but by udev
> >>>>>> or whatever service handles uevents, like ueventd on android.
> >>>>>
> >>>>> Which I'm not sure why is relevant here.
> >>>>
> >>>> It is relevant in the sense that the firmware loader should not even
> >>>> know that a uevent *can* cause a usermodehelper exec() if it runs in
> >>>> legacy mode. The firmware loader just has no business in fiddling with
> >>>> the details of driver core legacy stuff. I don't think his warning
> >>>> makes much sense.
> >>>
> >>> But that warning actually triggers for drivers that attempt to use
> >>> request_firmware() during system resume, even though /sbin/hotplug isn't
> >>> used any more.
> >>>
> >>
> >>
> >> I agree with Rafael about why the warning and the bail out is required,
> >> including the part about the races with freezer which he explained in his
> >> other mail. These problems have already been well documented too.
> >> (See Documentation/power/freezing-of-tasks.txt).
> >>
> >>> usermodehelper_is_disabled() means "we are in the middle of system power
> >>> transition" rather than anything else (I agree it should be called
> >>> suspend_in_progress() or something similar these days).
> >>>
> >>
> >>
> >> How about this patch then?
> >>
> >> ---
> >>
> >> From: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
> >> Subject: PM/firmware loader: Use better name for usermodehelper_is_disabled()
> >>
> >> Rafael J. Wysocki <rjw@sisk.pl> wrote:
> >>
> >> | usermodehelper_is_disabled() means "we are in the middle of system power
> >> | transition" rather than anything else (I agree it should be called
> >> | suspend_in_progress() or something similar these days).
> >>
> >>
> >> But simply renaming usermodehelper_is_disabled() to suspend_in_progress()
> >> isn't the best thing to do since that would be misleading because suspend
> >> transitions are begun much before usermodehelpers are disabled.
> >>
> >> Apart from that, we don't want people to suddenly start abusing this function
> >> in future in a totally different context to check if suspend is in progress.
> >>
> >> So, add an alias specific to firmware loaders alone, that will internally
> >> call usermodehelpers_is_disabled().
> >>
> >> Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
> >> ---
> >>
> >>  drivers/base/firmware_class.c |   12 +++++++++++-
> >>  1 files changed, 11 insertions(+), 1 deletions(-)
> >>
> >> diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
> >> index 6c9387d..9e401e1 100644
> >> --- a/drivers/base/firmware_class.c
> >> +++ b/drivers/base/firmware_class.c
> >> @@ -510,6 +510,8 @@ static void fw_destroy_instance(struct firmware_priv *fw_priv)
> >>  	device_unregister(f_dev);
> >>  }
> >>  
> >> +#define suspend_in_progress()	usermodehelper_is_disabled()
> > 
> > This looks like an overstretch to me.  I think a comment would be sufficient.
> 
> 
> On second thoughts... I agree, a comment is good enough.
> 
> > 
> >> +
> >>  static int _request_firmware(const struct firmware **firmware_p,
> >>  			     const char *name, struct device *device,
> >>  			     bool uevent, bool nowait)
> >> @@ -535,7 +537,15 @@ static int _request_firmware(const struct firmware **firmware_p,
> >>  
> >>  	read_lock_usermodehelper();
> >>  
> >> -	if (WARN_ON(usermodehelper_is_disabled())) {
> >> +	/*
> >> +	 * It is wrong to request firmware when the system is suspended,
> >> +	 * because it simply won't work reliably.
> > 
> > In fact, it won't work at all.
> > 
> >> +	 Also, it can cause races with
> >> +	 * the freezer, leading to freezing failures.
> > 
> > It actually is worse than that too.  It may cause a user space process
> > to run when we think we have frozen user space and _that_ may lead to
> > all kinds of interesting breakage.
> > 
> 
> 
> Oh, yes! That would be really dreadful!
> 
> >> 	 * So check if the system is
> >> +	 * in a state which is unsuitable for requesting firmware (because the
> >> +	 * system is suspended or not yet fully resumed) and bail out early if
> >> +	 * needed.
> > 
> > And here I'd explain why usermodehelper_is_disabled() is used for that.
> >
> 
> 
> OK
>  
> 
> >> +	 */
> >> +	if (WARN_ON(suspend_in_progress())) {
> >>  		dev_err(device, "firmware: %s will not be loaded\n", name);
> >>  		retval = -EBUSY;
> >>  		goto out;
> > 
> 
> 
> So here is the updated patch:
> (I know its a bit verbose, but given that it is causing a considerable amount of
> confusion, may be a proper comment with good explanation is worthwhile).
> 
> ---
> 
> From: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
> Subject: PM/firmware loader: Explain why usermodehelper_is_disabled() check is used
> 
> 
> Rafael J. Wysocki <rjw@sisk.pl> wrote:
> 
> | usermodehelper_is_disabled() means "we are in the middle of system power
> | transition" rather than anything else (I agree it should be called
> | suspend_in_progress() or something similar these days).
> 
> But instead of renaming usermodehelper_is_disabled(), add a comment
> explaining its importance and also why the warning and bail out at
> _request_firmware() makes sense.
> 
> Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>

That's fine by me.

If no one objects, I'll apply it.

Thanks,
Rafael


> ---
> 
>  drivers/base/firmware_class.c |   16 ++++++++++++++++
>  1 files changed, 16 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
> index 6c9387d..9199e3e 100644
> --- a/drivers/base/firmware_class.c
> +++ b/drivers/base/firmware_class.c
> @@ -535,6 +535,22 @@ static int _request_firmware(const struct firmware **firmware_p,
>  
>  	read_lock_usermodehelper();
>  
> +	/*
> +	 * It is wrong to request firmware when the system is suspended,
> +	 * because it simply won't work. Also, it can cause races with
> +	 * the freezer, leading to freezing failures. Worse than that,
> +	 * it may even cause a user space process to run when we think
> +	 * we have frozen the user space! - and that can lead to all kinds
> +	 * of interesting breakage..
> +	 *
> +	 * So check if the system is in a state which is unsuitable for
> +	 * requesting firmware (because it is suspended or not yet fully
> +	 * resumed) and bail out early if needed.
> +	 * Usermodehelpers are disabled at the beginning of suspend, before
> +	 * freezing tasks and re-enabled only towards the end of resume, after
> +	 * thawing tasks, when it is safe. So all we need to do here is ensure
> +	 * that we don't request firmware when usermodehelpers are disabled.
> +	 */
>  	if (WARN_ON(usermodehelper_is_disabled())) {
>  		dev_err(device, "firmware: %s will not be loaded\n", name);
>  		retval = -EBUSY;
> 
> 
> 
> 


^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware_class: Move request_firmware_nowait() to workqueues
  2012-03-16 20:19                                     ` Rafael J. Wysocki
@ 2012-03-16 20:26                                       ` Stephen Boyd
  2012-03-16 21:45                                         ` Rafael J. Wysocki
  0 siblings, 1 reply; 111+ messages in thread
From: Stephen Boyd @ 2012-03-16 20:26 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Christian Lamparter, linux-kernel, Linux PM mailing list,
	Srivatsa S. Bhat, alan, Linus Torvalds, Saravana Kannan,
	Greg Kroah-Hartman, Kay Sievers

On 03/16/12 13:19, Rafael J. Wysocki wrote:
> On Friday, March 16, 2012, Stephen Boyd wrote:
>> On 03/15/12 15:31, Rafael J. Wysocki wrote:
>>> On Thursday, March 15, 2012, Stephen Boyd wrote:
>>>> On 03/15/12 13:07, Christian Lamparter wrote:
>>>>> On Thursday, March 15, 2012 08:50:15 PM Stephen Boyd wrote:
>>>>>> Oddly enough a work_struct was already part of the firmware_work
>>>>>> structure but nobody was using it. Instead of creating a new
>>>>>> kthread for each request_firmware_nowait() just schedule the work
>>>>>> on the system workqueue. This should avoid some overhead in
>>>>>> forking new threads when they're not strictly necessary if
>>>>>> workqueues are available.
>>>>>>
>>>>>> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
>>>>>> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>>>>>> Cc: Kay Sievers <kay.sievers@vrfy.org>
>>>>>> Cc: Rafael J. Wysocki <rjw@sisk.pl>
>>>>>> ---
>>>>>>
>>>>>> I saw this while looking at this problem we're having.
>>>>> Correct me if I'm wrong, but wouldn't that stall all other
>>>>> global workqueue tasks for up to 60 seconds [in worst case]?
>>>>>
>>>>> But I think we can get rid of the firmware_work work struct...
>>>>>
>>>> My understanding is that with concurrency managed workqueues when the
>>>> work item blocks another will be scheduled to run almost immediately. So
>>>> before that change by Tejun workqueues would have been a bad idea
>>>> because it could have blocked up to 60 second but now it should be fine
>>>> because that work item will just be put to sleep and another request
>>>> will run.
>>> Please read the description of system_wq in workqueue.h.
>>>
>>> You should have used either system_long_wq or system_nrt_wq (depending on
>>> what you really need).
>>>
>>>
>> Thanks. I think we can use system_nrt_wq then? Or maybe even the
>> unbounded workqueue system_unbound_wq?
> Hmm.  Can you please remind me what the exact role of that work item is?
>
> It loads the device's firmware, but I'm not sure in what situations that's
> supposed to happen.
>

request_firmware_nowait() is used by code that wants to get the firmware
asynchronously. Callers pass in a callback function which is called once
the firmware is retrieved. The work item will correspond to one call to
request_firmware_nowait(), where the work item will handle the sysfs
entry generation, uevent generation, and wait_for_completion() calls
that _request_firmware() does.

The work item also executes the callback function the caller passes in
which could do probably anything and could take an arbitrarily long
time. It looks like some drivers even chain request_firmware_nowait()
together by calling request_firmware_nowait() from the callback functions.

-- 
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.


^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-16 20:23                     ` Rafael J. Wysocki
@ 2012-03-16 21:14                       ` Christian Lamparter
  2012-03-16 21:19                         ` Linus Torvalds
  2012-03-19  7:06                         ` Srivatsa S. Bhat
  0 siblings, 2 replies; 111+ messages in thread
From: Christian Lamparter @ 2012-03-16 21:14 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Srivatsa S. Bhat, Kay Sievers, Greg KH, linux-kernel, alan,
	Linus Torvalds, Linux PM mailing list, skannan, Stephen Boyd

> That's fine by me.
> 
> If no one objects, I'll apply it.

Congrats on that nice, long and "obvious" explanation. Really,
what do you mean by the "end of resume"? As far as I know it
is NOT "after" all ->resume calls have finished, in fact the
usermodehelper is still disabled during ->complete! Maybe a
hint about "after/before function X() has finished/starts" 

Furthermore, I wonder what happends about built-in modules
for devices that need a firmware at probe [e.g.: different
firmware support different special features. This is quite
common for wifi stuff. e.g.: Special firmwares for APs]?

Because As far as I know "driver_init();" is called before
"usermodehelper_enable();" in "do_basic_setup()".
So, theoretical these people should see the same WARNINGs
and read the comment about suspend/resume and I'm sure
they will be thinking: WTF! 

Regards,
	Chr
> > ---
> > 
> >  drivers/base/firmware_class.c |   16 ++++++++++++++++
> >  1 files changed, 16 insertions(+), 0 deletions(-)
> > 
> > diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
> > index 6c9387d..9199e3e 100644
> > --- a/drivers/base/firmware_class.c
> > +++ b/drivers/base/firmware_class.c
> > @@ -535,6 +535,22 @@ static int _request_firmware(const struct firmware **firmware_p,
> >  
> >  	read_lock_usermodehelper();
> >  
> > +	/*
> > +	 * It is wrong to request firmware when the system is suspended,
> > +	 * because it simply won't work. Also, it can cause races with
> > +	 * the freezer, leading to freezing failures. Worse than that,
> > +	 * it may even cause a user space process to run when we think
> > +	 * we have frozen the user space! - and that can lead to all kinds
> > +	 * of interesting breakage..
> > +	 *
> > +	 * So check if the system is in a state which is unsuitable for
> > +	 * requesting firmware (because it is suspended or not yet fully
> > +	 * resumed) and bail out early if needed.
> > +	 * Usermodehelpers are disabled at the beginning of suspend, before
> > +	 * freezing tasks and re-enabled only towards the end of resume, after
> > +	 * thawing tasks, when it is safe. So all we need to do here is ensure
> > +	 * that we don't request firmware when usermodehelpers are disabled.
> > +	 */
> >  	if (WARN_ON(usermodehelper_is_disabled())) {
> >  		dev_err(device, "firmware: %s will not be loaded\n", name);
> >  		retval = -EBUSY;

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-16 21:14                       ` Christian Lamparter
@ 2012-03-16 21:19                         ` Linus Torvalds
  2012-03-19  7:06                         ` Srivatsa S. Bhat
  1 sibling, 0 replies; 111+ messages in thread
From: Linus Torvalds @ 2012-03-16 21:19 UTC (permalink / raw)
  To: Christian Lamparter
  Cc: Rafael J. Wysocki, Srivatsa S. Bhat, Kay Sievers, Greg KH,
	linux-kernel, alan, Linux PM mailing list, skannan, Stephen Boyd

On Fri, Mar 16, 2012 at 2:14 PM, Christian Lamparter
<chunkeey@googlemail.com> wrote:
>
> Because As far as I know "driver_init();" is called before
> "usermodehelper_enable();" in "do_basic_setup()".
> So, theoretical these people should see the same WARNINGs
> and read the comment about suspend/resume and I'm sure
> they will be thinking: WTF!

Just make the explanation be simple:

  "The system is not 8in a fully initialized state, and you cannot
load firmware at this point. User mode is not running, not all devices
have necessarily been initialized, user space applications may or may
not be frozen, and the filesystem may or may not exist yet. Loading
firmware is buggy under these circumstances. Go away"

Don't try to go into any details. The "you can race with freezer" is
too much detail. Even "suspend/resume" is too much detail. The fact
is, the system just isn't ready yet. The details are almost entirely
irrelevant, at best they can be examples of some things that can cause
problems.

                      Linus

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware_class: Move request_firmware_nowait() to workqueues
  2012-03-16 20:26                                       ` Stephen Boyd
@ 2012-03-16 21:45                                         ` Rafael J. Wysocki
  2012-03-16 22:18                                           ` Christian Lamparter
  0 siblings, 1 reply; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-16 21:45 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Christian Lamparter, linux-kernel, Linux PM mailing list,
	Srivatsa S. Bhat, alan, Linus Torvalds, Saravana Kannan,
	Greg Kroah-Hartman, Kay Sievers

On Friday, March 16, 2012, Stephen Boyd wrote:
> On 03/16/12 13:19, Rafael J. Wysocki wrote:
> > On Friday, March 16, 2012, Stephen Boyd wrote:
> >> On 03/15/12 15:31, Rafael J. Wysocki wrote:
> >>> On Thursday, March 15, 2012, Stephen Boyd wrote:
> >>>> On 03/15/12 13:07, Christian Lamparter wrote:
> >>>>> On Thursday, March 15, 2012 08:50:15 PM Stephen Boyd wrote:
> >>>>>> Oddly enough a work_struct was already part of the firmware_work
> >>>>>> structure but nobody was using it. Instead of creating a new
> >>>>>> kthread for each request_firmware_nowait() just schedule the work
> >>>>>> on the system workqueue. This should avoid some overhead in
> >>>>>> forking new threads when they're not strictly necessary if
> >>>>>> workqueues are available.
> >>>>>>
> >>>>>> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
> >>>>>> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> >>>>>> Cc: Kay Sievers <kay.sievers@vrfy.org>
> >>>>>> Cc: Rafael J. Wysocki <rjw@sisk.pl>
> >>>>>> ---
> >>>>>>
> >>>>>> I saw this while looking at this problem we're having.
> >>>>> Correct me if I'm wrong, but wouldn't that stall all other
> >>>>> global workqueue tasks for up to 60 seconds [in worst case]?
> >>>>>
> >>>>> But I think we can get rid of the firmware_work work struct...
> >>>>>
> >>>> My understanding is that with concurrency managed workqueues when the
> >>>> work item blocks another will be scheduled to run almost immediately. So
> >>>> before that change by Tejun workqueues would have been a bad idea
> >>>> because it could have blocked up to 60 second but now it should be fine
> >>>> because that work item will just be put to sleep and another request
> >>>> will run.
> >>> Please read the description of system_wq in workqueue.h.
> >>>
> >>> You should have used either system_long_wq or system_nrt_wq (depending on
> >>> what you really need).
> >>>
> >>>
> >> Thanks. I think we can use system_nrt_wq then? Or maybe even the
> >> unbounded workqueue system_unbound_wq?
> > Hmm.  Can you please remind me what the exact role of that work item is?
> >
> > It loads the device's firmware, but I'm not sure in what situations that's
> > supposed to happen.
> >
> 
> request_firmware_nowait() is used by code that wants to get the firmware
> asynchronously. Callers pass in a callback function which is called once
> the firmware is retrieved. The work item will correspond to one call to
> request_firmware_nowait(), where the work item will handle the sysfs
> entry generation, uevent generation, and wait_for_completion() calls
> that _request_firmware() does.
> 
> The work item also executes the callback function the caller passes in
> which could do probably anything and could take an arbitrarily long
> time. It looks like some drivers even chain request_firmware_nowait()
> together by calling request_firmware_nowait() from the callback functions.

So it looks like an unbound workqueue would be suitable for that, but
perhaps it may even be an ordered one?

Rafael

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware_class: Move request_firmware_nowait() to workqueues
  2012-03-16 21:45                                         ` Rafael J. Wysocki
@ 2012-03-16 22:18                                           ` Christian Lamparter
  2012-03-16 22:35                                             ` Rafael J. Wysocki
  0 siblings, 1 reply; 111+ messages in thread
From: Christian Lamparter @ 2012-03-16 22:18 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Stephen Boyd, linux-kernel, Linux PM mailing list,
	Srivatsa S. Bhat, alan, Linus Torvalds, Saravana Kannan,
	Greg Kroah-Hartman, Kay Sievers

On Friday 16 March 2012 22:45:52 Rafael J. Wysocki wrote:
> On Friday, March 16, 2012, Stephen Boyd wrote:
> > On 03/16/12 13:19, Rafael J. Wysocki wrote:
> > > On Friday, March 16, 2012, Stephen Boyd wrote:
> > >> On 03/15/12 15:31, Rafael J. Wysocki wrote:
> > >>> On Thursday, March 15, 2012, Stephen Boyd wrote:
> > >>>> On 03/15/12 13:07, Christian Lamparter wrote:
> > >>>>> On Thursday, March 15, 2012 08:50:15 PM Stephen Boyd wrote:
> > >>>>>> Oddly enough a work_struct was already part of the firmware_work
> > >>>>>> structure but nobody was using it. Instead of creating a new
> > >>>>>> kthread for each request_firmware_nowait() just schedule the work
> > >>>>>> on the system workqueue. This should avoid some overhead in
> > >>>>>> forking new threads when they're not strictly necessary if
> > >>>>>> workqueues are available.
> > >>>>>>
> > >>>>>> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
> > >>>>>> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > >>>>>> Cc: Kay Sievers <kay.sievers@vrfy.org>
> > >>>>>> Cc: Rafael J. Wysocki <rjw@sisk.pl>
> > >>>>>> ---
> > >>>>>>
> > >>>>>> I saw this while looking at this problem we're having.
> > >>>>> Correct me if I'm wrong, but wouldn't that stall all other
> > >>>>> global workqueue tasks for up to 60 seconds [in worst case]?
> > >>>>>
> > >>>>> But I think we can get rid of the firmware_work work struct...
> > >>>>>
> > >>>> My understanding is that with concurrency managed workqueues when the
> > >>>> work item blocks another will be scheduled to run almost immediately. So
> > >>>> before that change by Tejun workqueues would have been a bad idea
> > >>>> because it could have blocked up to 60 second but now it should be fine
> > >>>> because that work item will just be put to sleep and another request
> > >>>> will run.
> > >>> Please read the description of system_wq in workqueue.h.
> > >>>
> > >>> You should have used either system_long_wq or system_nrt_wq (depending on
> > >>> what you really need).
> > >>>
> > >>>
> > >> Thanks. I think we can use system_nrt_wq then? Or maybe even the
> > >> unbounded workqueue system_unbound_wq?
> > > Hmm.  Can you please remind me what the exact role of that work item is?
> > >
> > > It loads the device's firmware, but I'm not sure in what situations that's
> > > supposed to happen.
> > >
> > 
> > request_firmware_nowait() is used by code that wants to get the firmware
> > asynchronously. Callers pass in a callback function which is called once
> > the firmware is retrieved. The work item will correspond to one call to
> > request_firmware_nowait(), where the work item will handle the sysfs
> > entry generation, uevent generation, and wait_for_completion() calls
> > that _request_firmware() does.
> > 
> > The work item also executes the callback function the caller passes in
> > which could do probably anything and could take an arbitrarily long
> > time. It looks like some drivers even chain request_firmware_nowait()
> > together by calling request_firmware_nowait() from the callback functions.
> 
> So it looks like an unbound workqueue would be suitable for that, but
> perhaps it may even be an ordered one?
Just a note:
kernel/kmod.c currently defines a workqueue "khelper"... So since we are
already "using" kmod's usermodehelper_*, then why not the mess with the
workqueue as well? 

Regards,
	Chr

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [RFC] firmware loader: retry _nowait requests when userhelper is not yet available
  2012-03-05 20:12 ` Srivatsa S. Bhat
  2012-03-09 22:30   ` [PATCH] firmware loader: don't cancel _nowait requests when helper " Christian Lamparter
@ 2012-03-16 22:19   ` Rafael J. Wysocki
  2012-03-16 22:25     ` Christian Lamparter
  1 sibling, 1 reply; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-16 22:19 UTC (permalink / raw)
  To: Srivatsa S. Bhat
  Cc: Christian Lamparter, linux-kernel, gregkh, alan, Linus Torvalds,
	Linux PM mailing list

On Monday, March 05, 2012, Srivatsa S. Bhat wrote:
> 
> [ Adding more Cc's. ]
> 
> On 03/04/2012 01:52 AM, Christian Lamparter wrote:
> 
> > During resume, the userhelper might not be available. However for
> > drivers which use the request_firmware_nowait interface, this will
> > only lead to a pointless WARNING and a device which no longer works
> > after the resume [since it couldn't get the firmware, because the
> > userhelper was not available to take the request].
> > 
> > In order to solve this "chicken or egg" dilemma, the code now
> > retries _nowait requests at one second intervals until the
> > "loading_timeout" time is up.
> > 
> > ---
> > I'm aware about the previous "request_firmware* in probe" discussions.
> > Unfortunately, the hardware needs firmware so there is no other way
> > around it. So please, I just wanted to know what the general opinion
> > about the idea behind this patch is.

BTW, I wonder what comments on this patch were posted?

Rafael


> > ---
> >  drivers/base/firmware_class.c |   24 +++++++++++++++++++++++-
> >  1 files changed, 23 insertions(+), 1 deletions(-)
> > 
> > diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
> > index 6c9387d..9f70096 100644
> > --- a/drivers/base/firmware_class.c
> > +++ b/drivers/base/firmware_class.c
> > @@ -19,6 +19,7 @@
> >  #include <linux/kthread.h>
> >  #include <linux/highmem.h>
> >  #include <linux/firmware.h>
> > +#include <linux/delay.h>
> >  #include <linux/slab.h>
> > 
> >  #define to_dev(obj) container_of(obj, struct device, kobj)
> > @@ -535,6 +536,11 @@ static int _request_firmware(const struct firmware **firmware_p,
> > 
> >  	read_lock_usermodehelper();
> > 
> > +	if (nowait && usermodehelper_is_disabled()) {
> > +		retval = -EBUSY;
> > +		goto out;
> > +	}
> > +
> >  	if (WARN_ON(usermodehelper_is_disabled())) {
> >  		dev_err(device, "firmware: %s will not be loaded\n", name);
> >  		retval = -EBUSY;
> > @@ -633,7 +639,7 @@ static int request_firmware_work_func(void *arg)
> >  {
> >  	struct firmware_work *fw_work = arg;
> >  	const struct firmware *fw;
> > -	int ret;
> > +	int ret, timeout = loading_timeout;
> > 
> >  	if (!arg) {
> >  		WARN_ON(1);
> > @@ -642,6 +648,22 @@ static int request_firmware_work_func(void *arg)
> > 
> >  	ret = _request_firmware(&fw, fw_work->name, fw_work->device,
> >  				fw_work->uevent, true);
> > +
> > +	while (ret == -EBUSY) {
> > +		/*
> > +		 * Try to retrieve the firmware within the loading timeout.
> > +		 * To stick with the loading timeout convention from above:
> > +		 *	loading_timeout = 0 means 'try forever' as well.
> > +		 */
> > +
> > +		msleep(1000);
> > +		ret = _request_firmware(&fw, fw_work->name, fw_work->device,
> > +					fw_work->uevent, true);
> > +
> > +		if (timeout != 0 && timeout-- == 1)
> 
> > +			break;
> 
> > +	};
> 
> > +
> 
> >  	fw_work->cont(fw, fw_work->context);
> > 
> >  	module_put(fw_work->module);
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
> 


^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [RFC] firmware loader: retry _nowait requests when userhelper is not yet available
  2012-03-16 22:19   ` [RFC] firmware loader: retry _nowait requests when userhelper " Rafael J. Wysocki
@ 2012-03-16 22:25     ` Christian Lamparter
  2012-03-16 22:57       ` Rafael J. Wysocki
  0 siblings, 1 reply; 111+ messages in thread
From: Christian Lamparter @ 2012-03-16 22:25 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Srivatsa S. Bhat, linux-kernel, gregkh, alan, Linus Torvalds,
	Linux PM mailing list

On Friday 16 March 2012 23:19:53 Rafael J. Wysocki wrote:
> > On 03/04/2012 01:52 AM, Christian Lamparter wrote:
> > 
> > > During resume, the userhelper might not be available. However for
> > > drivers which use the request_firmware_nowait interface, this will
> > > only lead to a pointless WARNING and a device which no longer works
> > > after the resume [since it couldn't get the firmware, because the
> > > userhelper was not available to take the request].
> > > 
> > > In order to solve this "chicken or egg" dilemma, the code now
> > > retries _nowait requests at one second intervals until the
> > > "loading_timeout" time is up.
> > > 
> > > ---
> > > I'm aware about the previous "request_firmware* in probe" discussions.
> > > Unfortunately, the hardware needs firmware so there is no other way
> > > around it. So please, I just wanted to know what the general opinion
> > > about the idea behind this patch is.
> 
> BTW, I wonder what comments on this patch were posted?
Only Alan Cox was kind enough to drop me a few words.

Why? Do you think it is actually sane from a specific POV?
[Don't tell me you do :D !]

Really, it wasn't until:
"[PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available"
https://lkml.org/lkml/2012/3/9/612 
that things started to pick up.

Regards,
	Chr

> > > ---
> > >  drivers/base/firmware_class.c |   24 +++++++++++++++++++++++-
> > >  1 files changed, 23 insertions(+), 1 deletions(-)
> > > 
> > > diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
> > > index 6c9387d..9f70096 100644
> > > --- a/drivers/base/firmware_class.c
> > > +++ b/drivers/base/firmware_class.c
> > > @@ -19,6 +19,7 @@
> > >  #include <linux/kthread.h>
> > >  #include <linux/highmem.h>
> > >  #include <linux/firmware.h>
> > > +#include <linux/delay.h>
> > >  #include <linux/slab.h>
> > > 
> > >  #define to_dev(obj) container_of(obj, struct device, kobj)
> > > @@ -535,6 +536,11 @@ static int _request_firmware(const struct firmware **firmware_p,
> > > 
> > >  	read_lock_usermodehelper();
> > > 
> > > +	if (nowait && usermodehelper_is_disabled()) {
> > > +		retval = -EBUSY;
> > > +		goto out;
> > > +	}
> > > +
> > >  	if (WARN_ON(usermodehelper_is_disabled())) {
> > >  		dev_err(device, "firmware: %s will not be loaded\n", name);
> > >  		retval = -EBUSY;
> > > @@ -633,7 +639,7 @@ static int request_firmware_work_func(void *arg)
> > >  {
> > >  	struct firmware_work *fw_work = arg;
> > >  	const struct firmware *fw;
> > > -	int ret;
> > > +	int ret, timeout = loading_timeout;
> > > 
> > >  	if (!arg) {
> > >  		WARN_ON(1);
> > > @@ -642,6 +648,22 @@ static int request_firmware_work_func(void *arg)
> > > 
> > >  	ret = _request_firmware(&fw, fw_work->name, fw_work->device,
> > >  				fw_work->uevent, true);
> > > +
> > > +	while (ret == -EBUSY) {
> > > +		/*
> > > +		 * Try to retrieve the firmware within the loading timeout.
> > > +		 * To stick with the loading timeout convention from above:
> > > +		 *	loading_timeout = 0 means 'try forever' as well.
> > > +		 */
> > > +
> > > +		msleep(1000);
> > > +		ret = _request_firmware(&fw, fw_work->name, fw_work->device,
> > > +					fw_work->uevent, true);
> > > +
> > > +		if (timeout != 0 && timeout-- == 1)
> > 
> > > +			break;
> > 
> > > +	};
> > 
> > > +
> > 
> > >  	fw_work->cont(fw, fw_work->context);
> > > 
> > >  	module_put(fw_work->module);
> > 

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware_class: Move request_firmware_nowait() to workqueues
  2012-03-16 22:18                                           ` Christian Lamparter
@ 2012-03-16 22:35                                             ` Rafael J. Wysocki
  0 siblings, 0 replies; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-16 22:35 UTC (permalink / raw)
  To: Christian Lamparter
  Cc: Stephen Boyd, linux-kernel, Linux PM mailing list,
	Srivatsa S. Bhat, alan, Linus Torvalds, Saravana Kannan,
	Greg Kroah-Hartman, Kay Sievers

On Friday, March 16, 2012, Christian Lamparter wrote:
> On Friday 16 March 2012 22:45:52 Rafael J. Wysocki wrote:
> > On Friday, March 16, 2012, Stephen Boyd wrote:
> > > On 03/16/12 13:19, Rafael J. Wysocki wrote:
> > > > On Friday, March 16, 2012, Stephen Boyd wrote:
> > > >> On 03/15/12 15:31, Rafael J. Wysocki wrote:
> > > >>> On Thursday, March 15, 2012, Stephen Boyd wrote:
> > > >>>> On 03/15/12 13:07, Christian Lamparter wrote:
> > > >>>>> On Thursday, March 15, 2012 08:50:15 PM Stephen Boyd wrote:
> > > >>>>>> Oddly enough a work_struct was already part of the firmware_work
> > > >>>>>> structure but nobody was using it. Instead of creating a new
> > > >>>>>> kthread for each request_firmware_nowait() just schedule the work
> > > >>>>>> on the system workqueue. This should avoid some overhead in
> > > >>>>>> forking new threads when they're not strictly necessary if
> > > >>>>>> workqueues are available.
> > > >>>>>>
> > > >>>>>> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
> > > >>>>>> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > > >>>>>> Cc: Kay Sievers <kay.sievers@vrfy.org>
> > > >>>>>> Cc: Rafael J. Wysocki <rjw@sisk.pl>
> > > >>>>>> ---
> > > >>>>>>
> > > >>>>>> I saw this while looking at this problem we're having.
> > > >>>>> Correct me if I'm wrong, but wouldn't that stall all other
> > > >>>>> global workqueue tasks for up to 60 seconds [in worst case]?
> > > >>>>>
> > > >>>>> But I think we can get rid of the firmware_work work struct...
> > > >>>>>
> > > >>>> My understanding is that with concurrency managed workqueues when the
> > > >>>> work item blocks another will be scheduled to run almost immediately. So
> > > >>>> before that change by Tejun workqueues would have been a bad idea
> > > >>>> because it could have blocked up to 60 second but now it should be fine
> > > >>>> because that work item will just be put to sleep and another request
> > > >>>> will run.
> > > >>> Please read the description of system_wq in workqueue.h.
> > > >>>
> > > >>> You should have used either system_long_wq or system_nrt_wq (depending on
> > > >>> what you really need).
> > > >>>
> > > >>>
> > > >> Thanks. I think we can use system_nrt_wq then? Or maybe even the
> > > >> unbounded workqueue system_unbound_wq?
> > > > Hmm.  Can you please remind me what the exact role of that work item is?
> > > >
> > > > It loads the device's firmware, but I'm not sure in what situations that's
> > > > supposed to happen.
> > > >
> > > 
> > > request_firmware_nowait() is used by code that wants to get the firmware
> > > asynchronously. Callers pass in a callback function which is called once
> > > the firmware is retrieved. The work item will correspond to one call to
> > > request_firmware_nowait(), where the work item will handle the sysfs
> > > entry generation, uevent generation, and wait_for_completion() calls
> > > that _request_firmware() does.
> > > 
> > > The work item also executes the callback function the caller passes in
> > > which could do probably anything and could take an arbitrarily long
> > > time. It looks like some drivers even chain request_firmware_nowait()
> > > together by calling request_firmware_nowait() from the callback functions.
> > 
> > So it looks like an unbound workqueue would be suitable for that, but
> > perhaps it may even be an ordered one?
> Just a note:
> kernel/kmod.c currently defines a workqueue "khelper"... So since we are
> already "using" kmod's usermodehelper_*, then why not the mess with the
> workqueue as well?

Well, under a different name, maybe ...

Rafael

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [RFC] firmware loader: retry _nowait requests when userhelper is not yet available
  2012-03-16 22:25     ` Christian Lamparter
@ 2012-03-16 22:57       ` Rafael J. Wysocki
  2012-03-16 23:35         ` Christian Lamparter
  2012-03-16 23:37         ` Linus Torvalds
  0 siblings, 2 replies; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-16 22:57 UTC (permalink / raw)
  To: Christian Lamparter
  Cc: Srivatsa S. Bhat, linux-kernel, gregkh, alan, Linus Torvalds,
	Linux PM mailing list

On Friday, March 16, 2012, Christian Lamparter wrote:
> On Friday 16 March 2012 23:19:53 Rafael J. Wysocki wrote:
> > > On 03/04/2012 01:52 AM, Christian Lamparter wrote:
> > > 
> > > > During resume, the userhelper might not be available. However for
> > > > drivers which use the request_firmware_nowait interface, this will
> > > > only lead to a pointless WARNING and a device which no longer works
> > > > after the resume [since it couldn't get the firmware, because the
> > > > userhelper was not available to take the request].
> > > > 
> > > > In order to solve this "chicken or egg" dilemma, the code now
> > > > retries _nowait requests at one second intervals until the
> > > > "loading_timeout" time is up.
> > > > 
> > > > ---
> > > > I'm aware about the previous "request_firmware* in probe" discussions.
> > > > Unfortunately, the hardware needs firmware so there is no other way
> > > > around it. So please, I just wanted to know what the general opinion
> > > > about the idea behind this patch is.
> > 
> > BTW, I wonder what comments on this patch were posted?
> Only Alan Cox was kind enough to drop me a few words.
> 
> Why? Do you think it is actually sane from a specific POV?
> [Don't tell me you do :D !]

I don't think it's really wrong.

I agree that the WARN_ON() isn't really useful in the request_firmware_nowait()
case, because the user of that doesn't really know when exactly the firmware is
going to be requested, so it can't really do anything about the warning.

Moreover, failures of request_firmware_nowait() just because it happens to
race with system suspend (or something of that kind), just because of "bad"
timing, aren't really useful either.

So, I think it makes sense for it to wait until the firmware can be loaded.

I'd do that a bit differently, though, for example like in the appended patch
(untested).

Thanks,
Rafael

---
 drivers/base/firmware_class.c |   31 +++++++++++++++++++++++++++----
 1 file changed, 27 insertions(+), 4 deletions(-)

Index: linux/drivers/base/firmware_class.c
===================================================================
--- linux.orig/drivers/base/firmware_class.c
+++ linux/drivers/base/firmware_class.c
@@ -20,6 +20,7 @@
 #include <linux/highmem.h>
 #include <linux/firmware.h>
 #include <linux/slab.h>
+#include <linux/delay.h>
 
 #define to_dev(obj) container_of(obj, struct device, kobj)
 
@@ -535,10 +536,31 @@ static int _request_firmware(const struc
 
 	read_lock_usermodehelper();
 
-	if (WARN_ON(usermodehelper_is_disabled())) {
+	if (nowait) {
+		int limit = loading_timeout * MSEC_PER_SEC;
+		int timeout = 10;  /* in msec */
+
+		while (usermodehelper_is_disabled()) {
+			read_unlock_usermodehelper();
+
+			msleep(timeout);
+			if (loading_timeout > 0) {
+				limit -= timeout;
+				if (limit <= 0) {
+					retval = -EBUSY;
+					goto out;
+				}
+			}
+			timeout += timeout;
+			if (loading_timeout > 0 && timeout > limit)
+				timeout = limit;
+
+			read_lock_usermodehelper();
+		}
+	} else if (WARN_ON(usermodehelper_is_disabled())) {
 		dev_err(device, "firmware: %s will not be loaded\n", name);
 		retval = -EBUSY;
-		goto out;
+		goto unlock;
 	}
 
 	if (uevent)
@@ -547,7 +569,7 @@ static int _request_firmware(const struc
 	fw_priv = fw_create_instance(firmware, name, device, uevent, nowait);
 	if (IS_ERR(fw_priv)) {
 		retval = PTR_ERR(fw_priv);
-		goto out;
+		goto unlock;
 	}
 
 	if (uevent) {
@@ -572,9 +594,10 @@ static int _request_firmware(const struc
 
 	fw_destroy_instance(fw_priv);
 
-out:
+unlock:
 	read_unlock_usermodehelper();
 
+out:
 	if (retval) {
 		release_firmware(firmware);
 		*firmware_p = NULL;

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [RFC] firmware loader: retry _nowait requests when userhelper is not yet available
  2012-03-16 22:57       ` Rafael J. Wysocki
@ 2012-03-16 23:35         ` Christian Lamparter
  2012-03-16 23:37         ` Linus Torvalds
  1 sibling, 0 replies; 111+ messages in thread
From: Christian Lamparter @ 2012-03-16 23:35 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Srivatsa S. Bhat, linux-kernel, gregkh, alan, Linus Torvalds,
	Linux PM mailing list

On Friday 16 March 2012 23:57:10 Rafael J. Wysocki wrote:
> On Friday, March 16, 2012, Christian Lamparter wrote:
> > On Friday 16 March 2012 23:19:53 Rafael J. Wysocki wrote:
> > > > On 03/04/2012 01:52 AM, Christian Lamparter wrote:
> > > > > During resume, the userhelper might not be available. However for
> > > > > drivers which use the request_firmware_nowait interface, this will
> > > > > only lead to a pointless WARNING and a device which no longer works
> > > > > after the resume [since it couldn't get the firmware, because the
> > > > > userhelper was not available to take the request].
> > > > > 
> > > > > In order to solve this "chicken or egg" dilemma, the code now
> > > > > retries _nowait requests at one second intervals until the
> > > > > "loading_timeout" time is up.
> > > 
> > > BTW, I wonder what comments on this patch were posted?
> > Only Alan Cox was kind enough to drop me a few words.
> > 
> > Why? Do you think it is actually sane from a specific POV?
> > [Don't tell me you do :D !]
> 
> I don't think it's really wrong.
Of course, I've tested both patches [the RFC and the other one].
The RFC might not be "really wrong" but the concept of busy
msleeping strikes me as a bit insane. [Maybe, that's because I
write drivers and I hate it when IO needs msleeps... brrr]
 
> I agree that the WARN_ON() isn't really useful in the request_firmware_nowait()
> case, because the user of that doesn't really know when exactly the firmware is
> going to be requested, so it can't really do anything about the warning.
> 
> Moreover, failures of request_firmware_nowait() just because it happens to
> race with system suspend (or something of that kind), just because of "bad"
> timing, aren't really useful either.
> 
If it's just about "waiting until the firmware can be loaded" then why not go
with the "easy approach in the [PATCH] don't cancel...". This just queues the
request in the _nowait case. And once the userspace helper is running, it will
pick up all backlogged firmware requests [of course, only the ones that have
not been timeouted yet] and life goes on!

Anyway, I know that I don't really have a say in what will be accepted.
So, it's all up to you guys! But I'll happily test any patches.

> So, I think it makes sense for it to wait until the firmware can be loaded.
> 
> I'd do that a bit differently, though, for example like in the appended patch
> (untested).
Just one comment. [see below] 

And now, I'm off to bed.

Good night,
	Chr

> ---
>  drivers/base/firmware_class.c |   31 +++++++++++++++++++++++++++----
>  1 file changed, 27 insertions(+), 4 deletions(-)


> Index: linux/drivers/base/firmware_class.c
> ===================================================================
> --- linux.orig/drivers/base/firmware_class.c
> +++ linux/drivers/base/firmware_class.c
> @@ -20,6 +20,7 @@
>  #include <linux/highmem.h>
>  #include <linux/firmware.h>
>  #include <linux/slab.h>
> +#include <linux/delay.h>
>  
>  #define to_dev(obj) container_of(obj, struct device, kobj)
>  
> @@ -535,10 +536,31 @@ static int _request_firmware(const struc
>  
>  	read_lock_usermodehelper();
>  
> -	if (WARN_ON(usermodehelper_is_disabled())) {
> +	if (nowait) {
> +		int limit = loading_timeout * MSEC_PER_SEC;
> +		int timeout = 10;  /* in msec */
> +
> +		while (usermodehelper_is_disabled()) {
> +			read_unlock_usermodehelper();
> +
> +			msleep(timeout);
timeout is 10 ms, right?

so this might apply:
Documentation/timers/timers-howto.txt
	- Why not msleep for (1ms - 20ms)?
		Explained originally here:
			http://lkml.org/lkml/2007/8/3/250
		msleep(1~20) may not do what the caller intends, and
		will often sleep longer (~20 ms actual sleep for any
		value given in the 1~20ms range). In many cases this
		is not the desired behavior.

Of course, that's of little importance.

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [RFC] firmware loader: retry _nowait requests when userhelper is not yet available
  2012-03-16 22:57       ` Rafael J. Wysocki
  2012-03-16 23:35         ` Christian Lamparter
@ 2012-03-16 23:37         ` Linus Torvalds
  2012-03-17  0:23           ` Rafael J. Wysocki
  2012-03-19 12:41           ` [RFC] firmware loader: retry _nowait requests when userhelper is not yet available James Courtier-Dutton
  1 sibling, 2 replies; 111+ messages in thread
From: Linus Torvalds @ 2012-03-16 23:37 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Christian Lamparter, Srivatsa S. Bhat, linux-kernel, gregkh,
	alan, Linux PM mailing list

On Fri, Mar 16, 2012 at 3:57 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> +       if (nowait) {
> +               int limit = loading_timeout * MSEC_PER_SEC;
> +               int timeout = 10;  /* in msec */
> +
> +               while (usermodehelper_is_disabled()) {
> +                       read_unlock_usermodehelper();
> +
> +                       msleep(timeout);

Ugh, this is disgusting.

The whole point of nowait was that it's not synchronous - so it should
just be driven by timers, not some kind of random "while sleep" loop.

And that fw thing already does have a timeout associated with it, and
quite frankly, the *sane* approach is to do all this not in
_request_firmware(), but in request_firmware_work_func() - never even
call _request_firmware() in the first place if the system isn't ready,
just reset the timeout to retry it again later.

Seriously. The rule should be really simple: nothing should *ever*
call "request_firmware()" (or the _request_firmware() helper function)
while the system is not up. That WARN_ON() should remain totally and
utterly unconditional, and it should *not* be conditional on "nowait"
or any idiotic crappy hack like that.

If there is an asynchronous thread - and there is, for the _nowait()
case - that asynchronous thread should set up the timer and retry in
ten seconds or whatever. It should *not* call 'request_firmware()" and
expect that to do something special.

                    Linus

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [RFC] firmware loader: retry _nowait requests when userhelper is not yet available
  2012-03-16 23:37         ` Linus Torvalds
@ 2012-03-17  0:23           ` Rafael J. Wysocki
  2012-03-17  0:33             ` Linus Torvalds
  2012-03-19 12:41           ` [RFC] firmware loader: retry _nowait requests when userhelper is not yet available James Courtier-Dutton
  1 sibling, 1 reply; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-17  0:23 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Christian Lamparter, Srivatsa S. Bhat, linux-kernel, gregkh,
	alan, Linux PM mailing list

On Saturday, March 17, 2012, Linus Torvalds wrote:
> On Fri, Mar 16, 2012 at 3:57 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> > +       if (nowait) {
> > +               int limit = loading_timeout * MSEC_PER_SEC;
> > +               int timeout = 10;  /* in msec */
> > +
> > +               while (usermodehelper_is_disabled()) {
> > +                       read_unlock_usermodehelper();
> > +
> > +                       msleep(timeout);
> 
> Ugh, this is disgusting.
> 
> The whole point of nowait was that it's not synchronous - so it should
> just be driven by timers, not some kind of random "while sleep" loop.
> 
> And that fw thing already does have a timeout associated with it, and
> quite frankly, the *sane* approach is to do all this not in
> _request_firmware(), but in request_firmware_work_func() - never even
> call _request_firmware() in the first place if the system isn't ready,
> just reset the timeout to retry it again later.
> 
> Seriously. The rule should be really simple: nothing should *ever*
> call "request_firmware()" (or the _request_firmware() helper function)
> while the system is not up. That WARN_ON() should remain totally and
> utterly unconditional, and it should *not* be conditional on "nowait"
> or any idiotic crappy hack like that.
> 
> If there is an asynchronous thread - and there is, for the _nowait()
> case - that asynchronous thread should set up the timer and retry in
> ten seconds or whatever. It should *not* call 'request_firmware()" and
> expect that to do something special.

OK, but that asynchronous thread needs to know whether or not the system is up.

It can use the usermodehelper_is_disabled() check, but that needs to be done
under read_lock_usermodehelper() and it can't release the lock before
calling _request_firmware(), or all that thing would be racy.  If it doesn't
release the lock, then _request_firmware() will take it again, reentrantly,
which isn't nice.  So, it looks like it has to use a different check.

I was pondering a suspend/resume notifier that would block either
request_firmware_work_func() (possibly with a timeout), if system suspend is
in progress, or system suspend, if _request_firmware() is in progress,
but that wouldn't cover the initialization case.

Thanks,
Rafael

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [RFC] firmware loader: retry _nowait requests when userhelper is not yet available
  2012-03-17  0:23           ` Rafael J. Wysocki
@ 2012-03-17  0:33             ` Linus Torvalds
  2012-03-18  0:29               ` Rafael J. Wysocki
  0 siblings, 1 reply; 111+ messages in thread
From: Linus Torvalds @ 2012-03-17  0:33 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Christian Lamparter, Srivatsa S. Bhat, linux-kernel, gregkh,
	alan, Linux PM mailing list

On Fri, Mar 16, 2012 at 5:23 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
>
> OK, but that asynchronous thread needs to know whether or not the system is up.

Sure.

> It can use the usermodehelper_is_disabled() check, but that needs to be done
> under read_lock_usermodehelper() and it can't release the lock before
> calling _request_firmware(), or all that thing would be racy.

Well, I think that it would actually be a good idea to perhaps split
up that existing _request_firmware() a bit. In fact, it might be good
to split up that whole "fw_create_instance()" too - and re-organize
the code a bit so that you end up creating the "firmware_priv" thing
first.

So maybe we could have a helper function that does that first part of
fw_create_instance() (the part that allocates it and does the
__module_get() part and other really basic initialization), and that
can be called unconditionally by the request_firmware_nowait() code
early.

That early part probably should *not* create the device attribute
files etc (although who knows - maybe sysfs is ok at this point).

So I think we really could re-organize the code to do a sane job - and
move just the actual udev setup etc to the final part that needs to be
delayed.

Hmm?

I haven't looked very deeply into it, but my *gut* feel is that it
should be doable pretty cleanly.

But yeah, it would be more than a little one-liner. I think it might
be worth it, though. Clearly separating out the three stages: "setup"
-> "wait for system to be ready" -> "do the actual load".

Then, the regular request_firmware() function would do exactly the
same things, except it would never do the "wait for system to be
ready" part: it would just fail with the warning if it wasn't already
ready. So they'd still share all the basic core code, it would just be
a slightly different organization from what it is now.

                 Linus

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-15  0:11                         ` Rafael J. Wysocki
  2012-03-15 19:50                           ` [PATCH] firmware_class: Move request_firmware_nowait() to workqueues Stephen Boyd
@ 2012-03-17  2:47                           ` Stephen Boyd
  2012-03-17  5:51                             ` Linus Torvalds
  1 sibling, 1 reply; 111+ messages in thread
From: Stephen Boyd @ 2012-03-17  2:47 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Saravana Kannan, Kay Sievers, Greg KH, Christian Lamparter,
	linux-kernel, Srivatsa S. Bhat, alan, Linus Torvalds,
	Linux PM mailing list

On 03/14/12 17:11, Rafael J. Wysocki wrote:
> On Thursday, March 15, 2012, Stephen Boyd wrote:
>> On 03/14/12 16:34, Rafael J. Wysocki wrote:
>>> On Thursday, March 15, 2012, Stephen Boyd wrote:
>>>> On 03/14/12 16:13, Rafael J. Wysocki wrote:
>>>>> On Thursday, March 15, 2012, Rafael J. Wysocki wrote:
>>>>>
>>>>>> Which is OK, I think.
>>>>> Moreover, thaw_kernel_threads() is _only_ called by (a) freeze_kernel_threads()
>>>>> on error and (b) user-space hibernate interface in kernel/power/user.c
>>>>> (and please read the comment in there describing what it's there for, which
>>>>> also explains why the schedule() call in there is necessary).
>>>> Exactly. So in case (a) when the error occurs we'll have this call flow:
>>>>
>>>> usermodehelpers_disable()
>>>> suspend_freeze_processes()
>>>>     freeze_processes()
>>>>     freeze_kernel_threads()
>>>>         try_to_freeze_tasks() <-- returns error
>>>>         thaw_kernel_threads()
>>>>             schedule()
>>>>     thaw_processes()
>>>> usermodehelpers_enable()
>>>>
>>>> Shouldn't we schedule only after we thaw all processes (not just tasks)?
>>>> Otherwise we may run a kernel thread before userspace is thawed?
>>> Yes, we may, but that isn't wrong, is it?
>>>
>>> Only a few kernel threads are freezable, so definitely kernel threads
>>> can run while user space is frozen.
>>>
>> Yes but if someone calls request_firmware() from a kthread then they
>> will hit the same problem where the thread runs and requests the
>> firmware and usermodehelpers are still disabled. Currently my code is
>> written with kthreads and that thread makes the request firmware call,
>> so this doesn't seem far fetched (although in my case I can probably fix
>> it).
> So again, please consider using suspend/resume notifiers to synchronize
> your kthread with system power transitions.

Ah. Freezable workqueues and threads are entirely not what I want. I
have to use suspend/resume notifiers so that I don't call
request_firmware() until suspend is over and I have to synchronize that
with a rwsem so that suspend is blocked until my call to
request_firmware() completes (and so request_firmware() is blocked until
suspend completes). Every user of request_firmware() has to do the same
check or be certain that their code won't run during a system-wide
suspend/resume.  Ouch.

Can we fix this in the core firmware loading code somehow? I really want
to have a way to differentiate between tasks that can block suspend from
progressing and tasks that won't. This way everyone who doesn't care
about suspend can still call request_firmware() and go to sleep if we're
in the middle of suspending and the ones who would block suspend get
failed immediately. That would seem to be more in line with why this
patch was made (i.e. don't block suspend/resume from progressing with
request_firmware() calls).

What about this? It basically keeps track of which task is the
suspending task and then only fails that one. I'm not completely sold on
this one but it would work most of the time.

---8<-----

diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 6c9387d..5127534 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -533,9 +533,7 @@ static int _request_firmware(const struct firmware **firmware_p,
 		return 0;
 	}
 
-	read_lock_usermodehelper();
-
-	if (WARN_ON(usermodehelper_is_disabled())) {
+	if (is_sleep_task()) {
 		dev_err(device, "firmware: %s will not be loaded\n", name);
 		retval = -EBUSY;
 		goto out;
@@ -550,6 +548,7 @@ static int _request_firmware(const struct firmware **firmware_p,
 		goto out;
 	}
 
+	read_lock_usermodehelper();
 	if (uevent) {
 		if (loading_timeout > 0)
 			mod_timer(&fw_priv->timeout,
@@ -560,6 +559,7 @@ static int _request_firmware(const struct firmware **firmware_p,
 	}
 
 	wait_for_completion(&fw_priv->completion);
+	read_unlock_usermodehelper();
 
 	set_bit(FW_STATUS_DONE, &fw_priv->status);
 	del_timer_sync(&fw_priv->timeout);
@@ -573,7 +573,6 @@ static int _request_firmware(const struct firmware **firmware_p,
 	fw_destroy_instance(fw_priv);
 
 out:
-	read_unlock_usermodehelper();
 
 	if (retval) {
 		release_firmware(firmware);
diff --git a/include/linux/kmod.h b/include/linux/kmod.h
index 9efeae6..d84da8c 100644
--- a/include/linux/kmod.h
+++ b/include/linux/kmod.h
@@ -115,6 +115,7 @@ extern void usermodehelper_init(void);
 extern int usermodehelper_disable(void);
 extern void usermodehelper_enable(void);
 extern bool usermodehelper_is_disabled(void);
+extern bool is_sleep_task(void);
 extern void read_lock_usermodehelper(void);
 extern void read_unlock_usermodehelper(void);
 
diff --git a/kernel/kmod.c b/kernel/kmod.c
index 9faa560..50fae27 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -368,6 +368,13 @@ void read_unlock_usermodehelper(void)
 }
 EXPORT_SYMBOL_GPL(read_unlock_usermodehelper);
 
+static struct task_struct *system_sleep_task;
+
+bool is_sleep_task(void)
+{
+	return current == system_sleep_task;
+}
+
 /**
  * usermodehelper_disable - prevent new helpers from being started
  */
@@ -375,9 +382,9 @@ int usermodehelper_disable(void)
 {
 	long retval;
 
+	system_sleep_task = current;
 	down_write(&umhelper_sem);
 	usermodehelper_disabled = 1;
-	up_write(&umhelper_sem);
 
 	/*
 	 * From now on call_usermodehelper_exec() won't start any new
@@ -391,9 +398,9 @@ int usermodehelper_disable(void)
 	if (retval)
 		return 0;
 
-	down_write(&umhelper_sem);
 	usermodehelper_disabled = 0;
 	up_write(&umhelper_sem);
+	system_sleep_task = NULL;
 	return -EAGAIN;
 }
 
@@ -402,9 +409,9 @@ int usermodehelper_disable(void)
  */
 void usermodehelper_enable(void)
 {
-	down_write(&umhelper_sem);
 	usermodehelper_disabled = 0;
 	up_write(&umhelper_sem);
+	system_sleep_task = NULL;
 }
 
 /**
-- 


Or maybe we should modify request_firmware_nowait() to have the suspend
notifier checks? Right now if I call request_firmware_nowait() from a
probe it just might happen to fail because the kthread could run before
resume is complete. I didn't call request_firmware(), so I really tried
not to block resume progress but I'm gambling that resume will be over
before my thread runs. I could write notifier rwsem code and then wait
for resume to finish before calling request_firmware_nowat(), but that
would require me to fork a thread/workqueue to run
request_firmware_nowait() which will then fork a thread again. Seems
useless to even use request_firmware_nowait() then.

How about this totally untested patch? We do the rwsem thing for
request_firmware_nowait() at least.
----8<-----

diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 6c9387d..f320ccd 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -20,6 +20,8 @@
 #include <linux/highmem.h>
 #include <linux/firmware.h>
 #include <linux/slab.h>
+#include <linux/suspend.h>
+#include <linux/rwsem.h>
 
 #define to_dev(obj) container_of(obj, struct device, kobj)
 
@@ -629,6 +631,9 @@ struct firmware_work {
 	bool uevent;
 };
 
+/* Synchronize request_firmware_work_func() with suspend */
+static DECLARE_RWSEM(fw_pm_rwsem);
+
 static int request_firmware_work_func(void *arg)
 {
 	struct firmware_work *fw_work = arg;
@@ -640,8 +645,10 @@ static int request_firmware_work_func(void *arg)
 		return 0;
 	}
 
+	down_read(&fw_pm_rwsem);
 	ret = _request_firmware(&fw, fw_work->name, fw_work->device,
 				fw_work->uevent, true);
+	up_read(&fw_pm_rwsem);
 	fw_work->cont(fw, fw_work->context);
 
 	module_put(fw_work->module);
@@ -704,13 +711,33 @@ request_firmware_nowait(
 	return 0;
 }
 
+static int firmware_class_pm_notify(struct notifier_block *block,
+		unsigned long event, void *p)
+{
+	switch (event) {
+	case PM_SUSPEND_PREPARE:
+		down_write(&fw_pm_rwsem);
+		break;
+	case PM_POST_SUSPEND:
+		up_write(&fw_pm_rwsem);
+		break;
+	}
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block firmware_class_pm_notifier = {
+	.notifier_call = firmware_class_pm_notify,
+};
+
 static int __init firmware_class_init(void)
 {
+	register_pm_notifier(&firmware_class_pm_notifier);
 	return class_register(&firmware_class);
 }
 
 static void __exit firmware_class_exit(void)
 {
+	unregister_pm_notifier(&firmware_class_pm_notifier);
 	class_unregister(&firmware_class);
 }
 
-- 


Hmm it seems something similar is going on in the other part of the
thread. I'll work something up in a few hours.

-- 
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.


^ permalink raw reply related	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-17  2:47                           ` [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available Stephen Boyd
@ 2012-03-17  5:51                             ` Linus Torvalds
  2012-03-17 20:06                               ` Rafael J. Wysocki
  2012-03-18  8:26                               ` Stephen Boyd
  0 siblings, 2 replies; 111+ messages in thread
From: Linus Torvalds @ 2012-03-17  5:51 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Rafael J. Wysocki, Saravana Kannan, Kay Sievers, Greg KH,
	Christian Lamparter, linux-kernel, Srivatsa S. Bhat, alan,
	Linux PM mailing list

On Fri, Mar 16, 2012 at 7:47 PM, Stephen Boyd <sboyd@codeaurora.org> wrote:
> -       if (WARN_ON(usermodehelper_is_disabled())) {
> +       if (is_sleep_task()) {
>                dev_err(device, "firmware: %s will not be loaded\n", name);

Stop these idiotic games already!

It's very simple: you cannot load firmware while the system is not
readt. Your moronic "let's change the test to something else" is
entirely and utterly misguided and totally misses the point.

It's not about sleeping, and it's not about anything even *remotely*
about that. Stop the idiocy already.

How hard is it to understand? How many times do people have to tell you?

That warning is very much valid during bootup, and that warning has
been *seen* during bootup. For example, try to compile in most
wireless drivers as non-modular, and that warning *has* to trigger.

Rafael, please consider everything along these *IDIOTIC* lines
completely NAK'ed. In fact, until Stephen starts showing any sign of
understanding that it's not about just some random small detail, just
ignore anything and everything from him.

Stephen, you've been told multiple times that that WARN_ON() is
correct. Until you understand that, just stop sending these entirely
random patches that change it to something completely wrong.

How hard can it be to understand that you cannot and must not load
firmware when the system isn't up-and-running.

And *dammit*, the fact that you send these kinds of completely
nonsensical patches that seem to think that "up-and-running" is just
about suspend (and not bootup, for example), all you are showing is
that you don't understand the problem. Stop, think, and read the
emails that have been in this thread and that have explained how it
*could* be solved.

Until you do that, any patch you send is just worthless. Really.

                     Linus

                              Linus

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-17  5:51                             ` Linus Torvalds
@ 2012-03-17 20:06                               ` Rafael J. Wysocki
  2012-03-18  8:26                               ` Stephen Boyd
  1 sibling, 0 replies; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-17 20:06 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Stephen Boyd, Saravana Kannan, Kay Sievers, Greg KH,
	Christian Lamparter, linux-kernel, Srivatsa S. Bhat, alan,
	Linux PM mailing list

On Saturday, March 17, 2012, Linus Torvalds wrote:
> On Fri, Mar 16, 2012 at 7:47 PM, Stephen Boyd <sboyd@codeaurora.org> wrote:
> > -       if (WARN_ON(usermodehelper_is_disabled())) {
> > +       if (is_sleep_task()) {
> >                dev_err(device, "firmware: %s will not be loaded\n", name);
> 
> Stop these idiotic games already!
> 
> It's very simple: you cannot load firmware while the system is not
> readt. Your moronic "let's change the test to something else" is
> entirely and utterly misguided and totally misses the point.
> 
> It's not about sleeping, and it's not about anything even *remotely*
> about that. Stop the idiocy already.
> 
> How hard is it to understand? How many times do people have to tell you?
> 
> That warning is very much valid during bootup, and that warning has
> been *seen* during bootup. For example, try to compile in most
> wireless drivers as non-modular, and that warning *has* to trigger.
> 
> Rafael, please consider everything along these *IDIOTIC* lines
> completely NAK'ed.

I will.

Thanks,
Rafael

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [RFC] firmware loader: retry _nowait requests when userhelper is not yet available
  2012-03-17  0:33             ` Linus Torvalds
@ 2012-03-18  0:29               ` Rafael J. Wysocki
  2012-03-18  2:21                 ` Linus Torvalds
  2012-03-18 12:43                 ` Christian Lamparter
  0 siblings, 2 replies; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-18  0:29 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Christian Lamparter, Srivatsa S. Bhat, linux-kernel, gregkh,
	alan, Linux PM mailing list

On Saturday, March 17, 2012, Linus Torvalds wrote:
> On Fri, Mar 16, 2012 at 5:23 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> >
> > OK, but that asynchronous thread needs to know whether or not the system is up.
> 
> Sure.
> 
> > It can use the usermodehelper_is_disabled() check, but that needs to be done
> > under read_lock_usermodehelper() and it can't release the lock before
> > calling _request_firmware(), or all that thing would be racy.
> 
> Well, I think that it would actually be a good idea to perhaps split
> up that existing _request_firmware() a bit. In fact, it might be good
> to split up that whole "fw_create_instance()" too - and re-organize
> the code a bit so that you end up creating the "firmware_priv" thing
> first.
> 
> So maybe we could have a helper function that does that first part of
> fw_create_instance() (the part that allocates it and does the
> __module_get() part and other really basic initialization), and that
> can be called unconditionally by the request_firmware_nowait() code
> early.
> 
> That early part probably should *not* create the device attribute
> files etc (although who knows - maybe sysfs is ok at this point).
> 
> So I think we really could re-organize the code to do a sane job - and
> move just the actual udev setup etc to the final part that needs to be
> delayed.
> 
> Hmm?
> 
> I haven't looked very deeply into it, but my *gut* feel is that it
> should be doable pretty cleanly.
> 
> But yeah, it would be more than a little one-liner. I think it might
> be worth it, though. Clearly separating out the three stages: "setup"
> -> "wait for system to be ready" -> "do the actual load".
> 
> Then, the regular request_firmware() function would do exactly the
> same things, except it would never do the "wait for system to be
> ready" part: it would just fail with the warning if it wasn't already
> ready. So they'd still share all the basic core code, it would just be
> a slightly different organization from what it is now.

The patch below (untested) goes slightly into that direction, although not as
far as to modify fw_create_instance().  It does, however, split
_request_firmware() into "prepare", "load" and "cleanup" parts and moves
the usermodehelper check along with the read-locking of umhelper_sem down
to the callers, ie. request_firmware() and request_firmware_work_func().

The difference between them is that request_firmware() fails immediately
with a WARN_ON() if it sees usermodehelper_disabled set after acquiring
umhelper_sem, while request_firmware_work_func() waits for
usermodehelper_disabled to be unset, with a timeout (the wait time is
subtracted from the _request_firmware() timeout).  The reason why
request_firmware_work_func() does it this way is that it can't wait for
usermodehelper_disabled to be unset with umhelper_sem held and it has to
call _request_firmware() under umhelper_sem (otherwise user space might be
frozen out from under it).

I'm falling asleep now, but hopefully the patch isn't totally busted. :-)
It should be split into a series of patches, though.

Thanks,
Rafael

---
 drivers/base/firmware_class.c |   98 +++++++++++++++++++++++++++---------------
 include/linux/kmod.h          |    6 +-
 kernel/kmod.c                 |   83 ++++++++++++++++++++++++-----------
 3 files changed, 124 insertions(+), 63 deletions(-)

Index: linux/kernel/kmod.c
===================================================================
--- linux.orig/kernel/kmod.c
+++ linux/kernel/kmod.c
@@ -291,22 +291,74 @@ static atomic_t running_helpers = ATOMIC
 static DECLARE_WAIT_QUEUE_HEAD(running_helpers_waitq);
 
 /*
+ * Used by usermodehelper_read_lock_wait() to wait for usermodehelper_disabled
+ * to become 'false'.
+ */
+static DECLARE_WAIT_QUEUE_HEAD(usermodehelper_disabled_waitq);
+
+/*
  * Time to wait for running_helpers to become zero before the setting of
  * usermodehelper_disabled in usermodehelper_disable() fails
  */
 #define RUNNING_HELPERS_TIMEOUT	(5 * HZ)
 
-void read_lock_usermodehelper(void)
+int usermodehelper_read_trylock(void)
+{
+	int ret = 0;
+
+	down_read(&umhelper_sem);
+	if (usermodehelper_disabled) {
+		up_read(&umhelper_sem);
+		ret = -EAGAIN;
+	}
+	return ret;
+}
+EXPORT_SYMBOL_GPL(usermodehelper_read_trylock);
+
+long usermodehelper_read_lock_wait(long timeout)
 {
+	DEFINE_WAIT(wait);
+	long ret = timeout;
+
+	if (timeout < 0)
+		return -EINVAL;
+
 	down_read(&umhelper_sem);
+	for (;;) {
+		prepare_to_wait(&usermodehelper_disabled_waitq, &wait,
+				TASK_UNINTERRUPTIBLE);
+		if (!usermodehelper_disabled)
+			break;
+
+		up_read(&umhelper_sem);
+
+		ret = schedule_timeout(timeout);
+		if (!ret)
+			break;
+
+		down_read(&umhelper_sem);
+	}
+	finish_wait(&usermodehelper_disabled_waitq, &wait);
+	return ret;
 }
-EXPORT_SYMBOL_GPL(read_lock_usermodehelper);
+EXPORT_SYMBOL_GPL(usermodehelper_read_lock_wait);
 
-void read_unlock_usermodehelper(void)
+void usermodehelper_read_unlock(void)
 {
 	up_read(&umhelper_sem);
 }
-EXPORT_SYMBOL_GPL(read_unlock_usermodehelper);
+EXPORT_SYMBOL_GPL(usermodehelper_read_unlock);
+
+/**
+ * usermodehelper_enable - allow new helpers to be started again
+ */
+void usermodehelper_enable(void)
+{
+	down_write(&umhelper_sem);
+	usermodehelper_disabled = 0;
+	wake_up(&usermodehelper_disabled_waitq);
+	up_write(&umhelper_sem);
+}
 
 /**
  * usermodehelper_disable - prevent new helpers from being started
@@ -331,31 +383,10 @@ int usermodehelper_disable(void)
 	if (retval)
 		return 0;
 
-	down_write(&umhelper_sem);
-	usermodehelper_disabled = 0;
-	up_write(&umhelper_sem);
+	usermodehelper_enable();
 	return -EAGAIN;
 }
 
-/**
- * usermodehelper_enable - allow new helpers to be started again
- */
-void usermodehelper_enable(void)
-{
-	down_write(&umhelper_sem);
-	usermodehelper_disabled = 0;
-	up_write(&umhelper_sem);
-}
-
-/**
- * usermodehelper_is_disabled - check if new helpers are allowed to be started
- */
-bool usermodehelper_is_disabled(void)
-{
-	return usermodehelper_disabled;
-}
-EXPORT_SYMBOL_GPL(usermodehelper_is_disabled);
-
 static void helper_lock(void)
 {
 	atomic_inc(&running_helpers);
Index: linux/include/linux/kmod.h
===================================================================
--- linux.orig/include/linux/kmod.h
+++ linux/include/linux/kmod.h
@@ -116,8 +116,8 @@ extern void usermodehelper_init(void);
 
 extern int usermodehelper_disable(void);
 extern void usermodehelper_enable(void);
-extern bool usermodehelper_is_disabled(void);
-extern void read_lock_usermodehelper(void);
-extern void read_unlock_usermodehelper(void);
+extern int usermodehelper_read_trylock(void);
+extern long usermodehelper_read_lock_wait(long timeout);
+extern void usermodehelper_read_unlock(void);
 
 #endif /* __LINUX_KMOD_H__ */
Index: linux/drivers/base/firmware_class.c
===================================================================
--- linux.orig/drivers/base/firmware_class.c
+++ linux/drivers/base/firmware_class.c
@@ -435,7 +435,7 @@ static void firmware_class_timeout(u_lon
 }
 
 static struct firmware_priv *
-fw_create_instance(struct firmware *firmware, const char *fw_name,
+fw_create_instance(const struct firmware *firmware, const char *fw_name,
 		   struct device *device, bool uevent, bool nowait)
 {
 	struct firmware_priv *fw_priv;
@@ -449,7 +449,7 @@ fw_create_instance(struct firmware *firm
 		goto err_out;
 	}
 
-	fw_priv->fw = firmware;
+	fw_priv->fw = (struct firmware *)firmware;
 	fw_priv->nowait = nowait;
 	strcpy(fw_priv->fw_id, fw_name);
 	init_completion(&fw_priv->completion);
@@ -510,16 +510,10 @@ static void fw_destroy_instance(struct f
 	device_unregister(f_dev);
 }
 
-static int _request_firmware(const struct firmware **firmware_p,
-			     const char *name, struct device *device,
-			     bool uevent, bool nowait)
+static int _request_firmware_prepare(const struct firmware **firmware_p,
+				     const char *name, struct device *device)
 {
-	struct firmware_priv *fw_priv;
 	struct firmware *firmware;
-	int retval = 0;
-
-	if (!firmware_p)
-		return -EINVAL;
 
 	*firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL);
 	if (!firmware) {
@@ -533,28 +527,33 @@ static int _request_firmware(const struc
 		return 0;
 	}
 
-	read_lock_usermodehelper();
+	return 1;
+}
 
-	if (WARN_ON(usermodehelper_is_disabled())) {
-		dev_err(device, "firmware: %s will not be loaded\n", name);
-		retval = -EBUSY;
-		goto out;
-	}
+static void _request_firmware_cleanup(const struct firmware **firmware_p)
+{
+	release_firmware(*firmware_p);
+	*firmware_p = NULL;
+}
+
+static int _request_firmware(const struct firmware *firmware,
+			     const char *name, struct device *device,
+			     bool uevent, bool nowait, long timeout)
+{
+	struct firmware_priv *fw_priv;
+	int retval = 0;
 
 	if (uevent)
 		dev_dbg(device, "firmware: requesting %s\n", name);
 
 	fw_priv = fw_create_instance(firmware, name, device, uevent, nowait);
-	if (IS_ERR(fw_priv)) {
-		retval = PTR_ERR(fw_priv);
-		goto out;
-	}
+	if (IS_ERR(fw_priv))
+		return PTR_ERR(fw_priv);
 
 	if (uevent) {
-		if (loading_timeout > 0)
+		if (timeout > 0)
 			mod_timer(&fw_priv->timeout,
-				  round_jiffies_up(jiffies +
-						   loading_timeout * HZ));
+				  round_jiffies_up(jiffies + timeout));
 
 		kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD);
 	}
@@ -572,14 +571,6 @@ static int _request_firmware(const struc
 
 	fw_destroy_instance(fw_priv);
 
-out:
-	read_unlock_usermodehelper();
-
-	if (retval) {
-		release_firmware(firmware);
-		*firmware_p = NULL;
-	}
-
 	return retval;
 }
 
@@ -602,7 +593,24 @@ int
 request_firmware(const struct firmware **firmware_p, const char *name,
                  struct device *device)
 {
-        return _request_firmware(firmware_p, name, device, true, false);
+	int ret;
+
+	ret = _request_firmware_prepare(firmware_p, name, device);
+	if (ret <= 0)
+		return ret;
+
+	ret = usermodehelper_read_trylock();
+	if (WARN_ON(ret)) {
+		dev_err(device, "firmware: %s will not be loaded\n", name);
+	} else {
+		ret = _request_firmware(*firmware_p, name, device, true, false,
+					loading_timeout * HZ);
+		usermodehelper_read_unlock();
+	}
+	if (ret)
+		_request_firmware_cleanup(firmware_p);
+
+	return ret;
 }
 
 /**
@@ -633,6 +641,7 @@ static int request_firmware_work_func(vo
 {
 	struct firmware_work *fw_work = arg;
 	const struct firmware *fw;
+	long timeout;
 	int ret;
 
 	if (!arg) {
@@ -640,8 +649,29 @@ static int request_firmware_work_func(vo
 		return 0;
 	}
 
-	ret = _request_firmware(&fw, fw_work->name, fw_work->device,
-				fw_work->uevent, true);
+	ret = _request_firmware_prepare(&fw, fw_work->name, fw_work->device);
+	if (ret <= 0)
+		return ret;
+
+	if (loading_timeout) {
+		timeout = usermodehelper_read_lock_wait(loading_timeout * HZ);
+		if (timeout <= 0)
+			ret = -EAGAIN;
+	} else {
+		usermodehelper_read_lock_wait(MAX_SCHEDULE_TIMEOUT);
+		timeout = 0;
+	}
+	if (ret > 0) {
+		ret = _request_firmware(fw, fw_work->name, fw_work->device,
+					fw_work->uevent, true, timeout);
+		usermodehelper_read_unlock();
+	} else {
+		dev_dbg(fw_work->device, "firmware: %s loading timed out\n",
+			fw_work->name);
+	}
+	if (ret)
+		_request_firmware_cleanup(&fw);
+
 	fw_work->cont(fw, fw_work->context);
 
 	module_put(fw_work->module);

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [RFC] firmware loader: retry _nowait requests when userhelper is not yet available
  2012-03-18  0:29               ` Rafael J. Wysocki
@ 2012-03-18  2:21                 ` Linus Torvalds
  2012-03-18 12:21                   ` Rafael J. Wysocki
  2012-03-18 12:43                 ` Christian Lamparter
  1 sibling, 1 reply; 111+ messages in thread
From: Linus Torvalds @ 2012-03-18  2:21 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Christian Lamparter, Srivatsa S. Bhat, linux-kernel, gregkh,
	alan, Linux PM mailing list

On Sat, Mar 17, 2012 at 5:29 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
>
> The patch below (untested) goes slightly into that direction, although not as
> far as to modify fw_create_instance().  It does, however, split
> _request_firmware() into "prepare", "load" and "cleanup" parts and moves
> the usermodehelper check along with the read-locking of umhelper_sem down
> to the callers, ie. request_firmware() and request_firmware_work_func().

Looks fairly reasonable to me from a quick read-through, and the code
seems to make sense.

                 Linus

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-17  5:51                             ` Linus Torvalds
  2012-03-17 20:06                               ` Rafael J. Wysocki
@ 2012-03-18  8:26                               ` Stephen Boyd
  2012-03-18 12:01                                 ` Rafael J. Wysocki
  1 sibling, 1 reply; 111+ messages in thread
From: Stephen Boyd @ 2012-03-18  8:26 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Rafael J. Wysocki, Saravana Kannan, Kay Sievers, Greg KH,
	Christian Lamparter, linux-kernel, Srivatsa S. Bhat, alan,
	Linux PM mailing list

On 3/16/2012 10:51 PM, Linus Torvalds wrote:
> On Fri, Mar 16, 2012 at 7:47 PM, Stephen Boyd <sboyd@codeaurora.org> wrote:
>> -       if (WARN_ON(usermodehelper_is_disabled())) {
>> +       if (is_sleep_task()) {
>>                dev_err(device, "firmware: %s will not be loaded\n", name);
> Stop these idiotic games already!
>
> It's very simple: you cannot load firmware while the system is not
> readt. Your moronic "let's change the test to something else" is
> entirely and utterly misguided and totally misses the point.
>
> It's not about sleeping, and it's not about anything even *remotely*
> about that. Stop the idiocy already.
>
> How hard is it to understand? How many times do people have to tell you?
>
> That warning is very much valid during bootup, and that warning has
> been *seen* during bootup. For example, try to compile in most
> wireless drivers as non-modular, and that warning *has* to trigger.

Ok. I like where nowait() is going in the other part of the thread but
I'm still confused about when request_firmware() is correct to use. It
seems that the function is inherently racy with freezing. Does every
user of request_firmware() need to synchronize with freezing?

For example, if one CPU is in the middle of a driver probe that makes a
request_firmware() call and another CPU is starting to suspend we will
have a race between usermodehelpers being disabled and the
request_firmware() call acquiring the usermodehelper rwsem. If the
suspending CPU wins the race it will disable usermodehelpers and the
request_firmware() call will return -EBUSY and warn.

CPU0                           CPU1
driver_probe()                 suspend_prepare()
  ...                            usermodehelper_disable()
  _request_firmware()              down_write(&umhelper_sem)
                                   usermodehelper_disabled = 1
                                   up_write(&umhelper_sem)
    down_read(&umhelper_sem)       ....
    WARN_ON(...)                   freeze_processes()
    <freeze>                       


Hopefully I'm missing something here? This is all theoretical right now
as I haven't actually seen any of this in practice.

-- 
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.


^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-18  8:26                               ` Stephen Boyd
@ 2012-03-18 12:01                                 ` Rafael J. Wysocki
  2012-03-19  6:32                                   ` Stephen Boyd
  0 siblings, 1 reply; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-18 12:01 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Linus Torvalds, Saravana Kannan, Kay Sievers, Greg KH,
	Christian Lamparter, linux-kernel, Srivatsa S. Bhat, alan,
	Linux PM mailing list

On Sunday, March 18, 2012, Stephen Boyd wrote:
> On 3/16/2012 10:51 PM, Linus Torvalds wrote:
> > On Fri, Mar 16, 2012 at 7:47 PM, Stephen Boyd <sboyd@codeaurora.org> wrote:
> >> -       if (WARN_ON(usermodehelper_is_disabled())) {
> >> +       if (is_sleep_task()) {
> >>                dev_err(device, "firmware: %s will not be loaded\n", name);
> > Stop these idiotic games already!
> >
> > It's very simple: you cannot load firmware while the system is not
> > readt. Your moronic "let's change the test to something else" is
> > entirely and utterly misguided and totally misses the point.
> >
> > It's not about sleeping, and it's not about anything even *remotely*
> > about that. Stop the idiocy already.
> >
> > How hard is it to understand? How many times do people have to tell you?
> >
> > That warning is very much valid during bootup, and that warning has
> > been *seen* during bootup. For example, try to compile in most
> > wireless drivers as non-modular, and that warning *has* to trigger.
> 
> Ok. I like where nowait() is going in the other part of the thread but
> I'm still confused about when request_firmware() is correct to use. It
> seems that the function is inherently racy with freezing. Does every
> user of request_firmware() need to synchronize with freezing?
> 
> For example, if one CPU is in the middle of a driver probe that makes a
> request_firmware() call and another CPU is starting to suspend we will
> have a race between usermodehelpers being disabled and the
> request_firmware() call acquiring the usermodehelper rwsem. If the
> suspending CPU wins the race it will disable usermodehelpers and the
> request_firmware() call will return -EBUSY and warn.

Yes, it will.

Thanks,
Rafael

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [RFC] firmware loader: retry _nowait requests when userhelper is not yet available
  2012-03-18  2:21                 ` Linus Torvalds
@ 2012-03-18 12:21                   ` Rafael J. Wysocki
  0 siblings, 0 replies; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-18 12:21 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Christian Lamparter, Srivatsa S. Bhat, linux-kernel, gregkh,
	alan, Linux PM mailing list

On Sunday, March 18, 2012, Linus Torvalds wrote:
> On Sat, Mar 17, 2012 at 5:29 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> >
> > The patch below (untested) goes slightly into that direction, although not as
> > far as to modify fw_create_instance().  It does, however, split
> > _request_firmware() into "prepare", "load" and "cleanup" parts and moves
> > the usermodehelper check along with the read-locking of umhelper_sem down
> > to the callers, ie. request_firmware() and request_firmware_work_func().
> 
> Looks fairly reasonable to me from a quick read-through, and the code
> seems to make sense.

Thanks!

I'll split it into a series of patches, then, and post for testing.

Rafael

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [RFC] firmware loader: retry _nowait requests when userhelper is not yet available
  2012-03-18  0:29               ` Rafael J. Wysocki
  2012-03-18  2:21                 ` Linus Torvalds
@ 2012-03-18 12:43                 ` Christian Lamparter
  2012-03-18 23:15                   ` [PATCH 0/3] firmware_class: Fix problem with async requests (was: Re: [RFC] firmware loader: retry ...) Rafael J. Wysocki
  1 sibling, 1 reply; 111+ messages in thread
From: Christian Lamparter @ 2012-03-18 12:43 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Linus Torvalds, Srivatsa S. Bhat, linux-kernel, gregkh, alan,
	Linux PM mailing list

On Sunday 18 March 2012 01:29:38 Rafael J. Wysocki wrote:
> The patch below (untested) goes slightly into that direction, although not as
> far as to modify fw_create_instance().  It does, however, split
> _request_firmware() into "prepare", "load" and "cleanup" parts and moves
> the usermodehelper check along with the read-locking of umhelper_sem down
> to the callers, ie. request_firmware() and request_firmware_work_func().
> 
> The difference between them is that request_firmware() fails immediately
> with a WARN_ON() if it sees usermodehelper_disabled set after acquiring
> umhelper_sem, while request_firmware_work_func() waits for
> usermodehelper_disabled to be unset, with a timeout (the wait time is
> subtracted from the _request_firmware() timeout).  The reason why
> request_firmware_work_func() does it this way is that it can't wait for
> usermodehelper_disabled to be unset with umhelper_sem held and it has to
> call _request_firmware() under umhelper_sem (otherwise user space might be
> frozen out from under it).
> 
> I'm falling asleep now, but hopefully the patch isn't totally busted. :-)
> It should be split into a series of patches, though.
I'm happy to report that my test system [with the patch applied] suspended
and resumed without any incidents.

Regards,
	Christian

^ permalink raw reply	[flat|nested] 111+ messages in thread

* [PATCH 0/3] firmware_class: Fix problem with async requests (was: Re: [RFC] firmware loader: retry ...)
  2012-03-18 12:43                 ` Christian Lamparter
@ 2012-03-18 23:15                   ` Rafael J. Wysocki
  2012-03-18 23:17                     ` [PATCH 1/3] firmware_class: Rework usermodehelper check Rafael J. Wysocki
                                       ` (2 more replies)
  0 siblings, 3 replies; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-18 23:15 UTC (permalink / raw)
  To: Christian Lamparter
  Cc: Linus Torvalds, Srivatsa S. Bhat, linux-kernel, gregkh, alan,
	Linux PM mailing list

On Sunday, March 18, 2012, Christian Lamparter wrote:
> On Sunday 18 March 2012 01:29:38 Rafael J. Wysocki wrote:
> > The patch below (untested) goes slightly into that direction, although not as
> > far as to modify fw_create_instance().  It does, however, split
> > _request_firmware() into "prepare", "load" and "cleanup" parts and moves
> > the usermodehelper check along with the read-locking of umhelper_sem down
> > to the callers, ie. request_firmware() and request_firmware_work_func().
> > 
> > The difference between them is that request_firmware() fails immediately
> > with a WARN_ON() if it sees usermodehelper_disabled set after acquiring
> > umhelper_sem, while request_firmware_work_func() waits for
> > usermodehelper_disabled to be unset, with a timeout (the wait time is
> > subtracted from the _request_firmware() timeout).  The reason why
> > request_firmware_work_func() does it this way is that it can't wait for
> > usermodehelper_disabled to be unset with umhelper_sem held and it has to
> > call _request_firmware() under umhelper_sem (otherwise user space might be
> > frozen out from under it).
> > 
> > I'm falling asleep now, but hopefully the patch isn't totally busted. :-)
> > It should be split into a series of patches, though.
> I'm happy to report that my test system [with the patch applied] suspended
> and resumed without any incidents.

Thanks for testing!

The following three patches should result in analogous code, although slightly
cleaned up.

Thanks,
Rafael


^ permalink raw reply	[flat|nested] 111+ messages in thread

* [PATCH 1/3] firmware_class: Rework usermodehelper check
  2012-03-18 23:15                   ` [PATCH 0/3] firmware_class: Fix problem with async requests (was: Re: [RFC] firmware loader: retry ...) Rafael J. Wysocki
@ 2012-03-18 23:17                     ` Rafael J. Wysocki
  2012-03-18 23:18                     ` [PATCH 2/3] firmware_class: Split _request_firmware() into three functions Rafael J. Wysocki
  2012-03-18 23:21                     ` [PATCH 3/3] firmware_class: Do not warn that system is not ready for async loads Rafael J. Wysocki
  2 siblings, 0 replies; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-18 23:17 UTC (permalink / raw)
  To: Christian Lamparter
  Cc: Linus Torvalds, Srivatsa S. Bhat, linux-kernel, gregkh, alan,
	Linux PM mailing list

From: Rafael J. Wysocki <rjw@sisk.pl>

Instead of two functions, read_lock_usermodehelper() and
usermodehelper_is_disabled(), used in combination, introduce
usermodehelper_read_trylock() that will only return with umhelper_sem
held if usermodehelper_disabled is unset (and will return -EAGAIN
otherwise) and make _request_firmware() use it.

Rename read_unlock_usermodehelper() to
usermodehelper_read_unlock() to follow the naming convention of the
new function.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 drivers/base/firmware_class.c |   11 +++++------
 include/linux/kmod.h          |    5 ++---
 kernel/kmod.c                 |   24 +++++++++++-------------
 3 files changed, 18 insertions(+), 22 deletions(-)

Index: linux/include/linux/kmod.h
===================================================================
--- linux.orig/include/linux/kmod.h
+++ linux/include/linux/kmod.h
@@ -116,8 +116,7 @@ extern void usermodehelper_init(void);
 
 extern int usermodehelper_disable(void);
 extern void usermodehelper_enable(void);
-extern bool usermodehelper_is_disabled(void);
-extern void read_lock_usermodehelper(void);
-extern void read_unlock_usermodehelper(void);
+extern int usermodehelper_read_trylock(void);
+extern void usermodehelper_read_unlock(void);
 
 #endif /* __LINUX_KMOD_H__ */
Index: linux/kernel/kmod.c
===================================================================
--- linux.orig/kernel/kmod.c
+++ linux/kernel/kmod.c
@@ -296,17 +296,24 @@ static DECLARE_WAIT_QUEUE_HEAD(running_h
  */
 #define RUNNING_HELPERS_TIMEOUT	(5 * HZ)
 
-void read_lock_usermodehelper(void)
+int usermodehelper_read_trylock(void)
 {
+	int ret = 0;
+
 	down_read(&umhelper_sem);
+	if (usermodehelper_disabled) {
+		up_read(&umhelper_sem);
+		ret = -EAGAIN;
+	}
+	return ret;
 }
-EXPORT_SYMBOL_GPL(read_lock_usermodehelper);
+EXPORT_SYMBOL_GPL(usermodehelper_read_trylock);
 
-void read_unlock_usermodehelper(void)
+void usermodehelper_read_unlock(void)
 {
 	up_read(&umhelper_sem);
 }
-EXPORT_SYMBOL_GPL(read_unlock_usermodehelper);
+EXPORT_SYMBOL_GPL(usermodehelper_read_unlock);
 
 /**
  * usermodehelper_disable - prevent new helpers from being started
@@ -347,15 +354,6 @@ void usermodehelper_enable(void)
 	up_write(&umhelper_sem);
 }
 
-/**
- * usermodehelper_is_disabled - check if new helpers are allowed to be started
- */
-bool usermodehelper_is_disabled(void)
-{
-	return usermodehelper_disabled;
-}
-EXPORT_SYMBOL_GPL(usermodehelper_is_disabled);
-
 static void helper_lock(void)
 {
 	atomic_inc(&running_helpers);
Index: linux/drivers/base/firmware_class.c
===================================================================
--- linux.orig/drivers/base/firmware_class.c
+++ linux/drivers/base/firmware_class.c
@@ -533,12 +533,10 @@ static int _request_firmware(const struc
 		return 0;
 	}
 
-	read_lock_usermodehelper();
-
-	if (WARN_ON(usermodehelper_is_disabled())) {
+	retval = usermodehelper_read_trylock();
+	if (WARN_ON(retval)) {
 		dev_err(device, "firmware: %s will not be loaded\n", name);
-		retval = -EBUSY;
-		goto out;
+		goto out_nolock;
 	}
 
 	if (uevent)
@@ -573,8 +571,9 @@ static int _request_firmware(const struc
 	fw_destroy_instance(fw_priv);
 
 out:
-	read_unlock_usermodehelper();
+	usermodehelper_read_unlock();
 
+out_nolock:
 	if (retval) {
 		release_firmware(firmware);
 		*firmware_p = NULL;


^ permalink raw reply	[flat|nested] 111+ messages in thread

* [PATCH 2/3] firmware_class: Split _request_firmware() into three functions
  2012-03-18 23:15                   ` [PATCH 0/3] firmware_class: Fix problem with async requests (was: Re: [RFC] firmware loader: retry ...) Rafael J. Wysocki
  2012-03-18 23:17                     ` [PATCH 1/3] firmware_class: Rework usermodehelper check Rafael J. Wysocki
@ 2012-03-18 23:18                     ` Rafael J. Wysocki
  2012-03-18 23:21                     ` [PATCH 3/3] firmware_class: Do not warn that system is not ready for async loads Rafael J. Wysocki
  2 siblings, 0 replies; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-18 23:18 UTC (permalink / raw)
  To: Christian Lamparter
  Cc: Linus Torvalds, Srivatsa S. Bhat, linux-kernel, gregkh, alan,
	Linux PM mailing list

From: Rafael J. Wysocki <rjw@sisk.pl>

Split _request_firmware() into three functions,
_request_firmware_prepare() doing preparatory work that need not be
done under umhelper_sem, _request_firmware_cleanup() doing the
post-error cleanup and _request_firmware() carrying out the remaining
operations.

This change is requisite for moving the acquisition of umhelper_sem
from _request_firmware() to the callers, which is going to be done
subsequently.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 drivers/base/firmware_class.c |   57 +++++++++++++++++++++++++++++-------------
 1 file changed, 40 insertions(+), 17 deletions(-)

Index: linux/drivers/base/firmware_class.c
===================================================================
--- linux.orig/drivers/base/firmware_class.c
+++ linux/drivers/base/firmware_class.c
@@ -435,7 +435,7 @@ static void firmware_class_timeout(u_lon
 }
 
 static struct firmware_priv *
-fw_create_instance(struct firmware *firmware, const char *fw_name,
+fw_create_instance(const struct firmware *firmware, const char *fw_name,
 		   struct device *device, bool uevent, bool nowait)
 {
 	struct firmware_priv *fw_priv;
@@ -449,7 +449,7 @@ fw_create_instance(struct firmware *firm
 		goto err_out;
 	}
 
-	fw_priv->fw = firmware;
+	fw_priv->fw = (struct firmware *)firmware;
 	fw_priv->nowait = nowait;
 	strcpy(fw_priv->fw_id, fw_name);
 	init_completion(&fw_priv->completion);
@@ -510,13 +510,10 @@ static void fw_destroy_instance(struct f
 	device_unregister(f_dev);
 }
 
-static int _request_firmware(const struct firmware **firmware_p,
-			     const char *name, struct device *device,
-			     bool uevent, bool nowait)
+static int _request_firmware_prepare(const struct firmware **firmware_p,
+				     const char *name, struct device *device)
 {
-	struct firmware_priv *fw_priv;
 	struct firmware *firmware;
-	int retval = 0;
 
 	if (!firmware_p)
 		return -EINVAL;
@@ -533,10 +530,26 @@ static int _request_firmware(const struc
 		return 0;
 	}
 
+	return 1;
+}
+
+static void _request_firmware_cleanup(const struct firmware **firmware_p)
+{
+	release_firmware(*firmware_p);
+	*firmware_p = NULL;
+}
+
+static int _request_firmware(const struct firmware *firmware,
+			     const char *name, struct device *device,
+			     bool uevent, bool nowait)
+{
+	struct firmware_priv *fw_priv;
+	int retval;
+
 	retval = usermodehelper_read_trylock();
 	if (WARN_ON(retval)) {
 		dev_err(device, "firmware: %s will not be loaded\n", name);
-		goto out_nolock;
+		return retval;
 	}
 
 	if (uevent)
@@ -572,13 +585,6 @@ static int _request_firmware(const struc
 
 out:
 	usermodehelper_read_unlock();
-
-out_nolock:
-	if (retval) {
-		release_firmware(firmware);
-		*firmware_p = NULL;
-	}
-
 	return retval;
 }
 
@@ -601,7 +607,17 @@ int
 request_firmware(const struct firmware **firmware_p, const char *name,
                  struct device *device)
 {
-        return _request_firmware(firmware_p, name, device, true, false);
+	int ret;
+
+	ret = _request_firmware_prepare(firmware_p, name, device);
+	if (ret <= 0)
+		return ret;
+
+	ret = _request_firmware(*firmware_p, name, device, true, false);
+	if (ret)
+		_request_firmware_cleanup(firmware_p);
+
+	return ret;
 }
 
 /**
@@ -639,8 +655,15 @@ static int request_firmware_work_func(vo
 		return 0;
 	}
 
-	ret = _request_firmware(&fw, fw_work->name, fw_work->device,
+	ret = _request_firmware_prepare(&fw, fw_work->name, fw_work->device);
+	if (ret <= 0)
+		return ret;
+
+	ret = _request_firmware(fw, fw_work->name, fw_work->device,
 				fw_work->uevent, true);
+	if (ret)
+		_request_firmware_cleanup(&fw);
+
 	fw_work->cont(fw, fw_work->context);
 
 	module_put(fw_work->module);


^ permalink raw reply	[flat|nested] 111+ messages in thread

* [PATCH 3/3] firmware_class: Do not warn that system is not ready for async loads
  2012-03-18 23:15                   ` [PATCH 0/3] firmware_class: Fix problem with async requests (was: Re: [RFC] firmware loader: retry ...) Rafael J. Wysocki
  2012-03-18 23:17                     ` [PATCH 1/3] firmware_class: Rework usermodehelper check Rafael J. Wysocki
  2012-03-18 23:18                     ` [PATCH 2/3] firmware_class: Split _request_firmware() into three functions Rafael J. Wysocki
@ 2012-03-18 23:21                     ` Rafael J. Wysocki
  2 siblings, 0 replies; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-18 23:21 UTC (permalink / raw)
  To: Christian Lamparter
  Cc: Linus Torvalds, Srivatsa S. Bhat, linux-kernel, gregkh, alan,
	Linux PM mailing list

From: Rafael J. Wysocki <rjw@sisk.pl>

If firmware is requested asynchronously, by calling
request_firmware_nowait(), there is no reason to fail the request
(and warn the user) when the system is (presumably temporarily)
unready for handling it (because user space is not available yet or
frozen).  For this reason, introduce an alternative routine for
read-locking umhelper_sem, usermodehelper_read_lock_wait(), that
will wait for usermodehelper_disabled to be unset (possibly with
a timeout) and make request_firmware_work_func() use it instead of
usermodehelper_read_trylock().

Accordingly, modify request_firmware() so that it uses
usermodehelper_read_trylock() to acquire umhelper_sem and remove
the code related to that lock from _request_firmware().

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 drivers/base/firmware_class.c |   51 +++++++++++++++++++++---------------
 include/linux/kmod.h          |    1 
 kernel/kmod.c                 |   59 ++++++++++++++++++++++++++++++++----------
 3 files changed, 77 insertions(+), 34 deletions(-)

Index: linux/include/linux/kmod.h
===================================================================
--- linux.orig/include/linux/kmod.h
+++ linux/include/linux/kmod.h
@@ -117,6 +117,7 @@ extern void usermodehelper_init(void);
 extern int usermodehelper_disable(void);
 extern void usermodehelper_enable(void);
 extern int usermodehelper_read_trylock(void);
+extern long usermodehelper_read_lock_wait(long timeout);
 extern void usermodehelper_read_unlock(void);
 
 #endif /* __LINUX_KMOD_H__ */
Index: linux/kernel/kmod.c
===================================================================
--- linux.orig/kernel/kmod.c
+++ linux/kernel/kmod.c
@@ -291,6 +291,12 @@ static atomic_t running_helpers = ATOMIC
 static DECLARE_WAIT_QUEUE_HEAD(running_helpers_waitq);
 
 /*
+ * Used by usermodehelper_read_lock_wait() to wait for usermodehelper_disabled
+ * to become 'false'.
+ */
+static DECLARE_WAIT_QUEUE_HEAD(usermodehelper_disabled_waitq);
+
+/*
  * Time to wait for running_helpers to become zero before the setting of
  * usermodehelper_disabled in usermodehelper_disable() fails
  */
@@ -309,6 +315,34 @@ int usermodehelper_read_trylock(void)
 }
 EXPORT_SYMBOL_GPL(usermodehelper_read_trylock);
 
+long usermodehelper_read_lock_wait(long timeout)
+{
+	DEFINE_WAIT(wait);
+	long ret = timeout;
+
+	if (timeout < 0)
+		return -EINVAL;
+
+	down_read(&umhelper_sem);
+	for (;;) {
+		prepare_to_wait(&usermodehelper_disabled_waitq, &wait,
+				TASK_UNINTERRUPTIBLE);
+		if (!usermodehelper_disabled)
+			break;
+
+		up_read(&umhelper_sem);
+
+		ret = schedule_timeout(timeout);
+		if (!ret)
+			break;
+
+		down_read(&umhelper_sem);
+	}
+	finish_wait(&usermodehelper_disabled_waitq, &wait);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(usermodehelper_read_lock_wait);
+
 void usermodehelper_read_unlock(void)
 {
 	up_read(&umhelper_sem);
@@ -316,6 +350,17 @@ void usermodehelper_read_unlock(void)
 EXPORT_SYMBOL_GPL(usermodehelper_read_unlock);
 
 /**
+ * usermodehelper_enable - allow new helpers to be started again
+ */
+void usermodehelper_enable(void)
+{
+	down_write(&umhelper_sem);
+	usermodehelper_disabled = 0;
+	wake_up(&usermodehelper_disabled_waitq);
+	up_write(&umhelper_sem);
+}
+
+/**
  * usermodehelper_disable - prevent new helpers from being started
  */
 int usermodehelper_disable(void)
@@ -338,22 +383,10 @@ int usermodehelper_disable(void)
 	if (retval)
 		return 0;
 
-	down_write(&umhelper_sem);
-	usermodehelper_disabled = 0;
-	up_write(&umhelper_sem);
+	usermodehelper_enable();
 	return -EAGAIN;
 }
 
-/**
- * usermodehelper_enable - allow new helpers to be started again
- */
-void usermodehelper_enable(void)
-{
-	down_write(&umhelper_sem);
-	usermodehelper_disabled = 0;
-	up_write(&umhelper_sem);
-}
-
 static void helper_lock(void)
 {
 	atomic_inc(&running_helpers);
Index: linux/drivers/base/firmware_class.c
===================================================================
--- linux.orig/drivers/base/firmware_class.c
+++ linux/drivers/base/firmware_class.c
@@ -81,6 +81,11 @@ enum {
 
 static int loading_timeout = 60;	/* In seconds */
 
+static inline long firmware_loading_timeout(void)
+{
+	return loading_timeout > 0 ? loading_timeout * HZ : MAX_SCHEDULE_TIMEOUT;
+}
+
 /* fw_lock could be moved to 'struct firmware_priv' but since it is just
  * guarding for corner cases a global lock should be OK */
 static DEFINE_MUTEX(fw_lock);
@@ -541,31 +546,22 @@ static void _request_firmware_cleanup(co
 
 static int _request_firmware(const struct firmware *firmware,
 			     const char *name, struct device *device,
-			     bool uevent, bool nowait)
+			     bool uevent, bool nowait, long timeout)
 {
 	struct firmware_priv *fw_priv;
-	int retval;
-
-	retval = usermodehelper_read_trylock();
-	if (WARN_ON(retval)) {
-		dev_err(device, "firmware: %s will not be loaded\n", name);
-		return retval;
-	}
+	int retval = 0;
 
 	if (uevent)
 		dev_dbg(device, "firmware: requesting %s\n", name);
 
 	fw_priv = fw_create_instance(firmware, name, device, uevent, nowait);
-	if (IS_ERR(fw_priv)) {
-		retval = PTR_ERR(fw_priv);
-		goto out;
-	}
+	if (IS_ERR(fw_priv))
+		return PTR_ERR(fw_priv);
 
 	if (uevent) {
-		if (loading_timeout > 0)
+		if (timeout != MAX_SCHEDULE_TIMEOUT)
 			mod_timer(&fw_priv->timeout,
-				  round_jiffies_up(jiffies +
-						   loading_timeout * HZ));
+				  round_jiffies_up(jiffies + timeout));
 
 		kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD);
 	}
@@ -582,9 +578,6 @@ static int _request_firmware(const struc
 	mutex_unlock(&fw_lock);
 
 	fw_destroy_instance(fw_priv);
-
-out:
-	usermodehelper_read_unlock();
 	return retval;
 }
 
@@ -613,7 +606,14 @@ request_firmware(const struct firmware *
 	if (ret <= 0)
 		return ret;
 
-	ret = _request_firmware(*firmware_p, name, device, true, false);
+	ret = usermodehelper_read_trylock();
+	if (WARN_ON(ret)) {
+		dev_err(device, "firmware: %s will not be loaded\n", name);
+	} else {
+		ret = _request_firmware(*firmware_p, name, device, true, false,
+					firmware_loading_timeout());
+		usermodehelper_read_unlock();
+	}
 	if (ret)
 		_request_firmware_cleanup(firmware_p);
 
@@ -648,6 +648,7 @@ static int request_firmware_work_func(vo
 {
 	struct firmware_work *fw_work = arg;
 	const struct firmware *fw;
+	long timeout;
 	int ret;
 
 	if (!arg) {
@@ -659,8 +660,16 @@ static int request_firmware_work_func(vo
 	if (ret <= 0)
 		return ret;
 
-	ret = _request_firmware(fw, fw_work->name, fw_work->device,
-				fw_work->uevent, true);
+	timeout = usermodehelper_read_lock_wait(firmware_loading_timeout());
+	if (timeout) {
+		ret = _request_firmware(fw, fw_work->name, fw_work->device,
+					fw_work->uevent, true, timeout);
+		usermodehelper_read_unlock();
+	} else {
+		dev_dbg(fw_work->device, "firmware: %s loading timed out\n",
+			fw_work->name);
+		ret = -EAGAIN;
+	}
 	if (ret)
 		_request_firmware_cleanup(&fw);
 


^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-18 12:01                                 ` Rafael J. Wysocki
@ 2012-03-19  6:32                                   ` Stephen Boyd
  2012-03-19 11:24                                     ` Rafael J. Wysocki
  0 siblings, 1 reply; 111+ messages in thread
From: Stephen Boyd @ 2012-03-19  6:32 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Linus Torvalds, Saravana Kannan, Kay Sievers, Greg KH,
	Christian Lamparter, linux-kernel, Srivatsa S. Bhat, alan,
	Linux PM mailing list

On 3/18/2012 5:01 AM, Rafael J. Wysocki wrote:
> On Sunday, March 18, 2012, Stephen Boyd wrote:
>
>> Ok. I like where nowait() is going in the other part of the thread but
>> I'm still confused about when request_firmware() is correct to use. It
>> seems that the function is inherently racy with freezing. Does every
>> user of request_firmware() need to synchronize with freezing?
>>
>> For example, if one CPU is in the middle of a driver probe that makes a
>> request_firmware() call and another CPU is starting to suspend we will
>> have a race between usermodehelpers being disabled and the
>> request_firmware() call acquiring the usermodehelper rwsem. If the
>> suspending CPU wins the race it will disable usermodehelpers and the
>> request_firmware() call will return -EBUSY and warn.
> Yes, it will.

That sounds wrong then, no? Why don't we have request_firmware() do a
read_lock on the usermodehelpers sem and then have suspend do a write
lock, disable usermodehelpers, wait for any users  to finish, freeze
processes and then unlock the write lock? That way we don't hit a case
where request_firmware() races with suspend, and we don't have to change
the warning or conditional.

-- 
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.


^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-16 21:14                       ` Christian Lamparter
  2012-03-16 21:19                         ` Linus Torvalds
@ 2012-03-19  7:06                         ` Srivatsa S. Bhat
  1 sibling, 0 replies; 111+ messages in thread
From: Srivatsa S. Bhat @ 2012-03-19  7:06 UTC (permalink / raw)
  To: Christian Lamparter
  Cc: Rafael J. Wysocki, Kay Sievers, Greg KH, linux-kernel, alan,
	Linus Torvalds, Linux PM mailing list, skannan, Stephen Boyd

On 03/17/2012 02:44 AM, Christian Lamparter wrote:

>> That's fine by me.
>>
>> If no one objects, I'll apply it.
> 
> Congrats on that nice, long and "obvious" explanation. Really,
> what do you mean by the "end of resume"? As far as I know it
> is NOT "after" all ->resume calls have finished, in fact the
> usermodehelper is still disabled during ->complete! Maybe a
> hint about "after/before function X() has finished/starts" 
> 


Unfortunately, it appears that you missed the context implied in my comment.
Probably you thought that we were referring only to device suspend and
resume. But actually we were talking about the entire system suspend and
resume, in which device suspend and resume is just one part.

I thought that point was quite clear from the words used in the comment:
"It is wrong to request firmware... system is suspended... So check if the
system is in a state which is unsuitable...". Moreover the comment also
mentions the freezing of tasks etc, which are not part of device suspend
and resume, and (hence) was another indication that we were talking of
suspend/resume at a higher level - the entire suspend/resume sequence, not
just a part of it.

With this clarified, I am pretty sure the comment will make more sense.
Also, the part of the code where usermodehelpers are disabled/enabled during
suspend/resume sequence is also pretty straightforward, and matches perfectly
with what I described in the comment:

kernel/power/suspend.c (or hibernate.c for hibernation sequence):

static int suspend_prepare(void)
{
	...
	pm_notifier_call_chain(PM_SUSPEND_PREPARE);
	...
	usermodehelper_disable();
	...
	suspend_freeze_processes();
	...
}

static void suspend_finish(void)
{
        suspend_thaw_processes();
        usermodehelper_enable();
        pm_notifier_call_chain(PM_POST_SUSPEND);
	...
}

int enter_state(suspend_state_t state)
{
	...
        pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);
	suspend_prepare();
	...
        pr_debug("PM: Entering %s sleep\n", pm_states[state]);
	...
	suspend_devices_and_enter(state);
	...
 Finish:
        pr_debug("PM: Finishing wakeup.\n");
        suspend_finish();
	...
}

[Anyway, this comment patch is probably moot at the moment, with Rafael's
new patches...]


> Regards,
> 	Chr
>>> ---
>>>
>>>  drivers/base/firmware_class.c |   16 ++++++++++++++++
>>>  1 files changed, 16 insertions(+), 0 deletions(-)
>>>
>>> diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
>>> index 6c9387d..9199e3e 100644
>>> --- a/drivers/base/firmware_class.c
>>> +++ b/drivers/base/firmware_class.c
>>> @@ -535,6 +535,22 @@ static int _request_firmware(const struct firmware **firmware_p,
>>>  
>>>  	read_lock_usermodehelper();
>>>  
>>> +	/*
>>> +	 * It is wrong to request firmware when the system is suspended,
>>> +	 * because it simply won't work. Also, it can cause races with
>>> +	 * the freezer, leading to freezing failures. Worse than that,
>>> +	 * it may even cause a user space process to run when we think
>>> +	 * we have frozen the user space! - and that can lead to all kinds
>>> +	 * of interesting breakage..
>>> +	 *
>>> +	 * So check if the system is in a state which is unsuitable for
>>> +	 * requesting firmware (because it is suspended or not yet fully
>>> +	 * resumed) and bail out early if needed.
>>> +	 * Usermodehelpers are disabled at the beginning of suspend, before
>>> +	 * freezing tasks and re-enabled only towards the end of resume, after
>>> +	 * thawing tasks, when it is safe. So all we need to do here is ensure
>>> +	 * that we don't request firmware when usermodehelpers are disabled.
>>> +	 */
>>>  	if (WARN_ON(usermodehelper_is_disabled())) {
>>>  		dev_err(device, "firmware: %s will not be loaded\n", name);
>>>  		retval = -EBUSY;
> 



^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-19  6:32                                   ` Stephen Boyd
@ 2012-03-19 11:24                                     ` Rafael J. Wysocki
  2012-03-19 23:00                                       ` Rafael J. Wysocki
  0 siblings, 1 reply; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-19 11:24 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Linus Torvalds, Saravana Kannan, Kay Sievers, Greg KH,
	Christian Lamparter, linux-kernel, Srivatsa S. Bhat, alan,
	Linux PM mailing list

On Monday, March 19, 2012, Stephen Boyd wrote:
> On 3/18/2012 5:01 AM, Rafael J. Wysocki wrote:
> > On Sunday, March 18, 2012, Stephen Boyd wrote:
> >
> >> Ok. I like where nowait() is going in the other part of the thread but
> >> I'm still confused about when request_firmware() is correct to use. It
> >> seems that the function is inherently racy with freezing. Does every
> >> user of request_firmware() need to synchronize with freezing?
> >>
> >> For example, if one CPU is in the middle of a driver probe that makes a
> >> request_firmware() call and another CPU is starting to suspend we will
> >> have a race between usermodehelpers being disabled and the
> >> request_firmware() call acquiring the usermodehelper rwsem. If the
> >> suspending CPU wins the race it will disable usermodehelpers and the
> >> request_firmware() call will return -EBUSY and warn.
> > Yes, it will.
> 
> That sounds wrong then, no? Why don't we have request_firmware() do a
> read_lock on the usermodehelpers sem and then have suspend do a write
> lock, disable usermodehelpers, wait for any users  to finish, freeze
> processes and then unlock the write lock? That way we don't hit a case
> where request_firmware() races with suspend, and we don't have to change
> the warning or conditional.

So, you're postulating that the freezing of tasks be done under
umhelper_sem write-locked, right?

That would lead to freezing failures if a user space task waited in
request_firmware() for umhelper_sem to become available for read-locking
and unfortunately we don't have an interruptible variant of down_read().

However, we may catch request_firmware() and try to freeze the task
calling it instead.  I'll try to prototype something along these lines later
today (on top of the three "firmware_class" patches I posted yesterday).

Thanks,
Rafael

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [RFC] firmware loader: retry _nowait requests when userhelper is not yet available
  2012-03-16 23:37         ` Linus Torvalds
  2012-03-17  0:23           ` Rafael J. Wysocki
@ 2012-03-19 12:41           ` James Courtier-Dutton
  1 sibling, 0 replies; 111+ messages in thread
From: James Courtier-Dutton @ 2012-03-19 12:41 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Rafael J. Wysocki, Christian Lamparter, Srivatsa S. Bhat,
	linux-kernel, gregkh, alan, Linux PM mailing list

On 16 March 2012 23:37, Linus Torvalds <torvalds@linux-foundation.org> wrote:
> On Fri, Mar 16, 2012 at 3:57 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
>> +       if (nowait) {
>> +               int limit = loading_timeout * MSEC_PER_SEC;
>> +               int timeout = 10;  /* in msec */
>> +
>> +               while (usermodehelper_is_disabled()) {
>> +                       read_unlock_usermodehelper();
>> +
>> +                       msleep(timeout);
>
> Ugh, this is disgusting.
>
> The whole point of nowait was that it's not synchronous - so it should
> just be driven by timers, not some kind of random "while sleep" loop.
>
> And that fw thing already does have a timeout associated with it, and
> quite frankly, the *sane* approach is to do all this not in
> _request_firmware(), but in request_firmware_work_func() - never even
> call _request_firmware() in the first place if the system isn't ready,
> just reset the timeout to retry it again later.
>
> Seriously. The rule should be really simple: nothing should *ever*
> call "request_firmware()" (or the _request_firmware() helper function)
> while the system is not up. That WARN_ON() should remain totally and
> utterly unconditional, and it should *not* be conditional on "nowait"
> or any idiotic crappy hack like that.
>
> If there is an asynchronous thread - and there is, for the _nowait()
> case - that asynchronous thread should set up the timer and retry in
> ten seconds or whatever. It should *not* call 'request_firmware()" and
> expect that to do something special.
>

Could an alternative be a new event/callback to the driver informing
it that the request_firmware() functionallity is present or not.
The driver would then get a callback on each transition from
"request_firmware() present" to/from "request_firmware() absent".
So, on boot up, the driver ".probe" gets called, and only when enough
infrastructure is up and running does the "request_firmware() present"
callback get called.
The question then becomes
Q1: "how do we determine when enough infrastructure is up for
request_firmware() to succeed?"
Now, if that question can actually be answered, I would prefer that
approach, than to each driver starting a timer based request, to keep
requesting every 2 seconds until it works.

Other similar themes:
could be the driver registers an interest in a particular firmware
file in a particular location, and then when the system determines
that that particular file is now readable, it makes a callback to the
driver. It is certainly an easier question to answer than Q1. No
timers needed.
This could be implemented with a "request_firmware(filename)" that
returns imeadiately but adds the filename to the list of firmware
files to look out for.
The driver then gets a callback "here_is_requested_firmware(filename)"
when the system determines that it can read it.
This list could be scanned immediately and after that; only when a
filesystem is mounted, or the user requests a rescan.

Kind Regards

James

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available
  2012-03-19 11:24                                     ` Rafael J. Wysocki
@ 2012-03-19 23:00                                       ` Rafael J. Wysocki
  2012-03-25 22:00                                         ` [PATCH 0/6] firmware_class: Fix problems with usermodehelper test Rafael J. Wysocki
  0 siblings, 1 reply; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-19 23:00 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Linus Torvalds, Saravana Kannan, Kay Sievers, Greg KH,
	Christian Lamparter, linux-kernel, Srivatsa S. Bhat, alan,
	Linux PM mailing list

On Monday, March 19, 2012, Rafael J. Wysocki wrote:
> On Monday, March 19, 2012, Stephen Boyd wrote:
> > On 3/18/2012 5:01 AM, Rafael J. Wysocki wrote:
> > > On Sunday, March 18, 2012, Stephen Boyd wrote:
> > >
> > >> Ok. I like where nowait() is going in the other part of the thread but
> > >> I'm still confused about when request_firmware() is correct to use. It
> > >> seems that the function is inherently racy with freezing. Does every
> > >> user of request_firmware() need to synchronize with freezing?
> > >>
> > >> For example, if one CPU is in the middle of a driver probe that makes a
> > >> request_firmware() call and another CPU is starting to suspend we will
> > >> have a race between usermodehelpers being disabled and the
> > >> request_firmware() call acquiring the usermodehelper rwsem. If the
> > >> suspending CPU wins the race it will disable usermodehelpers and the
> > >> request_firmware() call will return -EBUSY and warn.
> > > Yes, it will.
> > 
> > That sounds wrong then, no? Why don't we have request_firmware() do a
> > read_lock on the usermodehelpers sem and then have suspend do a write
> > lock, disable usermodehelpers, wait for any users  to finish, freeze
> > processes and then unlock the write lock? That way we don't hit a case
> > where request_firmware() races with suspend, and we don't have to change
> > the warning or conditional.
> 
> So, you're postulating that the freezing of tasks be done under
> umhelper_sem write-locked, right?
> 
> That would lead to freezing failures if a user space task waited in
> request_firmware() for umhelper_sem to become available for read-locking
> and unfortunately we don't have an interruptible variant of down_read().
> 
> However, we may catch request_firmware() and try to freeze the task
> calling it instead.  I'll try to prototype something along these lines later
> today (on top of the three "firmware_class" patches I posted yesterday).

Well, that's going to take some more time, as it's more complicated than
I thought initially.  Please, stay tuned.

Thanks,
Rafael


^ permalink raw reply	[flat|nested] 111+ messages in thread

* [PATCH 0/6] firmware_class: Fix problems with usermodehelper test
  2012-03-19 23:00                                       ` Rafael J. Wysocki
@ 2012-03-25 22:00                                         ` Rafael J. Wysocki
  2012-03-25 22:01                                           ` [PATCH 1/6] firmware_class: Rework usermodehelper check Rafael J. Wysocki
                                                             ` (9 more replies)
  0 siblings, 10 replies; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-25 22:00 UTC (permalink / raw)
  To: linux-kernel
  Cc: Stephen Boyd, Linus Torvalds, Saravana Kannan, Kay Sievers,
	Greg KH, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list

Hi all,

The following series of patches fixes two problems with
request_firmware() and request_firmware_nowait() resulting from commit
a144c6a6c924aa1da04dd77fb84b89927354fdff

    PM: Print a warning if firmware is requested when tasks are frozen

The first problem is that request_firmware_nowait() may fail if it happens
to run in parallel with system suspend.  It should't fail in such situations
and that is addressed by the first three patches (that code has been discussed
with Linus at al already).

The second issue is that request_firmware() may be called in a thread which
isn't related to system suspend and if suspend happens exactly at that time,
request_firmware() will fail (and print a scary warning), although it shouldn't.
This problem is addressed by the remaining three patches, which are new.

[1/6] - Rework the usermodehelper check in _request_firmware().
[2/6] - Split _request_firmware() into three functions.
[3/6] - If firmware is to be loaded asynchronously, wait for usermodehelper_disabled
        to be unset instead of failing the operation.
[4/6] - Unify the hibernation/suspend code's usage of usermodehelper_disable().
[5/6] - Move usermodehelper_disable() into freeze_processes().
[6/6] - Make freezable threads calling request_firware() avoid the race with the
        freezer.

Thanks,
Rafael


^ permalink raw reply	[flat|nested] 111+ messages in thread

* [PATCH 1/6] firmware_class: Rework usermodehelper check
  2012-03-25 22:00                                         ` [PATCH 0/6] firmware_class: Fix problems with usermodehelper test Rafael J. Wysocki
@ 2012-03-25 22:01                                           ` Rafael J. Wysocki
  2012-03-25 22:01                                           ` [PATCH 2/6] firmware_class: Split _request_firmware() into three functions Rafael J. Wysocki
                                                             ` (8 subsequent siblings)
  9 siblings, 0 replies; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-25 22:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: Stephen Boyd, Linus Torvalds, Saravana Kannan, Kay Sievers,
	Greg KH, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list

From: Rafael J. Wysocki <rjw@sisk.pl>

Instead of two functions, read_lock_usermodehelper() and
usermodehelper_is_disabled(), used in combination, introduce
usermodehelper_read_trylock() that will only return with umhelper_sem
held if usermodehelper_disabled is unset (and will return -EAGAIN
otherwise) and make _request_firmware() use it.

Rename read_unlock_usermodehelper() to
usermodehelper_read_unlock() to follow the naming convention of the
new function.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 drivers/base/firmware_class.c |   11 +++++------
 include/linux/kmod.h          |    5 ++---
 kernel/kmod.c                 |   24 +++++++++++-------------
 3 files changed, 18 insertions(+), 22 deletions(-)

Index: linux/include/linux/kmod.h
===================================================================
--- linux.orig/include/linux/kmod.h
+++ linux/include/linux/kmod.h
@@ -116,8 +116,7 @@ extern void usermodehelper_init(void);
 
 extern int usermodehelper_disable(void);
 extern void usermodehelper_enable(void);
-extern bool usermodehelper_is_disabled(void);
-extern void read_lock_usermodehelper(void);
-extern void read_unlock_usermodehelper(void);
+extern int usermodehelper_read_trylock(void);
+extern void usermodehelper_read_unlock(void);
 
 #endif /* __LINUX_KMOD_H__ */
Index: linux/kernel/kmod.c
===================================================================
--- linux.orig/kernel/kmod.c
+++ linux/kernel/kmod.c
@@ -296,17 +296,24 @@ static DECLARE_WAIT_QUEUE_HEAD(running_h
  */
 #define RUNNING_HELPERS_TIMEOUT	(5 * HZ)
 
-void read_lock_usermodehelper(void)
+int usermodehelper_read_trylock(void)
 {
+	int ret = 0;
+
 	down_read(&umhelper_sem);
+	if (usermodehelper_disabled) {
+		up_read(&umhelper_sem);
+		ret = -EAGAIN;
+	}
+	return ret;
 }
-EXPORT_SYMBOL_GPL(read_lock_usermodehelper);
+EXPORT_SYMBOL_GPL(usermodehelper_read_trylock);
 
-void read_unlock_usermodehelper(void)
+void usermodehelper_read_unlock(void)
 {
 	up_read(&umhelper_sem);
 }
-EXPORT_SYMBOL_GPL(read_unlock_usermodehelper);
+EXPORT_SYMBOL_GPL(usermodehelper_read_unlock);
 
 /**
  * usermodehelper_disable - prevent new helpers from being started
@@ -347,15 +354,6 @@ void usermodehelper_enable(void)
 	up_write(&umhelper_sem);
 }
 
-/**
- * usermodehelper_is_disabled - check if new helpers are allowed to be started
- */
-bool usermodehelper_is_disabled(void)
-{
-	return usermodehelper_disabled;
-}
-EXPORT_SYMBOL_GPL(usermodehelper_is_disabled);
-
 static void helper_lock(void)
 {
 	atomic_inc(&running_helpers);
Index: linux/drivers/base/firmware_class.c
===================================================================
--- linux.orig/drivers/base/firmware_class.c
+++ linux/drivers/base/firmware_class.c
@@ -533,12 +533,10 @@ static int _request_firmware(const struc
 		return 0;
 	}
 
-	read_lock_usermodehelper();
-
-	if (WARN_ON(usermodehelper_is_disabled())) {
+	retval = usermodehelper_read_trylock();
+	if (WARN_ON(retval)) {
 		dev_err(device, "firmware: %s will not be loaded\n", name);
-		retval = -EBUSY;
-		goto out;
+		goto out_nolock;
 	}
 
 	if (uevent)
@@ -573,8 +571,9 @@ static int _request_firmware(const struc
 	fw_destroy_instance(fw_priv);
 
 out:
-	read_unlock_usermodehelper();
+	usermodehelper_read_unlock();
 
+out_nolock:
 	if (retval) {
 		release_firmware(firmware);
 		*firmware_p = NULL;


^ permalink raw reply	[flat|nested] 111+ messages in thread

* [PATCH 2/6] firmware_class: Split _request_firmware() into three functions
  2012-03-25 22:00                                         ` [PATCH 0/6] firmware_class: Fix problems with usermodehelper test Rafael J. Wysocki
  2012-03-25 22:01                                           ` [PATCH 1/6] firmware_class: Rework usermodehelper check Rafael J. Wysocki
@ 2012-03-25 22:01                                           ` Rafael J. Wysocki
  2012-03-26 18:15                                             ` Stephen Boyd
  2012-03-25 22:02                                           ` [PATCH 3/6] firmware_class: Do not warn that system is not ready from async loads Rafael J. Wysocki
                                                             ` (7 subsequent siblings)
  9 siblings, 1 reply; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-25 22:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: Stephen Boyd, Linus Torvalds, Saravana Kannan, Kay Sievers,
	Greg KH, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list

From: Rafael J. Wysocki <rjw@sisk.pl>

Split _request_firmware() into three functions,
_request_firmware_prepare() doing preparatory work that need not be
done under umhelper_sem, _request_firmware_cleanup() doing the
post-error cleanup and _request_firmware() carrying out the remaining
operations.

This change is requisite for moving the acquisition of umhelper_sem
from _request_firmware() to the callers, which is going to be done
subsequently.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 drivers/base/firmware_class.c |   57 +++++++++++++++++++++++++++++-------------
 1 file changed, 40 insertions(+), 17 deletions(-)

Index: linux/drivers/base/firmware_class.c
===================================================================
--- linux.orig/drivers/base/firmware_class.c
+++ linux/drivers/base/firmware_class.c
@@ -435,7 +435,7 @@ static void firmware_class_timeout(u_lon
 }
 
 static struct firmware_priv *
-fw_create_instance(struct firmware *firmware, const char *fw_name,
+fw_create_instance(const struct firmware *firmware, const char *fw_name,
 		   struct device *device, bool uevent, bool nowait)
 {
 	struct firmware_priv *fw_priv;
@@ -449,7 +449,7 @@ fw_create_instance(struct firmware *firm
 		goto err_out;
 	}
 
-	fw_priv->fw = firmware;
+	fw_priv->fw = (struct firmware *)firmware;
 	fw_priv->nowait = nowait;
 	strcpy(fw_priv->fw_id, fw_name);
 	init_completion(&fw_priv->completion);
@@ -510,13 +510,10 @@ static void fw_destroy_instance(struct f
 	device_unregister(f_dev);
 }
 
-static int _request_firmware(const struct firmware **firmware_p,
-			     const char *name, struct device *device,
-			     bool uevent, bool nowait)
+static int _request_firmware_prepare(const struct firmware **firmware_p,
+				     const char *name, struct device *device)
 {
-	struct firmware_priv *fw_priv;
 	struct firmware *firmware;
-	int retval = 0;
 
 	if (!firmware_p)
 		return -EINVAL;
@@ -533,10 +530,26 @@ static int _request_firmware(const struc
 		return 0;
 	}
 
+	return 1;
+}
+
+static void _request_firmware_cleanup(const struct firmware **firmware_p)
+{
+	release_firmware(*firmware_p);
+	*firmware_p = NULL;
+}
+
+static int _request_firmware(const struct firmware *firmware,
+			     const char *name, struct device *device,
+			     bool uevent, bool nowait)
+{
+	struct firmware_priv *fw_priv;
+	int retval;
+
 	retval = usermodehelper_read_trylock();
 	if (WARN_ON(retval)) {
 		dev_err(device, "firmware: %s will not be loaded\n", name);
-		goto out_nolock;
+		return retval;
 	}
 
 	if (uevent)
@@ -572,13 +585,6 @@ static int _request_firmware(const struc
 
 out:
 	usermodehelper_read_unlock();
-
-out_nolock:
-	if (retval) {
-		release_firmware(firmware);
-		*firmware_p = NULL;
-	}
-
 	return retval;
 }
 
@@ -601,7 +607,17 @@ int
 request_firmware(const struct firmware **firmware_p, const char *name,
                  struct device *device)
 {
-        return _request_firmware(firmware_p, name, device, true, false);
+	int ret;
+
+	ret = _request_firmware_prepare(firmware_p, name, device);
+	if (ret <= 0)
+		return ret;
+
+	ret = _request_firmware(*firmware_p, name, device, true, false);
+	if (ret)
+		_request_firmware_cleanup(firmware_p);
+
+	return ret;
 }
 
 /**
@@ -639,8 +655,15 @@ static int request_firmware_work_func(vo
 		return 0;
 	}
 
-	ret = _request_firmware(&fw, fw_work->name, fw_work->device,
+	ret = _request_firmware_prepare(&fw, fw_work->name, fw_work->device);
+	if (ret <= 0)
+		return ret;
+
+	ret = _request_firmware(fw, fw_work->name, fw_work->device,
 				fw_work->uevent, true);
+	if (ret)
+		_request_firmware_cleanup(&fw);
+
 	fw_work->cont(fw, fw_work->context);
 
 	module_put(fw_work->module);


^ permalink raw reply	[flat|nested] 111+ messages in thread

* [PATCH 3/6] firmware_class: Do not warn that system is not ready from async loads
  2012-03-25 22:00                                         ` [PATCH 0/6] firmware_class: Fix problems with usermodehelper test Rafael J. Wysocki
  2012-03-25 22:01                                           ` [PATCH 1/6] firmware_class: Rework usermodehelper check Rafael J. Wysocki
  2012-03-25 22:01                                           ` [PATCH 2/6] firmware_class: Split _request_firmware() into three functions Rafael J. Wysocki
@ 2012-03-25 22:02                                           ` Rafael J. Wysocki
  2012-03-25 22:03                                           ` [PATCH 4/6] PM / Hibernate: Disable usermode helpers right before freezing tasks Rafael J. Wysocki
                                                             ` (6 subsequent siblings)
  9 siblings, 0 replies; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-25 22:02 UTC (permalink / raw)
  To: linux-kernel
  Cc: Stephen Boyd, Linus Torvalds, Saravana Kannan, Kay Sievers,
	Greg KH, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list

From: Rafael J. Wysocki <rjw@sisk.pl>

If firmware is requested asynchronously, by calling
request_firmware_nowait(), there is no reason to fail the request
(and warn the user) when the system is (presumably temporarily)
unready to handle it (because user space is not available yet or
frozen).  For this reason, introduce an alternative routine for
read-locking umhelper_sem, usermodehelper_read_lock_wait(), that
will wait for usermodehelper_disabled to be unset (possibly with
a timeout) and make request_firmware_work_func() use it instead of
usermodehelper_read_trylock().

Accordingly, modify request_firmware() so that it uses
usermodehelper_read_trylock() to acquire umhelper_sem and remove
the code related to that lock from _request_firmware().

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 drivers/base/firmware_class.c |   51 +++++++++++++++++++++---------------
 include/linux/kmod.h          |    1 
 kernel/kmod.c                 |   58 ++++++++++++++++++++++++++++++++----------
 3 files changed, 76 insertions(+), 34 deletions(-)

Index: linux/include/linux/kmod.h
===================================================================
--- linux.orig/include/linux/kmod.h
+++ linux/include/linux/kmod.h
@@ -117,6 +117,7 @@ extern void usermodehelper_init(void);
 extern int usermodehelper_disable(void);
 extern void usermodehelper_enable(void);
 extern int usermodehelper_read_trylock(void);
+extern long usermodehelper_read_lock_wait(long timeout);
 extern void usermodehelper_read_unlock(void);
 
 #endif /* __LINUX_KMOD_H__ */
Index: linux/kernel/kmod.c
===================================================================
--- linux.orig/kernel/kmod.c
+++ linux/kernel/kmod.c
@@ -291,6 +291,12 @@ static atomic_t running_helpers = ATOMIC
 static DECLARE_WAIT_QUEUE_HEAD(running_helpers_waitq);
 
 /*
+ * Used by usermodehelper_read_lock_wait() to wait for usermodehelper_disabled
+ * to become 'false'.
+ */
+static DECLARE_WAIT_QUEUE_HEAD(usermodehelper_disabled_waitq);
+
+/*
  * Time to wait for running_helpers to become zero before the setting of
  * usermodehelper_disabled in usermodehelper_disable() fails
  */
@@ -309,6 +315,33 @@ int usermodehelper_read_trylock(void)
 }
 EXPORT_SYMBOL_GPL(usermodehelper_read_trylock);
 
+long usermodehelper_read_lock_wait(long timeout)
+{
+	DEFINE_WAIT(wait);
+
+	if (timeout < 0)
+		return -EINVAL;
+
+	down_read(&umhelper_sem);
+	for (;;) {
+		prepare_to_wait(&usermodehelper_disabled_waitq, &wait,
+				TASK_UNINTERRUPTIBLE);
+		if (!usermodehelper_disabled)
+			break;
+
+		up_read(&umhelper_sem);
+
+		timeout = schedule_timeout(timeout);
+		if (!timeout)
+			break;
+
+		down_read(&umhelper_sem);
+	}
+	finish_wait(&usermodehelper_disabled_waitq, &wait);
+	return timeout;
+}
+EXPORT_SYMBOL_GPL(usermodehelper_read_lock_wait);
+
 void usermodehelper_read_unlock(void)
 {
 	up_read(&umhelper_sem);
@@ -316,6 +349,17 @@ void usermodehelper_read_unlock(void)
 EXPORT_SYMBOL_GPL(usermodehelper_read_unlock);
 
 /**
+ * usermodehelper_enable - allow new helpers to be started again
+ */
+void usermodehelper_enable(void)
+{
+	down_write(&umhelper_sem);
+	usermodehelper_disabled = 0;
+	wake_up(&usermodehelper_disabled_waitq);
+	up_write(&umhelper_sem);
+}
+
+/**
  * usermodehelper_disable - prevent new helpers from being started
  */
 int usermodehelper_disable(void)
@@ -338,22 +382,10 @@ int usermodehelper_disable(void)
 	if (retval)
 		return 0;
 
-	down_write(&umhelper_sem);
-	usermodehelper_disabled = 0;
-	up_write(&umhelper_sem);
+	usermodehelper_enable();
 	return -EAGAIN;
 }
 
-/**
- * usermodehelper_enable - allow new helpers to be started again
- */
-void usermodehelper_enable(void)
-{
-	down_write(&umhelper_sem);
-	usermodehelper_disabled = 0;
-	up_write(&umhelper_sem);
-}
-
 static void helper_lock(void)
 {
 	atomic_inc(&running_helpers);
Index: linux/drivers/base/firmware_class.c
===================================================================
--- linux.orig/drivers/base/firmware_class.c
+++ linux/drivers/base/firmware_class.c
@@ -81,6 +81,11 @@ enum {
 
 static int loading_timeout = 60;	/* In seconds */
 
+static inline long firmware_loading_timeout(void)
+{
+	return loading_timeout > 0 ? loading_timeout * HZ : MAX_SCHEDULE_TIMEOUT;
+}
+
 /* fw_lock could be moved to 'struct firmware_priv' but since it is just
  * guarding for corner cases a global lock should be OK */
 static DEFINE_MUTEX(fw_lock);
@@ -541,31 +546,22 @@ static void _request_firmware_cleanup(co
 
 static int _request_firmware(const struct firmware *firmware,
 			     const char *name, struct device *device,
-			     bool uevent, bool nowait)
+			     bool uevent, bool nowait, long timeout)
 {
 	struct firmware_priv *fw_priv;
-	int retval;
-
-	retval = usermodehelper_read_trylock();
-	if (WARN_ON(retval)) {
-		dev_err(device, "firmware: %s will not be loaded\n", name);
-		return retval;
-	}
+	int retval = 0;
 
 	if (uevent)
 		dev_dbg(device, "firmware: requesting %s\n", name);
 
 	fw_priv = fw_create_instance(firmware, name, device, uevent, nowait);
-	if (IS_ERR(fw_priv)) {
-		retval = PTR_ERR(fw_priv);
-		goto out;
-	}
+	if (IS_ERR(fw_priv))
+		return PTR_ERR(fw_priv);
 
 	if (uevent) {
-		if (loading_timeout > 0)
+		if (timeout != MAX_SCHEDULE_TIMEOUT)
 			mod_timer(&fw_priv->timeout,
-				  round_jiffies_up(jiffies +
-						   loading_timeout * HZ));
+				  round_jiffies_up(jiffies + timeout));
 
 		kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD);
 	}
@@ -582,9 +578,6 @@ static int _request_firmware(const struc
 	mutex_unlock(&fw_lock);
 
 	fw_destroy_instance(fw_priv);
-
-out:
-	usermodehelper_read_unlock();
 	return retval;
 }
 
@@ -613,7 +606,14 @@ request_firmware(const struct firmware *
 	if (ret <= 0)
 		return ret;
 
-	ret = _request_firmware(*firmware_p, name, device, true, false);
+	ret = usermodehelper_read_trylock();
+	if (WARN_ON(ret)) {
+		dev_err(device, "firmware: %s will not be loaded\n", name);
+	} else {
+		ret = _request_firmware(*firmware_p, name, device, true, false,
+					firmware_loading_timeout());
+		usermodehelper_read_unlock();
+	}
 	if (ret)
 		_request_firmware_cleanup(firmware_p);
 
@@ -648,6 +648,7 @@ static int request_firmware_work_func(vo
 {
 	struct firmware_work *fw_work = arg;
 	const struct firmware *fw;
+	long timeout;
 	int ret;
 
 	if (!arg) {
@@ -659,8 +660,16 @@ static int request_firmware_work_func(vo
 	if (ret <= 0)
 		return ret;
 
-	ret = _request_firmware(fw, fw_work->name, fw_work->device,
-				fw_work->uevent, true);
+	timeout = usermodehelper_read_lock_wait(firmware_loading_timeout());
+	if (timeout) {
+		ret = _request_firmware(fw, fw_work->name, fw_work->device,
+					fw_work->uevent, true, timeout);
+		usermodehelper_read_unlock();
+	} else {
+		dev_dbg(fw_work->device, "firmware: %s loading timed out\n",
+			fw_work->name);
+		ret = -EAGAIN;
+	}
 	if (ret)
 		_request_firmware_cleanup(&fw);
 


^ permalink raw reply	[flat|nested] 111+ messages in thread

* [PATCH 4/6] PM / Hibernate: Disable usermode helpers right before freezing tasks
  2012-03-25 22:00                                         ` [PATCH 0/6] firmware_class: Fix problems with usermodehelper test Rafael J. Wysocki
                                                             ` (2 preceding siblings ...)
  2012-03-25 22:02                                           ` [PATCH 3/6] firmware_class: Do not warn that system is not ready from async loads Rafael J. Wysocki
@ 2012-03-25 22:03                                           ` Rafael J. Wysocki
  2012-03-25 22:03                                           ` [PATCH 5/6] PM / Sleep: Move disabling of usermode helpers to the freezer Rafael J. Wysocki
                                                             ` (5 subsequent siblings)
  9 siblings, 0 replies; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-25 22:03 UTC (permalink / raw)
  To: linux-kernel
  Cc: Stephen Boyd, Linus Torvalds, Saravana Kannan, Kay Sievers,
	Greg KH, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list

From: Rafael J. Wysocki <rjw@sisk.pl>

There is no reason to call usermodehelper_disable() before creating
memory bitmaps in hibernate() and software_resume(), so call it right
before freeze_processes(), in accordance with the other suspend and
hibernation code.  Consequently, call usermodehelper_enable() right
after the thawing of tasks rather than after freeing the memory
bitmaps.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 kernel/power/hibernate.c |   23 ++++++++++-------------
 1 file changed, 10 insertions(+), 13 deletions(-)

Index: linux/kernel/power/hibernate.c
===================================================================
--- linux.orig/kernel/power/hibernate.c
+++ linux/kernel/power/hibernate.c
@@ -611,19 +611,19 @@ int hibernate(void)
 	if (error)
 		goto Exit;
 
-	error = usermodehelper_disable();
-	if (error)
-		goto Exit;
-
 	/* Allocate memory management structures */
 	error = create_basic_memory_bitmaps();
 	if (error)
-		goto Enable_umh;
+		goto Exit;
 
 	printk(KERN_INFO "PM: Syncing filesystems ... ");
 	sys_sync();
 	printk("done.\n");
 
+	error = usermodehelper_disable();
+	if (error)
+		goto Exit;
+
 	error = freeze_processes();
 	if (error)
 		goto Free_bitmaps;
@@ -660,9 +660,8 @@ int hibernate(void)
 	freezer_test_done = false;
 
  Free_bitmaps:
-	free_basic_memory_bitmaps();
- Enable_umh:
 	usermodehelper_enable();
+	free_basic_memory_bitmaps();
  Exit:
 	pm_notifier_call_chain(PM_POST_HIBERNATION);
 	pm_restore_console();
@@ -777,15 +776,13 @@ static int software_resume(void)
 	if (error)
 		goto close_finish;
 
-	error = usermodehelper_disable();
+	error = create_basic_memory_bitmaps();
 	if (error)
 		goto close_finish;
 
-	error = create_basic_memory_bitmaps();
-	if (error) {
-		usermodehelper_enable();
+	error = usermodehelper_disable();
+	if (error)
 		goto close_finish;
-	}
 
 	pr_debug("PM: Preparing processes for restore.\n");
 	error = freeze_processes();
@@ -805,8 +802,8 @@ static int software_resume(void)
 	swsusp_free();
 	thaw_processes();
  Done:
-	free_basic_memory_bitmaps();
 	usermodehelper_enable();
+	free_basic_memory_bitmaps();
  Finish:
 	pm_notifier_call_chain(PM_POST_RESTORE);
 	pm_restore_console();


^ permalink raw reply	[flat|nested] 111+ messages in thread

* [PATCH 5/6] PM / Sleep: Move disabling of usermode helpers to the freezer
  2012-03-25 22:00                                         ` [PATCH 0/6] firmware_class: Fix problems with usermodehelper test Rafael J. Wysocki
                                                             ` (3 preceding siblings ...)
  2012-03-25 22:03                                           ` [PATCH 4/6] PM / Hibernate: Disable usermode helpers right before freezing tasks Rafael J. Wysocki
@ 2012-03-25 22:03                                           ` Rafael J. Wysocki
  2012-03-25 22:04                                           ` [PATCH 6/6] PM / Sleep: Mitigate race between the freezer and request_firmware() Rafael J. Wysocki
                                                             ` (4 subsequent siblings)
  9 siblings, 0 replies; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-25 22:03 UTC (permalink / raw)
  To: linux-kernel
  Cc: Stephen Boyd, Linus Torvalds, Saravana Kannan, Kay Sievers,
	Greg KH, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list

From: Rafael J. Wysocki <rjw@sisk.pl>

The core suspend/hibernation code calls usermodehelper_disable() to
avoid race conditions between the freezer and the starting of
usermode helpers and each code path has to do that on its own.
However, it is always called right before freeze_processes()
and usermodehelper_enable() is always called right after
thaw_processes().  For this reason, to avoid code duplication and
to make the connection between usermodehelper_disable() and the
freezer more visible, make freeze_processes() call it and remove the
direct usermodehelper_disable() and usermodehelper_enable() calls
from all suspend/hibernation code paths.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 kernel/power/hibernate.c |   11 -----------
 kernel/power/process.c   |    7 +++++++
 kernel/power/suspend.c   |    7 -------
 kernel/power/user.c      |   10 +---------
 4 files changed, 8 insertions(+), 27 deletions(-)

Index: linux/kernel/power/process.c
===================================================================
--- linux.orig/kernel/power/process.c
+++ linux/kernel/power/process.c
@@ -16,6 +16,7 @@
 #include <linux/freezer.h>
 #include <linux/delay.h>
 #include <linux/workqueue.h>
+#include <linux/kmod.h>
 
 /* 
  * Timeout for stopping processes
@@ -122,6 +123,10 @@ int freeze_processes(void)
 {
 	int error;
 
+	error = usermodehelper_disable();
+	if (error)
+		return error;
+
 	if (!pm_freezing)
 		atomic_inc(&system_freezing_cnt);
 
@@ -187,6 +192,8 @@ void thaw_processes(void)
 	} while_each_thread(g, p);
 	read_unlock(&tasklist_lock);
 
+	usermodehelper_enable();
+
 	schedule();
 	printk("done.\n");
 }
Index: linux/kernel/power/suspend.c
===================================================================
--- linux.orig/kernel/power/suspend.c
+++ linux/kernel/power/suspend.c
@@ -12,7 +12,6 @@
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/init.h>
-#include <linux/kmod.h>
 #include <linux/console.h>
 #include <linux/cpu.h>
 #include <linux/syscalls.h>
@@ -102,17 +101,12 @@ static int suspend_prepare(void)
 	if (error)
 		goto Finish;
 
-	error = usermodehelper_disable();
-	if (error)
-		goto Finish;
-
 	error = suspend_freeze_processes();
 	if (!error)
 		return 0;
 
 	suspend_stats.failed_freeze++;
 	dpm_save_failed_step(SUSPEND_FREEZE);
-	usermodehelper_enable();
  Finish:
 	pm_notifier_call_chain(PM_POST_SUSPEND);
 	pm_restore_console();
@@ -259,7 +253,6 @@ int suspend_devices_and_enter(suspend_st
 static void suspend_finish(void)
 {
 	suspend_thaw_processes();
-	usermodehelper_enable();
 	pm_notifier_call_chain(PM_POST_SUSPEND);
 	pm_restore_console();
 }
Index: linux/kernel/power/hibernate.c
===================================================================
--- linux.orig/kernel/power/hibernate.c
+++ linux/kernel/power/hibernate.c
@@ -16,7 +16,6 @@
 #include <linux/string.h>
 #include <linux/device.h>
 #include <linux/async.h>
-#include <linux/kmod.h>
 #include <linux/delay.h>
 #include <linux/fs.h>
 #include <linux/mount.h>
@@ -620,10 +619,6 @@ int hibernate(void)
 	sys_sync();
 	printk("done.\n");
 
-	error = usermodehelper_disable();
-	if (error)
-		goto Exit;
-
 	error = freeze_processes();
 	if (error)
 		goto Free_bitmaps;
@@ -660,7 +655,6 @@ int hibernate(void)
 	freezer_test_done = false;
 
  Free_bitmaps:
-	usermodehelper_enable();
 	free_basic_memory_bitmaps();
  Exit:
 	pm_notifier_call_chain(PM_POST_HIBERNATION);
@@ -780,10 +774,6 @@ static int software_resume(void)
 	if (error)
 		goto close_finish;
 
-	error = usermodehelper_disable();
-	if (error)
-		goto close_finish;
-
 	pr_debug("PM: Preparing processes for restore.\n");
 	error = freeze_processes();
 	if (error) {
@@ -802,7 +792,6 @@ static int software_resume(void)
 	swsusp_free();
 	thaw_processes();
  Done:
-	usermodehelper_enable();
 	free_basic_memory_bitmaps();
  Finish:
 	pm_notifier_call_chain(PM_POST_RESTORE);
Index: linux/kernel/power/user.c
===================================================================
--- linux.orig/kernel/power/user.c
+++ linux/kernel/power/user.c
@@ -12,7 +12,6 @@
 #include <linux/suspend.h>
 #include <linux/syscalls.h>
 #include <linux/reboot.h>
-#include <linux/kmod.h>
 #include <linux/string.h>
 #include <linux/device.h>
 #include <linux/miscdevice.h>
@@ -222,14 +221,8 @@ static long snapshot_ioctl(struct file *
 		sys_sync();
 		printk("done.\n");
 
-		error = usermodehelper_disable();
-		if (error)
-			break;
-
 		error = freeze_processes();
-		if (error)
-			usermodehelper_enable();
-		else
+		if (!error)
 			data->frozen = 1;
 		break;
 
@@ -238,7 +231,6 @@ static long snapshot_ioctl(struct file *
 			break;
 		pm_restore_gfp_mask();
 		thaw_processes();
-		usermodehelper_enable();
 		data->frozen = 0;
 		break;
 


^ permalink raw reply	[flat|nested] 111+ messages in thread

* [PATCH 6/6] PM / Sleep: Mitigate race between the freezer and request_firmware()
  2012-03-25 22:00                                         ` [PATCH 0/6] firmware_class: Fix problems with usermodehelper test Rafael J. Wysocki
                                                             ` (4 preceding siblings ...)
  2012-03-25 22:03                                           ` [PATCH 5/6] PM / Sleep: Move disabling of usermode helpers to the freezer Rafael J. Wysocki
@ 2012-03-25 22:04                                           ` Rafael J. Wysocki
  2012-03-26 18:16                                             ` Stephen Boyd
  2012-03-26 18:42                                           ` [PATCH 0/6] firmware_class: Fix problems with usermodehelper test Greg KH
                                                             ` (3 subsequent siblings)
  9 siblings, 1 reply; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-25 22:04 UTC (permalink / raw)
  To: linux-kernel
  Cc: Stephen Boyd, Linus Torvalds, Saravana Kannan, Kay Sievers,
	Greg KH, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list

From: Rafael J. Wysocki <rjw@sisk.pl>

There is a race condition between the freezer and request_firmware()
such that if request_firmware() is run on one CPU and
freeze_processes() is run on another CPU and usermodehelper_disable()
called by it succeeds to grab umhelper_sem for writing before
usermodehelper_read_trylock() called from request_firmware()
acquires it for reading, the request_firmware() will fail and
trigger a WARN_ON() complaining that it was called at a wrong time.
However, in fact, it wasn't called at a wrong time and
freeze_processes() simply happened to be executed simultaneously.

To avoid this race, at least in some cases, modify
usermodehelper_read_trylock() so that it doesn't fail if the
freezing of tasks has just started and hasn't been completed yet.
Instead, during the freezing of tasks, it will try to freeze the
task that has called it so that it can wait until user space is
thawed without triggering the scary warning.

For this purpose, change usermodehelper_disabled so that it can
take three different values, UMH_ENABLED (0), UMH_FREEZING and
UMH_DISABLED.  The first one means that usermode helpers are
enabled, the last one means "hard disable" (i.e. the system is not
ready for usermode helpers to be used) and the second one
is reserved for the freezer.  Namely, when freeze_processes() is
started, it sets usermodehelper_disabled to UMH_FREEZING which
tells usermodehelper_read_trylock() that it shouldn't fail just
yet and should call try_to_freeze() if woken up and cannot
return immediately.  This way all freezable tasks that happen
to call request_firmware() right before freeze_processes() is
started and lose the race for umhelper_sem with it will be
frozen and will sleep until thaw_processes() unsets
usermodehelper_disabled.  [For the non-freezable callers of
request_firmware() the race for umhelper_sem against
freeze_processes() is unfortunately unavoidable.]

Reported-by: Stephen Boyd <sboyd@codeaurora.org>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 include/linux/kmod.h   |   21 +++++++++++++++++++--
 kernel/kmod.c          |   47 +++++++++++++++++++++++++++++++++++++----------
 kernel/power/process.c |    3 ++-
 3 files changed, 58 insertions(+), 13 deletions(-)

Index: linux/include/linux/kmod.h
===================================================================
--- linux.orig/include/linux/kmod.h
+++ linux/include/linux/kmod.h
@@ -112,10 +112,27 @@ call_usermodehelper(char *path, char **a
 
 extern struct ctl_table usermodehelper_table[];
 
+enum umh_disable_depth {
+	UMH_ENABLED = 0,
+	UMH_FREEZING,
+	UMH_DISABLED,
+};
+
 extern void usermodehelper_init(void);
 
-extern int usermodehelper_disable(void);
-extern void usermodehelper_enable(void);
+extern int __usermodehelper_disable(enum umh_disable_depth depth);
+extern void __usermodehelper_reset(enum umh_disable_depth depth);
+
+static inline int usermodehelper_disable(void)
+{
+	return __usermodehelper_disable(UMH_DISABLED);
+}
+
+static inline void usermodehelper_enable(void)
+{
+	__usermodehelper_reset(UMH_ENABLED);
+}
+
 extern int usermodehelper_read_trylock(void);
 extern long usermodehelper_read_lock_wait(long timeout);
 extern void usermodehelper_read_unlock(void);
Index: linux/kernel/kmod.c
===================================================================
--- linux.orig/kernel/kmod.c
+++ linux/kernel/kmod.c
@@ -279,7 +279,7 @@ static void __call_usermodehelper(struct
  * land has been frozen during a system-wide hibernation or suspend operation).
  * Should always be manipulated under umhelper_sem acquired for write.
  */
-static int usermodehelper_disabled = 1;
+static enum umh_disable_depth usermodehelper_disabled = UMH_DISABLED;
 
 /* Number of helpers running */
 static atomic_t running_helpers = ATOMIC_INIT(0);
@@ -304,13 +304,30 @@ static DECLARE_WAIT_QUEUE_HEAD(usermodeh
 
 int usermodehelper_read_trylock(void)
 {
+	DEFINE_WAIT(wait);
 	int ret = 0;
 
 	down_read(&umhelper_sem);
-	if (usermodehelper_disabled) {
+	for (;;) {
+		prepare_to_wait(&usermodehelper_disabled_waitq, &wait,
+				TASK_INTERRUPTIBLE);
+		if (!usermodehelper_disabled)
+			break;
+
+		if (usermodehelper_disabled == UMH_DISABLED)
+			ret = -EAGAIN;
+
 		up_read(&umhelper_sem);
-		ret = -EAGAIN;
+
+		if (ret)
+			break;
+
+		schedule();
+		try_to_freeze();
+
+		down_read(&umhelper_sem);
 	}
+	finish_wait(&usermodehelper_disabled_waitq, &wait);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(usermodehelper_read_trylock);
@@ -349,25 +366,35 @@ void usermodehelper_read_unlock(void)
 EXPORT_SYMBOL_GPL(usermodehelper_read_unlock);
 
 /**
- * usermodehelper_enable - allow new helpers to be started again
+ * __usermodehelper_reset - Change the value of usermodehelper_disabled.
+ * depth: New value to assign to usermodehelper_disabled.
+ *
+ * Change the value of usermodehelper_disabled (under umhelper_sem locked for
+ * writing) and wakeup tasks waiting for it to change.
  */
-void usermodehelper_enable(void)
+void __usermodehelper_reset(enum umh_disable_depth depth)
 {
 	down_write(&umhelper_sem);
-	usermodehelper_disabled = 0;
+	usermodehelper_disabled = depth;
 	wake_up(&usermodehelper_disabled_waitq);
 	up_write(&umhelper_sem);
 }
 
 /**
- * usermodehelper_disable - prevent new helpers from being started
+ * __usermodehelper_disable - Prevent new helpers from being started.
+ * @depth: New value to assign to usermodehelper_disabled.
+ *
+ * Set usermodehelper_disabled to @depth and wait for running helpers to exit.
  */
-int usermodehelper_disable(void)
+int __usermodehelper_disable(enum umh_disable_depth depth)
 {
 	long retval;
 
+	if (!depth)
+		return -EINVAL;
+
 	down_write(&umhelper_sem);
-	usermodehelper_disabled = 1;
+	usermodehelper_disabled = depth;
 	up_write(&umhelper_sem);
 
 	/*
@@ -382,7 +409,7 @@ int usermodehelper_disable(void)
 	if (retval)
 		return 0;
 
-	usermodehelper_enable();
+	__usermodehelper_reset(UMH_ENABLED);
 	return -EAGAIN;
 }
 
Index: linux/kernel/power/process.c
===================================================================
--- linux.orig/kernel/power/process.c
+++ linux/kernel/power/process.c
@@ -123,7 +123,7 @@ int freeze_processes(void)
 {
 	int error;
 
-	error = usermodehelper_disable();
+	error = __usermodehelper_disable(UMH_FREEZING);
 	if (error)
 		return error;
 
@@ -135,6 +135,7 @@ int freeze_processes(void)
 	error = try_to_freeze_tasks(true);
 	if (!error) {
 		printk("done.");
+		__usermodehelper_reset(UMH_DISABLED);
 		oom_killer_disable();
 	}
 	printk("\n");

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH 2/6] firmware_class: Split _request_firmware() into three functions
  2012-03-25 22:01                                           ` [PATCH 2/6] firmware_class: Split _request_firmware() into three functions Rafael J. Wysocki
@ 2012-03-26 18:15                                             ` Stephen Boyd
  2012-03-26 18:21                                               ` Stephen Boyd
  2012-03-26 20:36                                               ` Rafael J. Wysocki
  0 siblings, 2 replies; 111+ messages in thread
From: Stephen Boyd @ 2012-03-26 18:15 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: linux-kernel, Linus Torvalds, Saravana Kannan, Kay Sievers,
	Greg KH, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list

On 03/25/12 15:01, Rafael J. Wysocki wrote:
>  drivers/base/firmware_class.c |   57 +++++++++++++++++++++++++++++-------------
>  1 file changed, 40 insertions(+), 17 deletions(-)
>
> Index: linux/drivers/base/firmware_class.c
> ===================================================================
> --- linux.orig/drivers/base/firmware_class.c
> +++ linux/drivers/base/firmware_class.c
> @@ -435,7 +435,7 @@ static void firmware_class_timeout(u_lon
>  }
>  
>  static struct firmware_priv *
> -fw_create_instance(struct firmware *firmware, const char *fw_name,
> +fw_create_instance(const struct firmware *firmware, const char *fw_name,
>  		   struct device *device, bool uevent, bool nowait)
>  {
>  	struct firmware_priv *fw_priv;
> @@ -449,7 +449,7 @@ fw_create_instance(struct firmware *firm
>  		goto err_out;
>  	}
>  
> -	fw_priv->fw = firmware;
> +	fw_priv->fw = (struct firmware *)firmware;
>  	fw_priv->nowait = nowait;
>  	strcpy(fw_priv->fw_id, fw_name);
>  	init_completion(&fw_priv->completion);

Can we avoid this cast? If we do some parts of fw_create_instance()
during the setup phase I think we can avoid it.

> @@ -639,8 +655,15 @@ static int request_firmware_work_func(vo
>  		return 0;
>  	}
>  
> -	ret = _request_firmware(&fw, fw_work->name, fw_work->device,
> +	ret = _request_firmware_prepare(&fw, fw_work->name, fw_work->device);
> +	if (ret <= 0)
> +		return ret;

This needs to jump to the cont function so that users know loading
failed or that the firmware was builtin.

> +
> +	ret = _request_firmware(fw, fw_work->name, fw_work->device,
>  				fw_work->uevent, true);
> +	if (ret)
> +		_request_firmware_cleanup(&fw);
> +
>  	fw_work->cont(fw, fw_work->context);
>  
>  	module_put(fw_work->module);
>

Here's a compile only tested patch on top. The idea is return a fw_priv
pointer from the setup function and use that to indicate failure (error
pointer), builtin (NULL) or loadable (non-NULL). Then we can move all
the uevent/device stuff to the loading phase

----8<-----
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 5db254d..fbe98a8 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -440,13 +440,11 @@ fw_create_instance(const struct firmware *firmware, const char *fw_name,
 {
 	struct firmware_priv *fw_priv;
 	struct device *f_dev;
-	int error;
 
 	fw_priv = kzalloc(sizeof(*fw_priv) + strlen(fw_name) + 1 , GFP_KERNEL);
 	if (!fw_priv) {
 		dev_err(device, "%s: kmalloc failed\n", __func__);
-		error = -ENOMEM;
-		goto err_out;
+		return ERR_PTR(-ENOMEM);
 	}
 
 	fw_priv->fw = (struct firmware *)firmware;
@@ -463,42 +461,7 @@ fw_create_instance(const struct firmware *firmware, const char *fw_name,
 	f_dev->parent = device;
 	f_dev->class = &firmware_class;
 
-	dev_set_uevent_suppress(f_dev, true);
-
-	/* Need to pin this module until class device is destroyed */
-	__module_get(THIS_MODULE);
-
-	error = device_add(f_dev);
-	if (error) {
-		dev_err(device, "%s: device_register failed\n", __func__);
-		goto err_put_dev;
-	}
-
-	error = device_create_bin_file(f_dev, &firmware_attr_data);
-	if (error) {
-		dev_err(device, "%s: sysfs_create_bin_file failed\n", __func__);
-		goto err_del_dev;
-	}
-
-	error = device_create_file(f_dev, &dev_attr_loading);
-	if (error) {
-		dev_err(device, "%s: device_create_file failed\n", __func__);
-		goto err_del_bin_attr;
-	}
-
-	if (uevent)
-		dev_set_uevent_suppress(f_dev, false);
-
 	return fw_priv;
-
-err_del_bin_attr:
-	device_remove_bin_file(f_dev, &firmware_attr_data);
-err_del_dev:
-	device_del(f_dev);
-err_put_dev:
-	put_device(f_dev);
-err_out:
-	return ERR_PTR(error);
 }
 
 static void fw_destroy_instance(struct firmware_priv *fw_priv)
@@ -510,27 +473,34 @@ static void fw_destroy_instance(struct firmware_priv *fw_priv)
 	device_unregister(f_dev);
 }
 
-static int _request_firmware_prepare(const struct firmware **firmware_p,
-				     const char *name, struct device *device)
+static struct firmware_priv *
+_request_firmware_prepare(const struct firmware **firmware_p, const char *name,
+			  struct device *device, bool uevent, bool nowait)
 {
 	struct firmware *firmware;
+	struct firmware_priv *fw_priv;
 
 	if (!firmware_p)
-		return -EINVAL;
+		return ERR_PTR(-EINVAL);
 
 	*firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL);
 	if (!firmware) {
 		dev_err(device, "%s: kmalloc(struct firmware) failed\n",
 			__func__);
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 	}
 
 	if (fw_get_builtin_firmware(firmware, name)) {
 		dev_dbg(device, "firmware: using built-in firmware %s\n", name);
-		return 0;
+		return NULL;
 	}
 
-	return 1;
+	fw_priv = fw_create_instance(firmware, name, device, uevent, nowait);
+	if (IS_ERR(fw_priv)) {
+		release_firmware(firmware);
+		*firmware_p = NULL;
+	}
+	return fw_priv;
 }
 
 static void _request_firmware_cleanup(const struct firmware **firmware_p)
@@ -539,29 +509,44 @@ static void _request_firmware_cleanup(const struct firmware **firmware_p)
 	*firmware_p = NULL;
 }
 
-static int _request_firmware(const struct firmware *firmware,
-			     const char *name, struct device *device,
-			     bool uevent, bool nowait)
+static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent)
 {
-	struct firmware_priv *fw_priv;
 	int retval;
+	struct device *f_dev = &fw_priv->dev;
 
 	retval = usermodehelper_read_trylock();
 	if (WARN_ON(retval)) {
-		dev_err(device, "firmware: %s will not be loaded\n", name);
+		dev_err(f_dev, "firmware: %s will not be loaded\n",
+				fw_priv->fw_id);
 		return retval;
 	}
 
-	if (uevent)
-		dev_dbg(device, "firmware: requesting %s\n", name);
+	dev_set_uevent_suppress(f_dev, true);
 
-	fw_priv = fw_create_instance(firmware, name, device, uevent, nowait);
-	if (IS_ERR(fw_priv)) {
-		retval = PTR_ERR(fw_priv);
-		goto out;
+	/* Need to pin this module until class device is destroyed */
+	__module_get(THIS_MODULE);
+
+	retval = device_add(f_dev);
+	if (retval) {
+		dev_err(f_dev, "%s: device_register failed\n", __func__);
+		goto err_put_dev;
+	}
+
+	retval = device_create_bin_file(f_dev, &firmware_attr_data);
+	if (retval) {
+		dev_err(f_dev, "%s: sysfs_create_bin_file failed\n", __func__);
+		goto err_del_dev;
+	}
+
+	retval = device_create_file(f_dev, &dev_attr_loading);
+	if (retval) {
+		dev_err(f_dev, "%s: device_create_file failed\n", __func__);
+		goto err_del_bin_attr;
 	}
 
 	if (uevent) {
+		dev_set_uevent_suppress(f_dev, false);
+		dev_dbg(f_dev, "firmware: requesting %s\n", fw_priv->fw_id);
 		if (loading_timeout > 0)
 			mod_timer(&fw_priv->timeout,
 				  round_jiffies_up(jiffies +
@@ -586,6 +571,14 @@ static int _request_firmware(const struct firmware *firmware,
 out:
 	usermodehelper_read_unlock();
 	return retval;
+
+err_del_bin_attr:
+	device_remove_bin_file(f_dev, &firmware_attr_data);
+err_del_dev:
+	device_del(f_dev);
+err_put_dev:
+	put_device(f_dev);
+	goto out;
 }
 
 /**
@@ -607,13 +600,15 @@ int
 request_firmware(const struct firmware **firmware_p, const char *name,
                  struct device *device)
 {
+	struct firmware_priv *fw_priv;
 	int ret;
 
-	ret = _request_firmware_prepare(firmware_p, name, device);
-	if (ret <= 0)
-		return ret;
+	fw_priv = _request_firmware_prepare(firmware_p, name, device, true,
+					    false);
+	if (IS_ERR_OR_NULL(fw_priv))
+		return PTR_RET(fw_priv);
 
-	ret = _request_firmware(*firmware_p, name, device, true, false);
+	ret = _request_firmware_load(fw_priv, true);
 	if (ret)
 		_request_firmware_cleanup(firmware_p);
 
@@ -648,6 +643,7 @@ static int request_firmware_work_func(void *arg)
 {
 	struct firmware_work *fw_work = arg;
 	const struct firmware *fw;
+	struct firmware_priv *fw_priv;
 	int ret;
 
 	if (!arg) {
@@ -655,15 +651,18 @@ static int request_firmware_work_func(void *arg)
 		return 0;
 	}
 
-	ret = _request_firmware_prepare(&fw, fw_work->name, fw_work->device);
-	if (ret <= 0)
-		return ret;
+	fw_priv = _request_firmware_prepare(&fw, fw_work->name, fw_work->device,
+			fw_work->uevent, true);
+	if (IS_ERR_OR_NULL(fw_priv)) {
+		ret = PTR_RET(fw_priv);
+		goto out;
+	}
 
-	ret = _request_firmware(fw, fw_work->name, fw_work->device,
-				fw_work->uevent, true);
+	ret = _request_firmware_load(fw_priv, fw_work->uevent);
 	if (ret)
 		_request_firmware_cleanup(&fw);
 
+out:
 	fw_work->cont(fw, fw_work->context);
 
 	module_put(fw_work->module);

-- 
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.


^ permalink raw reply related	[flat|nested] 111+ messages in thread

* Re: [PATCH 6/6] PM / Sleep: Mitigate race between the freezer and request_firmware()
  2012-03-25 22:04                                           ` [PATCH 6/6] PM / Sleep: Mitigate race between the freezer and request_firmware() Rafael J. Wysocki
@ 2012-03-26 18:16                                             ` Stephen Boyd
  2012-03-26 20:06                                               ` Rafael J. Wysocki
  0 siblings, 1 reply; 111+ messages in thread
From: Stephen Boyd @ 2012-03-26 18:16 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: linux-kernel, Linus Torvalds, Saravana Kannan, Kay Sievers,
	Greg KH, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list

On 03/25/12 15:04, Rafael J. Wysocki wrote:
> Index: linux/kernel/power/process.c
> ===================================================================
> --- linux.orig/kernel/power/process.c
> +++ linux/kernel/power/process.c
> @@ -135,6 +135,7 @@ int freeze_processes(void)
>  	error = try_to_freeze_tasks(true);
>  	if (!error) {
>  		printk("done.");
> +		__usermodehelper_reset(UMH_DISABLED);
>  		oom_killer_disable();
>  	}
>  	printk("\n");

nitpick: This doesn't seem to be doing a reset, more like a set. Perhaps
this function should be called __usermodehelper_set()?

-- 
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.


^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH 2/6] firmware_class: Split _request_firmware() into three functions
  2012-03-26 18:15                                             ` Stephen Boyd
@ 2012-03-26 18:21                                               ` Stephen Boyd
  2012-03-26 20:12                                                 ` Rafael J. Wysocki
  2012-03-26 20:36                                               ` Rafael J. Wysocki
  1 sibling, 1 reply; 111+ messages in thread
From: Stephen Boyd @ 2012-03-26 18:21 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: linux-kernel, Linus Torvalds, Saravana Kannan, Kay Sievers,
	Greg KH, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list

On 03/26/12 11:15, Stephen Boyd wrote:
> On 03/25/12 15:01, Rafael J. Wysocki wrote:
>>  drivers/base/firmware_class.c |   57 +++++++++++++++++++++++++++++-------------
>>  1 file changed, 40 insertions(+), 17 deletions(-)
>>
>> Index: linux/drivers/base/firmware_class.c
>> ===================================================================
>> --- linux.orig/drivers/base/firmware_class.c
>> +++ linux/drivers/base/firmware_class.c
>> @@ -435,7 +435,7 @@ static void firmware_class_timeout(u_lon
>>  }
>>  
>>  static struct firmware_priv *
>> -fw_create_instance(struct firmware *firmware, const char *fw_name,
>> +fw_create_instance(const struct firmware *firmware, const char *fw_name,
>>  		   struct device *device, bool uevent, bool nowait)
>>  {
>>  	struct firmware_priv *fw_priv;
>> @@ -449,7 +449,7 @@ fw_create_instance(struct firmware *firm
>>  		goto err_out;
>>  	}
>>  
>> -	fw_priv->fw = firmware;
>> +	fw_priv->fw = (struct firmware *)firmware;
>>  	fw_priv->nowait = nowait;
>>  	strcpy(fw_priv->fw_id, fw_name);
>>  	init_completion(&fw_priv->completion);
> Can we avoid this cast? If we do some parts of fw_create_instance()
> during the setup phase I think we can avoid it.
>

Oops. With the other patch you can squash this in to do what I
originally talked about.

-----8<-----
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index fbe98a8..113d37d 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -435,7 +435,7 @@ static void firmware_class_timeout(u_long data)
 }
 
 static struct firmware_priv *
-fw_create_instance(const struct firmware *firmware, const char *fw_name,
+fw_create_instance(struct firmware *firmware, const char *fw_name,
                   struct device *device, bool uevent, bool nowait)
 {
        struct firmware_priv *fw_priv;
@@ -447,7 +447,7 @@ fw_create_instance(const struct firmware *firmware, const char *fw_name,
                return ERR_PTR(-ENOMEM);
        }
 
-       fw_priv->fw = (struct firmware *)firmware;
+       fw_priv->fw = firmware;
        fw_priv->nowait = nowait;
        strcpy(fw_priv->fw_id, fw_name);
        init_completion(&fw_priv->completion);


-- 
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.


^ permalink raw reply related	[flat|nested] 111+ messages in thread

* Re: [PATCH 0/6] firmware_class: Fix problems with usermodehelper test
  2012-03-25 22:00                                         ` [PATCH 0/6] firmware_class: Fix problems with usermodehelper test Rafael J. Wysocki
                                                             ` (5 preceding siblings ...)
  2012-03-25 22:04                                           ` [PATCH 6/6] PM / Sleep: Mitigate race between the freezer and request_firmware() Rafael J. Wysocki
@ 2012-03-26 18:42                                           ` Greg KH
  2012-03-26 20:37                                             ` Rafael J. Wysocki
  2012-03-27 21:28                                           ` [PATCH 1/2] firmware_class: Reorganize fw_create_instance() Stephen Boyd
                                                             ` (2 subsequent siblings)
  9 siblings, 1 reply; 111+ messages in thread
From: Greg KH @ 2012-03-26 18:42 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: linux-kernel, Stephen Boyd, Linus Torvalds, Saravana Kannan,
	Kay Sievers, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list

On Mon, Mar 26, 2012 at 12:00:34AM +0200, Rafael J. Wysocki wrote:
> Hi all,
> 
> The following series of patches fixes two problems with
> request_firmware() and request_firmware_nowait() resulting from commit
> a144c6a6c924aa1da04dd77fb84b89927354fdff
> 
>     PM: Print a warning if firmware is requested when tasks are frozen
> 
> The first problem is that request_firmware_nowait() may fail if it happens
> to run in parallel with system suspend.  It should't fail in such situations
> and that is addressed by the first three patches (that code has been discussed
> with Linus at al already).
> 
> The second issue is that request_firmware() may be called in a thread which
> isn't related to system suspend and if suspend happens exactly at that time,
> request_firmware() will fail (and print a scary warning), although it shouldn't.
> This problem is addressed by the remaining three patches, which are new.

At first glance, they all look good to me, thanks for doing this work:
	Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

I'm guessing this will go in through one of your trees, right?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH 6/6] PM / Sleep: Mitigate race between the freezer and request_firmware()
  2012-03-26 18:16                                             ` Stephen Boyd
@ 2012-03-26 20:06                                               ` Rafael J. Wysocki
  2012-03-27 21:25                                                 ` Stephen Boyd
  0 siblings, 1 reply; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-26 20:06 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: linux-kernel, Linus Torvalds, Saravana Kannan, Kay Sievers,
	Greg KH, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list

On Monday, March 26, 2012, Stephen Boyd wrote:
> On 03/25/12 15:04, Rafael J. Wysocki wrote:
> > Index: linux/kernel/power/process.c
> > ===================================================================
> > --- linux.orig/kernel/power/process.c
> > +++ linux/kernel/power/process.c
> > @@ -135,6 +135,7 @@ int freeze_processes(void)
> >  	error = try_to_freeze_tasks(true);
> >  	if (!error) {
> >  		printk("done.");
> > +		__usermodehelper_reset(UMH_DISABLED);
> >  		oom_killer_disable();
> >  	}
> >  	printk("\n");
> 
> nitpick: This doesn't seem to be doing a reset, more like a set. Perhaps
> this function should be called __usermodehelper_set()?

Yes, you are right.  I changed that before, but somehow managed to send an old
patch.  The new version follows.

Thanks,
Rafael

---
From: Rafael J. Wysocki <rjw@sisk.pl>
Subject: PM / Sleep: Mitigate race between the freezer and request_firmware()

There is a race condition between the freezer and request_firmware()
such that if request_firmware() is run on one CPU and
freeze_processes() is run on another CPU and usermodehelper_disable()
called by it succeeds to grab umhelper_sem for writing before
usermodehelper_read_trylock() called from request_firmware()
acquires it for reading, the request_firmware() will fail and
trigger a WARN_ON() complaining that it was called at a wrong time.
However, in fact, it wasn't called at a wrong time and
freeze_processes() simply happened to be executed simultaneously.

To avoid this race, at least in some cases, modify
usermodehelper_read_trylock() so that it doesn't fail if the
freezing of tasks has just started and hasn't been completed yet.
Instead, during the freezing of tasks, it will try to freeze the
task that has called it so that it can wait until user space is
thawed without triggering the scary warning.

For this purpose, change usermodehelper_disabled so that it can
take three different values, UMH_ENABLED (0), UMH_FREEZING and
UMH_DISABLED.  The first one means that usermode helpers are
enabled, the last one means "hard disable" (i.e. the system is not
ready for usermode helpers to be used) and the second one
is reserved for the freezer.  Namely, when freeze_processes() is
started, it sets usermodehelper_disabled to UMH_FREEZING which
tells usermodehelper_read_trylock() that it shouldn't fail just
yet and should call try_to_freeze() if woken up and cannot
return immediately.  This way all freezable tasks that happen
to call request_firmware() right before freeze_processes() is
started and lose the race for umhelper_sem with it will be
frozen and will sleep until thaw_processes() unsets
usermodehelper_disabled.  [For the non-freezable callers of
request_firmware() the race for umhelper_sem against
freeze_processes() is unfortunately unavoidable.]

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 include/linux/kmod.h   |   21 +++++++++++++++++++--
 kernel/kmod.c          |   47 +++++++++++++++++++++++++++++++++++++----------
 kernel/power/process.c |    3 ++-
 3 files changed, 58 insertions(+), 13 deletions(-)

Index: linux/include/linux/kmod.h
===================================================================
--- linux.orig/include/linux/kmod.h
+++ linux/include/linux/kmod.h
@@ -112,10 +112,27 @@ call_usermodehelper(char *path, char **a
 
 extern struct ctl_table usermodehelper_table[];
 
+enum umh_disable_depth {
+	UMH_ENABLED = 0,
+	UMH_FREEZING,
+	UMH_DISABLED,
+};
+
 extern void usermodehelper_init(void);
 
-extern int usermodehelper_disable(void);
-extern void usermodehelper_enable(void);
+extern int __usermodehelper_disable(enum umh_disable_depth depth);
+extern void __usermodehelper_set_disable_depth(enum umh_disable_depth depth);
+
+static inline int usermodehelper_disable(void)
+{
+	return __usermodehelper_disable(UMH_DISABLED);
+}
+
+static inline void usermodehelper_enable(void)
+{
+	__usermodehelper_set_disable_depth(UMH_ENABLED);
+}
+
 extern int usermodehelper_read_trylock(void);
 extern long usermodehelper_read_lock_wait(long timeout);
 extern void usermodehelper_read_unlock(void);
Index: linux/kernel/kmod.c
===================================================================
--- linux.orig/kernel/kmod.c
+++ linux/kernel/kmod.c
@@ -279,7 +279,7 @@ static void __call_usermodehelper(struct
  * land has been frozen during a system-wide hibernation or suspend operation).
  * Should always be manipulated under umhelper_sem acquired for write.
  */
-static int usermodehelper_disabled = 1;
+static enum umh_disable_depth usermodehelper_disabled = UMH_DISABLED;
 
 /* Number of helpers running */
 static atomic_t running_helpers = ATOMIC_INIT(0);
@@ -304,13 +304,30 @@ static DECLARE_WAIT_QUEUE_HEAD(usermodeh
 
 int usermodehelper_read_trylock(void)
 {
+	DEFINE_WAIT(wait);
 	int ret = 0;
 
 	down_read(&umhelper_sem);
-	if (usermodehelper_disabled) {
+	for (;;) {
+		prepare_to_wait(&usermodehelper_disabled_waitq, &wait,
+				TASK_INTERRUPTIBLE);
+		if (!usermodehelper_disabled)
+			break;
+
+		if (usermodehelper_disabled == UMH_DISABLED)
+			ret = -EAGAIN;
+
 		up_read(&umhelper_sem);
-		ret = -EAGAIN;
+
+		if (ret)
+			break;
+
+		schedule();
+		try_to_freeze();
+
+		down_read(&umhelper_sem);
 	}
+	finish_wait(&usermodehelper_disabled_waitq, &wait);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(usermodehelper_read_trylock);
@@ -349,25 +366,35 @@ void usermodehelper_read_unlock(void)
 EXPORT_SYMBOL_GPL(usermodehelper_read_unlock);
 
 /**
- * usermodehelper_enable - allow new helpers to be started again
+ * __usermodehelper_set_disable_depth - Modify usermodehelper_disabled.
+ * depth: New value to assign to usermodehelper_disabled.
+ *
+ * Change the value of usermodehelper_disabled (under umhelper_sem locked for
+ * writing) and wakeup tasks waiting for it to change.
  */
-void usermodehelper_enable(void)
+void __usermodehelper_set_disable_depth(enum umh_disable_depth depth)
 {
 	down_write(&umhelper_sem);
-	usermodehelper_disabled = 0;
+	usermodehelper_disabled = depth;
 	wake_up(&usermodehelper_disabled_waitq);
 	up_write(&umhelper_sem);
 }
 
 /**
- * usermodehelper_disable - prevent new helpers from being started
+ * __usermodehelper_disable - Prevent new helpers from being started.
+ * @depth: New value to assign to usermodehelper_disabled.
+ *
+ * Set usermodehelper_disabled to @depth and wait for running helpers to exit.
  */
-int usermodehelper_disable(void)
+int __usermodehelper_disable(enum umh_disable_depth depth)
 {
 	long retval;
 
+	if (!depth)
+		return -EINVAL;
+
 	down_write(&umhelper_sem);
-	usermodehelper_disabled = 1;
+	usermodehelper_disabled = depth;
 	up_write(&umhelper_sem);
 
 	/*
@@ -382,7 +409,7 @@ int usermodehelper_disable(void)
 	if (retval)
 		return 0;
 
-	usermodehelper_enable();
+	__usermodehelper_set_disable_depth(UMH_ENABLED);
 	return -EAGAIN;
 }
 
Index: linux/kernel/power/process.c
===================================================================
--- linux.orig/kernel/power/process.c
+++ linux/kernel/power/process.c
@@ -123,7 +123,7 @@ int freeze_processes(void)
 {
 	int error;
 
-	error = usermodehelper_disable();
+	error = __usermodehelper_disable(UMH_FREEZING);
 	if (error)
 		return error;
 
@@ -135,6 +135,7 @@ int freeze_processes(void)
 	error = try_to_freeze_tasks(true);
 	if (!error) {
 		printk("done.");
+		__usermodehelper_set_disable_depth(UMH_DISABLED);
 		oom_killer_disable();
 	}
 	printk("\n");

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH 2/6] firmware_class: Split _request_firmware() into three functions
  2012-03-26 18:21                                               ` Stephen Boyd
@ 2012-03-26 20:12                                                 ` Rafael J. Wysocki
  2012-03-26 20:31                                                   ` Stephen Boyd
  0 siblings, 1 reply; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-26 20:12 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: linux-kernel, Linus Torvalds, Saravana Kannan, Kay Sievers,
	Greg KH, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list

On Monday, March 26, 2012, Stephen Boyd wrote:
> On 03/26/12 11:15, Stephen Boyd wrote:
> > On 03/25/12 15:01, Rafael J. Wysocki wrote:
> >>  drivers/base/firmware_class.c |   57 +++++++++++++++++++++++++++++-------------
> >>  1 file changed, 40 insertions(+), 17 deletions(-)
> >>
> >> Index: linux/drivers/base/firmware_class.c
> >> ===================================================================
> >> --- linux.orig/drivers/base/firmware_class.c
> >> +++ linux/drivers/base/firmware_class.c
> >> @@ -435,7 +435,7 @@ static void firmware_class_timeout(u_lon
> >>  }
> >>  
> >>  static struct firmware_priv *
> >> -fw_create_instance(struct firmware *firmware, const char *fw_name,
> >> +fw_create_instance(const struct firmware *firmware, const char *fw_name,
> >>  		   struct device *device, bool uevent, bool nowait)
> >>  {
> >>  	struct firmware_priv *fw_priv;
> >> @@ -449,7 +449,7 @@ fw_create_instance(struct firmware *firm
> >>  		goto err_out;
> >>  	}
> >>  
> >> -	fw_priv->fw = firmware;
> >> +	fw_priv->fw = (struct firmware *)firmware;
> >>  	fw_priv->nowait = nowait;
> >>  	strcpy(fw_priv->fw_id, fw_name);
> >>  	init_completion(&fw_priv->completion);
> > Can we avoid this cast? If we do some parts of fw_create_instance()
> > during the setup phase I think we can avoid it.
> >
> 
> Oops. With the other patch you can squash this in to do what I
> originally talked about.
> 
> -----8<-----
> diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
> index fbe98a8..113d37d 100644
> --- a/drivers/base/firmware_class.c
> +++ b/drivers/base/firmware_class.c
> @@ -435,7 +435,7 @@ static void firmware_class_timeout(u_long data)
>  }
>  
>  static struct firmware_priv *
> -fw_create_instance(const struct firmware *firmware, const char *fw_name,
> +fw_create_instance(struct firmware *firmware, const char *fw_name,
>                    struct device *device, bool uevent, bool nowait)
>  {
>         struct firmware_priv *fw_priv;
> @@ -447,7 +447,7 @@ fw_create_instance(const struct firmware *firmware, const char *fw_name,
>                 return ERR_PTR(-ENOMEM);
>         }
>  
> -       fw_priv->fw = (struct firmware *)firmware;
> +       fw_priv->fw = firmware;
>         fw_priv->nowait = nowait;
>         strcpy(fw_priv->fw_id, fw_name);
>         init_completion(&fw_priv->completion);

Hmm, what other patch?  The one you send previously?

Rafael

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH 2/6] firmware_class: Split _request_firmware() into three functions
  2012-03-26 20:12                                                 ` Rafael J. Wysocki
@ 2012-03-26 20:31                                                   ` Stephen Boyd
  0 siblings, 0 replies; 111+ messages in thread
From: Stephen Boyd @ 2012-03-26 20:31 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: linux-kernel, Linus Torvalds, Saravana Kannan, Kay Sievers,
	Greg KH, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list

On 03/26/12 13:12, Rafael J. Wysocki wrote:
> Hmm, what other patch?  The one you send previously?

Yes.

-- 
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.


^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH 2/6] firmware_class: Split _request_firmware() into three functions
  2012-03-26 18:15                                             ` Stephen Boyd
  2012-03-26 18:21                                               ` Stephen Boyd
@ 2012-03-26 20:36                                               ` Rafael J. Wysocki
  2012-03-27 21:35                                                 ` Stephen Boyd
  1 sibling, 1 reply; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-26 20:36 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: linux-kernel, Linus Torvalds, Saravana Kannan, Kay Sievers,
	Greg KH, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list

On Monday, March 26, 2012, Stephen Boyd wrote:
> On 03/25/12 15:01, Rafael J. Wysocki wrote:
> >  drivers/base/firmware_class.c |   57 +++++++++++++++++++++++++++++-------------
> >  1 file changed, 40 insertions(+), 17 deletions(-)
> >
> > Index: linux/drivers/base/firmware_class.c
> > ===================================================================
> > --- linux.orig/drivers/base/firmware_class.c
> > +++ linux/drivers/base/firmware_class.c
> > @@ -435,7 +435,7 @@ static void firmware_class_timeout(u_lon
> >  }
> >  
> >  static struct firmware_priv *
> > -fw_create_instance(struct firmware *firmware, const char *fw_name,
> > +fw_create_instance(const struct firmware *firmware, const char *fw_name,
> >  		   struct device *device, bool uevent, bool nowait)
> >  {
> >  	struct firmware_priv *fw_priv;
> > @@ -449,7 +449,7 @@ fw_create_instance(struct firmware *firm
> >  		goto err_out;
> >  	}
> >  
> > -	fw_priv->fw = firmware;
> > +	fw_priv->fw = (struct firmware *)firmware;
> >  	fw_priv->nowait = nowait;
> >  	strcpy(fw_priv->fw_id, fw_name);
> >  	init_completion(&fw_priv->completion);
> 
> Can we avoid this cast? If we do some parts of fw_create_instance()
> during the setup phase I think we can avoid it.

Yes, we can, but I'm not sure I'd like to make so many changes at once.

> > @@ -639,8 +655,15 @@ static int request_firmware_work_func(vo
> >  		return 0;
> >  	}
> >  
> > -	ret = _request_firmware(&fw, fw_work->name, fw_work->device,
> > +	ret = _request_firmware_prepare(&fw, fw_work->name, fw_work->device);
> > +	if (ret <= 0)
> > +		return ret;
> 
> This needs to jump to the cont function so that users know loading
> failed or that the firmware was builtin.

You're right, sorry.  That should have been

	if (ret > 0) {
		ret = _request_firmware(fw, fw_work->name, fw_work->device,
			fw_work->uevent, true);
		if (ret)
			_request_firmware_cleanup(&fw);
	}

but actually using a jump makes the next patch look better.

Updated patch is appended.

> > +
> > +	ret = _request_firmware(fw, fw_work->name, fw_work->device,
> >  				fw_work->uevent, true);
> > +	if (ret)
> > +		_request_firmware_cleanup(&fw);
> > +
> >  	fw_work->cont(fw, fw_work->context);
> >  
> >  	module_put(fw_work->module);
> >
> 
> Here's a compile only tested patch on top. The idea is return a fw_priv
> pointer from the setup function and use that to indicate failure (error
> pointer), builtin (NULL) or loadable (non-NULL). Then we can move all
> the uevent/device stuff to the loading phase

Good.  Can you please send that as a patch on top of the whole series?
I'd like to avoid mixing your code with mine.  Also, I'd rather avoid
invalidating tests that have been carried out already with this series by
adding changes in the middle of it.

> ----8<-----
> diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
> index 5db254d..fbe98a8 100644
> --- a/drivers/base/firmware_class.c
> +++ b/drivers/base/firmware_class.c
> @@ -440,13 +440,11 @@ fw_create_instance(const struct firmware *firmware, const char *fw_name,
>  {
>  	struct firmware_priv *fw_priv;
>  	struct device *f_dev;
> -	int error;
>  
>  	fw_priv = kzalloc(sizeof(*fw_priv) + strlen(fw_name) + 1 , GFP_KERNEL);
>  	if (!fw_priv) {
>  		dev_err(device, "%s: kmalloc failed\n", __func__);
> -		error = -ENOMEM;
> -		goto err_out;
> +		return ERR_PTR(-ENOMEM);
>  	}
>  
>  	fw_priv->fw = (struct firmware *)firmware;
> @@ -463,42 +461,7 @@ fw_create_instance(const struct firmware *firmware, const char *fw_name,
>  	f_dev->parent = device;
>  	f_dev->class = &firmware_class;
>  
> -	dev_set_uevent_suppress(f_dev, true);
> -
> -	/* Need to pin this module until class device is destroyed */
> -	__module_get(THIS_MODULE);
> -
> -	error = device_add(f_dev);
> -	if (error) {
> -		dev_err(device, "%s: device_register failed\n", __func__);
> -		goto err_put_dev;
> -	}
> -
> -	error = device_create_bin_file(f_dev, &firmware_attr_data);
> -	if (error) {
> -		dev_err(device, "%s: sysfs_create_bin_file failed\n", __func__);
> -		goto err_del_dev;
> -	}
> -
> -	error = device_create_file(f_dev, &dev_attr_loading);
> -	if (error) {
> -		dev_err(device, "%s: device_create_file failed\n", __func__);
> -		goto err_del_bin_attr;
> -	}
> -
> -	if (uevent)
> -		dev_set_uevent_suppress(f_dev, false);
> -
>  	return fw_priv;
> -
> -err_del_bin_attr:
> -	device_remove_bin_file(f_dev, &firmware_attr_data);
> -err_del_dev:
> -	device_del(f_dev);
> -err_put_dev:
> -	put_device(f_dev);
> -err_out:
> -	return ERR_PTR(error);
>  }
>  
>  static void fw_destroy_instance(struct firmware_priv *fw_priv)
> @@ -510,27 +473,34 @@ static void fw_destroy_instance(struct firmware_priv *fw_priv)
>  	device_unregister(f_dev);
>  }
>  
> -static int _request_firmware_prepare(const struct firmware **firmware_p,
> -				     const char *name, struct device *device)
> +static struct firmware_priv *
> +_request_firmware_prepare(const struct firmware **firmware_p, const char *name,
> +			  struct device *device, bool uevent, bool nowait)
>  {
>  	struct firmware *firmware;
> +	struct firmware_priv *fw_priv;
>  
>  	if (!firmware_p)
> -		return -EINVAL;
> +		return ERR_PTR(-EINVAL);
>  
>  	*firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL);
>  	if (!firmware) {
>  		dev_err(device, "%s: kmalloc(struct firmware) failed\n",
>  			__func__);
> -		return -ENOMEM;
> +		return ERR_PTR(-ENOMEM);
>  	}
>  
>  	if (fw_get_builtin_firmware(firmware, name)) {
>  		dev_dbg(device, "firmware: using built-in firmware %s\n", name);
> -		return 0;
> +		return NULL;
>  	}
>  
> -	return 1;
> +	fw_priv = fw_create_instance(firmware, name, device, uevent, nowait);
> +	if (IS_ERR(fw_priv)) {
> +		release_firmware(firmware);
> +		*firmware_p = NULL;
> +	}
> +	return fw_priv;
>  }
>  
>  static void _request_firmware_cleanup(const struct firmware **firmware_p)
> @@ -539,29 +509,44 @@ static void _request_firmware_cleanup(const struct firmware **firmware_p)
>  	*firmware_p = NULL;
>  }
>  
> -static int _request_firmware(const struct firmware *firmware,
> -			     const char *name, struct device *device,
> -			     bool uevent, bool nowait)
> +static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent)
>  {
> -	struct firmware_priv *fw_priv;
>  	int retval;
> +	struct device *f_dev = &fw_priv->dev;
>  
>  	retval = usermodehelper_read_trylock();
>  	if (WARN_ON(retval)) {
> -		dev_err(device, "firmware: %s will not be loaded\n", name);
> +		dev_err(f_dev, "firmware: %s will not be loaded\n",
> +				fw_priv->fw_id);
>  		return retval;
>  	}
>  
> -	if (uevent)
> -		dev_dbg(device, "firmware: requesting %s\n", name);
> +	dev_set_uevent_suppress(f_dev, true);
>  
> -	fw_priv = fw_create_instance(firmware, name, device, uevent, nowait);
> -	if (IS_ERR(fw_priv)) {
> -		retval = PTR_ERR(fw_priv);
> -		goto out;
> +	/* Need to pin this module until class device is destroyed */
> +	__module_get(THIS_MODULE);
> +
> +	retval = device_add(f_dev);
> +	if (retval) {
> +		dev_err(f_dev, "%s: device_register failed\n", __func__);
> +		goto err_put_dev;
> +	}
> +
> +	retval = device_create_bin_file(f_dev, &firmware_attr_data);
> +	if (retval) {
> +		dev_err(f_dev, "%s: sysfs_create_bin_file failed\n", __func__);
> +		goto err_del_dev;
> +	}
> +
> +	retval = device_create_file(f_dev, &dev_attr_loading);
> +	if (retval) {
> +		dev_err(f_dev, "%s: device_create_file failed\n", __func__);
> +		goto err_del_bin_attr;
>  	}
>  
>  	if (uevent) {
> +		dev_set_uevent_suppress(f_dev, false);
> +		dev_dbg(f_dev, "firmware: requesting %s\n", fw_priv->fw_id);
>  		if (loading_timeout > 0)
>  			mod_timer(&fw_priv->timeout,
>  				  round_jiffies_up(jiffies +
> @@ -586,6 +571,14 @@ static int _request_firmware(const struct firmware *firmware,
>  out:
>  	usermodehelper_read_unlock();
>  	return retval;
> +
> +err_del_bin_attr:
> +	device_remove_bin_file(f_dev, &firmware_attr_data);
> +err_del_dev:
> +	device_del(f_dev);
> +err_put_dev:
> +	put_device(f_dev);
> +	goto out;
>  }
>  
>  /**
> @@ -607,13 +600,15 @@ int
>  request_firmware(const struct firmware **firmware_p, const char *name,
>                   struct device *device)
>  {
> +	struct firmware_priv *fw_priv;
>  	int ret;
>  
> -	ret = _request_firmware_prepare(firmware_p, name, device);
> -	if (ret <= 0)
> -		return ret;
> +	fw_priv = _request_firmware_prepare(firmware_p, name, device, true,
> +					    false);
> +	if (IS_ERR_OR_NULL(fw_priv))
> +		return PTR_RET(fw_priv);
>  
> -	ret = _request_firmware(*firmware_p, name, device, true, false);
> +	ret = _request_firmware_load(fw_priv, true);
>  	if (ret)
>  		_request_firmware_cleanup(firmware_p);
>  
> @@ -648,6 +643,7 @@ static int request_firmware_work_func(void *arg)
>  {
>  	struct firmware_work *fw_work = arg;
>  	const struct firmware *fw;
> +	struct firmware_priv *fw_priv;
>  	int ret;
>  
>  	if (!arg) {
> @@ -655,15 +651,18 @@ static int request_firmware_work_func(void *arg)
>  		return 0;
>  	}
>  
> -	ret = _request_firmware_prepare(&fw, fw_work->name, fw_work->device);
> -	if (ret <= 0)
> -		return ret;
> +	fw_priv = _request_firmware_prepare(&fw, fw_work->name, fw_work->device,
> +			fw_work->uevent, true);
> +	if (IS_ERR_OR_NULL(fw_priv)) {
> +		ret = PTR_RET(fw_priv);
> +		goto out;
> +	}
>  
> -	ret = _request_firmware(fw, fw_work->name, fw_work->device,
> -				fw_work->uevent, true);
> +	ret = _request_firmware_load(fw_priv, fw_work->uevent);
>  	if (ret)
>  		_request_firmware_cleanup(&fw);
>  
> +out:
>  	fw_work->cont(fw, fw_work->context);
>  
>  	module_put(fw_work->module);

---
From: Rafael J. Wysocki <rjw@sisk.pl>
Subject: firmware_class: Split _request_firmware() into three functions, v2

Split _request_firmware() into three functions,
_request_firmware_prepare() doing preparatory work that need not be
done under umhelper_sem, _request_firmware_cleanup() doing the
post-error cleanup and _request_firmware() carrying out the remaining
operations.

This change is requisite for moving the acquisition of umhelper_sem
from _request_firmware() to the callers, which is going to be done
subsequently.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 drivers/base/firmware_class.c |   58 +++++++++++++++++++++++++++++-------------
 1 file changed, 41 insertions(+), 17 deletions(-)

Index: linux/drivers/base/firmware_class.c
===================================================================
--- linux.orig/drivers/base/firmware_class.c
+++ linux/drivers/base/firmware_class.c
@@ -435,7 +435,7 @@ static void firmware_class_timeout(u_lon
 }
 
 static struct firmware_priv *
-fw_create_instance(struct firmware *firmware, const char *fw_name,
+fw_create_instance(const struct firmware *firmware, const char *fw_name,
 		   struct device *device, bool uevent, bool nowait)
 {
 	struct firmware_priv *fw_priv;
@@ -449,7 +449,7 @@ fw_create_instance(struct firmware *firm
 		goto err_out;
 	}
 
-	fw_priv->fw = firmware;
+	fw_priv->fw = (struct firmware *)firmware;
 	fw_priv->nowait = nowait;
 	strcpy(fw_priv->fw_id, fw_name);
 	init_completion(&fw_priv->completion);
@@ -510,13 +510,10 @@ static void fw_destroy_instance(struct f
 	device_unregister(f_dev);
 }
 
-static int _request_firmware(const struct firmware **firmware_p,
-			     const char *name, struct device *device,
-			     bool uevent, bool nowait)
+static int _request_firmware_prepare(const struct firmware **firmware_p,
+				     const char *name, struct device *device)
 {
-	struct firmware_priv *fw_priv;
 	struct firmware *firmware;
-	int retval = 0;
 
 	if (!firmware_p)
 		return -EINVAL;
@@ -533,10 +530,26 @@ static int _request_firmware(const struc
 		return 0;
 	}
 
+	return 1;
+}
+
+static void _request_firmware_cleanup(const struct firmware **firmware_p)
+{
+	release_firmware(*firmware_p);
+	*firmware_p = NULL;
+}
+
+static int _request_firmware(const struct firmware *firmware,
+			     const char *name, struct device *device,
+			     bool uevent, bool nowait)
+{
+	struct firmware_priv *fw_priv;
+	int retval;
+
 	retval = usermodehelper_read_trylock();
 	if (WARN_ON(retval)) {
 		dev_err(device, "firmware: %s will not be loaded\n", name);
-		goto out_nolock;
+		return retval;
 	}
 
 	if (uevent)
@@ -572,13 +585,6 @@ static int _request_firmware(const struc
 
 out:
 	usermodehelper_read_unlock();
-
-out_nolock:
-	if (retval) {
-		release_firmware(firmware);
-		*firmware_p = NULL;
-	}
-
 	return retval;
 }
 
@@ -601,7 +607,17 @@ int
 request_firmware(const struct firmware **firmware_p, const char *name,
                  struct device *device)
 {
-        return _request_firmware(firmware_p, name, device, true, false);
+	int ret;
+
+	ret = _request_firmware_prepare(firmware_p, name, device);
+	if (ret <= 0)
+		return ret;
+
+	ret = _request_firmware(*firmware_p, name, device, true, false);
+	if (ret)
+		_request_firmware_cleanup(firmware_p);
+
+	return ret;
 }
 
 /**
@@ -639,8 +655,16 @@ static int request_firmware_work_func(vo
 		return 0;
 	}
 
-	ret = _request_firmware(&fw, fw_work->name, fw_work->device,
+	ret = _request_firmware_prepare(&fw, fw_work->name, fw_work->device);
+	if (ret <= 0)
+		goto out;
+
+	ret = _request_firmware(fw, fw_work->name, fw_work->device,
 				fw_work->uevent, true);
+	if (ret)
+		_request_firmware_cleanup(&fw);
+
+ out:
 	fw_work->cont(fw, fw_work->context);
 
 	module_put(fw_work->module);

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH 0/6] firmware_class: Fix problems with usermodehelper test
  2012-03-26 18:42                                           ` [PATCH 0/6] firmware_class: Fix problems with usermodehelper test Greg KH
@ 2012-03-26 20:37                                             ` Rafael J. Wysocki
  0 siblings, 0 replies; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-26 20:37 UTC (permalink / raw)
  To: Greg KH
  Cc: linux-kernel, Stephen Boyd, Linus Torvalds, Saravana Kannan,
	Kay Sievers, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list

On Monday, March 26, 2012, Greg KH wrote:
> On Mon, Mar 26, 2012 at 12:00:34AM +0200, Rafael J. Wysocki wrote:
> > Hi all,
> > 
> > The following series of patches fixes two problems with
> > request_firmware() and request_firmware_nowait() resulting from commit
> > a144c6a6c924aa1da04dd77fb84b89927354fdff
> > 
> >     PM: Print a warning if firmware is requested when tasks are frozen
> > 
> > The first problem is that request_firmware_nowait() may fail if it happens
> > to run in parallel with system suspend.  It should't fail in such situations
> > and that is addressed by the first three patches (that code has been discussed
> > with Linus at al already).
> > 
> > The second issue is that request_firmware() may be called in a thread which
> > isn't related to system suspend and if suspend happens exactly at that time,
> > request_firmware() will fail (and print a scary warning), although it shouldn't.
> > This problem is addressed by the remaining three patches, which are new.
> 
> At first glance, they all look good to me, thanks for doing this work:
> 	Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

Thanks!

> I'm guessing this will go in through one of your trees, right?

That's correct.

Thanks,
Rafael

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH 6/6] PM / Sleep: Mitigate race between the freezer and request_firmware()
  2012-03-26 20:06                                               ` Rafael J. Wysocki
@ 2012-03-27 21:25                                                 ` Stephen Boyd
  2012-03-27 21:37                                                   ` Rafael J. Wysocki
  0 siblings, 1 reply; 111+ messages in thread
From: Stephen Boyd @ 2012-03-27 21:25 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: linux-kernel, Linus Torvalds, Saravana Kannan, Kay Sievers,
	Greg KH, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list

On 03/26/12 13:06, Rafael J. Wysocki wrote:
> On Monday, March 26, 2012, Stephen Boyd wrote:
>> On 03/25/12 15:04, Rafael J. Wysocki wrote:
>>> Index: linux/kernel/power/process.c
>>> ===================================================================
>>> --- linux.orig/kernel/power/process.c
>>> +++ linux/kernel/power/process.c
>>> @@ -135,6 +135,7 @@ int freeze_processes(void)
>>>  	error = try_to_freeze_tasks(true);
>>>  	if (!error) {
>>>  		printk("done.");
>>> +		__usermodehelper_reset(UMH_DISABLED);
>>>  		oom_killer_disable();
>>>  	}
>>>  	printk("\n");
>> nitpick: This doesn't seem to be doing a reset, more like a set. Perhaps
>> this function should be called __usermodehelper_set()?
> Yes, you are right.  I changed that before, but somehow managed to send an old
> patch.  The new version follows.

Looks good. Thanks.

> ---
> From: Rafael J. Wysocki <rjw@sisk.pl>
> Subject: PM / Sleep: Mitigate race between the freezer and request_firmware()
>
> There is a race condition between the freezer and request_firmware()
> such that if request_firmware() is run on one CPU and
> freeze_processes() is run on another CPU and usermodehelper_disable()
> called by it succeeds to grab umhelper_sem for writing before
> usermodehelper_read_trylock() called from request_firmware()
> acquires it for reading, the request_firmware() will fail and
> trigger a WARN_ON() complaining that it was called at a wrong time.
> However, in fact, it wasn't called at a wrong time and
> freeze_processes() simply happened to be executed simultaneously.
>
> To avoid this race, at least in some cases, modify
> usermodehelper_read_trylock() so that it doesn't fail if the
> freezing of tasks has just started and hasn't been completed yet.
> Instead, during the freezing of tasks, it will try to freeze the
> task that has called it so that it can wait until user space is
> thawed without triggering the scary warning.
>
> For this purpose, change usermodehelper_disabled so that it can
> take three different values, UMH_ENABLED (0), UMH_FREEZING and
> UMH_DISABLED.  The first one means that usermode helpers are
> enabled, the last one means "hard disable" (i.e. the system is not
> ready for usermode helpers to be used) and the second one
> is reserved for the freezer.  Namely, when freeze_processes() is
> started, it sets usermodehelper_disabled to UMH_FREEZING which
> tells usermodehelper_read_trylock() that it shouldn't fail just
> yet and should call try_to_freeze() if woken up and cannot
> return immediately.  This way all freezable tasks that happen
> to call request_firmware() right before freeze_processes() is
> started and lose the race for umhelper_sem with it will be
> frozen and will sleep until thaw_processes() unsets
> usermodehelper_disabled.  [For the non-freezable callers of
> request_firmware() the race for umhelper_sem against
> freeze_processes() is unfortunately unavoidable.]

Reported-by: Stephen Boyd <sboyd@codeaurora.org>

> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
> ---
>

-- 
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.


^ permalink raw reply	[flat|nested] 111+ messages in thread

* [PATCH 1/2] firmware_class: Reorganize fw_create_instance()
  2012-03-25 22:00                                         ` [PATCH 0/6] firmware_class: Fix problems with usermodehelper test Rafael J. Wysocki
                                                             ` (6 preceding siblings ...)
  2012-03-26 18:42                                           ` [PATCH 0/6] firmware_class: Fix problems with usermodehelper test Greg KH
@ 2012-03-27 21:28                                           ` Stephen Boyd
  2012-03-27 21:47                                             ` Rafael J. Wysocki
  2012-03-27 21:28                                           ` [PATCH 2/2] firmware_class: Move request_firmware_nowait() to workqueues Stephen Boyd
  2012-03-28 21:19                                           ` [PATCH v2 0/8] firmware_class: Fix problems with usermodehelper test Rafael J. Wysocki
  9 siblings, 1 reply; 111+ messages in thread
From: Stephen Boyd @ 2012-03-27 21:28 UTC (permalink / raw)
  To: linux-kernel
  Cc: Rafael J. Wysocki, Linus Torvalds, Saravana Kannan, Kay Sievers,
	Greg KH, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list

Recent patches to split up the three phases of request_firmware()
lead to a casting away of const in fw_create_instance(). We can
avoid this cast by splitting up fw_create_instance() a bit.

Make _request_firmware_setup() return a struct fw_priv and use
that struct instead of passing struct firmware to
_request_firmware(). Move the uevent and device file creation
bits to the loading phase and rename the function to
_request_firmware_load() to better reflect its purpose.

Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
---
 drivers/base/firmware_class.c |  135 +++++++++++++++++++----------------------
 1 file changed, 62 insertions(+), 73 deletions(-)

diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 72c644b..ae00a2f 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -440,21 +440,19 @@ static void firmware_class_timeout(u_long data)
 }
 
 static struct firmware_priv *
-fw_create_instance(const struct firmware *firmware, const char *fw_name,
+fw_create_instance(struct firmware *firmware, const char *fw_name,
 		   struct device *device, bool uevent, bool nowait)
 {
 	struct firmware_priv *fw_priv;
 	struct device *f_dev;
-	int error;
 
 	fw_priv = kzalloc(sizeof(*fw_priv) + strlen(fw_name) + 1 , GFP_KERNEL);
 	if (!fw_priv) {
 		dev_err(device, "%s: kmalloc failed\n", __func__);
-		error = -ENOMEM;
-		goto err_out;
+		return ERR_PTR(-ENOMEM);
 	}
 
-	fw_priv->fw = (struct firmware *)firmware;
+	fw_priv->fw = firmware;
 	fw_priv->nowait = nowait;
 	strcpy(fw_priv->fw_id, fw_name);
 	init_completion(&fw_priv->completion);
@@ -468,74 +466,37 @@ fw_create_instance(const struct firmware *firmware, const char *fw_name,
 	f_dev->parent = device;
 	f_dev->class = &firmware_class;
 
-	dev_set_uevent_suppress(f_dev, true);
-
-	/* Need to pin this module until class device is destroyed */
-	__module_get(THIS_MODULE);
-
-	error = device_add(f_dev);
-	if (error) {
-		dev_err(device, "%s: device_register failed\n", __func__);
-		goto err_put_dev;
-	}
-
-	error = device_create_bin_file(f_dev, &firmware_attr_data);
-	if (error) {
-		dev_err(device, "%s: sysfs_create_bin_file failed\n", __func__);
-		goto err_del_dev;
-	}
-
-	error = device_create_file(f_dev, &dev_attr_loading);
-	if (error) {
-		dev_err(device, "%s: device_create_file failed\n", __func__);
-		goto err_del_bin_attr;
-	}
-
-	if (uevent)
-		dev_set_uevent_suppress(f_dev, false);
-
 	return fw_priv;
-
-err_del_bin_attr:
-	device_remove_bin_file(f_dev, &firmware_attr_data);
-err_del_dev:
-	device_del(f_dev);
-err_put_dev:
-	put_device(f_dev);
-err_out:
-	return ERR_PTR(error);
-}
-
-static void fw_destroy_instance(struct firmware_priv *fw_priv)
-{
-	struct device *f_dev = &fw_priv->dev;
-
-	device_remove_file(f_dev, &dev_attr_loading);
-	device_remove_bin_file(f_dev, &firmware_attr_data);
-	device_unregister(f_dev);
 }
 
-static int _request_firmware_prepare(const struct firmware **firmware_p,
-				     const char *name, struct device *device)
+static struct firmware_priv *
+_request_firmware_prepare(const struct firmware **firmware_p, const char *name,
+			  struct device *device, bool uevent, bool nowait)
 {
 	struct firmware *firmware;
+	struct firmware_priv *fw_priv;
 
 	if (!firmware_p)
-		return -EINVAL;
+		return ERR_PTR(-EINVAL);
 
 	*firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL);
 	if (!firmware) {
 		dev_err(device, "%s: kmalloc(struct firmware) failed\n",
 			__func__);
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 	}
 
 	if (fw_get_builtin_firmware(firmware, name)) {
 		dev_dbg(device, "firmware: using built-in firmware %s\n", name);
-		return 0;
+		return NULL;
 	}
 
-	return 1;
+	fw_priv = fw_create_instance(firmware, name, device, uevent, nowait);
+	if (IS_ERR(fw_priv)) {
+		release_firmware(firmware);
+		*firmware_p = NULL;
+	}
+	return fw_priv;
 }
 
 static void _request_firmware_cleanup(const struct firmware **firmware_p)
@@ -544,21 +505,38 @@ static void _request_firmware_cleanup(const struct firmware **firmware_p)
 	*firmware_p = NULL;
 }
 
-static int _request_firmware(const struct firmware *firmware,
-			     const char *name, struct device *device,
-			     bool uevent, bool nowait, long timeout)
+static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent,
+				  long timeout)
 {
-	struct firmware_priv *fw_priv;
 	int retval = 0;
+	struct device *f_dev = &fw_priv->dev;
+
+	dev_set_uevent_suppress(f_dev, true);
 
-	if (uevent)
-		dev_dbg(device, "firmware: requesting %s\n", name);
+	/* Need to pin this module until class device is destroyed */
+	__module_get(THIS_MODULE);
 
-	fw_priv = fw_create_instance(firmware, name, device, uevent, nowait);
-	if (IS_ERR(fw_priv))
-		return PTR_ERR(fw_priv);
+	retval = device_add(f_dev);
+	if (retval) {
+		dev_err(f_dev, "%s: device_register failed\n", __func__);
+		goto err_put_dev;
+	}
+
+	retval = device_create_bin_file(f_dev, &firmware_attr_data);
+	if (retval) {
+		dev_err(f_dev, "%s: sysfs_create_bin_file failed\n", __func__);
+		goto err_del_dev;
+	}
+
+	retval = device_create_file(f_dev, &dev_attr_loading);
+	if (retval) {
+		dev_err(f_dev, "%s: device_create_file failed\n", __func__);
+		goto err_del_bin_attr;
+	}
 
 	if (uevent) {
+		dev_set_uevent_suppress(f_dev, false);
+		dev_dbg(f_dev, "firmware: requesting %s\n", fw_priv->fw_id);
 		if (timeout != MAX_SCHEDULE_TIMEOUT)
 			mod_timer(&fw_priv->timeout,
 				  round_jiffies_up(jiffies + timeout));
@@ -577,7 +555,13 @@ static int _request_firmware(const struct firmware *firmware,
 	fw_priv->fw = NULL;
 	mutex_unlock(&fw_lock);
 
-	fw_destroy_instance(fw_priv);
+	device_remove_file(f_dev, &dev_attr_loading);
+err_del_bin_attr:
+	device_remove_bin_file(f_dev, &firmware_attr_data);
+err_del_dev:
+	device_del(f_dev);
+err_put_dev:
+	put_device(f_dev);
 	return retval;
 }
 
@@ -600,17 +584,19 @@ int
 request_firmware(const struct firmware **firmware_p, const char *name,
                  struct device *device)
 {
+	struct firmware_priv *fw_priv;
 	int ret;
 
-	ret = _request_firmware_prepare(firmware_p, name, device);
-	if (ret <= 0)
-		return ret;
+	fw_priv = _request_firmware_prepare(firmware_p, name, device, true,
+					    false);
+	if (IS_ERR_OR_NULL(fw_priv))
+		return PTR_RET(fw_priv);
 
 	ret = usermodehelper_read_trylock();
 	if (WARN_ON(ret)) {
 		dev_err(device, "firmware: %s will not be loaded\n", name);
 	} else {
-		ret = _request_firmware(*firmware_p, name, device, true, false,
+		ret = _request_firmware_load(fw_priv, true,
 					firmware_loading_timeout());
 		usermodehelper_read_unlock();
 	}
@@ -648,6 +634,7 @@ static int request_firmware_work_func(void *arg)
 {
 	struct firmware_work *fw_work = arg;
 	const struct firmware *fw;
+	struct firmware_priv *fw_priv;
 	long timeout;
 	int ret;
 
@@ -656,14 +643,16 @@ static int request_firmware_work_func(void *arg)
 		return 0;
 	}
 
-	ret = _request_firmware_prepare(&fw, fw_work->name, fw_work->device);
-	if (ret <= 0)
+	fw_priv = _request_firmware_prepare(&fw, fw_work->name, fw_work->device,
+			fw_work->uevent, true);
+	if (IS_ERR_OR_NULL(fw_priv)) {
+		ret = PTR_RET(fw_priv);
 		goto out;
+	}
 
 	timeout = usermodehelper_read_lock_wait(firmware_loading_timeout());
 	if (timeout) {
-		ret = _request_firmware(fw, fw_work->name, fw_work->device,
-					fw_work->uevent, true, timeout);
+		ret = _request_firmware_load(fw_priv, fw_work->uevent, timeout);
 		usermodehelper_read_unlock();
 	} else {
 		dev_dbg(fw_work->device, "firmware: %s loading timed out\n",
-- 
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.


^ permalink raw reply related	[flat|nested] 111+ messages in thread

* [PATCH 2/2] firmware_class: Move request_firmware_nowait() to workqueues
  2012-03-25 22:00                                         ` [PATCH 0/6] firmware_class: Fix problems with usermodehelper test Rafael J. Wysocki
                                                             ` (7 preceding siblings ...)
  2012-03-27 21:28                                           ` [PATCH 1/2] firmware_class: Reorganize fw_create_instance() Stephen Boyd
@ 2012-03-27 21:28                                           ` Stephen Boyd
  2012-03-27 21:49                                             ` Rafael J. Wysocki
  2012-03-27 22:01                                             ` Tejun Heo
  2012-03-28 21:19                                           ` [PATCH v2 0/8] firmware_class: Fix problems with usermodehelper test Rafael J. Wysocki
  9 siblings, 2 replies; 111+ messages in thread
From: Stephen Boyd @ 2012-03-27 21:28 UTC (permalink / raw)
  To: linux-kernel
  Cc: Rafael J. Wysocki, Linus Torvalds, Saravana Kannan, Kay Sievers,
	Greg KH, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list, Tejun Heo

Oddly enough a work_struct was already part of the firmware_work
structure but nobody was using it. Instead of creating a new
kthread for each request_firmware_nowait() call just schedule the
work on the long system workqueue. This should avoid some overhead
in forking new threads when they're not strictly necessary.

Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
---

Is it better to use alloc_workqueue() and not put these on the system
long workqueue?

 drivers/base/firmware_class.c |   27 +++++++--------------------
 1 file changed, 7 insertions(+), 20 deletions(-)

diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index ae00a2f..4d8cb8b 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -16,10 +16,11 @@
 #include <linux/interrupt.h>
 #include <linux/bitops.h>
 #include <linux/mutex.h>
-#include <linux/kthread.h>
+#include <linux/workqueue.h>
 #include <linux/highmem.h>
 #include <linux/firmware.h>
 #include <linux/slab.h>
+#include <linux/sched.h>
 
 #define to_dev(obj) container_of(obj, struct device, kobj)
 
@@ -630,19 +631,15 @@ struct firmware_work {
 	bool uevent;
 };
 
-static int request_firmware_work_func(void *arg)
+static void request_firmware_work_func(struct work_struct *work)
 {
-	struct firmware_work *fw_work = arg;
+	struct firmware_work *fw_work;
 	const struct firmware *fw;
 	struct firmware_priv *fw_priv;
 	long timeout;
 	int ret;
 
-	if (!arg) {
-		WARN_ON(1);
-		return 0;
-	}
-
+	fw_work = container_of(work, struct firmware_work, work);
 	fw_priv = _request_firmware_prepare(&fw, fw_work->name, fw_work->device,
 			fw_work->uevent, true);
 	if (IS_ERR_OR_NULL(fw_priv)) {
@@ -667,8 +664,6 @@ static int request_firmware_work_func(void *arg)
 
 	module_put(fw_work->module);
 	kfree(fw_work);
-
-	return ret;
 }
 
 /**
@@ -694,7 +689,6 @@ request_firmware_nowait(
 	const char *name, struct device *device, gfp_t gfp, void *context,
 	void (*cont)(const struct firmware *fw, void *context))
 {
-	struct task_struct *task;
 	struct firmware_work *fw_work;
 
 	fw_work = kzalloc(sizeof (struct firmware_work), gfp);
@@ -713,15 +707,8 @@ request_firmware_nowait(
 		return -EFAULT;
 	}
 
-	task = kthread_run(request_firmware_work_func, fw_work,
-			    "firmware/%s", name);
-	if (IS_ERR(task)) {
-		fw_work->cont(NULL, fw_work->context);
-		module_put(fw_work->module);
-		kfree(fw_work);
-		return PTR_ERR(task);
-	}
-
+	INIT_WORK(&fw_work->work, request_firmware_work_func);
+	queue_work(system_long_wq, &fw_work->work);
 	return 0;
 }
 
-- 
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.


^ permalink raw reply related	[flat|nested] 111+ messages in thread

* Re: [PATCH 2/6] firmware_class: Split _request_firmware() into three functions
  2012-03-26 20:36                                               ` Rafael J. Wysocki
@ 2012-03-27 21:35                                                 ` Stephen Boyd
  2012-03-27 21:51                                                   ` Rafael J. Wysocki
  0 siblings, 1 reply; 111+ messages in thread
From: Stephen Boyd @ 2012-03-27 21:35 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: linux-kernel, Linus Torvalds, Saravana Kannan, Kay Sievers,
	Greg KH, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list

On 03/26/12 13:36, Rafael J. Wysocki wrote:
> On Monday, March 26, 2012, Stephen Boyd wrote:
>> On 03/25/12 15:01, Rafael J. Wysocki wrote:
>>> @@ -639,8 +655,15 @@ static int request_firmware_work_func(vo
>>>  		return 0;
>>>  	}
>>>  
>>> -	ret = _request_firmware(&fw, fw_work->name, fw_work->device,
>>> +	ret = _request_firmware_prepare(&fw, fw_work->name, fw_work->device);
>>> +	if (ret <= 0)
>>> +		return ret;
>> This needs to jump to the cont function so that users know loading
>> failed or that the firmware was builtin.
> You're right, sorry.  That should have been
>
> 	if (ret > 0) {
> 		ret = _request_firmware(fw, fw_work->name, fw_work->device,
> 			fw_work->uevent, true);
> 		if (ret)
> 			_request_firmware_cleanup(&fw);
> 	}
>
> but actually using a jump makes the next patch look better.
>
> Updated patch is appended.
> ---
> From: Rafael J. Wysocki <rjw@sisk.pl>
> Subject: firmware_class: Split _request_firmware() into three functions, v2
>
> Split _request_firmware() into three functions,
> _request_firmware_prepare() doing preparatory work that need not be
> done under umhelper_sem, _request_firmware_cleanup() doing the
> post-error cleanup and _request_firmware() carrying out the remaining
> operations.
>
> This change is requisite for moving the acquisition of umhelper_sem
> from _request_firmware() to the callers, which is going to be done
> subsequently.

Reviewed-by: Stephen Boyd <sboyd@codeaurora.org>

> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
> ---

-- 
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.


^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH 6/6] PM / Sleep: Mitigate race between the freezer and request_firmware()
  2012-03-27 21:25                                                 ` Stephen Boyd
@ 2012-03-27 21:37                                                   ` Rafael J. Wysocki
  0 siblings, 0 replies; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-27 21:37 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: linux-kernel, Linus Torvalds, Saravana Kannan, Kay Sievers,
	Greg KH, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list

On Tuesday, March 27, 2012, Stephen Boyd wrote:
> On 03/26/12 13:06, Rafael J. Wysocki wrote:
> > On Monday, March 26, 2012, Stephen Boyd wrote:
> >> On 03/25/12 15:04, Rafael J. Wysocki wrote:
> >>> Index: linux/kernel/power/process.c
> >>> ===================================================================
> >>> --- linux.orig/kernel/power/process.c
> >>> +++ linux/kernel/power/process.c
> >>> @@ -135,6 +135,7 @@ int freeze_processes(void)
> >>>  	error = try_to_freeze_tasks(true);
> >>>  	if (!error) {
> >>>  		printk("done.");
> >>> +		__usermodehelper_reset(UMH_DISABLED);
> >>>  		oom_killer_disable();
> >>>  	}
> >>>  	printk("\n");
> >> nitpick: This doesn't seem to be doing a reset, more like a set. Perhaps
> >> this function should be called __usermodehelper_set()?
> > Yes, you are right.  I changed that before, but somehow managed to send an old
> > patch.  The new version follows.
> 
> Looks good. Thanks.
> 
> > ---
> > From: Rafael J. Wysocki <rjw@sisk.pl>
> > Subject: PM / Sleep: Mitigate race between the freezer and request_firmware()
> >
> > There is a race condition between the freezer and request_firmware()
> > such that if request_firmware() is run on one CPU and
> > freeze_processes() is run on another CPU and usermodehelper_disable()
> > called by it succeeds to grab umhelper_sem for writing before
> > usermodehelper_read_trylock() called from request_firmware()
> > acquires it for reading, the request_firmware() will fail and
> > trigger a WARN_ON() complaining that it was called at a wrong time.
> > However, in fact, it wasn't called at a wrong time and
> > freeze_processes() simply happened to be executed simultaneously.
> >
> > To avoid this race, at least in some cases, modify
> > usermodehelper_read_trylock() so that it doesn't fail if the
> > freezing of tasks has just started and hasn't been completed yet.
> > Instead, during the freezing of tasks, it will try to freeze the
> > task that has called it so that it can wait until user space is
> > thawed without triggering the scary warning.
> >
> > For this purpose, change usermodehelper_disabled so that it can
> > take three different values, UMH_ENABLED (0), UMH_FREEZING and
> > UMH_DISABLED.  The first one means that usermode helpers are
> > enabled, the last one means "hard disable" (i.e. the system is not
> > ready for usermode helpers to be used) and the second one
> > is reserved for the freezer.  Namely, when freeze_processes() is
> > started, it sets usermodehelper_disabled to UMH_FREEZING which
> > tells usermodehelper_read_trylock() that it shouldn't fail just
> > yet and should call try_to_freeze() if woken up and cannot
> > return immediately.  This way all freezable tasks that happen
> > to call request_firmware() right before freeze_processes() is
> > started and lose the race for umhelper_sem with it will be
> > frozen and will sleep until thaw_processes() unsets
> > usermodehelper_disabled.  [For the non-freezable callers of
> > request_firmware() the race for umhelper_sem against
> > freeze_processes() is unfortunately unavoidable.]
> 
> Reported-by: Stephen Boyd <sboyd@codeaurora.org>

Yeah, sorry.

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH 1/2] firmware_class: Reorganize fw_create_instance()
  2012-03-27 21:28                                           ` [PATCH 1/2] firmware_class: Reorganize fw_create_instance() Stephen Boyd
@ 2012-03-27 21:47                                             ` Rafael J. Wysocki
  2012-03-27 21:49                                               ` Greg KH
  0 siblings, 1 reply; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-27 21:47 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: linux-kernel, Linus Torvalds, Saravana Kannan, Kay Sievers,
	Greg KH, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list

On Tuesday, March 27, 2012, Stephen Boyd wrote:
> Recent patches to split up the three phases of request_firmware()
> lead to a casting away of const in fw_create_instance(). We can
> avoid this cast by splitting up fw_create_instance() a bit.
> 
> Make _request_firmware_setup() return a struct fw_priv and use
> that struct instead of passing struct firmware to
> _request_firmware(). Move the uevent and device file creation
> bits to the loading phase and rename the function to
> _request_firmware_load() to better reflect its purpose.
> 
> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>

Looks good to me.

Greg, if that's fine with you, I'll add this patch (and the next one)
to my firmware_class series you've looked at recently.

Thanks,
Rafael

> ---
>  drivers/base/firmware_class.c |  135 +++++++++++++++++++----------------------
>  1 file changed, 62 insertions(+), 73 deletions(-)
> 
> diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
> index 72c644b..ae00a2f 100644
> --- a/drivers/base/firmware_class.c
> +++ b/drivers/base/firmware_class.c
> @@ -440,21 +440,19 @@ static void firmware_class_timeout(u_long data)
>  }
>  
>  static struct firmware_priv *
> -fw_create_instance(const struct firmware *firmware, const char *fw_name,
> +fw_create_instance(struct firmware *firmware, const char *fw_name,
>  		   struct device *device, bool uevent, bool nowait)
>  {
>  	struct firmware_priv *fw_priv;
>  	struct device *f_dev;
> -	int error;
>  
>  	fw_priv = kzalloc(sizeof(*fw_priv) + strlen(fw_name) + 1 , GFP_KERNEL);
>  	if (!fw_priv) {
>  		dev_err(device, "%s: kmalloc failed\n", __func__);
> -		error = -ENOMEM;
> -		goto err_out;
> +		return ERR_PTR(-ENOMEM);
>  	}
>  
> -	fw_priv->fw = (struct firmware *)firmware;
> +	fw_priv->fw = firmware;
>  	fw_priv->nowait = nowait;
>  	strcpy(fw_priv->fw_id, fw_name);
>  	init_completion(&fw_priv->completion);
> @@ -468,74 +466,37 @@ fw_create_instance(const struct firmware *firmware, const char *fw_name,
>  	f_dev->parent = device;
>  	f_dev->class = &firmware_class;
>  
> -	dev_set_uevent_suppress(f_dev, true);
> -
> -	/* Need to pin this module until class device is destroyed */
> -	__module_get(THIS_MODULE);
> -
> -	error = device_add(f_dev);
> -	if (error) {
> -		dev_err(device, "%s: device_register failed\n", __func__);
> -		goto err_put_dev;
> -	}
> -
> -	error = device_create_bin_file(f_dev, &firmware_attr_data);
> -	if (error) {
> -		dev_err(device, "%s: sysfs_create_bin_file failed\n", __func__);
> -		goto err_del_dev;
> -	}
> -
> -	error = device_create_file(f_dev, &dev_attr_loading);
> -	if (error) {
> -		dev_err(device, "%s: device_create_file failed\n", __func__);
> -		goto err_del_bin_attr;
> -	}
> -
> -	if (uevent)
> -		dev_set_uevent_suppress(f_dev, false);
> -
>  	return fw_priv;
> -
> -err_del_bin_attr:
> -	device_remove_bin_file(f_dev, &firmware_attr_data);
> -err_del_dev:
> -	device_del(f_dev);
> -err_put_dev:
> -	put_device(f_dev);
> -err_out:
> -	return ERR_PTR(error);
> -}
> -
> -static void fw_destroy_instance(struct firmware_priv *fw_priv)
> -{
> -	struct device *f_dev = &fw_priv->dev;
> -
> -	device_remove_file(f_dev, &dev_attr_loading);
> -	device_remove_bin_file(f_dev, &firmware_attr_data);
> -	device_unregister(f_dev);
>  }
>  
> -static int _request_firmware_prepare(const struct firmware **firmware_p,
> -				     const char *name, struct device *device)
> +static struct firmware_priv *
> +_request_firmware_prepare(const struct firmware **firmware_p, const char *name,
> +			  struct device *device, bool uevent, bool nowait)
>  {
>  	struct firmware *firmware;
> +	struct firmware_priv *fw_priv;
>  
>  	if (!firmware_p)
> -		return -EINVAL;
> +		return ERR_PTR(-EINVAL);
>  
>  	*firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL);
>  	if (!firmware) {
>  		dev_err(device, "%s: kmalloc(struct firmware) failed\n",
>  			__func__);
> -		return -ENOMEM;
> +		return ERR_PTR(-ENOMEM);
>  	}
>  
>  	if (fw_get_builtin_firmware(firmware, name)) {
>  		dev_dbg(device, "firmware: using built-in firmware %s\n", name);
> -		return 0;
> +		return NULL;
>  	}
>  
> -	return 1;
> +	fw_priv = fw_create_instance(firmware, name, device, uevent, nowait);
> +	if (IS_ERR(fw_priv)) {
> +		release_firmware(firmware);
> +		*firmware_p = NULL;
> +	}
> +	return fw_priv;
>  }
>  
>  static void _request_firmware_cleanup(const struct firmware **firmware_p)
> @@ -544,21 +505,38 @@ static void _request_firmware_cleanup(const struct firmware **firmware_p)
>  	*firmware_p = NULL;
>  }
>  
> -static int _request_firmware(const struct firmware *firmware,
> -			     const char *name, struct device *device,
> -			     bool uevent, bool nowait, long timeout)
> +static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent,
> +				  long timeout)
>  {
> -	struct firmware_priv *fw_priv;
>  	int retval = 0;
> +	struct device *f_dev = &fw_priv->dev;
> +
> +	dev_set_uevent_suppress(f_dev, true);
>  
> -	if (uevent)
> -		dev_dbg(device, "firmware: requesting %s\n", name);
> +	/* Need to pin this module until class device is destroyed */
> +	__module_get(THIS_MODULE);
>  
> -	fw_priv = fw_create_instance(firmware, name, device, uevent, nowait);
> -	if (IS_ERR(fw_priv))
> -		return PTR_ERR(fw_priv);
> +	retval = device_add(f_dev);
> +	if (retval) {
> +		dev_err(f_dev, "%s: device_register failed\n", __func__);
> +		goto err_put_dev;
> +	}
> +
> +	retval = device_create_bin_file(f_dev, &firmware_attr_data);
> +	if (retval) {
> +		dev_err(f_dev, "%s: sysfs_create_bin_file failed\n", __func__);
> +		goto err_del_dev;
> +	}
> +
> +	retval = device_create_file(f_dev, &dev_attr_loading);
> +	if (retval) {
> +		dev_err(f_dev, "%s: device_create_file failed\n", __func__);
> +		goto err_del_bin_attr;
> +	}
>  
>  	if (uevent) {
> +		dev_set_uevent_suppress(f_dev, false);
> +		dev_dbg(f_dev, "firmware: requesting %s\n", fw_priv->fw_id);
>  		if (timeout != MAX_SCHEDULE_TIMEOUT)
>  			mod_timer(&fw_priv->timeout,
>  				  round_jiffies_up(jiffies + timeout));
> @@ -577,7 +555,13 @@ static int _request_firmware(const struct firmware *firmware,
>  	fw_priv->fw = NULL;
>  	mutex_unlock(&fw_lock);
>  
> -	fw_destroy_instance(fw_priv);
> +	device_remove_file(f_dev, &dev_attr_loading);
> +err_del_bin_attr:
> +	device_remove_bin_file(f_dev, &firmware_attr_data);
> +err_del_dev:
> +	device_del(f_dev);
> +err_put_dev:
> +	put_device(f_dev);
>  	return retval;
>  }
>  
> @@ -600,17 +584,19 @@ int
>  request_firmware(const struct firmware **firmware_p, const char *name,
>                   struct device *device)
>  {
> +	struct firmware_priv *fw_priv;
>  	int ret;
>  
> -	ret = _request_firmware_prepare(firmware_p, name, device);
> -	if (ret <= 0)
> -		return ret;
> +	fw_priv = _request_firmware_prepare(firmware_p, name, device, true,
> +					    false);
> +	if (IS_ERR_OR_NULL(fw_priv))
> +		return PTR_RET(fw_priv);
>  
>  	ret = usermodehelper_read_trylock();
>  	if (WARN_ON(ret)) {
>  		dev_err(device, "firmware: %s will not be loaded\n", name);
>  	} else {
> -		ret = _request_firmware(*firmware_p, name, device, true, false,
> +		ret = _request_firmware_load(fw_priv, true,
>  					firmware_loading_timeout());
>  		usermodehelper_read_unlock();
>  	}
> @@ -648,6 +634,7 @@ static int request_firmware_work_func(void *arg)
>  {
>  	struct firmware_work *fw_work = arg;
>  	const struct firmware *fw;
> +	struct firmware_priv *fw_priv;
>  	long timeout;
>  	int ret;
>  
> @@ -656,14 +643,16 @@ static int request_firmware_work_func(void *arg)
>  		return 0;
>  	}
>  
> -	ret = _request_firmware_prepare(&fw, fw_work->name, fw_work->device);
> -	if (ret <= 0)
> +	fw_priv = _request_firmware_prepare(&fw, fw_work->name, fw_work->device,
> +			fw_work->uevent, true);
> +	if (IS_ERR_OR_NULL(fw_priv)) {
> +		ret = PTR_RET(fw_priv);
>  		goto out;
> +	}
>  
>  	timeout = usermodehelper_read_lock_wait(firmware_loading_timeout());
>  	if (timeout) {
> -		ret = _request_firmware(fw, fw_work->name, fw_work->device,
> -					fw_work->uevent, true, timeout);
> +		ret = _request_firmware_load(fw_priv, fw_work->uevent, timeout);
>  		usermodehelper_read_unlock();
>  	} else {
>  		dev_dbg(fw_work->device, "firmware: %s loading timed out\n",
> 


^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH 2/2] firmware_class: Move request_firmware_nowait() to workqueues
  2012-03-27 21:28                                           ` [PATCH 2/2] firmware_class: Move request_firmware_nowait() to workqueues Stephen Boyd
@ 2012-03-27 21:49                                             ` Rafael J. Wysocki
  2012-03-27 22:01                                             ` Tejun Heo
  1 sibling, 0 replies; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-27 21:49 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: linux-kernel, Linus Torvalds, Saravana Kannan, Kay Sievers,
	Greg KH, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list, Tejun Heo

On Tuesday, March 27, 2012, Stephen Boyd wrote:
> Oddly enough a work_struct was already part of the firmware_work
> structure but nobody was using it. Instead of creating a new
> kthread for each request_firmware_nowait() call just schedule the
> work on the long system workqueue. This should avoid some overhead
> in forking new threads when they're not strictly necessary.
> 
> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
> ---
> 
> Is it better to use alloc_workqueue() and not put these on the system
> long workqueue?

I think if that happens to interfere destructively with something,
we can always use a new workqueue.  For now, let's try to avoid
adding yet another one if possible.

Thanks,
Rafael


>  drivers/base/firmware_class.c |   27 +++++++--------------------
>  1 file changed, 7 insertions(+), 20 deletions(-)
> 
> diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
> index ae00a2f..4d8cb8b 100644
> --- a/drivers/base/firmware_class.c
> +++ b/drivers/base/firmware_class.c
> @@ -16,10 +16,11 @@
>  #include <linux/interrupt.h>
>  #include <linux/bitops.h>
>  #include <linux/mutex.h>
> -#include <linux/kthread.h>
> +#include <linux/workqueue.h>
>  #include <linux/highmem.h>
>  #include <linux/firmware.h>
>  #include <linux/slab.h>
> +#include <linux/sched.h>
>  
>  #define to_dev(obj) container_of(obj, struct device, kobj)
>  
> @@ -630,19 +631,15 @@ struct firmware_work {
>  	bool uevent;
>  };
>  
> -static int request_firmware_work_func(void *arg)
> +static void request_firmware_work_func(struct work_struct *work)
>  {
> -	struct firmware_work *fw_work = arg;
> +	struct firmware_work *fw_work;
>  	const struct firmware *fw;
>  	struct firmware_priv *fw_priv;
>  	long timeout;
>  	int ret;
>  
> -	if (!arg) {
> -		WARN_ON(1);
> -		return 0;
> -	}
> -
> +	fw_work = container_of(work, struct firmware_work, work);
>  	fw_priv = _request_firmware_prepare(&fw, fw_work->name, fw_work->device,
>  			fw_work->uevent, true);
>  	if (IS_ERR_OR_NULL(fw_priv)) {
> @@ -667,8 +664,6 @@ static int request_firmware_work_func(void *arg)
>  
>  	module_put(fw_work->module);
>  	kfree(fw_work);
> -
> -	return ret;
>  }
>  
>  /**
> @@ -694,7 +689,6 @@ request_firmware_nowait(
>  	const char *name, struct device *device, gfp_t gfp, void *context,
>  	void (*cont)(const struct firmware *fw, void *context))
>  {
> -	struct task_struct *task;
>  	struct firmware_work *fw_work;
>  
>  	fw_work = kzalloc(sizeof (struct firmware_work), gfp);
> @@ -713,15 +707,8 @@ request_firmware_nowait(
>  		return -EFAULT;
>  	}
>  
> -	task = kthread_run(request_firmware_work_func, fw_work,
> -			    "firmware/%s", name);
> -	if (IS_ERR(task)) {
> -		fw_work->cont(NULL, fw_work->context);
> -		module_put(fw_work->module);
> -		kfree(fw_work);
> -		return PTR_ERR(task);
> -	}
> -
> +	INIT_WORK(&fw_work->work, request_firmware_work_func);
> +	queue_work(system_long_wq, &fw_work->work);
>  	return 0;
>  }
>  
> 


^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH 1/2] firmware_class: Reorganize fw_create_instance()
  2012-03-27 21:47                                             ` Rafael J. Wysocki
@ 2012-03-27 21:49                                               ` Greg KH
  2012-03-27 21:56                                                 ` Rafael J. Wysocki
  0 siblings, 1 reply; 111+ messages in thread
From: Greg KH @ 2012-03-27 21:49 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Stephen Boyd, linux-kernel, Linus Torvalds, Saravana Kannan,
	Kay Sievers, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list

On Tue, Mar 27, 2012 at 11:47:06PM +0200, Rafael J. Wysocki wrote:
> On Tuesday, March 27, 2012, Stephen Boyd wrote:
> > Recent patches to split up the three phases of request_firmware()
> > lead to a casting away of const in fw_create_instance(). We can
> > avoid this cast by splitting up fw_create_instance() a bit.
> > 
> > Make _request_firmware_setup() return a struct fw_priv and use
> > that struct instead of passing struct firmware to
> > _request_firmware(). Move the uevent and device file creation
> > bits to the loading phase and rename the function to
> > _request_firmware_load() to better reflect its purpose.
> > 
> > Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
> 
> Looks good to me.
> 
> Greg, if that's fine with you, I'll add this patch (and the next one)
> to my firmware_class series you've looked at recently.

Yes, it's fine with me:
	Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>


^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH 2/6] firmware_class: Split _request_firmware() into three functions
  2012-03-27 21:35                                                 ` Stephen Boyd
@ 2012-03-27 21:51                                                   ` Rafael J. Wysocki
  0 siblings, 0 replies; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-27 21:51 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: linux-kernel, Linus Torvalds, Saravana Kannan, Kay Sievers,
	Greg KH, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list

On Tuesday, March 27, 2012, Stephen Boyd wrote:
> On 03/26/12 13:36, Rafael J. Wysocki wrote:
> > On Monday, March 26, 2012, Stephen Boyd wrote:
> >> On 03/25/12 15:01, Rafael J. Wysocki wrote:
> >>> @@ -639,8 +655,15 @@ static int request_firmware_work_func(vo
> >>>  		return 0;
> >>>  	}
> >>>  
> >>> -	ret = _request_firmware(&fw, fw_work->name, fw_work->device,
> >>> +	ret = _request_firmware_prepare(&fw, fw_work->name, fw_work->device);
> >>> +	if (ret <= 0)
> >>> +		return ret;
> >> This needs to jump to the cont function so that users know loading
> >> failed or that the firmware was builtin.
> > You're right, sorry.  That should have been
> >
> > 	if (ret > 0) {
> > 		ret = _request_firmware(fw, fw_work->name, fw_work->device,
> > 			fw_work->uevent, true);
> > 		if (ret)
> > 			_request_firmware_cleanup(&fw);
> > 	}
> >
> > but actually using a jump makes the next patch look better.
> >
> > Updated patch is appended.
> > ---
> > From: Rafael J. Wysocki <rjw@sisk.pl>
> > Subject: firmware_class: Split _request_firmware() into three functions, v2
> >
> > Split _request_firmware() into three functions,
> > _request_firmware_prepare() doing preparatory work that need not be
> > done under umhelper_sem, _request_firmware_cleanup() doing the
> > post-error cleanup and _request_firmware() carrying out the remaining
> > operations.
> >
> > This change is requisite for moving the acquisition of umhelper_sem
> > from _request_firmware() to the callers, which is going to be done
> > subsequently.
> 
> Reviewed-by: Stephen Boyd <sboyd@codeaurora.org>

Thanks!

Rafael

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH 1/2] firmware_class: Reorganize fw_create_instance()
  2012-03-27 21:49                                               ` Greg KH
@ 2012-03-27 21:56                                                 ` Rafael J. Wysocki
  0 siblings, 0 replies; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-27 21:56 UTC (permalink / raw)
  To: Greg KH
  Cc: Stephen Boyd, linux-kernel, Linus Torvalds, Saravana Kannan,
	Kay Sievers, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list

On Tuesday, March 27, 2012, Greg KH wrote:
> On Tue, Mar 27, 2012 at 11:47:06PM +0200, Rafael J. Wysocki wrote:
> > On Tuesday, March 27, 2012, Stephen Boyd wrote:
> > > Recent patches to split up the three phases of request_firmware()
> > > lead to a casting away of const in fw_create_instance(). We can
> > > avoid this cast by splitting up fw_create_instance() a bit.
> > > 
> > > Make _request_firmware_setup() return a struct fw_priv and use
> > > that struct instead of passing struct firmware to
> > > _request_firmware(). Move the uevent and device file creation
> > > bits to the loading phase and rename the function to
> > > _request_firmware_load() to better reflect its purpose.
> > > 
> > > Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
> > 
> > Looks good to me.
> > 
> > Greg, if that's fine with you, I'll add this patch (and the next one)
> > to my firmware_class series you've looked at recently.
> 
> Yes, it's fine with me:
> 	Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

Cool, thanks!

Rafael

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH 2/2] firmware_class: Move request_firmware_nowait() to workqueues
  2012-03-27 21:28                                           ` [PATCH 2/2] firmware_class: Move request_firmware_nowait() to workqueues Stephen Boyd
  2012-03-27 21:49                                             ` Rafael J. Wysocki
@ 2012-03-27 22:01                                             ` Tejun Heo
  2012-03-27 22:21                                               ` Rafael J. Wysocki
  1 sibling, 1 reply; 111+ messages in thread
From: Tejun Heo @ 2012-03-27 22:01 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: linux-kernel, Rafael J. Wysocki, Linus Torvalds, Saravana Kannan,
	Kay Sievers, Greg KH, Christian Lamparter, Srivatsa S. Bhat,
	alan, Linux PM mailing list

On Tue, Mar 27, 2012 at 02:28:30PM -0700, Stephen Boyd wrote:
> Oddly enough a work_struct was already part of the firmware_work
> structure but nobody was using it. Instead of creating a new
> kthread for each request_firmware_nowait() call just schedule the
> work on the long system workqueue. This should avoid some overhead
> in forking new threads when they're not strictly necessary.
> 
> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
> ---
> 
> Is it better to use alloc_workqueue() and not put these on the system
> long workqueue?

No, just use schedule_work() unless there are specific requirements
which can't be fulfilled that way (e.g. it's on memory allocation
path, may consume large amount of cpu cycles, ...)

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH 2/2] firmware_class: Move request_firmware_nowait() to workqueues
  2012-03-27 22:01                                             ` Tejun Heo
@ 2012-03-27 22:21                                               ` Rafael J. Wysocki
  2012-03-27 22:48                                                 ` Tejun Heo
  0 siblings, 1 reply; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-27 22:21 UTC (permalink / raw)
  To: Tejun Heo
  Cc: Stephen Boyd, linux-kernel, Linus Torvalds, Saravana Kannan,
	Kay Sievers, Greg KH, Christian Lamparter, Srivatsa S. Bhat,
	alan, Linux PM mailing list

On Wednesday, March 28, 2012, Tejun Heo wrote:
> On Tue, Mar 27, 2012 at 02:28:30PM -0700, Stephen Boyd wrote:
> > Oddly enough a work_struct was already part of the firmware_work
> > structure but nobody was using it. Instead of creating a new
> > kthread for each request_firmware_nowait() call just schedule the
> > work on the long system workqueue. This should avoid some overhead
> > in forking new threads when they're not strictly necessary.
> > 
> > Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
> > ---
> > 
> > Is it better to use alloc_workqueue() and not put these on the system
> > long workqueue?
> 
> No, just use schedule_work() unless there are specific requirements
> which can't be fulfilled that way (e.g. it's on memory allocation
> path, may consume large amount of cpu cycles, ...)

It may wait quite long.

Rafael

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH 2/2] firmware_class: Move request_firmware_nowait() to workqueues
  2012-03-27 22:21                                               ` Rafael J. Wysocki
@ 2012-03-27 22:48                                                 ` Tejun Heo
  2012-03-27 22:55                                                   ` Rafael J. Wysocki
  0 siblings, 1 reply; 111+ messages in thread
From: Tejun Heo @ 2012-03-27 22:48 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Stephen Boyd, linux-kernel, Linus Torvalds, Saravana Kannan,
	Kay Sievers, Greg KH, Christian Lamparter, Srivatsa S. Bhat,
	alan, Linux PM mailing list

On Wed, Mar 28, 2012 at 12:21:27AM +0200, Rafael J. Wysocki wrote:
> On Wednesday, March 28, 2012, Tejun Heo wrote:
> > On Tue, Mar 27, 2012 at 02:28:30PM -0700, Stephen Boyd wrote:
> > > Oddly enough a work_struct was already part of the firmware_work
> > > structure but nobody was using it. Instead of creating a new
> > > kthread for each request_firmware_nowait() call just schedule the
> > > work on the long system workqueue. This should avoid some overhead
> > > in forking new threads when they're not strictly necessary.
> > > 
> > > Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
> > > ---
> > > 
> > > Is it better to use alloc_workqueue() and not put these on the system
> > > long workqueue?
> > 
> > No, just use schedule_work() unless there are specific requirements
> > which can't be fulfilled that way (e.g. it's on memory allocation
> > path, may consume large amount of cpu cycles, ...)
> 
> It may wait quite long.

That shouldn't matter.  system_long_wq's name is a bit misleading at
this point.  The only reason it's used currently is to avoid cyclic
dependency involving flush_workqueue(), which calls for clearer
solution anyway.  So, yeap, using system_wq should be fine here.

Thank you.

-- 
tejun

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH 2/2] firmware_class: Move request_firmware_nowait() to workqueues
  2012-03-27 22:48                                                 ` Tejun Heo
@ 2012-03-27 22:55                                                   ` Rafael J. Wysocki
  2012-03-27 23:02                                                     ` Stephen Boyd
  2012-03-27 23:05                                                     ` Stephen Boyd
  0 siblings, 2 replies; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-27 22:55 UTC (permalink / raw)
  To: Tejun Heo, Stephen Boyd
  Cc: linux-kernel, Linus Torvalds, Saravana Kannan, Kay Sievers,
	Greg KH, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list

On Wednesday, March 28, 2012, Tejun Heo wrote:
> On Wed, Mar 28, 2012 at 12:21:27AM +0200, Rafael J. Wysocki wrote:
> > On Wednesday, March 28, 2012, Tejun Heo wrote:
> > > On Tue, Mar 27, 2012 at 02:28:30PM -0700, Stephen Boyd wrote:
> > > > Oddly enough a work_struct was already part of the firmware_work
> > > > structure but nobody was using it. Instead of creating a new
> > > > kthread for each request_firmware_nowait() call just schedule the
> > > > work on the long system workqueue. This should avoid some overhead
> > > > in forking new threads when they're not strictly necessary.
> > > > 
> > > > Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
> > > > ---
> > > > 
> > > > Is it better to use alloc_workqueue() and not put these on the system
> > > > long workqueue?
> > > 
> > > No, just use schedule_work() unless there are specific requirements
> > > which can't be fulfilled that way (e.g. it's on memory allocation
> > > path, may consume large amount of cpu cycles, ...)
> > 
> > It may wait quite long.
> 
> That shouldn't matter.  system_long_wq's name is a bit misleading at
> this point.  The only reason it's used currently is to avoid cyclic
> dependency involving flush_workqueue(), which calls for clearer
> solution anyway.  So, yeap, using system_wq should be fine here.

Good, thanks for the explanation.

Stephen, care to respin?

Rafael

^ permalink raw reply	[flat|nested] 111+ messages in thread

* Re: [PATCH 2/2] firmware_class: Move request_firmware_nowait() to workqueues
  2012-03-27 22:55                                                   ` Rafael J. Wysocki
@ 2012-03-27 23:02                                                     ` Stephen Boyd
  2012-03-27 23:05                                                     ` Stephen Boyd
  1 sibling, 0 replies; 111+ messages in thread
From: Stephen Boyd @ 2012-03-27 23:02 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Tejun Heo, linux-kernel, Linus Torvalds, Saravana Kannan,
	Kay Sievers, Greg KH, Christian Lamparter, Srivatsa S. Bhat,
	alan, Linux PM mailing list

On 03/27/12 15:55, Rafael J. Wysocki wrote:
> On Wednesday, March 28, 2012, Tejun Heo wrote:
>> On Wed, Mar 28, 2012 at 12:21:27AM +0200, Rafael J. Wysocki wrote:
>>> On Wednesday, March 28, 2012, Tejun Heo wrote:
>>>> On Tue, Mar 27, 2012 at 02:28:30PM -0700, Stephen Boyd wrote:
>>>>> Oddly enough a work_struct was already part of the firmware_work
>>>>> structure but nobody was using it. Instead of creating a new
>>>>> kthread for each request_firmware_nowait() call just schedule the
>>>>> work on the long system workqueue. This should avoid some overhead
>>>>> in forking new threads when they're not strictly necessary.
>>>>>
>>>>> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
>>>>> ---
>>>>>
>>>>> Is it better to use alloc_workqueue() and not put these on the system
>>>>> long workqueue?
>>>> No, just use schedule_work() unless there are specific requirements
>>>> which can't be fulfilled that way (e.g. it's on memory allocation
>>>> path, may consume large amount of cpu cycles, ...)
>>> It may wait quite long.
>> That shouldn't matter.  system_long_wq's name is a bit misleading at
>> this point.  The only reason it's used currently is to avoid cyclic
>> dependency involving flush_workqueue(), which calls for clearer
>> solution anyway.  So, yeap, using system_wq should be fine here.
> Good, thanks for the explanation.
>
> Stephen, care to respin?
>

Sure. We want system_wq instead of system_long_wq? If so let's use this
patch.

-----8<-- cut here -->8------

Subject: [PATCH] firmware_class: Move request_firmware_nowait() to workqueues

Oddly enough a work_struct was already part of the firmware_work
structure but nobody was using it. Instead of creating a new
kthread for each request_firmware_nowait() call just schedule the
work on the system workqueue. This should avoid some overhead
in forking new threads when they're not strictly necessary.

Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
---
 drivers/base/firmware_class.c |   27 +++++++--------------------
 1 file changed, 7 insertions(+), 20 deletions(-)

diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index ae00a2f..5401814 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -16,10 +16,11 @@
 #include <linux/interrupt.h>
 #include <linux/bitops.h>
 #include <linux/mutex.h>
-#include <linux/kthread.h>
+#include <linux/workqueue.h>
 #include <linux/highmem.h>
 #include <linux/firmware.h>
 #include <linux/slab.h>
+#include <linux/sched.h>
 
 #define to_dev(obj) container_of(obj, struct device, kobj)
 
@@ -630,19 +631,15 @@ struct firmware_work {
 	bool uevent;
 };
 
-static int request_firmware_work_func(void *arg)
+static void request_firmware_work_func(struct work_struct *work)
 {
-	struct firmware_work *fw_work = arg;
+	struct firmware_work *fw_work;
 	const struct firmware *fw;
 	struct firmware_priv *fw_priv;
 	long timeout;
 	int ret;
 
-	if (!arg) {
-		WARN_ON(1);
-		return 0;
-	}
-
+	fw_work = container_of(work, struct firmware_work, work);
 	fw_priv = _request_firmware_prepare(&fw, fw_work->name, fw_work->device,
 			fw_work->uevent, true);
 	if (IS_ERR_OR_NULL(fw_priv)) {
@@ -667,8 +664,6 @@ static int request_firmware_work_func(void *arg)
 
 	module_put(fw_work->module);
 	kfree(fw_work);
-
-	return ret;
 }
 
 /**
@@ -694,7 +689,6 @@ request_firmware_nowait(
 	const char *name, struct device *device, gfp_t gfp, void *context,
 	void (*cont)(const struct firmware *fw, void *context))
 {
-	struct task_struct *task;
 	struct firmware_work *fw_work;
 
 	fw_work = kzalloc(sizeof (struct firmware_work), gfp);
@@ -713,15 +707,8 @@ request_firmware_nowait(
 		return -EFAULT;
 	}
 
-	task = kthread_run(request_firmware_work_func, fw_work,
-			    "firmware/%s", name);
-	if (IS_ERR(task)) {
-		fw_work->cont(NULL, fw_work->context);
-		module_put(fw_work->module);
-		kfree(fw_work);
-		return PTR_ERR(task);
-	}
-
+	INIT_WORK(&fw_work->work, request_firmware_work_func);
+	schedule_work(&fw_work->work);
 	return 0;
 }
 

-- 
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.


^ permalink raw reply related	[flat|nested] 111+ messages in thread

* Re: [PATCH 2/2] firmware_class: Move request_firmware_nowait() to workqueues
  2012-03-27 22:55                                                   ` Rafael J. Wysocki
  2012-03-27 23:02                                                     ` Stephen Boyd
@ 2012-03-27 23:05                                                     ` Stephen Boyd
  1 sibling, 0 replies; 111+ messages in thread
From: Stephen Boyd @ 2012-03-27 23:05 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Tejun Heo, linux-kernel, Linus Torvalds, Saravana Kannan,
	Kay Sievers, Greg KH, Christian Lamparter, Srivatsa S. Bhat,
	alan, Linux PM mailing list

On 03/27/12 15:55, Rafael J. Wysocki wrote:
> On Wednesday, March 28, 2012, Tejun Heo wrote:
>> On Wed, Mar 28, 2012 at 12:21:27AM +0200, Rafael J. Wysocki wrote:
>>> On Wednesday, March 28, 2012, Tejun Heo wrote:
>>>> On Tue, Mar 27, 2012 at 02:28:30PM -0700, Stephen Boyd wrote:
>>>>> Oddly enough a work_struct was already part of the firmware_work
>>>>> structure but nobody was using it. Instead of creating a new
>>>>> kthread for each request_firmware_nowait() call just schedule the
>>>>> work on the long system workqueue. This should avoid some overhead
>>>>> in forking new threads when they're not strictly necessary.
>>>>>
>>>>> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
>>>>> ---
>>>>>
>>>>> Is it better to use alloc_workqueue() and not put these on the system
>>>>> long workqueue?
>>>> No, just use schedule_work() unless there are specific requirements
>>>> which can't be fulfilled that way (e.g. it's on memory allocation
>>>> path, may consume large amount of cpu cycles, ...)
>>> It may wait quite long.
>> That shouldn't matter.  system_long_wq's name is a bit misleading at
>> this point.  The only reason it's used currently is to avoid cyclic
>> dependency involving flush_workqueue(), which calls for clearer
>> solution anyway.  So, yeap, using system_wq should be fine here.
> Good, thanks for the explanation.
>
> Stephen, care to respin?
>

Sure. We want system_wq instead of system_long_wq? If so let's use this
patch.

-----8<-- cut here -->8------

Subject: [PATCH] firmware_class: Move request_firmware_nowait() to workqueues

Oddly enough a work_struct was already part of the firmware_work
structure but nobody was using it. Instead of creating a new
kthread for each request_firmware_nowait() call just schedule the
work on the system workqueue. This should avoid some overhead
in forking new threads when they're not strictly necessary.

Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
---
 drivers/base/firmware_class.c |   27 +++++++--------------------
 1 file changed, 7 insertions(+), 20 deletions(-)

diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index ae00a2f..5401814 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -16,10 +16,11 @@
 #include <linux/interrupt.h>
 #include <linux/bitops.h>
 #include <linux/mutex.h>
-#include <linux/kthread.h>
+#include <linux/workqueue.h>
 #include <linux/highmem.h>
 #include <linux/firmware.h>
 #include <linux/slab.h>
+#include <linux/sched.h>
 
 #define to_dev(obj) container_of(obj, struct device, kobj)
 
@@ -630,19 +631,15 @@ struct firmware_work {
 	bool uevent;
 };
 
-static int request_firmware_work_func(void *arg)
+static void request_firmware_work_func(struct work_struct *work)
 {
-	struct firmware_work *fw_work = arg;
+	struct firmware_work *fw_work;
 	const struct firmware *fw;
 	struct firmware_priv *fw_priv;
 	long timeout;
 	int ret;
 
-	if (!arg) {
-		WARN_ON(1);
-		return 0;
-	}
-
+	fw_work = container_of(work, struct firmware_work, work);
 	fw_priv = _request_firmware_prepare(&fw, fw_work->name, fw_work->device,
 			fw_work->uevent, true);
 	if (IS_ERR_OR_NULL(fw_priv)) {
@@ -667,8 +664,6 @@ static int request_firmware_work_func(void *arg)
 
 	module_put(fw_work->module);
 	kfree(fw_work);
-
-	return ret;
 }
 
 /**
@@ -694,7 +689,6 @@ request_firmware_nowait(
 	const char *name, struct device *device, gfp_t gfp, void *context,
 	void (*cont)(const struct firmware *fw, void *context))
 {
-	struct task_struct *task;
 	struct firmware_work *fw_work;
 
 	fw_work = kzalloc(sizeof (struct firmware_work), gfp);
@@ -713,15 +707,8 @@ request_firmware_nowait(
 		return -EFAULT;
 	}
 
-	task = kthread_run(request_firmware_work_func, fw_work,
-			    "firmware/%s", name);
-	if (IS_ERR(task)) {
-		fw_work->cont(NULL, fw_work->context);
-		module_put(fw_work->module);
-		kfree(fw_work);
-		return PTR_ERR(task);
-	}
-
+	INIT_WORK(&fw_work->work, request_firmware_work_func);
+	schedule_work(&fw_work->work);
 	return 0;
 }
 

-- 
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.


^ permalink raw reply related	[flat|nested] 111+ messages in thread

* [PATCH v2 0/8] firmware_class: Fix problems with usermodehelper test
  2012-03-25 22:00                                         ` [PATCH 0/6] firmware_class: Fix problems with usermodehelper test Rafael J. Wysocki
                                                             ` (8 preceding siblings ...)
  2012-03-27 21:28                                           ` [PATCH 2/2] firmware_class: Move request_firmware_nowait() to workqueues Stephen Boyd
@ 2012-03-28 21:19                                           ` Rafael J. Wysocki
  2012-03-28 21:20                                             ` [PATCH v2 1/8] firmware_class: Rework usermodehelper check Rafael J. Wysocki
                                                               ` (7 more replies)
  9 siblings, 8 replies; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-28 21:19 UTC (permalink / raw)
  To: linux-kernel
  Cc: Stephen Boyd, Linus Torvalds, Saravana Kannan, Kay Sievers,
	Greg KH, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list

Hi all,

On Monday, March 26, 2012, Rafael J. Wysocki wrote:
>
> The following series of patches fixes two problems with
> request_firmware() and request_firmware_nowait() resulting from commit
> a144c6a6c924aa1da04dd77fb84b89927354fdff
> 
>     PM: Print a warning if firmware is requested when tasks are frozen
> 
> The first problem is that request_firmware_nowait() may fail if it happens
> to run in parallel with system suspend.  It should't fail in such situations
> and that is addressed by the first three patches (that code has been discussed
> with Linus at al already).
> 
> The second issue is that request_firmware() may be called in a thread which
> isn't related to system suspend and if suspend happens exactly at that time,
> request_firmware() will fail (and print a scary warning), although it shouldn't.
> This problem is addressed by the remaining three patches, which are new.

The following series is a respin of this one including fixes of minor bugs
found by the reviewers in the previous version and two additional patches
from Stephen cleaning up things a bit more.

Since patches [1-6/8] fix regressions, I'd like the series to go into v3.4
if that's not too late.

[1/8] - Rework the usermodehelper check in _request_firmware().
[2/8] - Split _request_firmware() into three functions.
[3/8] - If firmware is to be loaded asynchronously, wait for usermodehelper_disabled
        to be unset instead of failing the operation.
[4/8] - Unify the hibernation/suspend code's usage of usermodehelper_disable().
[5/8] - Move usermodehelper_disable() into freeze_processes().
[6/8] - Make freezable threads calling request_firware() avoid the race with the
        freezer.
[7/8] - Split up fw_create_instance() to avoid casting out of const in it.
[8/8] - Use workqueues instead of kthreads in request_firmware_nowait().

Thanks,
Rafael


^ permalink raw reply	[flat|nested] 111+ messages in thread

* [PATCH v2 1/8] firmware_class: Rework usermodehelper check
  2012-03-28 21:19                                           ` [PATCH v2 0/8] firmware_class: Fix problems with usermodehelper test Rafael J. Wysocki
@ 2012-03-28 21:20                                             ` Rafael J. Wysocki
  2012-03-28 21:21                                             ` [PATCH v2 2/8] firmware_class: Split _request_firmware() into three functions, v2 Rafael J. Wysocki
                                                               ` (6 subsequent siblings)
  7 siblings, 0 replies; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-28 21:20 UTC (permalink / raw)
  To: linux-kernel
  Cc: Stephen Boyd, Linus Torvalds, Saravana Kannan, Kay Sievers,
	Greg KH, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list

From: Rafael J. Wysocki <rjw@sisk.pl>

Instead of two functions, read_lock_usermodehelper() and
usermodehelper_is_disabled(), used in combination, introduce
usermodehelper_read_trylock() that will only return with umhelper_sem
held if usermodehelper_disabled is unset (and will return -EAGAIN
otherwise) and make _request_firmware() use it.

Rename read_unlock_usermodehelper() to
usermodehelper_read_unlock() to follow the naming convention of the
new function.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 drivers/base/firmware_class.c |   11 +++++------
 include/linux/kmod.h          |    5 ++---
 kernel/kmod.c                 |   24 +++++++++++-------------
 3 files changed, 18 insertions(+), 22 deletions(-)

Index: linux/include/linux/kmod.h
===================================================================
--- linux.orig/include/linux/kmod.h
+++ linux/include/linux/kmod.h
@@ -114,8 +114,7 @@ extern void usermodehelper_init(void);
 
 extern int usermodehelper_disable(void);
 extern void usermodehelper_enable(void);
-extern bool usermodehelper_is_disabled(void);
-extern void read_lock_usermodehelper(void);
-extern void read_unlock_usermodehelper(void);
+extern int usermodehelper_read_trylock(void);
+extern void usermodehelper_read_unlock(void);
 
 #endif /* __LINUX_KMOD_H__ */
Index: linux/kernel/kmod.c
===================================================================
--- linux.orig/kernel/kmod.c
+++ linux/kernel/kmod.c
@@ -339,17 +339,24 @@ static DECLARE_WAIT_QUEUE_HEAD(running_h
  */
 #define RUNNING_HELPERS_TIMEOUT	(5 * HZ)
 
-void read_lock_usermodehelper(void)
+int usermodehelper_read_trylock(void)
 {
+	int ret = 0;
+
 	down_read(&umhelper_sem);
+	if (usermodehelper_disabled) {
+		up_read(&umhelper_sem);
+		ret = -EAGAIN;
+	}
+	return ret;
 }
-EXPORT_SYMBOL_GPL(read_lock_usermodehelper);
+EXPORT_SYMBOL_GPL(usermodehelper_read_trylock);
 
-void read_unlock_usermodehelper(void)
+void usermodehelper_read_unlock(void)
 {
 	up_read(&umhelper_sem);
 }
-EXPORT_SYMBOL_GPL(read_unlock_usermodehelper);
+EXPORT_SYMBOL_GPL(usermodehelper_read_unlock);
 
 /**
  * usermodehelper_disable - prevent new helpers from being started
@@ -390,15 +397,6 @@ void usermodehelper_enable(void)
 	up_write(&umhelper_sem);
 }
 
-/**
- * usermodehelper_is_disabled - check if new helpers are allowed to be started
- */
-bool usermodehelper_is_disabled(void)
-{
-	return usermodehelper_disabled;
-}
-EXPORT_SYMBOL_GPL(usermodehelper_is_disabled);
-
 static void helper_lock(void)
 {
 	atomic_inc(&running_helpers);
Index: linux/drivers/base/firmware_class.c
===================================================================
--- linux.orig/drivers/base/firmware_class.c
+++ linux/drivers/base/firmware_class.c
@@ -533,12 +533,10 @@ static int _request_firmware(const struc
 		return 0;
 	}
 
-	read_lock_usermodehelper();
-
-	if (WARN_ON(usermodehelper_is_disabled())) {
+	retval = usermodehelper_read_trylock();
+	if (WARN_ON(retval)) {
 		dev_err(device, "firmware: %s will not be loaded\n", name);
-		retval = -EBUSY;
-		goto out;
+		goto out_nolock;
 	}
 
 	if (uevent)
@@ -573,8 +571,9 @@ static int _request_firmware(const struc
 	fw_destroy_instance(fw_priv);
 
 out:
-	read_unlock_usermodehelper();
+	usermodehelper_read_unlock();
 
+out_nolock:
 	if (retval) {
 		release_firmware(firmware);
 		*firmware_p = NULL;


^ permalink raw reply	[flat|nested] 111+ messages in thread

* [PATCH v2 2/8] firmware_class: Split _request_firmware() into three functions, v2
  2012-03-28 21:19                                           ` [PATCH v2 0/8] firmware_class: Fix problems with usermodehelper test Rafael J. Wysocki
  2012-03-28 21:20                                             ` [PATCH v2 1/8] firmware_class: Rework usermodehelper check Rafael J. Wysocki
@ 2012-03-28 21:21                                             ` Rafael J. Wysocki
  2012-03-28 21:22                                             ` [PATCH v3 3/8] firmware_class: Do not warn that system is not ready from async loads Rafael J. Wysocki
                                                               ` (5 subsequent siblings)
  7 siblings, 0 replies; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-28 21:21 UTC (permalink / raw)
  To: linux-kernel
  Cc: Stephen Boyd, Linus Torvalds, Saravana Kannan, Kay Sievers,
	Greg KH, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list

From: Rafael J. Wysocki <rjw@sisk.pl>

Split _request_firmware() into three functions,
_request_firmware_prepare() doing preparatory work that need not be
done under umhelper_sem, _request_firmware_cleanup() doing the
post-error cleanup and _request_firmware() carrying out the remaining
operations.

This change is requisite for moving the acquisition of umhelper_sem
from _request_firmware() to the callers, which is going to be done
subsequently.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Stephen Boyd <sboyd@codeaurora.org>
---
 drivers/base/firmware_class.c |   58 +++++++++++++++++++++++++++++-------------
 1 file changed, 41 insertions(+), 17 deletions(-)

Index: linux/drivers/base/firmware_class.c
===================================================================
--- linux.orig/drivers/base/firmware_class.c
+++ linux/drivers/base/firmware_class.c
@@ -435,7 +435,7 @@ static void firmware_class_timeout(u_lon
 }
 
 static struct firmware_priv *
-fw_create_instance(struct firmware *firmware, const char *fw_name,
+fw_create_instance(const struct firmware *firmware, const char *fw_name,
 		   struct device *device, bool uevent, bool nowait)
 {
 	struct firmware_priv *fw_priv;
@@ -449,7 +449,7 @@ fw_create_instance(struct firmware *firm
 		goto err_out;
 	}
 
-	fw_priv->fw = firmware;
+	fw_priv->fw = (struct firmware *)firmware;
 	fw_priv->nowait = nowait;
 	strcpy(fw_priv->fw_id, fw_name);
 	init_completion(&fw_priv->completion);
@@ -510,13 +510,10 @@ static void fw_destroy_instance(struct f
 	device_unregister(f_dev);
 }
 
-static int _request_firmware(const struct firmware **firmware_p,
-			     const char *name, struct device *device,
-			     bool uevent, bool nowait)
+static int _request_firmware_prepare(const struct firmware **firmware_p,
+				     const char *name, struct device *device)
 {
-	struct firmware_priv *fw_priv;
 	struct firmware *firmware;
-	int retval = 0;
 
 	if (!firmware_p)
 		return -EINVAL;
@@ -533,10 +530,26 @@ static int _request_firmware(const struc
 		return 0;
 	}
 
+	return 1;
+}
+
+static void _request_firmware_cleanup(const struct firmware **firmware_p)
+{
+	release_firmware(*firmware_p);
+	*firmware_p = NULL;
+}
+
+static int _request_firmware(const struct firmware *firmware,
+			     const char *name, struct device *device,
+			     bool uevent, bool nowait)
+{
+	struct firmware_priv *fw_priv;
+	int retval;
+
 	retval = usermodehelper_read_trylock();
 	if (WARN_ON(retval)) {
 		dev_err(device, "firmware: %s will not be loaded\n", name);
-		goto out_nolock;
+		return retval;
 	}
 
 	if (uevent)
@@ -572,13 +585,6 @@ static int _request_firmware(const struc
 
 out:
 	usermodehelper_read_unlock();
-
-out_nolock:
-	if (retval) {
-		release_firmware(firmware);
-		*firmware_p = NULL;
-	}
-
 	return retval;
 }
 
@@ -601,7 +607,17 @@ int
 request_firmware(const struct firmware **firmware_p, const char *name,
                  struct device *device)
 {
-        return _request_firmware(firmware_p, name, device, true, false);
+	int ret;
+
+	ret = _request_firmware_prepare(firmware_p, name, device);
+	if (ret <= 0)
+		return ret;
+
+	ret = _request_firmware(*firmware_p, name, device, true, false);
+	if (ret)
+		_request_firmware_cleanup(firmware_p);
+
+	return ret;
 }
 
 /**
@@ -639,8 +655,16 @@ static int request_firmware_work_func(vo
 		return 0;
 	}
 
-	ret = _request_firmware(&fw, fw_work->name, fw_work->device,
+	ret = _request_firmware_prepare(&fw, fw_work->name, fw_work->device);
+	if (ret <= 0)
+		goto out;
+
+	ret = _request_firmware(fw, fw_work->name, fw_work->device,
 				fw_work->uevent, true);
+	if (ret)
+		_request_firmware_cleanup(&fw);
+
+ out:
 	fw_work->cont(fw, fw_work->context);
 
 	module_put(fw_work->module);


^ permalink raw reply	[flat|nested] 111+ messages in thread

* [PATCH v3 3/8] firmware_class: Do not warn that system is not ready from async loads
  2012-03-28 21:19                                           ` [PATCH v2 0/8] firmware_class: Fix problems with usermodehelper test Rafael J. Wysocki
  2012-03-28 21:20                                             ` [PATCH v2 1/8] firmware_class: Rework usermodehelper check Rafael J. Wysocki
  2012-03-28 21:21                                             ` [PATCH v2 2/8] firmware_class: Split _request_firmware() into three functions, v2 Rafael J. Wysocki
@ 2012-03-28 21:22                                             ` Rafael J. Wysocki
  2012-03-28 21:23                                             ` [PATCH v2 4/8] PM / Hibernate: Disable usermode helpers right before freezing tasks Rafael J. Wysocki
                                                               ` (4 subsequent siblings)
  7 siblings, 0 replies; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-28 21:22 UTC (permalink / raw)
  To: linux-kernel
  Cc: Stephen Boyd, Linus Torvalds, Saravana Kannan, Kay Sievers,
	Greg KH, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list

From: Rafael J. Wysocki <rjw@sisk.pl>

If firmware is requested asynchronously, by calling
request_firmware_nowait(), there is no reason to fail the request
(and warn the user) when the system is (presumably temporarily)
unready to handle it (because user space is not available yet or
frozen).  For this reason, introduce an alternative routine for
read-locking umhelper_sem, usermodehelper_read_lock_wait(), that
will wait for usermodehelper_disabled to be unset (possibly with
a timeout) and make request_firmware_work_func() use it instead of
usermodehelper_read_trylock().

Accordingly, modify request_firmware() so that it uses
usermodehelper_read_trylock() to acquire umhelper_sem and remove
the code related to that lock from _request_firmware().

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 drivers/base/firmware_class.c |   51 +++++++++++++++++++++---------------
 include/linux/kmod.h          |    1 
 kernel/kmod.c                 |   58 ++++++++++++++++++++++++++++++++----------
 3 files changed, 76 insertions(+), 34 deletions(-)

Index: linux/include/linux/kmod.h
===================================================================
--- linux.orig/include/linux/kmod.h
+++ linux/include/linux/kmod.h
@@ -115,6 +115,7 @@ extern void usermodehelper_init(void);
 extern int usermodehelper_disable(void);
 extern void usermodehelper_enable(void);
 extern int usermodehelper_read_trylock(void);
+extern long usermodehelper_read_lock_wait(long timeout);
 extern void usermodehelper_read_unlock(void);
 
 #endif /* __LINUX_KMOD_H__ */
Index: linux/kernel/kmod.c
===================================================================
--- linux.orig/kernel/kmod.c
+++ linux/kernel/kmod.c
@@ -334,6 +334,12 @@ static atomic_t running_helpers = ATOMIC
 static DECLARE_WAIT_QUEUE_HEAD(running_helpers_waitq);
 
 /*
+ * Used by usermodehelper_read_lock_wait() to wait for usermodehelper_disabled
+ * to become 'false'.
+ */
+static DECLARE_WAIT_QUEUE_HEAD(usermodehelper_disabled_waitq);
+
+/*
  * Time to wait for running_helpers to become zero before the setting of
  * usermodehelper_disabled in usermodehelper_disable() fails
  */
@@ -352,6 +358,33 @@ int usermodehelper_read_trylock(void)
 }
 EXPORT_SYMBOL_GPL(usermodehelper_read_trylock);
 
+long usermodehelper_read_lock_wait(long timeout)
+{
+	DEFINE_WAIT(wait);
+
+	if (timeout < 0)
+		return -EINVAL;
+
+	down_read(&umhelper_sem);
+	for (;;) {
+		prepare_to_wait(&usermodehelper_disabled_waitq, &wait,
+				TASK_UNINTERRUPTIBLE);
+		if (!usermodehelper_disabled)
+			break;
+
+		up_read(&umhelper_sem);
+
+		timeout = schedule_timeout(timeout);
+		if (!timeout)
+			break;
+
+		down_read(&umhelper_sem);
+	}
+	finish_wait(&usermodehelper_disabled_waitq, &wait);
+	return timeout;
+}
+EXPORT_SYMBOL_GPL(usermodehelper_read_lock_wait);
+
 void usermodehelper_read_unlock(void)
 {
 	up_read(&umhelper_sem);
@@ -359,6 +392,17 @@ void usermodehelper_read_unlock(void)
 EXPORT_SYMBOL_GPL(usermodehelper_read_unlock);
 
 /**
+ * usermodehelper_enable - allow new helpers to be started again
+ */
+void usermodehelper_enable(void)
+{
+	down_write(&umhelper_sem);
+	usermodehelper_disabled = 0;
+	wake_up(&usermodehelper_disabled_waitq);
+	up_write(&umhelper_sem);
+}
+
+/**
  * usermodehelper_disable - prevent new helpers from being started
  */
 int usermodehelper_disable(void)
@@ -381,22 +425,10 @@ int usermodehelper_disable(void)
 	if (retval)
 		return 0;
 
-	down_write(&umhelper_sem);
-	usermodehelper_disabled = 0;
-	up_write(&umhelper_sem);
+	usermodehelper_enable();
 	return -EAGAIN;
 }
 
-/**
- * usermodehelper_enable - allow new helpers to be started again
- */
-void usermodehelper_enable(void)
-{
-	down_write(&umhelper_sem);
-	usermodehelper_disabled = 0;
-	up_write(&umhelper_sem);
-}
-
 static void helper_lock(void)
 {
 	atomic_inc(&running_helpers);
Index: linux/drivers/base/firmware_class.c
===================================================================
--- linux.orig/drivers/base/firmware_class.c
+++ linux/drivers/base/firmware_class.c
@@ -81,6 +81,11 @@ enum {
 
 static int loading_timeout = 60;	/* In seconds */
 
+static inline long firmware_loading_timeout(void)
+{
+	return loading_timeout > 0 ? loading_timeout * HZ : MAX_SCHEDULE_TIMEOUT;
+}
+
 /* fw_lock could be moved to 'struct firmware_priv' but since it is just
  * guarding for corner cases a global lock should be OK */
 static DEFINE_MUTEX(fw_lock);
@@ -541,31 +546,22 @@ static void _request_firmware_cleanup(co
 
 static int _request_firmware(const struct firmware *firmware,
 			     const char *name, struct device *device,
-			     bool uevent, bool nowait)
+			     bool uevent, bool nowait, long timeout)
 {
 	struct firmware_priv *fw_priv;
-	int retval;
-
-	retval = usermodehelper_read_trylock();
-	if (WARN_ON(retval)) {
-		dev_err(device, "firmware: %s will not be loaded\n", name);
-		return retval;
-	}
+	int retval = 0;
 
 	if (uevent)
 		dev_dbg(device, "firmware: requesting %s\n", name);
 
 	fw_priv = fw_create_instance(firmware, name, device, uevent, nowait);
-	if (IS_ERR(fw_priv)) {
-		retval = PTR_ERR(fw_priv);
-		goto out;
-	}
+	if (IS_ERR(fw_priv))
+		return PTR_ERR(fw_priv);
 
 	if (uevent) {
-		if (loading_timeout > 0)
+		if (timeout != MAX_SCHEDULE_TIMEOUT)
 			mod_timer(&fw_priv->timeout,
-				  round_jiffies_up(jiffies +
-						   loading_timeout * HZ));
+				  round_jiffies_up(jiffies + timeout));
 
 		kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD);
 	}
@@ -582,9 +578,6 @@ static int _request_firmware(const struc
 	mutex_unlock(&fw_lock);
 
 	fw_destroy_instance(fw_priv);
-
-out:
-	usermodehelper_read_unlock();
 	return retval;
 }
 
@@ -613,7 +606,14 @@ request_firmware(const struct firmware *
 	if (ret <= 0)
 		return ret;
 
-	ret = _request_firmware(*firmware_p, name, device, true, false);
+	ret = usermodehelper_read_trylock();
+	if (WARN_ON(ret)) {
+		dev_err(device, "firmware: %s will not be loaded\n", name);
+	} else {
+		ret = _request_firmware(*firmware_p, name, device, true, false,
+					firmware_loading_timeout());
+		usermodehelper_read_unlock();
+	}
 	if (ret)
 		_request_firmware_cleanup(firmware_p);
 
@@ -648,6 +648,7 @@ static int request_firmware_work_func(vo
 {
 	struct firmware_work *fw_work = arg;
 	const struct firmware *fw;
+	long timeout;
 	int ret;
 
 	if (!arg) {
@@ -659,8 +660,16 @@ static int request_firmware_work_func(vo
 	if (ret <= 0)
 		goto out;
 
-	ret = _request_firmware(fw, fw_work->name, fw_work->device,
-				fw_work->uevent, true);
+	timeout = usermodehelper_read_lock_wait(firmware_loading_timeout());
+	if (timeout) {
+		ret = _request_firmware(fw, fw_work->name, fw_work->device,
+					fw_work->uevent, true, timeout);
+		usermodehelper_read_unlock();
+	} else {
+		dev_dbg(fw_work->device, "firmware: %s loading timed out\n",
+			fw_work->name);
+		ret = -EAGAIN;
+	}
 	if (ret)
 		_request_firmware_cleanup(&fw);
 


^ permalink raw reply	[flat|nested] 111+ messages in thread

* [PATCH v2 4/8] PM / Hibernate: Disable usermode helpers right before freezing tasks
  2012-03-28 21:19                                           ` [PATCH v2 0/8] firmware_class: Fix problems with usermodehelper test Rafael J. Wysocki
                                                               ` (2 preceding siblings ...)
  2012-03-28 21:22                                             ` [PATCH v3 3/8] firmware_class: Do not warn that system is not ready from async loads Rafael J. Wysocki
@ 2012-03-28 21:23                                             ` Rafael J. Wysocki
  2012-03-28 21:23                                             ` [PATCH v2 5/8] PM / Sleep: Move disabling of usermode helpers to the freezer Rafael J. Wysocki
                                                               ` (3 subsequent siblings)
  7 siblings, 0 replies; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-28 21:23 UTC (permalink / raw)
  To: linux-kernel
  Cc: Stephen Boyd, Linus Torvalds, Saravana Kannan, Kay Sievers,
	Greg KH, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list

From: Rafael J. Wysocki <rjw@sisk.pl>

There is no reason to call usermodehelper_disable() before creating
memory bitmaps in hibernate() and software_resume(), so call it right
before freeze_processes(), in accordance with the other suspend and
hibernation code.  Consequently, call usermodehelper_enable() right
after the thawing of tasks rather than after freeing the memory
bitmaps.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 kernel/power/hibernate.c |   23 ++++++++++-------------
 1 file changed, 10 insertions(+), 13 deletions(-)

Index: linux/kernel/power/hibernate.c
===================================================================
--- linux.orig/kernel/power/hibernate.c
+++ linux/kernel/power/hibernate.c
@@ -611,19 +611,19 @@ int hibernate(void)
 	if (error)
 		goto Exit;
 
-	error = usermodehelper_disable();
-	if (error)
-		goto Exit;
-
 	/* Allocate memory management structures */
 	error = create_basic_memory_bitmaps();
 	if (error)
-		goto Enable_umh;
+		goto Exit;
 
 	printk(KERN_INFO "PM: Syncing filesystems ... ");
 	sys_sync();
 	printk("done.\n");
 
+	error = usermodehelper_disable();
+	if (error)
+		goto Exit;
+
 	error = freeze_processes();
 	if (error)
 		goto Free_bitmaps;
@@ -660,9 +660,8 @@ int hibernate(void)
 	freezer_test_done = false;
 
  Free_bitmaps:
-	free_basic_memory_bitmaps();
- Enable_umh:
 	usermodehelper_enable();
+	free_basic_memory_bitmaps();
  Exit:
 	pm_notifier_call_chain(PM_POST_HIBERNATION);
 	pm_restore_console();
@@ -777,15 +776,13 @@ static int software_resume(void)
 	if (error)
 		goto close_finish;
 
-	error = usermodehelper_disable();
+	error = create_basic_memory_bitmaps();
 	if (error)
 		goto close_finish;
 
-	error = create_basic_memory_bitmaps();
-	if (error) {
-		usermodehelper_enable();
+	error = usermodehelper_disable();
+	if (error)
 		goto close_finish;
-	}
 
 	pr_debug("PM: Preparing processes for restore.\n");
 	error = freeze_processes();
@@ -805,8 +802,8 @@ static int software_resume(void)
 	swsusp_free();
 	thaw_processes();
  Done:
-	free_basic_memory_bitmaps();
 	usermodehelper_enable();
+	free_basic_memory_bitmaps();
  Finish:
 	pm_notifier_call_chain(PM_POST_RESTORE);
 	pm_restore_console();


^ permalink raw reply	[flat|nested] 111+ messages in thread

* [PATCH v2 5/8] PM / Sleep: Move disabling of usermode helpers to the freezer
  2012-03-28 21:19                                           ` [PATCH v2 0/8] firmware_class: Fix problems with usermodehelper test Rafael J. Wysocki
                                                               ` (3 preceding siblings ...)
  2012-03-28 21:23                                             ` [PATCH v2 4/8] PM / Hibernate: Disable usermode helpers right before freezing tasks Rafael J. Wysocki
@ 2012-03-28 21:23                                             ` Rafael J. Wysocki
  2012-03-28 21:24                                             ` [PATCH v2 6/8] PM / Sleep: Mitigate race between the freezer and request_firmware() Rafael J. Wysocki
                                                               ` (2 subsequent siblings)
  7 siblings, 0 replies; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-28 21:23 UTC (permalink / raw)
  To: linux-kernel
  Cc: Stephen Boyd, Linus Torvalds, Saravana Kannan, Kay Sievers,
	Greg KH, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list

From: Rafael J. Wysocki <rjw@sisk.pl>

The core suspend/hibernation code calls usermodehelper_disable() to
avoid race conditions between the freezer and the starting of
usermode helpers and each code path has to do that on its own.
However, it is always called right before freeze_processes()
and usermodehelper_enable() is always called right after
thaw_processes().  For this reason, to avoid code duplication and
to make the connection between usermodehelper_disable() and the
freezer more visible, make freeze_processes() call it and remove the
direct usermodehelper_disable() and usermodehelper_enable() calls
from all suspend/hibernation code paths.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 kernel/power/hibernate.c |   11 -----------
 kernel/power/process.c   |    7 +++++++
 kernel/power/suspend.c   |    7 -------
 kernel/power/user.c      |   10 +---------
 4 files changed, 8 insertions(+), 27 deletions(-)

Index: linux/kernel/power/process.c
===================================================================
--- linux.orig/kernel/power/process.c
+++ linux/kernel/power/process.c
@@ -16,6 +16,7 @@
 #include <linux/freezer.h>
 #include <linux/delay.h>
 #include <linux/workqueue.h>
+#include <linux/kmod.h>
 
 /* 
  * Timeout for stopping processes
@@ -122,6 +123,10 @@ int freeze_processes(void)
 {
 	int error;
 
+	error = usermodehelper_disable();
+	if (error)
+		return error;
+
 	if (!pm_freezing)
 		atomic_inc(&system_freezing_cnt);
 
@@ -187,6 +192,8 @@ void thaw_processes(void)
 	} while_each_thread(g, p);
 	read_unlock(&tasklist_lock);
 
+	usermodehelper_enable();
+
 	schedule();
 	printk("done.\n");
 }
Index: linux/kernel/power/suspend.c
===================================================================
--- linux.orig/kernel/power/suspend.c
+++ linux/kernel/power/suspend.c
@@ -12,7 +12,6 @@
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/init.h>
-#include <linux/kmod.h>
 #include <linux/console.h>
 #include <linux/cpu.h>
 #include <linux/syscalls.h>
@@ -102,17 +101,12 @@ static int suspend_prepare(void)
 	if (error)
 		goto Finish;
 
-	error = usermodehelper_disable();
-	if (error)
-		goto Finish;
-
 	error = suspend_freeze_processes();
 	if (!error)
 		return 0;
 
 	suspend_stats.failed_freeze++;
 	dpm_save_failed_step(SUSPEND_FREEZE);
-	usermodehelper_enable();
  Finish:
 	pm_notifier_call_chain(PM_POST_SUSPEND);
 	pm_restore_console();
@@ -259,7 +253,6 @@ int suspend_devices_and_enter(suspend_st
 static void suspend_finish(void)
 {
 	suspend_thaw_processes();
-	usermodehelper_enable();
 	pm_notifier_call_chain(PM_POST_SUSPEND);
 	pm_restore_console();
 }
Index: linux/kernel/power/hibernate.c
===================================================================
--- linux.orig/kernel/power/hibernate.c
+++ linux/kernel/power/hibernate.c
@@ -16,7 +16,6 @@
 #include <linux/string.h>
 #include <linux/device.h>
 #include <linux/async.h>
-#include <linux/kmod.h>
 #include <linux/delay.h>
 #include <linux/fs.h>
 #include <linux/mount.h>
@@ -620,10 +619,6 @@ int hibernate(void)
 	sys_sync();
 	printk("done.\n");
 
-	error = usermodehelper_disable();
-	if (error)
-		goto Exit;
-
 	error = freeze_processes();
 	if (error)
 		goto Free_bitmaps;
@@ -660,7 +655,6 @@ int hibernate(void)
 	freezer_test_done = false;
 
  Free_bitmaps:
-	usermodehelper_enable();
 	free_basic_memory_bitmaps();
  Exit:
 	pm_notifier_call_chain(PM_POST_HIBERNATION);
@@ -780,10 +774,6 @@ static int software_resume(void)
 	if (error)
 		goto close_finish;
 
-	error = usermodehelper_disable();
-	if (error)
-		goto close_finish;
-
 	pr_debug("PM: Preparing processes for restore.\n");
 	error = freeze_processes();
 	if (error) {
@@ -802,7 +792,6 @@ static int software_resume(void)
 	swsusp_free();
 	thaw_processes();
  Done:
-	usermodehelper_enable();
 	free_basic_memory_bitmaps();
  Finish:
 	pm_notifier_call_chain(PM_POST_RESTORE);
Index: linux/kernel/power/user.c
===================================================================
--- linux.orig/kernel/power/user.c
+++ linux/kernel/power/user.c
@@ -12,7 +12,6 @@
 #include <linux/suspend.h>
 #include <linux/syscalls.h>
 #include <linux/reboot.h>
-#include <linux/kmod.h>
 #include <linux/string.h>
 #include <linux/device.h>
 #include <linux/miscdevice.h>
@@ -222,14 +221,8 @@ static long snapshot_ioctl(struct file *
 		sys_sync();
 		printk("done.\n");
 
-		error = usermodehelper_disable();
-		if (error)
-			break;
-
 		error = freeze_processes();
-		if (error)
-			usermodehelper_enable();
-		else
+		if (!error)
 			data->frozen = 1;
 		break;
 
@@ -238,7 +231,6 @@ static long snapshot_ioctl(struct file *
 			break;
 		pm_restore_gfp_mask();
 		thaw_processes();
-		usermodehelper_enable();
 		data->frozen = 0;
 		break;
 


^ permalink raw reply	[flat|nested] 111+ messages in thread

* [PATCH v2 6/8] PM / Sleep: Mitigate race between the freezer and request_firmware()
  2012-03-28 21:19                                           ` [PATCH v2 0/8] firmware_class: Fix problems with usermodehelper test Rafael J. Wysocki
                                                               ` (4 preceding siblings ...)
  2012-03-28 21:23                                             ` [PATCH v2 5/8] PM / Sleep: Move disabling of usermode helpers to the freezer Rafael J. Wysocki
@ 2012-03-28 21:24                                             ` Rafael J. Wysocki
  2012-03-28 21:25                                             ` [PATCH v2 7/8] firmware_class: Reorganize fw_create_instance() Rafael J. Wysocki
  2012-03-28 21:26                                             ` [PATCH v2 8/8] firmware_class: Move request_firmware_nowait() to workqueues Rafael J. Wysocki
  7 siblings, 0 replies; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-28 21:24 UTC (permalink / raw)
  To: linux-kernel
  Cc: Stephen Boyd, Linus Torvalds, Saravana Kannan, Kay Sievers,
	Greg KH, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list

From: Rafael J. Wysocki <rjw@sisk.pl>

There is a race condition between the freezer and request_firmware()
such that if request_firmware() is run on one CPU and
freeze_processes() is run on another CPU and usermodehelper_disable()
called by it succeeds to grab umhelper_sem for writing before
usermodehelper_read_trylock() called from request_firmware()
acquires it for reading, the request_firmware() will fail and
trigger a WARN_ON() complaining that it was called at a wrong time.
However, in fact, it wasn't called at a wrong time and
freeze_processes() simply happened to be executed simultaneously.

To avoid this race, at least in some cases, modify
usermodehelper_read_trylock() so that it doesn't fail if the
freezing of tasks has just started and hasn't been completed yet.
Instead, during the freezing of tasks, it will try to freeze the
task that has called it so that it can wait until user space is
thawed without triggering the scary warning.

For this purpose, change usermodehelper_disabled so that it can
take three different values, UMH_ENABLED (0), UMH_FREEZING and
UMH_DISABLED.  The first one means that usermode helpers are
enabled, the last one means "hard disable" (i.e. the system is not
ready for usermode helpers to be used) and the second one
is reserved for the freezer.  Namely, when freeze_processes() is
started, it sets usermodehelper_disabled to UMH_FREEZING which
tells usermodehelper_read_trylock() that it shouldn't fail just
yet and should call try_to_freeze() if woken up and cannot
return immediately.  This way all freezable tasks that happen
to call request_firmware() right before freeze_processes() is
started and lose the race for umhelper_sem with it will be
frozen and will sleep until thaw_processes() unsets
usermodehelper_disabled.  [For the non-freezable callers of
request_firmware() the race for umhelper_sem against
freeze_processes() is unfortunately unavoidable.]

Reported-by: Stephen Boyd <sboyd@codeaurora.org>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 include/linux/kmod.h   |   21 +++++++++++++++++++--
 kernel/kmod.c          |   47 +++++++++++++++++++++++++++++++++++++----------
 kernel/power/process.c |    3 ++-
 3 files changed, 58 insertions(+), 13 deletions(-)

Index: linux/include/linux/kmod.h
===================================================================
--- linux.orig/include/linux/kmod.h
+++ linux/include/linux/kmod.h
@@ -110,10 +110,27 @@ call_usermodehelper(char *path, char **a
 
 extern struct ctl_table usermodehelper_table[];
 
+enum umh_disable_depth {
+	UMH_ENABLED = 0,
+	UMH_FREEZING,
+	UMH_DISABLED,
+};
+
 extern void usermodehelper_init(void);
 
-extern int usermodehelper_disable(void);
-extern void usermodehelper_enable(void);
+extern int __usermodehelper_disable(enum umh_disable_depth depth);
+extern void __usermodehelper_set_disable_depth(enum umh_disable_depth depth);
+
+static inline int usermodehelper_disable(void)
+{
+	return __usermodehelper_disable(UMH_DISABLED);
+}
+
+static inline void usermodehelper_enable(void)
+{
+	__usermodehelper_set_disable_depth(UMH_ENABLED);
+}
+
 extern int usermodehelper_read_trylock(void);
 extern long usermodehelper_read_lock_wait(long timeout);
 extern void usermodehelper_read_unlock(void);
Index: linux/kernel/kmod.c
===================================================================
--- linux.orig/kernel/kmod.c
+++ linux/kernel/kmod.c
@@ -322,7 +322,7 @@ static void __call_usermodehelper(struct
  * land has been frozen during a system-wide hibernation or suspend operation).
  * Should always be manipulated under umhelper_sem acquired for write.
  */
-static int usermodehelper_disabled = 1;
+static enum umh_disable_depth usermodehelper_disabled = UMH_DISABLED;
 
 /* Number of helpers running */
 static atomic_t running_helpers = ATOMIC_INIT(0);
@@ -347,13 +347,30 @@ static DECLARE_WAIT_QUEUE_HEAD(usermodeh
 
 int usermodehelper_read_trylock(void)
 {
+	DEFINE_WAIT(wait);
 	int ret = 0;
 
 	down_read(&umhelper_sem);
-	if (usermodehelper_disabled) {
+	for (;;) {
+		prepare_to_wait(&usermodehelper_disabled_waitq, &wait,
+				TASK_INTERRUPTIBLE);
+		if (!usermodehelper_disabled)
+			break;
+
+		if (usermodehelper_disabled == UMH_DISABLED)
+			ret = -EAGAIN;
+
 		up_read(&umhelper_sem);
-		ret = -EAGAIN;
+
+		if (ret)
+			break;
+
+		schedule();
+		try_to_freeze();
+
+		down_read(&umhelper_sem);
 	}
+	finish_wait(&usermodehelper_disabled_waitq, &wait);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(usermodehelper_read_trylock);
@@ -392,25 +409,35 @@ void usermodehelper_read_unlock(void)
 EXPORT_SYMBOL_GPL(usermodehelper_read_unlock);
 
 /**
- * usermodehelper_enable - allow new helpers to be started again
+ * __usermodehelper_set_disable_depth - Modify usermodehelper_disabled.
+ * depth: New value to assign to usermodehelper_disabled.
+ *
+ * Change the value of usermodehelper_disabled (under umhelper_sem locked for
+ * writing) and wakeup tasks waiting for it to change.
  */
-void usermodehelper_enable(void)
+void __usermodehelper_set_disable_depth(enum umh_disable_depth depth)
 {
 	down_write(&umhelper_sem);
-	usermodehelper_disabled = 0;
+	usermodehelper_disabled = depth;
 	wake_up(&usermodehelper_disabled_waitq);
 	up_write(&umhelper_sem);
 }
 
 /**
- * usermodehelper_disable - prevent new helpers from being started
+ * __usermodehelper_disable - Prevent new helpers from being started.
+ * @depth: New value to assign to usermodehelper_disabled.
+ *
+ * Set usermodehelper_disabled to @depth and wait for running helpers to exit.
  */
-int usermodehelper_disable(void)
+int __usermodehelper_disable(enum umh_disable_depth depth)
 {
 	long retval;
 
+	if (!depth)
+		return -EINVAL;
+
 	down_write(&umhelper_sem);
-	usermodehelper_disabled = 1;
+	usermodehelper_disabled = depth;
 	up_write(&umhelper_sem);
 
 	/*
@@ -425,7 +452,7 @@ int usermodehelper_disable(void)
 	if (retval)
 		return 0;
 
-	usermodehelper_enable();
+	__usermodehelper_set_disable_depth(UMH_ENABLED);
 	return -EAGAIN;
 }
 
Index: linux/kernel/power/process.c
===================================================================
--- linux.orig/kernel/power/process.c
+++ linux/kernel/power/process.c
@@ -123,7 +123,7 @@ int freeze_processes(void)
 {
 	int error;
 
-	error = usermodehelper_disable();
+	error = __usermodehelper_disable(UMH_FREEZING);
 	if (error)
 		return error;
 
@@ -135,6 +135,7 @@ int freeze_processes(void)
 	error = try_to_freeze_tasks(true);
 	if (!error) {
 		printk("done.");
+		__usermodehelper_set_disable_depth(UMH_DISABLED);
 		oom_killer_disable();
 	}
 	printk("\n");


^ permalink raw reply	[flat|nested] 111+ messages in thread

* [PATCH v2 7/8] firmware_class: Reorganize fw_create_instance()
  2012-03-28 21:19                                           ` [PATCH v2 0/8] firmware_class: Fix problems with usermodehelper test Rafael J. Wysocki
                                                               ` (5 preceding siblings ...)
  2012-03-28 21:24                                             ` [PATCH v2 6/8] PM / Sleep: Mitigate race between the freezer and request_firmware() Rafael J. Wysocki
@ 2012-03-28 21:25                                             ` Rafael J. Wysocki
  2012-03-28 21:26                                             ` [PATCH v2 8/8] firmware_class: Move request_firmware_nowait() to workqueues Rafael J. Wysocki
  7 siblings, 0 replies; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-28 21:25 UTC (permalink / raw)
  To: linux-kernel
  Cc: Stephen Boyd, Linus Torvalds, Saravana Kannan, Kay Sievers,
	Greg KH, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list

From: Stephen Boyd <sboyd@codeaurora.org>

Recent patches to split up the three phases of request_firmware()
lead to a casting away of const in fw_create_instance(). We can
avoid this cast by splitting up fw_create_instance() a bit.

Make _request_firmware_setup() return a struct fw_priv and use
that struct instead of passing struct firmware to
_request_firmware(). Move the uevent and device file creation
bits to the loading phase and rename the function to
_request_firmware_load() to better reflect its purpose.

Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 drivers/base/firmware_class.c |  135 +++++++++++++++++++-----------------------
 1 file changed, 62 insertions(+), 73 deletions(-)

Index: linux/drivers/base/firmware_class.c
===================================================================
--- linux.orig/drivers/base/firmware_class.c
+++ linux/drivers/base/firmware_class.c
@@ -440,21 +440,19 @@ static void firmware_class_timeout(u_lon
 }
 
 static struct firmware_priv *
-fw_create_instance(const struct firmware *firmware, const char *fw_name,
+fw_create_instance(struct firmware *firmware, const char *fw_name,
 		   struct device *device, bool uevent, bool nowait)
 {
 	struct firmware_priv *fw_priv;
 	struct device *f_dev;
-	int error;
 
 	fw_priv = kzalloc(sizeof(*fw_priv) + strlen(fw_name) + 1 , GFP_KERNEL);
 	if (!fw_priv) {
 		dev_err(device, "%s: kmalloc failed\n", __func__);
-		error = -ENOMEM;
-		goto err_out;
+		return ERR_PTR(-ENOMEM);
 	}
 
-	fw_priv->fw = (struct firmware *)firmware;
+	fw_priv->fw = firmware;
 	fw_priv->nowait = nowait;
 	strcpy(fw_priv->fw_id, fw_name);
 	init_completion(&fw_priv->completion);
@@ -468,74 +466,37 @@ fw_create_instance(const struct firmware
 	f_dev->parent = device;
 	f_dev->class = &firmware_class;
 
-	dev_set_uevent_suppress(f_dev, true);
-
-	/* Need to pin this module until class device is destroyed */
-	__module_get(THIS_MODULE);
-
-	error = device_add(f_dev);
-	if (error) {
-		dev_err(device, "%s: device_register failed\n", __func__);
-		goto err_put_dev;
-	}
-
-	error = device_create_bin_file(f_dev, &firmware_attr_data);
-	if (error) {
-		dev_err(device, "%s: sysfs_create_bin_file failed\n", __func__);
-		goto err_del_dev;
-	}
-
-	error = device_create_file(f_dev, &dev_attr_loading);
-	if (error) {
-		dev_err(device, "%s: device_create_file failed\n", __func__);
-		goto err_del_bin_attr;
-	}
-
-	if (uevent)
-		dev_set_uevent_suppress(f_dev, false);
-
 	return fw_priv;
-
-err_del_bin_attr:
-	device_remove_bin_file(f_dev, &firmware_attr_data);
-err_del_dev:
-	device_del(f_dev);
-err_put_dev:
-	put_device(f_dev);
-err_out:
-	return ERR_PTR(error);
 }
 
-static void fw_destroy_instance(struct firmware_priv *fw_priv)
-{
-	struct device *f_dev = &fw_priv->dev;
-
-	device_remove_file(f_dev, &dev_attr_loading);
-	device_remove_bin_file(f_dev, &firmware_attr_data);
-	device_unregister(f_dev);
-}
-
-static int _request_firmware_prepare(const struct firmware **firmware_p,
-				     const char *name, struct device *device)
+static struct firmware_priv *
+_request_firmware_prepare(const struct firmware **firmware_p, const char *name,
+			  struct device *device, bool uevent, bool nowait)
 {
 	struct firmware *firmware;
+	struct firmware_priv *fw_priv;
 
 	if (!firmware_p)
-		return -EINVAL;
+		return ERR_PTR(-EINVAL);
 
 	*firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL);
 	if (!firmware) {
 		dev_err(device, "%s: kmalloc(struct firmware) failed\n",
 			__func__);
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 	}
 
 	if (fw_get_builtin_firmware(firmware, name)) {
 		dev_dbg(device, "firmware: using built-in firmware %s\n", name);
-		return 0;
+		return NULL;
 	}
 
-	return 1;
+	fw_priv = fw_create_instance(firmware, name, device, uevent, nowait);
+	if (IS_ERR(fw_priv)) {
+		release_firmware(firmware);
+		*firmware_p = NULL;
+	}
+	return fw_priv;
 }
 
 static void _request_firmware_cleanup(const struct firmware **firmware_p)
@@ -544,21 +505,38 @@ static void _request_firmware_cleanup(co
 	*firmware_p = NULL;
 }
 
-static int _request_firmware(const struct firmware *firmware,
-			     const char *name, struct device *device,
-			     bool uevent, bool nowait, long timeout)
+static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent,
+				  long timeout)
 {
-	struct firmware_priv *fw_priv;
 	int retval = 0;
+	struct device *f_dev = &fw_priv->dev;
+
+	dev_set_uevent_suppress(f_dev, true);
 
-	if (uevent)
-		dev_dbg(device, "firmware: requesting %s\n", name);
+	/* Need to pin this module until class device is destroyed */
+	__module_get(THIS_MODULE);
 
-	fw_priv = fw_create_instance(firmware, name, device, uevent, nowait);
-	if (IS_ERR(fw_priv))
-		return PTR_ERR(fw_priv);
+	retval = device_add(f_dev);
+	if (retval) {
+		dev_err(f_dev, "%s: device_register failed\n", __func__);
+		goto err_put_dev;
+	}
+
+	retval = device_create_bin_file(f_dev, &firmware_attr_data);
+	if (retval) {
+		dev_err(f_dev, "%s: sysfs_create_bin_file failed\n", __func__);
+		goto err_del_dev;
+	}
+
+	retval = device_create_file(f_dev, &dev_attr_loading);
+	if (retval) {
+		dev_err(f_dev, "%s: device_create_file failed\n", __func__);
+		goto err_del_bin_attr;
+	}
 
 	if (uevent) {
+		dev_set_uevent_suppress(f_dev, false);
+		dev_dbg(f_dev, "firmware: requesting %s\n", fw_priv->fw_id);
 		if (timeout != MAX_SCHEDULE_TIMEOUT)
 			mod_timer(&fw_priv->timeout,
 				  round_jiffies_up(jiffies + timeout));
@@ -577,7 +555,13 @@ static int _request_firmware(const struc
 	fw_priv->fw = NULL;
 	mutex_unlock(&fw_lock);
 
-	fw_destroy_instance(fw_priv);
+	device_remove_file(f_dev, &dev_attr_loading);
+err_del_bin_attr:
+	device_remove_bin_file(f_dev, &firmware_attr_data);
+err_del_dev:
+	device_del(f_dev);
+err_put_dev:
+	put_device(f_dev);
 	return retval;
 }
 
@@ -600,17 +584,19 @@ int
 request_firmware(const struct firmware **firmware_p, const char *name,
                  struct device *device)
 {
+	struct firmware_priv *fw_priv;
 	int ret;
 
-	ret = _request_firmware_prepare(firmware_p, name, device);
-	if (ret <= 0)
-		return ret;
+	fw_priv = _request_firmware_prepare(firmware_p, name, device, true,
+					    false);
+	if (IS_ERR_OR_NULL(fw_priv))
+		return PTR_RET(fw_priv);
 
 	ret = usermodehelper_read_trylock();
 	if (WARN_ON(ret)) {
 		dev_err(device, "firmware: %s will not be loaded\n", name);
 	} else {
-		ret = _request_firmware(*firmware_p, name, device, true, false,
+		ret = _request_firmware_load(fw_priv, true,
 					firmware_loading_timeout());
 		usermodehelper_read_unlock();
 	}
@@ -648,6 +634,7 @@ static int request_firmware_work_func(vo
 {
 	struct firmware_work *fw_work = arg;
 	const struct firmware *fw;
+	struct firmware_priv *fw_priv;
 	long timeout;
 	int ret;
 
@@ -656,14 +643,16 @@ static int request_firmware_work_func(vo
 		return 0;
 	}
 
-	ret = _request_firmware_prepare(&fw, fw_work->name, fw_work->device);
-	if (ret <= 0)
+	fw_priv = _request_firmware_prepare(&fw, fw_work->name, fw_work->device,
+			fw_work->uevent, true);
+	if (IS_ERR_OR_NULL(fw_priv)) {
+		ret = PTR_RET(fw_priv);
 		goto out;
+	}
 
 	timeout = usermodehelper_read_lock_wait(firmware_loading_timeout());
 	if (timeout) {
-		ret = _request_firmware(fw, fw_work->name, fw_work->device,
-					fw_work->uevent, true, timeout);
+		ret = _request_firmware_load(fw_priv, fw_work->uevent, timeout);
 		usermodehelper_read_unlock();
 	} else {
 		dev_dbg(fw_work->device, "firmware: %s loading timed out\n",


^ permalink raw reply	[flat|nested] 111+ messages in thread

* [PATCH v2 8/8] firmware_class: Move request_firmware_nowait() to workqueues
  2012-03-28 21:19                                           ` [PATCH v2 0/8] firmware_class: Fix problems with usermodehelper test Rafael J. Wysocki
                                                               ` (6 preceding siblings ...)
  2012-03-28 21:25                                             ` [PATCH v2 7/8] firmware_class: Reorganize fw_create_instance() Rafael J. Wysocki
@ 2012-03-28 21:26                                             ` Rafael J. Wysocki
  7 siblings, 0 replies; 111+ messages in thread
From: Rafael J. Wysocki @ 2012-03-28 21:26 UTC (permalink / raw)
  To: linux-kernel
  Cc: Stephen Boyd, Linus Torvalds, Saravana Kannan, Kay Sievers,
	Greg KH, Christian Lamparter, Srivatsa S. Bhat, alan,
	Linux PM mailing list

From: Stephen Boyd <sboyd@codeaurora.org>

Oddly enough a work_struct was already part of the firmware_work
structure but nobody was using it. Instead of creating a new
kthread for each request_firmware_nowait() call just schedule the
work on the system workqueue. This should avoid some overhead
in forking new threads when they're not strictly necessary.

Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 drivers/base/firmware_class.c |   27 +++++++--------------------
 1 file changed, 7 insertions(+), 20 deletions(-)

Index: linux/drivers/base/firmware_class.c
===================================================================
--- linux.orig/drivers/base/firmware_class.c
+++ linux/drivers/base/firmware_class.c
@@ -16,10 +16,11 @@
 #include <linux/interrupt.h>
 #include <linux/bitops.h>
 #include <linux/mutex.h>
-#include <linux/kthread.h>
+#include <linux/workqueue.h>
 #include <linux/highmem.h>
 #include <linux/firmware.h>
 #include <linux/slab.h>
+#include <linux/sched.h>
 
 #define to_dev(obj) container_of(obj, struct device, kobj)
 
@@ -630,19 +631,15 @@ struct firmware_work {
 	bool uevent;
 };
 
-static int request_firmware_work_func(void *arg)
+static void request_firmware_work_func(struct work_struct *work)
 {
-	struct firmware_work *fw_work = arg;
+	struct firmware_work *fw_work;
 	const struct firmware *fw;
 	struct firmware_priv *fw_priv;
 	long timeout;
 	int ret;
 
-	if (!arg) {
-		WARN_ON(1);
-		return 0;
-	}
-
+	fw_work = container_of(work, struct firmware_work, work);
 	fw_priv = _request_firmware_prepare(&fw, fw_work->name, fw_work->device,
 			fw_work->uevent, true);
 	if (IS_ERR_OR_NULL(fw_priv)) {
@@ -667,8 +664,6 @@ static int request_firmware_work_func(vo
 
 	module_put(fw_work->module);
 	kfree(fw_work);
-
-	return ret;
 }
 
 /**
@@ -694,7 +689,6 @@ request_firmware_nowait(
 	const char *name, struct device *device, gfp_t gfp, void *context,
 	void (*cont)(const struct firmware *fw, void *context))
 {
-	struct task_struct *task;
 	struct firmware_work *fw_work;
 
 	fw_work = kzalloc(sizeof (struct firmware_work), gfp);
@@ -713,15 +707,8 @@ request_firmware_nowait(
 		return -EFAULT;
 	}
 
-	task = kthread_run(request_firmware_work_func, fw_work,
-			    "firmware/%s", name);
-	if (IS_ERR(task)) {
-		fw_work->cont(NULL, fw_work->context);
-		module_put(fw_work->module);
-		kfree(fw_work);
-		return PTR_ERR(task);
-	}
-
+	INIT_WORK(&fw_work->work, request_firmware_work_func);
+	schedule_work(&fw_work->work);
 	return 0;
 }
 


^ permalink raw reply	[flat|nested] 111+ messages in thread

end of thread, other threads:[~2012-03-28 21:24 UTC | newest]

Thread overview: 111+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-03-03 20:22 [RFC] firmware loader: retry _nowait requests when userhelper is not yet available Christian Lamparter
2012-03-03 23:57 ` Alan Cox
2012-03-04  1:50   ` Christian Lamparter
2012-03-05 20:12 ` Srivatsa S. Bhat
2012-03-09 22:30   ` [PATCH] firmware loader: don't cancel _nowait requests when helper " Christian Lamparter
2012-03-09 23:36     ` Greg KH
2012-03-10  0:52       ` Christian Lamparter
2012-03-11 11:56       ` Kay Sievers
2012-03-13  9:37         ` Saravana Kannan
2012-03-13  9:43         ` Saravana Kannan
2012-03-13 20:14           ` Rafael J. Wysocki
2012-03-14 19:21             ` Stephen Boyd
2012-03-14 23:04               ` Rafael J. Wysocki
2012-03-14 23:13                 ` Rafael J. Wysocki
2012-03-14 23:17                   ` Stephen Boyd
2012-03-14 23:34                     ` Rafael J. Wysocki
2012-03-14 23:38                       ` Stephen Boyd
2012-03-15  0:11                         ` Rafael J. Wysocki
2012-03-15 19:50                           ` [PATCH] firmware_class: Move request_firmware_nowait() to workqueues Stephen Boyd
2012-03-15 20:07                             ` Christian Lamparter
2012-03-15 20:12                               ` Stephen Boyd
2012-03-15 22:31                                 ` Rafael J. Wysocki
2012-03-16  1:39                                   ` Stephen Boyd
2012-03-16 20:19                                     ` Rafael J. Wysocki
2012-03-16 20:26                                       ` Stephen Boyd
2012-03-16 21:45                                         ` Rafael J. Wysocki
2012-03-16 22:18                                           ` Christian Lamparter
2012-03-16 22:35                                             ` Rafael J. Wysocki
2012-03-17  2:47                           ` [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available Stephen Boyd
2012-03-17  5:51                             ` Linus Torvalds
2012-03-17 20:06                               ` Rafael J. Wysocki
2012-03-18  8:26                               ` Stephen Boyd
2012-03-18 12:01                                 ` Rafael J. Wysocki
2012-03-19  6:32                                   ` Stephen Boyd
2012-03-19 11:24                                     ` Rafael J. Wysocki
2012-03-19 23:00                                       ` Rafael J. Wysocki
2012-03-25 22:00                                         ` [PATCH 0/6] firmware_class: Fix problems with usermodehelper test Rafael J. Wysocki
2012-03-25 22:01                                           ` [PATCH 1/6] firmware_class: Rework usermodehelper check Rafael J. Wysocki
2012-03-25 22:01                                           ` [PATCH 2/6] firmware_class: Split _request_firmware() into three functions Rafael J. Wysocki
2012-03-26 18:15                                             ` Stephen Boyd
2012-03-26 18:21                                               ` Stephen Boyd
2012-03-26 20:12                                                 ` Rafael J. Wysocki
2012-03-26 20:31                                                   ` Stephen Boyd
2012-03-26 20:36                                               ` Rafael J. Wysocki
2012-03-27 21:35                                                 ` Stephen Boyd
2012-03-27 21:51                                                   ` Rafael J. Wysocki
2012-03-25 22:02                                           ` [PATCH 3/6] firmware_class: Do not warn that system is not ready from async loads Rafael J. Wysocki
2012-03-25 22:03                                           ` [PATCH 4/6] PM / Hibernate: Disable usermode helpers right before freezing tasks Rafael J. Wysocki
2012-03-25 22:03                                           ` [PATCH 5/6] PM / Sleep: Move disabling of usermode helpers to the freezer Rafael J. Wysocki
2012-03-25 22:04                                           ` [PATCH 6/6] PM / Sleep: Mitigate race between the freezer and request_firmware() Rafael J. Wysocki
2012-03-26 18:16                                             ` Stephen Boyd
2012-03-26 20:06                                               ` Rafael J. Wysocki
2012-03-27 21:25                                                 ` Stephen Boyd
2012-03-27 21:37                                                   ` Rafael J. Wysocki
2012-03-26 18:42                                           ` [PATCH 0/6] firmware_class: Fix problems with usermodehelper test Greg KH
2012-03-26 20:37                                             ` Rafael J. Wysocki
2012-03-27 21:28                                           ` [PATCH 1/2] firmware_class: Reorganize fw_create_instance() Stephen Boyd
2012-03-27 21:47                                             ` Rafael J. Wysocki
2012-03-27 21:49                                               ` Greg KH
2012-03-27 21:56                                                 ` Rafael J. Wysocki
2012-03-27 21:28                                           ` [PATCH 2/2] firmware_class: Move request_firmware_nowait() to workqueues Stephen Boyd
2012-03-27 21:49                                             ` Rafael J. Wysocki
2012-03-27 22:01                                             ` Tejun Heo
2012-03-27 22:21                                               ` Rafael J. Wysocki
2012-03-27 22:48                                                 ` Tejun Heo
2012-03-27 22:55                                                   ` Rafael J. Wysocki
2012-03-27 23:02                                                     ` Stephen Boyd
2012-03-27 23:05                                                     ` Stephen Boyd
2012-03-28 21:19                                           ` [PATCH v2 0/8] firmware_class: Fix problems with usermodehelper test Rafael J. Wysocki
2012-03-28 21:20                                             ` [PATCH v2 1/8] firmware_class: Rework usermodehelper check Rafael J. Wysocki
2012-03-28 21:21                                             ` [PATCH v2 2/8] firmware_class: Split _request_firmware() into three functions, v2 Rafael J. Wysocki
2012-03-28 21:22                                             ` [PATCH v3 3/8] firmware_class: Do not warn that system is not ready from async loads Rafael J. Wysocki
2012-03-28 21:23                                             ` [PATCH v2 4/8] PM / Hibernate: Disable usermode helpers right before freezing tasks Rafael J. Wysocki
2012-03-28 21:23                                             ` [PATCH v2 5/8] PM / Sleep: Move disabling of usermode helpers to the freezer Rafael J. Wysocki
2012-03-28 21:24                                             ` [PATCH v2 6/8] PM / Sleep: Mitigate race between the freezer and request_firmware() Rafael J. Wysocki
2012-03-28 21:25                                             ` [PATCH v2 7/8] firmware_class: Reorganize fw_create_instance() Rafael J. Wysocki
2012-03-28 21:26                                             ` [PATCH v2 8/8] firmware_class: Move request_firmware_nowait() to workqueues Rafael J. Wysocki
2012-03-14 23:19                 ` [PATCH] firmware loader: don't cancel _nowait requests when helper is not yet available Rafael J. Wysocki
2012-03-13 19:42         ` Rafael J. Wysocki
2012-03-13 23:25           ` Kay Sievers
2012-03-14  0:10             ` Rafael J. Wysocki
2012-03-14  0:14               ` Kay Sievers
2012-03-14  0:54                 ` Linus Torvalds
2012-03-14  1:43                   ` Kay Sievers
2012-03-14  1:51                     ` Linus Torvalds
2012-03-14  1:55                       ` Kay Sievers
2012-03-14  2:00                         ` Kay Sievers
2012-03-14  2:21                         ` Linus Torvalds
2012-03-14 15:07               ` Srivatsa S. Bhat
2012-03-14 22:54                 ` Rafael J. Wysocki
2012-03-16  7:14                   ` Srivatsa S. Bhat
2012-03-16 20:23                     ` Rafael J. Wysocki
2012-03-16 21:14                       ` Christian Lamparter
2012-03-16 21:19                         ` Linus Torvalds
2012-03-19  7:06                         ` Srivatsa S. Bhat
2012-03-16 22:19   ` [RFC] firmware loader: retry _nowait requests when userhelper " Rafael J. Wysocki
2012-03-16 22:25     ` Christian Lamparter
2012-03-16 22:57       ` Rafael J. Wysocki
2012-03-16 23:35         ` Christian Lamparter
2012-03-16 23:37         ` Linus Torvalds
2012-03-17  0:23           ` Rafael J. Wysocki
2012-03-17  0:33             ` Linus Torvalds
2012-03-18  0:29               ` Rafael J. Wysocki
2012-03-18  2:21                 ` Linus Torvalds
2012-03-18 12:21                   ` Rafael J. Wysocki
2012-03-18 12:43                 ` Christian Lamparter
2012-03-18 23:15                   ` [PATCH 0/3] firmware_class: Fix problem with async requests (was: Re: [RFC] firmware loader: retry ...) Rafael J. Wysocki
2012-03-18 23:17                     ` [PATCH 1/3] firmware_class: Rework usermodehelper check Rafael J. Wysocki
2012-03-18 23:18                     ` [PATCH 2/3] firmware_class: Split _request_firmware() into three functions Rafael J. Wysocki
2012-03-18 23:21                     ` [PATCH 3/3] firmware_class: Do not warn that system is not ready for async loads Rafael J. Wysocki
2012-03-19 12:41           ` [RFC] firmware loader: retry _nowait requests when userhelper is not yet available James Courtier-Dutton

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.