Commit ebc05ba7 authored by Sainath Grandhi's avatar Sainath Grandhi Committed by David S. Miller

tap: Tap character device creation/destroy API

This patch provides tap device create/destroy APIs in tap.c.
Signed-off-by: default avatarSainath Grandhi <sainath.grandhi@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 635b8c8e
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
* Variables for dealing with macvtaps device numbers. * Variables for dealing with macvtaps device numbers.
*/ */
static dev_t macvtap_major; static dev_t macvtap_major;
#define MACVTAP_NUM_DEVS (1U << MINORBITS)
static const void *macvtap_net_namespace(struct device *d) static const void *macvtap_net_namespace(struct device *d)
{ {
...@@ -159,57 +158,46 @@ static struct notifier_block macvtap_notifier_block __read_mostly = { ...@@ -159,57 +158,46 @@ static struct notifier_block macvtap_notifier_block __read_mostly = {
.notifier_call = macvtap_device_event, .notifier_call = macvtap_device_event,
}; };
extern struct file_operations tap_fops;
static int macvtap_init(void) static int macvtap_init(void)
{ {
int err; int err;
err = alloc_chrdev_region(&macvtap_major, 0, err = tap_create_cdev(&macvtap_cdev, &macvtap_major, "macvtap");
MACVTAP_NUM_DEVS, "macvtap");
if (err)
goto out1;
cdev_init(&macvtap_cdev, &tap_fops);
err = cdev_add(&macvtap_cdev, macvtap_major, MACVTAP_NUM_DEVS);
if (err) if (err)
goto out2; goto out1;
err = class_register(&macvtap_class); err = class_register(&macvtap_class);
if (err) if (err)
goto out3; goto out2;
err = register_netdevice_notifier(&macvtap_notifier_block); err = register_netdevice_notifier(&macvtap_notifier_block);
if (err) if (err)
goto out4; goto out3;
err = macvlan_link_register(&macvtap_link_ops); err = macvlan_link_register(&macvtap_link_ops);
if (err) if (err)
goto out5; goto out4;
return 0; return 0;
out5:
unregister_netdevice_notifier(&macvtap_notifier_block);
out4: out4:
class_unregister(&macvtap_class); unregister_netdevice_notifier(&macvtap_notifier_block);
out3: out3:
cdev_del(&macvtap_cdev); class_unregister(&macvtap_class);
out2: out2:
unregister_chrdev_region(macvtap_major, MACVTAP_NUM_DEVS); tap_destroy_cdev(macvtap_major, &macvtap_cdev);
out1: out1:
return err; return err;
} }
module_init(macvtap_init); module_init(macvtap_init);
extern struct idr minor_idr;
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); unregister_netdevice_notifier(&macvtap_notifier_block);
class_unregister(&macvtap_class); class_unregister(&macvtap_class);
cdev_del(&macvtap_cdev); tap_destroy_cdev(macvtap_major, &macvtap_cdev);
unregister_chrdev_region(macvtap_major, MACVTAP_NUM_DEVS);
idr_destroy(&minor_idr);
} }
module_exit(macvtap_exit); module_exit(macvtap_exit);
......
...@@ -123,8 +123,12 @@ static struct proto tap_proto = { ...@@ -123,8 +123,12 @@ static struct proto tap_proto = {
}; };
#define TAP_NUM_DEVS (1U << MINORBITS) #define TAP_NUM_DEVS (1U << MINORBITS)
static DEFINE_MUTEX(minor_lock); struct major_info {
DEFINE_IDR(minor_idr); dev_t major;
struct idr minor_idr;
struct mutex minor_lock;
const char *device_name;
} macvtap_major;
#define GOODCOPY_LEN 128 #define GOODCOPY_LEN 128
...@@ -413,26 +417,26 @@ int tap_get_minor(struct macvlan_dev *vlan) ...@@ -413,26 +417,26 @@ int tap_get_minor(struct macvlan_dev *vlan)
{ {
int retval = -ENOMEM; int retval = -ENOMEM;
mutex_lock(&minor_lock); mutex_lock(&macvtap_major.minor_lock);
retval = idr_alloc(&minor_idr, vlan, 1, TAP_NUM_DEVS, GFP_KERNEL); retval = idr_alloc(&macvtap_major.minor_idr, vlan, 1, TAP_NUM_DEVS, GFP_KERNEL);
if (retval >= 0) { if (retval >= 0) {
vlan->minor = retval; vlan->minor = retval;
} else if (retval == -ENOSPC) { } else if (retval == -ENOSPC) {
netdev_err(vlan->dev, "Too many tap devices\n"); netdev_err(vlan->dev, "Too many tap devices\n");
retval = -EINVAL; retval = -EINVAL;
} }
mutex_unlock(&minor_lock); mutex_unlock(&macvtap_major.minor_lock);
return retval < 0 ? retval : 0; return retval < 0 ? retval : 0;
} }
void tap_free_minor(struct macvlan_dev *vlan) void tap_free_minor(struct macvlan_dev *vlan)
{ {
mutex_lock(&minor_lock); mutex_lock(&macvtap_major.minor_lock);
if (vlan->minor) { if (vlan->minor) {
idr_remove(&minor_idr, vlan->minor); idr_remove(&macvtap_major.minor_idr, vlan->minor);
vlan->minor = 0; vlan->minor = 0;
} }
mutex_unlock(&minor_lock); mutex_unlock(&macvtap_major.minor_lock);
} }
static struct net_device *dev_get_by_tap_minor(int minor) 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) ...@@ -440,13 +444,13 @@ static struct net_device *dev_get_by_tap_minor(int minor)
struct net_device *dev = NULL; struct net_device *dev = NULL;
struct macvlan_dev *vlan; struct macvlan_dev *vlan;
mutex_lock(&minor_lock); mutex_lock(&macvtap_major.minor_lock);
vlan = idr_find(&minor_idr, minor); vlan = idr_find(&macvtap_major.minor_idr, minor);
if (vlan) { if (vlan) {
dev = vlan->dev; dev = vlan->dev;
dev_hold(dev); dev_hold(dev);
} }
mutex_unlock(&minor_lock); mutex_unlock(&macvtap_major.minor_lock);
return dev; return dev;
} }
...@@ -1184,3 +1188,39 @@ int tap_queue_resize(struct macvlan_dev *vlan) ...@@ -1184,3 +1188,39 @@ int tap_queue_resize(struct macvlan_dev *vlan)
kfree(arrays); kfree(arrays);
return ret; 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);
}
...@@ -19,5 +19,8 @@ void tap_del_queues(struct net_device *dev); ...@@ -19,5 +19,8 @@ void tap_del_queues(struct net_device *dev);
int tap_get_minor(struct macvlan_dev *vlan); int tap_get_minor(struct macvlan_dev *vlan);
void tap_free_minor(struct macvlan_dev *vlan); void tap_free_minor(struct macvlan_dev *vlan);
int tap_queue_resize(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_*/ #endif /*_LINUX_IF_TAP_H_*/
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