dmop: add xendevicemodel_modified_memory_bulk()

This new lib devicemodel call allows multiple extents of pages to be
marked as modified in a single call.  This is something needed for a
usecase I'm working on.

The xen side of the modified_memory call has been modified to accept
an array of extents.  The devicemodel library either provides an array
of length 1, to support the original library function, or a second
function allows an array to be provided.

Signed-off-by: Jennifer Herbert <Jennifer.Herbert@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Paul Durrant <paul.durrant@citrix.com>
Acked-by: Wei Liu <wei.liu2@citrix.com>
Release-acked-by: Julien Grall <julien.grall@arm.com>
This commit is contained in:
Jennifer Herbert authored and Jan Beulich committed 2017-04-26 09:47:30 +02:00
1 parent a579c8bcf3
commit e3b93b3c59
4 files changed
+134 -51

No files matched your search

+22 -8
View File
@@ -459,22 +459,36 @@ int xendevicemodel_track_dirty_vram(
dirty_bitmap, (size_t)(nr + 7) / 8);
}
int xendevicemodel_modified_memory(
xendevicemodel_handle *dmod, domid_t domid, uint64_t first_pfn,
uint32_t nr)
int xendevicemodel_modified_memory_bulk(
xendevicemodel_handle *dmod, domid_t domid,
struct xen_dm_op_modified_memory_extent *extents, uint32_t nr)
{
struct xen_dm_op op;
struct xen_dm_op_modified_memory *data;
struct xen_dm_op_modified_memory *header;
size_t extents_size = nr * sizeof(struct xen_dm_op_modified_memory_extent);
memset(&op, 0, sizeof(op));
op.op = XEN_DMOP_modified_memory;
data = &op.u.modified_memory;
header = &op.u.modified_memory;
data->first_pfn = first_pfn;
data->nr = nr;
header->nr_extents = nr;
header->opaque = 0;
return xendevicemodel_op(dmod, domid, 1, &op, sizeof(op));
return xendevicemodel_op(dmod, domid, 2, &op, sizeof(op),
extents, extents_size);
}
int xendevicemodel_modified_memory(
xendevicemodel_handle *dmod, domid_t domid, uint64_t first_pfn,
uint32_t nr)
{
struct xen_dm_op_modified_memory_extent extent;
extent.first_pfn = first_pfn;
extent.nr = nr;
return xendevicemodel_modified_memory_bulk(dmod, domid, &extent, 1);
}
int xendevicemodel_set_mem_type(
@@ -254,8 +254,8 @@ int xendevicemodel_track_dirty_vram(
uint32_t nr, unsigned long *dirty_bitmap);
/**
* This function notifies the hypervisor that a set of domain pages
* have been modified.
* This function notifies the hypervisor that a set of contiguous
* domain pages have been modified.
*
* @parm dmod a handle to an open devicemodel interface.
* @parm domid the domain id to be serviced
@@ -267,6 +267,21 @@ int xendevicemodel_modified_memory(
xendevicemodel_handle *dmod, domid_t domid, uint64_t first_pfn,
uint32_t nr);
/**
* This function notifies the hypervisor that a set of discontiguous
* domain pages have been modified.
*
* @parm dmod a handle to an open devicemodel interface.
* @parm domid the domain id to be serviced
* @parm extents an array of extent structs, which each hold
a start_pfn and nr (number of pfns).
* @parm nr the number of extents in the array
* @return 0 on success, -1 on failure.
*/
int xendevicemodel_modified_memory_bulk(
xendevicemodel_handle *dmod, domid_t domid,
struct xen_dm_op_modified_memory_extent extents[], uint32_t nr);
/**
* This function notifies the hypervisor that a set of domain pages
* are to be treated in a specific way. (See the definition of
+79 -38
View File
@@ -153,56 +153,102 @@ static int set_isa_irq_level(struct domain *d, uint8_t isa_irq,
}
static int modified_memory(struct domain *d,
struct xen_dm_op_modified_memory *data)
const struct dmop_args *bufs,
struct xen_dm_op_modified_memory *header)
{
xen_pfn_t last_pfn = data->first_pfn + data->nr - 1;
unsigned int iter = 0;
int rc = 0;
#define EXTENTS_BUFFER 1
if ( (data->first_pfn > last_pfn) ||
(last_pfn > domain_get_maximum_gpfn(d)) )
return -EINVAL;
/* Process maximum of 256 pfns before checking for continuation. */
const unsigned int cont_check_interval = 0x100;
unsigned int *rem_extents = &header->nr_extents;
unsigned int batch_rem_pfns = cont_check_interval;
/* Used for continuation. */
unsigned int *pfns_done = &header->opaque;
if ( !paging_mode_log_dirty(d) )
return 0;
while ( iter < data->nr )
if ( (bufs->buf[EXTENTS_BUFFER].size /
sizeof(struct xen_dm_op_modified_memory_extent)) <
*rem_extents )
return -EINVAL;
while ( *rem_extents > 0 )
{
unsigned long pfn = data->first_pfn + iter;
struct page_info *page;
struct xen_dm_op_modified_memory_extent extent;
unsigned int batch_nr;
xen_pfn_t pfn, end_pfn;
int rc;
page = get_page_from_gfn(d, pfn, NULL, P2M_UNSHARE);
if ( page )
rc = COPY_FROM_GUEST_BUF_OFFSET(extent,
bufs, EXTENTS_BUFFER, (*rem_extents - 1) * sizeof(extent));
if ( rc )
return -EFAULT;
if ( extent.pad )
return -EINVAL;
end_pfn = extent.first_pfn + extent.nr;
if ( end_pfn <= extent.first_pfn ||
end_pfn > domain_get_maximum_gpfn(d) )
return -EINVAL;
if ( *pfns_done >= extent.nr )
return -EINVAL;
pfn = extent.first_pfn + *pfns_done;
batch_nr = extent.nr - *pfns_done;
if ( batch_nr > batch_rem_pfns )
{
mfn_t gmfn = _mfn(page_to_mfn(page));
paging_mark_dirty(d, gmfn);
/*
* These are most probably not page tables any more
* don't take a long time and don't die either.
*/
sh_remove_shadows(d, gmfn, 1, 0);
put_page(page);
batch_nr = batch_rem_pfns;
*pfns_done += batch_nr;
end_pfn = pfn + batch_nr;
}
else
{
(*rem_extents)--;
*pfns_done = 0;
}
iter++;
batch_rem_pfns -= batch_nr;
for ( ; pfn < end_pfn; pfn++ )
{
struct page_info *page;
page = get_page_from_gfn(d, pfn, NULL, P2M_UNSHARE);
if ( page )
{
mfn_t gmfn = _mfn(page_to_mfn(page));
paging_mark_dirty(d, gmfn);
/*
* These are most probably not page tables any more
* don't take a long time and don't die either.
*/
sh_remove_shadows(d, gmfn, 1, 0);
put_page(page);
}
}
/*
* Check for continuation every 256th iteration and if the
* iteration is not the last.
* After a full batch of cont_check_interval pfns
* have been processed, and there are still extents
* remaining to process, check for continuation.
*/
if ( (iter < data->nr) && ((iter & 0xff) == 0) &&
hypercall_preempt_check() )
if ( (batch_rem_pfns == 0) && (*rem_extents > 0) )
{
data->first_pfn += iter;
data->nr -= iter;
if ( hypercall_preempt_check() )
return -ERESTART;
rc = -ERESTART;
break;
batch_rem_pfns = cont_check_interval;
}
}
return 0;
return rc;
#undef EXTENTS_BUFFER
}
static bool allow_p2m_type_change(p2m_type_t old, p2m_type_t new)
@@ -539,13 +585,8 @@ static int dm_op(const struct dmop_args *op_args)
struct xen_dm_op_modified_memory *data =
&op.u.modified_memory;
const_op = false;
rc = -EINVAL;
if ( data->pad )
break;
rc = modified_memory(d, data);
rc = modified_memory(d, op_args, data);
const_op = !rc;
break;
}
+16 -3
View File
@@ -237,13 +237,26 @@ struct xen_dm_op_set_pci_link_route {
* XEN_DMOP_modified_memory: Notify that a set of pages were modified by
* an emulator.
*
* NOTE: In the event of a continuation, the @first_pfn is set to the
* value of the pfn of the remaining set of pages and @nr reduced
* to the size of the remaining set.
* DMOP buf 1 contains an array of xen_dm_op_modified_memory_extent with
* @nr_extents entries.
*
* On error, @nr_extents will contain the index+1 of the extent that
* had the error. It is not defined if or which pages may have been
* marked as dirty, in this event.
*/
#define XEN_DMOP_modified_memory 11
struct xen_dm_op_modified_memory {
/*
* IN - Number of extents to be processed
* OUT -returns n+1 for failing extent
*/
uint32_t nr_extents;
/* IN/OUT - Must be set to 0 */
uint32_t opaque;
};
struct xen_dm_op_modified_memory_extent {
/* IN - number of contiguous pages modified */
uint32_t nr;
uint32_t pad;
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.