Re: [PATCH] lscpu: Fix issue found on CPU hot-remove

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

 



On Wed, 2012-11-07 at 12:47 +0100, Karel Zak wrote:
> On Tue, Oct 23, 2012 at 01:49:46PM -0600, Toshi Kani wrote:
> > 1) The system has 4 CPUs
> >   $ lscpu -a -e
> >   CPU NODE SOCKET CORE L1d:L1i:L2 ONLINE
> >   0   0    0      0    0:0:0      yes
> >   1   0    1      1    1:1:1      yes
> >   2   0    2      2    2:2:2      yes
> >   3   0    3      3    3:3:3      yes
> > 
> > 2) Eject cpu2
> >   # echo 1 > /sys/bus/acpi/devices/LNXCPU:02/eject
> > 
> > 3) lscpu no longer recognizes cpu3 after cpu2 is ejected
> >   $ lscpu -a -e
> >   CPU NODE SOCKET CORE L1d:L1i:L2 ONLINE
> >   0   0    0      0    0:0:0      yes
> >   1   0    1      1    1:1:1      yes
> > 
> > The following changes are made to address this issue.
> >  - Use maxcpus to allocate and parse bitmaps.
> >  - Set desc->ncpu from cpu/present, which includes both on-line
> >    and off-line CPUs.
> 
>  In the directory tests we have a dump from some strange machine
> 
>     tests/ts/lscpu/dumps/sparc64-UltraSparc-T1.tar.gz
> 
>  where is 32 /sys/devices/system/cpu/cpu[0-9]* subdirectories, but the
>  present mask is 0-23, all the masks from the dump:
> 
>  present: 0-23
>  possible: 0-31
>  online: 0-23
>  offline: 24-31
>  count: 32      (means ls -d sys/devices/system/cpu/cpu[0-9]* | wc -l)
> 
>  strange, right? But I guess we can ignore this dump, according to
>  kernel Documentation/cpu-hotplug.txt the cpu[0-9]* subdirectories
>  have to follow the present mask. Maybe the dump is broken or so..

Hi Karel,

Thanks for the updated patch.  It looks good.  I have tested it on my
setup and it worked fine as well.

I agree that the present mask and cpu directories need to be consistent.
I looked at the kernel code and found the following change, which might
be the cause of this issue.

====
commit 9f13a1fd452f11c18004ba2422a6384b424ec8a9
Author: Ben Hutchings <ben@xxxxxxxxxxxxxxx>
Date:   Tue Jan 10 03:04:32 2012 +0000

    cpu: Register a generic CPU device on architectures that currently
do not
    
    frv, h8300, m68k, microblaze, openrisc, score, um and xtensa
currently
    do not register a CPU device.  Add the config option
GENERIC_CPU_DEVICES
    which causes a generic CPU device to be registered for each present
CPU,
    and make all these architectures select it.
    
    Richard Weinberger <richard@xxxxxx> covered UML and suggested using
    per_cpu.
    
    Signed-off-by: Ben Hutchings <ben@xxxxxxxxxxxxxxx>
    Signed-off-by: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx>
====


Hi Ben,

In the change log above, you described that a generic CPU device to be
registered for each "present" CPU.  However, in the code below, it used
for_each_possible_cpu(), instead of for_each_present_cpu().  Is this
what you intended?

+static void __init cpu_dev_register_generic(void)
+{
+#ifdef CONFIG_GENERIC_CPU_DEVICES
+       int i;
+
+       for_each_possible_cpu(i) {
+               if (register_cpu(&per_cpu(cpu_devices, i), i))
+                       panic("Failed to register CPU device");
+       }
+#endif
+}
+


Thanks,
-Toshi


>  Note that many of our old dumps in the tests/ts/lscpu/dumps don't
>  contain /sys/devices/system/cpu/{present,online,possible} masks, but
>  I will drop these incomplete dumps.
> 
> > -		desc->coremaps = xcalloc(desc->ncpus, sizeof(cpu_set_t *));
> > -		desc->socketmaps = xcalloc(desc->ncpus, sizeof(cpu_set_t *));
> > +		desc->coremaps = xcalloc(maxcpus, sizeof(cpu_set_t *));
> > +		desc->socketmaps = xcalloc(maxcpus, sizeof(cpu_set_t *));
> 
> [...]
> 
> > -	for (i = 0; i < desc->ncpus; i++) {
> > +	for (i = 0; i < maxcpus; i++) {
> >  		read_topology(desc, i);
> >  		read_cache(desc, i);
> >  		read_polarization(desc, i);
> 
>  What about to read /sys/devices/system/cpu/possible to determine the
>  maximal possible number of CPUs on the machine. It seems like
>  overkill to follow the maximal size of the cpu_set_t mask (=maxcpus).
> 
>  The "possible" mask is static and no affected by hot-plug.
> 
>  See the patch below.
> 
>     Karel
> 
> 
> diff --git a/sys-utils/lscpu.c b/sys-utils/lscpu.c
> index 25a0273..5b1a0af 100644
> --- a/sys-utils/lscpu.c
> +++ b/sys-utils/lscpu.c
> @@ -150,7 +150,9 @@ struct lscpu_desc {
>  	int	dispatching;	/* none, horizontal or vertical */
>  	int	mode;		/* rm, lm or/and tm */
>  
> -	int		ncpus;		/* number of CPUs */
> +	int		ncpuspos;	/* maximal possible CPUs */
> +	int		ncpus;		/* number of present CPUs */
> +	cpu_set_t	*present;	/* mask with present CPUs */
>  	cpu_set_t	*online;	/* mask with online CPUs */
>  
>  	int		nnodes;		/* number of NUMA modes */
> @@ -204,8 +206,11 @@ struct lscpu_modifier {
>  static int maxcpus;		/* size in bits of kernel cpu mask */
>  
>  #define is_cpu_online(_d, _cpu) \
> -		((_d) && (_d)->online ? \
> -			CPU_ISSET_S((_cpu), CPU_ALLOC_SIZE(maxcpus), (_d)->online) : 0)
> +	((_d) && (_d)->online ? \
> +		CPU_ISSET_S((_cpu), CPU_ALLOC_SIZE(maxcpus), (_d)->online) : 0)
> +#define is_cpu_present(_d, _cpu) \
> +	((_d) && (_d)->present ? \
> +		CPU_ISSET_S((_cpu), CPU_ALLOC_SIZE(maxcpus), (_d)->present) : 0)
>  
>  /*
>   * IDs
> @@ -334,16 +339,13 @@ read_basicinfo(struct lscpu_desc *desc, struct lscpu_modifier *mod)
>  	FILE *fp = path_fopen("r", 1, _PATH_PROC_CPUINFO);
>  	char buf[BUFSIZ];
>  	struct utsname utsbuf;
> +	size_t setsize;
>  
>  	/* architecture */
>  	if (uname(&utsbuf) == -1)
>  		err(EXIT_FAILURE, _("error: uname failed"));
>  	desc->arch = xstrdup(utsbuf.machine);
>  
> -	/* count CPU(s) */
> -	while(path_exist(_PATH_SYS_SYSTEM "/cpu/cpu%d", desc->ncpus))
> -		desc->ncpus++;
> -
>  	/* details */
>  	while (fgets(buf, sizeof(buf), fp) != NULL) {
>  		if (lookup(buf, "vendor", &desc->vendor)) ;
> @@ -391,11 +393,27 @@ read_basicinfo(struct lscpu_desc *desc, struct lscpu_modifier *mod)
>  	if (maxcpus <= 0)
>  		/* error or we are reading some /sys snapshot instead of the
>  		 * real /sys, let's use any crazy number... */
> -		maxcpus = desc->ncpus > 2048 ? desc->ncpus : 2048;
> +		maxcpus = 2048;
> +
> +	setsize = CPU_ALLOC_SIZE(maxcpus);
> +
> +	if (path_exist(_PATH_SYS_SYSTEM "/cpu/possible")) {
> +		cpu_set_t *tmp = path_cpulist(maxcpus, _PATH_SYS_SYSTEM "/cpu/possible");
> +		desc->ncpuspos = CPU_COUNT_S(setsize, tmp);
> +		cpuset_free(tmp);
> +	} else
> +		err(EXIT_FAILURE, _("failed to determine number of CPUs: %s"),
> +				_PATH_SYS_SYSTEM "/cpu/possible");
> +
> +
> +	/* get mask for present CPUs */
> +	if (path_exist(_PATH_SYS_SYSTEM "/cpu/present")) {
> +		desc->present = path_cpulist(maxcpus, _PATH_SYS_SYSTEM "/cpu/present");
> +		desc->ncpus = CPU_COUNT_S(setsize, desc->present);
> +	}
>  
>  	/* get mask for online CPUs */
>  	if (path_exist(_PATH_SYS_SYSTEM "/cpu/online")) {
> -		size_t setsize = CPU_ALLOC_SIZE(maxcpus);
>  		desc->online = path_cpulist(maxcpus, _PATH_SYS_SYSTEM "/cpu/online");
>  		desc->nthreads = CPU_COUNT_S(setsize, desc->online);
>  	}
> @@ -626,16 +644,16 @@ read_topology(struct lscpu_desc *desc, int num)
>  		 */
>  		if (!desc->nthreads)
>  			desc->nthreads = nbooks * nsockets * ncores * nthreads;
> -		/* For each map we make sure that it can have up to ncpus
> +		/* For each map we make sure that it can have up to ncpuspos
>  		 * entries. This is because we cannot reliably calculate the
>  		 * number of cores, sockets and books on all architectures.
>  		 * E.g. completely virtualized architectures like s390 may
>  		 * have multiple sockets of different sizes.
>  		 */
> -		desc->coremaps = xcalloc(desc->ncpus, sizeof(cpu_set_t *));
> -		desc->socketmaps = xcalloc(desc->ncpus, sizeof(cpu_set_t *));
> +		desc->coremaps = xcalloc(desc->ncpuspos, sizeof(cpu_set_t *));
> +		desc->socketmaps = xcalloc(desc->ncpuspos, sizeof(cpu_set_t *));
>  		if (book_siblings)
> -			desc->bookmaps = xcalloc(desc->ncpus, sizeof(cpu_set_t *));
> +			desc->bookmaps = xcalloc(desc->ncpuspos, sizeof(cpu_set_t *));
>  	}
>  
>  	add_cpuset_to_array(desc->socketmaps, &desc->nsockets, core_siblings);
> @@ -653,7 +671,7 @@ read_polarization(struct lscpu_desc *desc, int num)
>  	if (!path_exist(_PATH_SYS_CPU "/cpu%d/polarization", num))
>  		return;
>  	if (!desc->polarization)
> -		desc->polarization = xcalloc(desc->ncpus, sizeof(int));
> +		desc->polarization = xcalloc(desc->ncpuspos, sizeof(int));
>  	path_getstr(mode, sizeof(mode), _PATH_SYS_CPU "/cpu%d/polarization", num);
>  	if (strncmp(mode, "vertical:low", sizeof(mode)) == 0)
>  		desc->polarization[num] = POLAR_VLOW;
> @@ -673,7 +691,7 @@ read_address(struct lscpu_desc *desc, int num)
>  	if (!path_exist(_PATH_SYS_CPU "/cpu%d/address", num))
>  		return;
>  	if (!desc->addresses)
> -		desc->addresses = xcalloc(desc->ncpus, sizeof(int));
> +		desc->addresses = xcalloc(desc->ncpuspos, sizeof(int));
>  	desc->addresses[num] = path_getnum(_PATH_SYS_CPU "/cpu%d/address", num);
>  }
>  
> @@ -683,7 +701,7 @@ read_configured(struct lscpu_desc *desc, int num)
>  	if (!path_exist(_PATH_SYS_CPU "/cpu%d/configure", num))
>  		return;
>  	if (!desc->configured)
> -		desc->configured = xcalloc(desc->ncpus, sizeof(int));
> +		desc->configured = xcalloc(desc->ncpuspos, sizeof(int));
>  	desc->configured[num] = path_getnum(_PATH_SYS_CPU "/cpu%d/configure", num);
>  }
>  
> @@ -756,7 +774,7 @@ read_cache(struct lscpu_desc *desc, int num)
>  				  num, i);
>  
>  		if (!ca->sharedmaps)
> -			ca->sharedmaps = xcalloc(desc->ncpus, sizeof(cpu_set_t *));
> +			ca->sharedmaps = xcalloc(desc->ncpuspos, sizeof(cpu_set_t *));
>  		add_cpuset_to_array(ca->sharedmaps, &ca->nsharedmaps, map);
>  	}
>  }
> @@ -982,13 +1000,15 @@ print_parsable(struct lscpu_desc *desc, int cols[], int ncols,
>  	/*
>  	 * Data
>  	 */
> -	for (i = 0; i < desc->ncpus; i++) {
> +	for (i = 0; i < desc->ncpuspos; i++) {
>  		int c;
>  
>  		if (!mod->offline && desc->online && !is_cpu_online(desc, i))
>  			continue;
>  		if (!mod->online && desc->online && is_cpu_online(desc, i))
>  			continue;
> +		if (desc->present && !is_cpu_present(desc, i))
> +			continue;
>  		for (c = 0; c < ncols; c++) {
>  			if (mod->compat && cols[c] == COL_CACHE) {
>  				if (!desc->ncaches)
> @@ -1026,7 +1046,7 @@ print_readable(struct lscpu_desc *desc, int cols[], int ncols,
>  		tt_define_column(tt, xstrdup(data), 0, 0);
>  	}
>  
> -	for (i = 0; i < desc->ncpus; i++) {
> +	for (i = 0; i < desc->ncpuspos; i++) {
>  		int c;
>  		struct tt_line *line;
>  
> @@ -1034,6 +1054,8 @@ print_readable(struct lscpu_desc *desc, int cols[], int ncols,
>  			continue;
>  		if (!mod->online && desc->online && is_cpu_online(desc, i))
>  			continue;
> +		if (desc->present && !is_cpu_present(desc, i))
> +			continue;
>  
>  		line = tt_add_line(tt, NULL);
>  
> @@ -1117,8 +1139,8 @@ print_summary(struct lscpu_desc *desc, struct lscpu_modifier *mod)
>  		if (!set)
>  			err(EXIT_FAILURE, _("failed to callocate cpu set"));
>  		CPU_ZERO_S(setsize, set);
> -		for (i = 0; i < desc->ncpus; i++) {
> -			if (!is_cpu_online(desc, i))
> +		for (i = 0; i < desc->ncpuspos; i++) {
> +			if (!is_cpu_online(desc, i) && is_cpu_present(desc, i))
>  				CPU_SET_S(i, setsize, set);
>  		}
>  		print_cpuset(mod->hex ? _("Off-line CPU(s) mask:") :
> @@ -1339,7 +1361,7 @@ int main(int argc, char *argv[])
>  
>  	read_basicinfo(desc, mod);
>  
> -	for (i = 0; i < desc->ncpus; i++) {
> +	for (i = 0; i < desc->ncpuspos; i++) {
>  		read_topology(desc, i);
>  		read_cache(desc, i);
>  		read_polarization(desc, i);
> 


--
To unsubscribe from this list: send the line "unsubscribe util-linux" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux