History

vhost: switch to use new message format

We use to have message like: struct vhost_msg { int type; union { struct vhost_iotlb_msg iotlb; __u8 padding[64]; }; }; Unfortunately, there will be a hole of 32bit in 64bit machine because of the alignment. This leads a different formats between 32bit API and 64bit API. What's more it will break 32bit program running on 64bit machine. So fixing this by introducing a new message type with an explicit 32bit reserved field after type like: struct vhost_msg_v2 { __u32 type; __u32 reserved; union { struct vhost_iotlb_msg iotlb; __u8 padding[64]; }; }; We will have a consistent ABI after switching to use this. To enable this capability, introduce a new ioctl (VHOST_SET_BAKCEND_FEATURE) for userspace to enable this feature (VHOST_BACKEND_F_IOTLB_V2).

Jason Wang committed 8 years ago

Commit 429711a1 parent 9c2e9554 files · +111 −19Browse files

Unified · Split

4 files
  1. drivers/vhost/net.c +30 −0
  2. drivers/vhost/vhost.c +53 −18
  3. drivers/vhost/vhost.h +10 −1
  4. include/uapi/linux/vhost.h +18 −0
drivers/vhost/net.c+30−0
@@ -77,6 +77,10 @@ enum { · 76 unmodified lines
7777 (1ULL << VIRTIO_F_IOMMU_PLATFORM)
7878 };
7979
80+enum {
81+ VHOST_NET_BACKEND_FEATURES = (1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2)
82+};
83+
8084 enum {
8185 VHOST_NET_VQ_RX = 0,
8286 VHOST_NET_VQ_TX = 1,
@@ -1399,6 +1403,21 @@ done: · 1316 unmodified lines
13991403 return err;
14001404 }
14011405
1406+static int vhost_net_set_backend_features(struct vhost_net *n, u64 features)
1407+{
1408+ int i;
1409+
1410+ mutex_lock(&n->dev.mutex);
1411+ for (i = 0; i < VHOST_NET_VQ_MAX; ++i) {
1412+ mutex_lock(&n->vqs[i].vq.mutex);
1413+ n->vqs[i].vq.acked_backend_features = features;
1414+ mutex_unlock(&n->vqs[i].vq.mutex);
1415+ }
1416+ mutex_unlock(&n->dev.mutex);
1417+
1418+ return 0;
1419+}
1420+
14021421 static int vhost_net_set_features(struct vhost_net *n, u64 features)
14031422 {
14041423 size_t vhost_hlen, sock_hlen, hdr_len;
@@ -1489,6 +1508,17 @@ static long vhost_net_ioctl(struct file *f, unsigned int ioctl, · 84 unmodified lines
14891508 if (features & ~VHOST_NET_FEATURES)
14901509 return -EOPNOTSUPP;
14911510 return vhost_net_set_features(n, features);
1511+ case VHOST_GET_BACKEND_FEATURES:
1512+ features = VHOST_NET_BACKEND_FEATURES;
1513+ if (copy_to_user(featurep, &features, sizeof(features)))
1514+ return -EFAULT;
1515+ return 0;
1516+ case VHOST_SET_BACKEND_FEATURES:
1517+ if (copy_from_user(&features, featurep, sizeof(features)))
1518+ return -EFAULT;
1519+ if (features & ~VHOST_NET_BACKEND_FEATURES)
1520+ return -EOPNOTSUPP;
1521+ return vhost_net_set_backend_features(n, features);
14921522 case VHOST_RESET_OWNER:
14931523 return vhost_net_reset_owner(n);
14941524 case VHOST_SET_OWNER:
drivers/vhost/vhost.c+53−18
@@ -315,6 +315,7 @@ static void vhost_vq_reset(struct vhost_dev *dev, · 314 unmodified lines
315315 vq->log_addr = -1ull;
316316 vq->private_data = NULL;
317317 vq->acked_features = 0;
318+ vq->acked_backend_features = 0;
318319 vq->log_base = NULL;
319320 vq->error_ctx = NULL;
320321 vq->kick = NULL;
@@ -1027,28 +1028,40 @@ static int vhost_process_iotlb_msg(struct vhost_dev *dev, · 706 unmodified lines
10271028 ssize_t vhost_chr_write_iter(struct vhost_dev *dev,
10281029 struct iov_iter *from)
10291030 {
1030− struct vhost_msg_node node;
1031− unsigned size = sizeof(struct vhost_msg);
1032− size_t ret;
1033− int err;
1031+ struct vhost_iotlb_msg msg;
1032+ size_t offset;
1033+ int type, ret;
10341034
1035− if (iov_iter_count(from) < size)
1036− return 0;
1037− ret = copy_from_iter(&node.msg, size, from);
1038− if (ret != size)
1035+ ret = copy_from_iter(&type, sizeof(type), from);
1036+ if (ret != sizeof(type))
10391037 goto done;
10401038
1041− switch (node.msg.type) {
1039+ switch (type) {
10421040 case VHOST_IOTLB_MSG:
1043− err = vhost_process_iotlb_msg(dev, &node.msg.iotlb);
1044− if (err)
1045− ret = err;
1041+ /* There maybe a hole after type for V1 message type,
1042+ * so skip it here.
1043+ */
1044+ offset = offsetof(struct vhost_msg, iotlb) - sizeof(int);
1045+ break;
1046+ case VHOST_IOTLB_MSG_V2:
1047+ offset = sizeof(__u32);
10461048 break;
10471049 default:
10481050 ret = -EINVAL;
1049− break;
1051+ goto done;
1052+ }
1053+
1054+ iov_iter_advance(from, offset);
1055+ ret = copy_from_iter(&msg, sizeof(msg), from);
1056+ if (ret != sizeof(msg))
1057+ goto done;
1058+ if (vhost_process_iotlb_msg(dev, &msg)) {
1059+ ret = -EFAULT;
1060+ goto done;
10501061 }
10511062
1063+ ret = (type == VHOST_IOTLB_MSG) ? sizeof(struct vhost_msg) :
1064+ sizeof(struct vhost_msg_v2);
10521065 done:
10531066 return ret;
10541067 }
@@ -1107,13 +1120,28 @@ ssize_t vhost_chr_read_iter(struct vhost_dev *dev, struct iov_iter *to, · 52 unmodified lines
11071120 finish_wait(&dev->wait, &wait);
11081121
11091122 if (node) {
1110− ret = copy_to_iter(&node->msg, size, to);
1123+ struct vhost_iotlb_msg *msg;
1124+ void *start = &node->msg;
1125+
1126+ switch (node->msg.type) {
1127+ case VHOST_IOTLB_MSG:
1128+ size = sizeof(node->msg);
1129+ msg = &node->msg.iotlb;
1130+ break;
1131+ case VHOST_IOTLB_MSG_V2:
1132+ size = sizeof(node->msg_v2);
1133+ msg = &node->msg_v2.iotlb;
1134+ break;
1135+ default:
1136+ BUG();
1137+ break;
1138+ }
11111139
1112− if (ret != size || node->msg.type != VHOST_IOTLB_MISS) {
1140+ ret = copy_to_iter(start, size, to);
1141+ if (ret != size || msg->type != VHOST_IOTLB_MISS) {
11131142 kfree(node);
11141143 return ret;
11151144 }
1116−
11171145 vhost_enqueue_msg(dev, &dev->pending_list, node);
11181146 }
11191147
@@ -1126,12 +1154,19 @@ static int vhost_iotlb_miss(struct vhost_virtqueue *vq, u64 iova, int access) · 6 unmodified lines
11261154 struct vhost_dev *dev = vq->dev;
11271155 struct vhost_msg_node *node;
11281156 struct vhost_iotlb_msg *msg;
1157+ bool v2 = vhost_backend_has_feature(vq, VHOST_BACKEND_F_IOTLB_MSG_V2);
11291158
1130− node = vhost_new_msg(vq, VHOST_IOTLB_MISS);
1159+ node = vhost_new_msg(vq, v2 ? VHOST_IOTLB_MSG_V2 : VHOST_IOTLB_MSG);
11311160 if (!node)
11321161 return -ENOMEM;
11331162
1134− msg = &node->msg.iotlb;
1163+ if (v2) {
1164+ node->msg_v2.type = VHOST_IOTLB_MSG_V2;
1165+ msg = &node->msg_v2.iotlb;
1166+ } else {
1167+ msg = &node->msg.iotlb;
1168+ }
1169+
11351170 msg->type = VHOST_IOTLB_MISS;
11361171 msg->iova = iova;
11371172 msg->perm = access;
drivers/vhost/vhost.h+10−1
@@ -132,6 +132,7 @@ struct vhost_virtqueue { · 131 unmodified lines
132132 struct vhost_umem *iotlb;
133133 void *private_data;
134134 u64 acked_features;
135+ u64 acked_backend_features;
135136 /* Log write descriptors */
136137 void __user *log_base;
137138 struct vhost_log *log;
@@ -147,7 +148,10 @@ struct vhost_virtqueue { · 9 unmodified lines
147148 };
148149
149150 struct vhost_msg_node {
150− struct vhost_msg msg;
151+ union {
152+ struct vhost_msg msg;
153+ struct vhost_msg_v2 msg_v2;
154+ };
151155 struct vhost_virtqueue *vq;
152156 struct list_head node;
153157 };
@@ -238,6 +242,11 @@ static inline bool vhost_has_feature(struct vhost_virtqueue *vq, int bit) · 84 unmodified lines
238242 return vq->acked_features & (1ULL << bit);
239243 }
240244
245+static inline bool vhost_backend_has_feature(struct vhost_virtqueue *vq, int bit)
246+{
247+ return vq->acked_backend_features & (1ULL << bit);
248+}
249+
241250 #ifdef CONFIG_VHOST_CROSS_ENDIAN_LEGACY
242251 static inline bool vhost_is_little_endian(struct vhost_virtqueue *vq)
243252 {
include/uapi/linux/vhost.h+18−0
@@ -65,6 +65,7 @@ struct vhost_iotlb_msg { · 64 unmodified lines
6565 };
6666
6767 #define VHOST_IOTLB_MSG 0x1
68+#define VHOST_IOTLB_MSG_V2 0x2
6869
6970 struct vhost_msg {
7071 int type;
@@ -74,6 +75,15 @@ struct vhost_msg { · 3 unmodified lines
7475 };
7576 };
7677
78+struct vhost_msg_v2 {
79+ __u32 type;
80+ __u32 reserved;
81+ union {
82+ struct vhost_iotlb_msg iotlb;
83+ __u8 padding[64];
84+ };
85+};
86+
7787 struct vhost_memory_region {
7888 __u64 guest_phys_addr;
7989 __u64 memory_size; /* bytes */
@@ -160,6 +170,14 @@ struct vhost_memory { · 80 unmodified lines
160170 #define VHOST_GET_VRING_BUSYLOOP_TIMEOUT _IOW(VHOST_VIRTIO, 0x24, \
161171 struct vhost_vring_state)
162172
173+/* Set or get vhost backend capability */
174+
175+/* Use message type V2 */
176+#define VHOST_BACKEND_F_IOTLB_MSG_V2 0x1
177+
178+#define VHOST_SET_BACKEND_FEATURES _IOW(VHOST_VIRTIO, 0x25, __u64)
179+#define VHOST_GET_BACKEND_FEATURES _IOW(VHOST_VIRTIO, 0x26, __u64)
180+
163181 /* VHOST_NET specific defines */
164182
165183 /* Attach virtio net ring to a raw socket, or tap device.