Commit 9bf1907f authored by Eric W. Biederman's avatar Eric W. Biederman Committed by David S. Miller

macvtap: Rewrite macvtap_newlink so the error handling works.

Place macvlan_common_newlink at the end of macvtap_newlink because
failing in newlink after registering your network device is not
supported.

Move device_create into a netdevice creation notifier.   The network device
notifier is the only hook that is called after the network device has been
registered with the device layer and before register_network_device returns
success.
Signed-off-by: default avatarEric W. Biederman <ebiederm@xmission.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 2259fef0
...@@ -280,34 +280,16 @@ static int macvtap_newlink(struct net *src_net, ...@@ -280,34 +280,16 @@ static int macvtap_newlink(struct net *src_net,
struct nlattr *tb[], struct nlattr *tb[],
struct nlattr *data[]) struct nlattr *data[])
{ {
struct device *classdev; /* Don't put anything that may fail after macvlan_common_newlink
dev_t devt; * because we can't undo what it does.
int err; */
return macvlan_common_newlink(src_net, dev, tb, data,
err = macvlan_common_newlink(src_net, dev, tb, data, macvtap_receive, macvtap_forward);
macvtap_receive, macvtap_forward);
if (err)
goto out;
devt = MKDEV(MAJOR(macvtap_major), dev->ifindex);
classdev = device_create(macvtap_class, &dev->dev, devt,
dev, "tap%d", dev->ifindex);
if (IS_ERR(classdev)) {
err = PTR_ERR(classdev);
macvtap_del_queues(dev);
}
out:
return err;
} }
static void macvtap_dellink(struct net_device *dev, static void macvtap_dellink(struct net_device *dev,
struct list_head *head) struct list_head *head)
{ {
device_destroy(macvtap_class,
MKDEV(MAJOR(macvtap_major), dev->ifindex));
macvtap_del_queues(dev); macvtap_del_queues(dev);
macvlan_dellink(dev, head); macvlan_dellink(dev, head);
} }
...@@ -975,6 +957,42 @@ struct socket *macvtap_get_socket(struct file *file) ...@@ -975,6 +957,42 @@ struct socket *macvtap_get_socket(struct file *file)
} }
EXPORT_SYMBOL_GPL(macvtap_get_socket); EXPORT_SYMBOL_GPL(macvtap_get_socket);
static int macvtap_device_event(struct notifier_block *unused,
unsigned long event, void *ptr)
{
struct net_device *dev = ptr;
struct device *classdev;
dev_t devt;
if (dev->rtnl_link_ops != &macvtap_link_ops)
return NOTIFY_DONE;
switch (event) {
case NETDEV_REGISTER:
/* Create the device node here after the network device has
* been registered but before register_netdevice has
* finished running.
*/
devt = MKDEV(MAJOR(macvtap_major), dev->ifindex);
classdev = device_create(macvtap_class, &dev->dev, devt,
dev, "tap%d", dev->ifindex);
if (IS_ERR(classdev))
return notifier_from_errno(PTR_ERR(classdev));
break;
case NETDEV_UNREGISTER:
devt = MKDEV(MAJOR(macvtap_major), dev->ifindex);
device_destroy(macvtap_class, devt);
break;
}
return NOTIFY_DONE;
}
static struct notifier_block macvtap_notifier_block __read_mostly = {
.notifier_call = macvtap_device_event,
};
static int macvtap_init(void) static int macvtap_init(void)
{ {
int err; int err;
...@@ -995,12 +1013,18 @@ static int macvtap_init(void) ...@@ -995,12 +1013,18 @@ static int macvtap_init(void)
goto out3; goto out3;
} }
err = macvlan_link_register(&macvtap_link_ops); err = register_netdevice_notifier(&macvtap_notifier_block);
if (err) if (err)
goto out4; goto out4;
err = macvlan_link_register(&macvtap_link_ops);
if (err)
goto out5;
return 0; return 0;
out5:
unregister_netdevice_notifier(&macvtap_notifier_block);
out4: out4:
class_unregister(macvtap_class); class_unregister(macvtap_class);
out3: out3:
...@@ -1015,6 +1039,7 @@ module_init(macvtap_init); ...@@ -1015,6 +1039,7 @@ module_init(macvtap_init);
static void macvtap_exit(void) static void macvtap_exit(void)
{ {
rtnl_link_unregister(&macvtap_link_ops); rtnl_link_unregister(&macvtap_link_ops);
unregister_netdevice_notifier(&macvtap_notifier_block);
class_unregister(macvtap_class); class_unregister(macvtap_class);
cdev_del(&macvtap_cdev); cdev_del(&macvtap_cdev);
unregister_chrdev_region(macvtap_major, MACVTAP_NUM_DEVS); unregister_chrdev_region(macvtap_major, MACVTAP_NUM_DEVS);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment