diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2011-10-20 00:28:46 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-10-21 02:53:07 -0400 |
commit | 9bf1907f4293d61d5a283d18c4ad28d048261797 (patch) | |
tree | a234645761a946931ae3c0e3ba1088ebec455325 /drivers/net/macvtap.c | |
parent | 2259fef0bb80a8fc842b5690b89a640464df2859 (diff) |
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: Eric W. Biederman <ebiederm@xmission.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/macvtap.c')
-rw-r--r-- | drivers/net/macvtap.c | 73 |
1 files changed, 49 insertions, 24 deletions
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 515aa873929e..25689e9df3b7 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c | |||
@@ -280,34 +280,16 @@ static int macvtap_newlink(struct net *src_net, | |||
280 | struct nlattr *tb[], | 280 | struct nlattr *tb[], |
281 | struct nlattr *data[]) | 281 | struct nlattr *data[]) |
282 | { | 282 | { |
283 | struct device *classdev; | 283 | /* Don't put anything that may fail after macvlan_common_newlink |
284 | dev_t devt; | 284 | * because we can't undo what it does. |
285 | int err; | 285 | */ |
286 | 286 | return macvlan_common_newlink(src_net, dev, tb, data, | |
287 | err = macvlan_common_newlink(src_net, dev, tb, data, | 287 | macvtap_receive, macvtap_forward); |
288 | macvtap_receive, macvtap_forward); | ||
289 | if (err) | ||
290 | goto out; | ||
291 | |||
292 | devt = MKDEV(MAJOR(macvtap_major), dev->ifindex); | ||
293 | |||
294 | classdev = device_create(macvtap_class, &dev->dev, devt, | ||
295 | dev, "tap%d", dev->ifindex); | ||
296 | if (IS_ERR(classdev)) { | ||
297 | err = PTR_ERR(classdev); | ||
298 | macvtap_del_queues(dev); | ||
299 | } | ||
300 | |||
301 | out: | ||
302 | return err; | ||
303 | } | 288 | } |
304 | 289 | ||
305 | static void macvtap_dellink(struct net_device *dev, | 290 | static void macvtap_dellink(struct net_device *dev, |
306 | struct list_head *head) | 291 | struct list_head *head) |
307 | { | 292 | { |
308 | device_destroy(macvtap_class, | ||
309 | MKDEV(MAJOR(macvtap_major), dev->ifindex)); | ||
310 | |||
311 | macvtap_del_queues(dev); | 293 | macvtap_del_queues(dev); |
312 | macvlan_dellink(dev, head); | 294 | macvlan_dellink(dev, head); |
313 | } | 295 | } |
@@ -975,6 +957,42 @@ struct socket *macvtap_get_socket(struct file *file) | |||
975 | } | 957 | } |
976 | EXPORT_SYMBOL_GPL(macvtap_get_socket); | 958 | EXPORT_SYMBOL_GPL(macvtap_get_socket); |
977 | 959 | ||
960 | static int macvtap_device_event(struct notifier_block *unused, | ||
961 | unsigned long event, void *ptr) | ||
962 | { | ||
963 | struct net_device *dev = ptr; | ||
964 | struct device *classdev; | ||
965 | dev_t devt; | ||
966 | |||
967 | if (dev->rtnl_link_ops != &macvtap_link_ops) | ||
968 | return NOTIFY_DONE; | ||
969 | |||
970 | |||
971 | switch (event) { | ||
972 | case NETDEV_REGISTER: | ||
973 | /* Create the device node here after the network device has | ||
974 | * been registered but before register_netdevice has | ||
975 | * finished running. | ||
976 | */ | ||
977 | devt = MKDEV(MAJOR(macvtap_major), dev->ifindex); | ||
978 | classdev = device_create(macvtap_class, &dev->dev, devt, | ||
979 | dev, "tap%d", dev->ifindex); | ||
980 | if (IS_ERR(classdev)) | ||
981 | return notifier_from_errno(PTR_ERR(classdev)); | ||
982 | break; | ||
983 | case NETDEV_UNREGISTER: | ||
984 | devt = MKDEV(MAJOR(macvtap_major), dev->ifindex); | ||
985 | device_destroy(macvtap_class, devt); | ||
986 | break; | ||
987 | } | ||
988 | |||
989 | return NOTIFY_DONE; | ||
990 | } | ||
991 | |||
992 | static struct notifier_block macvtap_notifier_block __read_mostly = { | ||
993 | .notifier_call = macvtap_device_event, | ||
994 | }; | ||
995 | |||
978 | static int macvtap_init(void) | 996 | static int macvtap_init(void) |
979 | { | 997 | { |
980 | int err; | 998 | int err; |
@@ -995,12 +1013,18 @@ static int macvtap_init(void) | |||
995 | goto out3; | 1013 | goto out3; |
996 | } | 1014 | } |
997 | 1015 | ||
998 | err = macvlan_link_register(&macvtap_link_ops); | 1016 | err = register_netdevice_notifier(&macvtap_notifier_block); |
999 | if (err) | 1017 | if (err) |
1000 | goto out4; | 1018 | goto out4; |
1001 | 1019 | ||
1020 | err = macvlan_link_register(&macvtap_link_ops); | ||
1021 | if (err) | ||
1022 | goto out5; | ||
1023 | |||
1002 | return 0; | 1024 | return 0; |
1003 | 1025 | ||
1026 | out5: | ||
1027 | unregister_netdevice_notifier(&macvtap_notifier_block); | ||
1004 | out4: | 1028 | out4: |
1005 | class_unregister(macvtap_class); | 1029 | class_unregister(macvtap_class); |
1006 | out3: | 1030 | out3: |
@@ -1015,6 +1039,7 @@ module_init(macvtap_init); | |||
1015 | static void macvtap_exit(void) | 1039 | static void macvtap_exit(void) |
1016 | { | 1040 | { |
1017 | rtnl_link_unregister(&macvtap_link_ops); | 1041 | rtnl_link_unregister(&macvtap_link_ops); |
1042 | unregister_netdevice_notifier(&macvtap_notifier_block); | ||
1018 | class_unregister(macvtap_class); | 1043 | class_unregister(macvtap_class); |
1019 | cdev_del(&macvtap_cdev); | 1044 | cdev_del(&macvtap_cdev); |
1020 | unregister_chrdev_region(macvtap_major, MACVTAP_NUM_DEVS); | 1045 | unregister_chrdev_region(macvtap_major, MACVTAP_NUM_DEVS); |