dpdk/examples/vhost_blk/blk.c
<<
>>
Prefs
   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
  28static void
  29vhost_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
  42static int
  43vhost_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
  70int
  71vhost_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}
 126