[Crash-utility] [PATCH] Support cpu_map/cpu_mask changes in 2.6.29
Michael Holzheu
holzheu at linux.vnet.ibm.com
Wed Apr 29 08:52:04 UTC 2009
Hi Dave,
Am Dienstag, den 28.04.2009, 14:24 -0400 schrieb Dave Anderson:
>
> Michael,
>
> It's not clear to me how this function works:
>
> + * Get cpu map (possible, online, etc.) address from cpu mask (since 2.6.29)
> + */
> +static ulong
> +get_cpu_map_addr_from_mask(const char *type)
> +{
> + ulong cpu_mask_addr, cpu_map_addr;
> + char cpu_mask_symbol[32];
> + char *cpu_mask_buf;
> + int cpu_mask_size;
> +
> + sprintf(cpu_mask_symbol, "cpu_%s_mask", type);
> +
> + if (!symbol_exists(cpu_mask_symbol))
> + return 0;
> +
> + cpu_mask_addr = symbol_value(cpu_mask_symbol);
> + cpu_mask_size = STRUCT_SIZE("cpumask");
> + cpu_mask_buf = malloc(cpu_mask_size);
> + if (!cpu_mask_buf)
> + error(FATAL, "get_cpu_map_addr_from_mask: out of memory\n");
> + readmem(cpu_mask_addr, KVADDR, cpu_mask_buf, cpu_mask_size,
> + cpu_mask_symbol, FAULT_ON_ERROR);
> + cpu_map_addr = ULONG(cpu_mask_buf + MEMBER_OFFSET("cpumask", "bits"));
> + free(cpu_mask_buf);
> +
> + return cpu_map_addr;
> +}
>
> The caller to this function expects the address of a cpumask_t
> data structure. As I understand it, both before and after 2.6.29,
> the cpumask data structure looks like:
>
> typedef struct cpumask {
> unsigned long int bits[<variable-based-upon-NR_CPUS>];
> } cpumask_t;
>
> And pre-2.6.29, the 3 "cpu_xxxx_map" symbols were all statically
> defined cpumask structures:
>
> cpumask_t cpu_online_mask;
> cpumask_t cpu_possible_mask;
> cpumask_t cpu_present_mask;
>
> Whereas now the 3 symbols don't exist except as #define's like so:
>
> #define cpu_possible_map (*(cpumask_t *)cpu_possible_mask)
> #define cpu_online_map (*(cpumask_t *)cpu_online_mask)
> #define cpu_present_map (*(cpumask_t *)cpu_present_mask)
>
> and -- if I understand the code correctly -- each cpu_xxxx_mask
> is just a pointer to a cpumask data structure.
>
> So when the caller needs the address of the relevant cpumask data structure
> why doesn't your cpu_map_addr_from_mask() function simply do something
> like:
>
> get_symbol_data(cpu_mask_symbol, sizeof(void *), &tmp);
> return tmp;
>
> i.e., which would read the contents of the cpu_mask_symbol, which
> is the pointer that the caller wants.
>
> Instead, your function reads in the whole data structure, where
> the cpumask.bits[] array typically contains several items, i.e.,
> enough longs to contain NR_CPUS bits. Then, with ULONG(), it is
> essentially reading the unsigned long value found in the first
> bit[] array item, or:
>
> cpumask.bits[0];
>
> and therefore returning the *bitmask* contained in the first unsigned
> long in the bit[] array -- instead of the *address* of the cpumask
> data structure. How can that work?
>
> Or am I missing something?
No, you are completely right.
I tested my patch and it worked. But it only worked by chance. I read
the address using readmem(cpu_mask_size) in combination with ULONG(),
which is nonsense.
So the correct (and tested) version would be something like:
static ulong
get_cpu_map_addr_from_mask(const char *type)
{
char cpu_mask_symbol[32];
ulong cpu_map_addr;
sprintf(cpu_mask_symbol, "cpu_%s_mask", type);
if (!symbol_exists(cpu_mask_symbol))
return 0;
get_symbol_data(cpu_mask_symbol, sizeof(ulong), &cpu_map_addr);
return cpu_map_addr;
}
Michael
More information about the Crash-utility
mailing list