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

Commit 5990a305 authored by Jason Wang's avatar Jason Wang Committed by David S. Miller
Browse files

tun/tap: use ptr_ring instead of skb_array



This patch switches to use ptr_ring instead of skb_array. This will be
used to enqueue different types of pointers by encoding type into
lower bits.

Signed-off-by: default avatarJason Wang <jasowang@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a0ce0931
Loading
Loading
Loading
Loading
+21 −20
Original line number Original line Diff line number Diff line
@@ -330,7 +330,7 @@ rx_handler_result_t tap_handle_frame(struct sk_buff **pskb)
	if (!q)
	if (!q)
		return RX_HANDLER_PASS;
		return RX_HANDLER_PASS;


	if (__skb_array_full(&q->skb_array))
	if (__ptr_ring_full(&q->ring))
		goto drop;
		goto drop;


	skb_push(skb, ETH_HLEN);
	skb_push(skb, ETH_HLEN);
@@ -348,7 +348,7 @@ rx_handler_result_t tap_handle_frame(struct sk_buff **pskb)
			goto drop;
			goto drop;


		if (!segs) {
		if (!segs) {
			if (skb_array_produce(&q->skb_array, skb))
			if (ptr_ring_produce(&q->ring, skb))
				goto drop;
				goto drop;
			goto wake_up;
			goto wake_up;
		}
		}
@@ -358,7 +358,7 @@ rx_handler_result_t tap_handle_frame(struct sk_buff **pskb)
			struct sk_buff *nskb = segs->next;
			struct sk_buff *nskb = segs->next;


			segs->next = NULL;
			segs->next = NULL;
			if (skb_array_produce(&q->skb_array, segs)) {
			if (ptr_ring_produce(&q->ring, segs)) {
				kfree_skb(segs);
				kfree_skb(segs);
				kfree_skb_list(nskb);
				kfree_skb_list(nskb);
				break;
				break;
@@ -375,7 +375,7 @@ rx_handler_result_t tap_handle_frame(struct sk_buff **pskb)
		    !(features & NETIF_F_CSUM_MASK) &&
		    !(features & NETIF_F_CSUM_MASK) &&
		    skb_checksum_help(skb))
		    skb_checksum_help(skb))
			goto drop;
			goto drop;
		if (skb_array_produce(&q->skb_array, skb))
		if (ptr_ring_produce(&q->ring, skb))
			goto drop;
			goto drop;
	}
	}


@@ -497,7 +497,7 @@ static void tap_sock_destruct(struct sock *sk)
{
{
	struct tap_queue *q = container_of(sk, struct tap_queue, sk);
	struct tap_queue *q = container_of(sk, struct tap_queue, sk);


	skb_array_cleanup(&q->skb_array);
	ptr_ring_cleanup(&q->ring, __skb_array_destroy_skb);
}
}


static int tap_open(struct inode *inode, struct file *file)
static int tap_open(struct inode *inode, struct file *file)
@@ -517,7 +517,7 @@ static int tap_open(struct inode *inode, struct file *file)
					     &tap_proto, 0);
					     &tap_proto, 0);
	if (!q)
	if (!q)
		goto err;
		goto err;
	if (skb_array_init(&q->skb_array, tap->dev->tx_queue_len, GFP_KERNEL)) {
	if (ptr_ring_init(&q->ring, tap->dev->tx_queue_len, GFP_KERNEL)) {
		sk_free(&q->sk);
		sk_free(&q->sk);
		goto err;
		goto err;
	}
	}
@@ -546,7 +546,7 @@ static int tap_open(struct inode *inode, struct file *file)


	err = tap_set_queue(tap, file, q);
	err = tap_set_queue(tap, file, q);
	if (err) {
	if (err) {
		/* tap_sock_destruct() will take care of freeing skb_array */
		/* tap_sock_destruct() will take care of freeing ptr_ring */
		goto err_put;
		goto err_put;
	}
	}


@@ -583,7 +583,7 @@ static unsigned int tap_poll(struct file *file, poll_table *wait)
	mask = 0;
	mask = 0;
	poll_wait(file, &q->wq.wait, wait);
	poll_wait(file, &q->wq.wait, wait);


	if (!skb_array_empty(&q->skb_array))
	if (!ptr_ring_empty(&q->ring))
		mask |= POLLIN | POLLRDNORM;
		mask |= POLLIN | POLLRDNORM;


	if (sock_writeable(&q->sk) ||
	if (sock_writeable(&q->sk) ||
@@ -844,7 +844,7 @@ static ssize_t tap_do_read(struct tap_queue *q,
					TASK_INTERRUPTIBLE);
					TASK_INTERRUPTIBLE);


		/* Read frames from the queue */
		/* Read frames from the queue */
		skb = skb_array_consume(&q->skb_array);
		skb = ptr_ring_consume(&q->ring);
		if (skb)
		if (skb)
			break;
			break;
		if (noblock) {
		if (noblock) {
@@ -1176,7 +1176,7 @@ static int tap_peek_len(struct socket *sock)
{
{
	struct tap_queue *q = container_of(sock, struct tap_queue,
	struct tap_queue *q = container_of(sock, struct tap_queue,
					       sock);
					       sock);
	return skb_array_peek_len(&q->skb_array);
	return PTR_RING_PEEK_CALL(&q->ring, __skb_array_len_with_tag);
}
}


/* Ops structure to mimic raw sockets with tun */
/* Ops structure to mimic raw sockets with tun */
@@ -1202,7 +1202,7 @@ struct socket *tap_get_socket(struct file *file)
}
}
EXPORT_SYMBOL_GPL(tap_get_socket);
EXPORT_SYMBOL_GPL(tap_get_socket);


struct skb_array *tap_get_skb_array(struct file *file)
struct ptr_ring *tap_get_ptr_ring(struct file *file)
{
{
	struct tap_queue *q;
	struct tap_queue *q;


@@ -1211,29 +1211,30 @@ struct skb_array *tap_get_skb_array(struct file *file)
	q = file->private_data;
	q = file->private_data;
	if (!q)
	if (!q)
		return ERR_PTR(-EBADFD);
		return ERR_PTR(-EBADFD);
	return &q->skb_array;
	return &q->ring;
}
}
EXPORT_SYMBOL_GPL(tap_get_skb_array);
EXPORT_SYMBOL_GPL(tap_get_ptr_ring);


int tap_queue_resize(struct tap_dev *tap)
int tap_queue_resize(struct tap_dev *tap)
{
{
	struct net_device *dev = tap->dev;
	struct net_device *dev = tap->dev;
	struct tap_queue *q;
	struct tap_queue *q;
	struct skb_array **arrays;
	struct ptr_ring **rings;
	int n = tap->numqueues;
	int n = tap->numqueues;
	int ret, i = 0;
	int ret, i = 0;


	arrays = kmalloc_array(n, sizeof(*arrays), GFP_KERNEL);
	rings = kmalloc_array(n, sizeof(*rings), GFP_KERNEL);
	if (!arrays)
	if (!rings)
		return -ENOMEM;
		return -ENOMEM;


	list_for_each_entry(q, &tap->queue_list, next)
	list_for_each_entry(q, &tap->queue_list, next)
		arrays[i++] = &q->skb_array;
		rings[i++] = &q->ring;


	ret = skb_array_resize_multiple(arrays, n,
	ret = ptr_ring_resize_multiple(rings, n,
					dev->tx_queue_len, GFP_KERNEL);
				       dev->tx_queue_len, GFP_KERNEL,
				       __skb_array_destroy_skb);


	kfree(arrays);
	kfree(rings);
	return ret;
	return ret;
}
}
EXPORT_SYMBOL_GPL(tap_queue_resize);
EXPORT_SYMBOL_GPL(tap_queue_resize);
+22 −20
Original line number Original line Diff line number Diff line
@@ -179,7 +179,7 @@ struct tun_file {
	struct mutex napi_mutex;	/* Protects access to the above napi */
	struct mutex napi_mutex;	/* Protects access to the above napi */
	struct list_head next;
	struct list_head next;
	struct tun_struct *detached;
	struct tun_struct *detached;
	struct skb_array tx_array;
	struct ptr_ring tx_ring;
	struct xdp_rxq_info xdp_rxq;
	struct xdp_rxq_info xdp_rxq;
};
};


@@ -635,7 +635,7 @@ static void tun_queue_purge(struct tun_file *tfile)
{
{
	struct sk_buff *skb;
	struct sk_buff *skb;


	while ((skb = skb_array_consume(&tfile->tx_array)) != NULL)
	while ((skb = ptr_ring_consume(&tfile->tx_ring)) != NULL)
		kfree_skb(skb);
		kfree_skb(skb);


	skb_queue_purge(&tfile->sk.sk_write_queue);
	skb_queue_purge(&tfile->sk.sk_write_queue);
@@ -689,7 +689,8 @@ static void __tun_detach(struct tun_file *tfile, bool clean)
				unregister_netdevice(tun->dev);
				unregister_netdevice(tun->dev);
		}
		}
		if (tun) {
		if (tun) {
			skb_array_cleanup(&tfile->tx_array);
			ptr_ring_cleanup(&tfile->tx_ring,
					 __skb_array_destroy_skb);
			xdp_rxq_info_unreg(&tfile->xdp_rxq);
			xdp_rxq_info_unreg(&tfile->xdp_rxq);
		}
		}
		sock_put(&tfile->sk);
		sock_put(&tfile->sk);
@@ -782,7 +783,7 @@ static int tun_attach(struct tun_struct *tun, struct file *file,
	}
	}


	if (!tfile->detached &&
	if (!tfile->detached &&
	    skb_array_init(&tfile->tx_array, dev->tx_queue_len, GFP_KERNEL)) {
	    ptr_ring_init(&tfile->tx_ring, dev->tx_queue_len, GFP_KERNEL)) {
		err = -ENOMEM;
		err = -ENOMEM;
		goto out;
		goto out;
	}
	}
@@ -1048,7 +1049,7 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)


	nf_reset(skb);
	nf_reset(skb);


	if (skb_array_produce(&tfile->tx_array, skb))
	if (ptr_ring_produce(&tfile->tx_ring, skb))
		goto drop;
		goto drop;


	/* Notify and wake up reader process */
	/* Notify and wake up reader process */
@@ -1316,7 +1317,7 @@ static unsigned int tun_chr_poll(struct file *file, poll_table *wait)


	poll_wait(file, sk_sleep(sk), wait);
	poll_wait(file, sk_sleep(sk), wait);


	if (!skb_array_empty(&tfile->tx_array))
	if (!ptr_ring_empty(&tfile->tx_ring))
		mask |= POLLIN | POLLRDNORM;
		mask |= POLLIN | POLLRDNORM;


	if (tun->dev->flags & IFF_UP &&
	if (tun->dev->flags & IFF_UP &&
@@ -1966,7 +1967,7 @@ static struct sk_buff *tun_ring_recv(struct tun_file *tfile, int noblock,
	struct sk_buff *skb = NULL;
	struct sk_buff *skb = NULL;
	int error = 0;
	int error = 0;


	skb = skb_array_consume(&tfile->tx_array);
	skb = ptr_ring_consume(&tfile->tx_ring);
	if (skb)
	if (skb)
		goto out;
		goto out;
	if (noblock) {
	if (noblock) {
@@ -1978,7 +1979,7 @@ static struct sk_buff *tun_ring_recv(struct tun_file *tfile, int noblock,
	current->state = TASK_INTERRUPTIBLE;
	current->state = TASK_INTERRUPTIBLE;


	while (1) {
	while (1) {
		skb = skb_array_consume(&tfile->tx_array);
		skb = ptr_ring_consume(&tfile->tx_ring);
		if (skb)
		if (skb)
			break;
			break;
		if (signal_pending(current)) {
		if (signal_pending(current)) {
@@ -2208,7 +2209,7 @@ static int tun_peek_len(struct socket *sock)
	if (!tun)
	if (!tun)
		return 0;
		return 0;


	ret = skb_array_peek_len(&tfile->tx_array);
	ret = PTR_RING_PEEK_CALL(&tfile->tx_ring, __skb_array_len_with_tag);
	tun_put(tun);
	tun_put(tun);


	return ret;
	return ret;
@@ -3114,25 +3115,26 @@ static int tun_queue_resize(struct tun_struct *tun)
{
{
	struct net_device *dev = tun->dev;
	struct net_device *dev = tun->dev;
	struct tun_file *tfile;
	struct tun_file *tfile;
	struct skb_array **arrays;
	struct ptr_ring **rings;
	int n = tun->numqueues + tun->numdisabled;
	int n = tun->numqueues + tun->numdisabled;
	int ret, i;
	int ret, i;


	arrays = kmalloc_array(n, sizeof(*arrays), GFP_KERNEL);
	rings = kmalloc_array(n, sizeof(*rings), GFP_KERNEL);
	if (!arrays)
	if (!rings)
		return -ENOMEM;
		return -ENOMEM;


	for (i = 0; i < tun->numqueues; i++) {
	for (i = 0; i < tun->numqueues; i++) {
		tfile = rtnl_dereference(tun->tfiles[i]);
		tfile = rtnl_dereference(tun->tfiles[i]);
		arrays[i] = &tfile->tx_array;
		rings[i] = &tfile->tx_ring;
	}
	}
	list_for_each_entry(tfile, &tun->disabled, next)
	list_for_each_entry(tfile, &tun->disabled, next)
		arrays[i++] = &tfile->tx_array;
		rings[i++] = &tfile->tx_ring;


	ret = skb_array_resize_multiple(arrays, n,
	ret = ptr_ring_resize_multiple(rings, n,
					dev->tx_queue_len, GFP_KERNEL);
				       dev->tx_queue_len, GFP_KERNEL,
				       __skb_array_destroy_skb);


	kfree(arrays);
	kfree(rings);
	return ret;
	return ret;
}
}


@@ -3218,7 +3220,7 @@ struct socket *tun_get_socket(struct file *file)
}
}
EXPORT_SYMBOL_GPL(tun_get_socket);
EXPORT_SYMBOL_GPL(tun_get_socket);


struct skb_array *tun_get_skb_array(struct file *file)
struct ptr_ring *tun_get_tx_ring(struct file *file)
{
{
	struct tun_file *tfile;
	struct tun_file *tfile;


@@ -3227,9 +3229,9 @@ struct skb_array *tun_get_skb_array(struct file *file)
	tfile = file->private_data;
	tfile = file->private_data;
	if (!tfile)
	if (!tfile)
		return ERR_PTR(-EBADFD);
		return ERR_PTR(-EBADFD);
	return &tfile->tx_array;
	return &tfile->tx_ring;
}
}
EXPORT_SYMBOL_GPL(tun_get_skb_array);
EXPORT_SYMBOL_GPL(tun_get_tx_ring);


module_init(tun_init);
module_init(tun_init);
module_exit(tun_cleanup);
module_exit(tun_cleanup);
+20 −19
Original line number Original line Diff line number Diff line
@@ -89,7 +89,7 @@ struct vhost_net_ubuf_ref {


#define VHOST_RX_BATCH 64
#define VHOST_RX_BATCH 64
struct vhost_net_buf {
struct vhost_net_buf {
	struct sk_buff **queue;
	void **queue;
	int tail;
	int tail;
	int head;
	int head;
};
};
@@ -108,7 +108,7 @@ struct vhost_net_virtqueue {
	/* Reference counting for outstanding ubufs.
	/* Reference counting for outstanding ubufs.
	 * Protected by vq mutex. Writers must also take device mutex. */
	 * Protected by vq mutex. Writers must also take device mutex. */
	struct vhost_net_ubuf_ref *ubufs;
	struct vhost_net_ubuf_ref *ubufs;
	struct skb_array *rx_array;
	struct ptr_ring *rx_ring;
	struct vhost_net_buf rxq;
	struct vhost_net_buf rxq;
};
};


@@ -158,7 +158,7 @@ static int vhost_net_buf_produce(struct vhost_net_virtqueue *nvq)
	struct vhost_net_buf *rxq = &nvq->rxq;
	struct vhost_net_buf *rxq = &nvq->rxq;


	rxq->head = 0;
	rxq->head = 0;
	rxq->tail = skb_array_consume_batched(nvq->rx_array, rxq->queue,
	rxq->tail = ptr_ring_consume_batched(nvq->rx_ring, rxq->queue,
					      VHOST_RX_BATCH);
					      VHOST_RX_BATCH);
	return rxq->tail;
	return rxq->tail;
}
}
@@ -167,9 +167,10 @@ static void vhost_net_buf_unproduce(struct vhost_net_virtqueue *nvq)
{
{
	struct vhost_net_buf *rxq = &nvq->rxq;
	struct vhost_net_buf *rxq = &nvq->rxq;


	if (nvq->rx_array && !vhost_net_buf_is_empty(rxq)) {
	if (nvq->rx_ring && !vhost_net_buf_is_empty(rxq)) {
		skb_array_unconsume(nvq->rx_array, rxq->queue + rxq->head,
		ptr_ring_unconsume(nvq->rx_ring, rxq->queue + rxq->head,
				    vhost_net_buf_get_size(rxq));
				   vhost_net_buf_get_size(rxq),
				   __skb_array_destroy_skb);
		rxq->head = rxq->tail = 0;
		rxq->head = rxq->tail = 0;
	}
	}
}
}
@@ -583,7 +584,7 @@ static int peek_head_len(struct vhost_net_virtqueue *rvq, struct sock *sk)
	int len = 0;
	int len = 0;
	unsigned long flags;
	unsigned long flags;


	if (rvq->rx_array)
	if (rvq->rx_ring)
		return vhost_net_buf_peek(rvq);
		return vhost_net_buf_peek(rvq);


	spin_lock_irqsave(&sk->sk_receive_queue.lock, flags);
	spin_lock_irqsave(&sk->sk_receive_queue.lock, flags);
@@ -790,7 +791,7 @@ static void handle_rx(struct vhost_net *net)
			 * they refilled. */
			 * they refilled. */
			goto out;
			goto out;
		}
		}
		if (nvq->rx_array)
		if (nvq->rx_ring)
			msg.msg_control = vhost_net_buf_consume(&nvq->rxq);
			msg.msg_control = vhost_net_buf_consume(&nvq->rxq);
		/* On overrun, truncate and discard */
		/* On overrun, truncate and discard */
		if (unlikely(headcount > UIO_MAXIOV)) {
		if (unlikely(headcount > UIO_MAXIOV)) {
@@ -896,7 +897,7 @@ static int vhost_net_open(struct inode *inode, struct file *f)
	struct vhost_net *n;
	struct vhost_net *n;
	struct vhost_dev *dev;
	struct vhost_dev *dev;
	struct vhost_virtqueue **vqs;
	struct vhost_virtqueue **vqs;
	struct sk_buff **queue;
	void **queue;
	int i;
	int i;


	n = kvmalloc(sizeof *n, GFP_KERNEL | __GFP_RETRY_MAYFAIL);
	n = kvmalloc(sizeof *n, GFP_KERNEL | __GFP_RETRY_MAYFAIL);
@@ -908,7 +909,7 @@ static int vhost_net_open(struct inode *inode, struct file *f)
		return -ENOMEM;
		return -ENOMEM;
	}
	}


	queue = kmalloc_array(VHOST_RX_BATCH, sizeof(struct sk_buff *),
	queue = kmalloc_array(VHOST_RX_BATCH, sizeof(void *),
			      GFP_KERNEL);
			      GFP_KERNEL);
	if (!queue) {
	if (!queue) {
		kfree(vqs);
		kfree(vqs);
@@ -1046,23 +1047,23 @@ static struct socket *get_raw_socket(int fd)
	return ERR_PTR(r);
	return ERR_PTR(r);
}
}


static struct skb_array *get_tap_skb_array(int fd)
static struct ptr_ring *get_tap_ptr_ring(int fd)
{
{
	struct skb_array *array;
	struct ptr_ring *ring;
	struct file *file = fget(fd);
	struct file *file = fget(fd);


	if (!file)
	if (!file)
		return NULL;
		return NULL;
	array = tun_get_skb_array(file);
	ring = tun_get_tx_ring(file);
	if (!IS_ERR(array))
	if (!IS_ERR(ring))
		goto out;
		goto out;
	array = tap_get_skb_array(file);
	ring = tap_get_ptr_ring(file);
	if (!IS_ERR(array))
	if (!IS_ERR(ring))
		goto out;
		goto out;
	array = NULL;
	ring = NULL;
out:
out:
	fput(file);
	fput(file);
	return array;
	return ring;
}
}


static struct socket *get_tap_socket(int fd)
static struct socket *get_tap_socket(int fd)
@@ -1143,7 +1144,7 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd)
		vq->private_data = sock;
		vq->private_data = sock;
		vhost_net_buf_unproduce(nvq);
		vhost_net_buf_unproduce(nvq);
		if (index == VHOST_NET_VQ_RX)
		if (index == VHOST_NET_VQ_RX)
			nvq->rx_array = get_tap_skb_array(fd);
			nvq->rx_ring = get_tap_ptr_ring(fd);
		r = vhost_vq_init_access(vq);
		r = vhost_vq_init_access(vq);
		if (r)
		if (r)
			goto err_used;
			goto err_used;
+3 −3
Original line number Original line Diff line number Diff line
@@ -4,7 +4,7 @@


#if IS_ENABLED(CONFIG_TAP)
#if IS_ENABLED(CONFIG_TAP)
struct socket *tap_get_socket(struct file *);
struct socket *tap_get_socket(struct file *);
struct skb_array *tap_get_skb_array(struct file *file);
struct ptr_ring *tap_get_ptr_ring(struct file *file);
#else
#else
#include <linux/err.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/errno.h>
@@ -14,7 +14,7 @@ static inline struct socket *tap_get_socket(struct file *f)
{
{
	return ERR_PTR(-EINVAL);
	return ERR_PTR(-EINVAL);
}
}
static inline struct skb_array *tap_get_skb_array(struct file *f)
static inline struct ptr_ring *tap_get_ptr_ring(struct file *f)
{
{
	return ERR_PTR(-EINVAL);
	return ERR_PTR(-EINVAL);
}
}
@@ -70,7 +70,7 @@ struct tap_queue {
	u16 queue_index;
	u16 queue_index;
	bool enabled;
	bool enabled;
	struct list_head next;
	struct list_head next;
	struct skb_array skb_array;
	struct ptr_ring ring;
};
};


rx_handler_result_t tap_handle_frame(struct sk_buff **pskb);
rx_handler_result_t tap_handle_frame(struct sk_buff **pskb);
+2 −2
Original line number Original line Diff line number Diff line
@@ -19,7 +19,7 @@


#if defined(CONFIG_TUN) || defined(CONFIG_TUN_MODULE)
#if defined(CONFIG_TUN) || defined(CONFIG_TUN_MODULE)
struct socket *tun_get_socket(struct file *);
struct socket *tun_get_socket(struct file *);
struct skb_array *tun_get_skb_array(struct file *file);
struct ptr_ring *tun_get_tx_ring(struct file *file);
#else
#else
#include <linux/err.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/errno.h>
@@ -29,7 +29,7 @@ static inline struct socket *tun_get_socket(struct file *f)
{
{
	return ERR_PTR(-EINVAL);
	return ERR_PTR(-EINVAL);
}
}
static inline struct skb_array *tun_get_skb_array(struct file *f)
static inline struct ptr_ring *tun_get_tx_ring(struct file *f)
{
{
	return ERR_PTR(-EINVAL);
	return ERR_PTR(-EINVAL);
}
}