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

Re: [Xen-devel] [PATCH v11 7/7] microcode: reject late ucode loading if any core is parked



On 26.09.2019 15:53, Chao Gao wrote:
> If a core with all of its thread being parked, late ucode loading
> which currently only loads ucode on online threads would lead to
> differing ucode revisions in the system. In general, keeping ucode
> revision consistent would be less error-prone. To this end, if there
> is a parked thread doesn't have an online sibling thread, late ucode
> loading is rejected.
> 
> Two threads are on the same core or computing unit iff they have
> the same phys_proc_id and cpu_core_id/compute_unit_id. Based on
> phys_proc_id and cpu_core_id/compute_unit_id, an unique core id
> is generated for each thread. And use a bitmap to reduce the
> number of comparison.
> 
> Signed-off-by: Chao Gao <chao.gao@xxxxxxxxx>
> ---
> Alternatively, we can mask the thread id off apicid and use it
> as the unique core id. It needs to introduce new field in cpuinfo_x86
> to record the mask for thread id. So I don't take this way.

It feels a little odd that you introduce a "custom" ID, but it
should be fine without going this alternative route. (You
wouldn't need a new field though, I think, as we've got the
x86_num_siblings one already.)

What I continue to be unconvinced of is for the chosen approach
to be better than briefly unparking a thread on each core, as
previously suggested.

> --- a/xen/arch/x86/microcode.c
> +++ b/xen/arch/x86/microcode.c
> @@ -573,6 +573,64 @@ static int do_microcode_update(void *patch)
>      return ret;
>  }
>  
> +static unsigned int unique_core_id(unsigned int cpu, unsigned int 
> socket_shift)
> +{
> +    unsigned int core_id = cpu_to_cu(cpu);
> +
> +    if ( core_id == INVALID_CUID )
> +        core_id = cpu_to_core(cpu);
> +
> +    return (cpu_to_socket(cpu) << socket_shift) + core_id;
> +}
> +
> +static int has_parked_core(void)
> +{
> +    int ret = 0;

I don't think you need the initializer here.

> +    if ( park_offline_cpus )

    if ( !park_offline_cpus )
        return 0;

would allow one level less of indentation of the main part of
the function body.

> +    {
> +        unsigned int cpu, max_bits, core_width;
> +        unsigned int max_sockets = 1, max_cores = 1;
> +        struct cpuinfo_x86 *c = cpu_data;
> +        unsigned long *bitmap;
> +
> +        for_each_present_cpu(cpu)
> +        {
> +            if ( x86_cpu_to_apicid[cpu] == BAD_APICID )
> +                continue;
> +
> +            /* Note that cpu_to_socket() get an ID starting from 0. */
> +            if ( cpu_to_socket(cpu) + 1 > max_sockets )

Instead of "+ 1", why not >= ?

> +                max_sockets = cpu_to_socket(cpu) + 1;
> +
> +            if ( c[cpu].x86_max_cores > max_cores )
> +                max_cores = c[cpu].x86_max_cores;

What guarantees .x86_max_cores to be valid? Onlining a hot-added
CPU is a two step process afaict, XENPF_cpu_hotadd followed by
XENPF_cpu_online. In between the CPU would be marked present
(and cpu_add() would also have filled x86_cpu_to_apicid[cpu]),
but cpu_data[cpu] wouldn't have been filled yet afaict. This
also makes the results of the cpu_to_*() unreliable that you use
in unique_core_id().

However, if we assume sufficient similarity between CPU
packages (as you've done elsewhere in this series iirc), this
may not be an actual problem. But it wants mentioning in a code
comment, I think. Plus at the very least you depend on the used
cpu_data[] fields to not contain unduly large values (and hence
you e.g. depend on cpu_data[] not gaining an initializer,
setting the three fields of interest to their INVALID_* values,
as currently done by identify_cpu()).

> +        }
> +
> +        core_width = fls(max_cores);
> +        max_bits = max_sockets << core_width;
> +        bitmap = xzalloc_array(unsigned long, BITS_TO_LONGS(max_bits));
> +        if ( !bitmap )
> +            return -ENOMEM;
> +
> +        for_each_present_cpu(cpu)
> +        {
> +            if ( cpu_online(cpu) || x86_cpu_to_apicid[cpu] == BAD_APICID )
> +                continue;
> +
> +            __set_bit(unique_core_id(cpu, core_width), bitmap);
> +        }
> +
> +        for_each_online_cpu(cpu)
> +            __clear_bit(unique_core_id(cpu, core_width), bitmap);
> +
> +        ret = (find_first_bit(bitmap, max_bits) < max_bits);

I think bitmap_empty() would be a cheaper operation for the purpose
you have, especially if further up you rounded up max_bits to a
multiple of BITS_PER_LONG.

Jan

_______________________________________________
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®.