Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 298606
b: refs/heads/master
c: 9b78c1d
h: refs/heads/master
v: v3
  • Loading branch information
Rafael J. Wysocki committed Mar 28, 2012
1 parent 05b8d1a commit c7260a7
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 35 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 811fa4004485dec8977176bf605a5b0508ee206c
refs/heads/master: 9b78c1da60b3c62ccdd1509f0902ad19ceaf776b
51 changes: 30 additions & 21 deletions trunk/drivers/base/firmware_class.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -541,31 +546,22 @@ static void _request_firmware_cleanup(const struct firmware **firmware_p)

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);
}
Expand All @@ -582,9 +578,6 @@ static int _request_firmware(const struct firmware *firmware,
mutex_unlock(&fw_lock);

fw_destroy_instance(fw_priv);

out:
usermodehelper_read_unlock();
return retval;
}

Expand Down Expand Up @@ -613,7 +606,14 @@ request_firmware(const struct firmware **firmware_p, const char *name,
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);

Expand Down Expand Up @@ -648,6 +648,7 @@ static int request_firmware_work_func(void *arg)
{
struct firmware_work *fw_work = arg;
const struct firmware *fw;
long timeout;
int ret;

if (!arg) {
Expand All @@ -659,8 +660,16 @@ static int request_firmware_work_func(void *arg)
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);

Expand Down
1 change: 1 addition & 0 deletions trunk/include/linux/kmod.h
Original file line number Diff line number Diff line change
Expand Up @@ -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__ */
58 changes: 45 additions & 13 deletions trunk/kernel/kmod.c
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,12 @@ static atomic_t running_helpers = ATOMIC_INIT(0);
*/
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
Expand All @@ -352,12 +358,50 @@ 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);
}
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
*/
Expand All @@ -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);
Expand Down

0 comments on commit c7260a7

Please sign in to comment.