[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH v5 04/15] argo: init, destroy and soft-reset, with enable command line opt



On Mon, Jan 21, 2019 at 01:59:44AM -0800, Christopher Clark wrote:
> Initialises basic data structures and performs teardown of argo state
> for domain shutdown.
> 
> Inclusion of the Argo implementation is dependent on CONFIG_ARGO.
> 
> Introduces a new Xen command line parameter 'argo': bool to enable/disable
> the argo hypercall. Defaults to disabled.
> 
> New headers:
>   public/argo.h: with definions of addresses and ring structure, including
>   indexes for atomic update for communication between domain and hypervisor.
> 
>   xen/argo.h: to expose the hooks for integration into domain lifecycle:
>     argo_init: per-domain init of argo data structures for domain_create.
>     argo_destroy: teardown for domain_destroy and the error exit
>                   path of domain_create.
>     argo_soft_reset: reset of domain state for domain_soft_reset.
> 
> Adds a new field to struct domain: struct argo_domain *argo;
> 
> In accordance with recent work on _domain_destroy, argo_destroy is
> idempotent. It will tear down: all rings registered by this domain, all
> rings where this domain is the single sender (ie. specified partner,
> non-wildcard rings), and all pending notifications where this domain is
> awaiting signal about available space in the rings of other domains.
> 
> A count will be maintained of the number of rings that a domain has
> registered in order to limit it below the fixed maximum limit defined here.
> 
> Macros are defined to verify the internal locking state within the argo
> implementation. The macros are ASSERTed on entry to functions to validate
> and document the required lock state prior to calling.
> 
> The hash function for the hashtables that hold ring state is derived from
> the string hashing function djb2 (http://www.cse.yorku.ca/~oz/hash.html)
> by Daniel J. Bernstein. Basic testing with a limited number of domains and
> ports has shown reasonable distribution for the table size.
> 
> The software license on the public header is the BSD license, standard
> procedure for the public Xen headers. The public header was originally
> posted under a GPL license at: [1]:
> https://lists.xenproject.org/archives/html/xen-devel/2013-05/msg02710.html
> 
> The following ACK by Lars Kurth is to confirm that only people being
> employees of Citrix contributed to the header files in the series posted at
> [1] and that thus the copyright of the files in question is fully owned by
> Citrix. The ACK also confirms that Citrix is happy for the header files to
> be published under a BSD license in this series (which is based on [1]).
> 
> Signed-off-by: Christopher Clark <christopher.clark6@xxxxxxxxxxxxxx>
> Acked-by: Lars Kurth <lars.kurth@xxxxxxxxxx>
> Reviewed-by: Ross Philipson <ross.philipson@xxxxxxxxxx>

Thanks.

Reviewed-by: Roger Pau Monné <roger.pau@xxxxxxxxxx>

I've got some nits below, but it's purely cosmetic changes to make the
code cleaner.

> ---
> v4 Jan: amend the command line doc text referring to build configuration
> v4 feedback: use standard data structures as per common code
> v4 Jan: replace hash_index with djb2-derived hash algorithm
> v4 Andrew: switch argo command line option to list argo=<bool>
> v4: removed note to remove argo_destroy from domain_kill (test shows issue)
> v4 #04 Roger: drop unneeded init of ring_count in argo_domain_init
> v4 #04 Roger: replace if (ring_info->mfns) with ASSERTs in ring_unmap
> v4 #04 Roger: rewrite the locking verification macros
> v4 #04 Roger: make L1 lock description comment clearer about R(L1) and W(L1)
> v4 Andrew: fix split of dprintk in ring_map_info across v4 commits
> 
> v3 #04 Andrew: use xzalloc for struct argo_domain in argo_init
> v3 #04 Andrew: reference CONFIG_ARGO in the command line documentation
> v3 #07 Jan: rename ring_find_info to find_ring_info
> v3 #04 Andrew: don't truncate args do_argo_op printk
> v3 #07 Jan: fix numeric entries in printk format strings
> v3 #10 Roger: move find functions to top of file and drop prototypes
> v3 #04 Jan: meld compat check for hypercall arg types
> v3 #04 Roger/Jan: make lock names clearer and assert their state
> v3 #04 Jan: port -> aport with type; distinguish argo port from evtchn
> v3 #04 Jan: reorder call to argo_init_domain in argo_init
> v3 #04 Jan: ring_remove_mfns: zero count before freeing arrays
> v3 #04 Jason/Roger: soft_reset: can assume reinit is ok if d->argo set
> v3 #04 Roger: remove unused and confusing d->argo_lock
> v3 #04 Roger: add simple inlines in xen/argo.h, drop ifdef CONFIG_ARGO
> v3 #04 Roger: simpler return -EOPNOTSUPP in do_argo_op
> v3 #04 Roger: add const to domain arg to ring_remove_info
> v3 #04 Roger: use XFREE
> v3 #04 Roger: newline fix in wildcard_pending_list_remove
> v3 #04 Roger: mfn_mapping: void* instead of uint8_t*
> v3 #04 Roger: drop npages struct member in argo_ring_info; use len
> v3 #04 Roger/Jan: drop many fixed width types in internal structs
> v3 #04 Jason/Jan: drop pad and fixed width type in pending_ent struct
> v3 #04 Eric: moved ring_find_info from register op into this commit
> v3 moved hash_index function, nospec include from register op to this commit
> v3 moved XEN_ARGO_DOMID_ANY defn from register op into this commit
> v3 added #include <xen/sched.h> to <xen/argo.h> for domain struct defn
> v3 feedback #04 Roger: reorder #includes to alphabetical order
> v3 Added Ross's Reviewed-by.
> 
> v2 rewrite locking explanation comment
> v2 header copyright line now includes 2019
> v2 self: use ring_info backpointer in pending_ent to maintain npending
> v2 self: rename all_rings_remove_info to domain_rings_remove_all
> v2 feedback Jan: drop cookie, implement teardown
> v2 self: add npending to track number of pending entries per ring
> v2 self: amend comment on locking; drop section comments
> v2 cookie_eq: test low bits first and use likely on high bits
> v2 self: OVERHAUL
> v2 self: s/argo_pending_ent/pending_ent/g
> v2 self: drop pending_remove_ent, inline at single call site
> v1 feedback Roger, Jan: drop argo prefix on static functions
> v2 #4 Lars: add Acked-by and details to commit message.
> v2 feedback #9 Jan: document argo boot opt in xen-command-line.markdown
> v2 bugfix: xsm use in soft-reset prior to introduction
> v2 feedback #9 Jan: drop 'message' from do_argo_message_op
> v1 #5 feedback Paul: init/destroy unsigned, brackets and whitespace fixes
> v1 #5 feedback Paul: Use mfn_eq for comparing mfns.
> v1 #5 feedback Paul: init/destroy : use currd
> v1 #6 (#5) feedback Jan: init/destroy: s/ENOSYS/EOPNOTSUPP/
> v1 #6 feedback Paul: Folded patch 6 into patch 5.
> v1 #6 feedback Jan: drop opt_argo_enabled initializer
> v1 $6 feedback Jan: s/ENOSYS/EOPNOTSUPP/g and drop useless dprintk
> v1. #5 feedback Paul: change the license on public header to BSD
> - ack from Lars at Citrix.
> v1. self, Jan: drop unnecessary xen include from sched.h
> v1. self, Jan: drop inclusion of public argo.h in private one
> v1. self, Jan: add include of public argo.h to argo.c
> v1. self, Jan: drop fwd decl of argo_domain in priv header
> v1. Paul/self/Jan: add data structures to xlat.lst and compat/argo.h to 
> Makefile
> v1. self: removed allocation of event channel since switching to VIRQ
> v1. self: drop types.h include from private argo.h
> v1: reorder public argo include position
> v1: #13 feedback Jan: public namespace: prefix with xen
> v1: self: rename pending ent "id" to "domain_id"
> v1: self: add domain_cookie to ent struct
> v1. #15 feedback Jan: make cmd unsigned
> v1. #15 feedback Jan: make i loop variable unsigned
> v1: self: adjust dprintks in init, destroy
> v1: #18 feedback Jan: meld max ring count limit
> v1: self: use type not struct in public defn, affects compat gen header
> v1: feedback #15 Jan: handle upper-halves of hypercall args
> v1: add comment explaining the 'magic' field
> v1: self + Jan feedback: implement soft reset
> v1: feedback #13 Roger: use ASSERT_UNREACHABLE
> 
>  docs/misc/xen-command-line.pandoc |  15 +
>  xen/common/Makefile               |   2 +-
>  xen/common/argo.c                 | 617 
> +++++++++++++++++++++++++++++++++++++-
>  xen/common/compat/argo.c          |  23 ++
>  xen/common/domain.c               |   9 +
>  xen/include/Makefile              |   1 +
>  xen/include/public/argo.h         |  64 ++++
>  xen/include/xen/argo.h            |  44 +++
>  xen/include/xen/sched.h           |   5 +
>  xen/include/xlat.lst              |   2 +
>  10 files changed, 780 insertions(+), 2 deletions(-)
>  create mode 100644 xen/common/compat/argo.c
>  create mode 100644 xen/include/public/argo.h
>  create mode 100644 xen/include/xen/argo.h
> 
> diff --git a/docs/misc/xen-command-line.pandoc 
> b/docs/misc/xen-command-line.pandoc
> index d39bcee..93f41bc 100644
> --- a/docs/misc/xen-command-line.pandoc
> +++ b/docs/misc/xen-command-line.pandoc
> @@ -182,6 +182,21 @@ Permit Xen to use "Always Running APIC Timer" support on 
> compatible hardware
>  in combination with cpuidle.  This option is only expected to be useful for
>  developers wishing Xen to fall back to older timing methods on newer 
> hardware.
>  
> +### argo
> +    = List of [ <bool> ]
> +
> +Controls for the Argo hypervisor-mediated interdomain communication service.
> +
> +The functionality that this option controls is only available when Xen has 
> been
> +compiled with the build setting for Argo enabled in the build configuration.
> +
> +Argo is a interdomain communication mechanism, where Xen acts as the central
> +point of authority.  Guests may register memory rings to recieve messages,
> +query the status of other domains, and send messages by hypercall, all 
> subject
> +to appropriate auditing by Xen.
> +
> +*   An overall boolean acts as a global control.  Argo is disabled by 
> default.

I'm not sure it's worth adding a list item for the boolean, I would
just add the "Argo is disabled by default" to the first paragraph.

[...]
> +static struct argo_ring_info *
> +find_ring_info(const struct domain *d, const struct argo_ring_id *id)
> +{
> +    struct list_head *cursor, *bucket;
> +
> +    ASSERT(LOCKING_Read_rings_L2(d));
> +
> +    /* List is not modified here. Search and return the match if found. */
> +    bucket = &d->argo->ring_hash[hash_index(id)];
> +
> +    for ( cursor = bucket->next; cursor != bucket; cursor = cursor->next )

Why are you open-coding list_for_each here?

You might also consider using list_for_each_entry, so that you can
avoid the list_entry call below.

> +    {
> +        struct argo_ring_info *ring_info =
> +            list_entry(cursor, struct argo_ring_info, node);
> +        const struct argo_ring_id *cmpid = &ring_info->id;
> +
> +        if ( cmpid->aport == id->aport &&
> +             cmpid->domain_id == id->domain_id &&
> +             cmpid->partner_id == id->partner_id )
> +        {
> +            argo_dprintk("found ring_info for ring(%u:%x %u)\n",
> +                         id->domain_id, id->aport, id->partner_id);
> +            return ring_info;
> +        }
> +    }
> +    argo_dprintk("no ring_info for ring(%u:%x %u)\n",
> +                 id->domain_id, id->aport, id->partner_id);
> +
> +    return NULL;
> +}
[...]
> +static void
> +pending_remove_all(const struct domain *d, struct argo_ring_info *ring_info)
> +{
> +    struct list_head *ring_pending = &ring_info->pending;
> +    struct pending_ent *ent;
> +
> +    ASSERT(LOCKING_L3(d, ring_info));
> +
> +    /* Delete all pending notifications from this ring's list. */
> +    while ( !list_empty(ring_pending) )

Nit: you could use list_first_entry_or_null that joins the list_empty
and list_entry calls.

> +    {
> +        ent = list_entry(ring_pending->next, struct pending_ent, node);
> +
> +        /* For wildcard rings, remove each from their wildcard list too. */
> +        if ( ring_info->id.partner_id == XEN_ARGO_DOMID_ANY )
> +            wildcard_pending_list_remove(ent->domain_id, ent);
> +        list_del(&ent->node);
> +        xfree(ent);
> +    }
> +    ring_info->npending = 0;
> +}
> +
> +static void
> +wildcard_rings_pending_remove(struct domain *d)
> +{
> +    struct list_head *wildcard_head;
> +
> +    ASSERT(LOCKING_Write_L1);
> +
> +    /* Delete all pending signals to the domain about wildcard rings. */
> +    wildcard_head = &d->argo->wildcard_pend_list;
> +
> +    while ( !list_empty(wildcard_head) )
> +    {
> +        struct pending_ent *ent =
> +            list_entry(wildcard_head->next, struct pending_ent, node);

Same here regarding the usage of list_first_entry_or_null.

> +
> +        /*
> +         * The ent->node deleted here, and the npending value decreased,
> +         * belong to the ring_info of another domain, which is why this
> +         * function requires holding W(L1):
> +         * it implies the L3 lock that protects that ring_info struct.
> +         */
> +        ent->ring_info->npending--;
> +        list_del(&ent->node);
> +        list_del(&ent->wildcard_node);
> +        xfree(ent);
> +    }
> +}
[...]
> +static void
> +domain_rings_remove_all(struct domain *d)
> +{
> +    unsigned int i;
> +    struct argo_ring_info *ring_info;
> +
> +    ASSERT(LOCKING_Write_rings_L2(d));
> +
> +    for ( i = 0; i < ARGO_HASHTABLE_SIZE; ++i )
> +    {
> +        struct list_head *bucket = &d->argo->ring_hash[i];
> +
> +        while ( !list_empty(bucket) )
> +        {
> +            ring_info = list_entry(bucket->next, struct argo_ring_info, 
> node);

list_first_entry_or_null

> +            ring_remove_info(d, ring_info);
> +        }
> +    }
> +    d->argo->ring_count = 0;
> +}
> +
> +/*
> + * Tear down all rings of other domains where src_d domain is the partner.
> + * (ie. it is the single domain that can send to those rings.)
> + * This will also cancel any pending notifications about those rings.
> + */
> +static void
> +partner_rings_remove(struct domain *src_d)
> +{
> +    unsigned int i;
> +    struct argo_send_info *send_info;
> +    struct argo_ring_info *ring_info;
> +    struct domain *dst_d;
> +
> +    ASSERT(LOCKING_Write_L1);
> +
> +    for ( i = 0; i < ARGO_HASHTABLE_SIZE; ++i )
> +    {
> +        struct list_head *cursor, *bucket = &src_d->argo->send_hash[i];
> +
> +        /* Remove all ents from the send list. Take each off their ring 
> list. */
> +        for ( cursor = bucket->next; cursor != bucket; cursor = cursor->next 
> )

Another open-coded version of list_for_each, see my comments on the
instances above.

> +        {
> +            send_info = list_entry(cursor, struct argo_send_info, node);

send_info should be defined here to reduce it's scope.

> +
> +            dst_d = get_domain_by_id(send_info->id.domain_id);
> +            if ( dst_d && dst_d->argo )
> +            {
> +                ring_info = find_ring_info(dst_d, &send_info->id);

ring_info should be defined here.

> +                if ( ring_info )
> +                {
> +                    ring_remove_info(dst_d, ring_info);
> +                    dst_d->argo->ring_count--;
> +                }
> +                else
> +                    ASSERT_UNREACHABLE();
> +            }
> +            else
> +                ASSERT_UNREACHABLE();
> +
> +            if ( dst_d )
> +                put_domain(dst_d);
> +
> +            list_del(&send_info->node);
> +            xfree(send_info);
> +        }
> +    }
> +}

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.