1 /* Copyright (C) 2009 Red Hat, Inc.
2 * Author: Michael S. Tsirkin <mst@redhat.com>
4 * This work is licensed under the terms of the GNU GPL, version 2.
6 * test virtio server in host kernel.
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>
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
29 VHOST_TEST_VQ_MAX
= 1,
34 struct vhost_virtqueue vqs
[VHOST_TEST_VQ_MAX
];
37 /* Expects to be always run from workqueue - which acts as
38 * read-size critical section for our kind of RCU. */
39 static void handle_vq(struct vhost_test
*n
)
41 struct vhost_virtqueue
*vq
= &n
->dev
.vqs
[VHOST_TEST_VQ
];
44 size_t len
, total_len
= 0;
47 private = rcu_dereference_check(vq
->private_data
, 1);
51 mutex_lock(&vq
->mutex
);
52 vhost_disable_notify(&n
->dev
, vq
);
55 head
= vhost_get_vq_desc(&n
->dev
, vq
, vq
->iov
,
59 /* On error, stop handling until the next kick. */
60 if (unlikely(head
< 0))
62 /* Nothing new? Wait for eventfd to tell us they refilled. */
63 if (head
== vq
->num
) {
64 if (unlikely(vhost_enable_notify(&n
->dev
, vq
))) {
65 vhost_disable_notify(&n
->dev
, vq
);
71 vq_err(vq
, "Unexpected descriptor format for TX: "
72 "out %d, int %d\n", out
, in
);
75 len
= iov_length(vq
->iov
, out
);
78 vq_err(vq
, "Unexpected 0 len for TX\n");
81 vhost_add_used_and_signal(&n
->dev
, vq
, head
, 0);
83 if (unlikely(total_len
>= VHOST_TEST_WEIGHT
)) {
84 vhost_poll_queue(&vq
->poll
);
89 mutex_unlock(&vq
->mutex
);
92 static void handle_vq_kick(struct vhost_work
*work
)
94 struct vhost_virtqueue
*vq
= container_of(work
, struct vhost_virtqueue
,
96 struct vhost_test
*n
= container_of(vq
->dev
, struct vhost_test
, dev
);
101 static int vhost_test_open(struct inode
*inode
, struct file
*f
)
103 struct vhost_test
*n
= kmalloc(sizeof *n
, GFP_KERNEL
);
104 struct vhost_dev
*dev
;
111 n
->vqs
[VHOST_TEST_VQ
].handle_kick
= handle_vq_kick
;
112 r
= vhost_dev_init(dev
, n
->vqs
, VHOST_TEST_VQ_MAX
);
123 static void *vhost_test_stop_vq(struct vhost_test
*n
,
124 struct vhost_virtqueue
*vq
)
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
);
136 static void vhost_test_stop(struct vhost_test
*n
, void **privatep
)
138 *privatep
= vhost_test_stop_vq(n
, n
->vqs
+ VHOST_TEST_VQ
);
141 static void vhost_test_flush_vq(struct vhost_test
*n
, int index
)
143 vhost_poll_flush(&n
->dev
.vqs
[index
].poll
);
146 static void vhost_test_flush(struct vhost_test
*n
)
148 vhost_test_flush_vq(n
, VHOST_TEST_VQ
);
151 static int vhost_test_release(struct inode
*inode
, struct file
*f
)
153 struct vhost_test
*n
= f
->private_data
;
156 vhost_test_stop(n
, &private);
158 vhost_dev_cleanup(&n
->dev
, false);
159 /* We do an extra flush before freeing memory,
160 * since jobs can re-queue themselves. */
166 static long vhost_test_run(struct vhost_test
*n
, int test
)
168 void *priv
, *oldpriv
;
169 struct vhost_virtqueue
*vq
;
172 if (test
< 0 || test
> 1)
175 mutex_lock(&n
->dev
.mutex
);
176 r
= vhost_dev_check_owner(&n
->dev
);
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
])) {
188 for (index
= 0; index
< n
->dev
.nvqs
; ++index
) {
190 mutex_lock(&vq
->mutex
);
191 priv
= test
? n
: NULL
;
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
);
198 r
= vhost_init_used(&n
->vqs
[index
]);
200 mutex_unlock(&vq
->mutex
);
206 vhost_test_flush_vq(n
, index
);
210 mutex_unlock(&n
->dev
.mutex
);
214 mutex_unlock(&n
->dev
.mutex
);
218 static long vhost_test_reset_owner(struct vhost_test
*n
)
222 mutex_lock(&n
->dev
.mutex
);
223 err
= vhost_dev_check_owner(&n
->dev
);
226 vhost_test_stop(n
, &priv
);
228 err
= vhost_dev_reset_owner(&n
->dev
);
230 mutex_unlock(&n
->dev
.mutex
);
234 static int vhost_test_set_features(struct vhost_test
*n
, u64 features
)
236 mutex_lock(&n
->dev
.mutex
);
237 if ((features
& (1 << VHOST_F_LOG_ALL
)) &&
238 !vhost_log_access_ok(&n
->dev
)) {
239 mutex_unlock(&n
->dev
.mutex
);
242 n
->dev
.acked_features
= features
;
245 mutex_unlock(&n
->dev
.mutex
);
249 static long vhost_test_ioctl(struct file
*f
, unsigned int ioctl
,
252 struct vhost_test
*n
= f
->private_data
;
253 void __user
*argp
= (void __user
*)arg
;
254 u64 __user
*featurep
= argp
;
260 if (copy_from_user(&test
, argp
, sizeof test
))
262 return vhost_test_run(n
, test
);
263 case VHOST_GET_FEATURES
:
264 features
= VHOST_NET_FEATURES
;
265 if (copy_to_user(featurep
, &features
, sizeof features
))
268 case VHOST_SET_FEATURES
:
269 if (copy_from_user(&features
, featurep
, sizeof features
))
271 if (features
& ~VHOST_NET_FEATURES
)
273 return vhost_test_set_features(n
, features
);
274 case VHOST_RESET_OWNER
:
275 return vhost_test_reset_owner(n
);
277 mutex_lock(&n
->dev
.mutex
);
278 r
= vhost_dev_ioctl(&n
->dev
, ioctl
, arg
);
280 mutex_unlock(&n
->dev
.mutex
);
286 static long vhost_test_compat_ioctl(struct file
*f
, unsigned int ioctl
,
289 return vhost_test_ioctl(f
, ioctl
, (unsigned long)compat_ptr(arg
));
293 static const struct file_operations vhost_test_fops
= {
294 .owner
= THIS_MODULE
,
295 .release
= vhost_test_release
,
296 .unlocked_ioctl
= vhost_test_ioctl
,
298 .compat_ioctl
= vhost_test_compat_ioctl
,
300 .open
= vhost_test_open
,
301 .llseek
= noop_llseek
,
304 static struct miscdevice vhost_test_misc
= {
310 static int vhost_test_init(void)
312 return misc_register(&vhost_test_misc
);
314 module_init(vhost_test_init
);
316 static void vhost_test_exit(void)
318 misc_deregister(&vhost_test_misc
);
320 module_exit(vhost_test_exit
);
322 MODULE_VERSION("0.0.1");
323 MODULE_LICENSE("GPL v2");
324 MODULE_AUTHOR("Michael S. Tsirkin");
325 MODULE_DESCRIPTION("Host kernel side for virtio simulator");