v4:
- added support for iproute2 vdpa management tool in vdpa_sim_blk
- removed get/set_config patches
- 'vdpa: add return value to get_config/set_config callbacks'
- 'vhost/vdpa: remove vhost_vdpa_config_validate()'
- added get_config_size() patches
- 'vdpa: add get_config_size callback in vdpa_config_ops'
- 'vhost/vdpa: use get_config_size callback in vhost_vdpa_config_validate()'
v3: https://lore.kernel.org/lkml/20210204172230.85853-1-sgarzare@redhat.com/
v2: https://lore.kernel.org/lkml/20210128144127.113245-1-sgarzare@redhat.com/
v1: https://lore.kernel.org/lkml/93f207c0-61e6-3696-f218-e7d7ea9a7c93@redhat.com/
This series is the second part of the v1 linked above. The first part with
refactoring of vdpa_sim has already been merged.
The patches are based on Max Gurtovoy's work and extend the block simulator to
have a ramdisk behaviour.
As mentioned in the v1 there was 2 issues and I fixed them in this series:
1. The identical mapping in the IOMMU used until now in vdpa_sim created issues
when mapping different virtual pages with the same physical address.
Fixed by patch "vdpa_sim: use iova module to allocate IOVA addresses"
2. There was a race accessing the IOMMU between the vdpasim_blk_work() and the
device driver that map/unmap DMA regions. Fixed by patch "vringh: add
'iotlb_lock' to synchronize iotlb accesses"
I used the Xie's patch coming from VDUSE series to allow vhost-vdpa to use
block devices, and I added get_config_size() callback to allow any device
in vhost-vdpa.
The series also includes small fixes for vringh, vdpa, and vdpa_sim that I
discovered while implementing and testing the block simulator.
Thanks for your feedback,
Stefano
Max Gurtovoy (1):
vdpa: add vdpa simulator for block device
Stefano Garzarella (12):
vdpa_sim: use iova module to allocate IOVA addresses
vringh: add 'iotlb_lock' to synchronize iotlb accesses
vringh: reset kiov 'consumed' field in __vringh_iov()
vringh: explain more about cleaning riov and wiov
vringh: implement vringh_kiov_advance()
vringh: add vringh_kiov_length() helper
vdpa_sim: cleanup kiovs in vdpasim_free()
vdpa: add get_config_size callback in vdpa_config_ops
vhost/vdpa: use get_config_size callback in
vhost_vdpa_config_validate()
vdpa_sim_blk: implement ramdisk behaviour
vdpa_sim_blk: handle VIRTIO_BLK_T_GET_ID
vdpa_sim_blk: add support for vdpa management tool
Xie Yongji (1):
vhost/vdpa: Remove the restriction that only supports virtio-net
devices
drivers/vdpa/vdpa_sim/vdpa_sim.h | 2 +
include/linux/vdpa.h | 4 +
include/linux/vringh.h | 19 +-
drivers/vdpa/ifcvf/ifcvf_main.c | 6 +
drivers/vdpa/mlx5/net/mlx5_vnet.c | 6 +
drivers/vdpa/vdpa_sim/vdpa_sim.c | 127 ++++++----
drivers/vdpa/vdpa_sim/vdpa_sim_blk.c | 338 +++++++++++++++++++++++++++
drivers/vdpa/virtio_pci/vp_vdpa.c | 8 +
drivers/vhost/vdpa.c | 15 +-
drivers/vhost/vringh.c | 69 ++++--
drivers/vdpa/Kconfig | 8 +
drivers/vdpa/vdpa_sim/Makefile | 1 +
12 files changed, 529 insertions(+), 74 deletions(-)
create mode 100644 drivers/vdpa/vdpa_sim/vdpa_sim_blk.c
--
2.30.2
The identical mapping used until now created issues when mapping
different virtual pages with the same physical address.
To solve this issue, we can use the iova module, to handle the IOVA
allocation.
For simplicity we use an IOVA allocator with byte granularity.
We add two new functions, vdpasim_map_range() and vdpasim_unmap_range(),
to handle the IOVA allocation and the registration into the IOMMU/IOTLB.
These functions are used by dma_map_ops callbacks.
Acked-by: Jason Wang <redacted>
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
---
v2:
- used ULONG_MAX instead of ~0UL [Jason]
- fixed typos in comment and patch description [Jason]
---
drivers/vdpa/vdpa_sim/vdpa_sim.h | 2 +
drivers/vdpa/vdpa_sim/vdpa_sim.c | 108 +++++++++++++++++++------------
drivers/vdpa/Kconfig | 1 +
3 files changed, 69 insertions(+), 42 deletions(-)
@@ -57,6 +58,7 @@ struct vdpasim {/* virtio config according to device type */void*config;structvhost_iotlb*iommu;+structiova_domainiova;void*buffer;u32status;u32generation;
@@ -128,30 +129,57 @@ static int dir_to_perm(enum dma_data_direction dir)returnperm;}+staticdma_addr_tvdpasim_map_range(structvdpasim*vdpasim,phys_addr_tpaddr,+size_tsize,unsignedintperm)+{+structiova*iova;+dma_addr_tdma_addr;+intret;++/* We set the limit_pfn to the maximum (ULONG_MAX - 1) */+iova=alloc_iova(&vdpasim->iova,size,ULONG_MAX-1,true);+if(!iova)+returnDMA_MAPPING_ERROR;++dma_addr=iova_dma_addr(&vdpasim->iova,iova);++spin_lock(&vdpasim->iommu_lock);+ret=vhost_iotlb_add_range(vdpasim->iommu,(u64)dma_addr,+(u64)dma_addr+size-1,(u64)paddr,perm);+spin_unlock(&vdpasim->iommu_lock);++if(ret){+__free_iova(&vdpasim->iova,iova);+returnDMA_MAPPING_ERROR;+}++returndma_addr;+}++staticvoidvdpasim_unmap_range(structvdpasim*vdpasim,dma_addr_tdma_addr,+size_tsize)+{+spin_lock(&vdpasim->iommu_lock);+vhost_iotlb_del_range(vdpasim->iommu,(u64)dma_addr,+(u64)dma_addr+size-1);+spin_unlock(&vdpasim->iommu_lock);++free_iova(&vdpasim->iova,iova_pfn(&vdpasim->iova,dma_addr));+}+staticdma_addr_tvdpasim_map_page(structdevice*dev,structpage*page,unsignedlongoffset,size_tsize,enumdma_data_directiondir,unsignedlongattrs){structvdpasim*vdpasim=dev_to_sim(dev);-structvhost_iotlb*iommu=vdpasim->iommu;-u64pa=(page_to_pfn(page)<<PAGE_SHIFT)+offset;-intret,perm=dir_to_perm(dir);+phys_addr_tpaddr=page_to_phys(page)+offset;+intperm=dir_to_perm(dir);if(perm<0)returnDMA_MAPPING_ERROR;-/* For simplicity, use identical mapping to avoid e.g iova-*allocator.-*/-spin_lock(&vdpasim->iommu_lock);-ret=vhost_iotlb_add_range(iommu,pa,pa+size-1,-pa,dir_to_perm(dir));-spin_unlock(&vdpasim->iommu_lock);-if(ret)-returnDMA_MAPPING_ERROR;--return(dma_addr_t)(pa);+returnvdpasim_map_range(vdpasim,paddr,size,perm);}staticvoidvdpasim_unmap_page(structdevice*dev,dma_addr_tdma_addr,
@@ -271,6 +286,13 @@ struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr)for(i=0;i<dev_attr->nvqs;i++)vringh_set_iotlb(&vdpasim->vqs[i].vring,vdpasim->iommu);+ret=iova_cache_get();+if(ret)+gotoerr_iommu;++/* For simplicity we use an IOVA allocator with byte granularity */+init_iova_domain(&vdpasim->iova,1,0);+vdpasim->vdpa.dma_dev=dev;returnvdpasim;
Usually iotlb accesses are synchronized with a spinlock.
Let's request it as a new parameter in vringh_set_iotlb() and
hold it when we navigate the iotlb in iotlb_translate() to avoid
race conditions with any new additions/deletions of ranges from
the ioltb.
Acked-by: Jason Wang <redacted>
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
---
include/linux/vringh.h | 6 +++++-
drivers/vdpa/vdpa_sim/vdpa_sim.c | 3 ++-
drivers/vhost/vringh.c | 9 ++++++++-
3 files changed, 15 insertions(+), 3 deletions(-)
@@ -46,6 +46,9 @@ struct vringh {/* IOTLB for this vring */structvhost_iotlb*iotlb;+/* spinlock to synchronize IOTLB accesses */+spinlock_t*iotlb_lock;+/* The function to call to notify the guest about added buffers */void(*notify)(structvringh*);};
__vringh_iov() overwrites the contents of riov and wiov, in fact it
resets the 'i' and 'used' fields, but also the 'consumed' field should
be reset to avoid an inconsistent state.
Acked-by: Jason Wang <redacted>
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
---
drivers/vhost/vringh.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
riov and wiov can be reused with subsequent calls of vringh_getdesc_*().
Let's add a paragraph in the documentation of these functions to better
explain when riov and wiov need to be cleaned up.
Acked-by: Jason Wang <redacted>
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
---
drivers/vhost/vringh.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
In some cases, it may be useful to provide a way to skip a number
of bytes in a vringh_kiov.
Let's implement vringh_kiov_advance() for this purpose, reusing the
code from vringh_iov_xfer().
We replace that code calling the new vringh_kiov_advance().
Acked-by: Jason Wang <redacted>
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
---
include/linux/vringh.h | 2 ++
drivers/vhost/vringh.c | 41 +++++++++++++++++++++++++++++------------
2 files changed, 31 insertions(+), 12 deletions(-)
@@ -75,6 +75,34 @@ static inline int __vringh_get_head(const struct vringh *vrh,returnhead;}+/**+*vringh_kiov_advance-skipbytesfromvring_kiov+*@iov:aniovpassedtovringh_getdesc_*()(updatedasweconsume)+*@len:themaximumlengthtoadvance+*/+voidvringh_kiov_advance(structvringh_kiov*iov,size_tlen)+{+while(len&&iov->i<iov->used){+size_tpartlen=min(iov->iov[iov->i].iov_len,len);++iov->consumed+=partlen;+iov->iov[iov->i].iov_len-=partlen;+iov->iov[iov->i].iov_base+=partlen;++if(!iov->iov[iov->i].iov_len){+/* Fix up old iov element then increment. */+iov->iov[iov->i].iov_len=iov->consumed;+iov->iov[iov->i].iov_base-=iov->consumed;++iov->consumed=0;+iov->i++;+}++len-=partlen;+}+}+EXPORT_SYMBOL(vringh_kiov_advance);+/* Copy some bytes to/from the iovec. Returns num copied. */staticinlinessize_tvringh_iov_xfer(structvringh*vrh,structvringh_kiov*iov,
@@ -95,19 +123,8 @@ static inline ssize_t vringh_iov_xfer(struct vringh *vrh,done+=partlen;len-=partlen;ptr+=partlen;-iov->consumed+=partlen;-iov->iov[iov->i].iov_len-=partlen;-iov->iov[iov->i].iov_base+=partlen;-if(!iov->iov[iov->i].iov_len){-/* Fix up old iov element then increment. */-iov->iov[iov->i].iov_len=iov->consumed;-iov->iov[iov->i].iov_base-=iov->consumed;---iov->consumed=0;-iov->i++;-}+vringh_kiov_advance(iov,partlen);}returndone;}
This new helper returns the total number of bytes covered by
a vringh_kiov.
Suggested-by: Jason Wang <redacted>
Acked-by: Jason Wang <redacted>
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
---
include/linux/vringh.h | 11 +++++++++++
1 file changed, 11 insertions(+)
vringh_getdesc_iotlb() allocates memory to store the kvec, that
is freed with vringh_kiov_cleanup().
vringh_getdesc_iotlb() is able to reuse a kvec previously allocated,
so in order to avoid to allocate the kvec for each request, we are
not calling vringh_kiov_cleanup() when we finished to handle a
request, but we should call it when we free the entire device.
Acked-by: Jason Wang <redacted>
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
---
drivers/vdpa/vdpa_sim/vdpa_sim.c | 7 +++++++
1 file changed, 7 insertions(+)
This new callback is used to get the size of the configuration space
of vDPA devices.
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
---
include/linux/vdpa.h | 4 ++++
drivers/vdpa/ifcvf/ifcvf_main.c | 6 ++++++
drivers/vdpa/mlx5/net/mlx5_vnet.c | 6 ++++++
drivers/vdpa/vdpa_sim/vdpa_sim.c | 9 +++++++++
drivers/vdpa/virtio_pci/vp_vdpa.c | 8 ++++++++
5 files changed, 33 insertions(+)
From: Xie Yongji <redacted>
Since the config checks are done by the vDPA drivers, we can remove the
virtio-net restriction and we should be able to support all kinds of
virtio devices.
<linux/virtio_net.h> is not needed anymore, but we need to include
<linux/slab.h> to avoid compilation failures.
Signed-off-by: Xie Yongji <redacted>
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
---
drivers/vhost/vdpa.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
@@ -1018,10 +1018,6 @@ static int vhost_vdpa_probe(struct vdpa_device *vdpa)intminor;intr;-/* Currently, we only accept the network devices. */-if(ops->get_device_id(vdpa)!=VIRTIO_ID_NET)-return-ENOTSUPP;-v=kzalloc(sizeof(*v),GFP_KERNEL|__GFP_RETRY_MAYFAIL);if(!v)return-ENOMEM;
Let's use the new 'get_config_size()' callback available instead of
using the 'virtio_id' to get the size of the device config space.
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
---
drivers/vhost/vdpa.c | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)
From: Max Gurtovoy <mgurtovoy@nvidia.com>
This will allow running vDPA for virtio block protocol.
It's a preliminary implementation with a simple request handling:
for each request, only the status (last byte) is set.
It's always set to VIRTIO_BLK_S_OK.
Also input validation is missing and will be added in the next commits.
Signed-off-by: Max Gurtovoy <mgurtovoy@nvidia.com>
[sgarzare: various cleanups/fixes]
Acked-by: Jason Wang <redacted>
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
---
v4:
- include linux/blkdev.h to fix a build issue
- fix vdpa_register_device() passing the new 'nvqs' params
v3:
- updated Mellanox copyright to NVIDIA [Max]
- explained in the commit message that inputs are validated in subsequent
patches [Stefan]
v2:
- rebased on top of other changes (dev_attr, get_config(), notify(), etc.)
- memset to 0 the config structure in vdpasim_blk_get_config()
- used vdpasim pointer in vdpasim_blk_get_config()
v1:
- Removed unused headers
- Used cpu_to_vdpasim*() to store config fields
- Replaced 'select VDPA_SIM' with 'depends on VDPA_SIM' since selected
option can not depend on other [Jason]
- Start with a single queue for now [Jason]
- Add comments to memory barriers
---
drivers/vdpa/vdpa_sim/vdpa_sim_blk.c | 145 +++++++++++++++++++++++++++
drivers/vdpa/Kconfig | 7 ++
drivers/vdpa/vdpa_sim/Makefile | 1 +
3 files changed, 153 insertions(+)
create mode 100644 drivers/vdpa/vdpa_sim/vdpa_sim_blk.c
@@ -0,0 +1,145 @@+// SPDX-License-Identifier: GPL-2.0-only+/*+*VDPAsimulatorforblockdevice.+*+*Copyright(c)2020,NVIDIACORPORATION.Allrightsreserved.+*+*/++#include<linux/init.h>+#include<linux/module.h>+#include<linux/device.h>+#include<linux/kernel.h>+#include<linux/sched.h>+#include<linux/blkdev.h>+#include<linux/vringh.h>+#include<linux/vdpa.h>+#include<uapi/linux/virtio_blk.h>++#include"vdpa_sim.h"++#define DRV_VERSION "0.1"+#define DRV_AUTHOR "Max Gurtovoy <mgurtovoy@nvidia.com>"+#define DRV_DESC "vDPA Device Simulator for block device"+#define DRV_LICENSE "GPL v2"++#define VDPASIM_BLK_FEATURES (VDPASIM_FEATURES | \+(1ULL<<VIRTIO_BLK_F_SIZE_MAX)|\+(1ULL<<VIRTIO_BLK_F_SEG_MAX)|\+(1ULL<<VIRTIO_BLK_F_BLK_SIZE)|\+(1ULL<<VIRTIO_BLK_F_TOPOLOGY)|\+(1ULL<<VIRTIO_BLK_F_MQ))++#define VDPASIM_BLK_CAPACITY 0x40000+#define VDPASIM_BLK_SIZE_MAX 0x1000+#define VDPASIM_BLK_SEG_MAX 32+#define VDPASIM_BLK_VQ_NUM 1++staticstructvdpasim*vdpasim_blk_dev;++staticvoidvdpasim_blk_work(structwork_struct*work)+{+structvdpasim*vdpasim=container_of(work,structvdpasim,work);+u8status=VIRTIO_BLK_S_OK;+inti;++spin_lock(&vdpasim->lock);++if(!(vdpasim->status&VIRTIO_CONFIG_S_DRIVER_OK))+gotoout;++for(i=0;i<VDPASIM_BLK_VQ_NUM;i++){+structvdpasim_virtqueue*vq=&vdpasim->vqs[i];++if(!vq->ready)+continue;++while(vringh_getdesc_iotlb(&vq->vring,&vq->out_iov,+&vq->in_iov,&vq->head,+GFP_ATOMIC)>0){+intwrite;++vq->in_iov.i=vq->in_iov.used-1;+write=vringh_iov_push_iotlb(&vq->vring,&vq->in_iov,+&status,1);+if(write<=0)+break;++/* Make sure data is wrote before advancing index */+smp_wmb();++vringh_complete_iotlb(&vq->vring,vq->head,write);++/* Make sure used is visible before rasing the interrupt. */+smp_wmb();++local_bh_disable();+if(vringh_need_notify_iotlb(&vq->vring)>0)+vringh_notify(&vq->vring);+local_bh_enable();+}+}+out:+spin_unlock(&vdpasim->lock);+}++staticvoidvdpasim_blk_get_config(structvdpasim*vdpasim,void*config)+{+structvirtio_blk_config*blk_config=config;++memset(config,0,sizeof(structvirtio_blk_config));++blk_config->capacity=cpu_to_vdpasim64(vdpasim,VDPASIM_BLK_CAPACITY);+blk_config->size_max=cpu_to_vdpasim32(vdpasim,VDPASIM_BLK_SIZE_MAX);+blk_config->seg_max=cpu_to_vdpasim32(vdpasim,VDPASIM_BLK_SEG_MAX);+blk_config->num_queues=cpu_to_vdpasim16(vdpasim,VDPASIM_BLK_VQ_NUM);+blk_config->min_io_size=cpu_to_vdpasim16(vdpasim,1);+blk_config->opt_io_size=cpu_to_vdpasim32(vdpasim,1);+blk_config->blk_size=cpu_to_vdpasim32(vdpasim,SECTOR_SIZE);+}++staticint__initvdpasim_blk_init(void)+{+structvdpasim_dev_attrdev_attr={};+intret;++dev_attr.id=VIRTIO_ID_BLOCK;+dev_attr.supported_features=VDPASIM_BLK_FEATURES;+dev_attr.nvqs=VDPASIM_BLK_VQ_NUM;+dev_attr.config_size=sizeof(structvirtio_blk_config);+dev_attr.get_config=vdpasim_blk_get_config;+dev_attr.work_fn=vdpasim_blk_work;+dev_attr.buffer_size=PAGE_SIZE;++vdpasim_blk_dev=vdpasim_create(&dev_attr);+if(IS_ERR(vdpasim_blk_dev)){+ret=PTR_ERR(vdpasim_blk_dev);+gotoout;+}++ret=vdpa_register_device(&vdpasim_blk_dev->vdpa,VDPASIM_BLK_VQ_NUM);+if(ret)+gotoput_dev;++return0;++put_dev:+put_device(&vdpasim_blk_dev->vdpa.dev);+out:+returnret;+}++staticvoid__exitvdpasim_blk_exit(void)+{+structvdpa_device*vdpa=&vdpasim_blk_dev->vdpa;++vdpa_unregister_device(vdpa);+}++module_init(vdpasim_blk_init)+module_exit(vdpasim_blk_exit)++MODULE_VERSION(DRV_VERSION);+MODULE_LICENSE(DRV_LICENSE);+MODULE_AUTHOR(DRV_AUTHOR);+MODULE_DESCRIPTION(DRV_DESC);
Enable the user to create vDPA block simulator devices using the
vdpa management tool:
# Show vDPA supported devices
$ vdpa mgmtdev show
vdpasim_blk:
supported_classes block
# Create a vDPA block device named as 'blk0' from the management
# device vdpasim:
$ vdpa dev add mgmtdev vdpasim_blk name blk0
# Show the info of the 'blk0' device just created
$ vdpa dev show blk0 -jp
{
"dev": {
"blk0": {
"type": "block",
"mgmtdev": "vdpasim_blk",
"vendor_id": 0,
"max_vqs": 1,
"max_vq_size": 256
}
}
}
# Delete the vDPA device after its use
$ vdpa dev del blk0
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
---
drivers/vdpa/vdpa_sim/vdpa_sim_blk.c | 76 +++++++++++++++++++++++-----
1 file changed, 63 insertions(+), 13 deletions(-)
The previous implementation wrote only the status of each request.
This patch implements a more accurate block device simulator,
providing a ramdisk-like behavior and adding input validation.
Acked-by: Jason Wang <redacted>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
---
v2:
- used %zd %zx to print size_t and ssize_t variables in dev_err()
- removed unnecessary new line [Jason]
- moved VIRTIO_BLK_T_GET_ID in another patch [Jason]
- used push/pull instead of write/read terminology
- added vdpasim_blk_check_range() to avoid overflows [Stefan]
- use vdpasim*_to_cpu instead of le*_to_cpu
- used vringh_kiov_length() helper [Jason]
---
drivers/vdpa/vdpa_sim/vdpa_sim_blk.c | 164 ++++++++++++++++++++++++---
1 file changed, 146 insertions(+), 18 deletions(-)
@@ -37,10 +39,151 @@staticstructvdpasim*vdpasim_blk_dev;+staticboolvdpasim_blk_check_range(u64start_sector,size_trange_size)+{+u64range_sectors=range_size>>SECTOR_SHIFT;++if(range_size>VDPASIM_BLK_SIZE_MAX*VDPASIM_BLK_SEG_MAX)+returnfalse;++if(start_sector>VDPASIM_BLK_CAPACITY)+returnfalse;++if(range_sectors>VDPASIM_BLK_CAPACITY-start_sector)+returnfalse;++returntrue;+}++/* Returns 'true' if the request is handled (with or without an I/O error)+*andthestatusiscorrectlywritteninthelastbyteofthe'iniov',+*'false'otherwise.+*/+staticboolvdpasim_blk_handle_req(structvdpasim*vdpasim,+structvdpasim_virtqueue*vq)+{+size_tpushed=0,to_pull,to_push;+structvirtio_blk_outhdrhdr;+ssize_tbytes;+loff_toffset;+u64sector;+u8status;+u32type;+intret;++ret=vringh_getdesc_iotlb(&vq->vring,&vq->out_iov,&vq->in_iov,+&vq->head,GFP_ATOMIC);+if(ret!=1)+returnfalse;++if(vq->out_iov.used<1||vq->in_iov.used<1){+dev_err(&vdpasim->vdpa.dev,"missing headers - out_iov: %u in_iov %u\n",+vq->out_iov.used,vq->in_iov.used);+returnfalse;+}++if(vq->in_iov.iov[vq->in_iov.used-1].iov_len<1){+dev_err(&vdpasim->vdpa.dev,"request in header too short\n");+returnfalse;+}++/* The last byte is the status and we checked if the last iov has+*enoughroomforit.+*/+to_push=vringh_kiov_length(&vq->in_iov)-1;++to_pull=vringh_kiov_length(&vq->out_iov);++bytes=vringh_iov_pull_iotlb(&vq->vring,&vq->out_iov,&hdr,+sizeof(hdr));+if(bytes!=sizeof(hdr)){+dev_err(&vdpasim->vdpa.dev,"request out header too short\n");+returnfalse;+}++to_pull-=bytes;++type=vdpasim32_to_cpu(vdpasim,hdr.type);+sector=vdpasim64_to_cpu(vdpasim,hdr.sector);+offset=sector<<SECTOR_SHIFT;+status=VIRTIO_BLK_S_OK;++switch(type){+caseVIRTIO_BLK_T_IN:+if(!vdpasim_blk_check_range(sector,to_push)){+dev_err(&vdpasim->vdpa.dev,+"reading over the capacity - offset: 0x%llx len: 0x%zx\n",+offset,to_push);+status=VIRTIO_BLK_S_IOERR;+break;+}++bytes=vringh_iov_push_iotlb(&vq->vring,&vq->in_iov,+vdpasim->buffer+offset,+to_push);+if(bytes<0){+dev_err(&vdpasim->vdpa.dev,+"vringh_iov_push_iotlb() error: %zd offset: 0x%llx len: 0x%zx\n",+bytes,offset,to_push);+status=VIRTIO_BLK_S_IOERR;+break;+}++pushed+=bytes;+break;++caseVIRTIO_BLK_T_OUT:+if(!vdpasim_blk_check_range(sector,to_pull)){+dev_err(&vdpasim->vdpa.dev,+"writing over the capacity - offset: 0x%llx len: 0x%zx\n",+offset,to_pull);+status=VIRTIO_BLK_S_IOERR;+break;+}++bytes=vringh_iov_pull_iotlb(&vq->vring,&vq->out_iov,+vdpasim->buffer+offset,+to_pull);+if(bytes<0){+dev_err(&vdpasim->vdpa.dev,+"vringh_iov_pull_iotlb() error: %zd offset: 0x%llx len: 0x%zx\n",+bytes,offset,to_pull);+status=VIRTIO_BLK_S_IOERR;+break;+}+break;++default:+dev_warn(&vdpasim->vdpa.dev,+"Unsupported request type %d\n",type);+status=VIRTIO_BLK_S_IOERR;+break;+}++/* If some operations fail, we need to skip the remaining bytes+*toputthestatusinthelastbyte+*/+if(to_push-pushed>0)+vringh_kiov_advance(&vq->in_iov,to_push-pushed);++/* Last byte is the status */+bytes=vringh_iov_push_iotlb(&vq->vring,&vq->in_iov,&status,1);+if(bytes!=1)+returnfalse;++pushed+=bytes;++/* Make sure data is wrote before advancing index */+smp_wmb();++vringh_complete_iotlb(&vq->vring,vq->head,pushed);++returntrue;+}+staticvoidvdpasim_blk_work(structwork_struct*work){structvdpasim*vdpasim=container_of(work,structvdpasim,work);-u8status=VIRTIO_BLK_S_OK;inti;spin_lock(&vdpasim->lock);
@@ -54,22 +197,7 @@ static void vdpasim_blk_work(struct work_struct *work)if(!vq->ready)continue;-while(vringh_getdesc_iotlb(&vq->vring,&vq->out_iov,-&vq->in_iov,&vq->head,-GFP_ATOMIC)>0){-intwrite;--vq->in_iov.i=vq->in_iov.used-1;-write=vringh_iov_push_iotlb(&vq->vring,&vq->in_iov,-&status,1);-if(write<=0)-break;--/* Make sure data is wrote before advancing index */-smp_wmb();--vringh_complete_iotlb(&vq->vring,vq->head,write);-+while(vdpasim_blk_handle_req(vdpasim,vq)){/* Make sure used is visible before rasing the interrupt. */smp_wmb();
@@ -109,7 +237,7 @@ static int __init vdpasim_blk_init(void)dev_attr.config_size=sizeof(structvirtio_blk_config);dev_attr.get_config=vdpasim_blk_get_config;dev_attr.work_fn=vdpasim_blk_work;-dev_attr.buffer_size=PAGE_SIZE;+dev_attr.buffer_size=VDPASIM_BLK_CAPACITY<<SECTOR_SHIFT;vdpasim_blk_dev=vdpasim_create(&dev_attr);if(IS_ERR(vdpasim_blk_dev)){
This new helper returns the total number of bytes covered by
a vringh_kiov.
Suggested-by: Jason Wang <redacted>
Acked-by: Jason Wang <redacted>
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
---
include/linux/vringh.h | 11 +++++++++++
1 file changed, 11 insertions(+)
Do we really need an helper?
For instance, we can use:
len = iov_length((struct iovec *)kiov->iov, kiov->used);
Or do we want to avoid the cast?
Thanks,
Laurent
On Mon, Mar 15, 2021 at 05:51:30PM +0100, Laurent Vivier wrote:
On 15/03/2021 17:34, Stefano Garzarella wrote:
quoted
This new helper returns the total number of bytes covered by
a vringh_kiov.
Suggested-by: Jason Wang <redacted>
Acked-by: Jason Wang <redacted>
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
---
include/linux/vringh.h | 11 +++++++++++
1 file changed, 11 insertions(+)
Do we really need an helper?
For instance, we can use:
len = iov_length((struct iovec *)kiov->iov, kiov->used);
Or do we want to avoid the cast?
Yes, that should be fine. If we want, I can remove the helper and use
iov_length() directly. I thought vringh wanted to hide iovec from users
though.
Anyway talking to Jason, as a long term solution we should reconsider
vringh and support iov_iter.
Thanks,
Stefano
From: Jason Wang <hidden> Date: 2021-03-18 03:23:41
在 2021/3/16 上午12:34, Stefano Garzarella 写道:
Let's use the new 'get_config_size()' callback available instead of
using the 'virtio_id' to get the size of the device config space.
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
From: Jason Wang <hidden> Date: 2021-03-18 03:25:20
在 2021/3/16 上午12:34, Stefano Garzarella 写道:
From: Xie Yongji <redacted>
Since the config checks are done by the vDPA drivers, we can remove the
virtio-net restriction and we should be able to support all kinds of
virtio devices.
<linux/virtio_net.h> is not needed anymore, but we need to include
<linux/slab.h> to avoid compilation failures.
Signed-off-by: Xie Yongji <redacted>
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
@@ -1018,10 +1018,6 @@ static int vhost_vdpa_probe(struct vdpa_device *vdpa)intminor;intr;-/* Currently, we only accept the network devices. */-if(ops->get_device_id(vdpa)!=VIRTIO_ID_NET)-return-ENOTSUPP;-v=kzalloc(sizeof(*v),GFP_KERNEL|__GFP_RETRY_MAYFAIL);if(!v)return-ENOMEM;
From: Jason Wang <hidden> Date: 2021-03-18 03:33:39
在 2021/3/16 上午12:34, Stefano Garzarella 写道:
Enable the user to create vDPA block simulator devices using the
vdpa management tool:
# Show vDPA supported devices
$ vdpa mgmtdev show
vdpasim_blk:
supported_classes block
# Create a vDPA block device named as 'blk0' from the management
# device vdpasim:
$ vdpa dev add mgmtdev vdpasim_blk name blk0
# Show the info of the 'blk0' device just created
$ vdpa dev show blk0 -jp
{
"dev": {
"blk0": {
"type": "block",
"mgmtdev": "vdpasim_blk",
"vendor_id": 0,
"max_vqs": 1,
"max_vq_size": 256
}
}
}
# Delete the vDPA device after its use
$ vdpa dev del blk0
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
Hi Michael,
do you think this series is in an acceptable state to be queued for the
next merge window?
All patches should be already acked by Jason, let me know if I need to
change anything.
Thanks,
Stefano
On Mon, Mar 15, 2021 at 05:34:36PM +0100, Stefano Garzarella wrote:
v4:
- added support for iproute2 vdpa management tool in vdpa_sim_blk
- removed get/set_config patches
- 'vdpa: add return value to get_config/set_config callbacks'
- 'vhost/vdpa: remove vhost_vdpa_config_validate()'
- added get_config_size() patches
- 'vdpa: add get_config_size callback in vdpa_config_ops'
- 'vhost/vdpa: use get_config_size callback in vhost_vdpa_config_validate()'
v3: https://lore.kernel.org/lkml/20210204172230.85853-1-sgarzare@redhat.com/
v2: https://lore.kernel.org/lkml/20210128144127.113245-1-sgarzare@redhat.com/
v1: https://lore.kernel.org/lkml/93f207c0-61e6-3696-f218-e7d7ea9a7c93@redhat.com/
This series is the second part of the v1 linked above. The first part with
refactoring of vdpa_sim has already been merged.
The patches are based on Max Gurtovoy's work and extend the block simulator to
have a ramdisk behaviour.
As mentioned in the v1 there was 2 issues and I fixed them in this series:
1. The identical mapping in the IOMMU used until now in vdpa_sim created issues
when mapping different virtual pages with the same physical address.
Fixed by patch "vdpa_sim: use iova module to allocate IOVA addresses"
2. There was a race accessing the IOMMU between the vdpasim_blk_work() and the
device driver that map/unmap DMA regions. Fixed by patch "vringh: add
'iotlb_lock' to synchronize iotlb accesses"
I used the Xie's patch coming from VDUSE series to allow vhost-vdpa to use
block devices, and I added get_config_size() callback to allow any device
in vhost-vdpa.
The series also includes small fixes for vringh, vdpa, and vdpa_sim that I
discovered while implementing and testing the block simulator.
Thanks for your feedback,
Stefano
Max Gurtovoy (1):
vdpa: add vdpa simulator for block device
Stefano Garzarella (12):
vdpa_sim: use iova module to allocate IOVA addresses
vringh: add 'iotlb_lock' to synchronize iotlb accesses
vringh: reset kiov 'consumed' field in __vringh_iov()
vringh: explain more about cleaning riov and wiov
vringh: implement vringh_kiov_advance()
vringh: add vringh_kiov_length() helper
vdpa_sim: cleanup kiovs in vdpasim_free()
vdpa: add get_config_size callback in vdpa_config_ops
vhost/vdpa: use get_config_size callback in
vhost_vdpa_config_validate()
vdpa_sim_blk: implement ramdisk behaviour
vdpa_sim_blk: handle VIRTIO_BLK_T_GET_ID
vdpa_sim_blk: add support for vdpa management tool
Xie Yongji (1):
vhost/vdpa: Remove the restriction that only supports virtio-net
devices
drivers/vdpa/vdpa_sim/vdpa_sim.h | 2 +
include/linux/vdpa.h | 4 +
include/linux/vringh.h | 19 +-
drivers/vdpa/ifcvf/ifcvf_main.c | 6 +
drivers/vdpa/mlx5/net/mlx5_vnet.c | 6 +
drivers/vdpa/vdpa_sim/vdpa_sim.c | 127 ++++++----
drivers/vdpa/vdpa_sim/vdpa_sim_blk.c | 338 +++++++++++++++++++++++++++
drivers/vdpa/virtio_pci/vp_vdpa.c | 8 +
drivers/vhost/vdpa.c | 15 +-
drivers/vhost/vringh.c | 69 ++++--
drivers/vdpa/Kconfig | 8 +
drivers/vdpa/vdpa_sim/Makefile | 1 +
12 files changed, 529 insertions(+), 74 deletions(-)
create mode 100644 drivers/vdpa/vdpa_sim/vdpa_sim_blk.c
--
2.30.2
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization