aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/macvtap.c
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2011-10-20 00:29:24 -0400
committerDavid S. Miller <davem@davemloft.net>2011-10-21 02:53:07 -0400
commite09eff7fc1c6f011f7bdb304e10d2ceef08c88ab (patch)
tree170603217dedb0434244f4ef35928e6267cd5105 /drivers/net/macvtap.c
parent9bf1907f4293d61d5a283d18c4ad28d048261797 (diff)
macvtap: Fix the minor device number allocation
On systems that create and delete lots of dynamic devices the 31bit linux ifindex fails to fit in the 16bit macvtap minor, resulting in unusable macvtap devices. I have systems running automated tests that that hit this condition in just a few days. Use a linux idr allocator to track which mavtap minor numbers are available and and to track the association between macvtap minor numbers and macvtap network devices. Remove the unnecessary unneccessary check to see if the network device we have found is indeed a macvtap device. With macvtap specific data structures it is impossible to find any other kind of networking device. Increase the macvtap minor range from 65536 to the full 20 bits that is supported by linux device numbers. It doesn't solve the original problem but there is no penalty for a larger minor device range. 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.c87
1 files changed, 71 insertions, 16 deletions
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
index 25689e9df3b7..1b7082d08f33 100644
--- a/drivers/net/macvtap.c
+++ b/drivers/net/macvtap.c
@@ -51,15 +51,13 @@ static struct proto macvtap_proto = {
51}; 51};
52 52
53/* 53/*
54 * Minor number matches netdev->ifindex, so need a potentially 54 * Variables for dealing with macvtaps device numbers.
55 * large value. This also makes it possible to split the
56 * tap functionality out again in the future by offering it
57 * from other drivers besides macvtap. As long as every device
58 * only has one tap, the interface numbers assure that the
59 * device nodes are unique.
60 */ 55 */
61static dev_t macvtap_major; 56static dev_t macvtap_major;
62#define MACVTAP_NUM_DEVS 65536 57#define MACVTAP_NUM_DEVS (1U << MINORBITS)
58static DEFINE_MUTEX(minor_lock);
59static DEFINE_IDR(minor_idr);
60
63#define GOODCOPY_LEN 128 61#define GOODCOPY_LEN 128
64static struct class *macvtap_class; 62static struct class *macvtap_class;
65static struct cdev macvtap_cdev; 63static struct cdev macvtap_cdev;
@@ -275,6 +273,58 @@ static int macvtap_receive(struct sk_buff *skb)
275 return macvtap_forward(skb->dev, skb); 273 return macvtap_forward(skb->dev, skb);
276} 274}
277 275
276static int macvtap_get_minor(struct macvlan_dev *vlan)
277{
278 int retval = -ENOMEM;
279 int id;
280
281 mutex_lock(&minor_lock);
282 if (idr_pre_get(&minor_idr, GFP_KERNEL) == 0)
283 goto exit;
284
285 retval = idr_get_new_above(&minor_idr, vlan, 1, &id);
286 if (retval < 0) {
287 if (retval == -EAGAIN)
288 retval = -ENOMEM;
289 goto exit;
290 }
291 if (id < MACVTAP_NUM_DEVS) {
292 vlan->minor = id;
293 } else {
294 printk(KERN_ERR "too many macvtap devices\n");
295 retval = -EINVAL;
296 idr_remove(&minor_idr, id);
297 }
298exit:
299 mutex_unlock(&minor_lock);
300 return retval;
301}
302
303static void macvtap_free_minor(struct macvlan_dev *vlan)
304{
305 mutex_lock(&minor_lock);
306 if (vlan->minor) {
307 idr_remove(&minor_idr, vlan->minor);
308 vlan->minor = 0;
309 }
310 mutex_unlock(&minor_lock);
311}
312
313static struct net_device *dev_get_by_macvtap_minor(int minor)
314{
315 struct net_device *dev = NULL;
316 struct macvlan_dev *vlan;
317
318 mutex_lock(&minor_lock);
319 vlan = idr_find(&minor_idr, minor);
320 if (vlan) {
321 dev = vlan->dev;
322 dev_hold(dev);
323 }
324 mutex_unlock(&minor_lock);
325 return dev;
326}
327
278static int macvtap_newlink(struct net *src_net, 328static int macvtap_newlink(struct net *src_net,
279 struct net_device *dev, 329 struct net_device *dev,
280 struct nlattr *tb[], 330 struct nlattr *tb[],
@@ -329,7 +379,7 @@ static void macvtap_sock_destruct(struct sock *sk)
329static int macvtap_open(struct inode *inode, struct file *file) 379static int macvtap_open(struct inode *inode, struct file *file)
330{ 380{
331 struct net *net = current->nsproxy->net_ns; 381 struct net *net = current->nsproxy->net_ns;
332 struct net_device *dev = dev_get_by_index(net, iminor(inode)); 382 struct net_device *dev = dev_get_by_macvtap_minor(iminor(inode));
333 struct macvtap_queue *q; 383 struct macvtap_queue *q;
334 int err; 384 int err;
335 385
@@ -337,11 +387,6 @@ static int macvtap_open(struct inode *inode, struct file *file)
337 if (!dev) 387 if (!dev)
338 goto out; 388 goto out;
339 389
340 /* check if this is a macvtap device */
341 err = -EINVAL;
342 if (dev->rtnl_link_ops != &macvtap_link_ops)
343 goto out;
344
345 err = -ENOMEM; 390 err = -ENOMEM;
346 q = (struct macvtap_queue *)sk_alloc(net, AF_UNSPEC, GFP_KERNEL, 391 q = (struct macvtap_queue *)sk_alloc(net, AF_UNSPEC, GFP_KERNEL,
347 &macvtap_proto); 392 &macvtap_proto);
@@ -961,12 +1006,15 @@ static int macvtap_device_event(struct notifier_block *unused,
961 unsigned long event, void *ptr) 1006 unsigned long event, void *ptr)
962{ 1007{
963 struct net_device *dev = ptr; 1008 struct net_device *dev = ptr;
1009 struct macvlan_dev *vlan;
964 struct device *classdev; 1010 struct device *classdev;
965 dev_t devt; 1011 dev_t devt;
1012 int err;
966 1013
967 if (dev->rtnl_link_ops != &macvtap_link_ops) 1014 if (dev->rtnl_link_ops != &macvtap_link_ops)
968 return NOTIFY_DONE; 1015 return NOTIFY_DONE;
969 1016
1017 vlan = netdev_priv(dev);
970 1018
971 switch (event) { 1019 switch (event) {
972 case NETDEV_REGISTER: 1020 case NETDEV_REGISTER:
@@ -974,15 +1022,22 @@ static int macvtap_device_event(struct notifier_block *unused,
974 * been registered but before register_netdevice has 1022 * been registered but before register_netdevice has
975 * finished running. 1023 * finished running.
976 */ 1024 */
977 devt = MKDEV(MAJOR(macvtap_major), dev->ifindex); 1025 err = macvtap_get_minor(vlan);
1026 if (err)
1027 return notifier_from_errno(err);
1028
1029 devt = MKDEV(MAJOR(macvtap_major), vlan->minor);
978 classdev = device_create(macvtap_class, &dev->dev, devt, 1030 classdev = device_create(macvtap_class, &dev->dev, devt,
979 dev, "tap%d", dev->ifindex); 1031 dev, "tap%d", dev->ifindex);
980 if (IS_ERR(classdev)) 1032 if (IS_ERR(classdev)) {
1033 macvtap_free_minor(vlan);
981 return notifier_from_errno(PTR_ERR(classdev)); 1034 return notifier_from_errno(PTR_ERR(classdev));
1035 }
982 break; 1036 break;
983 case NETDEV_UNREGISTER: 1037 case NETDEV_UNREGISTER:
984 devt = MKDEV(MAJOR(macvtap_major), dev->ifindex); 1038 devt = MKDEV(MAJOR(macvtap_major), vlan->minor);
985 device_destroy(macvtap_class, devt); 1039 device_destroy(macvtap_class, devt);
1040 macvtap_free_minor(vlan);
986 break; 1041 break;
987 } 1042 }
988 1043