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
77 (1ULL << VIRTIO_F_IOMMU_PLATFORM)77 (1ULL << VIRTIO_F_IOMMU_PLATFORM)
78};78};
79 79
80enum {
81 VHOST_NET_BACKEND_FEATURES = (1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2)
82};
83
80enum {84enum {
81 VHOST_NET_VQ_RX = 0,85 VHOST_NET_VQ_RX = 0,
82 VHOST_NET_VQ_TX = 1,86 VHOST_NET_VQ_TX = 1,
@@ -1399,6 +1403,21 @@ done: · 1316 unmodified lines
1399 return err;1403 return err;
1400}1404}
1401 1405
1406static 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
1402static int vhost_net_set_features(struct vhost_net *n, u64 features)1421static int vhost_net_set_features(struct vhost_net *n, u64 features)
1403{1422{
1404 size_t vhost_hlen, sock_hlen, hdr_len;1423 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
1489 if (features & ~VHOST_NET_FEATURES)1508 if (features & ~VHOST_NET_FEATURES)
1490 return -EOPNOTSUPP;1509 return -EOPNOTSUPP;
1491 return vhost_net_set_features(n, features);1510 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);
1492 case VHOST_RESET_OWNER:1522 case VHOST_RESET_OWNER:
1493 return vhost_net_reset_owner(n);1523 return vhost_net_reset_owner(n);
1494 case VHOST_SET_OWNER:1524 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
315 vq->log_addr = -1ull;315 vq->log_addr = -1ull;
316 vq->private_data = NULL;316 vq->private_data = NULL;
317 vq->acked_features = 0;317 vq->acked_features = 0;
318 vq->acked_backend_features = 0;
318 vq->log_base = NULL;319 vq->log_base = NULL;
319 vq->error_ctx = NULL;320 vq->error_ctx = NULL;
320 vq->kick = NULL;321 vq->kick = NULL;
@@ -1027,28 +1028,40 @@ static int vhost_process_iotlb_msg(struct vhost_dev *dev, · 706 unmodified lines
1027ssize_t vhost_chr_write_iter(struct vhost_dev *dev,1028ssize_t vhost_chr_write_iter(struct vhost_dev *dev,
1028 struct iov_iter *from)1029 struct iov_iter *from)
1029{1030{
1030 struct vhost_msg_node node;1031 struct vhost_iotlb_msg msg;
1031 unsigned size = sizeof(struct vhost_msg);1032 size_t offset;
1032 size_t ret;1033 int type, ret;
1033 int err;
1034 1034
1035 if (iov_iter_count(from) < size)1035 ret = copy_from_iter(&type, sizeof(type), from);
1036 return 0;1036 if (ret != sizeof(type))
1037 ret = copy_from_iter(&node.msg, size, from);
1038 if (ret != size)
1039 goto done;1037 goto done;
1040 1038
1041 switch (node.msg.type) {1039 switch (type) {
1042 case VHOST_IOTLB_MSG:1040 case VHOST_IOTLB_MSG:
1043 err = vhost_process_iotlb_msg(dev, &node.msg.iotlb);1041 /* There maybe a hole after type for V1 message type,
1044 if (err)1042 * so skip it here.
1045 ret = err;1043 */
1044 offset = offsetof(struct vhost_msg, iotlb) - sizeof(int);
1045 break;
1046 case VHOST_IOTLB_MSG_V2:
1047 offset = sizeof(__u32);
1046 break;1048 break;
1047 default:1049 default:
1048 ret = -EINVAL;1050 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;
1050 }1061 }
1051 1062
1063 ret = (type == VHOST_IOTLB_MSG) ? sizeof(struct vhost_msg) :
1064 sizeof(struct vhost_msg_v2);
1052done:1065done:
1053 return ret;1066 return ret;
1054}1067}
@@ -1107,13 +1120,28 @@ ssize_t vhost_chr_read_iter(struct vhost_dev *dev, struct iov_iter *to, · 52 unmodified lines
1107 finish_wait(&dev->wait, &wait);1120 finish_wait(&dev->wait, &wait);
1108 1121
1109 if (node) {1122 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 }
1111 1139
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) {
1113 kfree(node);1142 kfree(node);
1114 return ret;1143 return ret;
1115 }1144 }
1116
1117 vhost_enqueue_msg(dev, &dev->pending_list, node);1145 vhost_enqueue_msg(dev, &dev->pending_list, node);
1118 }1146 }
1119 1147
@@ -1126,12 +1154,19 @@ static int vhost_iotlb_miss(struct vhost_virtqueue *vq, u64 iova, int access) · 6 unmodified lines
1126 struct vhost_dev *dev = vq->dev;1154 struct vhost_dev *dev = vq->dev;
1127 struct vhost_msg_node *node;1155 struct vhost_msg_node *node;
1128 struct vhost_iotlb_msg *msg;1156 struct vhost_iotlb_msg *msg;
1157 bool v2 = vhost_backend_has_feature(vq, VHOST_BACKEND_F_IOTLB_MSG_V2);
1129 1158
1130 node = vhost_new_msg(vq, VHOST_IOTLB_MISS);1159 node = vhost_new_msg(vq, v2 ? VHOST_IOTLB_MSG_V2 : VHOST_IOTLB_MSG);
1131 if (!node)1160 if (!node)
1132 return -ENOMEM;1161 return -ENOMEM;
1133 1162
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
1135 msg->type = VHOST_IOTLB_MISS;1170 msg->type = VHOST_IOTLB_MISS;
1136 msg->iova = iova;1171 msg->iova = iova;
1137 msg->perm = access;1172 msg->perm = access;
drivers/vhost/vhost.h+10−1
@@ -132,6 +132,7 @@ struct vhost_virtqueue { · 131 unmodified lines
132 struct vhost_umem *iotlb;132 struct vhost_umem *iotlb;
133 void *private_data;133 void *private_data;
134 u64 acked_features;134 u64 acked_features;
135 u64 acked_backend_features;
135 /* Log write descriptors */136 /* Log write descriptors */
136 void __user *log_base;137 void __user *log_base;
137 struct vhost_log *log;138 struct vhost_log *log;
@@ -147,7 +148,10 @@ struct vhost_virtqueue { · 9 unmodified lines
147};148};
148 149
149struct vhost_msg_node {150struct vhost_msg_node {
150 struct vhost_msg msg;151 union {
152 struct vhost_msg msg;
153 struct vhost_msg_v2 msg_v2;
154 };
151 struct vhost_virtqueue *vq;155 struct vhost_virtqueue *vq;
152 struct list_head node;156 struct list_head node;
153};157};
@@ -238,6 +242,11 @@ static inline bool vhost_has_feature(struct vhost_virtqueue *vq, int bit) · 84 unmodified lines
238 return vq->acked_features & (1ULL << bit);242 return vq->acked_features & (1ULL << bit);
239}243}
240 244
245static inline bool vhost_backend_has_feature(struct vhost_virtqueue *vq, int bit)
246{
247 return vq->acked_backend_features & (1ULL << bit);
248}
249
241#ifdef CONFIG_VHOST_CROSS_ENDIAN_LEGACY250#ifdef CONFIG_VHOST_CROSS_ENDIAN_LEGACY
242static inline bool vhost_is_little_endian(struct vhost_virtqueue *vq)251static inline bool vhost_is_little_endian(struct vhost_virtqueue *vq)
243{252{
include/uapi/linux/vhost.h+18−0
@@ -65,6 +65,7 @@ struct vhost_iotlb_msg { · 64 unmodified lines
65};65};
66 66
67#define VHOST_IOTLB_MSG 0x167#define VHOST_IOTLB_MSG 0x1
68#define VHOST_IOTLB_MSG_V2 0x2
68 69
69struct vhost_msg {70struct vhost_msg {
70 int type;71 int type;
@@ -74,6 +75,15 @@ struct vhost_msg { · 3 unmodified lines
74 };75 };
75};76};
76 77
78struct vhost_msg_v2 {
79 __u32 type;
80 __u32 reserved;
81 union {
82 struct vhost_iotlb_msg iotlb;
83 __u8 padding[64];
84 };
85};
86
77struct vhost_memory_region {87struct vhost_memory_region {
78 __u64 guest_phys_addr;88 __u64 guest_phys_addr;
79 __u64 memory_size; /* bytes */89 __u64 memory_size; /* bytes */
@@ -160,6 +170,14 @@ struct vhost_memory { · 80 unmodified lines
160#define VHOST_GET_VRING_BUSYLOOP_TIMEOUT _IOW(VHOST_VIRTIO, 0x24, \170#define VHOST_GET_VRING_BUSYLOOP_TIMEOUT _IOW(VHOST_VIRTIO, 0x24, \
161 struct vhost_vring_state)171 struct vhost_vring_state)
162 172
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
163/* VHOST_NET specific defines */181/* VHOST_NET specific defines */
164 182
165/* Attach virtio net ring to a raw socket, or tap device.183/* Attach virtio net ring to a raw socket, or tap device.