ipconfig: Handle devices which take some time to come up.
Some network devices, particularly USB ones, take several seconds to fully init and appear in the device list. If the user turned ipconfig on, they are using it for NFS root or some other early booting purpose. So it makes no sense to just flat out fail immediately if the device isn't found. It also doesn't make sense to just jack up the initial wait to something crazy like 10 seconds. Instead, poll immediately, and then periodically once a second, waiting for a usable device to appear. Fail after 12 seconds. Signed-off-by: David S. Miller <davem@davemloft.net> Tested-by: Christian Pellegrin <chripell@fsfe.org>
This commit is contained in:
parent
717ea4b347
commit
964ad81cbd
1 changed files with 47 additions and 10 deletions
|
@ -187,6 +187,16 @@ struct ic_device {
|
|||
static struct ic_device *ic_first_dev __initdata = NULL;/* List of open device */
|
||||
static struct net_device *ic_dev __initdata = NULL; /* Selected device */
|
||||
|
||||
static bool __init ic_device_match(struct net_device *dev)
|
||||
{
|
||||
if (user_dev_name[0] ? !strcmp(dev->name, user_dev_name) :
|
||||
(!(dev->flags & IFF_LOOPBACK) &&
|
||||
(dev->flags & (IFF_POINTOPOINT|IFF_BROADCAST)) &&
|
||||
strncmp(dev->name, "dummy", 5)))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int __init ic_open_devs(void)
|
||||
{
|
||||
struct ic_device *d, **last;
|
||||
|
@ -207,10 +217,7 @@ static int __init ic_open_devs(void)
|
|||
for_each_netdev(&init_net, dev) {
|
||||
if (dev->flags & IFF_LOOPBACK)
|
||||
continue;
|
||||
if (user_dev_name[0] ? !strcmp(dev->name, user_dev_name) :
|
||||
(!(dev->flags & IFF_LOOPBACK) &&
|
||||
(dev->flags & (IFF_POINTOPOINT|IFF_BROADCAST)) &&
|
||||
strncmp(dev->name, "dummy", 5))) {
|
||||
if (ic_device_match(dev)) {
|
||||
int able = 0;
|
||||
if (dev->mtu >= 364)
|
||||
able |= IC_BOOTP;
|
||||
|
@ -228,7 +235,7 @@ static int __init ic_open_devs(void)
|
|||
}
|
||||
if (!(d = kmalloc(sizeof(struct ic_device), GFP_KERNEL))) {
|
||||
rtnl_unlock();
|
||||
return -1;
|
||||
return -ENOMEM;
|
||||
}
|
||||
d->dev = dev;
|
||||
*last = d;
|
||||
|
@ -253,7 +260,7 @@ static int __init ic_open_devs(void)
|
|||
printk(KERN_ERR "IP-Config: Device `%s' not found.\n", user_dev_name);
|
||||
else
|
||||
printk(KERN_ERR "IP-Config: No network devices available.\n");
|
||||
return -1;
|
||||
return -ENODEV;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -1303,6 +1310,32 @@ __be32 __init root_nfs_parse_addr(char *name)
|
|||
return addr;
|
||||
}
|
||||
|
||||
#define DEVICE_WAIT_MAX 12 /* 12 seconds */
|
||||
|
||||
static int __init wait_for_devices(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
msleep(CONF_PRE_OPEN);
|
||||
for (i = 0; i < DEVICE_WAIT_MAX; i++) {
|
||||
struct net_device *dev;
|
||||
int found = 0;
|
||||
|
||||
rtnl_lock();
|
||||
for_each_netdev(&init_net, dev) {
|
||||
if (ic_device_match(dev)) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
rtnl_unlock();
|
||||
if (found)
|
||||
return 0;
|
||||
ssleep(1);
|
||||
}
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* IP Autoconfig dispatcher.
|
||||
*/
|
||||
|
@ -1313,6 +1346,7 @@ static int __init ip_auto_config(void)
|
|||
#ifdef IPCONFIG_DYNAMIC
|
||||
int retries = CONF_OPEN_RETRIES;
|
||||
#endif
|
||||
int err;
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
proc_net_fops_create(&init_net, "pnp", S_IRUGO, &pnp_seq_fops);
|
||||
|
@ -1325,12 +1359,15 @@ static int __init ip_auto_config(void)
|
|||
#ifdef IPCONFIG_DYNAMIC
|
||||
try_try_again:
|
||||
#endif
|
||||
/* Give hardware a chance to settle */
|
||||
msleep(CONF_PRE_OPEN);
|
||||
/* Wait for devices to appear */
|
||||
err = wait_for_devices();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Setup all network devices */
|
||||
if (ic_open_devs() < 0)
|
||||
return -1;
|
||||
err = ic_open_devs();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Give drivers a chance to settle */
|
||||
ssleep(CONF_POST_OPEN);
|
||||
|
|
Loading…
Reference in a new issue