Blame view

drivers/vhost/test.c 7.29 KB
71ccc212e   Michael S. Tsirkin   vhost test module
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  /* Copyright (C) 2009 Red Hat, Inc.
   * Author: Michael S. Tsirkin <mst@redhat.com>
   *
   * This work is licensed under the terms of the GNU GPL, version 2.
   *
   * test virtio server in host kernel.
   */
  
  #include <linux/compat.h>
  #include <linux/eventfd.h>
  #include <linux/vhost.h>
  #include <linux/miscdevice.h>
  #include <linux/module.h>
  #include <linux/mutex.h>
  #include <linux/workqueue.h>
71ccc212e   Michael S. Tsirkin   vhost test module
16
17
18
19
  #include <linux/file.h>
  #include <linux/slab.h>
  
  #include "test.h"
6ac1afbf6   Asias He   vhost: Make vhost...
20
  #include "vhost.h"
71ccc212e   Michael S. Tsirkin   vhost test module
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
  
  /* Max number of bytes transferred before requeueing the job.
   * Using this limit prevents one virtqueue from starving others. */
  #define VHOST_TEST_WEIGHT 0x80000
  
  enum {
  	VHOST_TEST_VQ = 0,
  	VHOST_TEST_VQ_MAX = 1,
  };
  
  struct vhost_test {
  	struct vhost_dev dev;
  	struct vhost_virtqueue vqs[VHOST_TEST_VQ_MAX];
  };
  
  /* Expects to be always run from workqueue - which acts as
   * read-size critical section for our kind of RCU. */
  static void handle_vq(struct vhost_test *n)
  {
09a34c840   Michael S. Tsirkin   vhost/test: updat...
40
  	struct vhost_virtqueue *vq = &n->vqs[VHOST_TEST_VQ];
71ccc212e   Michael S. Tsirkin   vhost test module
41
42
43
44
  	unsigned out, in;
  	int head;
  	size_t len, total_len = 0;
  	void *private;
09a34c840   Michael S. Tsirkin   vhost/test: updat...
45
46
47
48
  	mutex_lock(&vq->mutex);
  	private = vq->private_data;
  	if (!private) {
  		mutex_unlock(&vq->mutex);
71ccc212e   Michael S. Tsirkin   vhost test module
49
  		return;
09a34c840   Michael S. Tsirkin   vhost/test: updat...
50
  	}
71ccc212e   Michael S. Tsirkin   vhost test module
51

8ea8cf89e   Michael S. Tsirkin   vhost: support ev...
52
  	vhost_disable_notify(&n->dev, vq);
71ccc212e   Michael S. Tsirkin   vhost test module
53
54
  
  	for (;;) {
47283bef7   Michael S. Tsirkin   vhost: move memor...
55
  		head = vhost_get_vq_desc(vq, vq->iov,
71ccc212e   Michael S. Tsirkin   vhost test module
56
57
58
59
60
61
62
63
  					 ARRAY_SIZE(vq->iov),
  					 &out, &in,
  					 NULL, NULL);
  		/* On error, stop handling until the next kick. */
  		if (unlikely(head < 0))
  			break;
  		/* Nothing new?  Wait for eventfd to tell us they refilled. */
  		if (head == vq->num) {
8ea8cf89e   Michael S. Tsirkin   vhost: support ev...
64
65
  			if (unlikely(vhost_enable_notify(&n->dev, vq))) {
  				vhost_disable_notify(&n->dev, vq);
71ccc212e   Michael S. Tsirkin   vhost test module
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
  				continue;
  			}
  			break;
  		}
  		if (in) {
  			vq_err(vq, "Unexpected descriptor format for TX: "
  			       "out %d, int %d
  ", out, in);
  			break;
  		}
  		len = iov_length(vq->iov, out);
  		/* Sanity check */
  		if (!len) {
  			vq_err(vq, "Unexpected 0 len for TX
  ");
  			break;
  		}
  		vhost_add_used_and_signal(&n->dev, vq, head, 0);
  		total_len += len;
  		if (unlikely(total_len >= VHOST_TEST_WEIGHT)) {
  			vhost_poll_queue(&vq->poll);
  			break;
  		}
  	}
  
  	mutex_unlock(&vq->mutex);
  }
  
  static void handle_vq_kick(struct vhost_work *work)
  {
  	struct vhost_virtqueue *vq = container_of(work, struct vhost_virtqueue,
  						  poll.work);
  	struct vhost_test *n = container_of(vq->dev, struct vhost_test, dev);
  
  	handle_vq(n);
  }
  
  static int vhost_test_open(struct inode *inode, struct file *f)
  {
  	struct vhost_test *n = kmalloc(sizeof *n, GFP_KERNEL);
  	struct vhost_dev *dev;
09a34c840   Michael S. Tsirkin   vhost/test: updat...
107
  	struct vhost_virtqueue **vqs;
71ccc212e   Michael S. Tsirkin   vhost test module
108
109
110
  
  	if (!n)
  		return -ENOMEM;
6da2ec560   Kees Cook   treewide: kmalloc...
111
  	vqs = kmalloc_array(VHOST_TEST_VQ_MAX, sizeof(*vqs), GFP_KERNEL);
09a34c840   Michael S. Tsirkin   vhost/test: updat...
112
113
114
115
  	if (!vqs) {
  		kfree(n);
  		return -ENOMEM;
  	}
71ccc212e   Michael S. Tsirkin   vhost test module
116
117
  
  	dev = &n->dev;
09a34c840   Michael S. Tsirkin   vhost/test: updat...
118
  	vqs[VHOST_TEST_VQ] = &n->vqs[VHOST_TEST_VQ];
71ccc212e   Michael S. Tsirkin   vhost test module
119
  	n->vqs[VHOST_TEST_VQ].handle_kick = handle_vq_kick;
59566b6e8   Zhi Yong Wu   vhost: remove the...
120
  	vhost_dev_init(dev, vqs, VHOST_TEST_VQ_MAX);
71ccc212e   Michael S. Tsirkin   vhost test module
121
122
123
124
125
126
127
128
129
130
131
132
  
  	f->private_data = n;
  
  	return 0;
  }
  
  static void *vhost_test_stop_vq(struct vhost_test *n,
  				struct vhost_virtqueue *vq)
  {
  	void *private;
  
  	mutex_lock(&vq->mutex);
09a34c840   Michael S. Tsirkin   vhost/test: updat...
133
134
  	private = vq->private_data;
  	vq->private_data = NULL;
71ccc212e   Michael S. Tsirkin   vhost test module
135
136
137
138
139
140
141
142
143
144
145
  	mutex_unlock(&vq->mutex);
  	return private;
  }
  
  static void vhost_test_stop(struct vhost_test *n, void **privatep)
  {
  	*privatep = vhost_test_stop_vq(n, n->vqs + VHOST_TEST_VQ);
  }
  
  static void vhost_test_flush_vq(struct vhost_test *n, int index)
  {
09a34c840   Michael S. Tsirkin   vhost/test: updat...
146
  	vhost_poll_flush(&n->vqs[index].poll);
71ccc212e   Michael S. Tsirkin   vhost test module
147
148
149
150
151
152
153
154
155
156
157
158
159
160
  }
  
  static void vhost_test_flush(struct vhost_test *n)
  {
  	vhost_test_flush_vq(n, VHOST_TEST_VQ);
  }
  
  static int vhost_test_release(struct inode *inode, struct file *f)
  {
  	struct vhost_test *n = f->private_data;
  	void  *private;
  
  	vhost_test_stop(n, &private);
  	vhost_test_flush(n);
f6f93f75a   夷则(Caspar)   vhost: remove unu...
161
  	vhost_dev_cleanup(&n->dev);
71ccc212e   Michael S. Tsirkin   vhost test module
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
  	/* We do an extra flush before freeing memory,
  	 * since jobs can re-queue themselves. */
  	vhost_test_flush(n);
  	kfree(n);
  	return 0;
  }
  
  static long vhost_test_run(struct vhost_test *n, int test)
  {
  	void *priv, *oldpriv;
  	struct vhost_virtqueue *vq;
  	int r, index;
  
  	if (test < 0 || test > 1)
  		return -EINVAL;
  
  	mutex_lock(&n->dev.mutex);
  	r = vhost_dev_check_owner(&n->dev);
  	if (r)
  		goto err;
  
  	for (index = 0; index < n->dev.nvqs; ++index) {
  		/* Verify that ring has been setup correctly. */
  		if (!vhost_vq_access_ok(&n->vqs[index])) {
  			r = -EFAULT;
  			goto err;
  		}
  	}
  
  	for (index = 0; index < n->dev.nvqs; ++index) {
  		vq = n->vqs + index;
  		mutex_lock(&vq->mutex);
  		priv = test ? n : NULL;
  
  		/* start polling new socket */
22fa90c7f   Asias He   vhost: Remove cus...
197
198
  		oldpriv = vq->private_data;
  		vq->private_data = priv;
71ccc212e   Michael S. Tsirkin   vhost test module
199

80f7d0301   Greg Kurz   vhost: rename vho...
200
  		r = vhost_vq_init_access(&n->vqs[index]);
f59281daf   Jason Wang   vhost: init used ...
201

71ccc212e   Michael S. Tsirkin   vhost test module
202
  		mutex_unlock(&vq->mutex);
f59281daf   Jason Wang   vhost: init used ...
203
204
  		if (r)
  			goto err;
71ccc212e   Michael S. Tsirkin   vhost test module
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
  		if (oldpriv) {
  			vhost_test_flush_vq(n, index);
  		}
  	}
  
  	mutex_unlock(&n->dev.mutex);
  	return 0;
  
  err:
  	mutex_unlock(&n->dev.mutex);
  	return r;
  }
  
  static long vhost_test_reset_owner(struct vhost_test *n)
  {
  	void *priv = NULL;
  	long err;
446374d7c   Michael S. Tsirkin   vhost/test: fix a...
222
  	struct vhost_umem *umem;
150b9e51a   Michael S. Tsirkin   vhost: fix error ...
223

71ccc212e   Michael S. Tsirkin   vhost test module
224
225
226
227
  	mutex_lock(&n->dev.mutex);
  	err = vhost_dev_check_owner(&n->dev);
  	if (err)
  		goto done;
446374d7c   Michael S. Tsirkin   vhost/test: fix a...
228
229
  	umem = vhost_dev_reset_owner_prepare();
  	if (!umem) {
150b9e51a   Michael S. Tsirkin   vhost: fix error ...
230
231
232
  		err = -ENOMEM;
  		goto done;
  	}
71ccc212e   Michael S. Tsirkin   vhost test module
233
234
  	vhost_test_stop(n, &priv);
  	vhost_test_flush(n);
446374d7c   Michael S. Tsirkin   vhost/test: fix a...
235
  	vhost_dev_reset_owner(&n->dev, umem);
71ccc212e   Michael S. Tsirkin   vhost test module
236
237
238
239
240
241
242
  done:
  	mutex_unlock(&n->dev.mutex);
  	return err;
  }
  
  static int vhost_test_set_features(struct vhost_test *n, u64 features)
  {
ea16c5143   Michael S. Tsirkin   vhost: move acked...
243
  	struct vhost_virtqueue *vq;
71ccc212e   Michael S. Tsirkin   vhost test module
244
245
246
247
248
249
  	mutex_lock(&n->dev.mutex);
  	if ((features & (1 << VHOST_F_LOG_ALL)) &&
  	    !vhost_log_access_ok(&n->dev)) {
  		mutex_unlock(&n->dev.mutex);
  		return -EFAULT;
  	}
ea16c5143   Michael S. Tsirkin   vhost: move acked...
250
251
252
253
  	vq = &n->vqs[VHOST_TEST_VQ];
  	mutex_lock(&vq->mutex);
  	vq->acked_features = features;
  	mutex_unlock(&vq->mutex);
71ccc212e   Michael S. Tsirkin   vhost test module
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
  	mutex_unlock(&n->dev.mutex);
  	return 0;
  }
  
  static long vhost_test_ioctl(struct file *f, unsigned int ioctl,
  			     unsigned long arg)
  {
  	struct vhost_test *n = f->private_data;
  	void __user *argp = (void __user *)arg;
  	u64 __user *featurep = argp;
  	int test;
  	u64 features;
  	int r;
  	switch (ioctl) {
  	case VHOST_TEST_RUN:
  		if (copy_from_user(&test, argp, sizeof test))
  			return -EFAULT;
  		return vhost_test_run(n, test);
  	case VHOST_GET_FEATURES:
09a34c840   Michael S. Tsirkin   vhost/test: updat...
273
  		features = VHOST_FEATURES;
71ccc212e   Michael S. Tsirkin   vhost test module
274
275
276
277
  		if (copy_to_user(featurep, &features, sizeof features))
  			return -EFAULT;
  		return 0;
  	case VHOST_SET_FEATURES:
4e9fa50c6   Michael S. Tsirkin   vhost: move featu...
278
279
  		printk(KERN_ERR "1
  ");
71ccc212e   Michael S. Tsirkin   vhost test module
280
281
  		if (copy_from_user(&features, featurep, sizeof features))
  			return -EFAULT;
4e9fa50c6   Michael S. Tsirkin   vhost: move featu...
282
283
  		printk(KERN_ERR "2
  ");
09a34c840   Michael S. Tsirkin   vhost/test: updat...
284
  		if (features & ~VHOST_FEATURES)
71ccc212e   Michael S. Tsirkin   vhost test module
285
  			return -EOPNOTSUPP;
4e9fa50c6   Michael S. Tsirkin   vhost: move featu...
286
287
  		printk(KERN_ERR "3
  ");
71ccc212e   Michael S. Tsirkin   vhost test module
288
289
290
291
292
  		return vhost_test_set_features(n, features);
  	case VHOST_RESET_OWNER:
  		return vhost_test_reset_owner(n);
  	default:
  		mutex_lock(&n->dev.mutex);
73640c991   Michael S. Tsirkin   tools/virtio: fix...
293
294
295
  		r = vhost_dev_ioctl(&n->dev, ioctl, argp);
                  if (r == -ENOIOCTLCMD)
                          r = vhost_vring_ioctl(&n->dev, ioctl, argp);
71ccc212e   Michael S. Tsirkin   vhost test module
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
  		vhost_test_flush(n);
  		mutex_unlock(&n->dev.mutex);
  		return r;
  	}
  }
  
  #ifdef CONFIG_COMPAT
  static long vhost_test_compat_ioctl(struct file *f, unsigned int ioctl,
  				   unsigned long arg)
  {
  	return vhost_test_ioctl(f, ioctl, (unsigned long)compat_ptr(arg));
  }
  #endif
  
  static const struct file_operations vhost_test_fops = {
  	.owner          = THIS_MODULE,
  	.release        = vhost_test_release,
  	.unlocked_ioctl = vhost_test_ioctl,
  #ifdef CONFIG_COMPAT
  	.compat_ioctl   = vhost_test_compat_ioctl,
  #endif
  	.open           = vhost_test_open,
  	.llseek		= noop_llseek,
  };
  
  static struct miscdevice vhost_test_misc = {
  	MISC_DYNAMIC_MINOR,
  	"vhost-test",
  	&vhost_test_fops,
  };
ca75d601b   PrasannaKumar Muralidharan   miscdevice: Add h...
326
  module_misc_device(vhost_test_misc);
71ccc212e   Michael S. Tsirkin   vhost test module
327
328
329
330
331
  
  MODULE_VERSION("0.0.1");
  MODULE_LICENSE("GPL v2");
  MODULE_AUTHOR("Michael S. Tsirkin");
  MODULE_DESCRIPTION("Host kernel side for virtio simulator");