|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v2 05/11] ioreq: add internal ioreq initialization support
> -----Original Message-----
> From: Roger Pau Monne <roger.pau@xxxxxxxxxx>
> Sent: 03 September 2019 17:14
> To: xen-devel@xxxxxxxxxxxxxxxxxxxx
> Cc: Roger Pau Monne <roger.pau@xxxxxxxxxx>; Jan Beulich <jbeulich@xxxxxxxx>;
> Andrew Cooper
> <Andrew.Cooper3@xxxxxxxxxx>; Wei Liu <wl@xxxxxxx>; Paul Durrant
> <Paul.Durrant@xxxxxxxxxx>
> Subject: [PATCH v2 05/11] ioreq: add internal ioreq initialization support
>
> Add support for internal ioreq servers to initialization and
> deinitialization routines, prevent some functions from being executed
> against internal ioreq servers and add guards to only allow internal
> callers to modify internal ioreq servers. External callers (ie: from
> hypercalls) are only allowed to deal with external ioreq servers.
>
> Signed-off-by: Roger Pau Monné <roger.pau@xxxxxxxxxx>
> ---
> Changes since v1:
> - Do not pass an 'internal' parameter to most functions, and instead
> use the id to key whether an ioreq server is internal or external.
> - Prevent enabling an internal server without a handler.
> ---
> xen/arch/x86/hvm/dm.c | 17 ++-
> xen/arch/x86/hvm/ioreq.c | 173 +++++++++++++++++++------------
> xen/include/asm-x86/hvm/domain.h | 5 +-
> xen/include/asm-x86/hvm/ioreq.h | 8 +-
> 4 files changed, 135 insertions(+), 68 deletions(-)
>
> diff --git a/xen/arch/x86/hvm/dm.c b/xen/arch/x86/hvm/dm.c
> index c2fca9f729..6a3682e58c 100644
> --- a/xen/arch/x86/hvm/dm.c
> +++ b/xen/arch/x86/hvm/dm.c
> @@ -417,7 +417,7 @@ static int dm_op(const struct dmop_args *op_args)
> break;
>
> rc = hvm_create_ioreq_server(d, data->handle_bufioreq,
> - &data->id);
> + &data->id, false);
> break;
> }
>
> @@ -450,6 +450,9 @@ static int dm_op(const struct dmop_args *op_args)
> rc = -EINVAL;
> if ( data->pad )
> break;
> + rc = -EPERM;
> + if ( hvm_ioreq_is_internal(data->id) )
> + break;
>
> rc = hvm_map_io_range_to_ioreq_server(d, data->id, data->type,
> data->start, data->end);
> @@ -464,6 +467,9 @@ static int dm_op(const struct dmop_args *op_args)
> rc = -EINVAL;
> if ( data->pad )
> break;
> + rc = -EPERM;
> + if ( hvm_ioreq_is_internal(data->id) )
> + break;
>
> rc = hvm_unmap_io_range_from_ioreq_server(d, data->id, data->type,
> data->start, data->end);
> @@ -481,6 +487,9 @@ static int dm_op(const struct dmop_args *op_args)
> rc = -EOPNOTSUPP;
> if ( !hap_enabled(d) )
> break;
> + rc = -EPERM;
> + if ( hvm_ioreq_is_internal(data->id) )
> + break;
>
> if ( first_gfn == 0 )
> rc = hvm_map_mem_type_to_ioreq_server(d, data->id,
> @@ -528,6 +537,9 @@ static int dm_op(const struct dmop_args *op_args)
> rc = -EINVAL;
> if ( data->pad )
> break;
> + rc = -EPERM;
> + if ( hvm_ioreq_is_internal(data->id) )
> + break;
>
> rc = hvm_set_ioreq_server_state(d, data->id, !!data->enabled);
> break;
> @@ -541,6 +553,9 @@ static int dm_op(const struct dmop_args *op_args)
> rc = -EINVAL;
> if ( data->pad )
> break;
> + rc = -EPERM;
> + if ( hvm_ioreq_is_internal(data->id) )
> + break;
>
> rc = hvm_destroy_ioreq_server(d, data->id);
> break;
> diff --git a/xen/arch/x86/hvm/ioreq.c b/xen/arch/x86/hvm/ioreq.c
> index 95492bc111..dbc5e6b4c5 100644
> --- a/xen/arch/x86/hvm/ioreq.c
> +++ b/xen/arch/x86/hvm/ioreq.c
> @@ -59,10 +59,11 @@ static struct hvm_ioreq_server *get_ioreq_server(const
> struct domain *d,
> /*
> * Iterate over all possible ioreq servers.
> *
> - * NOTE: The iteration is backwards such that more recently created
> - * ioreq servers are favoured in hvm_select_ioreq_server().
> - * This is a semantic that previously existed when ioreq servers
> - * were held in a linked list.
> + * NOTE: The iteration is backwards such that internal and more recently
> + * created external ioreq servers are favoured in
> + * hvm_select_ioreq_server().
> + * This is a semantic that previously existed for external servers when
> + * ioreq servers were held in a linked list.
> */
> #define FOR_EACH_IOREQ_SERVER(d, id, s) \
> for ( (id) = MAX_NR_IOREQ_SERVERS; (id) != 0; ) \
> @@ -70,6 +71,12 @@ static struct hvm_ioreq_server *get_ioreq_server(const
> struct domain *d,
> continue; \
> else
>
> +#define FOR_EACH_EXTERNAL_IOREQ_SERVER(d, id, s) \
> + for ( (id) = MAX_NR_EXTERNAL_IOREQ_SERVERS; (id) != 0; ) \
> + if ( !(s = GET_IOREQ_SERVER(d, --(id))) ) \
> + continue; \
> + else
> +
> static ioreq_t *get_ioreq(struct hvm_ioreq_server *s, struct vcpu *v)
> {
> shared_iopage_t *p = s->ioreq.va;
> @@ -86,7 +93,7 @@ bool hvm_io_pending(struct vcpu *v)
> struct hvm_ioreq_server *s;
> unsigned int id;
>
> - FOR_EACH_IOREQ_SERVER(d, id, s)
> + FOR_EACH_EXTERNAL_IOREQ_SERVER(d, id, s)
> {
> struct hvm_ioreq_vcpu *sv;
>
> @@ -190,7 +197,7 @@ bool handle_hvm_io_completion(struct vcpu *v)
> return false;
> }
>
> - FOR_EACH_IOREQ_SERVER(d, id, s)
> + FOR_EACH_EXTERNAL_IOREQ_SERVER(d, id, s)
> {
> struct hvm_ioreq_vcpu *sv;
>
> @@ -430,7 +437,7 @@ bool is_ioreq_server_page(struct domain *d, const struct
> page_info *page)
>
> spin_lock_recursive(&d->arch.hvm.ioreq_server.lock);
>
> - FOR_EACH_IOREQ_SERVER(d, id, s)
> + FOR_EACH_EXTERNAL_IOREQ_SERVER(d, id, s)
> {
> if ( (s->ioreq.page == page) || (s->bufioreq.page == page) )
> {
> @@ -688,7 +695,7 @@ static int hvm_ioreq_server_alloc_rangesets(struct
> hvm_ioreq_server *s,
> return rc;
> }
>
> -static void hvm_ioreq_server_enable(struct hvm_ioreq_server *s)
> +static void hvm_ioreq_server_enable(struct hvm_ioreq_server *s, bool
> internal)
> {
> struct hvm_ioreq_vcpu *sv;
>
> @@ -697,29 +704,40 @@ static void hvm_ioreq_server_enable(struct
> hvm_ioreq_server *s)
> if ( s->enabled )
> goto done;
>
> - hvm_remove_ioreq_gfn(s, false);
> - hvm_remove_ioreq_gfn(s, true);
> + if ( !internal )
> + {
> + hvm_remove_ioreq_gfn(s, false);
> + hvm_remove_ioreq_gfn(s, true);
>
> - s->enabled = true;
> + list_for_each_entry ( sv,
> + &s->ioreq_vcpu_list,
> + list_entry )
> + hvm_update_ioreq_evtchn(s, sv);
> + }
> + else if ( !s->handler )
> + {
> + ASSERT_UNREACHABLE();
> + goto done;
> + }
>
> - list_for_each_entry ( sv,
> - &s->ioreq_vcpu_list,
> - list_entry )
> - hvm_update_ioreq_evtchn(s, sv);
> + s->enabled = true;
>
> done:
> spin_unlock(&s->lock);
> }
>
> -static void hvm_ioreq_server_disable(struct hvm_ioreq_server *s)
> +static void hvm_ioreq_server_disable(struct hvm_ioreq_server *s, bool
> internal)
> {
> spin_lock(&s->lock);
>
> if ( !s->enabled )
> goto done;
>
> - hvm_add_ioreq_gfn(s, true);
> - hvm_add_ioreq_gfn(s, false);
> + if ( !internal )
> + {
> + hvm_add_ioreq_gfn(s, true);
> + hvm_add_ioreq_gfn(s, false);
> + }
>
> s->enabled = false;
>
> @@ -736,33 +754,39 @@ static int hvm_ioreq_server_init(struct
> hvm_ioreq_server *s,
> int rc;
>
> s->target = d;
> -
> - get_knownalive_domain(currd);
> - s->emulator = currd;
> -
> spin_lock_init(&s->lock);
> - INIT_LIST_HEAD(&s->ioreq_vcpu_list);
> - spin_lock_init(&s->bufioreq_lock);
> -
> - s->ioreq.gfn = INVALID_GFN;
> - s->bufioreq.gfn = INVALID_GFN;
>
> rc = hvm_ioreq_server_alloc_rangesets(s, id);
> if ( rc )
> return rc;
>
> - s->bufioreq_handling = bufioreq_handling;
> -
> - for_each_vcpu ( d, v )
> + if ( !hvm_ioreq_is_internal(id) )
> {
> - rc = hvm_ioreq_server_add_vcpu(s, v);
> - if ( rc )
> - goto fail_add;
> + get_knownalive_domain(currd);
> +
> + s->emulator = currd;
> + INIT_LIST_HEAD(&s->ioreq_vcpu_list);
> + spin_lock_init(&s->bufioreq_lock);
> +
> + s->ioreq.gfn = INVALID_GFN;
> + s->bufioreq.gfn = INVALID_GFN;
> +
> + s->bufioreq_handling = bufioreq_handling;
> +
> + for_each_vcpu ( d, v )
> + {
> + rc = hvm_ioreq_server_add_vcpu(s, v);
> + if ( rc )
> + goto fail_add;
> + }
> }
> + else
> + s->handler = NULL;
The struct is zeroed out so initializing the handler is not necessary.
>
> return 0;
>
> fail_add:
> + ASSERT(!hvm_ioreq_is_internal(id));
> hvm_ioreq_server_remove_all_vcpus(s);
> hvm_ioreq_server_unmap_pages(s);
>
I think it would be worthwhile having that ASSERT repeated in the called
functions, and other functions that only operate on external ioreq servers e.g.
hvm_ioreq_server_add_vcpu(), hvm_ioreq_server_map_pages(), etc.
> @@ -772,30 +796,34 @@ static int hvm_ioreq_server_init(struct
> hvm_ioreq_server *s,
> return rc;
> }
>
> -static void hvm_ioreq_server_deinit(struct hvm_ioreq_server *s)
> +static void hvm_ioreq_server_deinit(struct hvm_ioreq_server *s, bool
> internal)
> {
> ASSERT(!s->enabled);
> - hvm_ioreq_server_remove_all_vcpus(s);
> -
> - /*
> - * NOTE: It is safe to call both hvm_ioreq_server_unmap_pages() and
> - * hvm_ioreq_server_free_pages() in that order.
> - * This is because the former will do nothing if the pages
> - * are not mapped, leaving the page to be freed by the latter.
> - * However if the pages are mapped then the former will set
> - * the page_info pointer to NULL, meaning the latter will do
> - * nothing.
> - */
> - hvm_ioreq_server_unmap_pages(s);
> - hvm_ioreq_server_free_pages(s);
>
> hvm_ioreq_server_free_rangesets(s);
>
> - put_domain(s->emulator);
> + if ( !internal )
Perhaps 'if ( internal ) return;' so as to avoid indenting the code below and
thus shrink the diff.
> + {
> + hvm_ioreq_server_remove_all_vcpus(s);
> +
> + /*
> + * NOTE: It is safe to call both hvm_ioreq_server_unmap_pages() and
> + * hvm_ioreq_server_free_pages() in that order.
> + * This is because the former will do nothing if the pages
> + * are not mapped, leaving the page to be freed by the latter.
> + * However if the pages are mapped then the former will set
> + * the page_info pointer to NULL, meaning the latter will do
> + * nothing.
> + */
> + hvm_ioreq_server_unmap_pages(s);
> + hvm_ioreq_server_free_pages(s);
> +
> + put_domain(s->emulator);
> + }
> }
>
> int hvm_create_ioreq_server(struct domain *d, int bufioreq_handling,
> - ioservid_t *id)
> + ioservid_t *id, bool internal)
> {
> struct hvm_ioreq_server *s;
> unsigned int i;
> @@ -811,7 +839,9 @@ int hvm_create_ioreq_server(struct domain *d, int
> bufioreq_handling,
> domain_pause(d);
> spin_lock_recursive(&d->arch.hvm.ioreq_server.lock);
>
> - for ( i = 0; i < MAX_NR_IOREQ_SERVERS; i++ )
> + for ( i = (internal ? MAX_NR_EXTERNAL_IOREQ_SERVERS : 0);
> + i < (internal ? MAX_NR_IOREQ_SERVERS :
> MAX_NR_EXTERNAL_IOREQ_SERVERS);
> + i++ )
> {
> if ( !GET_IOREQ_SERVER(d, i) )
> break;
> @@ -821,6 +851,9 @@ int hvm_create_ioreq_server(struct domain *d, int
> bufioreq_handling,
> if ( i >= MAX_NR_IOREQ_SERVERS )
> goto fail;
>
> + ASSERT((internal &&
> + i >= MAX_NR_EXTERNAL_IOREQ_SERVERS && i < MAX_NR_IOREQ_SERVERS)
> ||
> + (!internal && i < MAX_NR_EXTERNAL_IOREQ_SERVERS));
> /*
> * It is safe to call set_ioreq_server() prior to
> * hvm_ioreq_server_init() since the target domain is paused.
> @@ -864,20 +897,21 @@ int hvm_destroy_ioreq_server(struct domain *d,
> ioservid_t id)
> goto out;
>
> rc = -EPERM;
> - if ( s->emulator != current->domain )
> + /* NB: internal servers cannot be destroyed. */
> + if ( hvm_ioreq_is_internal(id) || s->emulator != current->domain )
Shouldn't the test of hvm_ioreq_is_internal(id) simply be an ASSERT? This
function should only be called from a dm_op(), right?
> goto out;
>
> domain_pause(d);
>
> p2m_set_ioreq_server(d, 0, id);
>
> - hvm_ioreq_server_disable(s);
> + hvm_ioreq_server_disable(s, hvm_ioreq_is_internal(id));
>
> /*
> * It is safe to call hvm_ioreq_server_deinit() prior to
> * set_ioreq_server() since the target domain is paused.
> */
> - hvm_ioreq_server_deinit(s);
> + hvm_ioreq_server_deinit(s, hvm_ioreq_is_internal(id));
> set_ioreq_server(d, id, NULL);
>
> domain_unpause(d);
> @@ -909,7 +943,8 @@ int hvm_get_ioreq_server_info(struct domain *d,
> ioservid_t id,
> goto out;
>
> rc = -EPERM;
> - if ( s->emulator != current->domain )
> + /* NB: don't allow fetching information from internal ioreq servers. */
> + if ( hvm_ioreq_is_internal(id) || s->emulator != current->domain )
Again here, and several places below.
Paul
> goto out;
>
> if ( ioreq_gfn || bufioreq_gfn )
> @@ -956,7 +991,7 @@ int hvm_get_ioreq_server_frame(struct domain *d,
> ioservid_t id,
> goto out;
>
> rc = -EPERM;
> - if ( s->emulator != current->domain )
> + if ( hvm_ioreq_is_internal(id) || s->emulator != current->domain )
> goto out;
>
> rc = hvm_ioreq_server_alloc_pages(s);
> @@ -1010,7 +1045,7 @@ int hvm_map_io_range_to_ioreq_server(struct domain *d,
> ioservid_t id,
> goto out;
>
> rc = -EPERM;
> - if ( s->emulator != current->domain )
> + if ( !hvm_ioreq_is_internal(id) && s->emulator != current->domain )
> goto out;
>
> switch ( type )
> @@ -1068,7 +1103,7 @@ int hvm_unmap_io_range_from_ioreq_server(struct domain
> *d, ioservid_t id,
> goto out;
>
> rc = -EPERM;
> - if ( s->emulator != current->domain )
> + if ( !hvm_ioreq_is_internal(id) && s->emulator != current->domain )
> goto out;
>
> switch ( type )
> @@ -1128,6 +1163,14 @@ int hvm_map_mem_type_to_ioreq_server(struct domain *d,
> ioservid_t id,
> if ( !s )
> goto out;
>
> + /*
> + * NB: do not support mapping internal ioreq servers to memory types, as
> + * the current internal ioreq servers don't need this feature and it's
> not
> + * been tested.
> + */
> + rc = -EINVAL;
> + if ( hvm_ioreq_is_internal(id) )
> + goto out;
> rc = -EPERM;
> if ( s->emulator != current->domain )
> goto out;
> @@ -1163,15 +1206,15 @@ int hvm_set_ioreq_server_state(struct domain *d,
> ioservid_t id,
> goto out;
>
> rc = -EPERM;
> - if ( s->emulator != current->domain )
> + if ( !hvm_ioreq_is_internal(id) && s->emulator != current->domain )
> goto out;
>
> domain_pause(d);
>
> if ( enabled )
> - hvm_ioreq_server_enable(s);
> + hvm_ioreq_server_enable(s, hvm_ioreq_is_internal(id));
> else
> - hvm_ioreq_server_disable(s);
> + hvm_ioreq_server_disable(s, hvm_ioreq_is_internal(id));
>
> domain_unpause(d);
>
> @@ -1190,7 +1233,7 @@ int hvm_all_ioreq_servers_add_vcpu(struct domain *d,
> struct vcpu *v)
>
> spin_lock_recursive(&d->arch.hvm.ioreq_server.lock);
>
> - FOR_EACH_IOREQ_SERVER(d, id, s)
> + FOR_EACH_EXTERNAL_IOREQ_SERVER(d, id, s)
> {
> rc = hvm_ioreq_server_add_vcpu(s, v);
> if ( rc )
> @@ -1202,7 +1245,7 @@ int hvm_all_ioreq_servers_add_vcpu(struct domain *d,
> struct vcpu *v)
> return 0;
>
> fail:
> - while ( id++ != MAX_NR_IOREQ_SERVERS )
> + while ( id++ != MAX_NR_EXTERNAL_IOREQ_SERVERS )
> {
> s = GET_IOREQ_SERVER(d, id);
>
> @@ -1224,7 +1267,7 @@ void hvm_all_ioreq_servers_remove_vcpu(struct domain
> *d, struct vcpu *v)
>
> spin_lock_recursive(&d->arch.hvm.ioreq_server.lock);
>
> - FOR_EACH_IOREQ_SERVER(d, id, s)
> + FOR_EACH_EXTERNAL_IOREQ_SERVER(d, id, s)
> hvm_ioreq_server_remove_vcpu(s, v);
>
> spin_unlock_recursive(&d->arch.hvm.ioreq_server.lock);
> @@ -1241,13 +1284,13 @@ void hvm_destroy_all_ioreq_servers(struct domain *d)
>
> FOR_EACH_IOREQ_SERVER(d, id, s)
> {
> - hvm_ioreq_server_disable(s);
> + hvm_ioreq_server_disable(s, hvm_ioreq_is_internal(id));
>
> /*
> * It is safe to call hvm_ioreq_server_deinit() prior to
> * set_ioreq_server() since the target domain is being destroyed.
> */
> - hvm_ioreq_server_deinit(s);
> + hvm_ioreq_server_deinit(s, hvm_ioreq_is_internal(id));
> set_ioreq_server(d, id, NULL);
>
> xfree(s);
> diff --git a/xen/include/asm-x86/hvm/domain.h
> b/xen/include/asm-x86/hvm/domain.h
> index 9fbe83f45a..9f92838b6e 100644
> --- a/xen/include/asm-x86/hvm/domain.h
> +++ b/xen/include/asm-x86/hvm/domain.h
> @@ -97,7 +97,10 @@ struct hvm_pi_ops {
> void (*vcpu_block)(struct vcpu *);
> };
>
> -#define MAX_NR_IOREQ_SERVERS 8
> +#define MAX_NR_EXTERNAL_IOREQ_SERVERS 8
> +#define MAX_NR_INTERNAL_IOREQ_SERVERS 1
> +#define MAX_NR_IOREQ_SERVERS \
> + (MAX_NR_EXTERNAL_IOREQ_SERVERS + MAX_NR_INTERNAL_IOREQ_SERVERS)
>
> struct hvm_domain {
> /* Guest page range used for non-default ioreq servers */
> diff --git a/xen/include/asm-x86/hvm/ioreq.h b/xen/include/asm-x86/hvm/ioreq.h
> index 65491c48d2..c3917aa74d 100644
> --- a/xen/include/asm-x86/hvm/ioreq.h
> +++ b/xen/include/asm-x86/hvm/ioreq.h
> @@ -24,7 +24,7 @@ bool handle_hvm_io_completion(struct vcpu *v);
> bool is_ioreq_server_page(struct domain *d, const struct page_info *page);
>
> int hvm_create_ioreq_server(struct domain *d, int bufioreq_handling,
> - ioservid_t *id);
> + ioservid_t *id, bool internal);
> int hvm_destroy_ioreq_server(struct domain *d, ioservid_t id);
> int hvm_get_ioreq_server_info(struct domain *d, ioservid_t id,
> unsigned long *ioreq_gfn,
> @@ -54,6 +54,12 @@ unsigned int hvm_broadcast_ioreq(ioreq_t *p, bool
> buffered);
>
> void hvm_ioreq_init(struct domain *d);
>
> +static inline bool hvm_ioreq_is_internal(unsigned int id)
> +{
> + ASSERT(id < MAX_NR_IOREQ_SERVERS);
> + return id >= MAX_NR_EXTERNAL_IOREQ_SERVERS;
> +}
> +
> #endif /* __ASM_X86_HVM_IOREQ_H__ */
>
> /*
> --
> 2.22.0
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |