[PATCH] cpumask: introduce new API, without changing anything - Kernel

This is a discussion on [PATCH] cpumask: introduce new API, without changing anything - Kernel ; (Tested in linux-next as well as locally. Linus, please apply). We want to deprecate cpumasks on the stack, as we are headed for gynormous numbers of CPUs. Eventually, we want to head towards an undefined 'struct cpumask' so they can ...

+ Reply to Thread
Results 1 to 16 of 16

Thread: [PATCH] cpumask: introduce new API, without changing anything

  1. [PATCH] cpumask: introduce new API, without changing anything

    (Tested in linux-next as well as locally. Linus, please apply).

    We want to deprecate cpumasks on the stack, as we are headed for
    gynormous numbers of CPUs. Eventually, we want to head towards an
    undefined 'struct cpumask' so they can never be declared on stack.

    1) New cpumask functions which take pointers instead of copies.
    (cpus_* -> cpumask_*)

    2) Several new helpers to reduce requirements for temporary cpumasks
    (cpumask_first_and, cpumask_next_and, cpumask_any_and)

    3) Helpers for declaring cpumasks on or offstack for large NR_CPUS
    (cpumask_var_t, alloc_cpumask_var and free_cpumask_var)

    4) 'struct cpumask' for explicitness and to mark new-style code.

    5) Make iterator functions stop at nr_cpu_ids (a runtime constant),
    not NR_CPUS for time efficiency and for smaller dynamic allocations
    in future.

    6) cpumask_copy() so we can allocate less than a full cpumask eventually
    (for alloc_cpumask_var), and so we can eliminate the 'struct cpumask'
    definition eventually.

    7) work_on_cpu() helper for doing task on a CPU, rather than saving old
    cpumask for current thread and manipulating it.

    8) smp_call_function_many() which is smp_call_function_mask() except
    taking a cpumask pointer.

    Note that this patch simply introduces the new functions and leaves
    the obsolescent ones in place. This is to simplify the transition
    patches.

    (Full kudos to co-author Mike for all the trial-and-error and haggling
    over this new API).

    Signed-off-by: Rusty Russell
    Acked-by: Mike Travis
    ---
    include/linux/cpumask.h | 513 +++++++++++++++++++++++++++++++++++++++++++++-
    include/linux/smp.h | 9
    include/linux/workqueue.h | 8
    kernel/cpu.c | 3
    kernel/workqueue.c | 45 ++++
    lib/cpumask.c | 78 ++++++
    6 files changed, 654 insertions(+), 2 deletions(-)

    diff -r 8f6fe5d6f181 include/linux/cpumask.h
    --- a/include/linux/cpumask.h Wed Nov 05 23:12:20 2008 +1100
    +++ b/include/linux/cpumask.h Fri Nov 07 00:15:12 2008 +1100
    @@ -4,6 +4,9 @@
    /*
    * Cpumasks provide a bitmap suitable for representing the
    * set of CPU's in a system, one bit position per CPU number.
    + *
    + * The new cpumask_ ops take a "struct cpumask *"; the old ones
    + * use cpumask_t.
    *
    * See detailed comments in the file linux/bitmap.h describing the
    * data type on which these cpumasks are based.
    @@ -31,7 +34,7 @@
    * will span the entire range of NR_CPUS.
    * . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
    *
    - * The available cpumask operations are:
    + * The obsolescent cpumask operations are:
    *
    * void cpu_set(cpu, mask) turn on bit 'cpu' in mask
    * void cpu_clear(cpu, mask) turn off bit 'cpu' in mask
    @@ -138,7 +141,7 @@
    #include
    #include

    -typedef struct { DECLARE_BITMAP(bits, NR_CPUS); } cpumask_t;
    +typedef struct cpumask { DECLARE_BITMAP(bits, NR_CPUS); } cpumask_t;
    extern cpumask_t _unused_cpumask_arg_;

    #define cpu_set(cpu, dst) __cpu_set((cpu), &(dst))
    @@ -527,4 +530,510 @@ extern cpumask_t cpu_active_map;
    #define for_each_online_cpu(cpu) for_each_cpu_mask_nr((cpu), cpu_online_map)
    #define for_each_present_cpu(cpu) for_each_cpu_mask_nr((cpu), cpu_present_map)

    +/* These are the new versions of the cpumask operators: passed by pointer.
    + * The older versions will be implemented in terms of these, then deleted. */
    +#define cpumask_bits(maskp) ((maskp)->bits)
    +
    +#if NR_CPUS <= BITS_PER_LONG
    +#define CPU_BITS_ALL \
    +{ \
    + [BITS_TO_LONGS(NR_CPUS)-1] = CPU_MASK_LAST_WORD \
    +}
    +
    +/* This produces more efficient code. */
    +#define nr_cpumask_bits NR_CPUS
    +
    +#else /* NR_CPUS > BITS_PER_LONG */
    +
    +#define CPU_BITS_ALL \
    +{ \
    + [0 ... BITS_TO_LONGS(NR_CPUS)-2] = ~0UL, \
    + [BITS_TO_LONGS(NR_CPUS)-1] = CPU_MASK_LAST_WORD \
    +}
    +
    +#define nr_cpumask_bits nr_cpu_ids
    +#endif /* NR_CPUS > BITS_PER_LONG */
    +
    +/* verify cpu argument to cpumask_* operators */
    +static inline unsigned int cpumask_check(unsigned int cpu)
    +{
    +#ifdef CONFIG_DEBUG_PER_CPU_MAPS
    + WARN_ON_ONCE(cpu >= nr_cpumask_bits);
    +#endif /* CONFIG_DEBUG_PER_CPU_MAPS */
    + return cpu;
    +}
    +
    +#if NR_CPUS == 1
    +/* Uniprocesor. */
    +#define cpumask_first(src) ({ (void)(src); 0; })
    +#define cpumask_next(n, src) ({ (void)(src); 1; })
    +#define cpumask_next_zero(n, src) ({ (void)(src); 1; })
    +#define cpumask_next_and(n, srcp, andp) ({ (void)(srcp), (void)(andp); 1; })
    +#define cpumask_any_but(mask, cpu) ({ (void)(mask); (void)(cpu); 0; })
    +
    +#define for_each_cpu(cpu, mask) \
    + for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask)
    +#define for_each_cpu_and(cpu, mask, and) \
    + for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask, (void)and)
    +#else
    +/**
    + * cpumask_first - get the first cpu in a cpumask
    + * @srcp: the cpumask pointer
    + *
    + * Returns >= nr_cpu_ids if no cpus set.
    + */
    +static inline unsigned int cpumask_first(const struct cpumask *srcp)
    +{
    + return find_first_bit(cpumask_bits(srcp), nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_next - get the next cpu in a cpumask
    + * @n: the cpu prior to the place to search (ie. return will be > @n)
    + * @srcp: the cpumask pointer
    + *
    + * Returns >= nr_cpu_ids if no further cpus set.
    + */
    +static inline unsigned int cpumask_next(int n, const struct cpumask *srcp)
    +{
    + /* -1 is a legal arg here. */
    + if (n != -1)
    + cpumask_check(n);
    + return find_next_bit(cpumask_bits(srcp), nr_cpumask_bits, n+1);
    +}
    +
    +/**
    + * cpumask_next_zero - get the next unset cpu in a cpumask
    + * @n: the cpu prior to the place to search (ie. return will be > @n)
    + * @srcp: the cpumask pointer
    + *
    + * Returns >= nr_cpu_ids if no further cpus unset.
    + */
    +static inline unsigned int cpumask_next_zero(int n, const struct cpumask *srcp)
    +{
    + /* -1 is a legal arg here. */
    + if (n != -1)
    + cpumask_check(n);
    + return find_next_zero_bit(cpumask_bits(srcp), nr_cpumask_bits, n+1);
    +}
    +
    +int cpumask_next_and(int n, const struct cpumask *, const struct cpumask *);
    +int cpumask_any_but(const struct cpumask *mask, unsigned int cpu);
    +
    +#define for_each_cpu(cpu, mask) \
    + for ((cpu) = -1; \
    + (cpu) = cpumask_next((cpu), (mask)), \
    + (cpu) < nr_cpu_ids
    +#define for_each_cpu_and(cpu, mask, and) \
    + for ((cpu) = -1; \
    + (cpu) = cpumask_next_and((cpu), (mask), (and)), \
    + (cpu) < nr_cpu_ids
    +#endif /* SMP */
    +
    +#define CPU_BITS_NONE \
    +{ \
    + [0 ... BITS_TO_LONGS(NR_CPUS)-1] = 0UL \
    +}
    +
    +#define CPU_BITS_CPU0 \
    +{ \
    + [0] = 1UL \
    +}
    +
    +/**
    + * cpumask_set_cpu - set a cpu in a cpumask
    + * @cpu: cpu number (< nr_cpu_ids)
    + * @dstp: the cpumask pointer
    + */
    +static inline void cpumask_set_cpu(unsigned int cpu, struct cpumask *dstp)
    +{
    + set_bit(cpumask_check(cpu), cpumask_bits(dstp));
    +}
    +
    +/**
    + * cpumask_clear_cpu - clear a cpu in a cpumask
    + * @cpu: cpu number (< nr_cpu_ids)
    + * @dstp: the cpumask pointer
    + */
    +static inline void cpumask_clear_cpu(int cpu, struct cpumask *dstp)
    +{
    + clear_bit(cpumask_check(cpu), cpumask_bits(dstp));
    +}
    +
    +/**
    + * cpumask_test_cpu - test for a cpu in a cpumask
    + * @cpu: cpu number (< nr_cpu_ids)
    + * @cpumask: the cpumask pointer
    + *
    + * No static inline type checking - see Subtlety (1) above.
    + */
    +#define cpumask_test_cpu(cpu, cpumask) \
    + test_bit(cpumask_check(cpu), (cpumask)->bits)
    +
    +/**
    + * cpumask_test_and_set_cpu - atomically test and set a cpu in a cpumask
    + * @cpu: cpu number (< nr_cpu_ids)
    + * @cpumask: the cpumask pointer
    + *
    + * test_and_set_bit wrapper for cpumasks.
    + */
    +static inline int cpumask_test_and_set_cpu(int cpu, struct cpumask *cpumask)
    +{
    + return test_and_set_bit(cpumask_check(cpu), cpumask_bits(cpumask));
    +}
    +
    +/**
    + * cpumask_setall - set all cpus (< nr_cpu_ids) in a cpumask
    + * @dstp: the cpumask pointer
    + */
    +static inline void cpumask_setall(struct cpumask *dstp)
    +{
    + bitmap_fill(cpumask_bits(dstp), nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_clear - clear all cpus (< nr_cpu_ids) in a cpumask
    + * @dstp: the cpumask pointer
    + */
    +static inline void cpumask_clear(struct cpumask *dstp)
    +{
    + bitmap_zero(cpumask_bits(dstp), nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_and - *dstp = *src1p & *src2p
    + * @dstp: the cpumask result
    + * @src1p: the first input
    + * @src2p: the second input
    + */
    +static inline void cpumask_and(struct cpumask *dstp,
    + const struct cpumask *src1p,
    + const struct cpumask *src2p)
    +{
    + bitmap_and(cpumask_bits(dstp), cpumask_bits(src1p),
    + cpumask_bits(src2p), nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_or - *dstp = *src1p | *src2p
    + * @dstp: the cpumask result
    + * @src1p: the first input
    + * @src2p: the second input
    + */
    +static inline void cpumask_or(struct cpumask *dstp, const struct cpumask *src1p,
    + const struct cpumask *src2p)
    +{
    + bitmap_or(cpumask_bits(dstp), cpumask_bits(src1p),
    + cpumask_bits(src2p), nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_xor - *dstp = *src1p ^ *src2p
    + * @dstp: the cpumask result
    + * @src1p: the first input
    + * @src2p: the second input
    + */
    +static inline void cpumask_xor(struct cpumask *dstp,
    + const struct cpumask *src1p,
    + const struct cpumask *src2p)
    +{
    + bitmap_xor(cpumask_bits(dstp), cpumask_bits(src1p),
    + cpumask_bits(src2p), nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_andnot - *dstp = *src1p & ~*src2p
    + * @dstp: the cpumask result
    + * @src1p: the first input
    + * @src2p: the second input
    + */
    +static inline void cpumask_andnot(struct cpumask *dstp,
    + const struct cpumask *src1p,
    + const struct cpumask *src2p)
    +{
    + bitmap_andnot(cpumask_bits(dstp), cpumask_bits(src1p),
    + cpumask_bits(src2p), nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_complement - *dstp = ~*srcp
    + * @dstp: the cpumask result
    + * @srcp: the input to invert
    + */
    +static inline void cpumask_complement(struct cpumask *dstp,
    + const struct cpumask *srcp)
    +{
    + bitmap_complement(cpumask_bits(dstp), cpumask_bits(srcp),
    + nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_equal - *src1p == *src2p
    + * @src1p: the first input
    + * @src2p: the second input
    + */
    +static inline bool cpumask_equal(const struct cpumask *src1p,
    + const struct cpumask *src2p)
    +{
    + return bitmap_equal(cpumask_bits(src1p), cpumask_bits(src2p),
    + nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_intersects - (*src1p & *src2p) != 0
    + * @src1p: the first input
    + * @src2p: the second input
    + */
    +static inline bool cpumask_intersects(const struct cpumask *src1p,
    + const struct cpumask *src2p)
    +{
    + return bitmap_intersects(cpumask_bits(src1p), cpumask_bits(src2p),
    + nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_subset - (*src1p & ~*src2p) == 0
    + * @src1p: the first input
    + * @src2p: the second input
    + */
    +static inline int cpumask_subset(const struct cpumask *src1p,
    + const struct cpumask *src2p)
    +{
    + return bitmap_subset(cpumask_bits(src1p), cpumask_bits(src2p),
    + nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_empty - *srcp == 0
    + * @srcp: the cpumask to that all cpus < nr_cpu_ids are clear.
    + */
    +static inline bool cpumask_empty(const struct cpumask *srcp)
    +{
    + return bitmap_empty(cpumask_bits(srcp), nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_full - *srcp == 0xFFFFFFFF...
    + * @srcp: the cpumask to that all cpus < nr_cpu_ids are set.
    + */
    +static inline bool cpumask_full(const struct cpumask *srcp)
    +{
    + return bitmap_full(cpumask_bits(srcp), nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_weight - Count of bits in *srcp
    + * @srcp: the cpumask to count bits (< nr_cpu_ids) in.
    + */
    +static inline unsigned int cpumask_weight(const struct cpumask *srcp)
    +{
    + return bitmap_weight(cpumask_bits(srcp), nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_shift_right - *dstp = *srcp >> n
    + * @dstp: the cpumask result
    + * @srcp: the input to shift
    + * @n: the number of bits to shift by
    + */
    +static inline void cpumask_shift_right(struct cpumask *dstp,
    + const struct cpumask *srcp, int n)
    +{
    + bitmap_shift_right(cpumask_bits(dstp), cpumask_bits(srcp), n,
    + nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_shift_left - *dstp = *srcp << n
    + * @dstp: the cpumask result
    + * @srcp: the input to shift
    + * @n: the number of bits to shift by
    + */
    +static inline void cpumask_shift_left(struct cpumask *dstp,
    + const struct cpumask *srcp, int n)
    +{
    + bitmap_shift_left(cpumask_bits(dstp), cpumask_bits(srcp), n,
    + nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_copy - *dstp = *srcp
    + * @dstp: the result
    + * @srcp: the input cpumask
    + */
    +static inline void cpumask_copy(struct cpumask *dstp,
    + const struct cpumask *srcp)
    +{
    + bitmap_copy(cpumask_bits(dstp), cpumask_bits(srcp), nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_any - pick a "random" cpu from *srcp
    + * @srcp: the input cpumask
    + *
    + * Returns >= nr_cpu_ids if no cpus set.
    + */
    +#define cpumask_any(srcp) cpumask_first(srcp)
    +
    +/**
    + * cpumask_first_and - return the first cpu from *srcp1 & *srcp2
    + * @src1p: the first input
    + * @src2p: the second input
    + *
    + * Returns >= nr_cpu_ids if no cpus set in both. See also cpumask_next_and().
    + */
    +#define cpumask_first_and(src1p, src2p) cpumask_next_and(-1, (src1p), (src2p))
    +
    +/**
    + * cpumask_any_and - pick a "random" cpu from *mask1 & *mask2
    + * @mask1: the first input cpumask
    + * @mask2: the second input cpumask
    + *
    + * Returns >= nr_cpu_ids if no cpus set.
    + */
    +#define cpumask_any_and(mask1, mask2) cpumask_first_and((mask1), (mask2))
    +
    +/**
    + * cpumask_of - the cpumask containing just a given cpu
    + * @cpu: the cpu (<= nr_cpu_ids)
    + */
    +#define cpumask_of(cpu) (get_cpu_mask(cpu))
    +
    +/**
    + * to_cpumask - convert an NR_CPUS bitmap to a struct cpumask *
    + * @bitmap: the bitmap
    + *
    + * There are a few places where cpumask_var_t isn't appropriate and
    + * static cpumasks must be used (eg. very early boot), yet we don't
    + * expose the definition of 'struct cpumask'.
    + *
    + * This does the conversion, and can be used as a constant initializer.
    + */
    +#define to_cpumask(bitmap) \
    + ((struct cpumask *)(1 ? (bitmap) \
    + : (void *)sizeof(__check_is_bitmap(bitmap))))
    +
    +static inline int __check_is_bitmap(const unsigned long *bitmap)
    +{
    + return 1;
    +}
    +
    +/**
    + * cpumask_size - size to allocate for a 'struct cpumask' in bytes
    + *
    + * This will eventually be a runtime variable, depending on nr_cpu_ids.
    + */
    +static inline size_t cpumask_size(void)
    +{
    + /* FIXME: Once all cpumask assignments are eliminated, this
    + * can be nr_cpumask_bits */
    + return BITS_TO_LONGS(NR_CPUS) * sizeof(long);
    +}
    +
    +/*
    + * cpumask_var_t: struct cpumask for stack usage.
    + *
    + * Oh, the wicked games we play! In order to make kernel coding a
    + * little more difficult, we typedef cpumask_var_t to an array or a
    + * pointer: doing &mask on an array is a noop, so it still works.
    + *
    + * ie.
    + * cpumask_var_t tmpmask;
    + * if (!alloc_cpumask_var(&tmpmask, GFP_KERNEL))
    + * return -ENOMEM;
    + *
    + * ... use 'tmpmask' like a normal struct cpumask * ...
    + *
    + * free_cpumask_var(tmpmask);
    + */
    +#ifdef CONFIG_CPUMASK_OFFSTACK
    +typedef struct cpumask *cpumask_var_t;
    +
    +bool alloc_cpumask_var(cpumask_var_t *mask, gfp_t flags);
    +void alloc_bootmem_cpumask_var(cpumask_var_t *mask);
    +void free_cpumask_var(cpumask_var_t mask);
    +void free_bootmem_cpumask_var(cpumask_var_t mask);
    +
    +#else
    +typedef struct cpumask cpumask_var_t[1];
    +
    +static inline bool alloc_cpumask_var(cpumask_var_t *mask, gfp_t flags)
    +{
    + return true;
    +}
    +
    +static inline void alloc_bootmem_cpumask_var(cpumask_var_t *mask)
    +{
    +}
    +
    +static inline void free_cpumask_var(cpumask_var_t mask)
    +{
    +}
    +
    +static inline void free_bootmem_cpumask_var(cpumask_var_t mask)
    +{
    +}
    +#endif /* CONFIG_CPUMASK_OFFSTACK */
    +
    +/* The pointer versions of the maps, these will become the primary versions. */
    +#define cpu_possible_mask ((const struct cpumask *)&cpu_possible_map)
    +#define cpu_online_mask ((const struct cpumask *)&cpu_online_map)
    +#define cpu_present_mask ((const struct cpumask *)&cpu_present_map)
    +#define cpu_active_mask ((const struct cpumask *)&cpu_active_map)
    +
    +/* It's common to want to use cpu_all_mask in struct member initializers,
    + * so it has to refer to an address rather than a pointer. */
    +extern const DECLARE_BITMAP(cpu_all_bits, NR_CPUS);
    +#define cpu_all_mask to_cpumask(cpu_all_bits)
    +
    +/* First bits of cpu_bit_bitmap are in fact unset. */
    +#define cpu_none_mask to_cpumask(cpu_bit_bitmap[0])
    +
    +/* Wrappers for arch boot code to manipulate normally-constant masks */
    +static inline void set_cpu_possible(unsigned int cpu, bool possible)
    +{
    + if (possible)
    + cpumask_set_cpu(cpu, &cpu_possible_map);
    + else
    + cpumask_clear_cpu(cpu, &cpu_possible_map);
    +}
    +
    +static inline void set_cpu_present(unsigned int cpu, bool present)
    +{
    + if (present)
    + cpumask_set_cpu(cpu, &cpu_present_map);
    + else
    + cpumask_clear_cpu(cpu, &cpu_present_map);
    +}
    +
    +static inline void set_cpu_online(unsigned int cpu, bool online)
    +{
    + if (online)
    + cpumask_set_cpu(cpu, &cpu_online_map);
    + else
    + cpumask_clear_cpu(cpu, &cpu_online_map);
    +}
    +
    +static inline void set_cpu_active(unsigned int cpu, bool active)
    +{
    + if (active)
    + cpumask_set_cpu(cpu, &cpu_active_map);
    + else
    + cpumask_clear_cpu(cpu, &cpu_active_map);
    +}
    +
    +static inline void init_cpu_present(const struct cpumask *src)
    +{
    + cpumask_copy(&cpu_present_map, src);
    +}
    +
    +static inline void init_cpu_possible(const struct cpumask *src)
    +{
    + cpumask_copy(&cpu_possible_map, src);
    +}
    +
    +static inline void init_cpu_online(const struct cpumask *src)
    +{
    + cpumask_copy(&cpu_online_map, src);
    +}
    #endif /* __LINUX_CPUMASK_H */
    diff -r 8f6fe5d6f181 include/linux/smp.h
    --- a/include/linux/smp.h Wed Nov 05 23:12:20 2008 +1100
    +++ b/include/linux/smp.h Fri Nov 07 00:15:12 2008 +1100
    @@ -64,8 +64,17 @@ extern void smp_cpus_done(unsigned int m
    * Call a function on all other processors
    */
    int smp_call_function(void(*func)(void *info), void *info, int wait);
    +/* Deprecated: use smp_call_function_many() which uses a cpumask ptr. */
    int smp_call_function_mask(cpumask_t mask, void(*func)(void *info), void *info,
    int wait);
    +
    +static inline void smp_call_function_many(const struct cpumask *mask,
    + void (*func)(void *info), void *info,
    + int wait)
    +{
    + smp_call_function_mask(*mask, func, info, wait);
    +}
    +
    int smp_call_function_single(int cpuid, void (*func) (void *info), void *info,
    int wait);
    void __smp_call_function_single(int cpuid, struct call_single_data *data);
    diff -r 8f6fe5d6f181 include/linux/workqueue.h
    --- a/include/linux/workqueue.h Wed Nov 05 23:12:20 2008 +1100
    +++ b/include/linux/workqueue.h Fri Nov 07 00:15:12 2008 +1100
    @@ -240,4 +240,12 @@ void cancel_rearming_delayed_work(struct
    cancel_delayed_work_sync(work);
    }

    +#ifndef CONFIG_SMP
    +static inline long work_on_cpu(unsigned int cpu, long (*fn)(void *), void *arg)
    +{
    + return fn(arg);
    +}
    +#else
    +long work_on_cpu(unsigned int cpu, long (*fn)(void *), void *arg);
    +#endif /* CONFIG_SMP */
    #endif
    diff -r 8f6fe5d6f181 kernel/cpu.c
    --- a/kernel/cpu.c Wed Nov 05 23:12:20 2008 +1100
    +++ b/kernel/cpu.c Fri Nov 07 00:15:12 2008 +1100
    @@ -499,3 +499,6 @@ const unsigned long cpu_bit_bitmap[BITS_
    #endif
    };
    EXPORT_SYMBOL_GPL(cpu_bit_bitmap);
    +
    +const DECLARE_BITMAP(cpu_all_bits, NR_CPUS) = CPU_BITS_ALL;
    +EXPORT_SYMBOL(cpu_all_bits);
    diff -r 8f6fe5d6f181 kernel/workqueue.c
    --- a/kernel/workqueue.c Wed Nov 05 23:12:20 2008 +1100
    +++ b/kernel/workqueue.c Fri Nov 07 00:15:12 2008 +1100
    @@ -970,6 +970,51 @@ undo:
    return ret;
    }

    +#ifdef CONFIG_SMP
    +struct work_for_cpu {
    + struct work_struct work;
    + long (*fn)(void *);
    + void *arg;
    + long ret;
    +};
    +
    +static void do_work_for_cpu(struct work_struct *w)
    +{
    + struct work_for_cpu *wfc = container_of(w, struct work_for_cpu, work);
    +
    + wfc->ret = wfc->fn(wfc->arg);
    +}
    +
    +/**
    + * work_on_cpu - run a function in user context on a particular cpu
    + * @cpu: the cpu to run on
    + * @fn: the function to run
    + * @arg: the function arg
    + *
    + * This will return -EINVAL in the cpu is not online, or the return value
    + * of @fn otherwise.
    + */
    +long work_on_cpu(unsigned int cpu, long (*fn)(void *), void *arg)
    +{
    + struct work_for_cpu wfc;
    +
    + INIT_WORK(&wfc.work, do_work_for_cpu);
    + wfc.fn = fn;
    + wfc.arg = arg;
    + get_online_cpus();
    + if (unlikely(!cpu_online(cpu)))
    + wfc.ret = -EINVAL;
    + else {
    + schedule_work_on(cpu, &wfc.work);
    + flush_work(&wfc.work);
    + }
    + put_online_cpus();
    +
    + return wfc.ret;
    +}
    +EXPORT_SYMBOL_GPL(work_on_cpu);
    +#endif /* CONFIG_SMP */
    +
    void __init init_workqueues(void)
    {
    cpu_populated_map = cpu_online_map;
    diff -r 8f6fe5d6f181 lib/cpumask.c
    --- a/lib/cpumask.c Wed Nov 05 23:12:20 2008 +1100
    +++ b/lib/cpumask.c Fri Nov 07 00:15:12 2008 +1100
    @@ -2,6 +2,7 @@
    #include
    #include
    #include
    +#include

    int __first_cpu(const cpumask_t *srcp)
    {
    @@ -35,3 +36,80 @@ int __any_online_cpu(const cpumask_t *ma
    return cpu;
    }
    EXPORT_SYMBOL(__any_online_cpu);
    +
    +/**
    + * cpumask_next_and - get the next cpu in *src1p & *src2p
    + * @n: the cpu prior to the place to search (ie. return will be > @n)
    + * @src1p: the first cpumask pointer
    + * @src2p: the second cpumask pointer
    + *
    + * Returns >= nr_cpu_ids if no further cpus set in both.
    + */
    +int cpumask_next_and(int n, const struct cpumask *src1p,
    + const struct cpumask *src2p)
    +{
    + while ((n = cpumask_next(n, src1p)) < nr_cpu_ids)
    + if (cpumask_test_cpu(n, src2p))
    + break;
    + return n;
    +}
    +EXPORT_SYMBOL(cpumask_next_and);
    +
    +/**
    + * cpumask_any_but - return a "random" in a cpumask, but not this one.
    + * @mask: the cpumask to search
    + * @cpu: the cpu to ignore.
    + *
    + * Often used to find any cpu but smp_processor_id() in a mask.
    + * Returns >= nr_cpu_ids if no cpus set.
    + */
    +int cpumask_any_but(const struct cpumask *mask, unsigned int cpu)
    +{
    + unsigned int i;
    +
    + for_each_cpu(i, mask)
    + if (i != cpu)
    + break;
    + return i;
    +}
    +
    +/* These are not inline because of header tangles. */
    +#ifdef CONFIG_CPUMASK_OFFSTACK
    +bool alloc_cpumask_var(cpumask_var_t *mask, gfp_t flags)
    +{
    + if (likely(slab_is_available()))
    + *mask = kmalloc(cpumask_size(), flags);
    + else {
    +#ifdef CONFIG_DEBUG_PER_CPU_MAPS
    + printk(KERN_ERR
    + "=> alloc_cpumask_var: kmalloc not available!\n");
    + dump_stack();
    +#endif
    + *mask = NULL;
    + }
    +#ifdef CONFIG_DEBUG_PER_CPU_MAPS
    + if (!*mask) {
    + printk(KERN_ERR "=> alloc_cpumask_var: failed!\n");
    + dump_stack();
    + }
    +#endif
    + return *mask != NULL;
    +}
    +EXPORT_SYMBOL(alloc_cpumask_var);
    +
    +void __init alloc_bootmem_cpumask_var(cpumask_var_t *mask)
    +{
    + *mask = alloc_bootmem(cpumask_size());
    +}
    +
    +void free_cpumask_var(cpumask_var_t mask)
    +{
    + kfree(mask);
    +}
    +EXPORT_SYMBOL(free_cpumask_var);
    +
    +void free_bootmem_cpumask_var(cpumask_var_t mask)
    +{
    + free_bootmem((unsigned long)mask, cpumask_size());
    +}
    +#endif


    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  2. Re: [PATCH] cpumask: introduce new API, without changing anything


    * Rusty Russell wrote:

    > (Tested in linux-next as well as locally. Linus, please apply).


    if this is equal to the patch that you sent me (see the git
    coordinates below), it was also stess-tested and build-coverage tested
    by me on a healthy range of x86 systems, in a range of build
    environments.

    > Signed-off-by: Rusty Russell
    > Acked-by: Mike Travis


    Acked-by: Ingo Molnar

    Ingo

    -------------->

    The cpus4096 git tree can be pulled from:

    git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip.git cpus4096

    Thanks,

    Ingo

    ------------------>
    Rusty Russell (1):
    cpumask: introduce new API, without changing anything


    include/linux/cpumask.h | 502 ++++++++++++++++++++++++++++++++++++++++++++-
    include/linux/smp.h | 9 +
    include/linux/workqueue.h | 8 +
    kernel/cpu.c | 3 +
    kernel/workqueue.c | 45 ++++
    lib/cpumask.c | 73 +++++++
    6 files changed, 638 insertions(+), 2 deletions(-)

    diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h
    index d3219d7..c8e6661 100644
    --- a/include/linux/cpumask.h
    +++ b/include/linux/cpumask.h
    @@ -5,6 +5,9 @@
    * Cpumasks provide a bitmap suitable for representing the
    * set of CPU's in a system, one bit position per CPU number.
    *
    + * The new cpumask_ ops take a "struct cpumask *"; the old ones
    + * use cpumask_t.
    + *
    * See detailed comments in the file linux/bitmap.h describing the
    * data type on which these cpumasks are based.
    *
    @@ -31,7 +34,7 @@
    * will span the entire range of NR_CPUS.
    * . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
    *
    - * The available cpumask operations are:
    + * The obsolescent cpumask operations are:
    *
    * void cpu_set(cpu, mask) turn on bit 'cpu' in mask
    * void cpu_clear(cpu, mask) turn off bit 'cpu' in mask
    @@ -138,7 +141,7 @@
    #include
    #include

    -typedef struct { DECLARE_BITMAP(bits, NR_CPUS); } cpumask_t;
    +typedef struct cpumask { DECLARE_BITMAP(bits, NR_CPUS); } cpumask_t;
    extern cpumask_t _unused_cpumask_arg_;

    #define cpu_set(cpu, dst) __cpu_set((cpu), &(dst))
    @@ -527,4 +530,499 @@ extern cpumask_t cpu_active_map;
    #define for_each_online_cpu(cpu) for_each_cpu_mask_nr((cpu), cpu_online_map)
    #define for_each_present_cpu(cpu) for_each_cpu_mask_nr((cpu), cpu_present_map)

    +/* These are the new versions of the cpumask operators: passed by pointer.
    + * The older versions will be implemented in terms of these, then deleted. */
    +#define cpumask_bits(maskp) ((maskp)->bits)
    +
    +#if NR_CPUS <= BITS_PER_LONG
    +#define CPU_BITS_ALL \
    +{ \
    + [BITS_TO_LONGS(NR_CPUS)-1] = CPU_MASK_LAST_WORD \
    +}
    +
    +/* This produces more efficient code. */
    +#define nr_cpumask_bits NR_CPUS
    +
    +#else /* NR_CPUS > BITS_PER_LONG */
    +
    +#define CPU_BITS_ALL \
    +{ \
    + [0 ... BITS_TO_LONGS(NR_CPUS)-2] = ~0UL, \
    + [BITS_TO_LONGS(NR_CPUS)-1] = CPU_MASK_LAST_WORD \
    +}
    +
    +#define nr_cpumask_bits nr_cpu_ids
    +#endif /* NR_CPUS > BITS_PER_LONG */
    +
    +/* verify cpu argument to cpumask_* operators */
    +static inline unsigned int cpumask_check(unsigned int cpu)
    +{
    +#ifdef CONFIG_DEBUG_PER_CPU_MAPS
    + WARN_ON_ONCE(cpu >= nr_cpumask_bits);
    +#endif /* CONFIG_DEBUG_PER_CPU_MAPS */
    + return cpu;
    +}
    +
    +#if NR_CPUS == 1
    +/* Uniprocesor. */
    +#define cpumask_first(src) ({ (void)(src); 0; })
    +#define cpumask_next(n, src) ({ (void)(src); 1; })
    +#define cpumask_next_zero(n, src) ({ (void)(src); 1; })
    +#define cpumask_next_and(n, srcp, andp) ({ (void)(srcp), (void)(andp); 1; })
    +#define cpumask_any_but(mask, cpu) ({ (void)(mask); (void)(cpu); 0; })
    +
    +#define for_each_cpu(cpu, mask) \
    + for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask)
    +#define for_each_cpu_and(cpu, mask, and) \
    + for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask, (void)and)
    +#else
    +/**
    + * cpumask_first - get the first cpu in a cpumask
    + * @srcp: the cpumask pointer
    + *
    + * Returns >= nr_cpu_ids if no cpus set.
    + */
    +static inline unsigned int cpumask_first(const struct cpumask *srcp)
    +{
    + return find_first_bit(cpumask_bits(srcp), nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_next - get the next cpu in a cpumask
    + * @n: the cpu prior to the place to search (ie. return will be > @n)
    + * @srcp: the cpumask pointer
    + *
    + * Returns >= nr_cpu_ids if no further cpus set.
    + */
    +static inline unsigned int cpumask_next(int n, const struct cpumask *srcp)
    +{
    + /* -1 is a legal arg here. */
    + if (n != -1)
    + cpumask_check(n);
    + return find_next_bit(cpumask_bits(srcp), nr_cpumask_bits, n+1);
    +}
    +
    +/**
    + * cpumask_next_zero - get the next unset cpu in a cpumask
    + * @n: the cpu prior to the place to search (ie. return will be > @n)
    + * @srcp: the cpumask pointer
    + *
    + * Returns >= nr_cpu_ids if no further cpus unset.
    + */
    +static inline unsigned int cpumask_next_zero(int n, const struct cpumask *srcp)
    +{
    + /* -1 is a legal arg here. */
    + if (n != -1)
    + cpumask_check(n);
    + return find_next_zero_bit(cpumask_bits(srcp), nr_cpumask_bits, n+1);
    +}
    +
    +int cpumask_next_and(int n, const struct cpumask *, const struct cpumask *);
    +int cpumask_any_but(const struct cpumask *mask, unsigned int cpu);
    +
    +#define for_each_cpu(cpu, mask) \
    + for ((cpu) = -1; \
    + (cpu) = cpumask_next((cpu), (mask)), \
    + (cpu) < nr_cpu_ids
    +#define for_each_cpu_and(cpu, mask, and) \
    + for ((cpu) = -1; \
    + (cpu) = cpumask_next_and((cpu), (mask), (and)), \
    + (cpu) < nr_cpu_ids
    +#endif /* SMP */
    +
    +#define CPU_BITS_NONE \
    +{ \
    + [0 ... BITS_TO_LONGS(NR_CPUS)-1] = 0UL \
    +}
    +
    +#define CPU_BITS_CPU0 \
    +{ \
    + [0] = 1UL \
    +}
    +
    +/**
    + * cpumask_set_cpu - set a cpu in a cpumask
    + * @cpu: cpu number (< nr_cpu_ids)
    + * @dstp: the cpumask pointer
    + */
    +static inline void cpumask_set_cpu(unsigned int cpu, struct cpumask *dstp)
    +{
    + set_bit(cpumask_check(cpu), cpumask_bits(dstp));
    +}
    +
    +/**
    + * cpumask_clear_cpu - clear a cpu in a cpumask
    + * @cpu: cpu number (< nr_cpu_ids)
    + * @dstp: the cpumask pointer
    + */
    +static inline void cpumask_clear_cpu(int cpu, struct cpumask *dstp)
    +{
    + clear_bit(cpumask_check(cpu), cpumask_bits(dstp));
    +}
    +
    +/**
    + * cpumask_test_cpu - test for a cpu in a cpumask
    + * @cpu: cpu number (< nr_cpu_ids)
    + * @cpumask: the cpumask pointer
    + *
    + * No static inline type checking - see Subtlety (1) above.
    + */
    +#define cpumask_test_cpu(cpu, cpumask) \
    + test_bit(cpumask_check(cpu), (cpumask)->bits)
    +
    +/**
    + * cpumask_test_and_set_cpu - atomically test and set a cpu in a cpumask
    + * @cpu: cpu number (< nr_cpu_ids)
    + * @cpumask: the cpumask pointer
    + *
    + * test_and_set_bit wrapper for cpumasks.
    + */
    +static inline int cpumask_test_and_set_cpu(int cpu, struct cpumask *cpumask)
    +{
    + return test_and_set_bit(cpumask_check(cpu), cpumask_bits(cpumask));
    +}
    +
    +/**
    + * cpumask_setall - set all cpus (< nr_cpu_ids) in a cpumask
    + * @dstp: the cpumask pointer
    + */
    +static inline void cpumask_setall(struct cpumask *dstp)
    +{
    + bitmap_fill(cpumask_bits(dstp), nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_clear - clear all cpus (< nr_cpu_ids) in a cpumask
    + * @dstp: the cpumask pointer
    + */
    +static inline void cpumask_clear(struct cpumask *dstp)
    +{
    + bitmap_zero(cpumask_bits(dstp), nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_and - *dstp = *src1p & *src2p
    + * @dstp: the cpumask result
    + * @src1p: the first input
    + * @src2p: the second input
    + */
    +static inline void cpumask_and(struct cpumask *dstp,
    + const struct cpumask *src1p,
    + const struct cpumask *src2p)
    +{
    + bitmap_and(cpumask_bits(dstp), cpumask_bits(src1p),
    + cpumask_bits(src2p), nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_or - *dstp = *src1p | *src2p
    + * @dstp: the cpumask result
    + * @src1p: the first input
    + * @src2p: the second input
    + */
    +static inline void cpumask_or(struct cpumask *dstp, const struct cpumask *src1p,
    + const struct cpumask *src2p)
    +{
    + bitmap_or(cpumask_bits(dstp), cpumask_bits(src1p),
    + cpumask_bits(src2p), nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_xor - *dstp = *src1p ^ *src2p
    + * @dstp: the cpumask result
    + * @src1p: the first input
    + * @src2p: the second input
    + */
    +static inline void cpumask_xor(struct cpumask *dstp,
    + const struct cpumask *src1p,
    + const struct cpumask *src2p)
    +{
    + bitmap_xor(cpumask_bits(dstp), cpumask_bits(src1p),
    + cpumask_bits(src2p), nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_andnot - *dstp = *src1p & ~*src2p
    + * @dstp: the cpumask result
    + * @src1p: the first input
    + * @src2p: the second input
    + */
    +static inline void cpumask_andnot(struct cpumask *dstp,
    + const struct cpumask *src1p,
    + const struct cpumask *src2p)
    +{
    + bitmap_andnot(cpumask_bits(dstp), cpumask_bits(src1p),
    + cpumask_bits(src2p), nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_complement - *dstp = ~*srcp
    + * @dstp: the cpumask result
    + * @srcp: the input to invert
    + */
    +static inline void cpumask_complement(struct cpumask *dstp,
    + const struct cpumask *srcp)
    +{
    + bitmap_complement(cpumask_bits(dstp), cpumask_bits(srcp),
    + nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_equal - *src1p == *src2p
    + * @src1p: the first input
    + * @src2p: the second input
    + */
    +static inline bool cpumask_equal(const struct cpumask *src1p,
    + const struct cpumask *src2p)
    +{
    + return bitmap_equal(cpumask_bits(src1p), cpumask_bits(src2p),
    + nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_intersects - (*src1p & *src2p) != 0
    + * @src1p: the first input
    + * @src2p: the second input
    + */
    +static inline bool cpumask_intersects(const struct cpumask *src1p,
    + const struct cpumask *src2p)
    +{
    + return bitmap_intersects(cpumask_bits(src1p), cpumask_bits(src2p),
    + nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_subset - (*src1p & ~*src2p) == 0
    + * @src1p: the first input
    + * @src2p: the second input
    + */
    +static inline int cpumask_subset(const struct cpumask *src1p,
    + const struct cpumask *src2p)
    +{
    + return bitmap_subset(cpumask_bits(src1p), cpumask_bits(src2p),
    + nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_empty - *srcp == 0
    + * @srcp: the cpumask to that all cpus < nr_cpu_ids are clear.
    + */
    +static inline bool cpumask_empty(const struct cpumask *srcp)
    +{
    + return bitmap_empty(cpumask_bits(srcp), nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_full - *srcp == 0xFFFFFFFF...
    + * @srcp: the cpumask to that all cpus < nr_cpu_ids are set.
    + */
    +static inline bool cpumask_full(const struct cpumask *srcp)
    +{
    + return bitmap_full(cpumask_bits(srcp), nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_weight - Count of bits in *srcp
    + * @srcp: the cpumask to count bits (< nr_cpu_ids) in.
    + */
    +static inline unsigned int cpumask_weight(const struct cpumask *srcp)
    +{
    + return bitmap_weight(cpumask_bits(srcp), nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_shift_right - *dstp = *srcp >> n
    + * @dstp: the cpumask result
    + * @srcp: the input to shift
    + * @n: the number of bits to shift by
    + */
    +static inline void cpumask_shift_right(struct cpumask *dstp,
    + const struct cpumask *srcp, int n)
    +{
    + bitmap_shift_right(cpumask_bits(dstp), cpumask_bits(srcp), n,
    + nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_shift_left - *dstp = *srcp << n
    + * @dstp: the cpumask result
    + * @srcp: the input to shift
    + * @n: the number of bits to shift by
    + */
    +static inline void cpumask_shift_left(struct cpumask *dstp,
    + const struct cpumask *srcp, int n)
    +{
    + bitmap_shift_left(cpumask_bits(dstp), cpumask_bits(srcp), n,
    + nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_copy - *dstp = *srcp
    + * @dstp: the result
    + * @srcp: the input cpumask
    + */
    +static inline void cpumask_copy(struct cpumask *dstp,
    + const struct cpumask *srcp)
    +{
    + bitmap_copy(cpumask_bits(dstp), cpumask_bits(srcp), nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_any - pick a "random" cpu from *srcp
    + * @srcp: the input cpumask
    + *
    + * Returns >= nr_cpu_ids if no cpus set.
    + */
    +#define cpumask_any(srcp) cpumask_first(srcp)
    +
    +/**
    + * cpumask_first_and - return the first cpu from *srcp1 & *srcp2
    + * @src1p: the first input
    + * @src2p: the second input
    + *
    + * Returns >= nr_cpu_ids if no cpus set in both. See also cpumask_next_and().
    + */
    +#define cpumask_first_and(src1p, src2p) cpumask_next_and(-1, (src1p), (src2p))
    +
    +/**
    + * cpumask_any_and - pick a "random" cpu from *mask1 & *mask2
    + * @mask1: the first input cpumask
    + * @mask2: the second input cpumask
    + *
    + * Returns >= nr_cpu_ids if no cpus set.
    + */
    +#define cpumask_any_and(mask1, mask2) cpumask_first_and((mask1), (mask2))
    +
    +/**
    + * to_cpumask - convert an NR_CPUS bitmap to a struct cpumask *
    + * @bitmap: the bitmap
    + *
    + * There are a few places where cpumask_var_t isn't appropriate and
    + * static cpumasks must be used (eg. very early boot), yet we don't
    + * expose the definition of 'struct cpumask'.
    + *
    + * This does the conversion, and can be used as a constant initializer.
    + */
    +#define to_cpumask(bitmap) \
    + ((struct cpumask *)(1 ? (bitmap) \
    + : (void *)sizeof(__check_is_bitmap(bitmap))))
    +
    +static inline int __check_is_bitmap(const unsigned long *bitmap)
    +{
    + return 1;
    +}
    +
    +/**
    + * cpumask_size - size to allocate for a 'struct cpumask' in bytes
    + *
    + * This will eventually be a runtime variable, depending on nr_cpu_ids.
    + */
    +static inline size_t cpumask_size(void)
    +{
    + /* FIXME: Once all cpumask assignments are eliminated, this
    + * can be nr_cpumask_bits */
    + return BITS_TO_LONGS(NR_CPUS) * sizeof(long);
    +}
    +
    +/*
    + * cpumask_var_t: struct cpumask for stack usage.
    + *
    + * Oh, the wicked games we play! In order to make kernel coding a
    + * little more difficult, we typedef cpumask_var_t to an array or a
    + * pointer: doing &mask on an array is a noop, so it still works.
    + *
    + * ie.
    + * cpumask_var_t tmpmask;
    + * if (!alloc_cpumask_var(&tmpmask, GFP_KERNEL))
    + * return -ENOMEM;
    + *
    + * ... use 'tmpmask' like a normal struct cpumask * ...
    + *
    + * free_cpumask_var(tmpmask);
    + */
    +#ifdef CONFIG_CPUMASK_OFFSTACK
    +typedef struct cpumask *cpumask_var_t;
    +
    +bool alloc_cpumask_var(cpumask_var_t *mask, gfp_t flags);
    +void alloc_bootmem_cpumask_var(cpumask_var_t *mask);
    +void free_cpumask_var(cpumask_var_t mask);
    +
    +#else
    +typedef struct cpumask cpumask_var_t[1];
    +
    +static inline bool alloc_cpumask_var(cpumask_var_t *mask, gfp_t flags)
    +{
    + return true;
    +}
    +
    +static inline void alloc_bootmem_cpumask_var(cpumask_var_t *mask)
    +{
    +}
    +
    +static inline void free_cpumask_var(cpumask_var_t mask)
    +{
    +}
    +#endif /* CONFIG_CPUMASK_OFFSTACK */
    +
    +/* The pointer versions of the maps, these will become the primary versions. */
    +#define cpu_possible_mask ((const struct cpumask *)&cpu_possible_map)
    +#define cpu_online_mask ((const struct cpumask *)&cpu_online_map)
    +#define cpu_present_mask ((const struct cpumask *)&cpu_present_map)
    +#define cpu_active_mask ((const struct cpumask *)&cpu_active_map)
    +
    +/* It's common to want to use cpu_all_mask in struct member initializers,
    + * so it has to refer to an address rather than a pointer. */
    +extern const DECLARE_BITMAP(cpu_all_bits, NR_CPUS);
    +#define cpu_all_mask to_cpumask(cpu_all_bits)
    +
    +/* First bits of cpu_bit_bitmap are in fact unset. */
    +#define cpu_none_mask to_cpumask(cpu_bit_bitmap[0])
    +
    +/* Wrappers for arch boot code to manipulate normally-constant masks */
    +static inline void set_cpu_possible(unsigned int cpu, bool possible)
    +{
    + if (possible)
    + cpumask_set_cpu(cpu, &cpu_possible_map);
    + else
    + cpumask_clear_cpu(cpu, &cpu_possible_map);
    +}
    +
    +static inline void set_cpu_present(unsigned int cpu, bool present)
    +{
    + if (present)
    + cpumask_set_cpu(cpu, &cpu_present_map);
    + else
    + cpumask_clear_cpu(cpu, &cpu_present_map);
    +}
    +
    +static inline void set_cpu_online(unsigned int cpu, bool online)
    +{
    + if (online)
    + cpumask_set_cpu(cpu, &cpu_online_map);
    + else
    + cpumask_clear_cpu(cpu, &cpu_online_map);
    +}
    +
    +static inline void set_cpu_active(unsigned int cpu, bool active)
    +{
    + if (active)
    + cpumask_set_cpu(cpu, &cpu_active_map);
    + else
    + cpumask_clear_cpu(cpu, &cpu_active_map);
    +}
    +
    +static inline void init_cpu_present(const struct cpumask *src)
    +{
    + cpumask_copy(&cpu_present_map, src);
    +}
    +
    +static inline void init_cpu_possible(const struct cpumask *src)
    +{
    + cpumask_copy(&cpu_possible_map, src);
    +}
    +
    +static inline void init_cpu_online(const struct cpumask *src)
    +{
    + cpumask_copy(&cpu_online_map, src);
    +}
    #endif /* __LINUX_CPUMASK_H */
    diff --git a/include/linux/smp.h b/include/linux/smp.h
    index 2e4d58b..3f9a600 100644
    --- a/include/linux/smp.h
    +++ b/include/linux/smp.h
    @@ -64,8 +64,17 @@ extern void smp_cpus_done(unsigned int max_cpus);
    * Call a function on all other processors
    */
    int smp_call_function(void(*func)(void *info), void *info, int wait);
    +/* Deprecated: use smp_call_function_many() which uses a cpumask ptr. */
    int smp_call_function_mask(cpumask_t mask, void(*func)(void *info), void *info,
    int wait);
    +
    +static inline void smp_call_function_many(const struct cpumask *mask,
    + void (*func)(void *info), void *info,
    + int wait)
    +{
    + smp_call_function_mask(*mask, func, info, wait);
    +}
    +
    int smp_call_function_single(int cpuid, void (*func) (void *info), void *info,
    int wait);
    void __smp_call_function_single(int cpuid, struct call_single_data *data);
    diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
    index 89a5a12..b362911 100644
    --- a/include/linux/workqueue.h
    +++ b/include/linux/workqueue.h
    @@ -240,4 +240,12 @@ void cancel_rearming_delayed_work(struct delayed_work *work)
    cancel_delayed_work_sync(work);
    }

    +#ifndef CONFIG_SMP
    +static inline long work_on_cpu(unsigned int cpu, long (*fn)(void *), void *arg)
    +{
    + return fn(arg);
    +}
    +#else
    +long work_on_cpu(unsigned int cpu, long (*fn)(void *), void *arg);
    +#endif /* CONFIG_SMP */
    #endif
    diff --git a/kernel/cpu.c b/kernel/cpu.c
    index 86d4904..5a732c5 100644
    --- a/kernel/cpu.c
    +++ b/kernel/cpu.c
    @@ -499,3 +499,6 @@ const unsigned long cpu_bit_bitmap[BITS_PER_LONG+1][BITS_TO_LONGS(NR_CPUS)] = {
    #endif
    };
    EXPORT_SYMBOL_GPL(cpu_bit_bitmap);
    +
    +const DECLARE_BITMAP(cpu_all_bits, NR_CPUS) = CPU_BITS_ALL;
    +EXPORT_SYMBOL(cpu_all_bits);
    diff --git a/kernel/workqueue.c b/kernel/workqueue.c
    index f928f2a..d4dc69d 100644
    --- a/kernel/workqueue.c
    +++ b/kernel/workqueue.c
    @@ -970,6 +970,51 @@ undo:
    return ret;
    }

    +#ifdef CONFIG_SMP
    +struct work_for_cpu {
    + struct work_struct work;
    + long (*fn)(void *);
    + void *arg;
    + long ret;
    +};
    +
    +static void do_work_for_cpu(struct work_struct *w)
    +{
    + struct work_for_cpu *wfc = container_of(w, struct work_for_cpu, work);
    +
    + wfc->ret = wfc->fn(wfc->arg);
    +}
    +
    +/**
    + * work_on_cpu - run a function in user context on a particular cpu
    + * @cpu: the cpu to run on
    + * @fn: the function to run
    + * @arg: the function arg
    + *
    + * This will return -EINVAL in the cpu is not online, or the return value
    + * of @fn otherwise.
    + */
    +long work_on_cpu(unsigned int cpu, long (*fn)(void *), void *arg)
    +{
    + struct work_for_cpu wfc;
    +
    + INIT_WORK(&wfc.work, do_work_for_cpu);
    + wfc.fn = fn;
    + wfc.arg = arg;
    + get_online_cpus();
    + if (unlikely(!cpu_online(cpu)))
    + wfc.ret = -EINVAL;
    + else {
    + schedule_work_on(cpu, &wfc.work);
    + flush_work(&wfc.work);
    + }
    + put_online_cpus();
    +
    + return wfc.ret;
    +}
    +EXPORT_SYMBOL_GPL(work_on_cpu);
    +#endif /* CONFIG_SMP */
    +
    void __init init_workqueues(void)
    {
    cpu_populated_map = cpu_online_map;
    diff --git a/lib/cpumask.c b/lib/cpumask.c
    index 5f97dc2..5ceb421 100644
    --- a/lib/cpumask.c
    +++ b/lib/cpumask.c
    @@ -2,6 +2,7 @@
    #include
    #include
    #include
    +#include

    int __first_cpu(const cpumask_t *srcp)
    {
    @@ -35,3 +36,75 @@ int __any_online_cpu(const cpumask_t *mask)
    return cpu;
    }
    EXPORT_SYMBOL(__any_online_cpu);
    +
    +/**
    + * cpumask_next_and - get the next cpu in *src1p & *src2p
    + * @n: the cpu prior to the place to search (ie. return will be > @n)
    + * @src1p: the first cpumask pointer
    + * @src2p: the second cpumask pointer
    + *
    + * Returns >= nr_cpu_ids if no further cpus set in both.
    + */
    +int cpumask_next_and(int n, const struct cpumask *src1p,
    + const struct cpumask *src2p)
    +{
    + while ((n = cpumask_next(n, src1p)) < nr_cpu_ids)
    + if (cpumask_test_cpu(n, src2p))
    + break;
    + return n;
    +}
    +EXPORT_SYMBOL(cpumask_next_and);
    +
    +/**
    + * cpumask_any_but - return a "random" in a cpumask, but not this one.
    + * @mask: the cpumask to search
    + * @cpu: the cpu to ignore.
    + *
    + * Often used to find any cpu but smp_processor_id() in a mask.
    + * Returns >= nr_cpu_ids if no cpus set.
    + */
    +int cpumask_any_but(const struct cpumask *mask, unsigned int cpu)
    +{
    + unsigned int i;
    +
    + for_each_cpu(i, mask)
    + if (i != cpu)
    + break;
    + return i;
    +}
    +
    +/* These are not inline because of header tangles. */
    +#ifdef CONFIG_CPUMASK_OFFSTACK
    +bool alloc_cpumask_var(cpumask_var_t *mask, gfp_t flags)
    +{
    + if (likely(slab_is_available()))
    + *mask = kmalloc(cpumask_size(), flags);
    + else {
    +#ifdef CONFIG_DEBUG_PER_CPU_MAPS
    + printk(KERN_ERR
    + "=> alloc_cpumask_var: kmalloc not available!\n");
    + dump_stack();
    +#endif
    + *mask = NULL;
    + }
    +#ifdef CONFIG_DEBUG_PER_CPU_MAPS
    + if (!*mask) {
    + printk(KERN_ERR "=> alloc_cpumask_var: failed!\n");
    + dump_stack();
    + }
    +#endif
    + return *mask != NULL;
    +}
    +EXPORT_SYMBOL(alloc_cpumask_var);
    +
    +void __init alloc_bootmem_cpumask_var(cpumask_var_t *mask)
    +{
    + *mask = alloc_bootmem(cpumask_size());
    +}
    +
    +void free_cpumask_var(cpumask_var_t mask)
    +{
    + kfree(mask);
    +}
    +EXPORT_SYMBOL(free_cpumask_var);
    +#endif
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  3. Re: [PATCH] cpumask: introduce new API, without changing anything

    On Fri, 7 Nov 2008 09:40:16 +0100 Ingo Molnar wrote:

    > +#if NR_CPUS == 1
    > +/* Uniprocesor. */
    > +#define cpumask_first(src) ({ (void)(src); 0; })
    >
    > ...
    >
    > +#else
    > +static inline unsigned int cpumask_first(const struct cpumask *srcp)
    > +{
    > + return find_first_bit(cpumask_bits(srcp), nr_cpumask_bits);
    > +}
    >
    > ...
    >
    > +#endif /* SMP */


    So I can happily compile and run

    cpumask_first("hello, world");

    with CONFIG_SMP=n?

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  4. Re: [PATCH] cpumask: introduce new API, without changing anything


    * Andrew Morton wrote:

    > > +#if NR_CPUS == 1
    > > +/* Uniprocesor. */


    btw: s/Uniprocesor/Uniprocessor

    > > +#define cpumask_first(src) ({ (void)(src); 0; })
    > >
    > > ...
    > >
    > > +#else
    > > +static inline unsigned int cpumask_first(const struct cpumask *srcp)
    > > +{
    > > + return find_first_bit(cpumask_bits(srcp), nr_cpumask_bits);
    > > +}
    > >
    > > ...
    > >
    > > +#endif /* SMP */

    >
    > So I can happily compile and run
    >
    > cpumask_first("hello, world");
    >
    > with CONFIG_SMP=n?


    yeah, you are right that the use of a macro sucks there, it should be
    an inline function.

    We should stop using CPP, which is the outdated tech of the sixties.
    We should go with the new wave of the seventies and use this shiny new
    "C" language that's all the rage with features like type checking and
    stuff.

    Ingo
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  5. Re: [PATCH] cpumask: introduce new API, without changing anything

    Hi Ingo,

    On Fri, 7 Nov 2008 09:40:16 +0100 Ingo Molnar wrote:
    >
    > if this is equal to the patch that you sent me (see the git
    > coordinates below), it was also stess-tested and build-coverage tested
    > by me on a healthy range of x86 systems, in a range of build
    > environments.


    It isn't identical. See my message about a small merge conflict between
    the cpus4096 tree and the rr tree in linux-next today.

    --
    Cheers,
    Stephen Rothwell sfr@canb.auug.org.au
    http://www.canb.auug.org.au/~sfr/

    -----BEGIN PGP SIGNATURE-----
    Version: GnuPG v1.4.9 (GNU/Linux)

    iEYEARECAAYFAkkUBksACgkQjjKRsyhoI8zV+gCcCA/i5dKxihbIM6qBQoah1scG
    LqwAn0drbMwbriLTMW7CQmGqWMSndUiq
    =iG5a
    -----END PGP SIGNATURE-----


  6. Re: [PATCH] cpumask: introduce new API, without changing anything


    * Stephen Rothwell wrote:

    > Hi Ingo,
    >
    > On Fri, 7 Nov 2008 09:40:16 +0100 Ingo Molnar wrote:
    > >
    > > if this is equal to the patch that you sent me (see the git
    > > coordinates below), it was also stess-tested and build-coverage tested
    > > by me on a healthy range of x86 systems, in a range of build
    > > environments.

    >
    > It isn't identical. See my message about a small merge conflict
    > between the cpus4096 tree and the rr tree in linux-next today.


    but the change was not due to some merge conflict, it was a change
    done to the patch itself.

    The merge conflict happened because Rusty iterated the patch in a
    non-append manner so two versions of the same patch collided in
    linux-next.

    So ... what was the change, was it _really_ tested as-is in the
    linux-next tree for a longer time, or just merged a couple of hours
    ago?

    Rusty, i pointed it out before, this kind of workflow you use in the
    rr tree is really inefficient for such types of changes. You destroy
    testing results by rebasing all the time, you make changes harder to
    review and as an end result you make it harder to achieve a better end
    result.

    Ingo
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  7. Re: [PATCH] cpumask: introduce new API, without changing anything

    On Friday 07 November 2008 19:52:29 Andrew Morton wrote:
    > So I can happily compile and run
    >
    > cpumask_first("hello, world");
    >
    > with CONFIG_SMP=n?


    Good point. It was based on the existing "first_cpu", but it's not a practice
    we should encourage.

    Hmm, the implementation of these UP versions is wrong in corner cases, too.
    Obviously it doesn't currently matter the way they are used, but a nasty trap
    for the future.

    Here's the addition, I've queued it for linux-next (which will next come out
    after the weekend).

    diff -u b/include/linux/cpumask.h b/include/linux/cpumask.h
    --- b/include/linux/cpumask.h Fri Nov 07 00:15:12 2008 +1100
    +++ b/include/linux/cpumask.h Fri Nov 07 22:28:33 2008 +1100
    @@ -564,12 +564,36 @@
    }

    #if NR_CPUS == 1
    -/* Uniprocesor. */
    -#define cpumask_first(src) ({ (void)(src); 0; })
    -#define cpumask_next(n, src) ({ (void)(src); 1; })
    -#define cpumask_next_zero(n, src) ({ (void)(src); 1; })
    -#define cpumask_next_and(n, srcp, andp) ({ (void)(srcp), (void)(andp); 1; })
    -#define cpumask_any_but(mask, cpu) ({ (void)(mask); (void)(cpu); 0; })
    +/* Uniprocessor. Assume all masks are "1". */
    +static inline unsigned int cpumask_first(const struct cpumask *srcp)
    +{
    + return 0;
    +}
    +
    +/* Valid inputs for n are -1 and 0. */
    +static inline unsigned int cpumask_next(int n, const struct cpumask *srcp)
    +{
    + return n+1;
    +}
    +
    +static inline unsigned int cpumask_next_zero(int n, const struct cpumask *srcp)
    +{
    + return n+1;
    +}
    +
    +static inline unsigned int cpumask_next_and(int n,
    + const struct cpumask *srcp,
    + const struct cpumask *andp)
    +{
    + return n+1;
    +}
    +
    +/* cpu must be a valid cpu, ie 0, so there's no other choice. */
    +static inline unsigned int cpumask_any_but(const struct cpumask *mask,
    + unsigned int cpu)
    +{
    + return 1;
    +}

    #define for_each_cpu(cpu, mask) \
    for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask)
    diff -u b/lib/cpumask.c b/lib/cpumask.c
    --- b/lib/cpumask.c Fri Nov 07 00:15:12 2008 +1100
    +++ b/lib/cpumask.c Fri Nov 07 22:28:33 2008 +1100
    @@ -67,6 +67,7 @@
    {
    unsigned int i;

    + cpumask_check(cpu);
    for_each_cpu(i, mask)
    if (i != cpu)
    break;



    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  8. Re: [PATCH] cpumask: introduce new API, without changing anything


    * Ingo Molnar wrote:

    > but the change was not due to some merge conflict, it was a change
    > done to the patch itself.
    >
    > The merge conflict happened because Rusty iterated the patch in a
    > non-append manner so two versions of the same patch collided in
    > linux-next.
    >
    > So ... what was the change, was it _really_ tested as-is in the
    > linux-next tree for a longer time, or just merged a couple of hours
    > ago?


    hm, i just researched it a bit, and the patch Rusty just submitted to
    Linus was not in linux-next it appears, as the modified commit is just
    a few hours old.

    Find below the delta patch between the two versions, and an
    analysis/review of the changes. I've started testing it as well, and
    it's looking good so far.

    Here is when the new version showed up in linux-next a few hours ago:

    | commit 92a8334f1b0ad1f65127bc763ab214d6b60ec966
    | Author: Stephen Rothwell
    | AuthorDate: Fri Nov 7 20:44:35 2008 +1100
    | Commit: Stephen Rothwell
    | CommitDate: Fri Nov 7 20:44:35 2008 +1100
    |
    | Add linux-next specific files for 20081107

    It was a new (and modified) quilt-exported commit from "quilt/rr":

    | 0c82f41: cpumask:new-API-only
    |
    | Author: Rusty Russell
    | AuthorDate: Fri Nov 7 11:12:29 2008 +1100
    | Commit: Stephen Rothwell
    | CommitDate: Fri Nov 7 11:12:29 2008 +1100

    Which collided with a previous version of that patch in the cpus4096
    tree:

    | 2d3854a: cpumask: introduce new API, without changing anything
    |
    | Author: Rusty Russell
    | AuthorDate: Wed Nov 5 13:39:10 2008 +1100
    | CommitDate: Thu Nov 6 09:05:33 2008 +0100

    "0c82f41: cpumask:new-API-only" thus has only a couple of hours of
    lifetime and the "this has been in linux-next" is only true for that
    short time period.

    So ... i've reconstructed what's new in 0c82f41, and i came up with
    the delta patch below.

    Review of the delta patch:

    - the cpumask_of() is added to the SMP section of cpumask.h but not to
    the UP section. Similarly, some of the other SMP APIs are not
    declared in the UP section either. (Furthermore, the macros in the
    UP section should really be inlines, not macros - as akpm noticed it
    too.)

    - the free_bootmem_cpumask_var() addition looks good but is a tiny bit
    incomplete: the free_bootmem_cpumask_var() function should be marked
    __init, like all bootmem methods are.

    i guess these changes should be OK.

    Note that such types of minor problems are very easy to spot and
    address in an append-only workflow (even if you just emulate it in
    quilt), but are hidden and laborous to extract with an agreesive
    quilt-rebasing history-eating workflow that just exports completely
    new versions of patches.

    Just in case you are wondering why i care so much about 'your' patch:
    i'd like it to go upstream. The patch and the plan affects subsystems
    i'm (co-)maintaining, in a nontrivial way, (scheduler, irq and x86
    code), and the cpumask code caused trouble in the past so i'd like to
    know _exactly_ what future changes go into it. Isnt that a fair
    interest?

    But your "rr tree" is not suitable at all to follow the development of
    this effort. Deltas are not transparent and reviewable, the changes
    are mixed into other changes and you force me into this kind of review
    and delta patch forensics and that is very inefficient - and it
    obviously harms the end result and wastes time for no good reason.

    And yes, when all is said and done and everyone's happy there's no
    problem with eventually collapsing delta patches together into a
    single clean patch.

    Most of the time it's not _worth_ touching existing history with
    folding patches: as you can see it from the patch below, there's no
    technical reason why it could not have been a separate delta patch.
    Those changes do not cause _any_ bisection barrier, nor do they cause
    any other of problem either.

    And dont get me wrong, destroying the delta was not malice on your
    part in any way, it was "just" a side-effect destruction of
    information that resulted out of your customary work flow. I realize
    that you like and prefer that workflow, and that you have used it for
    years, but you should also accept it when i point out the problems
    that it causes down the line.

    And the thing is, a year ago i was in similar shoes and i was on the
    receiving end of similar complaints, and in hindsight i do not regret
    at all having changed to a Git workflow =B-)

    Ingo

    ----------------->
    From cd83e42c6b0413dcbb548c2ead799111ff7e6a13 Mon Sep 17 00:00:00 2001
    From: Rusty Russell
    Date: Fri, 7 Nov 2008 11:12:29 +1100
    Subject: [PATCH] cpumask: new API, v2

    - add cpumask_of()
    - add free_bootmem_cpumask_var()

    Signed-off-by: Rusty Russell
    Signed-off-by: Ingo Molnar
    ---
    include/linux/cpumask.h | 11 +++++++++++
    lib/cpumask.c | 5 +++++
    2 files changed, 16 insertions(+), 0 deletions(-)

    diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h
    index c8e6661..31caa1b 100644
    --- a/include/linux/cpumask.h
    +++ b/include/linux/cpumask.h
    @@ -894,6 +894,12 @@ static inline void cpumask_copy(struct cpumask *dstp,
    #define cpumask_any_and(mask1, mask2) cpumask_first_and((mask1), (mask2))

    /**
    + * cpumask_of - the cpumask containing just a given cpu
    + * @cpu: the cpu (<= nr_cpu_ids)
    + */
    +#define cpumask_of(cpu) (get_cpu_mask(cpu))
    +
    +/**
    * to_cpumask - convert an NR_CPUS bitmap to a struct cpumask *
    * @bitmap: the bitmap
    *
    @@ -946,6 +952,7 @@ typedef struct cpumask *cpumask_var_t;
    bool alloc_cpumask_var(cpumask_var_t *mask, gfp_t flags);
    void alloc_bootmem_cpumask_var(cpumask_var_t *mask);
    void free_cpumask_var(cpumask_var_t mask);
    +void free_bootmem_cpumask_var(cpumask_var_t mask);

    #else
    typedef struct cpumask cpumask_var_t[1];
    @@ -962,6 +969,10 @@ static inline void alloc_bootmem_cpumask_var(cpumask_var_t *mask)
    static inline void free_cpumask_var(cpumask_var_t mask)
    {
    }
    +
    +static inline void free_bootmem_cpumask_var(cpumask_var_t mask)
    +{
    +}
    #endif /* CONFIG_CPUMASK_OFFSTACK */

    /* The pointer versions of the maps, these will become the primary versions. */
    diff --git a/lib/cpumask.c b/lib/cpumask.c
    index 5ceb421..2ebc3a9 100644
    --- a/lib/cpumask.c
    +++ b/lib/cpumask.c
    @@ -107,4 +107,9 @@ void free_cpumask_var(cpumask_var_t mask)
    kfree(mask);
    }
    EXPORT_SYMBOL(free_cpumask_var);
    +
    +void free_bootmem_cpumask_var(cpumask_var_t mask)
    +{
    + free_bootmem((unsigned long)mask, cpumask_size());
    +}
    #endif
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  9. Re: [PATCH] cpumask: introduce new API, without changing anything

    Ingo Molnar wrote:
    ....
    > Find below the delta patch between the two versions, and an
    > analysis/review of the changes. I've started testing it as well, and
    > it's looking good so far.
    >

    ....
    > "0c82f41: cpumask:new-API-only" thus has only a couple of hours of
    > lifetime and the "this has been in linux-next" is only true for that
    > short time period.
    >
    > So ... i've reconstructed what's new in 0c82f41, and i came up with
    > the delta patch below.

    ....
    >>From cd83e42c6b0413dcbb548c2ead799111ff7e6a13 Mon Sep 17 00:00:00 2001

    > From: Rusty Russell
    > Date: Fri, 7 Nov 2008 11:12:29 +1100
    > Subject: [PATCH] cpumask: new API, v2
    >
    > - add cpumask_of()
    > - add free_bootmem_cpumask_var()

    ....

    I'd like to begin resubmitting the patches that were in the cpus4096-v2
    branch but I'm not quite sure how to set up the git tree. I have:

    git-remote add linus git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
    git-remote add tip git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip.git
    git-remote update
    git-checkout -b cpus4096 tip/cpus4096

    But I don't see the linux-next changes (like cpumask_first for uniprocessor), so I'm
    guessing I need to either merge in linux-next, or insert it into the above setup
    commands?

    Fyi, hopefully this patch submission conduit will work:

    generic only: via linux-next
    arch-specific (x86 + others): Rusty via arch-maintainers (linux-next?)
    (x86 only): Mike via tip/cpus4096

    Does this work for you?

    Thanks,
    Mike

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  10. Re: [PATCH] cpumask: introduce new API, without changing anything

    On Friday 07 November 2008 23:24:00 Ingo Molnar wrote:
    > Find below the delta patch between the two versions, and an
    > analysis/review of the changes. I've started testing it as well, and
    > it's looking good so far.


    Ok, I sent through the latest delta on top of this before, but see below.

    > - the cpumask_of() is added to the SMP section of cpumask.h but not to
    > the UP section.


    Not quite: it's in the general section. Don't scare me like that

    > - the free_bootmem_cpumask_var() addition looks good but is a tiny bit
    > incomplete: the free_bootmem_cpumask_var() function should be marked
    > __init, like all bootmem methods are.


    Looks like you took that draft I mailed around? Mike asked for free_... as a
    response to that. But I'll fix the __init.

    I've restored the patch into that version you have, plus separate updates. I
    hope that fixes the workflow issues.

    Updates below for reference.

    Thanks,
    Rusty.
    ===
    Signed-off-by: Rusty Russell

    diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h
    --- a/include/linux/cpumask.h
    +++ b/include/linux/cpumask.h
    @@ -894,6 +894,12 @@ static inline void cpumask_copy(struct c
    #define cpumask_any_and(mask1, mask2) cpumask_first_and((mask1), (mask2))

    /**
    + * cpumask_of - the cpumask containing just a given cpu
    + * @cpu: the cpu (<= nr_cpu_ids)
    + */
    +#define cpumask_of(cpu) (get_cpu_mask(cpu))
    +
    +/**
    * to_cpumask - convert an NR_CPUS bitmap to a struct cpumask *
    * @bitmap: the bitmap
    *
    @@ -946,6 +952,7 @@ bool alloc_cpumask_var(cpumask_var_t *ma
    bool alloc_cpumask_var(cpumask_var_t *mask, gfp_t flags);
    void alloc_bootmem_cpumask_var(cpumask_var_t *mask);
    void free_cpumask_var(cpumask_var_t mask);
    +void free_bootmem_cpumask_var(cpumask_var_t mask);

    #else
    typedef struct cpumask cpumask_var_t[1];
    @@ -960,6 +967,10 @@ static inline void alloc_bootmem_cpumask
    }

    static inline void free_cpumask_var(cpumask_var_t mask)
    +{
    +}
    +
    +static inline void free_bootmem_cpumask_var(cpumask_var_t mask)
    {
    }
    #endif /* CONFIG_CPUMASK_OFFSTACK */
    diff --git a/lib/cpumask.c b/lib/cpumask.c
    --- a/lib/cpumask.c
    +++ b/lib/cpumask.c
    @@ -107,4 +107,9 @@ void free_cpumask_var(cpumask_var_t mask
    kfree(mask);
    }
    EXPORT_SYMBOL(free_cpumask_var);
    +
    +void free_bootmem_cpumask_var(cpumask_var_t mask)
    +{
    + free_bootmem((unsigned long)mask, cpumask_size());
    +}
    #endif
    ===
    1) Andrew pointed out inlines are superior to macros. Also, UP versions
    weren't correct in all cases (doesn't matter at the moment, but
    nasty surprise one day).

    2) Documentation was missing for for_each_cpu and for_each_cpu_and.

    3) As we state when fixing the UP version, the "cpu" arg to
    "cpumask_any_but()" must be a valid CPU number, so add debug check.

    Signed-off-by: Rusty Russell

    diff -r 09f8198c811d include/linux/cpumask.h
    --- a/include/linux/cpumask.h Sat Nov 08 20:05:51 2008 +1100
    +++ b/include/linux/cpumask.h Sat Nov 08 20:10:07 2008 +1100
    @@ -564,12 +564,36 @@ static inline unsigned int cpumask_check
    }

    #if NR_CPUS == 1
    -/* Uniprocesor. */
    -#define cpumask_first(src) ({ (void)(src); 0; })
    -#define cpumask_next(n, src) ({ (void)(src); 1; })
    -#define cpumask_next_zero(n, src) ({ (void)(src); 1; })
    -#define cpumask_next_and(n, srcp, andp) ({ (void)(srcp), (void)(andp); 1; })
    -#define cpumask_any_but(mask, cpu) ({ (void)(mask); (void)(cpu); 0; })
    +/* Uniprocessor. Assume all masks are "1". */
    +static inline unsigned int cpumask_first(const struct cpumask *srcp)
    +{
    + return 0;
    +}
    +
    +/* Valid inputs for n are -1 and 0. */
    +static inline unsigned int cpumask_next(int n, const struct cpumask *srcp)
    +{
    + return n+1;
    +}
    +
    +static inline unsigned int cpumask_next_zero(int n, const struct cpumask *srcp)
    +{
    + return n+1;
    +}
    +
    +static inline unsigned int cpumask_next_and(int n,
    + const struct cpumask *srcp,
    + const struct cpumask *andp)
    +{
    + return n+1;
    +}
    +
    +/* cpu must be a valid cpu, ie 0, so there's no other choice. */
    +static inline unsigned int cpumask_any_but(const struct cpumask *mask,
    + unsigned int cpu)
    +{
    + return 1;
    +}

    #define for_each_cpu(cpu, mask) \
    for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask)
    @@ -620,10 +644,32 @@ int cpumask_next_and(int n, const struct
    int cpumask_next_and(int n, const struct cpumask *, const struct cpumask *);
    int cpumask_any_but(const struct cpumask *mask, unsigned int cpu);

    +/**
    + * for_each_cpu - iterate over every cpu in a mask
    + * @cpu: the (optionally unsigned) integer iterator
    + * @mask: the cpumask pointer
    + *
    + * After the loop, cpu is >= nr_cpu_ids.
    + */
    #define for_each_cpu(cpu, mask) \
    for ((cpu) = -1; \
    (cpu) = cpumask_next((cpu), (mask)), \
    (cpu) < nr_cpu_ids
    +
    +/**
    + * for_each_cpu_and - iterate over every cpu in both masks
    + * @cpu: the (optionally unsigned) integer iterator
    + * @mask: the first cpumask pointer
    + * @and: the second cpumask pointer
    + *
    + * This saves a temporary CPU mask in many places. It is equivalent to:
    + * struct cpumask tmp;
    + * cpumask_and(&tmp, &mask, &and);
    + * for_each_cpu(cpu, &tmp)
    + * ...
    + *
    + * After the loop, cpu is >= nr_cpu_ids.
    + */
    #define for_each_cpu_and(cpu, mask, and) \
    for ((cpu) = -1; \
    (cpu) = cpumask_next_and((cpu), (mask), (and)), \
    diff -r 09f8198c811d lib/cpumask.c
    --- a/lib/cpumask.c Sat Nov 08 20:05:51 2008 +1100
    +++ b/lib/cpumask.c Sat Nov 08 20:10:07 2008 +1100
    @@ -67,6 +67,7 @@ int cpumask_any_but(const struct cpumask
    {
    unsigned int i;

    + cpumask_check(cpu);
    for_each_cpu(i, mask)
    if (i != cpu)
    break;
    ===
    Ingo points out that free_bootmem_cpumask_var() should be __init.

    Signed-off-by: Rusty Russell

    diff -r dfda8a1507d5 lib/cpumask.c
    --- a/lib/cpumask.c Sat Nov 08 20:10:15 2008 +1100
    +++ b/lib/cpumask.c Sat Nov 08 20:19:14 2008 +1100
    @@ -109,7 +109,7 @@ void free_cpumask_var(cpumask_var_t mask
    }
    EXPORT_SYMBOL(free_cpumask_var);

    -void free_bootmem_cpumask_var(cpumask_var_t mask)
    +void __init free_bootmem_cpumask_var(cpumask_var_t mask)
    {
    free_bootmem((unsigned long)mask, cpumask_size());
    }









    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  11. Re: [PATCH] cpumask: introduce new API, without changing anything


    * Rusty Russell wrote:

    > On Friday 07 November 2008 23:24:00 Ingo Molnar wrote:
    > > Find below the delta patch between the two versions, and an
    > > analysis/review of the changes. I've started testing it as well, and
    > > it's looking good so far.

    >
    > Ok, I sent through the latest delta on top of this before, but see below.
    >
    > > - the cpumask_of() is added to the SMP section of cpumask.h but not to
    > > the UP section.

    >
    > Not quite: it's in the general section. Don't scare me like that


    heh, indeed - i looked twice and both times i missed this in the
    middle of that code:

    #endif /* SMP */

    .... sorry, my bad! (a newline before this line might have helped)

    > > - the free_bootmem_cpumask_var() addition looks good but is a tiny bit
    > > incomplete: the free_bootmem_cpumask_var() function should be marked
    > > __init, like all bootmem methods are.

    >
    > Looks like you took that draft I mailed around? Mike asked for
    > free_... as a response to that. But I'll fix the __init.
    >
    > I've restored the patch into that version you have, plus separate
    > updates. I hope that fixes the workflow issues.
    >
    > Updates below for reference.


    thanks a ton, this looks perfect.

    Mike, could you please double-check that the version that is in
    tip/cpus4096 [622e0ed] is the final version you need, and that if you
    base subsequent patches on it it works as expected?

    Then it would be all green and Rusty could send the final version of
    the patch to Linus. It has my ack obviously:

    Acked-by: Ingo Molnar

    and once that patch hits upstream, we could restructure/rebase the
    commits in cpus4096-v2 ontop of upstream and spread them out properly.
    Does that sound optimal?

    Thomas also did a cross-build of it, and it looks all good:

    Run 141: 2008-11-07 13:54:41 .. 2008-11-07 15:02:59

    Run 141: 17 of 19 operations OK
    Run 141: 2 of 19 operations FAILED

    http://www.tglx.de/autoqa-logs/000141-0008-0005.log
    http://www.tglx.de/autoqa-logs/000141-0008-0015.log

    the two build failures are not related to these changes.

    Ingo
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  12. Re: [PATCH] cpumask: introduce new API, without changing anything



    On Sat, 8 Nov 2008, Rusty Russell wrote:
    >
    > Ok, I sent through the latest delta on top of this before, but see below.


    Can somebody send a final patch-set to me? Right now I have multiple
    versions of patches, apparently on top of each other, and sometimes
    multiple patches per email. Very confusing, and I do _not_ want to apply
    the wrong thing by mistake.

    Linus
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  13. Re: [PATCH] cpumask: introduce new API, without changing anything


    * Linus Torvalds wrote:

    > On Sat, 8 Nov 2008, Rusty Russell wrote:
    > >
    > > Ok, I sent through the latest delta on top of this before, but see below.

    >
    > Can somebody send a final patch-set to me? Right now I have multiple
    > versions of patches, apparently on top of each other, and sometimes
    > multiple patches per email. Very confusing, and I do _not_ want to
    > apply the wrong thing by mistake.


    I've got them collected and tested (and so has Rusty), see the tree
    URI below. There's no pending problem left that i know of. I also just
    did a fresh test-build and test-boot of this tree, for good measure.

    Ingo

    -------------------->

    the latest cpus4096 git tree can be found at:

    git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip.git cpus4096

    Thanks,

    Ingo

    ------------------>
    Rusty Russell (3):
    cpumask: introduce new API, without changing anything
    cpumask: new API, v2
    cpumask: introduce new API, without changing anything, v3


    include/linux/cpumask.h | 559 ++++++++++++++++++++++++++++++++++++++++++++-
    include/linux/smp.h | 9 +
    include/linux/workqueue.h | 8 +
    kernel/cpu.c | 3 +
    kernel/workqueue.c | 45 ++++
    lib/cpumask.c | 79 +++++++
    6 files changed, 701 insertions(+), 2 deletions(-)

    diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h
    index d3219d7..21e1dd4 100644
    --- a/include/linux/cpumask.h
    +++ b/include/linux/cpumask.h
    @@ -5,6 +5,9 @@
    * Cpumasks provide a bitmap suitable for representing the
    * set of CPU's in a system, one bit position per CPU number.
    *
    + * The new cpumask_ ops take a "struct cpumask *"; the old ones
    + * use cpumask_t.
    + *
    * See detailed comments in the file linux/bitmap.h describing the
    * data type on which these cpumasks are based.
    *
    @@ -31,7 +34,7 @@
    * will span the entire range of NR_CPUS.
    * . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
    *
    - * The available cpumask operations are:
    + * The obsolescent cpumask operations are:
    *
    * void cpu_set(cpu, mask) turn on bit 'cpu' in mask
    * void cpu_clear(cpu, mask) turn off bit 'cpu' in mask
    @@ -138,7 +141,7 @@
    #include
    #include

    -typedef struct { DECLARE_BITMAP(bits, NR_CPUS); } cpumask_t;
    +typedef struct cpumask { DECLARE_BITMAP(bits, NR_CPUS); } cpumask_t;
    extern cpumask_t _unused_cpumask_arg_;

    #define cpu_set(cpu, dst) __cpu_set((cpu), &(dst))
    @@ -527,4 +530,556 @@ extern cpumask_t cpu_active_map;
    #define for_each_online_cpu(cpu) for_each_cpu_mask_nr((cpu), cpu_online_map)
    #define for_each_present_cpu(cpu) for_each_cpu_mask_nr((cpu), cpu_present_map)

    +/* These are the new versions of the cpumask operators: passed by pointer.
    + * The older versions will be implemented in terms of these, then deleted. */
    +#define cpumask_bits(maskp) ((maskp)->bits)
    +
    +#if NR_CPUS <= BITS_PER_LONG
    +#define CPU_BITS_ALL \
    +{ \
    + [BITS_TO_LONGS(NR_CPUS)-1] = CPU_MASK_LAST_WORD \
    +}
    +
    +/* This produces more efficient code. */
    +#define nr_cpumask_bits NR_CPUS
    +
    +#else /* NR_CPUS > BITS_PER_LONG */
    +
    +#define CPU_BITS_ALL \
    +{ \
    + [0 ... BITS_TO_LONGS(NR_CPUS)-2] = ~0UL, \
    + [BITS_TO_LONGS(NR_CPUS)-1] = CPU_MASK_LAST_WORD \
    +}
    +
    +#define nr_cpumask_bits nr_cpu_ids
    +#endif /* NR_CPUS > BITS_PER_LONG */
    +
    +/* verify cpu argument to cpumask_* operators */
    +static inline unsigned int cpumask_check(unsigned int cpu)
    +{
    +#ifdef CONFIG_DEBUG_PER_CPU_MAPS
    + WARN_ON_ONCE(cpu >= nr_cpumask_bits);
    +#endif /* CONFIG_DEBUG_PER_CPU_MAPS */
    + return cpu;
    +}
    +
    +#if NR_CPUS == 1
    +/* Uniprocessor. Assume all masks are "1". */
    +static inline unsigned int cpumask_first(const struct cpumask *srcp)
    +{
    + return 0;
    +}
    +
    +/* Valid inputs for n are -1 and 0. */
    +static inline unsigned int cpumask_next(int n, const struct cpumask *srcp)
    +{
    + return n+1;
    +}
    +
    +static inline unsigned int cpumask_next_zero(int n, const struct cpumask *srcp)
    +{
    + return n+1;
    +}
    +
    +static inline unsigned int cpumask_next_and(int n,
    + const struct cpumask *srcp,
    + const struct cpumask *andp)
    +{
    + return n+1;
    +}
    +
    +/* cpu must be a valid cpu, ie 0, so there's no other choice. */
    +static inline unsigned int cpumask_any_but(const struct cpumask *mask,
    + unsigned int cpu)
    +{
    + return 1;
    +}
    +
    +#define for_each_cpu(cpu, mask) \
    + for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask)
    +#define for_each_cpu_and(cpu, mask, and) \
    + for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask, (void)and)
    +#else
    +/**
    + * cpumask_first - get the first cpu in a cpumask
    + * @srcp: the cpumask pointer
    + *
    + * Returns >= nr_cpu_ids if no cpus set.
    + */
    +static inline unsigned int cpumask_first(const struct cpumask *srcp)
    +{
    + return find_first_bit(cpumask_bits(srcp), nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_next - get the next cpu in a cpumask
    + * @n: the cpu prior to the place to search (ie. return will be > @n)
    + * @srcp: the cpumask pointer
    + *
    + * Returns >= nr_cpu_ids if no further cpus set.
    + */
    +static inline unsigned int cpumask_next(int n, const struct cpumask *srcp)
    +{
    + /* -1 is a legal arg here. */
    + if (n != -1)
    + cpumask_check(n);
    + return find_next_bit(cpumask_bits(srcp), nr_cpumask_bits, n+1);
    +}
    +
    +/**
    + * cpumask_next_zero - get the next unset cpu in a cpumask
    + * @n: the cpu prior to the place to search (ie. return will be > @n)
    + * @srcp: the cpumask pointer
    + *
    + * Returns >= nr_cpu_ids if no further cpus unset.
    + */
    +static inline unsigned int cpumask_next_zero(int n, const struct cpumask *srcp)
    +{
    + /* -1 is a legal arg here. */
    + if (n != -1)
    + cpumask_check(n);
    + return find_next_zero_bit(cpumask_bits(srcp), nr_cpumask_bits, n+1);
    +}
    +
    +int cpumask_next_and(int n, const struct cpumask *, const struct cpumask *);
    +int cpumask_any_but(const struct cpumask *mask, unsigned int cpu);
    +
    +/**
    + * for_each_cpu - iterate over every cpu in a mask
    + * @cpu: the (optionally unsigned) integer iterator
    + * @mask: the cpumask pointer
    + *
    + * After the loop, cpu is >= nr_cpu_ids.
    + */
    +#define for_each_cpu(cpu, mask) \
    + for ((cpu) = -1; \
    + (cpu) = cpumask_next((cpu), (mask)), \
    + (cpu) < nr_cpu_ids
    +
    +/**
    + * for_each_cpu_and - iterate over every cpu in both masks
    + * @cpu: the (optionally unsigned) integer iterator
    + * @mask: the first cpumask pointer
    + * @and: the second cpumask pointer
    + *
    + * This saves a temporary CPU mask in many places. It is equivalent to:
    + * struct cpumask tmp;
    + * cpumask_and(&tmp, &mask, &and);
    + * for_each_cpu(cpu, &tmp)
    + * ...
    + *
    + * After the loop, cpu is >= nr_cpu_ids.
    + */
    +#define for_each_cpu_and(cpu, mask, and) \
    + for ((cpu) = -1; \
    + (cpu) = cpumask_next_and((cpu), (mask), (and)), \
    + (cpu) < nr_cpu_ids
    +#endif /* SMP */
    +
    +#define CPU_BITS_NONE \
    +{ \
    + [0 ... BITS_TO_LONGS(NR_CPUS)-1] = 0UL \
    +}
    +
    +#define CPU_BITS_CPU0 \
    +{ \
    + [0] = 1UL \
    +}
    +
    +/**
    + * cpumask_set_cpu - set a cpu in a cpumask
    + * @cpu: cpu number (< nr_cpu_ids)
    + * @dstp: the cpumask pointer
    + */
    +static inline void cpumask_set_cpu(unsigned int cpu, struct cpumask *dstp)
    +{
    + set_bit(cpumask_check(cpu), cpumask_bits(dstp));
    +}
    +
    +/**
    + * cpumask_clear_cpu - clear a cpu in a cpumask
    + * @cpu: cpu number (< nr_cpu_ids)
    + * @dstp: the cpumask pointer
    + */
    +static inline void cpumask_clear_cpu(int cpu, struct cpumask *dstp)
    +{
    + clear_bit(cpumask_check(cpu), cpumask_bits(dstp));
    +}
    +
    +/**
    + * cpumask_test_cpu - test for a cpu in a cpumask
    + * @cpu: cpu number (< nr_cpu_ids)
    + * @cpumask: the cpumask pointer
    + *
    + * No static inline type checking - see Subtlety (1) above.
    + */
    +#define cpumask_test_cpu(cpu, cpumask) \
    + test_bit(cpumask_check(cpu), (cpumask)->bits)
    +
    +/**
    + * cpumask_test_and_set_cpu - atomically test and set a cpu in a cpumask
    + * @cpu: cpu number (< nr_cpu_ids)
    + * @cpumask: the cpumask pointer
    + *
    + * test_and_set_bit wrapper for cpumasks.
    + */
    +static inline int cpumask_test_and_set_cpu(int cpu, struct cpumask *cpumask)
    +{
    + return test_and_set_bit(cpumask_check(cpu), cpumask_bits(cpumask));
    +}
    +
    +/**
    + * cpumask_setall - set all cpus (< nr_cpu_ids) in a cpumask
    + * @dstp: the cpumask pointer
    + */
    +static inline void cpumask_setall(struct cpumask *dstp)
    +{
    + bitmap_fill(cpumask_bits(dstp), nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_clear - clear all cpus (< nr_cpu_ids) in a cpumask
    + * @dstp: the cpumask pointer
    + */
    +static inline void cpumask_clear(struct cpumask *dstp)
    +{
    + bitmap_zero(cpumask_bits(dstp), nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_and - *dstp = *src1p & *src2p
    + * @dstp: the cpumask result
    + * @src1p: the first input
    + * @src2p: the second input
    + */
    +static inline void cpumask_and(struct cpumask *dstp,
    + const struct cpumask *src1p,
    + const struct cpumask *src2p)
    +{
    + bitmap_and(cpumask_bits(dstp), cpumask_bits(src1p),
    + cpumask_bits(src2p), nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_or - *dstp = *src1p | *src2p
    + * @dstp: the cpumask result
    + * @src1p: the first input
    + * @src2p: the second input
    + */
    +static inline void cpumask_or(struct cpumask *dstp, const struct cpumask *src1p,
    + const struct cpumask *src2p)
    +{
    + bitmap_or(cpumask_bits(dstp), cpumask_bits(src1p),
    + cpumask_bits(src2p), nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_xor - *dstp = *src1p ^ *src2p
    + * @dstp: the cpumask result
    + * @src1p: the first input
    + * @src2p: the second input
    + */
    +static inline void cpumask_xor(struct cpumask *dstp,
    + const struct cpumask *src1p,
    + const struct cpumask *src2p)
    +{
    + bitmap_xor(cpumask_bits(dstp), cpumask_bits(src1p),
    + cpumask_bits(src2p), nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_andnot - *dstp = *src1p & ~*src2p
    + * @dstp: the cpumask result
    + * @src1p: the first input
    + * @src2p: the second input
    + */
    +static inline void cpumask_andnot(struct cpumask *dstp,
    + const struct cpumask *src1p,
    + const struct cpumask *src2p)
    +{
    + bitmap_andnot(cpumask_bits(dstp), cpumask_bits(src1p),
    + cpumask_bits(src2p), nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_complement - *dstp = ~*srcp
    + * @dstp: the cpumask result
    + * @srcp: the input to invert
    + */
    +static inline void cpumask_complement(struct cpumask *dstp,
    + const struct cpumask *srcp)
    +{
    + bitmap_complement(cpumask_bits(dstp), cpumask_bits(srcp),
    + nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_equal - *src1p == *src2p
    + * @src1p: the first input
    + * @src2p: the second input
    + */
    +static inline bool cpumask_equal(const struct cpumask *src1p,
    + const struct cpumask *src2p)
    +{
    + return bitmap_equal(cpumask_bits(src1p), cpumask_bits(src2p),
    + nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_intersects - (*src1p & *src2p) != 0
    + * @src1p: the first input
    + * @src2p: the second input
    + */
    +static inline bool cpumask_intersects(const struct cpumask *src1p,
    + const struct cpumask *src2p)
    +{
    + return bitmap_intersects(cpumask_bits(src1p), cpumask_bits(src2p),
    + nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_subset - (*src1p & ~*src2p) == 0
    + * @src1p: the first input
    + * @src2p: the second input
    + */
    +static inline int cpumask_subset(const struct cpumask *src1p,
    + const struct cpumask *src2p)
    +{
    + return bitmap_subset(cpumask_bits(src1p), cpumask_bits(src2p),
    + nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_empty - *srcp == 0
    + * @srcp: the cpumask to that all cpus < nr_cpu_ids are clear.
    + */
    +static inline bool cpumask_empty(const struct cpumask *srcp)
    +{
    + return bitmap_empty(cpumask_bits(srcp), nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_full - *srcp == 0xFFFFFFFF...
    + * @srcp: the cpumask to that all cpus < nr_cpu_ids are set.
    + */
    +static inline bool cpumask_full(const struct cpumask *srcp)
    +{
    + return bitmap_full(cpumask_bits(srcp), nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_weight - Count of bits in *srcp
    + * @srcp: the cpumask to count bits (< nr_cpu_ids) in.
    + */
    +static inline unsigned int cpumask_weight(const struct cpumask *srcp)
    +{
    + return bitmap_weight(cpumask_bits(srcp), nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_shift_right - *dstp = *srcp >> n
    + * @dstp: the cpumask result
    + * @srcp: the input to shift
    + * @n: the number of bits to shift by
    + */
    +static inline void cpumask_shift_right(struct cpumask *dstp,
    + const struct cpumask *srcp, int n)
    +{
    + bitmap_shift_right(cpumask_bits(dstp), cpumask_bits(srcp), n,
    + nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_shift_left - *dstp = *srcp << n
    + * @dstp: the cpumask result
    + * @srcp: the input to shift
    + * @n: the number of bits to shift by
    + */
    +static inline void cpumask_shift_left(struct cpumask *dstp,
    + const struct cpumask *srcp, int n)
    +{
    + bitmap_shift_left(cpumask_bits(dstp), cpumask_bits(srcp), n,
    + nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_copy - *dstp = *srcp
    + * @dstp: the result
    + * @srcp: the input cpumask
    + */
    +static inline void cpumask_copy(struct cpumask *dstp,
    + const struct cpumask *srcp)
    +{
    + bitmap_copy(cpumask_bits(dstp), cpumask_bits(srcp), nr_cpumask_bits);
    +}
    +
    +/**
    + * cpumask_any - pick a "random" cpu from *srcp
    + * @srcp: the input cpumask
    + *
    + * Returns >= nr_cpu_ids if no cpus set.
    + */
    +#define cpumask_any(srcp) cpumask_first(srcp)
    +
    +/**
    + * cpumask_first_and - return the first cpu from *srcp1 & *srcp2
    + * @src1p: the first input
    + * @src2p: the second input
    + *
    + * Returns >= nr_cpu_ids if no cpus set in both. See also cpumask_next_and().
    + */
    +#define cpumask_first_and(src1p, src2p) cpumask_next_and(-1, (src1p), (src2p))
    +
    +/**
    + * cpumask_any_and - pick a "random" cpu from *mask1 & *mask2
    + * @mask1: the first input cpumask
    + * @mask2: the second input cpumask
    + *
    + * Returns >= nr_cpu_ids if no cpus set.
    + */
    +#define cpumask_any_and(mask1, mask2) cpumask_first_and((mask1), (mask2))
    +
    +/**
    + * cpumask_of - the cpumask containing just a given cpu
    + * @cpu: the cpu (<= nr_cpu_ids)
    + */
    +#define cpumask_of(cpu) (get_cpu_mask(cpu))
    +
    +/**
    + * to_cpumask - convert an NR_CPUS bitmap to a struct cpumask *
    + * @bitmap: the bitmap
    + *
    + * There are a few places where cpumask_var_t isn't appropriate and
    + * static cpumasks must be used (eg. very early boot), yet we don't
    + * expose the definition of 'struct cpumask'.
    + *
    + * This does the conversion, and can be used as a constant initializer.
    + */
    +#define to_cpumask(bitmap) \
    + ((struct cpumask *)(1 ? (bitmap) \
    + : (void *)sizeof(__check_is_bitmap(bitmap))))
    +
    +static inline int __check_is_bitmap(const unsigned long *bitmap)
    +{
    + return 1;
    +}
    +
    +/**
    + * cpumask_size - size to allocate for a 'struct cpumask' in bytes
    + *
    + * This will eventually be a runtime variable, depending on nr_cpu_ids.
    + */
    +static inline size_t cpumask_size(void)
    +{
    + /* FIXME: Once all cpumask assignments are eliminated, this
    + * can be nr_cpumask_bits */
    + return BITS_TO_LONGS(NR_CPUS) * sizeof(long);
    +}
    +
    +/*
    + * cpumask_var_t: struct cpumask for stack usage.
    + *
    + * Oh, the wicked games we play! In order to make kernel coding a
    + * little more difficult, we typedef cpumask_var_t to an array or a
    + * pointer: doing &mask on an array is a noop, so it still works.
    + *
    + * ie.
    + * cpumask_var_t tmpmask;
    + * if (!alloc_cpumask_var(&tmpmask, GFP_KERNEL))
    + * return -ENOMEM;
    + *
    + * ... use 'tmpmask' like a normal struct cpumask * ...
    + *
    + * free_cpumask_var(tmpmask);
    + */
    +#ifdef CONFIG_CPUMASK_OFFSTACK
    +typedef struct cpumask *cpumask_var_t;
    +
    +bool alloc_cpumask_var(cpumask_var_t *mask, gfp_t flags);
    +void alloc_bootmem_cpumask_var(cpumask_var_t *mask);
    +void free_cpumask_var(cpumask_var_t mask);
    +void free_bootmem_cpumask_var(cpumask_var_t mask);
    +
    +#else
    +typedef struct cpumask cpumask_var_t[1];
    +
    +static inline bool alloc_cpumask_var(cpumask_var_t *mask, gfp_t flags)
    +{
    + return true;
    +}
    +
    +static inline void alloc_bootmem_cpumask_var(cpumask_var_t *mask)
    +{
    +}
    +
    +static inline void free_cpumask_var(cpumask_var_t mask)
    +{
    +}
    +
    +static inline void free_bootmem_cpumask_var(cpumask_var_t mask)
    +{
    +}
    +#endif /* CONFIG_CPUMASK_OFFSTACK */
    +
    +/* The pointer versions of the maps, these will become the primary versions. */
    +#define cpu_possible_mask ((const struct cpumask *)&cpu_possible_map)
    +#define cpu_online_mask ((const struct cpumask *)&cpu_online_map)
    +#define cpu_present_mask ((const struct cpumask *)&cpu_present_map)
    +#define cpu_active_mask ((const struct cpumask *)&cpu_active_map)
    +
    +/* It's common to want to use cpu_all_mask in struct member initializers,
    + * so it has to refer to an address rather than a pointer. */
    +extern const DECLARE_BITMAP(cpu_all_bits, NR_CPUS);
    +#define cpu_all_mask to_cpumask(cpu_all_bits)
    +
    +/* First bits of cpu_bit_bitmap are in fact unset. */
    +#define cpu_none_mask to_cpumask(cpu_bit_bitmap[0])
    +
    +/* Wrappers for arch boot code to manipulate normally-constant masks */
    +static inline void set_cpu_possible(unsigned int cpu, bool possible)
    +{
    + if (possible)
    + cpumask_set_cpu(cpu, &cpu_possible_map);
    + else
    + cpumask_clear_cpu(cpu, &cpu_possible_map);
    +}
    +
    +static inline void set_cpu_present(unsigned int cpu, bool present)
    +{
    + if (present)
    + cpumask_set_cpu(cpu, &cpu_present_map);
    + else
    + cpumask_clear_cpu(cpu, &cpu_present_map);
    +}
    +
    +static inline void set_cpu_online(unsigned int cpu, bool online)
    +{
    + if (online)
    + cpumask_set_cpu(cpu, &cpu_online_map);
    + else
    + cpumask_clear_cpu(cpu, &cpu_online_map);
    +}
    +
    +static inline void set_cpu_active(unsigned int cpu, bool active)
    +{
    + if (active)
    + cpumask_set_cpu(cpu, &cpu_active_map);
    + else
    + cpumask_clear_cpu(cpu, &cpu_active_map);
    +}
    +
    +static inline void init_cpu_present(const struct cpumask *src)
    +{
    + cpumask_copy(&cpu_present_map, src);
    +}
    +
    +static inline void init_cpu_possible(const struct cpumask *src)
    +{
    + cpumask_copy(&cpu_possible_map, src);
    +}
    +
    +static inline void init_cpu_online(const struct cpumask *src)
    +{
    + cpumask_copy(&cpu_online_map, src);
    +}
    #endif /* __LINUX_CPUMASK_H */
    diff --git a/include/linux/smp.h b/include/linux/smp.h
    index 2e4d58b..3f9a600 100644
    --- a/include/linux/smp.h
    +++ b/include/linux/smp.h
    @@ -64,8 +64,17 @@ extern void smp_cpus_done(unsigned int max_cpus);
    * Call a function on all other processors
    */
    int smp_call_function(void(*func)(void *info), void *info, int wait);
    +/* Deprecated: use smp_call_function_many() which uses a cpumask ptr. */
    int smp_call_function_mask(cpumask_t mask, void(*func)(void *info), void *info,
    int wait);
    +
    +static inline void smp_call_function_many(const struct cpumask *mask,
    + void (*func)(void *info), void *info,
    + int wait)
    +{
    + smp_call_function_mask(*mask, func, info, wait);
    +}
    +
    int smp_call_function_single(int cpuid, void (*func) (void *info), void *info,
    int wait);
    void __smp_call_function_single(int cpuid, struct call_single_data *data);
    diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
    index 89a5a12..b362911 100644
    --- a/include/linux/workqueue.h
    +++ b/include/linux/workqueue.h
    @@ -240,4 +240,12 @@ void cancel_rearming_delayed_work(struct delayed_work *work)
    cancel_delayed_work_sync(work);
    }

    +#ifndef CONFIG_SMP
    +static inline long work_on_cpu(unsigned int cpu, long (*fn)(void *), void *arg)
    +{
    + return fn(arg);
    +}
    +#else
    +long work_on_cpu(unsigned int cpu, long (*fn)(void *), void *arg);
    +#endif /* CONFIG_SMP */
    #endif
    diff --git a/kernel/cpu.c b/kernel/cpu.c
    index 86d4904..5a732c5 100644
    --- a/kernel/cpu.c
    +++ b/kernel/cpu.c
    @@ -499,3 +499,6 @@ const unsigned long cpu_bit_bitmap[BITS_PER_LONG+1][BITS_TO_LONGS(NR_CPUS)] = {
    #endif
    };
    EXPORT_SYMBOL_GPL(cpu_bit_bitmap);
    +
    +const DECLARE_BITMAP(cpu_all_bits, NR_CPUS) = CPU_BITS_ALL;
    +EXPORT_SYMBOL(cpu_all_bits);
    diff --git a/kernel/workqueue.c b/kernel/workqueue.c
    index f928f2a..d4dc69d 100644
    --- a/kernel/workqueue.c
    +++ b/kernel/workqueue.c
    @@ -970,6 +970,51 @@ undo:
    return ret;
    }

    +#ifdef CONFIG_SMP
    +struct work_for_cpu {
    + struct work_struct work;
    + long (*fn)(void *);
    + void *arg;
    + long ret;
    +};
    +
    +static void do_work_for_cpu(struct work_struct *w)
    +{
    + struct work_for_cpu *wfc = container_of(w, struct work_for_cpu, work);
    +
    + wfc->ret = wfc->fn(wfc->arg);
    +}
    +
    +/**
    + * work_on_cpu - run a function in user context on a particular cpu
    + * @cpu: the cpu to run on
    + * @fn: the function to run
    + * @arg: the function arg
    + *
    + * This will return -EINVAL in the cpu is not online, or the return value
    + * of @fn otherwise.
    + */
    +long work_on_cpu(unsigned int cpu, long (*fn)(void *), void *arg)
    +{
    + struct work_for_cpu wfc;
    +
    + INIT_WORK(&wfc.work, do_work_for_cpu);
    + wfc.fn = fn;
    + wfc.arg = arg;
    + get_online_cpus();
    + if (unlikely(!cpu_online(cpu)))
    + wfc.ret = -EINVAL;
    + else {
    + schedule_work_on(cpu, &wfc.work);
    + flush_work(&wfc.work);
    + }
    + put_online_cpus();
    +
    + return wfc.ret;
    +}
    +EXPORT_SYMBOL_GPL(work_on_cpu);
    +#endif /* CONFIG_SMP */
    +
    void __init init_workqueues(void)
    {
    cpu_populated_map = cpu_online_map;
    diff --git a/lib/cpumask.c b/lib/cpumask.c
    index 5f97dc2..8d03f22 100644
    --- a/lib/cpumask.c
    +++ b/lib/cpumask.c
    @@ -2,6 +2,7 @@
    #include
    #include
    #include
    +#include

    int __first_cpu(const cpumask_t *srcp)
    {
    @@ -35,3 +36,81 @@ int __any_online_cpu(const cpumask_t *mask)
    return cpu;
    }
    EXPORT_SYMBOL(__any_online_cpu);
    +
    +/**
    + * cpumask_next_and - get the next cpu in *src1p & *src2p
    + * @n: the cpu prior to the place to search (ie. return will be > @n)
    + * @src1p: the first cpumask pointer
    + * @src2p: the second cpumask pointer
    + *
    + * Returns >= nr_cpu_ids if no further cpus set in both.
    + */
    +int cpumask_next_and(int n, const struct cpumask *src1p,
    + const struct cpumask *src2p)
    +{
    + while ((n = cpumask_next(n, src1p)) < nr_cpu_ids)
    + if (cpumask_test_cpu(n, src2p))
    + break;
    + return n;
    +}
    +EXPORT_SYMBOL(cpumask_next_and);
    +
    +/**
    + * cpumask_any_but - return a "random" in a cpumask, but not this one.
    + * @mask: the cpumask to search
    + * @cpu: the cpu to ignore.
    + *
    + * Often used to find any cpu but smp_processor_id() in a mask.
    + * Returns >= nr_cpu_ids if no cpus set.
    + */
    +int cpumask_any_but(const struct cpumask *mask, unsigned int cpu)
    +{
    + unsigned int i;
    +
    + cpumask_check(cpu);
    + for_each_cpu(i, mask)
    + if (i != cpu)
    + break;
    + return i;
    +}
    +
    +/* These are not inline because of header tangles. */
    +#ifdef CONFIG_CPUMASK_OFFSTACK
    +bool alloc_cpumask_var(cpumask_var_t *mask, gfp_t flags)
    +{
    + if (likely(slab_is_available()))
    + *mask = kmalloc(cpumask_size(), flags);
    + else {
    +#ifdef CONFIG_DEBUG_PER_CPU_MAPS
    + printk(KERN_ERR
    + "=> alloc_cpumask_var: kmalloc not available!\n");
    + dump_stack();
    +#endif
    + *mask = NULL;
    + }
    +#ifdef CONFIG_DEBUG_PER_CPU_MAPS
    + if (!*mask) {
    + printk(KERN_ERR "=> alloc_cpumask_var: failed!\n");
    + dump_stack();
    + }
    +#endif
    + return *mask != NULL;
    +}
    +EXPORT_SYMBOL(alloc_cpumask_var);
    +
    +void __init alloc_bootmem_cpumask_var(cpumask_var_t *mask)
    +{
    + *mask = alloc_bootmem(cpumask_size());
    +}
    +
    +void free_cpumask_var(cpumask_var_t mask)
    +{
    + kfree(mask);
    +}
    +EXPORT_SYMBOL(free_cpumask_var);
    +
    +void __init free_bootmem_cpumask_var(cpumask_var_t mask)
    +{
    + free_bootmem((unsigned long)mask, cpumask_size());
    +}
    +#endif
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  14. Re: [PATCH] cpumask: introduce new API, without changing anything


    * Ingo Molnar wrote:

    > > On Sat, 8 Nov 2008, Rusty Russell wrote:
    > > >
    > > > Ok, I sent through the latest delta on top of this before, but see below.

    > >
    > > Can somebody send a final patch-set to me? Right now I have multiple
    > > versions of patches, apparently on top of each other, and sometimes
    > > multiple patches per email. Very confusing, and I do _not_ want to
    > > apply the wrong thing by mistake.

    >
    > I've got them collected and tested (and so has Rusty), see the tree
    > URI below. There's no pending problem left that i know of. I also
    > just did a fresh test-build and test-boot of this tree, for good
    > measure.


    Thomas did a cross-build test of Linus's latest
    (v2.6.28-rc3-261-g8b805ef), and it seems OK (see the results below) -
    no new cross-build failures introduced.

    Ingo

    --------------->
    Run 142: 2008-11-09 21:38:04 .. 2008-11-09 22:30:35

    Run 142: 17 of 19 operations OK
    Run 142: 2 of 19 operations FAILED

    http://www.tglx.de/autoqa-logs/000142-0008-0005.log
    http://www.tglx.de/autoqa-logs/000142-0008-0015.log

    Changed warnings:
    http://www.tglx.de/autoqa-logs/d0001...-0008-0006.log
    http://www.tglx.de/autoqa-logs/d0001...-0008-0023.log
    http://www.tglx.de/autoqa-logs/d0001...-0008-0024.log

    Full results at: http://www.tglx.de/autoqa/index
    _______________________________________________
    autoqa mailing list
    autoqa@www.tglx.de
    http://www.tglx.de/mailman/listinfo/autoqa
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  15. Re: [PATCH] cpumask: introduce new API, without changing anything

    On Monday 10 November 2008 07:01:50 Linus Torvalds wrote:
    > On Sat, 8 Nov 2008, Rusty Russell wrote:
    > > Ok, I sent through the latest delta on top of this before, but see below.

    >
    > Can somebody send a final patch-set to me? Right now I have multiple
    > versions of patches, apparently on top of each other, and sometimes
    > multiple patches per email. Very confusing, and I do _not_ want to apply
    > the wrong thing by mistake.


    Sure, am waiting for a final run through linux-next. There's no huge hurry
    and it helps find obscure arch compile/include issues.

    Cheers,
    Rusty.
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  16. Re: [PATCH] cpumask: introduce new API, without changing anything

    Ingo Molnar wrote:
    ....
    > Mike, could you please double-check that the version that is in
    > tip/cpus4096 [622e0ed] is the final version you need, and that if you
    > base subsequent patches on it it works as expected?

    ....
    I'm checking this out, so far it looks good.

    > and once that patch hits upstream, we could restructure/rebase the
    > commits in cpus4096-v2 ontop of upstream and spread them out properly.
    > Does that sound optimal?


    Yes, thanks. I'm doing the x86 portion now. Rusty is doing the other
    arch and core changes.


    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

+ Reply to Thread