Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2017 Intel Corporation.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "spdk/stdinc.h"
7 : :
8 : : #include "spdk/bdev.h"
9 : : #include "spdk/endian.h"
10 : : #include "spdk/env.h"
11 : : #include "spdk/thread.h"
12 : : #include "spdk/string.h"
13 : : #include "spdk/util.h"
14 : : #include "spdk/json.h"
15 : :
16 : : #include "spdk_internal/assert.h"
17 : : #include "spdk/bdev_module.h"
18 : : #include "spdk/log.h"
19 : : #include "spdk_internal/virtio.h"
20 : : #include "spdk_internal/vhost_user.h"
21 : :
22 : : #include <linux/virtio_blk.h>
23 : : #include <linux/virtio_ids.h>
24 : :
25 : : #include "bdev_virtio.h"
26 : :
27 : : struct virtio_blk_dev {
28 : : struct virtio_dev vdev;
29 : : struct spdk_bdev bdev;
30 : : bool readonly;
31 : : bool unmap;
32 : : };
33 : :
34 : : struct virtio_blk_io_ctx {
35 : : struct iovec iov_req;
36 : : struct iovec iov_resp;
37 : : struct iovec iov_unmap;
38 : : struct virtio_blk_outhdr req;
39 : : struct virtio_blk_discard_write_zeroes unmap;
40 : : uint8_t resp;
41 : : };
42 : :
43 : : struct bdev_virtio_blk_io_channel {
44 : : struct virtio_dev *vdev;
45 : :
46 : : /** Virtqueue exclusively assigned to this channel. */
47 : : struct virtqueue *vq;
48 : :
49 : : /** Virtio response poller. */
50 : : struct spdk_poller *poller;
51 : : };
52 : :
53 : : /* Features desired/implemented by this driver. */
54 : : #define VIRTIO_BLK_DEV_SUPPORTED_FEATURES \
55 : : (1ULL << VIRTIO_BLK_F_SIZE_MAX | \
56 : : 1ULL << VIRTIO_BLK_F_SEG_MAX | \
57 : : 1ULL << VIRTIO_BLK_F_BLK_SIZE | \
58 : : 1ULL << VIRTIO_BLK_F_TOPOLOGY | \
59 : : 1ULL << VIRTIO_BLK_F_MQ | \
60 : : 1ULL << VIRTIO_BLK_F_RO | \
61 : : 1ULL << VIRTIO_BLK_F_DISCARD | \
62 : : 1ULL << VIRTIO_RING_F_EVENT_IDX)
63 : :
64 : : /* 10 sec for max poll period */
65 : : #define VIRTIO_BLK_HOTPLUG_POLL_PERIOD_MAX 10000000ULL
66 : : /* Default poll period is 100ms */
67 : : #define VIRTIO_BLK_HOTPLUG_POLL_PERIOD_DEFAULT 100000ULL
68 : :
69 : : static struct spdk_poller *g_blk_hotplug_poller = NULL;
70 : : static int g_blk_hotplug_fd = -1;
71 : :
72 : : static int bdev_virtio_initialize(void);
73 : : static int bdev_virtio_blk_get_ctx_size(void);
74 : :
75 : : static struct spdk_bdev_module virtio_blk_if = {
76 : : .name = "virtio_blk",
77 : : .module_init = bdev_virtio_initialize,
78 : : .get_ctx_size = bdev_virtio_blk_get_ctx_size,
79 : : };
80 : :
81 : 2317 : SPDK_BDEV_MODULE_REGISTER(virtio_blk, &virtio_blk_if)
82 : :
83 : : static int bdev_virtio_blk_ch_create_cb(void *io_device, void *ctx_buf);
84 : : static void bdev_virtio_blk_ch_destroy_cb(void *io_device, void *ctx_buf);
85 : :
86 : : static struct virtio_blk_io_ctx *
87 : 3076867 : bdev_virtio_blk_init_io_vreq(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
88 : : {
89 : : struct virtio_blk_outhdr *req;
90 : : uint8_t *resp;
91 : : struct virtio_blk_discard_write_zeroes *desc;
92 : :
93 : 3076867 : struct virtio_blk_io_ctx *io_ctx = (struct virtio_blk_io_ctx *)bdev_io->driver_ctx;
94 : :
95 : 3076867 : req = &io_ctx->req;
96 : 3076867 : resp = &io_ctx->resp;
97 : 3076867 : desc = &io_ctx->unmap;
98 : :
99 : 3076867 : io_ctx->iov_req.iov_base = req;
100 : 3076867 : io_ctx->iov_req.iov_len = sizeof(*req);
101 : :
102 : 3076867 : io_ctx->iov_resp.iov_base = resp;
103 : 3076867 : io_ctx->iov_resp.iov_len = sizeof(*resp);
104 : :
105 : 3076867 : io_ctx->iov_unmap.iov_base = desc;
106 : 3076867 : io_ctx->iov_unmap.iov_len = sizeof(*desc);
107 : :
108 [ - + ]: 3076867 : memset(req, 0, sizeof(*req));
109 : 3076867 : return io_ctx;
110 : : }
111 : :
112 : : static void
113 : 3076867 : bdev_virtio_blk_send_io(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
114 : : {
115 : 3076867 : struct bdev_virtio_blk_io_channel *virtio_channel = spdk_io_channel_get_ctx(ch);
116 : 3076867 : struct virtqueue *vq = virtio_channel->vq;
117 : 3076867 : struct virtio_blk_io_ctx *io_ctx = (struct virtio_blk_io_ctx *)bdev_io->driver_ctx;
118 : : int rc;
119 : :
120 : 3076867 : rc = virtqueue_req_start(vq, bdev_io, bdev_io->u.bdev.iovcnt + 2);
121 [ + + ]: 3076867 : if (rc == -ENOMEM) {
122 : 229252 : spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_NOMEM);
123 : 229252 : return;
124 [ - + ]: 2847615 : } else if (rc != 0) {
125 : 0 : spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
126 : 0 : return;
127 : : }
128 : :
129 : 2847615 : virtqueue_req_add_iovs(vq, &io_ctx->iov_req, 1, SPDK_VIRTIO_DESC_RO);
130 [ - + ]: 2847615 : if (bdev_io->type == SPDK_BDEV_IO_TYPE_UNMAP) {
131 : 0 : virtqueue_req_add_iovs(vq, &io_ctx->iov_unmap, 1, SPDK_VIRTIO_DESC_RO);
132 : : } else {
133 : 2847615 : virtqueue_req_add_iovs(vq, bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt,
134 [ + + ]: 2847615 : bdev_io->type == SPDK_BDEV_IO_TYPE_READ ?
135 : : SPDK_VIRTIO_DESC_WR : SPDK_VIRTIO_DESC_RO);
136 : : }
137 : 2847615 : virtqueue_req_add_iovs(vq, &io_ctx->iov_resp, 1, SPDK_VIRTIO_DESC_WR);
138 : :
139 : 2847615 : virtqueue_req_flush(vq);
140 : : }
141 : :
142 : : static void
143 : 3076867 : bdev_virtio_command(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
144 : : {
145 : 3076867 : struct virtio_blk_io_ctx *io_ctx = bdev_virtio_blk_init_io_vreq(ch, bdev_io);
146 : 3076867 : struct virtio_blk_outhdr *req = &io_ctx->req;
147 : 3076867 : struct virtio_blk_discard_write_zeroes *desc = &io_ctx->unmap;
148 : :
149 [ + + ]: 3076867 : if (bdev_io->type == SPDK_BDEV_IO_TYPE_READ) {
150 : 1703962 : req->type = VIRTIO_BLK_T_IN;
151 [ + - ]: 1372905 : } else if (bdev_io->type == SPDK_BDEV_IO_TYPE_WRITE) {
152 : 1372905 : req->type = VIRTIO_BLK_T_OUT;
153 [ # # ]: 0 : } else if (bdev_io->type == SPDK_BDEV_IO_TYPE_UNMAP) {
154 : 0 : req->type = VIRTIO_BLK_T_DISCARD;
155 : 0 : desc->sector = bdev_io->u.bdev.offset_blocks *
156 : 0 : spdk_bdev_get_block_size(bdev_io->bdev) / 512;
157 : 0 : desc->num_sectors = bdev_io->u.bdev.num_blocks *
158 : 0 : spdk_bdev_get_block_size(bdev_io->bdev) / 512;
159 : 0 : desc->flags = 0;
160 : : }
161 : :
162 : 6153734 : req->sector = bdev_io->u.bdev.offset_blocks *
163 : 3076867 : spdk_bdev_get_block_size(bdev_io->bdev) / 512;
164 : :
165 : 3076867 : bdev_virtio_blk_send_io(ch, bdev_io);
166 : 3076867 : }
167 : :
168 : : static void
169 : 1703962 : bdev_virtio_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io,
170 : : bool success)
171 : : {
172 [ - + ]: 1703962 : if (!success) {
173 : 0 : spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
174 : 0 : return;
175 : : }
176 : :
177 : 1703962 : bdev_virtio_command(ch, bdev_io);
178 : : }
179 : :
180 : : static int
181 : 3076867 : _bdev_virtio_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
182 : : {
183 : 3076867 : struct virtio_blk_dev *bvdev = bdev_io->bdev->ctxt;
184 : :
185 [ + + - - : 3076867 : switch (bdev_io->type) {
- ]
186 : 1703962 : case SPDK_BDEV_IO_TYPE_READ:
187 : 1703962 : spdk_bdev_io_get_buf(bdev_io, bdev_virtio_get_buf_cb,
188 : 1703962 : bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen);
189 : 1703962 : return 0;
190 : 1372905 : case SPDK_BDEV_IO_TYPE_WRITE:
191 [ - + - + ]: 1372905 : if (bvdev->readonly) {
192 : 0 : spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
193 : : } else {
194 : 1372905 : bdev_virtio_command(ch, bdev_io);
195 : : }
196 : 1372905 : return 0;
197 : 0 : case SPDK_BDEV_IO_TYPE_RESET:
198 : 0 : spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS);
199 : 0 : return 0;
200 : 0 : case SPDK_BDEV_IO_TYPE_UNMAP:
201 [ # # # # ]: 0 : if (bvdev->unmap) {
202 : 0 : bdev_virtio_command(ch, bdev_io);
203 : : } else {
204 : 0 : spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
205 : : }
206 : 0 : return 0;
207 : 0 : case SPDK_BDEV_IO_TYPE_FLUSH:
208 : : default:
209 : 0 : return -1;
210 : : }
211 : :
212 : : SPDK_UNREACHABLE();
213 : : }
214 : :
215 : : static void
216 : 3076867 : bdev_virtio_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
217 : : {
218 [ - + ]: 3076867 : if (_bdev_virtio_submit_request(ch, bdev_io) < 0) {
219 : 0 : spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
220 : : }
221 : 3076867 : }
222 : :
223 : : static bool
224 : 1149 : bdev_virtio_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type)
225 : : {
226 : 1149 : struct virtio_blk_dev *bvdev = ctx;
227 : :
228 [ + + + + ]: 1149 : switch (io_type) {
229 : 106 : case SPDK_BDEV_IO_TYPE_READ:
230 : : case SPDK_BDEV_IO_TYPE_RESET:
231 : 106 : return true;
232 : 106 : case SPDK_BDEV_IO_TYPE_WRITE:
233 [ - + ]: 106 : return !bvdev->readonly;
234 : 53 : case SPDK_BDEV_IO_TYPE_UNMAP:
235 [ - + ]: 53 : return bvdev->unmap;
236 : 884 : case SPDK_BDEV_IO_TYPE_FLUSH:
237 : : default:
238 : 884 : return false;
239 : : }
240 : : }
241 : :
242 : : static struct spdk_io_channel *
243 : 17 : bdev_virtio_get_io_channel(void *ctx)
244 : : {
245 : 17 : struct virtio_blk_dev *bvdev = ctx;
246 : :
247 : 17 : return spdk_get_io_channel(bvdev);
248 : : }
249 : :
250 : : static void
251 : 12 : virtio_blk_dev_unregister_cb(void *io_device)
252 : : {
253 : 12 : struct virtio_blk_dev *bvdev = io_device;
254 : 12 : struct virtio_dev *vdev = &bvdev->vdev;
255 : :
256 : 12 : virtio_dev_stop(vdev);
257 : 12 : virtio_dev_destruct(vdev);
258 : 12 : spdk_bdev_destruct_done(&bvdev->bdev, 0);
259 : 12 : free(bvdev);
260 : 12 : }
261 : :
262 : : static int
263 : 12 : bdev_virtio_disk_destruct(void *ctx)
264 : : {
265 : 12 : struct virtio_blk_dev *bvdev = ctx;
266 : :
267 : 12 : spdk_io_device_unregister(bvdev, virtio_blk_dev_unregister_cb);
268 : 12 : return 1;
269 : : }
270 : :
271 : : int
272 : 6 : bdev_virtio_blk_dev_remove(const char *name, bdev_virtio_remove_cb cb_fn, void *cb_arg)
273 : : {
274 : 6 : return spdk_bdev_unregister_by_name(name, &virtio_blk_if, cb_fn, cb_arg);
275 : : }
276 : :
277 : : static int
278 : 53 : bdev_virtio_dump_json_config(void *ctx, struct spdk_json_write_ctx *w)
279 : : {
280 : 53 : struct virtio_blk_dev *bvdev = ctx;
281 : :
282 : 53 : virtio_dev_dump_json_info(&bvdev->vdev, w);
283 : 53 : return 0;
284 : : }
285 : :
286 : : static void
287 : 5 : bdev_virtio_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w)
288 : : {
289 : 5 : struct virtio_blk_dev *bvdev = bdev->ctxt;
290 : :
291 : 5 : spdk_json_write_object_begin(w);
292 : :
293 : 5 : spdk_json_write_named_string(w, "method", "bdev_virtio_attach_controller");
294 : :
295 : 5 : spdk_json_write_named_object_begin(w, "params");
296 : 5 : spdk_json_write_named_string(w, "name", bvdev->vdev.name);
297 : 5 : spdk_json_write_named_string(w, "dev_type", "blk");
298 : :
299 : : /* Write transport specific parameters. */
300 : 5 : bvdev->vdev.backend_ops->write_json_config(&bvdev->vdev, w);
301 : :
302 : 5 : spdk_json_write_object_end(w);
303 : :
304 : 5 : spdk_json_write_object_end(w);
305 : 5 : }
306 : :
307 : : static const struct spdk_bdev_fn_table virtio_fn_table = {
308 : : .destruct = bdev_virtio_disk_destruct,
309 : : .submit_request = bdev_virtio_submit_request,
310 : : .io_type_supported = bdev_virtio_io_type_supported,
311 : : .get_io_channel = bdev_virtio_get_io_channel,
312 : : .dump_info_json = bdev_virtio_dump_json_config,
313 : : .write_config_json = bdev_virtio_write_config_json,
314 : : };
315 : :
316 : : static void
317 : 2847615 : bdev_virtio_io_cpl(struct spdk_bdev_io *bdev_io)
318 : : {
319 : 2847615 : struct virtio_blk_io_ctx *io_ctx = (struct virtio_blk_io_ctx *)bdev_io->driver_ctx;
320 : :
321 [ + - ]: 2847615 : spdk_bdev_io_complete(bdev_io, io_ctx->resp == VIRTIO_BLK_S_OK ?
322 : : SPDK_BDEV_IO_STATUS_SUCCESS : SPDK_BDEV_IO_STATUS_FAILED);
323 : 2847615 : }
324 : :
325 : : static int
326 : 22250555 : bdev_virtio_poll(void *arg)
327 : : {
328 : 22250555 : struct bdev_virtio_blk_io_channel *ch = arg;
329 : 2655935 : void *io[32];
330 : 2655935 : uint32_t io_len[32];
331 : : uint16_t i, cnt;
332 : :
333 : 22250555 : cnt = virtio_recv_pkts(ch->vq, io, io_len, SPDK_COUNTOF(io));
334 [ + + ]: 25098170 : for (i = 0; i < cnt; ++i) {
335 : 2847615 : bdev_virtio_io_cpl(io[i]);
336 : : }
337 : :
338 : 22250555 : return cnt;
339 : : }
340 : :
341 : : static int
342 : 17 : bdev_virtio_blk_ch_create_cb(void *io_device, void *ctx_buf)
343 : : {
344 : 17 : struct virtio_blk_dev *bvdev = io_device;
345 : 17 : struct virtio_dev *vdev = &bvdev->vdev;
346 : 17 : struct bdev_virtio_blk_io_channel *ch = ctx_buf;
347 : : struct virtqueue *vq;
348 : : int32_t queue_idx;
349 : :
350 : 17 : queue_idx = virtio_dev_find_and_acquire_queue(vdev, 0);
351 [ - + ]: 17 : if (queue_idx < 0) {
352 : 0 : SPDK_ERRLOG("Couldn't get an unused queue for the io_channel.\n");
353 : 0 : return -1;
354 : : }
355 : :
356 : 17 : vq = vdev->vqs[queue_idx];
357 : :
358 : 17 : ch->vdev = vdev;
359 : 17 : ch->vq = vq;
360 : :
361 : 17 : ch->poller = SPDK_POLLER_REGISTER(bdev_virtio_poll, ch, 0);
362 : 17 : return 0;
363 : : }
364 : :
365 : : static void
366 : 17 : bdev_virtio_blk_ch_destroy_cb(void *io_device, void *ctx_buf)
367 : : {
368 : 17 : struct virtio_blk_dev *bvdev = io_device;
369 : 17 : struct virtio_dev *vdev = &bvdev->vdev;
370 : 17 : struct bdev_virtio_blk_io_channel *ch = ctx_buf;
371 : 17 : struct virtqueue *vq = ch->vq;
372 : :
373 : 17 : spdk_poller_unregister(&ch->poller);
374 : 17 : virtio_dev_release_queue(vdev, vq->vq_queue_index);
375 : 17 : }
376 : :
377 : : static int
378 : 12 : virtio_blk_dev_init(struct virtio_blk_dev *bvdev, uint16_t max_queues)
379 : : {
380 : 12 : struct virtio_dev *vdev = &bvdev->vdev;
381 : 12 : struct spdk_bdev *bdev = &bvdev->bdev;
382 : 1 : uint64_t capacity, num_blocks;
383 : 1 : uint32_t block_size, size_max, seg_max;
384 : 1 : uint16_t host_max_queues;
385 : : int rc;
386 : :
387 [ + - ]: 12 : if (virtio_dev_has_feature(vdev, VIRTIO_BLK_F_BLK_SIZE)) {
388 : 12 : rc = virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, blk_size),
389 : : &block_size, sizeof(block_size));
390 [ - + ]: 12 : if (rc) {
391 : 0 : SPDK_ERRLOG("%s: config read failed: %s\n", vdev->name, spdk_strerror(-rc));
392 : 0 : return rc;
393 : : }
394 : :
395 [ + - - + ]: 12 : if (block_size == 0 || block_size % 512 != 0) {
396 : 0 : SPDK_ERRLOG("%s: invalid block size (%"PRIu32"). Must be "
397 : : "a multiple of 512.\n", vdev->name, block_size);
398 : 0 : return -EIO;
399 : : }
400 : : } else {
401 : 0 : block_size = 512;
402 : : }
403 : :
404 : 12 : rc = virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, capacity),
405 : : &capacity, sizeof(capacity));
406 [ - + ]: 12 : if (rc) {
407 : 0 : SPDK_ERRLOG("%s: config read failed: %s\n", vdev->name, spdk_strerror(-rc));
408 : 0 : return rc;
409 : : }
410 : :
411 : : /* `capacity` is a number of 512-byte sectors. */
412 [ - + ]: 12 : num_blocks = capacity * 512 / block_size;
413 [ - + ]: 12 : if (num_blocks == 0) {
414 : 0 : SPDK_ERRLOG("%s: size too small (size: %"PRIu64", blocksize: %"PRIu32").\n",
415 : : vdev->name, capacity * 512, block_size);
416 : 0 : return -EIO;
417 : : }
418 : :
419 [ - + - + ]: 12 : if ((capacity * 512) % block_size != 0) {
420 : 0 : SPDK_WARNLOG("%s: size has been rounded down to the nearest block size boundary. "
421 : : "(block size: %"PRIu32", previous size: %"PRIu64", new size: %"PRIu64")\n",
422 : : vdev->name, block_size, capacity * 512, num_blocks * block_size);
423 : : }
424 : :
425 [ + - ]: 12 : if (virtio_dev_has_feature(vdev, VIRTIO_BLK_F_MQ)) {
426 : 12 : rc = virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, num_queues),
427 : : &host_max_queues, sizeof(host_max_queues));
428 [ - + ]: 12 : if (rc) {
429 : 0 : SPDK_ERRLOG("%s: config read failed: %s\n", vdev->name, spdk_strerror(-rc));
430 : 0 : return rc;
431 : : }
432 : : } else {
433 : 0 : host_max_queues = 1;
434 : : }
435 : :
436 [ + - ]: 12 : if (virtio_dev_has_feature(vdev, VIRTIO_BLK_F_SIZE_MAX)) {
437 : 12 : rc = virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, size_max),
438 : : &size_max, sizeof(size_max));
439 [ - + ]: 12 : if (rc) {
440 : 0 : SPDK_ERRLOG("%s: config read failed: %s\n", vdev->name, spdk_strerror(-rc));
441 : 0 : return rc;
442 : : }
443 : :
444 [ - + ]: 12 : if (spdk_unlikely(size_max < block_size)) {
445 : 0 : SPDK_WARNLOG("%s: minimum segment size is set to block size %u forcefully.\n",
446 : : vdev->name, block_size);
447 : 0 : size_max = block_size;
448 : : }
449 : :
450 : 12 : bdev->max_segment_size = size_max;
451 : : }
452 : :
453 [ + - ]: 12 : if (virtio_dev_has_feature(vdev, VIRTIO_BLK_F_SEG_MAX)) {
454 : 12 : rc = virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, seg_max),
455 : : &seg_max, sizeof(seg_max));
456 [ - + ]: 12 : if (rc) {
457 : 0 : SPDK_ERRLOG("%s: config read failed: %s\n", vdev->name, spdk_strerror(-rc));
458 : 0 : return rc;
459 : : }
460 : :
461 [ - + ]: 12 : if (spdk_unlikely(seg_max == 0)) {
462 : 0 : SPDK_ERRLOG("%s: virtio blk SEG_MAX can't be 0\n", vdev->name);
463 : 0 : return -EINVAL;
464 : : }
465 : :
466 : 12 : bdev->max_num_segments = seg_max;
467 : : }
468 : :
469 [ - + ]: 12 : if (virtio_dev_has_feature(vdev, VIRTIO_BLK_F_RO)) {
470 : 0 : bvdev->readonly = true;
471 : : }
472 : :
473 [ + - ]: 12 : if (virtio_dev_has_feature(vdev, VIRTIO_BLK_F_DISCARD)) {
474 : 12 : bvdev->unmap = true;
475 : : }
476 : :
477 [ - + ]: 12 : if (max_queues == 0) {
478 : 0 : SPDK_ERRLOG("%s: requested 0 request queues (%"PRIu16" available).\n",
479 : : vdev->name, host_max_queues);
480 : 0 : return -EINVAL;
481 : : }
482 : :
483 [ - + ]: 12 : if (max_queues > host_max_queues) {
484 : 0 : SPDK_WARNLOG("%s: requested %"PRIu16" request queues "
485 : : "but only %"PRIu16" available.\n",
486 : : vdev->name, max_queues, host_max_queues);
487 : 0 : max_queues = host_max_queues;
488 : : }
489 : :
490 : : /* bdev is tied with the virtio device; we can reuse the name */
491 : 12 : bdev->name = vdev->name;
492 : 12 : rc = virtio_dev_start(vdev, max_queues, 0);
493 [ - + ]: 12 : if (rc != 0) {
494 : 0 : return rc;
495 : : }
496 : :
497 : 12 : bdev->product_name = "VirtioBlk Disk";
498 : 12 : bdev->write_cache = 0;
499 : 12 : bdev->blocklen = block_size;
500 : 12 : bdev->blockcnt = num_blocks;
501 : :
502 : 12 : bdev->ctxt = bvdev;
503 : 12 : bdev->fn_table = &virtio_fn_table;
504 : 12 : bdev->module = &virtio_blk_if;
505 : :
506 : 12 : spdk_io_device_register(bvdev, bdev_virtio_blk_ch_create_cb,
507 : : bdev_virtio_blk_ch_destroy_cb,
508 : : sizeof(struct bdev_virtio_blk_io_channel),
509 : 12 : vdev->name);
510 : :
511 : 12 : rc = spdk_bdev_register(bdev);
512 [ - + ]: 12 : if (rc) {
513 : 0 : SPDK_ERRLOG("Failed to register bdev name=%s\n", bdev->name);
514 : 0 : spdk_io_device_unregister(bvdev, NULL);
515 : 0 : virtio_dev_stop(vdev);
516 : 0 : return rc;
517 : : }
518 : :
519 : 12 : return 0;
520 : : }
521 : :
522 : : static struct virtio_blk_dev *
523 : 0 : virtio_pci_blk_dev_create(const char *name, struct virtio_pci_ctx *pci_ctx)
524 : : {
525 : : static int pci_dev_counter = 0;
526 : : struct virtio_blk_dev *bvdev;
527 : : struct virtio_dev *vdev;
528 : 0 : char *default_name = NULL;
529 : 0 : uint16_t num_queues;
530 : : int rc;
531 : :
532 : 0 : bvdev = calloc(1, sizeof(*bvdev));
533 [ # # ]: 0 : if (bvdev == NULL) {
534 : 0 : SPDK_ERRLOG("virtio device calloc failed\n");
535 : 0 : return NULL;
536 : : }
537 : 0 : vdev = &bvdev->vdev;
538 : :
539 [ # # ]: 0 : if (name == NULL) {
540 : 0 : default_name = spdk_sprintf_alloc("VirtioBlk%"PRIu32, pci_dev_counter++);
541 [ # # ]: 0 : if (default_name == NULL) {
542 : 0 : free(vdev);
543 : 0 : return NULL;
544 : : }
545 : 0 : name = default_name;
546 : : }
547 : :
548 : 0 : rc = virtio_pci_dev_init(vdev, name, pci_ctx);
549 : 0 : free(default_name);
550 : :
551 [ # # ]: 0 : if (rc != 0) {
552 : 0 : free(bvdev);
553 : 0 : return NULL;
554 : : }
555 : :
556 : 0 : rc = virtio_dev_reset(vdev, VIRTIO_BLK_DEV_SUPPORTED_FEATURES);
557 [ # # ]: 0 : if (rc != 0) {
558 : 0 : goto fail;
559 : : }
560 : :
561 : : /* TODO: add a way to limit usable virtqueues */
562 [ # # ]: 0 : if (virtio_dev_has_feature(vdev, VIRTIO_BLK_F_MQ)) {
563 : 0 : rc = virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, num_queues),
564 : : &num_queues, sizeof(num_queues));
565 [ # # ]: 0 : if (rc) {
566 : 0 : SPDK_ERRLOG("%s: config read failed: %s\n", vdev->name, spdk_strerror(-rc));
567 : 0 : goto fail;
568 : : }
569 : : } else {
570 : 0 : num_queues = 1;
571 : : }
572 : :
573 : 0 : rc = virtio_blk_dev_init(bvdev, num_queues);
574 [ # # ]: 0 : if (rc != 0) {
575 : 0 : goto fail;
576 : : }
577 : :
578 : 0 : return bvdev;
579 : :
580 : 0 : fail:
581 : 0 : vdev->ctx = NULL;
582 : 0 : virtio_dev_destruct(vdev);
583 : 0 : free(bvdev);
584 : 0 : return NULL;
585 : : }
586 : :
587 : : static struct virtio_blk_dev *
588 : 11 : virtio_user_blk_dev_create(const char *name, const char *path,
589 : : uint16_t num_queues, uint32_t queue_size)
590 : : {
591 : : struct virtio_blk_dev *bvdev;
592 : : uint64_t feature_bits;
593 : : int rc;
594 : :
595 : 11 : bvdev = calloc(1, sizeof(*bvdev));
596 [ - + ]: 11 : if (bvdev == NULL) {
597 : 0 : SPDK_ERRLOG("calloc failed for virtio device %s: %s\n", name, path);
598 : 0 : return NULL;
599 : : }
600 : :
601 : 11 : rc = virtio_user_dev_init(&bvdev->vdev, name, path, queue_size);
602 [ - + ]: 11 : if (rc != 0) {
603 : 0 : SPDK_ERRLOG("Failed to create virito device %s: %s\n", name, path);
604 : 0 : free(bvdev);
605 : 0 : return NULL;
606 : : }
607 : :
608 : 11 : feature_bits = VIRTIO_BLK_DEV_SUPPORTED_FEATURES;
609 : 11 : feature_bits |= (1ULL << VHOST_USER_F_PROTOCOL_FEATURES);
610 : 11 : rc = virtio_dev_reset(&bvdev->vdev, feature_bits);
611 [ - + ]: 11 : if (rc != 0) {
612 : 0 : virtio_dev_destruct(&bvdev->vdev);
613 : 0 : free(bvdev);
614 : 0 : return NULL;
615 : : }
616 : :
617 : 11 : rc = virtio_blk_dev_init(bvdev, num_queues);
618 [ - + ]: 11 : if (rc != 0) {
619 : 0 : virtio_dev_destruct(&bvdev->vdev);
620 : 0 : free(bvdev);
621 : 0 : return NULL;
622 : : }
623 : :
624 : 11 : return bvdev;
625 : : }
626 : :
627 : : struct bdev_virtio_pci_dev_create_ctx {
628 : : const char *name;
629 : : struct virtio_blk_dev *ret;
630 : : };
631 : :
632 : : static int
633 : 0 : bdev_virtio_pci_blk_dev_create_cb(struct virtio_pci_ctx *pci_ctx, void *ctx)
634 : : {
635 : 0 : struct bdev_virtio_pci_dev_create_ctx *create_ctx = ctx;
636 : :
637 : 0 : create_ctx->ret = virtio_pci_blk_dev_create(create_ctx->name, pci_ctx);
638 [ # # ]: 0 : if (create_ctx->ret == NULL) {
639 : 0 : return -1;
640 : : }
641 : :
642 : 0 : return 0;
643 : : }
644 : :
645 : : struct spdk_bdev *
646 : 0 : bdev_virtio_pci_blk_dev_create(const char *name, struct spdk_pci_addr *pci_addr)
647 : : {
648 : 0 : struct bdev_virtio_pci_dev_create_ctx create_ctx;
649 : :
650 : 0 : create_ctx.name = name;
651 : 0 : create_ctx.ret = NULL;
652 : :
653 : 0 : virtio_pci_dev_attach(bdev_virtio_pci_blk_dev_create_cb, &create_ctx,
654 : : VIRTIO_ID_BLOCK, pci_addr);
655 : :
656 [ # # ]: 0 : if (create_ctx.ret == NULL) {
657 : 0 : return NULL;
658 : : }
659 : :
660 : 0 : return &create_ctx.ret->bdev;
661 : : }
662 : :
663 : : static int
664 : 0 : bdev_virtio_pci_blk_monitor(void *arg)
665 : : {
666 : : const char *vdev_name;
667 : 0 : struct bdev_virtio_pci_dev_create_ctx create_ctx;
668 : :
669 [ # # ]: 0 : while ((vdev_name = virtio_pci_dev_event_process(g_blk_hotplug_fd, VIRTIO_ID_BLOCK)) != NULL) {
670 : 0 : bdev_virtio_blk_dev_remove(vdev_name, NULL, NULL);
671 : : }
672 : :
673 : : /* Enumerate virtio pci_blk device */
674 [ # # ]: 0 : memset(&create_ctx, 0, sizeof(create_ctx));
675 : 0 : virtio_pci_dev_enumerate(bdev_virtio_pci_blk_dev_create_cb, &create_ctx,
676 : : VIRTIO_ID_BLOCK);
677 : :
678 : 0 : return SPDK_POLLER_BUSY;
679 : : }
680 : :
681 : : int
682 : 0 : bdev_virtio_pci_blk_set_hotplug(bool enabled, uint64_t period_us)
683 : : {
684 [ # # # # ]: 0 : if (enabled == true && !spdk_process_is_primary()) {
685 : 0 : return -EPERM;
686 : : }
687 : :
688 [ # # ]: 0 : if (g_blk_hotplug_poller) {
689 : 0 : close(g_blk_hotplug_fd);
690 : 0 : spdk_poller_unregister(&g_blk_hotplug_poller);
691 : : }
692 : :
693 [ # # ]: 0 : if (!enabled) {
694 : 0 : return 0;
695 : : }
696 : :
697 : 0 : g_blk_hotplug_fd = spdk_pci_event_listen();
698 [ # # ]: 0 : if (g_blk_hotplug_fd < 0) {
699 : 0 : return g_blk_hotplug_fd;
700 : : }
701 : :
702 [ # # ]: 0 : period_us = period_us ? period_us : VIRTIO_BLK_HOTPLUG_POLL_PERIOD_DEFAULT;
703 : 0 : period_us = spdk_min(period_us, VIRTIO_BLK_HOTPLUG_POLL_PERIOD_MAX);
704 : 0 : g_blk_hotplug_poller = spdk_poller_register(bdev_virtio_pci_blk_monitor, NULL, period_us);
705 [ # # ]: 0 : if (!g_blk_hotplug_poller) {
706 : 0 : close(g_blk_hotplug_fd);
707 : 0 : return -1;
708 : : }
709 : :
710 : 0 : return 0;
711 : : }
712 : :
713 : : static int
714 : 2127 : bdev_virtio_initialize(void)
715 : : {
716 : 2127 : return 0;
717 : : }
718 : :
719 : : struct spdk_bdev *
720 : 11 : bdev_virtio_user_blk_dev_create(const char *name, const char *path,
721 : : unsigned num_queues, unsigned queue_size)
722 : : {
723 : : struct virtio_blk_dev *bvdev;
724 : :
725 : 11 : bvdev = virtio_user_blk_dev_create(name, path, num_queues, queue_size);
726 [ - + ]: 11 : if (bvdev == NULL) {
727 : 0 : return NULL;
728 : : }
729 : :
730 : 11 : return &bvdev->bdev;
731 : : }
732 : :
733 : : struct spdk_bdev *
734 : 1 : bdev_virtio_vfio_user_blk_dev_create(const char *name, const char *path)
735 : : {
736 : : struct virtio_blk_dev *bvdev;
737 : 1 : uint16_t num_queues = 0;
738 : : int rc;
739 : :
740 : 1 : bvdev = calloc(1, sizeof(*bvdev));
741 [ - + ]: 1 : if (bvdev == NULL) {
742 : 0 : SPDK_ERRLOG("calloc failed for virtio device %s: %s\n", name, path);
743 : 0 : return NULL;
744 : : }
745 : :
746 : 1 : rc = virtio_vfio_user_dev_init(&bvdev->vdev, name, path);
747 [ - + ]: 1 : if (rc != 0) {
748 : 0 : SPDK_ERRLOG("Failed to create %s as virtio device\n", path);
749 : 0 : free(bvdev);
750 : 0 : return NULL;
751 : : }
752 : :
753 : 1 : rc = virtio_dev_reset(&bvdev->vdev, VIRTIO_BLK_DEV_SUPPORTED_FEATURES);
754 [ - + ]: 1 : if (rc != 0) {
755 : 0 : SPDK_ERRLOG("Failed to reset %s as virtio device\n", path);
756 : 0 : virtio_dev_destruct(&bvdev->vdev);
757 : 0 : free(bvdev);
758 : 0 : return NULL;
759 : : }
760 : :
761 [ + - ]: 1 : if (virtio_dev_has_feature(&bvdev->vdev, VIRTIO_BLK_F_MQ)) {
762 : 1 : rc = virtio_dev_read_dev_config(&bvdev->vdev, offsetof(struct virtio_blk_config, num_queues),
763 : : &num_queues, sizeof(num_queues));
764 [ - + ]: 1 : if (rc) {
765 : 0 : SPDK_ERRLOG("%s: config read failed: %s\n", name, spdk_strerror(-rc));
766 : 0 : virtio_dev_destruct(&bvdev->vdev);
767 : 0 : free(bvdev);
768 : 0 : return NULL;
769 : : }
770 : : } else {
771 : 0 : num_queues = 1;
772 : : }
773 : :
774 : 1 : rc = virtio_blk_dev_init(bvdev, num_queues);
775 [ - + ]: 1 : if (rc != 0) {
776 : 0 : SPDK_ERRLOG("Failed to initialize %s as virtio device\n", path);
777 : 0 : virtio_dev_destruct(&bvdev->vdev);
778 : 0 : free(bvdev);
779 : 0 : return NULL;
780 : : }
781 : :
782 : 1 : return &bvdev->bdev;
783 : : }
784 : :
785 : : static int
786 : 2127 : bdev_virtio_blk_get_ctx_size(void)
787 : : {
788 : 2127 : return sizeof(struct virtio_blk_io_ctx);
789 : : }
790 : :
791 : 2317 : SPDK_LOG_REGISTER_COMPONENT(virtio_blk)
|