Skip to content

Commit 1fae562

Browse files
Tian Taogregkh
authored andcommitted
cpumask: introduce cpumap_print_list/bitmask_to_buf to support large bitmask and list
The existing cpumap_print_to_pagebuf() is used by cpu topology and other drivers to export hexadecimal bitmask and decimal list to userspace by sysfs ABI. Right now, those drivers are using a normal attribute for this kind of ABIs. A normal attribute typically has show entry as below: static ssize_t example_dev_show(struct device *dev, struct device_attribute *attr, char *buf) { ... return cpumap_print_to_pagebuf(true, buf, &pmu_mmdc->cpu); } show entry of attribute has no offset and count parameters and this means the file is limited to one page only. cpumap_print_to_pagebuf() API works terribly well for this kind of normal attribute with buf parameter and without offset, count: static inline ssize_t cpumap_print_to_pagebuf(bool list, char *buf, const struct cpumask *mask) { return bitmap_print_to_pagebuf(list, buf, cpumask_bits(mask), nr_cpu_ids); } The problem is once we have many cpus, we have a chance to make bitmask or list more than one page. Especially for list, it could be as complex as 0,3,5,7,9,...... We have no simple way to know it exact size. It turns out bin_attribute is a way to break this limit. bin_attribute has show entry as below: static ssize_t example_bin_attribute_show(struct file *filp, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t offset, size_t count) { ... } With the new offset and count parameters, this makes sysfs ABI be able to support file size more than one page. For example, offset could be >= 4096. This patch introduces cpumap_print_bitmask/list_to_buf() and their bitmap infrastructure bitmap_print_bitmask/list_to_buf() so that those drivers can move to bin_attribute to support large bitmask and list. At the same time, we have to pass those corresponding parameters such as offset, count from bin_attribute to this new API. Cc: Andrew Morton <[email protected]> Cc: Andy Shevchenko <[email protected]> Cc: Randy Dunlap <[email protected]> Cc: Stefano Brivio <[email protected]> Cc: Alexander Gordeev <[email protected]> Cc: "Ma, Jianpeng" <[email protected]> Cc: Yury Norov <[email protected]> Cc: Valentin Schneider <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Daniel Bristot de Oliveira <[email protected]> Reviewed-by: Jonathan Cameron <[email protected]> Signed-off-by: Tian Tao <[email protected]> Signed-off-by: Barry Song <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent bd935a7 commit 1fae562

File tree

3 files changed

+147
-0
lines changed

3 files changed

+147
-0
lines changed

include/linux/bitmap.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,12 @@ unsigned int bitmap_ord_to_pos(const unsigned long *bitmap, unsigned int ord, un
227227
int bitmap_print_to_pagebuf(bool list, char *buf,
228228
const unsigned long *maskp, int nmaskbits);
229229

230+
extern int bitmap_print_bitmask_to_buf(char *buf, const unsigned long *maskp,
231+
int nmaskbits, loff_t off, size_t count);
232+
233+
extern int bitmap_print_list_to_buf(char *buf, const unsigned long *maskp,
234+
int nmaskbits, loff_t off, size_t count);
235+
230236
#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) & (BITS_PER_LONG - 1)))
231237
#define BITMAP_LAST_WORD_MASK(nbits) (~0UL >> (-(nbits) & (BITS_PER_LONG - 1)))
232238

include/linux/cpumask.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -983,6 +983,44 @@ cpumap_print_to_pagebuf(bool list, char *buf, const struct cpumask *mask)
983983
nr_cpu_ids);
984984
}
985985

986+
/**
987+
* cpumap_print_bitmask_to_buf - copies the cpumask into the buffer as
988+
* hex values of cpumask
989+
*
990+
* @buf: the buffer to copy into
991+
* @mask: the cpumask to copy
992+
* @off: in the string from which we are copying, we copy to @buf
993+
* @count: the maximum number of bytes to print
994+
*
995+
* The function prints the cpumask into the buffer as hex values of
996+
* cpumask; Typically used by bin_attribute to export cpumask bitmask
997+
* ABI.
998+
*
999+
* Returns the length of how many bytes have been copied.
1000+
*/
1001+
static inline ssize_t
1002+
cpumap_print_bitmask_to_buf(char *buf, const struct cpumask *mask,
1003+
loff_t off, size_t count)
1004+
{
1005+
return bitmap_print_bitmask_to_buf(buf, cpumask_bits(mask),
1006+
nr_cpu_ids, off, count);
1007+
}
1008+
1009+
/**
1010+
* cpumap_print_list_to_buf - copies the cpumask into the buffer as
1011+
* comma-separated list of cpus
1012+
*
1013+
* Everything is same with the above cpumap_print_bitmask_to_buf()
1014+
* except the print format.
1015+
*/
1016+
static inline ssize_t
1017+
cpumap_print_list_to_buf(char *buf, const struct cpumask *mask,
1018+
loff_t off, size_t count)
1019+
{
1020+
return bitmap_print_list_to_buf(buf, cpumask_bits(mask),
1021+
nr_cpu_ids, off, count);
1022+
}
1023+
9861024
#if NR_CPUS <= BITS_PER_LONG
9871025
#define CPU_MASK_ALL \
9881026
(cpumask_t) { { \

lib/bitmap.c

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,109 @@ int bitmap_print_to_pagebuf(bool list, char *buf, const unsigned long *maskp,
487487
}
488488
EXPORT_SYMBOL(bitmap_print_to_pagebuf);
489489

490+
/**
491+
* bitmap_print_to_buf - convert bitmap to list or hex format ASCII string
492+
* @list: indicates whether the bitmap must be list
493+
* true: print in decimal list format
494+
* false: print in hexadecimal bitmask format
495+
*/
496+
static int bitmap_print_to_buf(bool list, char *buf, const unsigned long *maskp,
497+
int nmaskbits, loff_t off, size_t count)
498+
{
499+
const char *fmt = list ? "%*pbl\n" : "%*pb\n";
500+
ssize_t size;
501+
void *data;
502+
503+
data = kasprintf(GFP_KERNEL, fmt, nmaskbits, maskp);
504+
if (!data)
505+
return -ENOMEM;
506+
507+
size = memory_read_from_buffer(buf, count, &off, data, strlen(data) + 1);
508+
kfree(data);
509+
510+
return size;
511+
}
512+
513+
/**
514+
* bitmap_print_bitmask_to_buf - convert bitmap to hex bitmask format ASCII string
515+
*
516+
* The bitmap_print_to_pagebuf() is used indirectly via its cpumap wrapper
517+
* cpumap_print_to_pagebuf() or directly by drivers to export hexadecimal
518+
* bitmask and decimal list to userspace by sysfs ABI.
519+
* Drivers might be using a normal attribute for this kind of ABIs. A
520+
* normal attribute typically has show entry as below:
521+
* static ssize_t example_attribute_show(struct device *dev,
522+
* struct device_attribute *attr, char *buf)
523+
* {
524+
* ...
525+
* return bitmap_print_to_pagebuf(true, buf, &mask, nr_trig_max);
526+
* }
527+
* show entry of attribute has no offset and count parameters and this
528+
* means the file is limited to one page only.
529+
* bitmap_print_to_pagebuf() API works terribly well for this kind of
530+
* normal attribute with buf parameter and without offset, count:
531+
* bitmap_print_to_pagebuf(bool list, char *buf, const unsigned long *maskp,
532+
* int nmaskbits)
533+
* {
534+
* }
535+
* The problem is once we have a large bitmap, we have a chance to get a
536+
* bitmask or list more than one page. Especially for list, it could be
537+
* as complex as 0,3,5,7,9,... We have no simple way to know it exact size.
538+
* It turns out bin_attribute is a way to break this limit. bin_attribute
539+
* has show entry as below:
540+
* static ssize_t
541+
* example_bin_attribute_show(struct file *filp, struct kobject *kobj,
542+
* struct bin_attribute *attr, char *buf,
543+
* loff_t offset, size_t count)
544+
* {
545+
* ...
546+
* }
547+
* With the new offset and count parameters, this makes sysfs ABI be able
548+
* to support file size more than one page. For example, offset could be
549+
* >= 4096.
550+
* bitmap_print_bitmask_to_buf(), bitmap_print_list_to_buf() wit their
551+
* cpumap wrapper cpumap_print_bitmask_to_buf(), cpumap_print_list_to_buf()
552+
* make those drivers be able to support large bitmask and list after they
553+
* move to use bin_attribute. In result, we have to pass the corresponding
554+
* parameters such as off, count from bin_attribute show entry to this API.
555+
*
556+
* @buf: buffer into which string is placed
557+
* @maskp: pointer to bitmap to convert
558+
* @nmaskbits: size of bitmap, in bits
559+
* @off: in the string from which we are copying, We copy to @buf
560+
* @count: the maximum number of bytes to print
561+
*
562+
* The role of cpumap_print_bitmask_to_buf() and cpumap_print_list_to_buf()
563+
* is similar with cpumap_print_to_pagebuf(), the difference is that
564+
* bitmap_print_to_pagebuf() mainly serves sysfs attribute with the assumption
565+
* the destination buffer is exactly one page and won't be more than one page.
566+
* cpumap_print_bitmask_to_buf() and cpumap_print_list_to_buf(), on the other
567+
* hand, mainly serves bin_attribute which doesn't work with exact one page,
568+
* and it can break the size limit of converted decimal list and hexadecimal
569+
* bitmask.
570+
*
571+
* Returns the number of characters actually printed to @buf
572+
*/
573+
int bitmap_print_bitmask_to_buf(char *buf, const unsigned long *maskp,
574+
int nmaskbits, loff_t off, size_t count)
575+
{
576+
return bitmap_print_to_buf(false, buf, maskp, nmaskbits, off, count);
577+
}
578+
EXPORT_SYMBOL(bitmap_print_bitmask_to_buf);
579+
580+
/**
581+
* bitmap_print_list_to_buf - convert bitmap to decimal list format ASCII string
582+
*
583+
* Everything is same with the above bitmap_print_bitmask_to_buf() except
584+
* the print format.
585+
*/
586+
int bitmap_print_list_to_buf(char *buf, const unsigned long *maskp,
587+
int nmaskbits, loff_t off, size_t count)
588+
{
589+
return bitmap_print_to_buf(true, buf, maskp, nmaskbits, off, count);
590+
}
591+
EXPORT_SYMBOL(bitmap_print_list_to_buf);
592+
490593
/*
491594
* Region 9-38:4/10 describes the following bitmap structure:
492595
* 0 9 12 18 38 N

0 commit comments

Comments
 (0)