util-linux.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] lscpu: Fix issue found on CPU hot-remove
@ 2012-10-23 19:49 Toshi Kani
  2012-11-07 11:47 ` Karel Zak
  0 siblings, 1 reply; 6+ messages in thread
From: Toshi Kani @ 2012-10-23 19:49 UTC (permalink / raw)
  To: util-linux, kzak; +Cc: heiko.carstens, kerolasa, Toshi Kani

read_basicinfo() relies on sysfs cpu directories
"/sys/devices/system/cpu/cpu%d" with assumption that cpu
logical number %d is always sequentially assigned for all
CPUs. However, this assumption is not correct with CPU
hot-remove operation since it removes a target sysfs cpu
directory after it is ejected. As a result, lscpu may not
recognize all CPUs.

The issue can be easily reproduced on KVM or VirtualBox,
which supports CPU eject operation, as follows.

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.
 - Add is_cpu_present() to check if a CPU is present. Ejected
   CPUs are not present.

Signed-off-by: Toshi Kani <toshi.kani@hp.com>
---
 sys-utils/lscpu.c | 53 ++++++++++++++++++++++++++++++++---------------------
 1 file changed, 32 insertions(+), 21 deletions(-)

diff --git a/sys-utils/lscpu.c b/sys-utils/lscpu.c
index 25a0273..946eb41 100644
--- a/sys-utils/lscpu.c
+++ b/sys-utils/lscpu.c
@@ -150,7 +150,8 @@ struct lscpu_desc {
 	int	dispatching;	/* none, horizontal or vertical */
 	int	mode;		/* rm, lm or/and tm */
 
-	int		ncpus;		/* number of 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 +205,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
@@ -340,10 +344,6 @@ read_basicinfo(struct lscpu_desc *desc, struct lscpu_modifier *mod)
 		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,7 +391,14 @@ 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;
+
+	/* get mask for present CPUs */
+	if (path_exist(_PATH_SYS_SYSTEM "/cpu/present")) {
+		size_t setsize = CPU_ALLOC_SIZE(maxcpus);
+		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")) {
@@ -626,16 +633,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 maxcpus
 		 * 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(maxcpus, sizeof(cpu_set_t *));
+		desc->socketmaps = xcalloc(maxcpus, sizeof(cpu_set_t *));
 		if (book_siblings)
-			desc->bookmaps = xcalloc(desc->ncpus, sizeof(cpu_set_t *));
+			desc->bookmaps = xcalloc(maxcpus, sizeof(cpu_set_t *));
 	}
 
 	add_cpuset_to_array(desc->socketmaps, &desc->nsockets, core_siblings);
@@ -653,7 +660,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(maxcpus, 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 +680,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(maxcpus, sizeof(int));
 	desc->addresses[num] = path_getnum(_PATH_SYS_CPU "/cpu%d/address", num);
 }
 
@@ -683,7 +690,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(maxcpus, sizeof(int));
 	desc->configured[num] = path_getnum(_PATH_SYS_CPU "/cpu%d/configure", num);
 }
 
@@ -756,7 +763,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(maxcpus, sizeof(cpu_set_t *));
 		add_cpuset_to_array(ca->sharedmaps, &ca->nsharedmaps, map);
 	}
 }
@@ -982,13 +989,15 @@ print_parsable(struct lscpu_desc *desc, int cols[], int ncols,
 	/*
 	 * Data
 	 */
-	for (i = 0; i < desc->ncpus; i++) {
+	for (i = 0; i < maxcpus; 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 +1035,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 < maxcpus; i++) {
 		int c;
 		struct tt_line *line;
 
@@ -1034,6 +1043,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 +1128,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 < maxcpus; 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 +1350,7 @@ int main(int argc, char *argv[])
 
 	read_basicinfo(desc, mod);
 
-	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);
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH] lscpu: Fix issue found on CPU hot-remove
  2012-10-23 19:49 [PATCH] lscpu: Fix issue found on CPU hot-remove Toshi Kani
@ 2012-11-07 11:47 ` Karel Zak
  2012-11-07 23:29   ` Toshi Kani
  0 siblings, 1 reply; 6+ messages in thread
From: Karel Zak @ 2012-11-07 11:47 UTC (permalink / raw)
  To: Toshi Kani; +Cc: util-linux, heiko.carstens, kerolasa

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

 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);

-- 
 Karel Zak  <kzak@redhat.com>
 http://karelzak.blogspot.com

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH] lscpu: Fix issue found on CPU hot-remove
  2012-11-07 11:47 ` Karel Zak
@ 2012-11-07 23:29   ` Toshi Kani
  2012-11-08  4:32     ` Ben Hutchings
  2012-11-12 15:42     ` Karel Zak
  0 siblings, 2 replies; 6+ messages in thread
From: Toshi Kani @ 2012-11-07 23:29 UTC (permalink / raw)
  To: Karel Zak, ben; +Cc: util-linux, heiko.carstens, kerolasa

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@decadent.org.uk>
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@nod.at> covered UML and suggested using
    per_cpu.
    
    Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
====


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);
> 



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] lscpu: Fix issue found on CPU hot-remove
  2012-11-07 23:29   ` Toshi Kani
@ 2012-11-08  4:32     ` Ben Hutchings
  2012-11-08 15:25       ` Toshi Kani
  2012-11-12 15:42     ` Karel Zak
  1 sibling, 1 reply; 6+ messages in thread
From: Ben Hutchings @ 2012-11-08  4:32 UTC (permalink / raw)
  To: Toshi Kani; +Cc: Karel Zak, util-linux, heiko.carstens, kerolasa

[-- Attachment #1: Type: text/plain, Size: 3300 bytes --]

On Wed, 2012-11-07 at 16:29 -0700, Toshi Kani wrote:
> 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@decadent.org.uk>
> 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@nod.at> covered UML and suggested using
>     per_cpu.
>     
>     Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
>     Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
> ====
> 
> 
> 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?
[...]

I think the distinction doesn't matter - the GENERIC_CPU_DEVICES code
does not support hotplug and therefore can only be used if present ==
possible.

Ben.

-- 
Ben Hutchings
The program is absolutely right; therefore, the computer must be wrong.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 828 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] lscpu: Fix issue found on CPU hot-remove
  2012-11-08  4:32     ` Ben Hutchings
@ 2012-11-08 15:25       ` Toshi Kani
  0 siblings, 0 replies; 6+ messages in thread
From: Toshi Kani @ 2012-11-08 15:25 UTC (permalink / raw)
  To: Ben Hutchings; +Cc: Karel Zak, util-linux, heiko.carstens, kerolasa

On Thu, 2012-11-08 at 04:32 +0000, Ben Hutchings wrote:
> On Wed, 2012-11-07 at 16:29 -0700, Toshi Kani wrote:
> > 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@decadent.org.uk>
> > 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@nod.at> covered UML and suggested using
> >     per_cpu.
> >     
> >     Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
> >     Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
> > ====
> > 
> > 
> > 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?
> [...]
> 
> I think the distinction doesn't matter - the GENERIC_CPU_DEVICES code
> does not support hotplug and therefore can only be used if present ==
> possible.

Hi Ben,

You may be right about that on those architectures where you added
GENERIC_CPU_DEVICES.  We have seen strange cpu directories on Sparc64,
but it does not seem to use the GENERIC_CPU_DEVICES code.  So, this
issue may not be related with your change.  Sorry about that.

Thanks,
-Toshi


> Ben.
> 



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] lscpu: Fix issue found on CPU hot-remove
  2012-11-07 23:29   ` Toshi Kani
  2012-11-08  4:32     ` Ben Hutchings
@ 2012-11-12 15:42     ` Karel Zak
  1 sibling, 0 replies; 6+ messages in thread
From: Karel Zak @ 2012-11-12 15:42 UTC (permalink / raw)
  To: Toshi Kani; +Cc: ben, util-linux, heiko.carstens, kerolasa

On Wed, Nov 07, 2012 at 04:29:35PM -0700, Toshi Kani wrote:
> Thanks for the updated patch.  It looks good.  I have tested it on my
> setup and it worked fine as well.

 Applied, thanks.

-- 
 Karel Zak  <kzak@redhat.com>
 http://karelzak.blogspot.com

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2012-11-12 15:42 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-10-23 19:49 [PATCH] lscpu: Fix issue found on CPU hot-remove Toshi Kani
2012-11-07 11:47 ` Karel Zak
2012-11-07 23:29   ` Toshi Kani
2012-11-08  4:32     ` Ben Hutchings
2012-11-08 15:25       ` Toshi Kani
2012-11-12 15:42     ` Karel Zak

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).