Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+9 −21
Original line number Original line Diff line number Diff line
@@ -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 = {
	.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);


+51 −11
Original line number Original line Diff line number Diff line
@@ -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)
{
{
	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)
	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)
	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);
}
+3 −0
Original line number Original line Diff line number Diff line
@@ -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_*/