-----Original Message----- From: tiantao (H) Sent: Thursday, May 27, 2021 2:57 PM To: Song Bao Hua (Barry Song) song.bao.hua@hisilicon.com; Jonathan Cameron jonathan.cameron@huawei.com Cc: linuxarm@openeuler.org; tiantao (H) tiantao6@hisilicon.com Subject: [PATCH v7] topology: use bin_attribute to avoid buff overflow
Reading sys/devices/system/cpu/cpuX/topology/ returns cpu topology. However, the size of this file is limited to PAGE_SIZE because of the limitation for sysfs attribute. so we use bin_attribute instead of attribute to avoid NR_CPUS too big to cause buff overflow.
This patch is based on the following discussion. https://www.spinics.net/lists/linux-doc/msg95921.html
Signed-off-by: Tian Tao tiantao6@hisilicon.com
v2: rewrite the function name##_read v3: remove the temp buffer. v4: rewrite the function name##_read v5: rewrite the patch v6: update the commit message v7: remove BUFF_SIZE, dynamic calculation of size
drivers/base/topology.c | 144
Thanks very much. We are almost there.
+++++++++++++++++++++++++++++++----------------- 1 file changed, 94 insertions(+), 50 deletions(-)
diff --git a/drivers/base/topology.c b/drivers/base/topology.c index 4d254fc..883fa39 100644 --- a/drivers/base/topology.c +++ b/drivers/base/topology.c @@ -21,24 +21,59 @@ static ssize_t name##_show(struct device *dev, \ return sysfs_emit(buf, "%d\n", topology_##name(dev->id)); \ }
-#define define_siblings_show_map(name, mask) \ -static ssize_t name##_show(struct device *dev, \
struct device_attribute *attr, char *buf) \
-{ \
- return cpumap_print_to_pagebuf(false, buf, topology_##mask(dev->id));\
-} +static int topology_snprintf(char *buf, ssize_t size, const char *fmt, ...) +{
- va_list args;
- int i;
As discussed, better to make a common wrapper so that other modules calling cpumap_print_to_pagebuf, such as drivers/base/node.c, can reuse the wrapper.
-#define define_siblings_show_list(name, mask) \ -static ssize_t name##_list_show(struct device *dev, \
struct device_attribute *attr, \
char *buf) \
-{ \
- return cpumap_print_to_pagebuf(true, buf, topology_##mask(dev->id));\
- va_start(args, fmt);
- if (size <= 0)
i = vsnprintf(NULL, 0, fmt, args);
- else
i = vscnprintf(buf, size, fmt, args);
- va_end(args);
- return i;
}
-#define define_siblings_show_func(name, mask) \
- define_siblings_show_map(name, mask); \
- define_siblings_show_list(name, mask)
+#define define_siblings_read_func(name, mask) \ +static ssize_t name##_read(struct file *file, struct kobject *kobj, \
struct bin_attribute *attr, char *buf, \
loff_t off, size_t count) \
+{ \
- struct device *dev = kobj_to_dev(kobj); \
- int len; \
- void *data; \
- len = topology_snprintf(NULL, 0, "%*pb\n", nr_cpu_ids, \
cpumask_bits(topology_##mask(dev->id))); \
- data = kvmalloc(len+1, GFP_KERNEL); \
- if (!data) \
return -ENOMEM; \
- len = topology_snprintf(data, len+1, "%*pb\n", nr_cpu_ids, \
cpumask_bits(topology_##mask(dev->id))); \
- len = memory_read_from_buffer(buf, count, &off, data, len); \
- kvfree(data); \
- return len; \
+} \
\
+static ssize_t name##_list_read(struct file *file, struct kobject *kobj, \
struct bin_attribute *attr, char *buf, \
loff_t off, size_t count) \
+{ \
- struct device *dev = kobj_to_dev(kobj); \
- int len; \
- void *data; \
- len = topology_snprintf(NULL, 0, "%*pbl\n", nr_cpu_ids, \
cpumask_bits(topology_##mask(dev->id))); \
- data = kvmalloc(len+1, GFP_KERNEL); \
- if (!data) \
return -ENOMEM; \
- len = topology_snprintf(data, len+1, "%*pbl\n", nr_cpu_ids, \
cpumask_bits(topology_##mask(dev->id))); \
- len = memory_read_from_buffer(buf, count, &off, data, len); \
- kvfree(data); \
- return len; \
+}
As discussed, here we have some bad smells in code. The only difference between name##_list_read and name##_read is pb and pbl.
Thanks Barry