Received: by 2002:a05:6a10:1287:0:0:0:0 with SMTP id d7csp339382pxv; Thu, 15 Jul 2021 05:37:53 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzUG5s4JkoPcEYMzVe/rztZ9exRcZyLz7xz/1nnm/OdWeaddnAtTx3TgNgNqbVkv0QPtubp X-Received: by 2002:a50:ff09:: with SMTP id a9mr6719564edu.368.1626352672850; Thu, 15 Jul 2021 05:37:52 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1626352672; cv=none; d=google.com; s=arc-20160816; b=sFfQevQezJi5LBC1J3mveZW640SvYhs6GBBxH4w2ZXxkKxK1+BQQzZJEXPmuxkMGpT rSUwjjlg1T4sVBAkL8Tn9o9tJa6sjHmvs0+CNk2DkNoWhV0AxK61iO1/BjHYOkJ3Ysvp aApHJmFNOkGzh6oWFoSG+mLMZlagbkjl3/67h/YP/TutBz4Qf/JXFqEJQen8F5GX9zCY sOA3AX1UAZG9t6sC26mw3ufwvuNXsnRJUTyz3xcWDr02d2X0SoR2a+Qr3p85+TZu/FuH PxrkZ/fYAdJg/VYV5OEmw3WTPNQmvX6Sko7y5ikOYEjioCFNk3ZY9MtAyW5nOSKKYWFl jc0A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=64rlO/c5xumiDSju3sDAIv4b3d2zrKY01CGx/Xoqoug=; b=QSPS57qZoBcSdLSg/DayXvXVKyxVbmAcFGwyfxEaav07VBHgNUJWWh2f0lEWIUhPfm 6zJTbqgy5e2TDBjTGVx0b6sj3PWWAIuJ+rnem5kNMbKOvrtqtUa+ARZswliokN8DBhVv 4o2Ade4XA8KbPYGzU4UFt9Cw/SoeETngUGpdAaQWPhfTe1RI9JkqBY6ndPmjhl6ZsiMd 9nNNsxZekR5UsvxOm1wCRn47WbmtxvTNW5MR34sgvPttuFrQ9psYzrcb2mQxaoll+XhF FYANPOa8jjpQ19NkzgaXzFMjuF+8vpPNN1b9B/LAaHp9nDSBe9Ewz4akWFzTpx/+uR1g tcmg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=hisilicon.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id l7si8470986edk.216.2021.07.15.05.37.29; Thu, 15 Jul 2021 05:37:52 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=hisilicon.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231477AbhGOMCe (ORCPT + 99 others); Thu, 15 Jul 2021 08:02:34 -0400 Received: from szxga02-in.huawei.com ([45.249.212.188]:6934 "EHLO szxga02-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231462AbhGOMCd (ORCPT ); Thu, 15 Jul 2021 08:02:33 -0400 Received: from dggemv704-chm.china.huawei.com (unknown [172.30.72.54]) by szxga02-in.huawei.com (SkyGuard) with ESMTP id 4GQXrg6bXGz7v49; Thu, 15 Jul 2021 19:56:03 +0800 (CST) Received: from dggemi761-chm.china.huawei.com (10.1.198.147) by dggemv704-chm.china.huawei.com (10.3.19.47) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) id 15.1.2176.2; Thu, 15 Jul 2021 19:59:38 +0800 Received: from SWX921481.china.huawei.com (10.126.202.216) by dggemi761-chm.china.huawei.com (10.1.198.147) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2176.2; Thu, 15 Jul 2021 19:59:33 +0800 From: Barry Song To: , , , , CC: , , , , , , , , , , , , , , , , Tian Tao , Barry Song Subject: [PATCH v7 1/4] cpumask: introduce cpumap_print_to_buf to support large bitmask and list Date: Thu, 15 Jul 2021 23:58:53 +1200 Message-ID: <20210715115856.11304-2-song.bao.hua@hisilicon.com> X-Mailer: git-send-email 2.21.0.windows.1 In-Reply-To: <20210715115856.11304-1-song.bao.hua@hisilicon.com> References: <20210715115856.11304-1-song.bao.hua@hisilicon.com> MIME-Version: 1.0 Content-Transfer-Encoding: 7BIT Content-Type: text/plain; charset=US-ASCII X-Originating-IP: [10.126.202.216] X-ClientProxiedBy: dggems705-chm.china.huawei.com (10.3.19.182) To dggemi761-chm.china.huawei.com (10.1.198.147) X-CFilter-Loop: Reflected Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Tian Tao 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_to_buf() and its bitmap infrastructure bitmap_print_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. Signed-off-by: Tian Tao Cc: Andrew Morton Cc: Andy Shevchenko Cc: Randy Dunlap Cc: Stefano Brivio Cc: Alexander Gordeev Cc: "Ma, Jianpeng" Cc: Yury Norov Cc: Valentin Schneider Cc: Peter Zijlstra Cc: Daniel Bristot de Oliveira Signed-off-by: Barry Song --- v7: explanation deserves to be a paragraph in code according to Andy's comments; include/linux/bitmap.h | 2 ++ include/linux/cpumask.h | 63 +++++++++++++++++++++++++++++++++ lib/bitmap.c | 78 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 143 insertions(+) diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h index a36cfcec4e77..0de6effa2797 100644 --- a/include/linux/bitmap.h +++ b/include/linux/bitmap.h @@ -226,6 +226,8 @@ void bitmap_copy_le(unsigned long *dst, const unsigned long *src, unsigned int n unsigned int bitmap_ord_to_pos(const unsigned long *bitmap, unsigned int ord, unsigned int nbits); int bitmap_print_to_pagebuf(bool list, char *buf, const unsigned long *maskp, int nmaskbits); +int bitmap_print_to_buf(bool list, char *buf, const unsigned long *maskp, + int nmaskbits, loff_t off, size_t count); #define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) & (BITS_PER_LONG - 1))) #define BITMAP_LAST_WORD_MASK(nbits) (~0UL >> (-(nbits) & (BITS_PER_LONG - 1))) diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h index f3689a52bfd0..f81ade866cf7 100644 --- a/include/linux/cpumask.h +++ b/include/linux/cpumask.h @@ -983,6 +983,69 @@ cpumap_print_to_pagebuf(bool list, char *buf, const struct cpumask *mask) nr_cpu_ids); } +/** + * cpumap_print_to_buf - copies the cpumask into the buffer + * @list: indicates whether the cpumap must be list + * true: print in decimal list format + * false: print in hexadecimal bitmask format + * + * 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. + * Drivers might be using a normal attribute for this kind of ABIs. A + * normal attribute typically has show entry as below: + * static ssize_t example_attribute_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. 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: + * cpumap_print_to_pagebuf(bool list, char *buf, const struct cpumask *mask) + * { + * } + * 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. + * cpumap_print_to_buf() makes those drivers be able to to support large + * bitmask and list after they move to use bin_attribute. In result, we + * have to pass the corresponding parameters such as off, count from + * bin_attribute show entry to this API. + * + * @mask: the cpumask to copy + * @buf: the buffer to copy into + * @off: in the string from which we are copying, We copy to @buf + * @count: the maximum number of bytes to print + * + * The function copies the cpumask into the buffer either as comma-separated + * list of cpus or hex values of cpumask; Typically used by bin_attribute to + * export cpumask bitmask and list ABI. + * + * Returns the length of how many bytes have been copied. + */ +static inline ssize_t +cpumap_print_to_buf(bool list, char *buf, const struct cpumask *mask, + loff_t off, size_t count) +{ + return bitmap_print_to_buf(list, buf, cpumask_bits(mask), + nr_cpu_ids, off, count); +} + #if NR_CPUS <= BITS_PER_LONG #define CPU_MASK_ALL \ (cpumask_t) { { \ diff --git a/lib/bitmap.c b/lib/bitmap.c index 9401d39e4722..56bcffe2fa8c 100644 --- a/lib/bitmap.c +++ b/lib/bitmap.c @@ -487,6 +487,84 @@ int bitmap_print_to_pagebuf(bool list, char *buf, const unsigned long *maskp, } EXPORT_SYMBOL(bitmap_print_to_pagebuf); +/** + * bitmap_print_to_buf - convert bitmap to list or hex format ASCII string + * @list: indicates whether the bitmap must be list + * true: print in decimal list format + * false: print in hexadecimal bitmask format + * + * The bitmap_print_to_pagebuf() is used indirectly via its cpumap wrapper + * cpumap_print_to_pagebuf() or directly by drivers to export hexadecimal + * bitmask and decimal list to userspace by sysfs ABI. + * Drivers might be using a normal attribute for this kind of ABIs. A + * normal attribute typically has show entry as below: + * static ssize_t example_attribute_show(struct device *dev, + * struct device_attribute *attr, char *buf) + * { + * ... + * return bitmap_print_to_pagebuf(true, buf, &mask, nr_trig_max); + * } + * show entry of attribute has no offset and count parameters and this + * means the file is limited to one page only. + * bitmap_print_to_pagebuf() API works terribly well for this kind of + * normal attribute with buf parameter and without offset, count: + * bitmap_print_to_pagebuf(bool list, char *buf, const unsigned long *maskp, + * int nmaskbits) + * { + * } + * The problem is once we have a large bitmap, we have a chance to get a + * 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. + * bitmap_print_to_buf() and its cpumap wrapper cpumap_print_to_buf() makes + * those drivers be able to support large bitmask and list after they move + * to use bin_attribute. In result, we have to pass the corresponding + * parameters such as off, count from bin_attribute show entry to this API. + * + * @buf: buffer into which string is placed + * @maskp: pointer to bitmap to convert + * @nmaskbits: size of bitmap, in bits + * @off: in the string from which we are copying, We copy to @buf + * @count: the maximum number of bytes to print + * + * The role of cpumap_print_to_buf() and cpumap_print_to_pagebuf() is similar, + * the difference is that bitmap_print_to_pagebuf() mainly serves sysfs + * attribute with the assumption the destination buffer is exactly one page + * and won't be more than one page. cpumap_print_to_buf(), on the other hand, + * mainly serves bin_attribute which doesn't work with exact one page, and it + * can break the size limit of converted decimal list and hexadecimal bitmask. + * + * Returns the number of characters actually printed to @buf + */ +int bitmap_print_to_buf(bool list, char *buf, const unsigned long *maskp, + int nmaskbits, loff_t off, size_t count) +{ + const char *fmt = list ? "%*pbl\n" : "%*pb\n"; + ssize_t size; + void *data; + + data = kasprintf(GFP_KERNEL, fmt, nmaskbits, maskp); + if (!data) + return -ENOMEM; + + size = memory_read_from_buffer(buf, count, &off, data, strlen(data) + 1); + kfree(data); + + return size; +} +EXPORT_SYMBOL(bitmap_print_to_buf); + /* * Region 9-38:4/10 describes the following bitmap structure: * 0 9 12 18 38 N -- 2.25.1