tap: Tap character device creation/destroy API
authorSainath Grandhi <sainath.grandhi@intel.com>
Sat, 11 Feb 2017 00:03:48 +0000 (16:03 -0800)
committerDavid S. Miller <davem@davemloft.net>
Sun, 12 Feb 2017 01:59:41 +0000 (20:59 -0500)
This patch provides tap device create/destroy APIs in tap.c.

Signed-off-by: Sainath Grandhi <sainath.grandhi@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/macvtap_main.c
drivers/net/tap.c
include/linux/if_tap.h

index 548f339a75bd4032abe901462583e33e14fd354b..215ab7abae892625953d2d0489ffe9a59d25eedf 100644 (file)
@@ -28,7 +28,6 @@
  * Variables for dealing with macvtaps device numbers.
  */
 static dev_t macvtap_major;
-#define MACVTAP_NUM_DEVS (1U << MINORBITS)
 
 static const void *macvtap_net_namespace(struct device *d)
 {
@@ -159,57 +158,46 @@ static struct notifier_block macvtap_notifier_block __read_mostly = {
        .notifier_call  = macvtap_device_event,
 };
 
-extern struct file_operations tap_fops;
 static int macvtap_init(void)
 {
        int err;
 
-       err = alloc_chrdev_region(&macvtap_major, 0,
-                               MACVTAP_NUM_DEVS, "macvtap");
-       if (err)
-               goto out1;
+       err = tap_create_cdev(&macvtap_cdev, &macvtap_major, "macvtap");
 
-       cdev_init(&macvtap_cdev, &tap_fops);
-       err = cdev_add(&macvtap_cdev, macvtap_major, MACVTAP_NUM_DEVS);
        if (err)
-               goto out2;
+               goto out1;
 
        err = class_register(&macvtap_class);
        if (err)
-               goto out3;
+               goto out2;
 
        err = register_netdevice_notifier(&macvtap_notifier_block);
        if (err)
-               goto out4;
+               goto out3;
 
        err = macvlan_link_register(&macvtap_link_ops);
        if (err)
-               goto out5;
+               goto out4;
 
        return 0;
 
-out5:
-       unregister_netdevice_notifier(&macvtap_notifier_block);
 out4:
-       class_unregister(&macvtap_class);
+       unregister_netdevice_notifier(&macvtap_notifier_block);
 out3:
-       cdev_del(&macvtap_cdev);
+       class_unregister(&macvtap_class);
 out2:
-       unregister_chrdev_region(macvtap_major, MACVTAP_NUM_DEVS);
+       tap_destroy_cdev(macvtap_major, &macvtap_cdev);
 out1:
        return err;
 }
 module_init(macvtap_init);
 
-extern struct idr minor_idr;
 static void macvtap_exit(void)
 {
        rtnl_link_unregister(&macvtap_link_ops);
        unregister_netdevice_notifier(&macvtap_notifier_block);
        class_unregister(&macvtap_class);
-       cdev_del(&macvtap_cdev);
-       unregister_chrdev_region(macvtap_major, MACVTAP_NUM_DEVS);
-       idr_destroy(&minor_idr);
+       tap_destroy_cdev(macvtap_major, &macvtap_cdev);
 }
 module_exit(macvtap_exit);
 
index 15ca2d531d05522cec3daacf9a87a6f70236835d..04ba9782c2f3094796c6f5f0f22bdffc510c7bf5 100644 (file)
@@ -123,8 +123,12 @@ static struct proto tap_proto = {
 };
 
 #define TAP_NUM_DEVS (1U << MINORBITS)
-static DEFINE_MUTEX(minor_lock);
-DEFINE_IDR(minor_idr);
+struct major_info {
+       dev_t major;
+       struct idr minor_idr;
+       struct mutex minor_lock;
+       const char *device_name;
+} macvtap_major;
 
 #define GOODCOPY_LEN 128
 
@@ -413,26 +417,26 @@ int tap_get_minor(struct macvlan_dev *vlan)
 {
        int retval = -ENOMEM;
 
-       mutex_lock(&minor_lock);
-       retval = idr_alloc(&minor_idr, vlan, 1, TAP_NUM_DEVS, GFP_KERNEL);
+       mutex_lock(&macvtap_major.minor_lock);
+       retval = idr_alloc(&macvtap_major.minor_idr, vlan, 1, TAP_NUM_DEVS, GFP_KERNEL);
        if (retval >= 0) {
                vlan->minor = retval;
        } else if (retval == -ENOSPC) {
                netdev_err(vlan->dev, "Too many tap devices\n");
                retval = -EINVAL;
        }
-       mutex_unlock(&minor_lock);
+       mutex_unlock(&macvtap_major.minor_lock);
        return retval < 0 ? retval : 0;
 }
 
 void tap_free_minor(struct macvlan_dev *vlan)
 {
-       mutex_lock(&minor_lock);
+       mutex_lock(&macvtap_major.minor_lock);
        if (vlan->minor) {
-               idr_remove(&minor_idr, vlan->minor);
+               idr_remove(&macvtap_major.minor_idr, vlan->minor);
                vlan->minor = 0;
        }
-       mutex_unlock(&minor_lock);
+       mutex_unlock(&macvtap_major.minor_lock);
 }
 
 static struct net_device *dev_get_by_tap_minor(int minor)
@@ -440,13 +444,13 @@ static struct net_device *dev_get_by_tap_minor(int minor)
        struct net_device *dev = NULL;
        struct macvlan_dev *vlan;
 
-       mutex_lock(&minor_lock);
-       vlan = idr_find(&minor_idr, minor);
+       mutex_lock(&macvtap_major.minor_lock);
+       vlan = idr_find(&macvtap_major.minor_idr, minor);
        if (vlan) {
                dev = vlan->dev;
                dev_hold(dev);
        }
-       mutex_unlock(&minor_lock);
+       mutex_unlock(&macvtap_major.minor_lock);
        return dev;
 }
 
@@ -1184,3 +1188,39 @@ int tap_queue_resize(struct macvlan_dev *vlan)
        kfree(arrays);
        return ret;
 }
+
+int tap_create_cdev(struct cdev *tap_cdev,
+                   dev_t *tap_major, const char *device_name)
+{
+       int err;
+
+       err = alloc_chrdev_region(tap_major, 0, TAP_NUM_DEVS, device_name);
+       if (err)
+               goto out1;
+
+       cdev_init(tap_cdev, &tap_fops);
+       err = cdev_add(tap_cdev, *tap_major, TAP_NUM_DEVS);
+       if (err)
+               goto out2;
+
+       macvtap_major.major = MAJOR(*tap_major);
+
+       idr_init(&macvtap_major.minor_idr);
+       mutex_init(&macvtap_major.minor_lock);
+
+       macvtap_major.device_name = device_name;
+
+       return 0;
+
+out2:
+       unregister_chrdev_region(*tap_major, TAP_NUM_DEVS);
+out1:
+       return err;
+}
+
+void tap_destroy_cdev(dev_t major, struct cdev *tap_cdev)
+{
+       cdev_del(tap_cdev);
+       unregister_chrdev_region(major, TAP_NUM_DEVS);
+       idr_destroy(&macvtap_major.minor_idr);
+}
index 97d27b8ebd552466833cff8a5fc3d9be86a33ce9..a2dfd9063a6c3bb2cfe1e47dd044495a8fab872a 100644 (file)
@@ -19,5 +19,8 @@ void tap_del_queues(struct net_device *dev);
 int tap_get_minor(struct macvlan_dev *vlan);
 void tap_free_minor(struct macvlan_dev *vlan);
 int tap_queue_resize(struct macvlan_dev *vlan);
+int tap_create_cdev(struct cdev *tap_cdev,
+                   dev_t *tap_major, const char *device_name);
+void tap_destroy_cdev(dev_t major, struct cdev *tap_cdev);
 
 #endif /*_LINUX_IF_TAP_H_*/