Commit 513e3d2d11c9 ("cpumask: always use nr_cpu_ids in formatting and parsing functions") converted both cpumask printing and parsing functions to use nr_cpu_ids instead of nr_cpumask_bits. While this was okay for the printing functions as it just picked one of the two output formats that we were alternating between depending on a kernel config, doing the same for parsing wasn't okay. nr_cpumask_bits can be either nr_cpu_ids or NR_CPUS. We can always use nr_cpu_ids but that is a variable while NR_CPUS is a constant, so it can be more efficient to use NR_CPUS when we can get away with it. Converting the printing functions to nr_cpu_ids makes sense because it affects how the masks get presented to userspace and doesn't break anything; however, using nr_cpu_ids for parsing functions can incorrectly leave the higher bits uninitialized while reading in these masks from userland. As all testing and comparison functions use nr_cpumask_bits which can be larger than nr_cpu_ids, the parsed cpumasks can erroneously yield false negative results. This made the taskstats interface incorrectly return -EINVAL even when the inputs were correct. Fix it by restoring the parse functions to use nr_cpumask_bits instead of nr_cpu_ids.
Showing the changes to include/linux (1 of 1 file). Show all
Unified · Split
| @@ -560,7 +560,7 @@ static inline void cpumask_copy(struct cpumask *dstp, · 559 unmodified lines | |||
| 560 | static inline int cpumask_parse_user(const char __user *buf, int len, | 560 | static inline int cpumask_parse_user(const char __user *buf, int len, |
| 561 | struct cpumask *dstp) | 561 | struct cpumask *dstp) |
| 562 | { | 562 | { |
| 563 | return bitmap_parse_user(buf, len, cpumask_bits(dstp), nr_cpu_ids); | 563 | return bitmap_parse_user(buf, len, cpumask_bits(dstp), nr_cpumask_bits); |
| 564 | } | 564 | } |
| 565 | 565 | ||
| 566 | /** | 566 | /** |
| @@ -575,7 +575,7 @@ static inline int cpumask_parselist_user(const char __user *buf, int len, · 8 unmodified lines | |||
| 575 | struct cpumask *dstp) | 575 | struct cpumask *dstp) |
| 576 | { | 576 | { |
| 577 | return bitmap_parselist_user(buf, len, cpumask_bits(dstp), | 577 | return bitmap_parselist_user(buf, len, cpumask_bits(dstp), |
| 578 | nr_cpu_ids); | 578 | nr_cpumask_bits); |
| 579 | } | 579 | } |
| 580 | 580 | ||
| 581 | /** | 581 | /** |
| @@ -590,7 +590,7 @@ static inline int cpumask_parse(const char *buf, struct cpumask *dstp) · 8 unmodified lines | |||
| 590 | char *nl = strchr(buf, '\n'); | 590 | char *nl = strchr(buf, '\n'); |
| 591 | unsigned int len = nl ? (unsigned int)(nl - buf) : strlen(buf); | 591 | unsigned int len = nl ? (unsigned int)(nl - buf) : strlen(buf); |
| 592 | 592 | ||
| 593 | return bitmap_parse(buf, len, cpumask_bits(dstp), nr_cpu_ids); | 593 | return bitmap_parse(buf, len, cpumask_bits(dstp), nr_cpumask_bits); |
| 594 | } | 594 | } |
| 595 | 595 | ||
| 596 | /** | 596 | /** |
| @@ -602,7 +602,7 @@ static inline int cpumask_parse(const char *buf, struct cpumask *dstp) · 5 unmodified lines | |||
| 602 | */ | 602 | */ |
| 603 | static inline int cpulist_parse(const char *buf, struct cpumask *dstp) | 603 | static inline int cpulist_parse(const char *buf, struct cpumask *dstp) |
| 604 | { | 604 | { |
| 605 | return bitmap_parselist(buf, cpumask_bits(dstp), nr_cpu_ids); | 605 | return bitmap_parselist(buf, cpumask_bits(dstp), nr_cpumask_bits); |
| 606 | } | 606 | } |
| 607 | 607 | ||
| 608 | /** | 608 | /** |