aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/vhost/net.c9
-rw-r--r--drivers/vhost/test.c320
-rw-r--r--drivers/vhost/test.h7
-rw-r--r--drivers/vhost/vhost.c44
-rw-r--r--drivers/vhost/vhost.h2
-rw-r--r--tools/virtio/Makefile12
-rw-r--r--tools/virtio/linux/device.h2
-rw-r--r--tools/virtio/linux/slab.h2
-rw-r--r--tools/virtio/linux/virtio.h223
-rw-r--r--tools/virtio/vhost_test/Makefile2
-rw-r--r--tools/virtio/vhost_test/vhost_test.c1
-rw-r--r--tools/virtio/virtio_test.c248
12 files changed, 842 insertions, 30 deletions
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index f442668a1e5..9b3ca103135 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -10,7 +10,6 @@
10#include <linux/eventfd.h> 10#include <linux/eventfd.h>
11#include <linux/vhost.h> 11#include <linux/vhost.h>
12#include <linux/virtio_net.h> 12#include <linux/virtio_net.h>
13#include <linux/mmu_context.h>
14#include <linux/miscdevice.h> 13#include <linux/miscdevice.h>
15#include <linux/module.h> 14#include <linux/module.h>
16#include <linux/mutex.h> 15#include <linux/mutex.h>
@@ -143,7 +142,6 @@ static void handle_tx(struct vhost_net *net)
143 return; 142 return;
144 } 143 }
145 144
146 use_mm(net->dev.mm);
147 mutex_lock(&vq->mutex); 145 mutex_lock(&vq->mutex);
148 vhost_disable_notify(vq); 146 vhost_disable_notify(vq);
149 147
@@ -208,7 +206,6 @@ static void handle_tx(struct vhost_net *net)
208 } 206 }
209 207
210 mutex_unlock(&vq->mutex); 208 mutex_unlock(&vq->mutex);
211 unuse_mm(net->dev.mm);
212} 209}
213 210
214static int peek_head_len(struct sock *sk) 211static int peek_head_len(struct sock *sk)
@@ -313,7 +310,6 @@ static void handle_rx_big(struct vhost_net *net)
313 if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue)) 310 if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue))
314 return; 311 return;
315 312
316 use_mm(net->dev.mm);
317 mutex_lock(&vq->mutex); 313 mutex_lock(&vq->mutex);
318 vhost_disable_notify(vq); 314 vhost_disable_notify(vq);
319 hdr_size = vq->vhost_hlen; 315 hdr_size = vq->vhost_hlen;
@@ -392,7 +388,6 @@ static void handle_rx_big(struct vhost_net *net)
392 } 388 }
393 389
394 mutex_unlock(&vq->mutex); 390 mutex_unlock(&vq->mutex);
395 unuse_mm(net->dev.mm);
396} 391}
397 392
398/* Expects to be always run from workqueue - which acts as 393/* Expects to be always run from workqueue - which acts as
@@ -424,7 +419,6 @@ static void handle_rx_mergeable(struct vhost_net *net)
424 if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue)) 419 if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue))
425 return; 420 return;
426 421
427 use_mm(net->dev.mm);
428 mutex_lock(&vq->mutex); 422 mutex_lock(&vq->mutex);
429 vhost_disable_notify(vq); 423 vhost_disable_notify(vq);
430 vhost_hlen = vq->vhost_hlen; 424 vhost_hlen = vq->vhost_hlen;
@@ -459,7 +453,7 @@ static void handle_rx_mergeable(struct vhost_net *net)
459 move_iovec_hdr(vq->iov, vq->hdr, vhost_hlen, in); 453 move_iovec_hdr(vq->iov, vq->hdr, vhost_hlen, in);
460 else 454 else
461 /* Copy the header for use in VIRTIO_NET_F_MRG_RXBUF: 455 /* Copy the header for use in VIRTIO_NET_F_MRG_RXBUF:
462 * needed because sendmsg can modify msg_iov. */ 456 * needed because recvmsg can modify msg_iov. */
463 copy_iovec_hdr(vq->iov, vq->hdr, sock_hlen, in); 457 copy_iovec_hdr(vq->iov, vq->hdr, sock_hlen, in);
464 msg.msg_iovlen = in; 458 msg.msg_iovlen = in;
465 err = sock->ops->recvmsg(NULL, sock, &msg, 459 err = sock->ops->recvmsg(NULL, sock, &msg,
@@ -501,7 +495,6 @@ static void handle_rx_mergeable(struct vhost_net *net)
501 } 495 }
502 496
503 mutex_unlock(&vq->mutex); 497 mutex_unlock(&vq->mutex);
504 unuse_mm(net->dev.mm);
505} 498}
506 499
507static void handle_rx(struct vhost_net *net) 500static void handle_rx(struct vhost_net *net)
diff --git a/drivers/vhost/test.c b/drivers/vhost/test.c
new file mode 100644
index 00000000000..099f30230d0
--- /dev/null
+++ b/drivers/vhost/test.c
@@ -0,0 +1,320 @@
1/* Copyright (C) 2009 Red Hat, Inc.
2 * Author: Michael S. Tsirkin <mst@redhat.com>
3 *
4 * This work is licensed under the terms of the GNU GPL, version 2.
5 *
6 * test virtio server in host kernel.
7 */
8
9#include <linux/compat.h>
10#include <linux/eventfd.h>
11#include <linux/vhost.h>
12#include <linux/miscdevice.h>
13#include <linux/module.h>
14#include <linux/mutex.h>
15#include <linux/workqueue.h>
16#include <linux/rcupdate.h>
17#include <linux/file.h>
18#include <linux/slab.h>
19
20#include "test.h"
21#include "vhost.c"
22
23/* Max number of bytes transferred before requeueing the job.
24 * Using this limit prevents one virtqueue from starving others. */
25#define VHOST_TEST_WEIGHT 0x80000
26
27enum {
28 VHOST_TEST_VQ = 0,
29 VHOST_TEST_VQ_MAX = 1,
30};
31
32struct vhost_test {
33 struct vhost_dev dev;
34 struct vhost_virtqueue vqs[VHOST_TEST_VQ_MAX];
35};
36
37/* Expects to be always run from workqueue - which acts as
38 * read-size critical section for our kind of RCU. */
39static void handle_vq(struct vhost_test *n)
40{
41 struct vhost_virtqueue *vq = &n->dev.vqs[VHOST_TEST_VQ];
42 unsigned out, in;
43 int head;
44 size_t len, total_len = 0;
45 void *private;
46
47 private = rcu_dereference_check(vq->private_data, 1);
48 if (!private)
49 return;
50
51 mutex_lock(&vq->mutex);
52 vhost_disable_notify(vq);
53
54 for (;;) {
55 head = vhost_get_vq_desc(&n->dev, vq, vq->iov,
56 ARRAY_SIZE(vq->iov),
57 &out, &in,
58 NULL, NULL);
59 /* On error, stop handling until the next kick. */
60 if (unlikely(head < 0))
61 break;
62 /* Nothing new? Wait for eventfd to tell us they refilled. */
63 if (head == vq->num) {
64 if (unlikely(vhost_enable_notify(vq))) {
65 vhost_disable_notify(vq);
66 continue;
67 }
68 break;
69 }
70 if (in) {
71 vq_err(vq, "Unexpected descriptor format for TX: "
72 "out %d, int %d\n", out, in);
73 break;
74 }
75 len = iov_length(vq->iov, out);
76 /* Sanity check */
77 if (!len) {
78 vq_err(vq, "Unexpected 0 len for TX\n");
79 break;
80 }
81 vhost_add_used_and_signal(&n->dev, vq, head, 0);
82 total_len += len;
83 if (unlikely(total_len >= VHOST_TEST_WEIGHT)) {
84 vhost_poll_queue(&vq->poll);
85 break;
86 }
87 }
88
89 mutex_unlock(&vq->mutex);
90}
91
92static void handle_vq_kick(struct vhost_work *work)
93{
94 struct vhost_virtqueue *vq = container_of(work, struct vhost_virtqueue,
95 poll.work);
96 struct vhost_test *n = container_of(vq->dev, struct vhost_test, dev);
97
98 handle_vq(n);
99}
100
101static int vhost_test_open(struct inode *inode, struct file *f)
102{
103 struct vhost_test *n = kmalloc(sizeof *n, GFP_KERNEL);
104 struct vhost_dev *dev;
105 int r;
106
107 if (!n)
108 return -ENOMEM;
109
110 dev = &n->dev;
111 n->vqs[VHOST_TEST_VQ].handle_kick = handle_vq_kick;
112 r = vhost_dev_init(dev, n->vqs, VHOST_TEST_VQ_MAX);
113 if (r < 0) {
114 kfree(n);
115 return r;
116 }
117
118 f->private_data = n;
119
120 return 0;
121}
122
123static void *vhost_test_stop_vq(struct vhost_test *n,
124 struct vhost_virtqueue *vq)
125{
126 void *private;
127
128 mutex_lock(&vq->mutex);
129 private = rcu_dereference_protected(vq->private_data,
130 lockdep_is_held(&vq->mutex));
131 rcu_assign_pointer(vq->private_data, NULL);
132 mutex_unlock(&vq->mutex);
133 return private;
134}
135
136static void vhost_test_stop(struct vhost_test *n, void **privatep)
137{
138 *privatep = vhost_test_stop_vq(n, n->vqs + VHOST_TEST_VQ);
139}
140
141static void vhost_test_flush_vq(struct vhost_test *n, int index)
142{
143 vhost_poll_flush(&n->dev.vqs[index].poll);
144}
145
146static void vhost_test_flush(struct vhost_test *n)
147{
148 vhost_test_flush_vq(n, VHOST_TEST_VQ);
149}
150
151static int vhost_test_release(struct inode *inode, struct file *f)
152{
153 struct vhost_test *n = f->private_data;
154 void *private;
155
156 vhost_test_stop(n, &private);
157 vhost_test_flush(n);
158 vhost_dev_cleanup(&n->dev);
159 /* We do an extra flush before freeing memory,
160 * since jobs can re-queue themselves. */
161 vhost_test_flush(n);
162 kfree(n);
163 return 0;
164}
165
166static long vhost_test_run(struct vhost_test *n, int test)
167{
168 void *priv, *oldpriv;
169 struct vhost_virtqueue *vq;
170 int r, index;
171
172 if (test < 0 || test > 1)
173 return -EINVAL;
174
175 mutex_lock(&n->dev.mutex);
176 r = vhost_dev_check_owner(&n->dev);
177 if (r)
178 goto err;
179
180 for (index = 0; index < n->dev.nvqs; ++index) {
181 /* Verify that ring has been setup correctly. */
182 if (!vhost_vq_access_ok(&n->vqs[index])) {
183 r = -EFAULT;
184 goto err;
185 }
186 }
187
188 for (index = 0; index < n->dev.nvqs; ++index) {
189 vq = n->vqs + index;
190 mutex_lock(&vq->mutex);
191 priv = test ? n : NULL;
192
193 /* start polling new socket */
194 oldpriv = rcu_dereference_protected(vq->private_data,
195 lockdep_is_held(&vq->mutex));
196 rcu_assign_pointer(vq->private_data, priv);
197
198 mutex_unlock(&vq->mutex);
199
200 if (oldpriv) {
201 vhost_test_flush_vq(n, index);
202 }
203 }
204
205 mutex_unlock(&n->dev.mutex);
206 return 0;
207
208err:
209 mutex_unlock(&n->dev.mutex);
210 return r;
211}
212
213static long vhost_test_reset_owner(struct vhost_test *n)
214{
215 void *priv = NULL;
216 long err;
217 mutex_lock(&n->dev.mutex);
218 err = vhost_dev_check_owner(&n->dev);
219 if (err)
220 goto done;
221 vhost_test_stop(n, &priv);
222 vhost_test_flush(n);
223 err = vhost_dev_reset_owner(&n->dev);
224done:
225 mutex_unlock(&n->dev.mutex);
226 return err;
227}
228
229static int vhost_test_set_features(struct vhost_test *n, u64 features)
230{
231 mutex_lock(&n->dev.mutex);
232 if ((features & (1 << VHOST_F_LOG_ALL)) &&
233 !vhost_log_access_ok(&n->dev)) {
234 mutex_unlock(&n->dev.mutex);
235 return -EFAULT;
236 }
237 n->dev.acked_features = features;
238 smp_wmb();
239 vhost_test_flush(n);
240 mutex_unlock(&n->dev.mutex);
241 return 0;
242}
243
244static long vhost_test_ioctl(struct file *f, unsigned int ioctl,
245 unsigned long arg)
246{
247 struct vhost_test *n = f->private_data;
248 void __user *argp = (void __user *)arg;
249 u64 __user *featurep = argp;
250 int test;
251 u64 features;
252 int r;
253 switch (ioctl) {
254 case VHOST_TEST_RUN:
255 if (copy_from_user(&test, argp, sizeof test))
256 return -EFAULT;
257 return vhost_test_run(n, test);
258 case VHOST_GET_FEATURES:
259 features = VHOST_FEATURES;
260 if (copy_to_user(featurep, &features, sizeof features))
261 return -EFAULT;
262 return 0;
263 case VHOST_SET_FEATURES:
264 if (copy_from_user(&features, featurep, sizeof features))
265 return -EFAULT;
266 if (features & ~VHOST_FEATURES)
267 return -EOPNOTSUPP;
268 return vhost_test_set_features(n, features);
269 case VHOST_RESET_OWNER:
270 return vhost_test_reset_owner(n);
271 default:
272 mutex_lock(&n->dev.mutex);
273 r = vhost_dev_ioctl(&n->dev, ioctl, arg);
274 vhost_test_flush(n);
275 mutex_unlock(&n->dev.mutex);
276 return r;
277 }
278}
279
280#ifdef CONFIG_COMPAT
281static long vhost_test_compat_ioctl(struct file *f, unsigned int ioctl,
282 unsigned long arg)
283{
284 return vhost_test_ioctl(f, ioctl, (unsigned long)compat_ptr(arg));
285}
286#endif
287
288static const struct file_operations vhost_test_fops = {
289 .owner = THIS_MODULE,
290 .release = vhost_test_release,
291 .unlocked_ioctl = vhost_test_ioctl,
292#ifdef CONFIG_COMPAT
293 .compat_ioctl = vhost_test_compat_ioctl,
294#endif
295 .open = vhost_test_open,
296 .llseek = noop_llseek,
297};
298
299static struct miscdevice vhost_test_misc = {
300 MISC_DYNAMIC_MINOR,
301 "vhost-test",
302 &vhost_test_fops,
303};
304
305static int vhost_test_init(void)
306{
307 return misc_register(&vhost_test_misc);
308}
309module_init(vhost_test_init);
310
311static void vhost_test_exit(void)
312{
313 misc_deregister(&vhost_test_misc);
314}
315module_exit(vhost_test_exit);
316
317MODULE_VERSION("0.0.1");
318MODULE_LICENSE("GPL v2");
319MODULE_AUTHOR("Michael S. Tsirkin");
320MODULE_DESCRIPTION("Host kernel side for virtio simulator");
diff --git a/drivers/vhost/test.h b/drivers/vhost/test.h
new file mode 100644
index 00000000000..1fef5df8215
--- /dev/null
+++ b/drivers/vhost/test.h
@@ -0,0 +1,7 @@
1#ifndef LINUX_VHOST_TEST_H
2#define LINUX_VHOST_TEST_H
3
4/* Start a given test on the virtio null device. 0 stops all tests. */
5#define VHOST_TEST_RUN _IOW(VHOST_VIRTIO, 0x31, int)
6
7#endif
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index 94701ff3a23..38244f59cdd 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -15,6 +15,7 @@
15#include <linux/vhost.h> 15#include <linux/vhost.h>
16#include <linux/virtio_net.h> 16#include <linux/virtio_net.h>
17#include <linux/mm.h> 17#include <linux/mm.h>
18#include <linux/mmu_context.h>
18#include <linux/miscdevice.h> 19#include <linux/miscdevice.h>
19#include <linux/mutex.h> 20#include <linux/mutex.h>
20#include <linux/rcupdate.h> 21#include <linux/rcupdate.h>
@@ -29,8 +30,6 @@
29#include <linux/if_packet.h> 30#include <linux/if_packet.h>
30#include <linux/if_arp.h> 31#include <linux/if_arp.h>
31 32
32#include <net/sock.h>
33
34#include "vhost.h" 33#include "vhost.h"
35 34
36enum { 35enum {
@@ -157,7 +156,6 @@ static void vhost_vq_reset(struct vhost_dev *dev,
157 vq->avail_idx = 0; 156 vq->avail_idx = 0;
158 vq->last_used_idx = 0; 157 vq->last_used_idx = 0;
159 vq->used_flags = 0; 158 vq->used_flags = 0;
160 vq->used_flags = 0;
161 vq->log_used = false; 159 vq->log_used = false;
162 vq->log_addr = -1ull; 160 vq->log_addr = -1ull;
163 vq->vhost_hlen = 0; 161 vq->vhost_hlen = 0;
@@ -178,6 +176,8 @@ static int vhost_worker(void *data)
178 struct vhost_work *work = NULL; 176 struct vhost_work *work = NULL;
179 unsigned uninitialized_var(seq); 177 unsigned uninitialized_var(seq);
180 178
179 use_mm(dev->mm);
180
181 for (;;) { 181 for (;;) {
182 /* mb paired w/ kthread_stop */ 182 /* mb paired w/ kthread_stop */
183 set_current_state(TASK_INTERRUPTIBLE); 183 set_current_state(TASK_INTERRUPTIBLE);
@@ -192,7 +192,7 @@ static int vhost_worker(void *data)
192 if (kthread_should_stop()) { 192 if (kthread_should_stop()) {
193 spin_unlock_irq(&dev->work_lock); 193 spin_unlock_irq(&dev->work_lock);
194 __set_current_state(TASK_RUNNING); 194 __set_current_state(TASK_RUNNING);
195 return 0; 195 break;
196 } 196 }
197 if (!list_empty(&dev->work_list)) { 197 if (!list_empty(&dev->work_list)) {
198 work = list_first_entry(&dev->work_list, 198 work = list_first_entry(&dev->work_list,
@@ -210,6 +210,8 @@ static int vhost_worker(void *data)
210 schedule(); 210 schedule();
211 211
212 } 212 }
213 unuse_mm(dev->mm);
214 return 0;
213} 215}
214 216
215/* Helper to allocate iovec buffers for all vqs. */ 217/* Helper to allocate iovec buffers for all vqs. */
@@ -402,15 +404,14 @@ void vhost_dev_cleanup(struct vhost_dev *dev)
402 kfree(rcu_dereference_protected(dev->memory, 404 kfree(rcu_dereference_protected(dev->memory,
403 lockdep_is_held(&dev->mutex))); 405 lockdep_is_held(&dev->mutex)));
404 RCU_INIT_POINTER(dev->memory, NULL); 406 RCU_INIT_POINTER(dev->memory, NULL);
405 if (dev->mm)
406 mmput(dev->mm);
407 dev->mm = NULL;
408
409 WARN_ON(!list_empty(&dev->work_list)); 407 WARN_ON(!list_empty(&dev->work_list));
410 if (dev->worker) { 408 if (dev->worker) {
411 kthread_stop(dev->worker); 409 kthread_stop(dev->worker);
412 dev->worker = NULL; 410 dev->worker = NULL;
413 } 411 }
412 if (dev->mm)
413 mmput(dev->mm);
414 dev->mm = NULL;
414} 415}
415 416
416static int log_access_ok(void __user *log_base, u64 addr, unsigned long sz) 417static int log_access_ok(void __user *log_base, u64 addr, unsigned long sz)
@@ -881,14 +882,15 @@ static int set_bit_to_user(int nr, void __user *addr)
881static int log_write(void __user *log_base, 882static int log_write(void __user *log_base,
882 u64 write_address, u64 write_length) 883 u64 write_address, u64 write_length)
883{ 884{
885 u64 write_page = write_address / VHOST_PAGE_SIZE;
884 int r; 886 int r;
885 if (!write_length) 887 if (!write_length)
886 return 0; 888 return 0;
887 write_address /= VHOST_PAGE_SIZE; 889 write_length += write_address % VHOST_PAGE_SIZE;
888 for (;;) { 890 for (;;) {
889 u64 base = (u64)(unsigned long)log_base; 891 u64 base = (u64)(unsigned long)log_base;
890 u64 log = base + write_address / 8; 892 u64 log = base + write_page / 8;
891 int bit = write_address % 8; 893 int bit = write_page % 8;
892 if ((u64)(unsigned long)log != log) 894 if ((u64)(unsigned long)log != log)
893 return -EFAULT; 895 return -EFAULT;
894 r = set_bit_to_user(bit, (void __user *)(unsigned long)log); 896 r = set_bit_to_user(bit, (void __user *)(unsigned long)log);
@@ -897,7 +899,7 @@ static int log_write(void __user *log_base,
897 if (write_length <= VHOST_PAGE_SIZE) 899 if (write_length <= VHOST_PAGE_SIZE)
898 break; 900 break;
899 write_length -= VHOST_PAGE_SIZE; 901 write_length -= VHOST_PAGE_SIZE;
900 write_address += VHOST_PAGE_SIZE; 902 write_page += 1;
901 } 903 }
902 return r; 904 return r;
903} 905}
@@ -1092,7 +1094,7 @@ int vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,
1092 1094
1093 /* Check it isn't doing very strange things with descriptor numbers. */ 1095 /* Check it isn't doing very strange things with descriptor numbers. */
1094 last_avail_idx = vq->last_avail_idx; 1096 last_avail_idx = vq->last_avail_idx;
1095 if (unlikely(get_user(vq->avail_idx, &vq->avail->idx))) { 1097 if (unlikely(__get_user(vq->avail_idx, &vq->avail->idx))) {
1096 vq_err(vq, "Failed to access avail idx at %p\n", 1098 vq_err(vq, "Failed to access avail idx at %p\n",
1097 &vq->avail->idx); 1099 &vq->avail->idx);
1098 return -EFAULT; 1100 return -EFAULT;
@@ -1113,8 +1115,8 @@ int vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,
1113 1115
1114 /* Grab the next descriptor number they're advertising, and increment 1116 /* Grab the next descriptor number they're advertising, and increment
1115 * the index we've seen. */ 1117 * the index we've seen. */
1116 if (unlikely(get_user(head, 1118 if (unlikely(__get_user(head,
1117 &vq->avail->ring[last_avail_idx % vq->num]))) { 1119 &vq->avail->ring[last_avail_idx % vq->num]))) {
1118 vq_err(vq, "Failed to read head: idx %d address %p\n", 1120 vq_err(vq, "Failed to read head: idx %d address %p\n",
1119 last_avail_idx, 1121 last_avail_idx,
1120 &vq->avail->ring[last_avail_idx % vq->num]); 1122 &vq->avail->ring[last_avail_idx % vq->num]);
@@ -1213,17 +1215,17 @@ int vhost_add_used(struct vhost_virtqueue *vq, unsigned int head, int len)
1213 /* The virtqueue contains a ring of used buffers. Get a pointer to the 1215 /* The virtqueue contains a ring of used buffers. Get a pointer to the
1214 * next entry in that used ring. */ 1216 * next entry in that used ring. */
1215 used = &vq->used->ring[vq->last_used_idx % vq->num]; 1217 used = &vq->used->ring[vq->last_used_idx % vq->num];
1216 if (put_user(head, &used->id)) { 1218 if (__put_user(head, &used->id)) {
1217 vq_err(vq, "Failed to write used id"); 1219 vq_err(vq, "Failed to write used id");
1218 return -EFAULT; 1220 return -EFAULT;
1219 } 1221 }
1220 if (put_user(len, &used->len)) { 1222 if (__put_user(len, &used->len)) {
1221 vq_err(vq, "Failed to write used len"); 1223 vq_err(vq, "Failed to write used len");
1222 return -EFAULT; 1224 return -EFAULT;
1223 } 1225 }
1224 /* Make sure buffer is written before we update index. */ 1226 /* Make sure buffer is written before we update index. */
1225 smp_wmb(); 1227 smp_wmb();
1226 if (put_user(vq->last_used_idx + 1, &vq->used->idx)) { 1228 if (__put_user(vq->last_used_idx + 1, &vq->used->idx)) {
1227 vq_err(vq, "Failed to increment used idx"); 1229 vq_err(vq, "Failed to increment used idx");
1228 return -EFAULT; 1230 return -EFAULT;
1229 } 1231 }
@@ -1255,7 +1257,7 @@ static int __vhost_add_used_n(struct vhost_virtqueue *vq,
1255 1257
1256 start = vq->last_used_idx % vq->num; 1258 start = vq->last_used_idx % vq->num;
1257 used = vq->used->ring + start; 1259 used = vq->used->ring + start;
1258 if (copy_to_user(used, heads, count * sizeof *used)) { 1260 if (__copy_to_user(used, heads, count * sizeof *used)) {
1259 vq_err(vq, "Failed to write used"); 1261 vq_err(vq, "Failed to write used");
1260 return -EFAULT; 1262 return -EFAULT;
1261 } 1263 }
@@ -1316,7 +1318,7 @@ void vhost_signal(struct vhost_dev *dev, struct vhost_virtqueue *vq)
1316 * interrupts. */ 1318 * interrupts. */
1317 smp_mb(); 1319 smp_mb();
1318 1320
1319 if (get_user(flags, &vq->avail->flags)) { 1321 if (__get_user(flags, &vq->avail->flags)) {
1320 vq_err(vq, "Failed to get flags"); 1322 vq_err(vq, "Failed to get flags");
1321 return; 1323 return;
1322 } 1324 }
@@ -1367,7 +1369,7 @@ bool vhost_enable_notify(struct vhost_virtqueue *vq)
1367 /* They could have slipped one in as we were doing that: make 1369 /* They could have slipped one in as we were doing that: make
1368 * sure it's written, then check again. */ 1370 * sure it's written, then check again. */
1369 smp_mb(); 1371 smp_mb();
1370 r = get_user(avail_idx, &vq->avail->idx); 1372 r = __get_user(avail_idx, &vq->avail->idx);
1371 if (r) { 1373 if (r) {
1372 vq_err(vq, "Failed to check avail idx at %p: %d\n", 1374 vq_err(vq, "Failed to check avail idx at %p: %d\n",
1373 &vq->avail->idx, r); 1375 &vq->avail->idx, r);
diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h
index 073d06ae091..2af44b7b1f3 100644
--- a/drivers/vhost/vhost.h
+++ b/drivers/vhost/vhost.h
@@ -102,7 +102,7 @@ struct vhost_virtqueue {
102 * flush the vhost_work instead of synchronize_rcu. Therefore readers do 102 * flush the vhost_work instead of synchronize_rcu. Therefore readers do
103 * not need to call rcu_read_lock/rcu_read_unlock: the beginning of 103 * not need to call rcu_read_lock/rcu_read_unlock: the beginning of
104 * vhost_work execution acts instead of rcu_read_lock() and the end of 104 * vhost_work execution acts instead of rcu_read_lock() and the end of
105 * vhost_work execution acts instead of rcu_read_lock(). 105 * vhost_work execution acts instead of rcu_read_unlock().
106 * Writers use virtqueue mutex. */ 106 * Writers use virtqueue mutex. */
107 void __rcu *private_data; 107 void __rcu *private_data;
108 /* Log write descriptors */ 108 /* Log write descriptors */
diff --git a/tools/virtio/Makefile b/tools/virtio/Makefile
new file mode 100644
index 00000000000..d1d442ed106
--- /dev/null
+++ b/tools/virtio/Makefile
@@ -0,0 +1,12 @@
1all: test mod
2test: virtio_test
3virtio_test: virtio_ring.o virtio_test.o
4CFLAGS += -g -O2 -Wall -I. -I ../../usr/include/ -Wno-pointer-sign -fno-strict-overflow -MMD
5vpath %.c ../../drivers/virtio
6mod:
7 ${MAKE} -C `pwd`/../.. M=`pwd`/vhost_test
8.PHONY: all test mod clean
9clean:
10 ${RM} *.o vhost_test/*.o vhost_test/.*.cmd \
11 vhost_test/Module.symvers vhost_test/modules.order *.d
12-include *.d
diff --git a/tools/virtio/linux/device.h b/tools/virtio/linux/device.h
new file mode 100644
index 00000000000..4ad7e1df0db
--- /dev/null
+++ b/tools/virtio/linux/device.h
@@ -0,0 +1,2 @@
1#ifndef LINUX_DEVICE_H
2#endif
diff --git a/tools/virtio/linux/slab.h b/tools/virtio/linux/slab.h
new file mode 100644
index 00000000000..81baeac8ae4
--- /dev/null
+++ b/tools/virtio/linux/slab.h
@@ -0,0 +1,2 @@
1#ifndef LINUX_SLAB_H
2#endif
diff --git a/tools/virtio/linux/virtio.h b/tools/virtio/linux/virtio.h
new file mode 100644
index 00000000000..669bcdd4580
--- /dev/null
+++ b/tools/virtio/linux/virtio.h
@@ -0,0 +1,223 @@
1#ifndef LINUX_VIRTIO_H
2#define LINUX_VIRTIO_H
3
4#include <stdbool.h>
5#include <stdlib.h>
6#include <stddef.h>
7#include <stdio.h>
8#include <string.h>
9#include <assert.h>
10
11#include <linux/types.h>
12#include <errno.h>
13
14typedef unsigned long long dma_addr_t;
15
16struct scatterlist {
17 unsigned long page_link;
18 unsigned int offset;
19 unsigned int length;
20 dma_addr_t dma_address;
21};
22
23struct page {
24 unsigned long long dummy;
25};
26
27#define BUG_ON(__BUG_ON_cond) assert(!(__BUG_ON_cond))
28
29/* Physical == Virtual */
30#define virt_to_phys(p) ((unsigned long)p)
31#define phys_to_virt(a) ((void *)(unsigned long)(a))
32/* Page address: Virtual / 4K */
33#define virt_to_page(p) ((struct page*)((virt_to_phys(p) / 4096) * \
34 sizeof(struct page)))
35#define offset_in_page(p) (((unsigned long)p) % 4096)
36#define sg_phys(sg) ((sg->page_link & ~0x3) / sizeof(struct page) * 4096 + \
37 sg->offset)
38static inline void sg_mark_end(struct scatterlist *sg)
39{
40 /*
41 * Set termination bit, clear potential chain bit
42 */
43 sg->page_link |= 0x02;
44 sg->page_link &= ~0x01;
45}
46static inline void sg_init_table(struct scatterlist *sgl, unsigned int nents)
47{
48 memset(sgl, 0, sizeof(*sgl) * nents);
49 sg_mark_end(&sgl[nents - 1]);
50}
51static inline void sg_assign_page(struct scatterlist *sg, struct page *page)
52{
53 unsigned long page_link = sg->page_link & 0x3;
54
55 /*
56 * In order for the low bit stealing approach to work, pages
57 * must be aligned at a 32-bit boundary as a minimum.
58 */
59 BUG_ON((unsigned long) page & 0x03);
60 sg->page_link = page_link | (unsigned long) page;
61}
62
63static inline void sg_set_page(struct scatterlist *sg, struct page *page,
64 unsigned int len, unsigned int offset)
65{
66 sg_assign_page(sg, page);
67 sg->offset = offset;
68 sg->length = len;
69}
70
71static inline void sg_set_buf(struct scatterlist *sg, const void *buf,
72 unsigned int buflen)
73{
74 sg_set_page(sg, virt_to_page(buf), buflen, offset_in_page(buf));
75}
76
77static inline void sg_init_one(struct scatterlist *sg, const void *buf, unsigned int buflen)
78{
79 sg_init_table(sg, 1);
80 sg_set_buf(sg, buf, buflen);
81}
82
83typedef __u16 u16;
84
85typedef enum {
86 GFP_KERNEL,
87 GFP_ATOMIC,
88} gfp_t;
89typedef enum {
90 IRQ_NONE,
91 IRQ_HANDLED
92} irqreturn_t;
93
94static inline void *kmalloc(size_t s, gfp_t gfp)
95{
96 return malloc(s);
97}
98
99static inline void kfree(void *p)
100{
101 free(p);
102}
103
104#define container_of(ptr, type, member) ({ \
105 const typeof( ((type *)0)->member ) *__mptr = (ptr); \
106 (type *)( (char *)__mptr - offsetof(type,member) );})
107
108#define uninitialized_var(x) x = x
109
110# ifndef likely
111# define likely(x) (__builtin_expect(!!(x), 1))
112# endif
113# ifndef unlikely
114# define unlikely(x) (__builtin_expect(!!(x), 0))
115# endif
116
117#define pr_err(format, ...) fprintf (stderr, format, ## __VA_ARGS__)
118#ifdef DEBUG
119#define pr_debug(format, ...) fprintf (stderr, format, ## __VA_ARGS__)
120#else
121#define pr_debug(format, ...) do {} while (0)
122#endif
123#define dev_err(dev, format, ...) fprintf (stderr, format, ## __VA_ARGS__)
124#define dev_warn(dev, format, ...) fprintf (stderr, format, ## __VA_ARGS__)
125
126/* TODO: empty stubs for now. Broken but enough for virtio_ring.c */
127#define list_add_tail(a, b) do {} while (0)
128#define list_del(a) do {} while (0)
129
130#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
131#define BITS_PER_BYTE 8
132#define BITS_PER_LONG (sizeof(long) * BITS_PER_BYTE)
133#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
134/* TODO: Not atomic as it should be:
135 * we don't use this for anything important. */
136static inline void clear_bit(int nr, volatile unsigned long *addr)
137{
138 unsigned long mask = BIT_MASK(nr);
139 unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
140
141 *p &= ~mask;
142}
143
144static inline int test_bit(int nr, const volatile unsigned long *addr)
145{
146 return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
147}
148
149/* The only feature we care to support */
150#define virtio_has_feature(dev, feature) \
151 test_bit((feature), (dev)->features)
152/* end of stubs */
153
154struct virtio_device {
155 void *dev;
156 unsigned long features[1];
157};
158
159struct virtqueue {
160 /* TODO: commented as list macros are empty stubs for now.
161 * Broken but enough for virtio_ring.c
162 * struct list_head list; */
163 void (*callback)(struct virtqueue *vq);
164 const char *name;
165 struct virtio_device *vdev;
166 void *priv;
167};
168
169#define EXPORT_SYMBOL_GPL(__EXPORT_SYMBOL_GPL_name) \
170 void __EXPORT_SYMBOL_GPL##__EXPORT_SYMBOL_GPL_name() { \
171}
172#define MODULE_LICENSE(__MODULE_LICENSE_value) \
173 const char *__MODULE_LICENSE_name = __MODULE_LICENSE_value
174
175#define CONFIG_SMP
176
177#if defined(__i386__) || defined(__x86_64__)
178#define barrier() asm volatile("" ::: "memory")
179#define mb() __sync_synchronize()
180
181#define smp_mb() mb()
182# define smp_rmb() barrier()
183# define smp_wmb() barrier()
184#else
185#error Please fill in barrier macros
186#endif
187
188/* Interfaces exported by virtio_ring. */
189int virtqueue_add_buf_gfp(struct virtqueue *vq,
190 struct scatterlist sg[],
191 unsigned int out_num,
192 unsigned int in_num,
193 void *data,
194 gfp_t gfp);
195
196static inline int virtqueue_add_buf(struct virtqueue *vq,
197 struct scatterlist sg[],
198 unsigned int out_num,
199 unsigned int in_num,
200 void *data)
201{
202 return virtqueue_add_buf_gfp(vq, sg, out_num, in_num, data, GFP_ATOMIC);
203}
204
205void virtqueue_kick(struct virtqueue *vq);
206
207void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len);
208
209void virtqueue_disable_cb(struct virtqueue *vq);
210
211bool virtqueue_enable_cb(struct virtqueue *vq);
212
213void *virtqueue_detach_unused_buf(struct virtqueue *vq);
214struct virtqueue *vring_new_virtqueue(unsigned int num,
215 unsigned int vring_align,
216 struct virtio_device *vdev,
217 void *pages,
218 void (*notify)(struct virtqueue *vq),
219 void (*callback)(struct virtqueue *vq),
220 const char *name);
221void vring_del_virtqueue(struct virtqueue *vq);
222
223#endif
diff --git a/tools/virtio/vhost_test/Makefile b/tools/virtio/vhost_test/Makefile
new file mode 100644
index 00000000000..a1d35b81b31
--- /dev/null
+++ b/tools/virtio/vhost_test/Makefile
@@ -0,0 +1,2 @@
1obj-m += vhost_test.o
2EXTRA_CFLAGS += -Idrivers/vhost
diff --git a/tools/virtio/vhost_test/vhost_test.c b/tools/virtio/vhost_test/vhost_test.c
new file mode 100644
index 00000000000..18735189e62
--- /dev/null
+++ b/tools/virtio/vhost_test/vhost_test.c
@@ -0,0 +1 @@
#include "test.c"
diff --git a/tools/virtio/virtio_test.c b/tools/virtio/virtio_test.c
new file mode 100644
index 00000000000..df0c6d2c386
--- /dev/null
+++ b/tools/virtio/virtio_test.c
@@ -0,0 +1,248 @@
1#define _GNU_SOURCE
2#include <getopt.h>
3#include <string.h>
4#include <poll.h>
5#include <sys/eventfd.h>
6#include <stdlib.h>
7#include <assert.h>
8#include <unistd.h>
9#include <sys/ioctl.h>
10#include <sys/stat.h>
11#include <sys/types.h>
12#include <fcntl.h>
13#include <linux/vhost.h>
14#include <linux/virtio.h>
15#include <linux/virtio_ring.h>
16#include "../../drivers/vhost/test.h"
17
18struct vq_info {
19 int kick;
20 int call;
21 int num;
22 int idx;
23 void *ring;
24 /* copy used for control */
25 struct vring vring;
26 struct virtqueue *vq;
27};
28
29struct vdev_info {
30 struct virtio_device vdev;
31 int control;
32 struct pollfd fds[1];
33 struct vq_info vqs[1];
34 int nvqs;
35 void *buf;
36 size_t buf_size;
37 struct vhost_memory *mem;
38};
39
40void vq_notify(struct virtqueue *vq)
41{
42 struct vq_info *info = vq->priv;
43 unsigned long long v = 1;
44 int r;
45 r = write(info->kick, &v, sizeof v);
46 assert(r == sizeof v);
47}
48
49void vq_callback(struct virtqueue *vq)
50{
51}
52
53
54void vhost_vq_setup(struct vdev_info *dev, struct vq_info *info)
55{
56 struct vhost_vring_state state = { .index = info->idx };
57 struct vhost_vring_file file = { .index = info->idx };
58 unsigned long long features = dev->vdev.features[0];
59 struct vhost_vring_addr addr = {
60 .index = info->idx,
61 .desc_user_addr = (uint64_t)(unsigned long)info->vring.desc,
62 .avail_user_addr = (uint64_t)(unsigned long)info->vring.avail,
63 .used_user_addr = (uint64_t)(unsigned long)info->vring.used,
64 };
65 int r;
66 r = ioctl(dev->control, VHOST_SET_FEATURES, &features);
67 assert(r >= 0);
68 state.num = info->vring.num;
69 r = ioctl(dev->control, VHOST_SET_VRING_NUM, &state);
70 assert(r >= 0);
71 state.num = 0;
72 r = ioctl(dev->control, VHOST_SET_VRING_BASE, &state);
73 assert(r >= 0);
74 r = ioctl(dev->control, VHOST_SET_VRING_ADDR, &addr);
75 assert(r >= 0);
76 file.fd = info->kick;
77 r = ioctl(dev->control, VHOST_SET_VRING_KICK, &file);
78 assert(r >= 0);
79 file.fd = info->call;
80 r = ioctl(dev->control, VHOST_SET_VRING_CALL, &file);
81 assert(r >= 0);
82}
83
84static void vq_info_add(struct vdev_info *dev, int num)
85{
86 struct vq_info *info = &dev->vqs[dev->nvqs];
87 int r;
88 info->idx = dev->nvqs;
89 info->kick = eventfd(0, EFD_NONBLOCK);
90 info->call = eventfd(0, EFD_NONBLOCK);
91 r = posix_memalign(&info->ring, 4096, vring_size(num, 4096));
92 assert(r >= 0);
93 memset(info->ring, 0, vring_size(num, 4096));
94 vring_init(&info->vring, num, info->ring, 4096);
95 info->vq = vring_new_virtqueue(info->vring.num, 4096, &dev->vdev, info->ring,
96 vq_notify, vq_callback, "test");
97 assert(info->vq);
98 info->vq->priv = info;
99 vhost_vq_setup(dev, info);
100 dev->fds[info->idx].fd = info->call;
101 dev->fds[info->idx].events = POLLIN;
102 dev->nvqs++;
103}
104
105static void vdev_info_init(struct vdev_info* dev, unsigned long long features)
106{
107 int r;
108 memset(dev, 0, sizeof *dev);
109 dev->vdev.features[0] = features;
110 dev->vdev.features[1] = features >> 32;
111 dev->buf_size = 1024;
112 dev->buf = malloc(dev->buf_size);
113 assert(dev->buf);
114 dev->control = open("/dev/vhost-test", O_RDWR);
115 assert(dev->control >= 0);
116 r = ioctl(dev->control, VHOST_SET_OWNER, NULL);
117 assert(r >= 0);
118 dev->mem = malloc(offsetof(struct vhost_memory, regions) +
119 sizeof dev->mem->regions[0]);
120 assert(dev->mem);
121 memset(dev->mem, 0, offsetof(struct vhost_memory, regions) +
122 sizeof dev->mem->regions[0]);
123 dev->mem->nregions = 1;
124 dev->mem->regions[0].guest_phys_addr = (long)dev->buf;
125 dev->mem->regions[0].userspace_addr = (long)dev->buf;
126 dev->mem->regions[0].memory_size = dev->buf_size;
127 r = ioctl(dev->control, VHOST_SET_MEM_TABLE, dev->mem);
128 assert(r >= 0);
129}
130
131/* TODO: this is pretty bad: we get a cache line bounce
132 * for the wait queue on poll and another one on read,
133 * plus the read which is there just to clear the
134 * current state. */
135static void wait_for_interrupt(struct vdev_info *dev)
136{
137 int i;
138 unsigned long long val;
139 poll(dev->fds, dev->nvqs, -1);
140 for (i = 0; i < dev->nvqs; ++i)
141 if (dev->fds[i].revents & POLLIN) {
142 read(dev->fds[i].fd, &val, sizeof val);
143 }
144}
145
146static void run_test(struct vdev_info *dev, struct vq_info *vq, int bufs)
147{
148 struct scatterlist sl;
149 long started = 0, completed = 0;
150 long completed_before;
151 int r, test = 1;
152 unsigned len;
153 long long spurious = 0;
154 r = ioctl(dev->control, VHOST_TEST_RUN, &test);
155 assert(r >= 0);
156 for (;;) {
157 virtqueue_disable_cb(vq->vq);
158 completed_before = completed;
159 do {
160 if (started < bufs) {
161 sg_init_one(&sl, dev->buf, dev->buf_size);
162 r = virtqueue_add_buf(vq->vq, &sl, 1, 0,
163 dev->buf + started);
164 if (likely(r >= 0)) {
165 ++started;
166 virtqueue_kick(vq->vq);
167 }
168 } else
169 r = -1;
170
171 /* Flush out completed bufs if any */
172 if (virtqueue_get_buf(vq->vq, &len)) {
173 ++completed;
174 r = 0;
175 }
176
177 } while (r >= 0);
178 if (completed == completed_before)
179 ++spurious;
180 assert(completed <= bufs);
181 assert(started <= bufs);
182 if (completed == bufs)
183 break;
184 if (virtqueue_enable_cb(vq->vq)) {
185 wait_for_interrupt(dev);
186 }
187 }
188 test = 0;
189 r = ioctl(dev->control, VHOST_TEST_RUN, &test);
190 assert(r >= 0);
191 fprintf(stderr, "spurious wakeus: 0x%llx\n", spurious);
192}
193
194const char optstring[] = "h";
195const struct option longopts[] = {
196 {
197 .name = "help",
198 .val = 'h',
199 },
200 {
201 .name = "indirect",
202 .val = 'I',
203 },
204 {
205 .name = "no-indirect",
206 .val = 'i',
207 },
208 {
209 }
210};
211
212static void help()
213{
214 fprintf(stderr, "Usage: virtio_test [--help] [--no-indirect]\n");
215}
216
217int main(int argc, char **argv)
218{
219 struct vdev_info dev;
220 unsigned long long features = 1ULL << VIRTIO_RING_F_INDIRECT_DESC;
221 int o;
222
223 for (;;) {
224 o = getopt_long(argc, argv, optstring, longopts, NULL);
225 switch (o) {
226 case -1:
227 goto done;
228 case '?':
229 help();
230 exit(2);
231 case 'h':
232 help();
233 goto done;
234 case 'i':
235 features &= ~(1ULL << VIRTIO_RING_F_INDIRECT_DESC);
236 break;
237 default:
238 assert(0);
239 break;
240 }
241 }
242
243done:
244 vdev_info_init(&dev, features);
245 vq_info_add(&dev, 256);
246 run_test(&dev, &dev.vqs[0], 0x100000);
247 return 0;
248}