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 Diff line number Diff line
@@ -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);

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