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

Commit 6b9e2cea authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull virtio updates from Michael Tsirkin:
 "virtio: virtio 1.0 support, misc patches

  This adds a lot of infrastructure for virtio 1.0 support.  Notable
  missing pieces: virtio pci, virtio balloon (needs spec extension),
  vhost scsi.

  Plus, there are some minor fixes in a couple of places.

  Note: some net drivers are affected by these patches.  David said he's
  fine with merging these patches through my tree.

  Rusty's on vacation, he acked using my tree for these, too"

* tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost: (70 commits)
  virtio_ccw: finalize_features error handling
  virtio_ccw: future-proof finalize_features
  virtio_pci: rename virtio_pci -> virtio_pci_common
  virtio_pci: update file descriptions and copyright
  virtio_pci: split out legacy device support
  virtio_pci: setup config vector indirectly
  virtio_pci: setup vqs indirectly
  virtio_pci: delete vqs indirectly
  virtio_pci: use priv for vq notification
  virtio_pci: free up vq->priv
  virtio_pci: fix coding style for structs
  virtio_pci: add isr field
  virtio: drop legacy_only driver flag
  virtio_balloon: drop legacy_only driver flag
  virtio_ccw: rev 1 devices set VIRTIO_F_VERSION_1
  virtio: allow finalize_features to fail
  virtio_ccw: legacy: don't negotiate rev 1/features
  virtio: add API to detect legacy devices
  virtio_console: fix sparse warnings
  vhost: remove unnecessary forward declarations in vhost.h
  ...
parents 14ba9a2e f01a2a81
Loading
Loading
Loading
Loading
+43 −31
Original line number Diff line number Diff line
@@ -80,7 +80,7 @@ static int __virtblk_add_req(struct virtqueue *vq,
{
	struct scatterlist hdr, status, cmd, sense, inhdr, *sgs[6];
	unsigned int num_out = 0, num_in = 0;
	int type = vbr->out_hdr.type & ~VIRTIO_BLK_T_OUT;
	__virtio32 type = vbr->out_hdr.type & ~cpu_to_virtio32(vq->vdev, VIRTIO_BLK_T_OUT);

	sg_init_one(&hdr, &vbr->out_hdr, sizeof(vbr->out_hdr));
	sgs[num_out++] = &hdr;
@@ -91,19 +91,19 @@ static int __virtblk_add_req(struct virtqueue *vq,
	 * block, and before the normal inhdr we put the sense data and the
	 * inhdr with additional status information.
	 */
	if (type == VIRTIO_BLK_T_SCSI_CMD) {
	if (type == cpu_to_virtio32(vq->vdev, VIRTIO_BLK_T_SCSI_CMD)) {
		sg_init_one(&cmd, vbr->req->cmd, vbr->req->cmd_len);
		sgs[num_out++] = &cmd;
	}

	if (have_data) {
		if (vbr->out_hdr.type & VIRTIO_BLK_T_OUT)
		if (vbr->out_hdr.type & cpu_to_virtio32(vq->vdev, VIRTIO_BLK_T_OUT))
			sgs[num_out++] = data_sg;
		else
			sgs[num_out + num_in++] = data_sg;
	}

	if (type == VIRTIO_BLK_T_SCSI_CMD) {
	if (type == cpu_to_virtio32(vq->vdev, VIRTIO_BLK_T_SCSI_CMD)) {
		sg_init_one(&sense, vbr->req->sense, SCSI_SENSE_BUFFERSIZE);
		sgs[num_out + num_in++] = &sense;
		sg_init_one(&inhdr, &vbr->in_hdr, sizeof(vbr->in_hdr));
@@ -119,12 +119,13 @@ static int __virtblk_add_req(struct virtqueue *vq,
static inline void virtblk_request_done(struct request *req)
{
	struct virtblk_req *vbr = blk_mq_rq_to_pdu(req);
	struct virtio_blk *vblk = req->q->queuedata;
	int error = virtblk_result(vbr);

	if (req->cmd_type == REQ_TYPE_BLOCK_PC) {
		req->resid_len = vbr->in_hdr.residual;
		req->sense_len = vbr->in_hdr.sense_len;
		req->errors = vbr->in_hdr.errors;
		req->resid_len = virtio32_to_cpu(vblk->vdev, vbr->in_hdr.residual);
		req->sense_len = virtio32_to_cpu(vblk->vdev, vbr->in_hdr.sense_len);
		req->errors = virtio32_to_cpu(vblk->vdev, vbr->in_hdr.errors);
	} else if (req->cmd_type == REQ_TYPE_SPECIAL) {
		req->errors = (error != 0);
	}
@@ -173,25 +174,25 @@ static int virtio_queue_rq(struct blk_mq_hw_ctx *hctx, struct request *req,

	vbr->req = req;
	if (req->cmd_flags & REQ_FLUSH) {
		vbr->out_hdr.type = VIRTIO_BLK_T_FLUSH;
		vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_FLUSH);
		vbr->out_hdr.sector = 0;
		vbr->out_hdr.ioprio = req_get_ioprio(vbr->req);
		vbr->out_hdr.ioprio = cpu_to_virtio32(vblk->vdev, req_get_ioprio(vbr->req));
	} else {
		switch (req->cmd_type) {
		case REQ_TYPE_FS:
			vbr->out_hdr.type = 0;
			vbr->out_hdr.sector = blk_rq_pos(vbr->req);
			vbr->out_hdr.ioprio = req_get_ioprio(vbr->req);
			vbr->out_hdr.sector = cpu_to_virtio64(vblk->vdev, blk_rq_pos(vbr->req));
			vbr->out_hdr.ioprio = cpu_to_virtio32(vblk->vdev, req_get_ioprio(vbr->req));
			break;
		case REQ_TYPE_BLOCK_PC:
			vbr->out_hdr.type = VIRTIO_BLK_T_SCSI_CMD;
			vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_SCSI_CMD);
			vbr->out_hdr.sector = 0;
			vbr->out_hdr.ioprio = req_get_ioprio(vbr->req);
			vbr->out_hdr.ioprio = cpu_to_virtio32(vblk->vdev, req_get_ioprio(vbr->req));
			break;
		case REQ_TYPE_SPECIAL:
			vbr->out_hdr.type = VIRTIO_BLK_T_GET_ID;
			vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_GET_ID);
			vbr->out_hdr.sector = 0;
			vbr->out_hdr.ioprio = req_get_ioprio(vbr->req);
			vbr->out_hdr.ioprio = cpu_to_virtio32(vblk->vdev, req_get_ioprio(vbr->req));
			break;
		default:
			/* We don't put anything else in the queue. */
@@ -204,9 +205,9 @@ static int virtio_queue_rq(struct blk_mq_hw_ctx *hctx, struct request *req,
	num = blk_rq_map_sg(hctx->queue, vbr->req, vbr->sg);
	if (num) {
		if (rq_data_dir(vbr->req) == WRITE)
			vbr->out_hdr.type |= VIRTIO_BLK_T_OUT;
			vbr->out_hdr.type |= cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_OUT);
		else
			vbr->out_hdr.type |= VIRTIO_BLK_T_IN;
			vbr->out_hdr.type |= cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_IN);
	}

	spin_lock_irqsave(&vblk->vqs[qid].lock, flags);
@@ -331,7 +332,8 @@ static ssize_t virtblk_serial_show(struct device *dev,

	return err;
}
DEVICE_ATTR(serial, S_IRUGO, virtblk_serial_show, NULL);

static DEVICE_ATTR(serial, S_IRUGO, virtblk_serial_show, NULL);

static void virtblk_config_changed_work(struct work_struct *work)
{
@@ -476,7 +478,8 @@ static int virtblk_get_cache_mode(struct virtio_device *vdev)
				   struct virtio_blk_config, wce,
				   &writeback);
	if (err)
		writeback = virtio_has_feature(vdev, VIRTIO_BLK_F_WCE);
		writeback = virtio_has_feature(vdev, VIRTIO_BLK_F_WCE) ||
		            virtio_has_feature(vdev, VIRTIO_F_VERSION_1);

	return writeback;
}
@@ -821,16 +824,25 @@ static const struct virtio_device_id id_table[] = {
	{ 0 },
};

static unsigned int features[] = {
static unsigned int features_legacy[] = {
	VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, VIRTIO_BLK_F_GEOMETRY,
	VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, VIRTIO_BLK_F_SCSI,
	VIRTIO_BLK_F_WCE, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE,
	VIRTIO_BLK_F_MQ,
}
;
static unsigned int features[] = {
	VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, VIRTIO_BLK_F_GEOMETRY,
	VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE,
	VIRTIO_BLK_F_TOPOLOGY,
	VIRTIO_BLK_F_MQ,
};

static struct virtio_driver virtio_blk = {
	.feature_table			= features,
	.feature_table_size		= ARRAY_SIZE(features),
	.feature_table_legacy		= features_legacy,
	.feature_table_size_legacy	= ARRAY_SIZE(features_legacy),
	.driver.name			= KBUILD_MODNAME,
	.driver.owner			= THIS_MODULE,
	.id_table			= id_table,
@@ -871,8 +883,8 @@ static int __init init(void)

static void __exit fini(void)
{
	unregister_blkdev(major, "virtblk");
	unregister_virtio_driver(&virtio_blk);
	unregister_blkdev(major, "virtblk");
	destroy_workqueue(virtblk_wq);
}
module_init(init);
+22 −17
Original line number Diff line number Diff line
@@ -355,7 +355,7 @@ static inline bool use_multiport(struct ports_device *portdev)
	 */
	if (!portdev->vdev)
		return 0;
	return portdev->vdev->features[0] & (1 << VIRTIO_CONSOLE_F_MULTIPORT);
	return __virtio_test_bit(portdev->vdev, VIRTIO_CONSOLE_F_MULTIPORT);
}

static DEFINE_SPINLOCK(dma_bufs_lock);
@@ -566,9 +566,9 @@ static ssize_t __send_control_msg(struct ports_device *portdev, u32 port_id,
	if (!use_multiport(portdev))
		return 0;

	cpkt.id = port_id;
	cpkt.event = event;
	cpkt.value = value;
	cpkt.id = cpu_to_virtio32(portdev->vdev, port_id);
	cpkt.event = cpu_to_virtio16(portdev->vdev, event);
	cpkt.value = cpu_to_virtio16(portdev->vdev, value);

	vq = portdev->c_ovq;

@@ -669,8 +669,8 @@ static ssize_t __send_to_port(struct port *port, struct scatterlist *sg,
 * Give out the data that's requested from the buffer that we have
 * queued up.
 */
static ssize_t fill_readbuf(struct port *port, char *out_buf, size_t out_count,
			    bool to_user)
static ssize_t fill_readbuf(struct port *port, char __user *out_buf,
			    size_t out_count, bool to_user)
{
	struct port_buffer *buf;
	unsigned long flags;
@@ -688,7 +688,8 @@ static ssize_t fill_readbuf(struct port *port, char *out_buf, size_t out_count,
		if (ret)
			return -EFAULT;
	} else {
		memcpy(out_buf, buf->buf + buf->offset, out_count);
		memcpy((__force char *)out_buf, buf->buf + buf->offset,
		       out_count);
	}

	buf->offset += out_count;
@@ -1162,7 +1163,7 @@ static int get_chars(u32 vtermno, char *buf, int count)
	/* If we don't have an input queue yet, we can't get input. */
	BUG_ON(!port->in_vq);

	return fill_readbuf(port, buf, count, false);
	return fill_readbuf(port, (__force char __user *)buf, count, false);
}

static void resize_console(struct port *port)
@@ -1602,7 +1603,8 @@ static void unplug_port(struct port *port)
}

/* Any private messages that the Host and Guest want to share */
static void handle_control_message(struct ports_device *portdev,
static void handle_control_message(struct virtio_device *vdev,
				   struct ports_device *portdev,
				   struct port_buffer *buf)
{
	struct virtio_console_control *cpkt;
@@ -1612,15 +1614,16 @@ static void handle_control_message(struct ports_device *portdev,

	cpkt = (struct virtio_console_control *)(buf->buf + buf->offset);

	port = find_port_by_id(portdev, cpkt->id);
	if (!port && cpkt->event != VIRTIO_CONSOLE_PORT_ADD) {
	port = find_port_by_id(portdev, virtio32_to_cpu(vdev, cpkt->id));
	if (!port &&
	    cpkt->event != cpu_to_virtio16(vdev, VIRTIO_CONSOLE_PORT_ADD)) {
		/* No valid header at start of buffer.  Drop it. */
		dev_dbg(&portdev->vdev->dev,
			"Invalid index %u in control packet\n", cpkt->id);
		return;
	}

	switch (cpkt->event) {
	switch (virtio16_to_cpu(vdev, cpkt->event)) {
	case VIRTIO_CONSOLE_PORT_ADD:
		if (port) {
			dev_dbg(&portdev->vdev->dev,
@@ -1628,13 +1631,15 @@ static void handle_control_message(struct ports_device *portdev,
			send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
			break;
		}
		if (cpkt->id >= portdev->config.max_nr_ports) {
		if (virtio32_to_cpu(vdev, cpkt->id) >=
		    portdev->config.max_nr_ports) {
			dev_warn(&portdev->vdev->dev,
				"Request for adding port with out-of-bound id %u, max. supported id: %u\n",
				"Request for adding port with "
				"out-of-bound id %u, max. supported id: %u\n",
				cpkt->id, portdev->config.max_nr_ports - 1);
			break;
		}
		add_port(portdev, cpkt->id);
		add_port(portdev, virtio32_to_cpu(vdev, cpkt->id));
		break;
	case VIRTIO_CONSOLE_PORT_REMOVE:
		unplug_port(port);
@@ -1670,7 +1675,7 @@ static void handle_control_message(struct ports_device *portdev,
		break;
	}
	case VIRTIO_CONSOLE_PORT_OPEN:
		port->host_connected = cpkt->value;
		port->host_connected = virtio16_to_cpu(vdev, cpkt->value);
		wake_up_interruptible(&port->waitqueue);
		/*
		 * If the host port got closed and the host had any
@@ -1752,7 +1757,7 @@ static void control_work_handler(struct work_struct *work)
		buf->len = len;
		buf->offset = 0;

		handle_control_message(portdev, buf);
		handle_control_message(vq->vdev, portdev, buf);

		spin_lock(&portdev->c_ivq_lock);
		if (add_inbuf(portdev->c_ivq, buf) < 0) {
+11 −6
Original line number Diff line number Diff line
@@ -94,7 +94,7 @@ static unsigned desc_size(const struct lguest_device_desc *desc)
}

/* This gets the device's feature bits. */
static u32 lg_get_features(struct virtio_device *vdev)
static u64 lg_get_features(struct virtio_device *vdev)
{
	unsigned int i;
	u32 features = 0;
@@ -126,7 +126,7 @@ static void status_notify(struct virtio_device *vdev)
 * sorted out, this routine is called so we can tell the Host which features we
 * understand and accept.
 */
static void lg_finalize_features(struct virtio_device *vdev)
static int lg_finalize_features(struct virtio_device *vdev)
{
	unsigned int i, bits;
	struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
@@ -136,20 +136,25 @@ static void lg_finalize_features(struct virtio_device *vdev)
	/* Give virtio_ring a chance to accept features. */
	vring_transport_features(vdev);

	/* Make sure we don't have any features > 32 bits! */
	BUG_ON((u32)vdev->features != vdev->features);

	/*
	 * The vdev->feature array is a Linux bitmask: this isn't the same as a
	 * the simple array of bits used by lguest devices for features.  So we
	 * do this slow, manual conversion which is completely general.
	 * Since lguest is currently x86-only, we're little-endian.  That
	 * means we could just memcpy.  But it's not time critical, and in
	 * case someone copies this code, we do it the slow, obvious way.
	 */
	memset(out_features, 0, desc->feature_len);
	bits = min_t(unsigned, desc->feature_len, sizeof(vdev->features)) * 8;
	for (i = 0; i < bits; i++) {
		if (test_bit(i, vdev->features))
		if (__virtio_test_bit(vdev, i))
			out_features[i / 8] |= (1 << (i % 8));
	}

	/* Tell Host we've finished with this device's feature negotiation */
	status_notify(vdev);

	return 0;
}

/* Once they've found a field, getting a copy of it is easy. */
+9 −5
Original line number Diff line number Diff line
@@ -68,7 +68,7 @@ static inline struct device *mic_dev(struct mic_vdev *mvdev)
}

/* This gets the device's feature bits. */
static u32 mic_get_features(struct virtio_device *vdev)
static u64 mic_get_features(struct virtio_device *vdev)
{
	unsigned int i, bits;
	u32 features = 0;
@@ -76,8 +76,7 @@ static u32 mic_get_features(struct virtio_device *vdev)
	u8 __iomem *in_features = mic_vq_features(desc);
	int feature_len = ioread8(&desc->feature_len);

	bits = min_t(unsigned, feature_len,
		sizeof(vdev->features)) * 8;
	bits = min_t(unsigned, feature_len, sizeof(features)) * 8;
	for (i = 0; i < bits; i++)
		if (ioread8(&in_features[i / 8]) & (BIT(i % 8)))
			features |= BIT(i);
@@ -85,7 +84,7 @@ static u32 mic_get_features(struct virtio_device *vdev)
	return features;
}

static void mic_finalize_features(struct virtio_device *vdev)
static int mic_finalize_features(struct virtio_device *vdev)
{
	unsigned int i, bits;
	struct mic_device_desc __iomem *desc = to_micvdev(vdev)->desc;
@@ -97,14 +96,19 @@ static void mic_finalize_features(struct virtio_device *vdev)
	/* Give virtio_ring a chance to accept features. */
	vring_transport_features(vdev);

	/* Make sure we don't have any features > 32 bits! */
	BUG_ON((u32)vdev->features != vdev->features);

	memset_io(out_features, 0, feature_len);
	bits = min_t(unsigned, feature_len,
		sizeof(vdev->features)) * 8;
	for (i = 0; i < bits; i++) {
		if (test_bit(i, vdev->features))
		if (__virtio_test_bit(vdev, i))
			iowrite8(ioread8(&out_features[i / 8]) | (1 << (i % 8)),
				 &out_features[i / 8]);
	}

	return 0;
}

/*
+43 −25
Original line number Diff line number Diff line
@@ -45,6 +45,18 @@ struct macvtap_queue {
	struct list_head next;
};

#define MACVTAP_FEATURES (IFF_VNET_HDR | IFF_VNET_LE | IFF_MULTI_QUEUE)

static inline u16 macvtap16_to_cpu(struct macvtap_queue *q, __virtio16 val)
{
	return __virtio16_to_cpu(q->flags & IFF_VNET_LE, val);
}

static inline __virtio16 cpu_to_macvtap16(struct macvtap_queue *q, u16 val)
{
	return __cpu_to_virtio16(q->flags & IFF_VNET_LE, val);
}

static struct proto macvtap_proto = {
	.name = "macvtap",
	.owner = THIS_MODULE,
@@ -557,7 +569,8 @@ static inline struct sk_buff *macvtap_alloc_skb(struct sock *sk, size_t prepad,
 * macvtap_skb_from_vnet_hdr and macvtap_skb_to_vnet_hdr should
 * be shared with the tun/tap driver.
 */
static int macvtap_skb_from_vnet_hdr(struct sk_buff *skb,
static int macvtap_skb_from_vnet_hdr(struct macvtap_queue *q,
				     struct sk_buff *skb,
				     struct virtio_net_hdr *vnet_hdr)
{
	unsigned short gso_type = 0;
@@ -588,13 +601,13 @@ static int macvtap_skb_from_vnet_hdr(struct sk_buff *skb,
	}

	if (vnet_hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
		if (!skb_partial_csum_set(skb, vnet_hdr->csum_start,
					  vnet_hdr->csum_offset))
		if (!skb_partial_csum_set(skb, macvtap16_to_cpu(q, vnet_hdr->csum_start),
					  macvtap16_to_cpu(q, vnet_hdr->csum_offset)))
			return -EINVAL;
	}

	if (vnet_hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
		skb_shinfo(skb)->gso_size = vnet_hdr->gso_size;
		skb_shinfo(skb)->gso_size = macvtap16_to_cpu(q, vnet_hdr->gso_size);
		skb_shinfo(skb)->gso_type = gso_type;

		/* Header must be checked, and gso_segs computed. */
@@ -604,7 +617,8 @@ static int macvtap_skb_from_vnet_hdr(struct sk_buff *skb,
	return 0;
}

static void macvtap_skb_to_vnet_hdr(const struct sk_buff *skb,
static void macvtap_skb_to_vnet_hdr(struct macvtap_queue *q,
				    const struct sk_buff *skb,
				    struct virtio_net_hdr *vnet_hdr)
{
	memset(vnet_hdr, 0, sizeof(*vnet_hdr));
@@ -613,8 +627,8 @@ static void macvtap_skb_to_vnet_hdr(const struct sk_buff *skb,
		struct skb_shared_info *sinfo = skb_shinfo(skb);

		/* This is a hint as to how much should be linear. */
		vnet_hdr->hdr_len = skb_headlen(skb);
		vnet_hdr->gso_size = sinfo->gso_size;
		vnet_hdr->hdr_len = cpu_to_macvtap16(q, skb_headlen(skb));
		vnet_hdr->gso_size = cpu_to_macvtap16(q, sinfo->gso_size);
		if (sinfo->gso_type & SKB_GSO_TCPV4)
			vnet_hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
		else if (sinfo->gso_type & SKB_GSO_TCPV6)
@@ -628,10 +642,13 @@ static void macvtap_skb_to_vnet_hdr(const struct sk_buff *skb,

	if (skb->ip_summed == CHECKSUM_PARTIAL) {
		vnet_hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
		vnet_hdr->csum_start = skb_checksum_start_offset(skb);
		if (vlan_tx_tag_present(skb))
			vnet_hdr->csum_start += VLAN_HLEN;
		vnet_hdr->csum_offset = skb->csum_offset;
			vnet_hdr->csum_start = cpu_to_macvtap16(q,
				skb_checksum_start_offset(skb) + VLAN_HLEN);
		else
			vnet_hdr->csum_start = cpu_to_macvtap16(q,
				skb_checksum_start_offset(skb));
		vnet_hdr->csum_offset = cpu_to_macvtap16(q, skb->csum_offset);
	} else if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
		vnet_hdr->flags = VIRTIO_NET_HDR_F_DATA_VALID;
	} /* else everything is zero */
@@ -666,12 +683,14 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
		if (err < 0)
			goto err;
		if ((vnet_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) &&
		     vnet_hdr.csum_start + vnet_hdr.csum_offset + 2 >
							vnet_hdr.hdr_len)
			vnet_hdr.hdr_len = vnet_hdr.csum_start +
						vnet_hdr.csum_offset + 2;
		     macvtap16_to_cpu(q, vnet_hdr.csum_start) +
		     macvtap16_to_cpu(q, vnet_hdr.csum_offset) + 2 >
			     macvtap16_to_cpu(q, vnet_hdr.hdr_len))
			vnet_hdr.hdr_len = cpu_to_macvtap16(q,
				 macvtap16_to_cpu(q, vnet_hdr.csum_start) +
				 macvtap16_to_cpu(q, vnet_hdr.csum_offset) + 2);
		err = -EINVAL;
		if (vnet_hdr.hdr_len > len)
		if (macvtap16_to_cpu(q, vnet_hdr.hdr_len) > len)
			goto err;
	}

@@ -684,7 +703,8 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
		goto err;

	if (m && m->msg_control && sock_flag(&q->sk, SOCK_ZEROCOPY)) {
		copylen = vnet_hdr.hdr_len ? vnet_hdr.hdr_len : GOODCOPY_LEN;
		copylen = vnet_hdr.hdr_len ?
			macvtap16_to_cpu(q, vnet_hdr.hdr_len) : GOODCOPY_LEN;
		if (copylen > good_linear)
			copylen = good_linear;
		linear = copylen;
@@ -695,10 +715,10 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,

	if (!zerocopy) {
		copylen = len;
		if (vnet_hdr.hdr_len > good_linear)
		if (macvtap16_to_cpu(q, vnet_hdr.hdr_len) > good_linear)
			linear = good_linear;
		else
			linear = vnet_hdr.hdr_len;
			linear = macvtap16_to_cpu(q, vnet_hdr.hdr_len);
	}

	skb = macvtap_alloc_skb(&q->sk, NET_IP_ALIGN, copylen,
@@ -725,7 +745,7 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
	skb->protocol = eth_hdr(skb)->h_proto;

	if (vnet_hdr_len) {
		err = macvtap_skb_from_vnet_hdr(skb, &vnet_hdr);
		err = macvtap_skb_from_vnet_hdr(q, skb, &vnet_hdr);
		if (err)
			goto err_kfree;
	}
@@ -791,7 +811,7 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q,
		if ((len -= vnet_hdr_len) < 0)
			return -EINVAL;

		macvtap_skb_to_vnet_hdr(skb, &vnet_hdr);
		macvtap_skb_to_vnet_hdr(q, skb, &vnet_hdr);

		if (memcpy_toiovecend(iv, (void *)&vnet_hdr, 0, sizeof(vnet_hdr)))
			return -EFAULT;
@@ -1003,8 +1023,7 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd,
			return -EFAULT;

		ret = 0;
		if ((u & ~(IFF_VNET_HDR | IFF_MULTI_QUEUE)) !=
		    (IFF_NO_PI | IFF_TAP))
		if ((u & ~MACVTAP_FEATURES) != (IFF_NO_PI | IFF_TAP))
			ret = -EINVAL;
		else
			q->flags = u;
@@ -1036,8 +1055,7 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd,
		return ret;

	case TUNGETFEATURES:
		if (put_user(IFF_TAP | IFF_NO_PI | IFF_VNET_HDR |
			     IFF_MULTI_QUEUE, up))
		if (put_user(IFF_TAP | IFF_NO_PI | MACVTAP_FEATURES, up))
			return -EFAULT;
		return 0;

Loading