dm_op: convert HVMOP_modified_memory

This patch introduces code to handle DMOP continuations.

NOTE: This patch also modifies the type of the 'nr' argument of
      xc_hvm_modified_memory() from uint64_t to uint32_t. In practice the
      value passed was always truncated to 32 bits.

Suggested-by: Jan Beulich <jbeulich@suse.com>
Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
Acked-by: Wei Liu <wei.liu2@citrix.com>
Acked-by: Daniel De Graaf <dgdegra@tycho.nsa.gov>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
This commit is contained in:
Paul Durrant authored and Jan Beulich committed 2017-01-25 10:47:13 +01:00
1 parent 7b2e218fd6
commit b30c5979e0
8 files changed
+118 -96

No files matched your search

+1 -1
View File
@@ -1627,7 +1627,7 @@ int xc_hvm_track_dirty_vram(
* Notify that some pages got modified by the Device Model
*/
int xc_hvm_modified_memory(
xc_interface *xch, domid_t dom, uint64_t first_pfn, uint64_t nr);
xc_interface *xch, domid_t dom, uint64_t first_pfn, uint32_t nr);
/*
* Set a range of memory to a specific type.
+9 -18
View File
@@ -573,29 +573,20 @@ int xc_hvm_track_dirty_vram(
}
int xc_hvm_modified_memory(
xc_interface *xch, domid_t dom, uint64_t first_pfn, uint64_t nr)
xc_interface *xch, domid_t dom, uint64_t first_pfn, uint32_t nr)
{
DECLARE_HYPERCALL_BUFFER(struct xen_hvm_modified_memory, arg);
int rc;
struct xen_dm_op op;
struct xen_dm_op_modified_memory *data;
arg = xc_hypercall_buffer_alloc(xch, arg, sizeof(*arg));
if ( arg == NULL )
{
PERROR("Could not allocate memory for xc_hvm_modified_memory hypercall");
return -1;
}
memset(&op, 0, sizeof(op));
arg->domid = dom;
arg->first_pfn = first_pfn;
arg->nr = nr;
op.op = XEN_DMOP_modified_memory;
data = &op.u.modified_memory;
rc = xencall2(xch->xcall, __HYPERVISOR_hvm_op,
HVMOP_modified_memory,
HYPERCALL_BUFFER_AS_ARG(arg));
data->first_pfn = first_pfn;
data->nr = nr;
xc_hypercall_buffer_free(xch, arg);
return rc;
return do_dm_op(xch, dom, 1, &op, sizeof(op));
}
int xc_hvm_set_mem_type(
+87 -3
View File
@@ -14,6 +14,7 @@
* this program; If not, see <http://www.gnu.org/licenses/>.
*/
#include <xen/event.h>
#include <xen/guest_access.h>
#include <xen/hypercall.h>
#include <xen/sched.h>
@@ -117,6 +118,59 @@ static int set_isa_irq_level(struct domain *d, uint8_t isa_irq,
return 0;
}
static int modified_memory(struct domain *d,
struct xen_dm_op_modified_memory *data)
{
xen_pfn_t last_pfn = data->first_pfn + data->nr - 1;
unsigned int iter = 0;
int rc = 0;
if ( (data->first_pfn > last_pfn) ||
(last_pfn > domain_get_maximum_gpfn(d)) )
return -EINVAL;
if ( !paging_mode_log_dirty(d) )
return 0;
while ( iter < data->nr )
{
unsigned long pfn = data->first_pfn + iter;
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);
}
iter++;
/*
* Check for continuation every 256th iteration and if the
* iteration is not the last.
*/
if ( (iter < data->nr) && ((iter & 0xff) == 0) &&
hypercall_preempt_check() )
{
data->first_pfn += iter;
data->nr -= iter;
rc = -ERESTART;
break;
}
}
return rc;
}
static int dm_op(domid_t domid,
unsigned int nr_bufs,
xen_dm_op_buf_t bufs[])
@@ -283,12 +337,27 @@ static int dm_op(domid_t domid,
break;
}
case XEN_DMOP_modified_memory:
{
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);
break;
}
default:
rc = -EOPNOTSUPP;
break;
}
if ( !rc &&
if ( (!rc || rc == -ERESTART) &&
!const_op &&
!copy_buf_to_guest(bufs, nr_bufs, 0, &op, sizeof(op)) )
rc = -EFAULT;
@@ -308,6 +377,7 @@ CHECK_dm_op_track_dirty_vram;
CHECK_dm_op_set_pci_intx_level;
CHECK_dm_op_set_isa_irq_level;
CHECK_dm_op_set_pci_link_route;
CHECK_dm_op_modified_memory;
#define MAX_NR_BUFS 2
@@ -317,6 +387,7 @@ int compat_dm_op(domid_t domid,
{
struct xen_dm_op_buf nat[MAX_NR_BUFS];
unsigned int i;
int rc;
if ( nr_bufs > MAX_NR_BUFS )
return -E2BIG;
@@ -336,7 +407,13 @@ int compat_dm_op(domid_t domid,
#undef XLAT_dm_op_buf_HNDL_h
}
return dm_op(domid, nr_bufs, nat);
rc = dm_op(domid, nr_bufs, nat);
if ( rc == -ERESTART )
rc = hypercall_create_continuation(__HYPERVISOR_dm_op, "iih",
domid, nr_bufs, bufs);
return rc;
}
long do_dm_op(domid_t domid,
@@ -344,6 +421,7 @@ long do_dm_op(domid_t domid,
XEN_GUEST_HANDLE_PARAM(xen_dm_op_buf_t) bufs)
{
struct xen_dm_op_buf nat[MAX_NR_BUFS];
int rc;
if ( nr_bufs > MAX_NR_BUFS )
return -E2BIG;
@@ -351,7 +429,13 @@ long do_dm_op(domid_t domid,
if ( copy_from_guest_offset(nat, bufs, 0, nr_bufs) )
return -EFAULT;
return dm_op(domid, nr_bufs, nat);
rc = dm_op(domid, nr_bufs, nat);
if ( rc == -ERESTART )
rc = hypercall_create_continuation(__HYPERVISOR_dm_op, "iih",
domid, nr_bufs, bufs);
return rc;
}
/*
-60
View File
@@ -4969,7 +4969,6 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg)
default:
mask = ~0UL;
break;
case HVMOP_modified_memory:
case HVMOP_set_mem_type:
mask = HVMOP_op_mask;
break;
@@ -5002,65 +5001,6 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg)
rc = guest_handle_is_null(arg) ? hvmop_flush_tlb_all() : -EINVAL;
break;
case HVMOP_modified_memory:
{
struct xen_hvm_modified_memory a;
struct domain *d;
if ( copy_from_guest(&a, arg, 1) )
return -EFAULT;
rc = rcu_lock_remote_domain_by_id(a.domid, &d);
if ( rc != 0 )
return rc;
rc = -EINVAL;
if ( !is_hvm_domain(d) )
goto modmem_fail;
rc = xsm_hvm_control(XSM_DM_PRIV, d, op);
if ( rc )
goto modmem_fail;
rc = -EINVAL;
if ( a.nr < start_iter ||
((a.first_pfn + a.nr - 1) < a.first_pfn) ||
((a.first_pfn + a.nr - 1) > domain_get_maximum_gpfn(d)) )
goto modmem_fail;
rc = 0;
if ( !paging_mode_log_dirty(d) )
goto modmem_fail;
while ( a.nr > start_iter )
{
unsigned long pfn = a.first_pfn + start_iter;
struct page_info *page;
page = get_page_from_gfn(d, pfn, NULL, P2M_UNSHARE);
if ( page )
{
paging_mark_dirty(d, _mfn(page_to_mfn(page)));
/* These are most probably not page tables any more */
/* don't take a long time and don't die either */
sh_remove_shadows(d, _mfn(page_to_mfn(page)), 1, 0);
put_page(page);
}
/* Check for continuation if it's not the last interation */
if ( a.nr > ++start_iter && !(start_iter & HVMOP_op_mask) &&
hypercall_preempt_check() )
{
rc = -ERESTART;
break;
}
}
modmem_fail:
rcu_unlock_domain(d);
break;
}
case HVMOP_get_mem_type:
rc = hvmop_get_mem_type(
guest_handle_cast(arg, xen_hvm_get_mem_type_t));
+19
View File
@@ -233,6 +233,24 @@ struct xen_dm_op_set_pci_link_route {
uint8_t isa_irq;
};
/*
* 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.
*/
#define XEN_DMOP_modified_memory 11
struct xen_dm_op_modified_memory {
/* IN - number of contiguous pages modified */
uint32_t nr;
uint32_t pad;
/* IN - first pfn modified */
uint64_aligned_t first_pfn;
};
struct xen_dm_op {
uint32_t op;
uint32_t pad;
@@ -247,6 +265,7 @@ struct xen_dm_op {
struct xen_dm_op_set_pci_intx_level set_pci_intx_level;
struct xen_dm_op_set_isa_irq_level set_isa_irq_level;
struct xen_dm_op_set_pci_link_route set_pci_link_route;
struct xen_dm_op_modified_memory modified_memory;
} u;
};
-13
View File
@@ -99,19 +99,6 @@ typedef enum {
/* Following tools-only interfaces may change in future. */
#if defined(__XEN__) || defined(__XEN_TOOLS__)
/* Notify that some pages got modified by the Device Model. */
#define HVMOP_modified_memory 7
struct xen_hvm_modified_memory {
/* Domain to be updated. */
domid_t domid;
/* Number of pages. */
uint32_t nr;
/* First pfn. */
uint64_aligned_t first_pfn;
};
typedef struct xen_hvm_modified_memory xen_hvm_modified_memory_t;
DEFINE_XEN_GUEST_HANDLE(xen_hvm_modified_memory_t);
#define HVMOP_set_mem_type 8
/* Notify that a region of memory is to be treated in a specific way. */
struct xen_hvm_set_mem_type {
+1
View File
@@ -61,6 +61,7 @@
? dm_op_destroy_ioreq_server hvm/dm_op.h
? dm_op_get_ioreq_server_info hvm/dm_op.h
? dm_op_ioreq_server_range hvm/dm_op.h
? dm_op_modified_memory hvm/dm_op.h
? dm_op_set_ioreq_server_state hvm/dm_op.h
? dm_op_set_isa_irq_level hvm/dm_op.h
? dm_op_set_pci_intx_level hvm/dm_op.h
+1 -1
View File
@@ -262,7 +262,7 @@ class hvm
bind_irq
# XEN_DOMCTL_pin_mem_cacheattr
cacheattr
# HVMOP_modified_memory, HVMOP_get_mem_type, HVMOP_set_mem_type,
# HVMOP_get_mem_type, HVMOP_set_mem_type,
# HVMOP_set_mem_access, HVMOP_get_mem_access, HVMOP_pagetable_dying,
# HVMOP_inject_trap
hvmctl
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.