examples/vhost_blk: refactor to increase readability
[dpdk.git] / examples / vhost_blk / blk.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2019 Intel Corporation
3  */
4
5 /**
6  * This work is largely based on the "vhost-user-blk" implementation by
7  * SPDK(https://github.com/spdk/spdk).
8  */
9
10 #include <stdio.h>
11 #include <stdint.h>
12 #include <unistd.h>
13 #include <assert.h>
14 #include <ctype.h>
15 #include <string.h>
16 #include <stddef.h>
17
18 #include <rte_atomic.h>
19 #include <rte_cycles.h>
20 #include <rte_log.h>
21 #include <rte_malloc.h>
22 #include <rte_byteorder.h>
23 #include <rte_string_fns.h>
24
25 #include "vhost_blk.h"
26 #include "blk_spec.h"
27
28 static void
29 vhost_strcpy_pad(void *dst, const char *src, size_t size, int pad)
30 {
31         size_t len;
32
33         len = strlen(src);
34         if (len < size) {
35                 memcpy(dst, src, len);
36                 memset((char *)dst + len, pad, size - len);
37         } else {
38                 memcpy(dst, src, size);
39         }
40 }
41
42 static int
43 vhost_bdev_blk_readwrite(struct vhost_block_dev *bdev,
44                           struct vhost_blk_task *task,
45                           uint64_t lba_512, __rte_unused uint32_t xfer_len)
46 {
47         uint32_t i;
48         uint64_t offset;
49         uint32_t nbytes = 0;
50
51         offset = lba_512 * 512;
52
53         /* iovs[0] is the head and iovs[iovs_cnt - 1] is the tail
54          * Middle is the data range
55          */
56         for (i = 1; i < task->iovs_cnt - 1; i++) {
57                 if (task->dxfer_dir == BLK_DIR_TO_DEV)
58                         memcpy(bdev->data + offset, task->iovs[i].iov_base,
59                                task->iovs[i].iov_len);
60                 else
61                         memcpy(task->iovs[i].iov_base, bdev->data + offset,
62                                task->iovs[i].iov_len);
63                 offset += task->iovs[i].iov_len;
64                 nbytes += task->iovs[i].iov_len;
65         }
66
67         return nbytes;
68 }
69
70 int
71 vhost_bdev_process_blk_commands(struct vhost_block_dev *bdev,
72                                  struct vhost_blk_task *task)
73 {
74         size_t used_len;
75
76         if (unlikely(task->data_len > (bdev->blockcnt * bdev->blocklen))) {
77                 fprintf(stderr, "read or write beyond capacity\n");
78                 return VIRTIO_BLK_S_UNSUPP;
79         }
80
81         switch (task->req->type) {
82         case VIRTIO_BLK_T_IN:
83                 if (unlikely(task->data_len == 0 ||
84                         (task->data_len & (512 - 1)) != 0)) {
85                         fprintf(stderr,
86                                 "%s - passed IO buffer is not multiple of 512b"
87                                 "(req_idx = %"PRIu16").\n",
88                                 task->req->type ? "WRITE" : "READ",
89                                 task->req_idx);
90                         return VIRTIO_BLK_S_UNSUPP;
91                 }
92
93                 task->dxfer_dir = BLK_DIR_FROM_DEV;
94                 vhost_bdev_blk_readwrite(bdev, task,
95                                          task->req->sector, task->data_len);
96                 break;
97         case VIRTIO_BLK_T_OUT:
98                 if (unlikely(task->data_len == 0 ||
99                         (task->data_len & (512 - 1)) != 0)) {
100                         fprintf(stderr,
101                                 "%s - passed IO buffer is not multiple of 512b"
102                                 "(req_idx = %"PRIu16").\n",
103                                 task->req->type ? "WRITE" : "READ",
104                                 task->req_idx);
105                         return VIRTIO_BLK_S_UNSUPP;
106                 }
107
108                 task->dxfer_dir = BLK_DIR_TO_DEV;
109                 vhost_bdev_blk_readwrite(bdev, task,
110                                          task->req->sector, task->data_len);
111                 break;
112         case VIRTIO_BLK_T_GET_ID:
113                 if (!task->iovs_cnt || task->data_len)
114                         return VIRTIO_BLK_S_UNSUPP;
115                 used_len = RTE_MIN((size_t)VIRTIO_BLK_ID_BYTES, task->data_len);
116                 vhost_strcpy_pad(task->iovs[0].iov_base,
117                                  bdev->product_name, used_len, ' ');
118                 break;
119         default:
120                 fprintf(stderr, "unsupported cmd\n");
121                 return VIRTIO_BLK_S_UNSUPP;
122         }
123
124         return VIRTIO_BLK_S_OK;
125 }