mirror of
https://github.com/Motorhead1991/qemu.git
synced 2026-03-04 09:04:39 -07:00
vfio: Move dirty tracking related services into container-base.c
Routines of common.c : vfio_devices_all_dirty_tracking_started vfio_devices_all_device_dirty_tracking vfio_devices_query_dirty_bitmap vfio_get_dirty_bitmap are all related to dirty page tracking directly at the container level or at the container device level. Naming is a bit confusing. We will propose new names in the following changes. Reviewed-by: Joao Martins <joao.m.martins@oracle.com> Reviewed-by: Avihai Horon <avihaih@nvidia.com> Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-27-clg@redhat.com Signed-off-by: Cédric Le Goater <clg@redhat.com>
This commit is contained in:
parent
819a5865c0
commit
6b7c812972
6 changed files with 149 additions and 141 deletions
130
hw/vfio/common.c
130
hw/vfio/common.c
|
|
@ -51,27 +51,6 @@
|
|||
*/
|
||||
|
||||
|
||||
static bool vfio_devices_all_device_dirty_tracking_started(
|
||||
const VFIOContainerBase *bcontainer)
|
||||
{
|
||||
VFIODevice *vbasedev;
|
||||
|
||||
QLIST_FOREACH(vbasedev, &bcontainer->device_list, container_next) {
|
||||
if (!vbasedev->dirty_tracking) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vfio_devices_all_dirty_tracking_started(
|
||||
const VFIOContainerBase *bcontainer)
|
||||
{
|
||||
return vfio_devices_all_device_dirty_tracking_started(bcontainer) ||
|
||||
bcontainer->dirty_pages_started;
|
||||
}
|
||||
|
||||
static bool vfio_log_sync_needed(const VFIOContainerBase *bcontainer)
|
||||
{
|
||||
VFIODevice *vbasedev;
|
||||
|
|
@ -96,22 +75,6 @@ static bool vfio_log_sync_needed(const VFIOContainerBase *bcontainer)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool vfio_devices_all_device_dirty_tracking(const VFIOContainerBase *bcontainer)
|
||||
{
|
||||
VFIODevice *vbasedev;
|
||||
|
||||
QLIST_FOREACH(vbasedev, &bcontainer->device_list, container_next) {
|
||||
if (vbasedev->device_dirty_page_tracking == ON_OFF_AUTO_OFF) {
|
||||
return false;
|
||||
}
|
||||
if (!vbasedev->dirty_pages_supported) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool vfio_listener_skipped_section(MemoryRegionSection *section)
|
||||
{
|
||||
return (!memory_region_is_ram(section->mr) &&
|
||||
|
|
@ -1009,99 +972,6 @@ static void vfio_listener_log_global_stop(MemoryListener *listener)
|
|||
}
|
||||
}
|
||||
|
||||
static int vfio_device_dma_logging_report(VFIODevice *vbasedev, hwaddr iova,
|
||||
hwaddr size, void *bitmap)
|
||||
{
|
||||
uint64_t buf[DIV_ROUND_UP(sizeof(struct vfio_device_feature) +
|
||||
sizeof(struct vfio_device_feature_dma_logging_report),
|
||||
sizeof(uint64_t))] = {};
|
||||
struct vfio_device_feature *feature = (struct vfio_device_feature *)buf;
|
||||
struct vfio_device_feature_dma_logging_report *report =
|
||||
(struct vfio_device_feature_dma_logging_report *)feature->data;
|
||||
|
||||
report->iova = iova;
|
||||
report->length = size;
|
||||
report->page_size = qemu_real_host_page_size();
|
||||
report->bitmap = (uintptr_t)bitmap;
|
||||
|
||||
feature->argsz = sizeof(buf);
|
||||
feature->flags = VFIO_DEVICE_FEATURE_GET |
|
||||
VFIO_DEVICE_FEATURE_DMA_LOGGING_REPORT;
|
||||
|
||||
if (ioctl(vbasedev->fd, VFIO_DEVICE_FEATURE, feature)) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vfio_devices_query_dirty_bitmap(const VFIOContainerBase *bcontainer,
|
||||
VFIOBitmap *vbmap, hwaddr iova, hwaddr size, Error **errp)
|
||||
{
|
||||
VFIODevice *vbasedev;
|
||||
int ret;
|
||||
|
||||
QLIST_FOREACH(vbasedev, &bcontainer->device_list, container_next) {
|
||||
ret = vfio_device_dma_logging_report(vbasedev, iova, size,
|
||||
vbmap->bitmap);
|
||||
if (ret) {
|
||||
error_setg_errno(errp, -ret,
|
||||
"%s: Failed to get DMA logging report, iova: "
|
||||
"0x%" HWADDR_PRIx ", size: 0x%" HWADDR_PRIx,
|
||||
vbasedev->name, iova, size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vfio_get_dirty_bitmap(const VFIOContainerBase *bcontainer, uint64_t iova,
|
||||
uint64_t size, ram_addr_t ram_addr, Error **errp)
|
||||
{
|
||||
bool all_device_dirty_tracking =
|
||||
vfio_devices_all_device_dirty_tracking(bcontainer);
|
||||
uint64_t dirty_pages;
|
||||
VFIOBitmap vbmap;
|
||||
int ret;
|
||||
|
||||
if (!bcontainer->dirty_pages_supported && !all_device_dirty_tracking) {
|
||||
cpu_physical_memory_set_dirty_range(ram_addr, size,
|
||||
tcg_enabled() ? DIRTY_CLIENTS_ALL :
|
||||
DIRTY_CLIENTS_NOCODE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = vfio_bitmap_alloc(&vbmap, size);
|
||||
if (ret) {
|
||||
error_setg_errno(errp, -ret,
|
||||
"Failed to allocate dirty tracking bitmap");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (all_device_dirty_tracking) {
|
||||
ret = vfio_devices_query_dirty_bitmap(bcontainer, &vbmap, iova, size,
|
||||
errp);
|
||||
} else {
|
||||
ret = vfio_container_query_dirty_bitmap(bcontainer, &vbmap, iova, size,
|
||||
errp);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
dirty_pages = cpu_physical_memory_set_dirty_lebitmap(vbmap.bitmap, ram_addr,
|
||||
vbmap.pages);
|
||||
|
||||
trace_vfio_get_dirty_bitmap(iova, size, vbmap.size, ram_addr, dirty_pages);
|
||||
out:
|
||||
g_free(vbmap.bitmap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
IOMMUNotifier n;
|
||||
VFIOGuestIOMMU *giommu;
|
||||
|
|
|
|||
|
|
@ -10,12 +10,20 @@
|
|||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/vfio.h>
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "system/tcg.h"
|
||||
#include "system/ram_addr.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/vfio/vfio-container-base.h"
|
||||
#include "hw/vfio/vfio-common.h" /* vfio_reset_handler */
|
||||
#include "system/reset.h"
|
||||
#include "vfio-helpers.h"
|
||||
|
||||
#include "trace.h"
|
||||
|
||||
static QLIST_HEAD(, VFIOAddressSpace) vfio_address_spaces =
|
||||
QLIST_HEAD_INITIALIZER(vfio_address_spaces);
|
||||
|
|
@ -143,6 +151,136 @@ int vfio_container_query_dirty_bitmap(const VFIOContainerBase *bcontainer,
|
|||
errp);
|
||||
}
|
||||
|
||||
static bool vfio_devices_all_device_dirty_tracking_started(
|
||||
const VFIOContainerBase *bcontainer)
|
||||
{
|
||||
VFIODevice *vbasedev;
|
||||
|
||||
QLIST_FOREACH(vbasedev, &bcontainer->device_list, container_next) {
|
||||
if (!vbasedev->dirty_tracking) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vfio_devices_all_dirty_tracking_started(
|
||||
const VFIOContainerBase *bcontainer)
|
||||
{
|
||||
return vfio_devices_all_device_dirty_tracking_started(bcontainer) ||
|
||||
bcontainer->dirty_pages_started;
|
||||
}
|
||||
|
||||
bool vfio_devices_all_device_dirty_tracking(const VFIOContainerBase *bcontainer)
|
||||
{
|
||||
VFIODevice *vbasedev;
|
||||
|
||||
QLIST_FOREACH(vbasedev, &bcontainer->device_list, container_next) {
|
||||
if (vbasedev->device_dirty_page_tracking == ON_OFF_AUTO_OFF) {
|
||||
return false;
|
||||
}
|
||||
if (!vbasedev->dirty_pages_supported) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int vfio_device_dma_logging_report(VFIODevice *vbasedev, hwaddr iova,
|
||||
hwaddr size, void *bitmap)
|
||||
{
|
||||
uint64_t buf[DIV_ROUND_UP(sizeof(struct vfio_device_feature) +
|
||||
sizeof(struct vfio_device_feature_dma_logging_report),
|
||||
sizeof(uint64_t))] = {};
|
||||
struct vfio_device_feature *feature = (struct vfio_device_feature *)buf;
|
||||
struct vfio_device_feature_dma_logging_report *report =
|
||||
(struct vfio_device_feature_dma_logging_report *)feature->data;
|
||||
|
||||
report->iova = iova;
|
||||
report->length = size;
|
||||
report->page_size = qemu_real_host_page_size();
|
||||
report->bitmap = (uintptr_t)bitmap;
|
||||
|
||||
feature->argsz = sizeof(buf);
|
||||
feature->flags = VFIO_DEVICE_FEATURE_GET |
|
||||
VFIO_DEVICE_FEATURE_DMA_LOGGING_REPORT;
|
||||
|
||||
if (ioctl(vbasedev->fd, VFIO_DEVICE_FEATURE, feature)) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vfio_devices_query_dirty_bitmap(const VFIOContainerBase *bcontainer,
|
||||
VFIOBitmap *vbmap, hwaddr iova, hwaddr size, Error **errp)
|
||||
{
|
||||
VFIODevice *vbasedev;
|
||||
int ret;
|
||||
|
||||
QLIST_FOREACH(vbasedev, &bcontainer->device_list, container_next) {
|
||||
ret = vfio_device_dma_logging_report(vbasedev, iova, size,
|
||||
vbmap->bitmap);
|
||||
if (ret) {
|
||||
error_setg_errno(errp, -ret,
|
||||
"%s: Failed to get DMA logging report, iova: "
|
||||
"0x%" HWADDR_PRIx ", size: 0x%" HWADDR_PRIx,
|
||||
vbasedev->name, iova, size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vfio_get_dirty_bitmap(const VFIOContainerBase *bcontainer, uint64_t iova,
|
||||
uint64_t size, ram_addr_t ram_addr, Error **errp)
|
||||
{
|
||||
bool all_device_dirty_tracking =
|
||||
vfio_devices_all_device_dirty_tracking(bcontainer);
|
||||
uint64_t dirty_pages;
|
||||
VFIOBitmap vbmap;
|
||||
int ret;
|
||||
|
||||
if (!bcontainer->dirty_pages_supported && !all_device_dirty_tracking) {
|
||||
cpu_physical_memory_set_dirty_range(ram_addr, size,
|
||||
tcg_enabled() ? DIRTY_CLIENTS_ALL :
|
||||
DIRTY_CLIENTS_NOCODE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = vfio_bitmap_alloc(&vbmap, size);
|
||||
if (ret) {
|
||||
error_setg_errno(errp, -ret,
|
||||
"Failed to allocate dirty tracking bitmap");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (all_device_dirty_tracking) {
|
||||
ret = vfio_devices_query_dirty_bitmap(bcontainer, &vbmap, iova, size,
|
||||
errp);
|
||||
} else {
|
||||
ret = vfio_container_query_dirty_bitmap(bcontainer, &vbmap, iova, size,
|
||||
errp);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
dirty_pages = cpu_physical_memory_set_dirty_lebitmap(vbmap.bitmap, ram_addr,
|
||||
vbmap.pages);
|
||||
|
||||
trace_vfio_get_dirty_bitmap(iova, size, vbmap.size, ram_addr, dirty_pages);
|
||||
out:
|
||||
g_free(vbmap.bitmap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gpointer copy_iova_range(gconstpointer src, gpointer data)
|
||||
{
|
||||
Range *source = (Range *)src;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
vfio_ss = ss.source_set()
|
||||
vfio_ss.add(files(
|
||||
'common.c',
|
||||
'container-base.c',
|
||||
'container.c',
|
||||
'helpers.c',
|
||||
))
|
||||
|
|
@ -19,7 +20,6 @@ specific_ss.add_all(when: 'CONFIG_VFIO', if_true: vfio_ss)
|
|||
system_ss.add(when: 'CONFIG_VFIO_XGMAC', if_true: files('calxeda-xgmac.c'))
|
||||
system_ss.add(when: 'CONFIG_VFIO_AMD_XGBE', if_true: files('amd-xgbe.c'))
|
||||
system_ss.add(when: 'CONFIG_VFIO', if_true: files(
|
||||
'container-base.c',
|
||||
'cpr.c',
|
||||
'device.c',
|
||||
'migration.c',
|
||||
|
|
|
|||
|
|
@ -106,9 +106,11 @@ vfio_put_group(int fd) "close group->fd=%d"
|
|||
vfio_get_device(const char * name, unsigned int flags, unsigned int num_regions, unsigned int num_irqs) "Device %s flags: %u, regions: %u, irqs: %u"
|
||||
vfio_put_base_device(int fd) "close vdev->fd=%d"
|
||||
vfio_legacy_dma_unmap_overflow_workaround(void) ""
|
||||
vfio_get_dirty_bitmap(uint64_t iova, uint64_t size, uint64_t bitmap_size, uint64_t start, uint64_t dirty_pages) "iova=0x%"PRIx64" size= 0x%"PRIx64" bitmap_size=0x%"PRIx64" start=0x%"PRIx64" dirty_pages=%"PRIu64
|
||||
vfio_iommu_map_dirty_notify(uint64_t iova_start, uint64_t iova_end) "iommu dirty @ 0x%"PRIx64" - 0x%"PRIx64
|
||||
|
||||
# container-base.c
|
||||
vfio_get_dirty_bitmap(uint64_t iova, uint64_t size, uint64_t bitmap_size, uint64_t start, uint64_t dirty_pages) "iova=0x%"PRIx64" size= 0x%"PRIx64" bitmap_size=0x%"PRIx64" start=0x%"PRIx64" dirty_pages=%"PRIu64
|
||||
|
||||
# region.c
|
||||
vfio_region_write(const char *name, int index, uint64_t addr, uint64_t data, unsigned size) " (%s:region%d+0x%"PRIx64", 0x%"PRIx64 ", %d)"
|
||||
vfio_region_read(char *name, int index, uint64_t addr, unsigned size, uint64_t data) " (%s:region%d+0x%"PRIx64", %d) = 0x%"PRIx64
|
||||
|
|
|
|||
|
|
@ -141,15 +141,6 @@ int vfio_get_dev_region_info(VFIODevice *vbasedev, uint32_t type,
|
|||
bool vfio_has_region_cap(VFIODevice *vbasedev, int region, uint16_t cap_type);
|
||||
#endif
|
||||
|
||||
bool vfio_devices_all_dirty_tracking_started(
|
||||
const VFIOContainerBase *bcontainer);
|
||||
bool
|
||||
vfio_devices_all_device_dirty_tracking(const VFIOContainerBase *bcontainer);
|
||||
int vfio_devices_query_dirty_bitmap(const VFIOContainerBase *bcontainer,
|
||||
VFIOBitmap *vbmap, hwaddr iova, hwaddr size, Error **errp);
|
||||
int vfio_get_dirty_bitmap(const VFIOContainerBase *bcontainer, uint64_t iova,
|
||||
uint64_t size, ram_addr_t ram_addr, Error **errp);
|
||||
|
||||
/* Returns 0 on success, or a negative errno. */
|
||||
bool vfio_device_get_name(VFIODevice *vbasedev, Error **errp);
|
||||
void vfio_device_set_fd(VFIODevice *vbasedev, const char *str, Error **errp);
|
||||
|
|
|
|||
|
|
@ -91,6 +91,13 @@ int vfio_container_set_dirty_page_tracking(VFIOContainerBase *bcontainer,
|
|||
bool start, Error **errp);
|
||||
int vfio_container_query_dirty_bitmap(const VFIOContainerBase *bcontainer,
|
||||
VFIOBitmap *vbmap, hwaddr iova, hwaddr size, Error **errp);
|
||||
bool vfio_devices_all_dirty_tracking_started(const VFIOContainerBase *bcontainer);
|
||||
bool vfio_devices_all_device_dirty_tracking(const VFIOContainerBase *bcontainer);
|
||||
int vfio_devices_query_dirty_bitmap(const VFIOContainerBase *bcontainer,
|
||||
VFIOBitmap *vbmap, hwaddr iova, hwaddr size,
|
||||
Error **errp);
|
||||
int vfio_get_dirty_bitmap(const VFIOContainerBase *bcontainer, uint64_t iova,
|
||||
uint64_t size, ram_addr_t ram_addr, Error **errp);
|
||||
|
||||
GList *vfio_container_get_iova_ranges(const VFIOContainerBase *bcontainer);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue