};
 
 /*
- * Minor number matches netdev->ifindex, so need a potentially
- * large value. This also makes it possible to split the
- * tap functionality out again in the future by offering it
- * from other drivers besides macvtap. As long as every device
- * only has one tap, the interface numbers assure that the
- * device nodes are unique.
+ * Variables for dealing with macvtaps device numbers.
  */
 static dev_t macvtap_major;
-#define MACVTAP_NUM_DEVS 65536
+#define MACVTAP_NUM_DEVS (1U << MINORBITS)
+static DEFINE_MUTEX(minor_lock);
+static DEFINE_IDR(minor_idr);
+
 #define GOODCOPY_LEN 128
 static struct class *macvtap_class;
 static struct cdev macvtap_cdev;
        return macvtap_forward(skb->dev, skb);
 }
 
+static int macvtap_get_minor(struct macvlan_dev *vlan)
+{
+       int retval = -ENOMEM;
+       int id;
+
+       mutex_lock(&minor_lock);
+       if (idr_pre_get(&minor_idr, GFP_KERNEL) == 0)
+               goto exit;
+
+       retval = idr_get_new_above(&minor_idr, vlan, 1, &id);
+       if (retval < 0) {
+               if (retval == -EAGAIN)
+                       retval = -ENOMEM;
+               goto exit;
+       }
+       if (id < MACVTAP_NUM_DEVS) {
+               vlan->minor = id;
+       } else {
+               printk(KERN_ERR "too many macvtap devices\n");
+               retval = -EINVAL;
+               idr_remove(&minor_idr, id);
+       }
+exit:
+       mutex_unlock(&minor_lock);
+       return retval;
+}
+
+static void macvtap_free_minor(struct macvlan_dev *vlan)
+{
+       mutex_lock(&minor_lock);
+       if (vlan->minor) {
+               idr_remove(&minor_idr, vlan->minor);
+               vlan->minor = 0;
+       }
+       mutex_unlock(&minor_lock);
+}
+
+static struct net_device *dev_get_by_macvtap_minor(int minor)
+{
+       struct net_device *dev = NULL;
+       struct macvlan_dev *vlan;
+
+       mutex_lock(&minor_lock);
+       vlan = idr_find(&minor_idr, minor);
+       if (vlan) {
+               dev = vlan->dev;
+               dev_hold(dev);
+       }
+       mutex_unlock(&minor_lock);
+       return dev;
+}
+
 static int macvtap_newlink(struct net *src_net,
                           struct net_device *dev,
                           struct nlattr *tb[],
 static int macvtap_open(struct inode *inode, struct file *file)
 {
        struct net *net = current->nsproxy->net_ns;
-       struct net_device *dev = dev_get_by_index(net, iminor(inode));
+       struct net_device *dev = dev_get_by_macvtap_minor(iminor(inode));
        struct macvtap_queue *q;
        int err;
 
        if (!dev)
                goto out;
 
-       /* check if this is a macvtap device */
-       err = -EINVAL;
-       if (dev->rtnl_link_ops != &macvtap_link_ops)
-               goto out;
-
        err = -ENOMEM;
        q = (struct macvtap_queue *)sk_alloc(net, AF_UNSPEC, GFP_KERNEL,
                                             &macvtap_proto);
                                unsigned long event, void *ptr)
 {
        struct net_device *dev = ptr;
+       struct macvlan_dev *vlan;
        struct device *classdev;
        dev_t devt;
+       int err;
 
        if (dev->rtnl_link_ops != &macvtap_link_ops)
                return NOTIFY_DONE;
 
+       vlan = netdev_priv(dev);
 
        switch (event) {
        case NETDEV_REGISTER:
                 * been registered but before register_netdevice has
                 * finished running.
                 */
-               devt = MKDEV(MAJOR(macvtap_major), dev->ifindex);
+               err = macvtap_get_minor(vlan);
+               if (err)
+                       return notifier_from_errno(err);
+
+               devt = MKDEV(MAJOR(macvtap_major), vlan->minor);
                classdev = device_create(macvtap_class, &dev->dev, devt,
                                         dev, "tap%d", dev->ifindex);
-               if (IS_ERR(classdev))
+               if (IS_ERR(classdev)) {
+                       macvtap_free_minor(vlan);
                        return notifier_from_errno(PTR_ERR(classdev));
+               }
                break;
        case NETDEV_UNREGISTER:
-               devt = MKDEV(MAJOR(macvtap_major), dev->ifindex);
+               devt = MKDEV(MAJOR(macvtap_major), vlan->minor);
                device_destroy(macvtap_class, devt);
+               macvtap_free_minor(vlan);
                break;
        }