Re: [PATCH] cpumask 5/10 rewrite cpumask.h - single bitmap based implementation

Mikael Pettersson
2004-06-06T15:09:23Z

On Fri, 4 Jun 2004 12:01:46 -0700, Paul Jackson wrote:
>William Lee Irwin III wrote:
>> +void bitmap_to_u32_array(u32 *dst, unsigned long *src, int nwords)
...
>Mikael - does William's routine look like the makings of something
>that fits your needs?

It could, except I think it gets the word order wrong:

+#if defined(__BIG_ENDIAN) && BITS_PER_LONG == 64
+void bitmap_to_u32_array(u32 *dst, unsigned long *src, int nwords)
+{
+ int i;
+
+ for (i = 0; i < nwords; ++i) {
+ u64 word = src[i];
+ dst[2*i] = word >> 32;
+ dst[2*i+1] = word;
+ }
+}
+#else
+void bitmap_to_u32_array(u32 *dst, unsigned long *src, int nwords)
+{
+ memcpy(dst, src, nwords*sizeof(unsigned long));
+}
+#endif

Notice how it emits the high int before the low int.
(Which btw also is the native big-endian storage order,
so the memcpy() would have done the same.)

Now consider the location of bit 0, with mask value 1(*),
on a 64-bit big-endian machine. The code above puts this
in the second int, as bit 0 in *((char*)dst + 7).
But a 32-bit user-space, or a 64-bit user-space that sees
an array of ints not longs, wants it in the first int,
as bit 0 in *((char*)dst + 3).

Perfctr's marshalling procedure for cpumask_t values
(drivers/perfctr/init.c:cpus_copy_to_user() in recent -mm)
is endian-neutral and converts each long by emitting the
ints from least significant to most significant.

Considering the API for retrieving an array of unknown size,
perfctr's marshalling procedure does the following:

> const unsigned int k_nrwords = PERFCTR_CPUMASK_NRLONGS*(sizeof(long)/sizeof(int));
> unsigned int u_nrwords;
> if (get_user(u_nrwords, &argp->nrwords))
> return -EFAULT;
> if (put_user(k_nrwords, &argp->nrwords))
> return -EFAULT;
> if (u_nrwords < k_nrwords)
> return -EOVERFLOW;

That is, it always tells user-space how much space is needed,
and if user-space provided too little, it gets EOVERFLOW.
Knowing the number of words in the encoded cpumask_t also
avoids having to know the exact value of NR_CPUS in user-space.

/Mikael

(*) Normal bit order, not IBM POWER's reversed bit order.