aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2012-03-28 17:30:02 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2012-03-28 17:30:02 -0400
commit9b78c1da60b3c62ccdd1509f0902ad19ceaf776b (patch)
tree1e662bb29f04c2b875207d907db917476ddce60b
parent811fa4004485dec8977176bf605a5b0508ee206c (diff)
firmware_class: Do not warn that system is not ready from async loads
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> Cc: stable@vger.kernel.org
-rw-r--r--drivers/base/firmware_class.c51
-rw-r--r--include/linux/kmod.h1
-rw-r--r--kernel/kmod.c58
3 files changed, 76 insertions, 34 deletions
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 60290671f04a..72c644b191a4 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -81,6 +81,11 @@ enum {
81 81
82static int loading_timeout = 60; /* In seconds */ 82static int loading_timeout = 60; /* In seconds */
83 83
84static inline long firmware_loading_timeout(void)
85{
86 return loading_timeout > 0 ? loading_timeout * HZ : MAX_SCHEDULE_TIMEOUT;
87}
88
84/* fw_lock could be moved to 'struct firmware_priv' but since it is just 89/* fw_lock could be moved to 'struct firmware_priv' but since it is just
85 * guarding for corner cases a global lock should be OK */ 90 * guarding for corner cases a global lock should be OK */
86static DEFINE_MUTEX(fw_lock); 91static DEFINE_MUTEX(fw_lock);
@@ -541,31 +546,22 @@ static void _request_firmware_cleanup(const struct firmware **firmware_p)
541 546
542static int _request_firmware(const struct firmware *firmware, 547static int _request_firmware(const struct firmware *firmware,
543 const char *name, struct device *device, 548 const char *name, struct device *device,
544 bool uevent, bool nowait) 549 bool uevent, bool nowait, long timeout)
545{ 550{
546 struct firmware_priv *fw_priv; 551 struct firmware_priv *fw_priv;
547 int retval; 552 int retval = 0;
548
549 retval = usermodehelper_read_trylock();
550 if (WARN_ON(retval)) {
551 dev_err(device, "firmware: %s will not be loaded\n", name);
552 return retval;
553 }
554 553
555 if (uevent) 554 if (uevent)
556 dev_dbg(device, "firmware: requesting %s\n", name); 555 dev_dbg(device, "firmware: requesting %s\n", name);
557 556
558 fw_priv = fw_create_instance(firmware, name, device, uevent, nowait); 557 fw_priv = fw_create_instance(firmware, name, device, uevent, nowait);
559 if (IS_ERR(fw_priv)) { 558 if (IS_ERR(fw_priv))
560 retval = PTR_ERR(fw_priv); 559 return PTR_ERR(fw_priv);
561 goto out;
562 }
563 560
564 if (uevent) { 561 if (uevent) {
565 if (loading_timeout > 0) 562 if (timeout != MAX_SCHEDULE_TIMEOUT)
566 mod_timer(&fw_priv->timeout, 563 mod_timer(&fw_priv->timeout,
567 round_jiffies_up(jiffies + 564 round_jiffies_up(jiffies + timeout));
568 loading_timeout * HZ));
569 565
570 kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD); 566 kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD);
571 } 567 }
@@ -582,9 +578,6 @@ static int _request_firmware(const struct firmware *firmware,
582 mutex_unlock(&fw_lock); 578 mutex_unlock(&fw_lock);
583 579
584 fw_destroy_instance(fw_priv); 580 fw_destroy_instance(fw_priv);
585
586out:
587 usermodehelper_read_unlock();
588 return retval; 581 return retval;
589} 582}
590 583
@@ -613,7 +606,14 @@ request_firmware(const struct firmware **firmware_p, const char *name,
613 if (ret <= 0) 606 if (ret <= 0)
614 return ret; 607 return ret;
615 608
616 ret = _request_firmware(*firmware_p, name, device, true, false); 609 ret = usermodehelper_read_trylock();
610 if (WARN_ON(ret)) {
611 dev_err(device, "firmware: %s will not be loaded\n", name);
612 } else {
613 ret = _request_firmware(*firmware_p, name, device, true, false,
614 firmware_loading_timeout());
615 usermodehelper_read_unlock();
616 }
617 if (ret) 617 if (ret)
618 _request_firmware_cleanup(firmware_p); 618 _request_firmware_cleanup(firmware_p);
619 619
@@ -648,6 +648,7 @@ static int request_firmware_work_func(void *arg)
648{ 648{
649 struct firmware_work *fw_work = arg; 649 struct firmware_work *fw_work = arg;
650 const struct firmware *fw; 650 const struct firmware *fw;
651 long timeout;
651 int ret; 652 int ret;
652 653
653 if (!arg) { 654 if (!arg) {
@@ -659,8 +660,16 @@ static int request_firmware_work_func(void *arg)
659 if (ret <= 0) 660 if (ret <= 0)
660 goto out; 661 goto out;
661 662
662 ret = _request_firmware(fw, fw_work->name, fw_work->device, 663 timeout = usermodehelper_read_lock_wait(firmware_loading_timeout());
663 fw_work->uevent, true); 664 if (timeout) {
665 ret = _request_firmware(fw, fw_work->name, fw_work->device,
666 fw_work->uevent, true, timeout);
667 usermodehelper_read_unlock();
668 } else {
669 dev_dbg(fw_work->device, "firmware: %s loading timed out\n",
670 fw_work->name);
671 ret = -EAGAIN;
672 }
664 if (ret) 673 if (ret)
665 _request_firmware_cleanup(&fw); 674 _request_firmware_cleanup(&fw);
666 675
diff --git a/include/linux/kmod.h b/include/linux/kmod.h
index 97d22c3e08b1..b087377ae2c4 100644
--- a/include/linux/kmod.h
+++ b/include/linux/kmod.h
@@ -115,6 +115,7 @@ extern void usermodehelper_init(void);
115extern int usermodehelper_disable(void); 115extern int usermodehelper_disable(void);
116extern void usermodehelper_enable(void); 116extern void usermodehelper_enable(void);
117extern int usermodehelper_read_trylock(void); 117extern int usermodehelper_read_trylock(void);
118extern long usermodehelper_read_lock_wait(long timeout);
118extern void usermodehelper_read_unlock(void); 119extern void usermodehelper_read_unlock(void);
119 120
120#endif /* __LINUX_KMOD_H__ */ 121#endif /* __LINUX_KMOD_H__ */
diff --git a/kernel/kmod.c b/kernel/kmod.c
index 4079ac1d5e79..da7fcca279f9 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -334,6 +334,12 @@ static atomic_t running_helpers = ATOMIC_INIT(0);
334static DECLARE_WAIT_QUEUE_HEAD(running_helpers_waitq); 334static DECLARE_WAIT_QUEUE_HEAD(running_helpers_waitq);
335 335
336/* 336/*
337 * Used by usermodehelper_read_lock_wait() to wait for usermodehelper_disabled
338 * to become 'false'.
339 */
340static DECLARE_WAIT_QUEUE_HEAD(usermodehelper_disabled_waitq);
341
342/*
337 * Time to wait for running_helpers to become zero before the setting of 343 * Time to wait for running_helpers to become zero before the setting of
338 * usermodehelper_disabled in usermodehelper_disable() fails 344 * usermodehelper_disabled in usermodehelper_disable() fails
339 */ 345 */
@@ -352,6 +358,33 @@ int usermodehelper_read_trylock(void)
352} 358}
353EXPORT_SYMBOL_GPL(usermodehelper_read_trylock); 359EXPORT_SYMBOL_GPL(usermodehelper_read_trylock);
354 360
361long usermodehelper_read_lock_wait(long timeout)
362{
363 DEFINE_WAIT(wait);
364
365 if (timeout < 0)
366 return -EINVAL;
367
368 down_read(&umhelper_sem);
369 for (;;) {
370 prepare_to_wait(&usermodehelper_disabled_waitq, &wait,
371 TASK_UNINTERRUPTIBLE);
372 if (!usermodehelper_disabled)
373 break;
374
375 up_read(&umhelper_sem);
376
377 timeout = schedule_timeout(timeout);
378 if (!timeout)
379 break;
380
381 down_read(&umhelper_sem);
382 }
383 finish_wait(&usermodehelper_disabled_waitq, &wait);
384 return timeout;
385}
386EXPORT_SYMBOL_GPL(usermodehelper_read_lock_wait);
387
355void usermodehelper_read_unlock(void) 388void usermodehelper_read_unlock(void)
356{ 389{
357 up_read(&umhelper_sem); 390 up_read(&umhelper_sem);
@@ -359,6 +392,17 @@ void usermodehelper_read_unlock(void)
359EXPORT_SYMBOL_GPL(usermodehelper_read_unlock); 392EXPORT_SYMBOL_GPL(usermodehelper_read_unlock);
360 393
361/** 394/**
395 * usermodehelper_enable - allow new helpers to be started again
396 */
397void usermodehelper_enable(void)
398{
399 down_write(&umhelper_sem);
400 usermodehelper_disabled = 0;
401 wake_up(&usermodehelper_disabled_waitq);
402 up_write(&umhelper_sem);
403}
404
405/**
362 * usermodehelper_disable - prevent new helpers from being started 406 * usermodehelper_disable - prevent new helpers from being started
363 */ 407 */
364int usermodehelper_disable(void) 408int usermodehelper_disable(void)
@@ -381,22 +425,10 @@ int usermodehelper_disable(void)
381 if (retval) 425 if (retval)
382 return 0; 426 return 0;
383 427
384 down_write(&umhelper_sem); 428 usermodehelper_enable();
385 usermodehelper_disabled = 0;
386 up_write(&umhelper_sem);
387 return -EAGAIN; 429 return -EAGAIN;
388} 430}
389 431
390/**
391 * usermodehelper_enable - allow new helpers to be started again
392 */
393void usermodehelper_enable(void)
394{
395 down_write(&umhelper_sem);
396 usermodehelper_disabled = 0;
397 up_write(&umhelper_sem);
398}
399
400static void helper_lock(void) 432static void helper_lock(void)
401{ 433{
402 atomic_inc(&running_helpers); 434 atomic_inc(&running_helpers);