aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/drivers/net_kern.c
diff options
context:
space:
mode:
authorJeff Dike <jdike@addtoit.com>2007-05-06 17:51:04 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-07 15:13:00 -0400
commitf34d9d2dcb7f17b64124841345b23adc0843e7a5 (patch)
tree0bb200273bcc37da8dd32945ae25c213c9efe2c2 /arch/um/drivers/net_kern.c
parentb16895b63c504698b0c3ab26ca3c41a4fa162a42 (diff)
uml: network interface hotplug error handling
This fixes a number of problems associated with network interface hotplug. The userspace initialization function can fail in some cases, but the failure was never passed back to eth_configure, which proceeded with the configuration. This results in a zombie device that is present, but can't work. This is fixed by allowing the initialization routines to return an error, which is checked, and the configuration aborted on failure. eth_configure failed to check for many failures. Even when it did check, it didn't undo whatever initializations has already happened, so a present, but partially initialized and non-working device could result. It now checks everything that can fail, and bails out, undoing whatever had been done. The return value of eth_configure was always ignored, so it is now just void. Signed-off-by: Jeff Dike <jdike@linux.intel.com> Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> Cc: Jeff Garzik <jeff@garzik.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/um/drivers/net_kern.c')
-rw-r--r--arch/um/drivers/net_kern.c81
1 files changed, 46 insertions, 35 deletions
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
index 859303730b2f..ac746fb5d10f 100644
--- a/arch/um/drivers/net_kern.c
+++ b/arch/um/drivers/net_kern.c
@@ -325,8 +325,8 @@ static struct platform_driver uml_net_driver = {
325}; 325};
326static int driver_registered; 326static int driver_registered;
327 327
328static int eth_configure(int n, void *init, char *mac, 328static void eth_configure(int n, void *init, char *mac,
329 struct transport *transport) 329 struct transport *transport)
330{ 330{
331 struct uml_net *device; 331 struct uml_net *device;
332 struct net_device *dev; 332 struct net_device *dev;
@@ -339,16 +339,12 @@ static int eth_configure(int n, void *init, char *mac,
339 device = kzalloc(sizeof(*device), GFP_KERNEL); 339 device = kzalloc(sizeof(*device), GFP_KERNEL);
340 if (device == NULL) { 340 if (device == NULL) {
341 printk(KERN_ERR "eth_configure failed to allocate uml_net\n"); 341 printk(KERN_ERR "eth_configure failed to allocate uml_net\n");
342 return(1); 342 return;
343 } 343 }
344 344
345 INIT_LIST_HEAD(&device->list); 345 INIT_LIST_HEAD(&device->list);
346 device->index = n; 346 device->index = n;
347 347
348 spin_lock(&devices_lock);
349 list_add(&device->list, &devices);
350 spin_unlock(&devices_lock);
351
352 setup_etheraddr(mac, device->mac); 348 setup_etheraddr(mac, device->mac);
353 349
354 printk(KERN_INFO "Netdevice %d ", n); 350 printk(KERN_INFO "Netdevice %d ", n);
@@ -360,7 +356,7 @@ static int eth_configure(int n, void *init, char *mac,
360 dev = alloc_etherdev(size); 356 dev = alloc_etherdev(size);
361 if (dev == NULL) { 357 if (dev == NULL) {
362 printk(KERN_ERR "eth_configure: failed to allocate device\n"); 358 printk(KERN_ERR "eth_configure: failed to allocate device\n");
363 return 1; 359 goto out_free_device;
364 } 360 }
365 361
366 lp = dev->priv; 362 lp = dev->priv;
@@ -376,7 +372,8 @@ static int eth_configure(int n, void *init, char *mac,
376 } 372 }
377 device->pdev.id = n; 373 device->pdev.id = n;
378 device->pdev.name = DRIVER_NAME; 374 device->pdev.name = DRIVER_NAME;
379 platform_device_register(&device->pdev); 375 if(platform_device_register(&device->pdev))
376 goto out_free_netdev;
380 SET_NETDEV_DEV(dev,&device->pdev.dev); 377 SET_NETDEV_DEV(dev,&device->pdev.dev);
381 378
382 /* If this name ends up conflicting with an existing registered 379 /* If this name ends up conflicting with an existing registered
@@ -386,31 +383,12 @@ static int eth_configure(int n, void *init, char *mac,
386 snprintf(dev->name, sizeof(dev->name), "eth%d", n); 383 snprintf(dev->name, sizeof(dev->name), "eth%d", n);
387 device->dev = dev; 384 device->dev = dev;
388 385
386 /*
387 * These just fill in a data structure, so there's no failure
388 * to be worried about.
389 */
389 (*transport->kern->init)(dev, init); 390 (*transport->kern->init)(dev, init);
390 391
391 dev->mtu = transport->user->max_packet;
392 dev->open = uml_net_open;
393 dev->hard_start_xmit = uml_net_start_xmit;
394 dev->stop = uml_net_close;
395 dev->get_stats = uml_net_get_stats;
396 dev->set_multicast_list = uml_net_set_multicast_list;
397 dev->tx_timeout = uml_net_tx_timeout;
398 dev->set_mac_address = uml_net_set_mac;
399 dev->change_mtu = uml_net_change_mtu;
400 dev->ethtool_ops = &uml_net_ethtool_ops;
401 dev->watchdog_timeo = (HZ >> 1);
402 dev->irq = UM_ETH_IRQ;
403
404 rtnl_lock();
405 err = register_netdevice(dev);
406 rtnl_unlock();
407 if (err) {
408 device->dev = NULL;
409 /* XXX: should we call ->remove() here? */
410 free_netdev(dev);
411 return 1;
412 }
413
414 /* lp.user is the first four bytes of the transport data, which 392 /* lp.user is the first four bytes of the transport data, which
415 * has already been initialized. This structure assignment will 393 * has already been initialized. This structure assignment will
416 * overwrite that, so we make sure that .user gets overwritten with 394 * overwrite that, so we make sure that .user gets overwritten with
@@ -438,12 +416,45 @@ static int eth_configure(int n, void *init, char *mac,
438 lp->tl.function = uml_net_user_timer_expire; 416 lp->tl.function = uml_net_user_timer_expire;
439 memcpy(lp->mac, device->mac, sizeof(lp->mac)); 417 memcpy(lp->mac, device->mac, sizeof(lp->mac));
440 418
441 if (transport->user->init) 419 if ((transport->user->init != NULL) &&
442 (*transport->user->init)(&lp->user, dev); 420 ((*transport->user->init)(&lp->user, dev) != 0))
421 goto out_unregister;
443 422
444 set_ether_mac(dev, device->mac); 423 set_ether_mac(dev, device->mac);
424 dev->mtu = transport->user->max_packet;
425 dev->open = uml_net_open;
426 dev->hard_start_xmit = uml_net_start_xmit;
427 dev->stop = uml_net_close;
428 dev->get_stats = uml_net_get_stats;
429 dev->set_multicast_list = uml_net_set_multicast_list;
430 dev->tx_timeout = uml_net_tx_timeout;
431 dev->set_mac_address = uml_net_set_mac;
432 dev->change_mtu = uml_net_change_mtu;
433 dev->ethtool_ops = &uml_net_ethtool_ops;
434 dev->watchdog_timeo = (HZ >> 1);
435 dev->irq = UM_ETH_IRQ;
445 436
446 return 0; 437 rtnl_lock();
438 err = register_netdevice(dev);
439 rtnl_unlock();
440 if (err)
441 goto out_undo_user_init;
442
443 spin_lock(&devices_lock);
444 list_add(&device->list, &devices);
445 spin_unlock(&devices_lock);
446
447 return;
448
449out_undo_user_init:
450 if (transport->user->init != NULL)
451 (*transport->user->remove)(&lp->user);
452out_unregister:
453 platform_device_unregister(&device->pdev);
454out_free_netdev:
455 free_netdev(dev);
456out_free_device: ;
457 kfree(device);
447} 458}
448 459
449static struct uml_net *find_device(int n) 460static struct uml_net *find_device(int n)