Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f34d9d2d authored by Jeff Dike's avatar Jeff Dike Committed by Linus Torvalds
Browse files

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: default avatarJeff Dike <jdike@linux.intel.com>
Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Cc: Jeff Garzik <jeff@garzik.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent b16895b6
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -123,7 +123,7 @@ static int connect_to_switch(struct daemon_data *pri)
	return err;
}

static void daemon_user_init(void *data, void *dev)
static int daemon_user_init(void *data, void *dev)
{
	struct daemon_data *pri = data;
	struct timeval tv;
@@ -146,7 +146,10 @@ static void daemon_user_init(void *data, void *dev)
	if(pri->fd < 0){
		kfree(pri->local_addr);
		pri->local_addr = NULL;
		return pri->fd;
	}

	return 0;
}

static int daemon_open(void *data)
+2 −1
Original line number Diff line number Diff line
@@ -42,12 +42,13 @@ static struct sockaddr_in *new_addr(char *addr, unsigned short port)
	return sin;
}

static void mcast_user_init(void *data, void *dev)
static int mcast_user_init(void *data, void *dev)
{
	struct mcast_data *pri = data;

	pri->mcast_addr = new_addr(pri->addr, pri->port);
	pri->dev = dev;
	return 0;
}

static void mcast_remove(void *data)
+46 −35
Original line number Diff line number Diff line
@@ -325,7 +325,7 @@ static struct platform_driver uml_net_driver = {
};
static int driver_registered;

static int eth_configure(int n, void *init, char *mac,
static void eth_configure(int n, void *init, char *mac,
			  struct transport *transport)
{
	struct uml_net *device;
@@ -339,16 +339,12 @@ static int eth_configure(int n, void *init, char *mac,
	device = kzalloc(sizeof(*device), GFP_KERNEL);
	if (device == NULL) {
		printk(KERN_ERR "eth_configure failed to allocate uml_net\n");
		return(1);
		return;
	}

	INIT_LIST_HEAD(&device->list);
	device->index = n;

	spin_lock(&devices_lock);
	list_add(&device->list, &devices);
	spin_unlock(&devices_lock);

	setup_etheraddr(mac, device->mac);

	printk(KERN_INFO "Netdevice %d ", n);
@@ -360,7 +356,7 @@ static int eth_configure(int n, void *init, char *mac,
	dev = alloc_etherdev(size);
	if (dev == NULL) {
		printk(KERN_ERR "eth_configure: failed to allocate device\n");
		return 1;
		goto out_free_device;
	}

	lp = dev->priv;
@@ -376,7 +372,8 @@ static int eth_configure(int n, void *init, char *mac,
	}
	device->pdev.id = n;
	device->pdev.name = DRIVER_NAME;
	platform_device_register(&device->pdev);
	if(platform_device_register(&device->pdev))
		goto out_free_netdev;
	SET_NETDEV_DEV(dev,&device->pdev.dev);

	/* If this name ends up conflicting with an existing registered
@@ -386,31 +383,12 @@ static int eth_configure(int n, void *init, char *mac,
	snprintf(dev->name, sizeof(dev->name), "eth%d", n);
	device->dev = dev;

	/*
	 * These just fill in a data structure, so there's no failure
	 * to be worried about.
	 */
	(*transport->kern->init)(dev, init);

	dev->mtu = transport->user->max_packet;
	dev->open = uml_net_open;
	dev->hard_start_xmit = uml_net_start_xmit;
	dev->stop = uml_net_close;
	dev->get_stats = uml_net_get_stats;
	dev->set_multicast_list = uml_net_set_multicast_list;
	dev->tx_timeout = uml_net_tx_timeout;
	dev->set_mac_address = uml_net_set_mac;
	dev->change_mtu = uml_net_change_mtu;
	dev->ethtool_ops = &uml_net_ethtool_ops;
	dev->watchdog_timeo = (HZ >> 1);
	dev->irq = UM_ETH_IRQ;

	rtnl_lock();
	err = register_netdevice(dev);
	rtnl_unlock();
	if (err) {
		device->dev = NULL;
		/* XXX: should we call ->remove() here? */
		free_netdev(dev);
		return 1;
	}

	/* lp.user is the first four bytes of the transport data, which
	 * has already been initialized.  This structure assignment will
	 * 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,
	lp->tl.function = uml_net_user_timer_expire;
	memcpy(lp->mac, device->mac, sizeof(lp->mac));

	if (transport->user->init)
		(*transport->user->init)(&lp->user, dev);
	if ((transport->user->init != NULL) &&
	    ((*transport->user->init)(&lp->user, dev) != 0))
		goto out_unregister;

	set_ether_mac(dev, device->mac);
	dev->mtu = transport->user->max_packet;
	dev->open = uml_net_open;
	dev->hard_start_xmit = uml_net_start_xmit;
	dev->stop = uml_net_close;
	dev->get_stats = uml_net_get_stats;
	dev->set_multicast_list = uml_net_set_multicast_list;
	dev->tx_timeout = uml_net_tx_timeout;
	dev->set_mac_address = uml_net_set_mac;
	dev->change_mtu = uml_net_change_mtu;
	dev->ethtool_ops = &uml_net_ethtool_ops;
	dev->watchdog_timeo = (HZ >> 1);
	dev->irq = UM_ETH_IRQ;

	return 0;
	rtnl_lock();
	err = register_netdevice(dev);
	rtnl_unlock();
	if (err)
		goto out_undo_user_init;

	spin_lock(&devices_lock);
	list_add(&device->list, &devices);
	spin_unlock(&devices_lock);

	return;

out_undo_user_init:
	if (transport->user->init != NULL)
		(*transport->user->remove)(&lp->user);
out_unregister:
	platform_device_unregister(&device->pdev);
out_free_netdev:
	free_netdev(dev);
out_free_device: ;
	kfree(device);
}

static struct uml_net *find_device(int n)
+3 −2
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@

#define PCAP_FD(p) (*(int *)(p))

static void pcap_user_init(void *data, void *dev)
static int pcap_user_init(void *data, void *dev)
{
	struct pcap_data *pri = data;
	pcap_t *p;
@@ -28,11 +28,12 @@ static void pcap_user_init(void *data, void *dev)
	if(p == NULL){
		printk("pcap_user_init : pcap_open_live failed - '%s'\n", 
		       errors);
		return;
		return -EINVAL;
	}

	pri->dev = dev;
	pri->pcap = p;
	return 0;
}

static int pcap_open(void *data)
+2 −1
Original line number Diff line number Diff line
@@ -17,11 +17,12 @@
#include "os.h"
#include "um_malloc.h"

void slip_user_init(void *data, void *dev)
static int slip_user_init(void *data, void *dev)
{
	struct slip_data *pri = data;

	pri->dev = dev;
	return 0;
}

static int set_up_tty(int fd)
Loading