All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v6 1/3] PCI/DOE: Expose the DOE features via sysfs
@ 2023-08-17 23:58 Alistair Francis
  2023-08-17 23:58 ` [PATCH v6 2/3] sysfs: Add a attr_is_visible function to attribute_group Alistair Francis
                   ` (4 more replies)
  0 siblings, 5 replies; 28+ messages in thread
From: Alistair Francis @ 2023-08-17 23:58 UTC (permalink / raw)
  To: bhelgaas, linux-pci, Jonathan.Cameron, lukas
  Cc: alex.williamson, christian.koenig, kch, gregkh, logang,
	linux-kernel, alistair23, chaitanyak, rdunlap, Alistair Francis

The PCIe 6 specification added support for the Data Object Exchange (DOE).
When DOE is supported the Discovery Data Object Protocol must be
implemented. The protocol allows a requester to obtain information about
the other DOE features supported by the device.

The kernel is already querying the DOE features supported and cacheing
the values. This patch exposes the values via sysfs. This will allow
userspace to determine which DOE features are supported by the PCIe
device.

By exposing the information to userspace tools like lspci can relay the
information to users. By listing all of the supported features we can
allow userspace to parse and support the list, which might include
vendor specific features as well as yet to be supported features.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
v6:
 - Use "feature" instead of protocol
 - Don't use any devm_* functions
 - Add two more patches to the series
v5:
 - Return the file name as the file contents
 - Code cleanups and simplifications
v4:
 - Fixup typos in the documentation
 - Make it clear that the file names contain the information
 - Small code cleanups
 - Remove most #ifdefs
 - Remove extra NULL assignment
v3:
 - Expose each DOE feature as a separate file
v2:
 - Add documentation
 - Code cleanups

This patch will create a doe_features directory for all
PCIe devices without the next two patches

 Documentation/ABI/testing/sysfs-bus-pci |  11 +++
 drivers/pci/doe.c                       | 112 ++++++++++++++++++++++++
 drivers/pci/pci-sysfs.c                 |  10 +++
 drivers/pci/pci.h                       |   3 +
 include/linux/pci-doe.h                 |   1 +
 5 files changed, 137 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci
index ecf47559f495..199ee5d27d9d 100644
--- a/Documentation/ABI/testing/sysfs-bus-pci
+++ b/Documentation/ABI/testing/sysfs-bus-pci
@@ -500,3 +500,14 @@ Description:
 		console drivers from the device.  Raw users of pci-sysfs
 		resourceN attributes must be terminated prior to resizing.
 		Success of the resizing operation is not guaranteed.
+
+What:		/sys/bus/pci/devices/.../doe_features
+Date:		August 2023
+Contact:	Linux PCI developers <linux-pci@vger.kernel.org>
+Description:
+		This directory contains a list of the supported
+		Data Object Exchange (DOE) features. The feature values are in the
+		file name. The contents of each file are the same as the name.
+		The value comes from the device and specifies the vendor and
+		data object type supported. The lower byte is the data object
+		type and the next two bytes are the vendor ID.
diff --git a/drivers/pci/doe.c b/drivers/pci/doe.c
index 1b97a5ab71a9..316aac60ccd5 100644
--- a/drivers/pci/doe.c
+++ b/drivers/pci/doe.c
@@ -56,6 +56,8 @@ struct pci_doe_mb {
 	wait_queue_head_t wq;
 	struct workqueue_struct *work_queue;
 	unsigned long flags;
+
+	struct device_attribute *sysfs_attrs;
 };
 
 struct pci_doe_protocol {
@@ -92,6 +94,116 @@ struct pci_doe_task {
 	struct pci_doe_mb *doe_mb;
 };
 
+#ifdef CONFIG_SYSFS
+static umode_t pci_doe_sysfs_attr_is_visible(struct kobject *kobj,
+					     struct attribute *a, int n)
+{
+	struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
+	unsigned long total_features = 0;
+	struct pci_doe_mb *doe_mb;
+	unsigned long index, j;
+	void *entry;
+
+	xa_for_each(&pdev->doe_mbs, index, doe_mb) {
+		xa_for_each(&doe_mb->prots, j, entry)
+			total_features++;
+	}
+
+	if (total_features == 0)
+		return 0;
+
+	return a->mode;
+}
+
+static struct attribute *pci_dev_doe_feature_attrs[] = {
+	NULL,
+};
+
+const struct attribute_group pci_dev_doe_feature_group = {
+	.name	= "doe_features",
+	.attrs	= pci_dev_doe_feature_attrs,
+	.is_visible = pci_doe_sysfs_attr_is_visible,
+};
+
+static ssize_t pci_doe_sysfs_feature_show(struct device *dev,
+					  struct device_attribute *attr,
+					  char *buf)
+{
+	return sysfs_emit(buf, "%s\n", attr->attr.name);
+}
+
+static int pci_doe_sysfs_feature_supports(struct pci_dev *pdev,
+					  struct pci_doe_mb *doe_mb)
+{
+	struct device *dev = &pdev->dev;
+	struct device_attribute *attrs;
+	unsigned long num_features = 0;
+	unsigned long vid, type;
+	unsigned long i;
+	void *entry;
+	int ret;
+
+	xa_for_each(&doe_mb->prots, i, entry)
+		num_features++;
+
+	attrs = kcalloc(num_features, sizeof(*attrs), GFP_KERNEL);
+	if (!attrs)
+		return -ENOMEM;
+
+	doe_mb->sysfs_attrs = attrs;
+	xa_for_each(&doe_mb->prots, i, entry) {
+		sysfs_attr_init(&attrs[i].attr);
+		vid = xa_to_value(entry) >> 8;
+		type = xa_to_value(entry) & 0xFF;
+		attrs[i].attr.name = kasprintf(GFP_KERNEL,
+					       "0x%04lX:%02lX", vid, type);
+		if (!attrs[i].attr.name) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+
+		attrs[i].attr.mode = 0444;
+		attrs[i].show = pci_doe_sysfs_feature_show;
+
+		ret = sysfs_add_file_to_group(&dev->kobj, &attrs[i].attr,
+					      pci_dev_doe_feature_group.name);
+		if (ret)
+			goto fail;
+	}
+
+	return 0;
+
+fail:
+	doe_mb->sysfs_attrs = NULL;
+	xa_for_each(&doe_mb->prots, i, entry) {
+		if (attrs[i].show)
+			sysfs_remove_file_from_group(&dev->kobj, &attrs[i].attr,
+						     pci_dev_doe_feature_group.name);
+		kfree(attrs[i].attr.name);
+	}
+
+	kfree(attrs);
+
+	return ret;
+}
+
+int doe_sysfs_init(struct pci_dev *pdev)
+{
+	struct pci_doe_mb *doe_mb;
+	unsigned long index;
+	int ret;
+
+	xa_for_each(&pdev->doe_mbs, index, doe_mb) {
+		ret = pci_doe_sysfs_feature_supports(pdev, doe_mb);
+
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+#endif
+
 static int pci_doe_wait(struct pci_doe_mb *doe_mb, unsigned long timeout)
 {
 	if (wait_event_timeout(doe_mb->wq,
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index ab32a91f287b..3f5104cf78b6 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -16,6 +16,7 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/pci.h>
+#include <linux/pci-doe.h>
 #include <linux/stat.h>
 #include <linux/export.h>
 #include <linux/topology.h>
@@ -1226,6 +1227,12 @@ static int pci_create_resource_files(struct pci_dev *pdev)
 	int i;
 	int retval;
 
+	if (IS_ENABLED(CONFIG_PCI_DOE)) {
+		retval = doe_sysfs_init(pdev);
+		if (retval)
+			return retval;
+	}
+
 	/* Expose the PCI resources from this device as files */
 	for (i = 0; i < PCI_STD_NUM_BARS; i++) {
 
@@ -1651,6 +1658,9 @@ static const struct attribute_group *pci_dev_attr_groups[] = {
 #endif
 #ifdef CONFIG_PCIEASPM
 	&aspm_ctrl_attr_group,
+#endif
+#ifdef CONFIG_PCI_DOE
+	&pci_dev_doe_feature_group,
 #endif
 	NULL,
 };
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index a4c397434057..139d37a0d4cd 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -180,6 +180,9 @@ extern const struct attribute_group *pci_dev_groups[];
 extern const struct attribute_group *pcibus_groups[];
 extern const struct device_type pci_dev_type;
 extern const struct attribute_group *pci_bus_groups[];
+#ifdef CONFIG_SYSFS
+extern const struct attribute_group pci_dev_doe_feature_group;
+#endif
 
 extern unsigned long pci_hotplug_io_size;
 extern unsigned long pci_hotplug_mmio_size;
diff --git a/include/linux/pci-doe.h b/include/linux/pci-doe.h
index 1f14aed4354b..4cc13d9ccb50 100644
--- a/include/linux/pci-doe.h
+++ b/include/linux/pci-doe.h
@@ -22,4 +22,5 @@ int pci_doe(struct pci_doe_mb *doe_mb, u16 vendor, u8 type,
 	    const void *request, size_t request_sz,
 	    void *response, size_t response_sz);
 
+int doe_sysfs_init(struct pci_dev *pci_dev);
 #endif
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v6 2/3] sysfs: Add a attr_is_visible function to attribute_group
  2023-08-17 23:58 [PATCH v6 1/3] PCI/DOE: Expose the DOE features via sysfs Alistair Francis
@ 2023-08-17 23:58 ` Alistair Francis
  2023-08-18  0:35   ` Damien Le Moal
  2023-08-19 10:57   ` Greg KH
  2023-08-17 23:58 ` [PATCH v6 3/3] PCI/DOE: Only expose the sysfs attribute group if DOE is supported Alistair Francis
                   ` (3 subsequent siblings)
  4 siblings, 2 replies; 28+ messages in thread
From: Alistair Francis @ 2023-08-17 23:58 UTC (permalink / raw)
  To: bhelgaas, linux-pci, Jonathan.Cameron, lukas
  Cc: alex.williamson, christian.koenig, kch, gregkh, logang,
	linux-kernel, alistair23, chaitanyak, rdunlap, Alistair Francis

When creating an attribute group, if it is named a subdirectory it is
created and the sysfs files are placed into that subdirectory.  If no
files are created, normally the directory would still be present, but it
would be empty.

This can be confusing for users, as it appears the feature is avaliable
as there is a directory, but it isn't supported by the hardware or the
kernel.

One way to fix this is to remove directories that don't contain any
files, such as [1]. The problem with this is that there are currently
lots of users in the kernel who expect the group to remain even if
empty, as they dynamically add/merge properties later.

The documentation for sysfs_merge_group() specifically says

    This function returns an error if the group doesn't exist or any of the
    files already exist in that group, in which case none of the new files
    are created.

So just not adding the group if it's empty doesn't work, at least not
with the code we currently have. The code can be changed to support
this, but it is difficult to determine how this will affect existing use
cases.

This approach instead adds a new function pointer, attr_is_visible(), to
`struct attribute_group` which can be set if the user wants to filter
the avaliablility of the function.

This matches the .is_visible() function pointer that already exists and
is commonly used. This approach provides greater control over if the
directory should be visible or not.

This will be used by the PCIe DOE sysfs attributes to kind the directory
on devices that don't support DOE.

1: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git/commit/?h=debugfs_cleanup&id=f670945dfbaf353fe068544c31e3fa45575da5b5

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
v6:
 - Add patch

 fs/sysfs/group.c      | 12 +++++++++++-
 include/linux/sysfs.h |  6 ++++++
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
index 138676463336..34afd5becdbe 100644
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -111,6 +111,7 @@ static int internal_create_group(struct kobject *kobj, int update,
 	kuid_t uid;
 	kgid_t gid;
 	int error;
+	umode_t mode;
 
 	if (WARN_ON(!kobj || (!update && !kobj->sd)))
 		return -EINVAL;
@@ -125,6 +126,15 @@ static int internal_create_group(struct kobject *kobj, int update,
 		return 0;
 	}
 
+	if (grp->attr_is_visible) {
+		mode = grp->attr_is_visible(kobj);
+
+		if (mode == 0)
+			return 0;
+	} else {
+		mode = S_IRWXU | S_IRUGO | S_IXUGO;
+	}
+
 	kobject_get_ownership(kobj, &uid, &gid);
 	if (grp->name) {
 		if (update) {
@@ -136,7 +146,7 @@ static int internal_create_group(struct kobject *kobj, int update,
 			}
 		} else {
 			kn = kernfs_create_dir_ns(kobj->sd, grp->name,
-						  S_IRWXU | S_IRUGO | S_IXUGO,
+						  mode,
 						  uid, gid, kobj, NULL);
 			if (IS_ERR(kn)) {
 				if (PTR_ERR(kn) == -EEXIST)
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index fd3fe5c8c17f..808e7fc0ca57 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -63,6 +63,11 @@ do {							\
  * @name:	Optional: Attribute group name
  *		If specified, the attribute group will be created in
  *		a new subdirectory with this name.
+ * @attr_is_visible:	Optional: Function to return permissions
+ *		associated with the attribute group. Only read/write
+ *		permissions as well as SYSFS_PREALLOC are accepted. Must
+ *		return 0 if an attribute is not visible. The returned value
+ *		will replace static permissions defined in struct attribute.
  * @is_visible:	Optional: Function to return permissions associated with an
  *		attribute of the group. Will be called repeatedly for each
  *		non-binary attribute in the group. Only read/write
@@ -83,6 +88,7 @@ do {							\
  */
 struct attribute_group {
 	const char		*name;
+	umode_t			(*attr_is_visible)(struct kobject *);
 	umode_t			(*is_visible)(struct kobject *,
 					      struct attribute *, int);
 	umode_t			(*is_bin_visible)(struct kobject *,
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v6 3/3] PCI/DOE: Only expose the sysfs attribute group if DOE is supported
  2023-08-17 23:58 [PATCH v6 1/3] PCI/DOE: Expose the DOE features via sysfs Alistair Francis
  2023-08-17 23:58 ` [PATCH v6 2/3] sysfs: Add a attr_is_visible function to attribute_group Alistair Francis
@ 2023-08-17 23:58 ` Alistair Francis
  2023-08-18  4:52 ` [PATCH v6 1/3] PCI/DOE: Expose the DOE features via sysfs Chaitanya Kulkarni
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 28+ messages in thread
From: Alistair Francis @ 2023-08-17 23:58 UTC (permalink / raw)
  To: bhelgaas, linux-pci, Jonathan.Cameron, lukas
  Cc: alex.williamson, christian.koenig, kch, gregkh, logang,
	linux-kernel, alistair23, chaitanyak, rdunlap, Alistair Francis

Now that the new attr_is_visible() function is avaliable as part of
`struct attribute_group` we can use that to hide the attribute group
on devices that don't support DOE.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
v6:
 - Add patch

 drivers/pci/doe.c | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/drivers/pci/doe.c b/drivers/pci/doe.c
index 316aac60ccd5..1a021e8b3e0c 100644
--- a/drivers/pci/doe.c
+++ b/drivers/pci/doe.c
@@ -95,8 +95,7 @@ struct pci_doe_task {
 };
 
 #ifdef CONFIG_SYSFS
-static umode_t pci_doe_sysfs_attr_is_visible(struct kobject *kobj,
-					     struct attribute *a, int n)
+static umode_t pci_doe_sysfs_group_is_visible(struct kobject *kobj)
 {
 	struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
 	unsigned long total_features = 0;
@@ -112,7 +111,17 @@ static umode_t pci_doe_sysfs_attr_is_visible(struct kobject *kobj,
 	if (total_features == 0)
 		return 0;
 
-	return a->mode;
+	return S_IRWXU | S_IRUGO | S_IXUGO;
+}
+
+static umode_t pci_doe_sysfs_attr_is_visible(struct kobject *kobj,
+					     struct attribute *a, int n)
+{
+	if (pci_doe_sysfs_group_is_visible(kobj)) {
+		return a->mode;
+	}
+
+	return 0;
 }
 
 static struct attribute *pci_dev_doe_feature_attrs[] = {
@@ -122,6 +131,7 @@ static struct attribute *pci_dev_doe_feature_attrs[] = {
 const struct attribute_group pci_dev_doe_feature_group = {
 	.name	= "doe_features",
 	.attrs	= pci_dev_doe_feature_attrs,
+	.attr_is_visible = pci_doe_sysfs_group_is_visible,
 	.is_visible = pci_doe_sysfs_attr_is_visible,
 };
 
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 2/3] sysfs: Add a attr_is_visible function to attribute_group
  2023-08-17 23:58 ` [PATCH v6 2/3] sysfs: Add a attr_is_visible function to attribute_group Alistair Francis
@ 2023-08-18  0:35   ` Damien Le Moal
  2023-08-19 10:57   ` Greg KH
  1 sibling, 0 replies; 28+ messages in thread
From: Damien Le Moal @ 2023-08-18  0:35 UTC (permalink / raw)
  To: Alistair Francis, bhelgaas, linux-pci, Jonathan.Cameron, lukas
  Cc: alex.williamson, christian.koenig, kch, gregkh, logang,
	linux-kernel, chaitanyak, rdunlap, Alistair Francis

On 2023/08/18 8:58, Alistair Francis wrote:
> When creating an attribute group, if it is named a subdirectory it is
> created and the sysfs files are placed into that subdirectory.  If no
> files are created, normally the directory would still be present, but it
> would be empty.
> 
> This can be confusing for users, as it appears the feature is avaliable
> as there is a directory, but it isn't supported by the hardware or the
> kernel.
> 
> One way to fix this is to remove directories that don't contain any
> files, such as [1]. The problem with this is that there are currently
> lots of users in the kernel who expect the group to remain even if
> empty, as they dynamically add/merge properties later.
> 
> The documentation for sysfs_merge_group() specifically says
> 
>     This function returns an error if the group doesn't exist or any of the
>     files already exist in that group, in which case none of the new files
>     are created.
> 
> So just not adding the group if it's empty doesn't work, at least not
> with the code we currently have. The code can be changed to support
> this, but it is difficult to determine how this will affect existing use
> cases.
> 
> This approach instead adds a new function pointer, attr_is_visible(), to
> `struct attribute_group` which can be set if the user wants to filter
> the avaliablility of the function.
> 
> This matches the .is_visible() function pointer that already exists and
> is commonly used. This approach provides greater control over if the
> directory should be visible or not.
> 
> This will be used by the PCIe DOE sysfs attributes to kind the directory
> on devices that don't support DOE.
> 
> 1: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git/commit/?h=debugfs_cleanup&id=f670945dfbaf353fe068544c31e3fa45575da5b5
> 
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
> v6:
>  - Add patch
> 
>  fs/sysfs/group.c      | 12 +++++++++++-
>  include/linux/sysfs.h |  6 ++++++
>  2 files changed, 17 insertions(+), 1 deletion(-)
> 
> diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
> index 138676463336..34afd5becdbe 100644
> --- a/fs/sysfs/group.c
> +++ b/fs/sysfs/group.c
> @@ -111,6 +111,7 @@ static int internal_create_group(struct kobject *kobj, int update,
>  	kuid_t uid;
>  	kgid_t gid;
>  	int error;
> +	umode_t mode;
>  
>  	if (WARN_ON(!kobj || (!update && !kobj->sd)))
>  		return -EINVAL;
> @@ -125,6 +126,15 @@ static int internal_create_group(struct kobject *kobj, int update,
>  		return 0;
>  	}
>  
> +	if (grp->attr_is_visible) {
> +		mode = grp->attr_is_visible(kobj);
> +

Remove the blank line here.

> +		if (mode == 0)

Nit: if (!mode)

> +			return 0;
> +	} else {
> +		mode = S_IRWXU | S_IRUGO | S_IXUGO;
> +	}
> +
>  	kobject_get_ownership(kobj, &uid, &gid);
>  	if (grp->name) {
>  		if (update) {
> @@ -136,7 +146,7 @@ static int internal_create_group(struct kobject *kobj, int update,
>  			}
>  		} else {
>  			kn = kernfs_create_dir_ns(kobj->sd, grp->name,
> -						  S_IRWXU | S_IRUGO | S_IXUGO,
> +						  mode,
>  						  uid, gid, kobj, NULL);
>  			if (IS_ERR(kn)) {
>  				if (PTR_ERR(kn) == -EEXIST)
> diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
> index fd3fe5c8c17f..808e7fc0ca57 100644
> --- a/include/linux/sysfs.h
> +++ b/include/linux/sysfs.h
> @@ -63,6 +63,11 @@ do {							\
>   * @name:	Optional: Attribute group name
>   *		If specified, the attribute group will be created in
>   *		a new subdirectory with this name.
> + * @attr_is_visible:	Optional: Function to return permissions

Given that the existing is_visible() function apply to an attribute, naming this
one "grp_is_visible" may be better. Otherwise, this is really confusing I think.

> + *		associated with the attribute group. Only read/write
> + *		permissions as well as SYSFS_PREALLOC are accepted. Must
> + *		return 0 if an attribute is not visible. The returned value
> + *		will replace static permissions defined in struct attribute.
>   * @is_visible:	Optional: Function to return permissions associated with an
>   *		attribute of the group. Will be called repeatedly for each
>   *		non-binary attribute in the group. Only read/write
> @@ -83,6 +88,7 @@ do {							\
>   */
>  struct attribute_group {
>  	const char		*name;
> +	umode_t			(*attr_is_visible)(struct kobject *);
>  	umode_t			(*is_visible)(struct kobject *,
>  					      struct attribute *, int);
>  	umode_t			(*is_bin_visible)(struct kobject *,

-- 
Damien Le Moal
Western Digital Research


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 1/3] PCI/DOE: Expose the DOE features via sysfs
  2023-08-17 23:58 [PATCH v6 1/3] PCI/DOE: Expose the DOE features via sysfs Alistair Francis
  2023-08-17 23:58 ` [PATCH v6 2/3] sysfs: Add a attr_is_visible function to attribute_group Alistair Francis
  2023-08-17 23:58 ` [PATCH v6 3/3] PCI/DOE: Only expose the sysfs attribute group if DOE is supported Alistair Francis
@ 2023-08-18  4:52 ` Chaitanya Kulkarni
  2023-08-18  5:48 ` kernel test robot
  2023-08-21 21:07 ` kernel test robot
  4 siblings, 0 replies; 28+ messages in thread
From: Chaitanya Kulkarni @ 2023-08-18  4:52 UTC (permalink / raw)
  To: Alistair Francis, bhelgaas, linux-pci, Jonathan.Cameron, lukas
  Cc: alex.williamson, christian.koenig, Chaitanya Kulkarni, gregkh,
	logang, linux-kernel, rdunlap, Alistair Francis

On 8/17/23 16:58, Alistair Francis wrote:
> The PCIe 6 specification added support for the Data Object Exchange (DOE).
> When DOE is supported the Discovery Data Object Protocol must be
> implemented. The protocol allows a requester to obtain information about
> the other DOE features supported by the device.
>
> The kernel is already querying the DOE features supported and cacheing
> the values. This patch exposes the values via sysfs. This will allow
> userspace to determine which DOE features are supported by the PCIe
> device.
>
> By exposing the information to userspace tools like lspci can relay the
> information to users. By listing all of the supported features we can
> allow userspace to parse and support the list, which might include
> vendor specific features as well as yet to be supported features.
>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
> v6:
>   - Use "feature" instead of protocol
>   - Don't use any devm_* functions
>   - Add two more patches to the series
> v5:
>   - Return the file name as the file contents
>   - Code cleanups and simplifications
> v4:
>   - Fixup typos in the documentation
>   - Make it clear that the file names contain the information
>   - Small code cleanups
>   - Remove most #ifdefs
>   - Remove extra NULL assignment
> v3:
>   - Expose each DOE feature as a separate file
> v2:
>   - Add documentation
>   - Code cleanups
>
> This patch will create a doe_features directory for all
> PCIe devices without the next two patches
>
>   Documentation/ABI/testing/sysfs-bus-pci |  11 +++
>   drivers/pci/doe.c                       | 112 ++++++++++++++++++++++++
>   drivers/pci/pci-sysfs.c                 |  10 +++
>   drivers/pci/pci.h                       |   3 +
>   include/linux/pci-doe.h                 |   1 +
>   5 files changed, 137 insertions(+)
>
> diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci
> index ecf47559f495..199ee5d27d9d 100644
> --- a/Documentation/ABI/testing/sysfs-bus-pci
> +++ b/Documentation/ABI/testing/sysfs-bus-pci
> @@ -500,3 +500,14 @@ Description:
>   		console drivers from the device.  Raw users of pci-sysfs
>   		resourceN attributes must be terminated prior to resizing.
>   		Success of the resizing operation is not guaranteed.
> +
> +What:		/sys/bus/pci/devices/.../doe_features
> +Date:		August 2023
> +Contact:	Linux PCI developers <linux-pci@vger.kernel.org>
> +Description:
> +		This directory contains a list of the supported
> +		Data Object Exchange (DOE) features. The feature values are in the

overly long line above ...

> +		file name. The contents of each file are the same as the name.
> +		The value comes from the device and specifies the vendor and
> +		data object type supported. The lower byte is the data object
> +		type and the next two bytes are the vendor ID.
> diff --git a/drivers/pci/doe.c b/drivers/pci/doe.c
> index 1b97a5ab71a9..316aac60ccd5 100644
> --- a/drivers/pci/doe.c
> +++ b/drivers/pci/doe.c
> @@ -56,6 +56,8 @@ struct pci_doe_mb {
>   	wait_queue_head_t wq;
>   	struct workqueue_struct *work_queue;
>   	unsigned long flags;
> +
> +	struct device_attribute *sysfs_attrs;

above naked declaration without CONFIG_SYSFS seems really odd
especially following code is under CONFIG_SYSFS, unless it is
accessed outside of CONFIG_SYSFS (which I don't think it is
a right interface) then ignore this comment ..

>   };
>   
>   struct pci_doe_protocol {
> @@ -92,6 +94,116 @@ struct pci_doe_task {
>   	struct pci_doe_mb *doe_mb;
>   };
>   
> +#ifdef CONFIG_SYSFS
> +static umode_t pci_doe_sysfs_attr_is_visible(struct kobject *kobj,
> +					     struct attribute *a, int n)
> +{
> +	struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
> +	unsigned long total_features = 0;
> +	struct pci_doe_mb *doe_mb;
> +	unsigned long index, j;
> +	void *entry;
> +
> +	xa_for_each(&pdev->doe_mbs, index, doe_mb) {
> +		xa_for_each(&doe_mb->prots, j, entry)
> +			total_features++;
> +	}
> +
> +	if (total_features == 0)
> +		return 0;
> +
> +	return a->mode;
> +}
> +

this removes the need for extra variable to avoids unnecessary
loop iterations unless there is bug in this suggestion, why not following ?

static umode_t pci_doe_sysfs_attr_is_visible(struct kobject *kobj,
					     struct attribute *a, int n)
{
	struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
	struct pci_doe_mb *doe_mb;
	unsigned long index, j;
	void *entry;

	xa_for_each(&pdev->doe_mbs, index, doe_mb) {
		xa_for_each(&doe_mb->prots, j, entry)
			return a->mode;
	}

	return 0;
}


> +static struct attribute *pci_dev_doe_feature_attrs[] = {
> +	NULL,
> +};
> +
> +const struct attribute_group pci_dev_doe_feature_group = {
> +	.name	= "doe_features",
> +	.attrs	= pci_dev_doe_feature_attrs,
> +	.is_visible = pci_doe_sysfs_attr_is_visible,
> +};
> +
> +static ssize_t pci_doe_sysfs_feature_show(struct device *dev,
> +					  struct device_attribute *attr,
> +					  char *buf)
> +{
> +	return sysfs_emit(buf, "%s\n", attr->attr.name);
> +}
> +
> +static int pci_doe_sysfs_feature_supports(struct pci_dev *pdev,
> +					  struct pci_doe_mb *doe_mb)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct device_attribute *attrs;
> +	unsigned long num_features = 0;
> +	unsigned long vid, type;
> +	unsigned long i;
> +	void *entry;
> +	int ret;
> +
> +	xa_for_each(&doe_mb->prots, i, entry)
> +		num_features++;
> +
> +	attrs = kcalloc(num_features, sizeof(*attrs), GFP_KERNEL);
> +	if (!attrs)
> +		return -ENOMEM;
> +
> +	doe_mb->sysfs_attrs = attrs;
> +	xa_for_each(&doe_mb->prots, i, entry) {
> +		sysfs_attr_init(&attrs[i].attr);
> +		vid = xa_to_value(entry) >> 8;
> +		type = xa_to_value(entry) & 0xFF;
> +		attrs[i].attr.name = kasprintf(GFP_KERNEL,
> +					       "0x%04lX:%02lX", vid, type);
> +		if (!attrs[i].attr.name) {
> +			ret = -ENOMEM;
> +			goto fail;
> +		}
> +
> +		attrs[i].attr.mode = 0444;
> +		attrs[i].show = pci_doe_sysfs_feature_show;
> +
> +		ret = sysfs_add_file_to_group(&dev->kobj, &attrs[i].attr,
> +					      pci_dev_doe_feature_group.name);
> +		if (ret)
> +			goto fail;
> +	}
> +
> +	return 0;
> +
> +fail:
> +	doe_mb->sysfs_attrs = NULL;
> +	xa_for_each(&doe_mb->prots, i, entry) {
> +		if (attrs[i].show)
> +			sysfs_remove_file_from_group(&dev->kobj, &attrs[i].attr,
> +						     pci_dev_doe_feature_group.name);
> +		kfree(attrs[i].attr.name);
> +	}
> +
> +	kfree(attrs);
> +
> +	return ret;
> +}
> +
> +int doe_sysfs_init(struct pci_dev *pdev)
> +{
> +	struct pci_doe_mb *doe_mb;
> +	unsigned long index;
> +	int ret;
> +
> +	xa_for_each(&pdev->doe_mbs, index, doe_mb) {
> +		ret = pci_doe_sysfs_feature_supports(pdev, doe_mb);
> +
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +#endif
> +
>   static int pci_doe_wait(struct pci_doe_mb *doe_mb, unsigned long timeout)
>   {
>   	if (wait_event_timeout(doe_mb->wq,
> diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
> index ab32a91f287b..3f5104cf78b6 100644
> --- a/drivers/pci/pci-sysfs.c
> +++ b/drivers/pci/pci-sysfs.c
> @@ -16,6 +16,7 @@
>   #include <linux/kernel.h>
>   #include <linux/sched.h>
>   #include <linux/pci.h>
> +#include <linux/pci-doe.h>
>   #include <linux/stat.h>
>   #include <linux/export.h>
>   #include <linux/topology.h>
> @@ -1226,6 +1227,12 @@ static int pci_create_resource_files(struct pci_dev *pdev)
>   	int i;
>   	int retval;
>   
> +	if (IS_ENABLED(CONFIG_PCI_DOE)) {
> +		retval = doe_sysfs_init(pdev);
> +		if (retval)
> +			return retval;
> +	}
> +
>   	/* Expose the PCI resources from this device as files */
>   	for (i = 0; i < PCI_STD_NUM_BARS; i++) {
>   
> @@ -1651,6 +1658,9 @@ static const struct attribute_group *pci_dev_attr_groups[] = {
>   #endif
>   #ifdef CONFIG_PCIEASPM
>   	&aspm_ctrl_attr_group,
> +#endif
> +#ifdef CONFIG_PCI_DOE
> +	&pci_dev_doe_feature_group,
>   #endif
>   	NULL,
>   };
> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
> index a4c397434057..139d37a0d4cd 100644
> --- a/drivers/pci/pci.h
> +++ b/drivers/pci/pci.h
> @@ -180,6 +180,9 @@ extern const struct attribute_group *pci_dev_groups[];
>   extern const struct attribute_group *pcibus_groups[];
>   extern const struct device_type pci_dev_type;
>   extern const struct attribute_group *pci_bus_groups[];
> +#ifdef CONFIG_SYSFS
> +extern const struct attribute_group pci_dev_doe_feature_group;
> +#endif
>   
>   extern unsigned long pci_hotplug_io_size;
>   extern unsigned long pci_hotplug_mmio_size;
> diff --git a/include/linux/pci-doe.h b/include/linux/pci-doe.h
> index 1f14aed4354b..4cc13d9ccb50 100644
> --- a/include/linux/pci-doe.h
> +++ b/include/linux/pci-doe.h
> @@ -22,4 +22,5 @@ int pci_doe(struct pci_doe_mb *doe_mb, u16 vendor, u8 type,
>   	    const void *request, size_t request_sz,
>   	    void *response, size_t response_sz);
>   
> +int doe_sysfs_init(struct pci_dev *pci_dev);
>   #endif


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 1/3] PCI/DOE: Expose the DOE features via sysfs
  2023-08-17 23:58 [PATCH v6 1/3] PCI/DOE: Expose the DOE features via sysfs Alistair Francis
                   ` (2 preceding siblings ...)
  2023-08-18  4:52 ` [PATCH v6 1/3] PCI/DOE: Expose the DOE features via sysfs Chaitanya Kulkarni
@ 2023-08-18  5:48 ` kernel test robot
  2023-08-21 21:07 ` kernel test robot
  4 siblings, 0 replies; 28+ messages in thread
From: kernel test robot @ 2023-08-18  5:48 UTC (permalink / raw)
  To: Alistair Francis, bhelgaas, linux-pci, Jonathan.Cameron, lukas
  Cc: oe-kbuild-all, alex.williamson, christian.koenig, kch, gregkh,
	logang, linux-kernel, alistair23, chaitanyak, rdunlap,
	Alistair Francis

Hi Alistair,

kernel test robot noticed the following build warnings:

[auto build test WARNING on pci/next]
[also build test WARNING on pci/for-linus driver-core/driver-core-testing driver-core/driver-core-next driver-core/driver-core-linus linus/master v6.5-rc6 next-20230817]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Alistair-Francis/sysfs-Add-a-attr_is_visible-function-to-attribute_group/20230818-080110
base:   https://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git next
patch link:    https://lore.kernel.org/r/20230817235810.596458-1-alistair.francis%40wdc.com
patch subject: [PATCH v6 1/3] PCI/DOE: Expose the DOE features via sysfs
config: loongarch-allyesconfig (https://download.01.org/0day-ci/archive/20230818/202308181341.DWHmL2Au-lkp@intel.com/config)
compiler: loongarch64-linux-gcc (GCC) 12.3.0
reproduce: (https://download.01.org/0day-ci/archive/20230818/202308181341.DWHmL2Au-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202308181341.DWHmL2Au-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/pci/doe.c:61: warning: Function parameter or member 'sysfs_attrs' not described in 'pci_doe_mb'


vim +61 drivers/pci/doe.c

a4ff8e7a716013 Li Ming          2022-11-16  36  
9d24322e887b6a Jonathan Cameron 2022-07-19  37  /**
9d24322e887b6a Jonathan Cameron 2022-07-19  38   * struct pci_doe_mb - State for a single DOE mailbox
9d24322e887b6a Jonathan Cameron 2022-07-19  39   *
9d24322e887b6a Jonathan Cameron 2022-07-19  40   * This state is used to manage a single DOE mailbox capability.  All fields
9d24322e887b6a Jonathan Cameron 2022-07-19  41   * should be considered opaque to the consumers and the structure passed into
022b66f38195f6 Lukas Wunner     2023-03-11  42   * the helpers below after being created by pci_doe_create_mb().
9d24322e887b6a Jonathan Cameron 2022-07-19  43   *
9d24322e887b6a Jonathan Cameron 2022-07-19  44   * @pdev: PCI device this mailbox belongs to
9d24322e887b6a Jonathan Cameron 2022-07-19  45   * @cap_offset: Capability offset
9d24322e887b6a Jonathan Cameron 2022-07-19  46   * @prots: Array of protocols supported (encoded as long values)
9d24322e887b6a Jonathan Cameron 2022-07-19  47   * @wq: Wait queue for work item
9d24322e887b6a Jonathan Cameron 2022-07-19  48   * @work_queue: Queue of pci_doe_work items
9d24322e887b6a Jonathan Cameron 2022-07-19  49   * @flags: Bit array of PCI_DOE_FLAG_* flags
9d24322e887b6a Jonathan Cameron 2022-07-19  50   */
9d24322e887b6a Jonathan Cameron 2022-07-19  51  struct pci_doe_mb {
9d24322e887b6a Jonathan Cameron 2022-07-19  52  	struct pci_dev *pdev;
9d24322e887b6a Jonathan Cameron 2022-07-19  53  	u16 cap_offset;
9d24322e887b6a Jonathan Cameron 2022-07-19  54  	struct xarray prots;
9d24322e887b6a Jonathan Cameron 2022-07-19  55  
9d24322e887b6a Jonathan Cameron 2022-07-19  56  	wait_queue_head_t wq;
9d24322e887b6a Jonathan Cameron 2022-07-19  57  	struct workqueue_struct *work_queue;
9d24322e887b6a Jonathan Cameron 2022-07-19  58  	unsigned long flags;
2a8556606e90c6 Alistair Francis 2023-08-17  59  
2a8556606e90c6 Alistair Francis 2023-08-17  60  	struct device_attribute *sysfs_attrs;
9d24322e887b6a Jonathan Cameron 2022-07-19 @61  };
9d24322e887b6a Jonathan Cameron 2022-07-19  62  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 2/3] sysfs: Add a attr_is_visible function to attribute_group
  2023-08-17 23:58 ` [PATCH v6 2/3] sysfs: Add a attr_is_visible function to attribute_group Alistair Francis
  2023-08-18  0:35   ` Damien Le Moal
@ 2023-08-19 10:57   ` Greg KH
  2023-08-22 20:20     ` Alistair Francis
  1 sibling, 1 reply; 28+ messages in thread
From: Greg KH @ 2023-08-19 10:57 UTC (permalink / raw)
  To: Alistair Francis
  Cc: bhelgaas, linux-pci, Jonathan.Cameron, lukas, alex.williamson,
	christian.koenig, kch, logang, linux-kernel, chaitanyak, rdunlap,
	Alistair Francis

On Thu, Aug 17, 2023 at 07:58:09PM -0400, Alistair Francis wrote:
> The documentation for sysfs_merge_group() specifically says
> 
>     This function returns an error if the group doesn't exist or any of the
>     files already exist in that group, in which case none of the new files
>     are created.
> 
> So just not adding the group if it's empty doesn't work, at least not
> with the code we currently have. The code can be changed to support
> this, but it is difficult to determine how this will affect existing use
> cases.

Did you try?  I'd really really really prefer we do it this way as it's
much simpler overall to have the sysfs core "do the right thing
automatically" than to force each and every bus/subsystem to have to
manually add this type of attribute.

Also, on a personal level, I want this function to work as it will allow
us to remove some code in some busses that don't really need to be there
(dynamic creation of some device attributes), which will then also allow
me to remove some apis in the driver core that should not be used at all
anymore (but keep creeping back in as there is still a few users.)

So I'll be selfish here and say "please try to get my proposed change to
work, it's really the correct thing to do here."

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 1/3] PCI/DOE: Expose the DOE features via sysfs
  2023-08-17 23:58 [PATCH v6 1/3] PCI/DOE: Expose the DOE features via sysfs Alistair Francis
                   ` (3 preceding siblings ...)
  2023-08-18  5:48 ` kernel test robot
@ 2023-08-21 21:07 ` kernel test robot
  4 siblings, 0 replies; 28+ messages in thread
From: kernel test robot @ 2023-08-21 21:07 UTC (permalink / raw)
  To: Alistair Francis, bhelgaas, linux-pci, Jonathan.Cameron, lukas
  Cc: llvm, oe-kbuild-all, alex.williamson, christian.koenig, kch,
	gregkh, logang, linux-kernel, alistair23, chaitanyak, rdunlap,
	Alistair Francis

Hi Alistair,

kernel test robot noticed the following build warnings:

[auto build test WARNING on pci/next]
[also build test WARNING on pci/for-linus driver-core/driver-core-testing driver-core/driver-core-next driver-core/driver-core-linus linus/master v6.5-rc7 next-20230821]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Alistair-Francis/sysfs-Add-a-attr_is_visible-function-to-attribute_group/20230818-080110
base:   https://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git next
patch link:    https://lore.kernel.org/r/20230817235810.596458-1-alistair.francis%40wdc.com
patch subject: [PATCH v6 1/3] PCI/DOE: Expose the DOE features via sysfs
config: i386-randconfig-006-20230821 (https://download.01.org/0day-ci/archive/20230822/202308220442.udC7U63t-lkp@intel.com/config)
compiler: clang version 16.0.4 (https://github.com/llvm/llvm-project.git ae42196bc493ffe877a7e3dff8be32035dea4d07)
reproduce: (https://download.01.org/0day-ci/archive/20230822/202308220442.udC7U63t-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202308220442.udC7U63t-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/pci/doe.c:61: warning: Function parameter or member 'sysfs_attrs' not described in 'pci_doe_mb'


vim +61 drivers/pci/doe.c

a4ff8e7a716013 Li Ming          2022-11-16  36  
9d24322e887b6a Jonathan Cameron 2022-07-19  37  /**
9d24322e887b6a Jonathan Cameron 2022-07-19  38   * struct pci_doe_mb - State for a single DOE mailbox
9d24322e887b6a Jonathan Cameron 2022-07-19  39   *
9d24322e887b6a Jonathan Cameron 2022-07-19  40   * This state is used to manage a single DOE mailbox capability.  All fields
9d24322e887b6a Jonathan Cameron 2022-07-19  41   * should be considered opaque to the consumers and the structure passed into
022b66f38195f6 Lukas Wunner     2023-03-11  42   * the helpers below after being created by pci_doe_create_mb().
9d24322e887b6a Jonathan Cameron 2022-07-19  43   *
9d24322e887b6a Jonathan Cameron 2022-07-19  44   * @pdev: PCI device this mailbox belongs to
9d24322e887b6a Jonathan Cameron 2022-07-19  45   * @cap_offset: Capability offset
9d24322e887b6a Jonathan Cameron 2022-07-19  46   * @prots: Array of protocols supported (encoded as long values)
9d24322e887b6a Jonathan Cameron 2022-07-19  47   * @wq: Wait queue for work item
9d24322e887b6a Jonathan Cameron 2022-07-19  48   * @work_queue: Queue of pci_doe_work items
9d24322e887b6a Jonathan Cameron 2022-07-19  49   * @flags: Bit array of PCI_DOE_FLAG_* flags
9d24322e887b6a Jonathan Cameron 2022-07-19  50   */
9d24322e887b6a Jonathan Cameron 2022-07-19  51  struct pci_doe_mb {
9d24322e887b6a Jonathan Cameron 2022-07-19  52  	struct pci_dev *pdev;
9d24322e887b6a Jonathan Cameron 2022-07-19  53  	u16 cap_offset;
9d24322e887b6a Jonathan Cameron 2022-07-19  54  	struct xarray prots;
9d24322e887b6a Jonathan Cameron 2022-07-19  55  
9d24322e887b6a Jonathan Cameron 2022-07-19  56  	wait_queue_head_t wq;
9d24322e887b6a Jonathan Cameron 2022-07-19  57  	struct workqueue_struct *work_queue;
9d24322e887b6a Jonathan Cameron 2022-07-19  58  	unsigned long flags;
2a8556606e90c6 Alistair Francis 2023-08-17  59  
2a8556606e90c6 Alistair Francis 2023-08-17  60  	struct device_attribute *sysfs_attrs;
9d24322e887b6a Jonathan Cameron 2022-07-19 @61  };
9d24322e887b6a Jonathan Cameron 2022-07-19  62  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 2/3] sysfs: Add a attr_is_visible function to attribute_group
  2023-08-19 10:57   ` Greg KH
@ 2023-08-22 20:20     ` Alistair Francis
  2023-08-23  7:02       ` Greg KH
  0 siblings, 1 reply; 28+ messages in thread
From: Alistair Francis @ 2023-08-22 20:20 UTC (permalink / raw)
  To: Greg KH
  Cc: bhelgaas, linux-pci, Jonathan.Cameron, lukas, alex.williamson,
	christian.koenig, kch, logang, linux-kernel, chaitanyak, rdunlap,
	Alistair Francis

On Sat, Aug 19, 2023 at 6:57 AM Greg KH <gregkh@linuxfoundation.org> wrote:
>
> On Thu, Aug 17, 2023 at 07:58:09PM -0400, Alistair Francis wrote:
> > The documentation for sysfs_merge_group() specifically says
> >
> >     This function returns an error if the group doesn't exist or any of the
> >     files already exist in that group, in which case none of the new files
> >     are created.
> >
> > So just not adding the group if it's empty doesn't work, at least not
> > with the code we currently have. The code can be changed to support
> > this, but it is difficult to determine how this will affect existing use
> > cases.
>
> Did you try?  I'd really really really prefer we do it this way as it's
> much simpler overall to have the sysfs core "do the right thing
> automatically" than to force each and every bus/subsystem to have to
> manually add this type of attribute.
>
> Also, on a personal level, I want this function to work as it will allow
> us to remove some code in some busses that don't really need to be there
> (dynamic creation of some device attributes), which will then also allow
> me to remove some apis in the driver core that should not be used at all
> anymore (but keep creeping back in as there is still a few users.)
>
> So I'll be selfish here and say "please try to get my proposed change to
> work, it's really the correct thing to do here."

I did try!

This is an attempt:
https://github.com/alistair23/linux/commit/56b55756a2d7a66f7b6eb8a5692b1b5e2f81a9a9

It is based on your original patch with a bunch of:

if (!parent) {
    parent = kernfs_create_dir_ns(kobj->sd, grp->name,
                  S_IRWXU | S_IRUGO | S_IXUGO,
                  uid, gid, kobj, NULL);
    ...
    }


added throughout the code base.

Very basic testing shows that it does what I need it to do and I don't
see any kernel oops on boot.

I prefer the approach I have in this mailing list patch. But if you
like the commit mentioned above I can tidy and clean it up and then
use that instead

Alistair

>
> thanks,
>
> greg k-h

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 2/3] sysfs: Add a attr_is_visible function to attribute_group
  2023-08-22 20:20     ` Alistair Francis
@ 2023-08-23  7:02       ` Greg KH
  2023-08-28  5:05         ` Alistair Francis
  0 siblings, 1 reply; 28+ messages in thread
From: Greg KH @ 2023-08-23  7:02 UTC (permalink / raw)
  To: Alistair Francis
  Cc: bhelgaas, linux-pci, Jonathan.Cameron, lukas, alex.williamson,
	christian.koenig, kch, logang, linux-kernel, chaitanyak, rdunlap,
	Alistair Francis

On Tue, Aug 22, 2023 at 04:20:06PM -0400, Alistair Francis wrote:
> On Sat, Aug 19, 2023 at 6:57 AM Greg KH <gregkh@linuxfoundation.org> wrote:
> >
> > On Thu, Aug 17, 2023 at 07:58:09PM -0400, Alistair Francis wrote:
> > > The documentation for sysfs_merge_group() specifically says
> > >
> > >     This function returns an error if the group doesn't exist or any of the
> > >     files already exist in that group, in which case none of the new files
> > >     are created.
> > >
> > > So just not adding the group if it's empty doesn't work, at least not
> > > with the code we currently have. The code can be changed to support
> > > this, but it is difficult to determine how this will affect existing use
> > > cases.
> >
> > Did you try?  I'd really really really prefer we do it this way as it's
> > much simpler overall to have the sysfs core "do the right thing
> > automatically" than to force each and every bus/subsystem to have to
> > manually add this type of attribute.
> >
> > Also, on a personal level, I want this function to work as it will allow
> > us to remove some code in some busses that don't really need to be there
> > (dynamic creation of some device attributes), which will then also allow
> > me to remove some apis in the driver core that should not be used at all
> > anymore (but keep creeping back in as there is still a few users.)
> >
> > So I'll be selfish here and say "please try to get my proposed change to
> > work, it's really the correct thing to do here."
> 
> I did try!
> 
> This is an attempt:
> https://github.com/alistair23/linux/commit/56b55756a2d7a66f7b6eb8a5692b1b5e2f81a9a9
> 
> It is based on your original patch with a bunch of:
> 
> if (!parent) {
>     parent = kernfs_create_dir_ns(kobj->sd, grp->name,
>                   S_IRWXU | S_IRUGO | S_IXUGO,
>                   uid, gid, kobj, NULL);
>     ...
>     }
> 
> 
> added throughout the code base.
> 
> Very basic testing shows that it does what I need it to do and I don't
> see any kernel oops on boot.

Nice!

Mind if I take it and clean it up a bit and test with it here?  Again, I
need this functionality for other stuff as well, so getting it merged
for your feature is fine with me.

> I prefer the approach I have in this mailing list patch. But if you
> like the commit mentioned above I can tidy and clean it up and then
> use that instead

I would rather do it this way.  I can work on this on Friday if you want
me to.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 2/3] sysfs: Add a attr_is_visible function to attribute_group
  2023-08-23  7:02       ` Greg KH
@ 2023-08-28  5:05         ` Alistair Francis
  2023-08-31  8:31           ` Greg KH
  0 siblings, 1 reply; 28+ messages in thread
From: Alistair Francis @ 2023-08-28  5:05 UTC (permalink / raw)
  To: Greg KH
  Cc: bhelgaas, linux-pci, Jonathan.Cameron, lukas, alex.williamson,
	christian.koenig, kch, logang, linux-kernel, chaitanyak, rdunlap,
	Alistair Francis

On Wed, Aug 23, 2023 at 5:02 PM Greg KH <gregkh@linuxfoundation.org> wrote:
>
> On Tue, Aug 22, 2023 at 04:20:06PM -0400, Alistair Francis wrote:
> > On Sat, Aug 19, 2023 at 6:57 AM Greg KH <gregkh@linuxfoundation.org> wrote:
> > >
> > > On Thu, Aug 17, 2023 at 07:58:09PM -0400, Alistair Francis wrote:
> > > > The documentation for sysfs_merge_group() specifically says
> > > >
> > > >     This function returns an error if the group doesn't exist or any of the
> > > >     files already exist in that group, in which case none of the new files
> > > >     are created.
> > > >
> > > > So just not adding the group if it's empty doesn't work, at least not
> > > > with the code we currently have. The code can be changed to support
> > > > this, but it is difficult to determine how this will affect existing use
> > > > cases.
> > >
> > > Did you try?  I'd really really really prefer we do it this way as it's
> > > much simpler overall to have the sysfs core "do the right thing
> > > automatically" than to force each and every bus/subsystem to have to
> > > manually add this type of attribute.
> > >
> > > Also, on a personal level, I want this function to work as it will allow
> > > us to remove some code in some busses that don't really need to be there
> > > (dynamic creation of some device attributes), which will then also allow
> > > me to remove some apis in the driver core that should not be used at all
> > > anymore (but keep creeping back in as there is still a few users.)
> > >
> > > So I'll be selfish here and say "please try to get my proposed change to
> > > work, it's really the correct thing to do here."
> >
> > I did try!
> >
> > This is an attempt:
> > https://github.com/alistair23/linux/commit/56b55756a2d7a66f7b6eb8a5692b1b5e2f81a9a9
> >
> > It is based on your original patch with a bunch of:
> >
> > if (!parent) {
> >     parent = kernfs_create_dir_ns(kobj->sd, grp->name,
> >                   S_IRWXU | S_IRUGO | S_IXUGO,
> >                   uid, gid, kobj, NULL);
> >     ...
> >     }
> >
> >
> > added throughout the code base.
> >
> > Very basic testing shows that it does what I need it to do and I don't
> > see any kernel oops on boot.
>
> Nice!
>
> Mind if I take it and clean it up a bit and test with it here?  Again, I
> need this functionality for other stuff as well, so getting it merged
> for your feature is fine with me.

Sure! Go ahead. Sorry I was travelling last week.

>
> > I prefer the approach I have in this mailing list patch. But if you
> > like the commit mentioned above I can tidy and clean it up and then
> > use that instead
>
> I would rather do it this way.  I can work on this on Friday if you want
> me to.

Yeah, that's fine with me. If you aren't able to let me know and I can
finish up the patch and send it with this series

Alistair

>
> thanks,
>
> greg k-h

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 2/3] sysfs: Add a attr_is_visible function to attribute_group
  2023-08-28  5:05         ` Alistair Francis
@ 2023-08-31  8:31           ` Greg KH
  2023-08-31 14:36             ` Greg KH
  0 siblings, 1 reply; 28+ messages in thread
From: Greg KH @ 2023-08-31  8:31 UTC (permalink / raw)
  To: Alistair Francis
  Cc: bhelgaas, linux-pci, Jonathan.Cameron, lukas, alex.williamson,
	christian.koenig, kch, logang, linux-kernel, chaitanyak, rdunlap,
	Alistair Francis

On Mon, Aug 28, 2023 at 03:05:41PM +1000, Alistair Francis wrote:
> On Wed, Aug 23, 2023 at 5:02 PM Greg KH <gregkh@linuxfoundation.org> wrote:
> >
> > On Tue, Aug 22, 2023 at 04:20:06PM -0400, Alistair Francis wrote:
> > > On Sat, Aug 19, 2023 at 6:57 AM Greg KH <gregkh@linuxfoundation.org> wrote:
> > > >
> > > > On Thu, Aug 17, 2023 at 07:58:09PM -0400, Alistair Francis wrote:
> > > > > The documentation for sysfs_merge_group() specifically says
> > > > >
> > > > >     This function returns an error if the group doesn't exist or any of the
> > > > >     files already exist in that group, in which case none of the new files
> > > > >     are created.
> > > > >
> > > > > So just not adding the group if it's empty doesn't work, at least not
> > > > > with the code we currently have. The code can be changed to support
> > > > > this, but it is difficult to determine how this will affect existing use
> > > > > cases.
> > > >
> > > > Did you try?  I'd really really really prefer we do it this way as it's
> > > > much simpler overall to have the sysfs core "do the right thing
> > > > automatically" than to force each and every bus/subsystem to have to
> > > > manually add this type of attribute.
> > > >
> > > > Also, on a personal level, I want this function to work as it will allow
> > > > us to remove some code in some busses that don't really need to be there
> > > > (dynamic creation of some device attributes), which will then also allow
> > > > me to remove some apis in the driver core that should not be used at all
> > > > anymore (but keep creeping back in as there is still a few users.)
> > > >
> > > > So I'll be selfish here and say "please try to get my proposed change to
> > > > work, it's really the correct thing to do here."
> > >
> > > I did try!
> > >
> > > This is an attempt:
> > > https://github.com/alistair23/linux/commit/56b55756a2d7a66f7b6eb8a5692b1b5e2f81a9a9
> > >
> > > It is based on your original patch with a bunch of:
> > >
> > > if (!parent) {
> > >     parent = kernfs_create_dir_ns(kobj->sd, grp->name,
> > >                   S_IRWXU | S_IRUGO | S_IXUGO,
> > >                   uid, gid, kobj, NULL);
> > >     ...
> > >     }
> > >
> > >
> > > added throughout the code base.
> > >
> > > Very basic testing shows that it does what I need it to do and I don't
> > > see any kernel oops on boot.
> >
> > Nice!
> >
> > Mind if I take it and clean it up a bit and test with it here?  Again, I
> > need this functionality for other stuff as well, so getting it merged
> > for your feature is fine with me.
> 
> Sure! Go ahead. Sorry I was travelling last week.
> 
> >
> > > I prefer the approach I have in this mailing list patch. But if you
> > > like the commit mentioned above I can tidy and clean it up and then
> > > use that instead
> >
> > I would rather do it this way.  I can work on this on Friday if you want
> > me to.
> 
> Yeah, that's fine with me. If you aren't able to let me know and I can
> finish up the patch and send it with this series

Great, and for the email record, as github links are not stable, here's
the patch that you have above attached below.  I'll test this out and
clean it up a bit more and see how it goes...

thanks,

greg k-h


From 2929d17b58d02dcf52d0345fa966c616e09a5afa Mon Sep 17 00:00:00 2001
From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Date: Wed, 24 Aug 2022 15:45:36 +0200
Subject: [PATCH] sysfs: do not create empty directories if no attributes are
 present

When creating an attribute group, if it is named a subdirectory is
created and the sysfs files are placed into that subdirectory.  If no
files are created, normally the directory would still be present, but it
would be empty.  Clean this up by removing the directory if no files
were successfully created in the group at all.

Co-developed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Co-developed-by: Alistair Francis <alistair.francis@wdc.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 fs/sysfs/file.c  | 14 ++++++++++--
 fs/sysfs/group.c | 56 ++++++++++++++++++++++++++++++++++++------------
 2 files changed, 54 insertions(+), 16 deletions(-)

diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index a12ac0356c69..7aab6c09662c 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -391,8 +391,18 @@ int sysfs_add_file_to_group(struct kobject *kobj,
 		kernfs_get(parent);
 	}
 
-	if (!parent)
-		return -ENOENT;
+	if (!parent) {
+		parent = kernfs_create_dir_ns(kobj->sd, group,
+					  S_IRWXU | S_IRUGO | S_IXUGO,
+					  uid, gid, kobj, NULL);
+		if (IS_ERR(parent)) {
+			if (PTR_ERR(parent) == -EEXIST)
+				sysfs_warn_dup(kobj->sd, group);
+			return PTR_ERR(parent);
+		}
+
+		kernfs_get(parent);
+	}
 
 	kobject_get_ownership(kobj, &uid, &gid);
 	error = sysfs_add_file_mode_ns(parent, attr, attr->mode, uid, gid,
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
index 138676463336..013fa333cd3c 100644
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -31,12 +31,14 @@ static void remove_files(struct kernfs_node *parent,
 			kernfs_remove_by_name(parent, (*bin_attr)->attr.name);
 }
 
+/* returns -ERROR if error, or >= 0 for number of files actually created */
 static int create_files(struct kernfs_node *parent, struct kobject *kobj,
 			kuid_t uid, kgid_t gid,
 			const struct attribute_group *grp, int update)
 {
 	struct attribute *const *attr;
 	struct bin_attribute *const *bin_attr;
+	int files_created = 0;
 	int error = 0, i;
 
 	if (grp->attrs) {
@@ -65,6 +67,8 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
 						       gid, NULL);
 			if (unlikely(error))
 				break;
+
+			files_created++;
 		}
 		if (error) {
 			remove_files(parent, grp);
@@ -95,12 +99,15 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
 							   NULL);
 			if (error)
 				break;
+			files_created++;
 		}
 		if (error)
 			remove_files(parent, grp);
 	}
 exit:
-	return error;
+	if (error)
+		return error;
+	return files_created;
 }
 
 
@@ -130,9 +137,14 @@ static int internal_create_group(struct kobject *kobj, int update,
 		if (update) {
 			kn = kernfs_find_and_get(kobj->sd, grp->name);
 			if (!kn) {
-				pr_warn("Can't update unknown attr grp name: %s/%s\n",
-					kobj->name, grp->name);
-				return -EINVAL;
+				kn = kernfs_create_dir_ns(kobj->sd, grp->name,
+							  S_IRWXU | S_IRUGO | S_IXUGO,
+							  uid, gid, kobj, NULL);
+				if (IS_ERR(kn)) {
+					if (PTR_ERR(kn) == -EEXIST)
+						sysfs_warn_dup(kobj->sd, grp->name);
+					return PTR_ERR(kn);
+				}
 			}
 		} else {
 			kn = kernfs_create_dir_ns(kobj->sd, grp->name,
@@ -150,11 +162,18 @@ static int internal_create_group(struct kobject *kobj, int update,
 
 	kernfs_get(kn);
 	error = create_files(kn, kobj, uid, gid, grp, update);
-	if (error) {
+	if (error <= 0) {
+		/*
+		 * If an error happened _OR_ if no files were created in the
+		 * attribute group, and we have a name for this group, delete
+		 * the name so there's not an empty directory.
+		 */
 		if (grp->name)
 			kernfs_remove(kn);
+	} else {
+		error = 0;
+		kernfs_put(kn);
 	}
-	kernfs_put(kn);
 
 	if (grp->name && update)
 		kernfs_put(kn);
@@ -318,13 +337,12 @@ void sysfs_remove_groups(struct kobject *kobj,
 EXPORT_SYMBOL_GPL(sysfs_remove_groups);
 
 /**
- * sysfs_merge_group - merge files into a pre-existing attribute group.
+ * sysfs_merge_group - merge files into a attribute group.
  * @kobj:	The kobject containing the group.
  * @grp:	The files to create and the attribute group they belong to.
  *
- * This function returns an error if the group doesn't exist or any of the
- * files already exist in that group, in which case none of the new files
- * are created.
+ * This function returns an error if any of the files already exist in
+ * that group, in which case none of the new files are created.
  */
 int sysfs_merge_group(struct kobject *kobj,
 		       const struct attribute_group *grp)
@@ -336,12 +354,22 @@ int sysfs_merge_group(struct kobject *kobj,
 	struct attribute *const *attr;
 	int i;
 
-	parent = kernfs_find_and_get(kobj->sd, grp->name);
-	if (!parent)
-		return -ENOENT;
-
 	kobject_get_ownership(kobj, &uid, &gid);
 
+	parent = kernfs_find_and_get(kobj->sd, grp->name);
+	if (!parent) {
+		parent = kernfs_create_dir_ns(kobj->sd, grp->name,
+					  S_IRWXU | S_IRUGO | S_IXUGO,
+					  uid, gid, kobj, NULL);
+		if (IS_ERR(parent)) {
+			if (PTR_ERR(parent) == -EEXIST)
+				sysfs_warn_dup(kobj->sd, grp->name);
+			return PTR_ERR(parent);
+		}
+
+		kernfs_get(parent);
+	}
+
 	for ((i = 0, attr = grp->attrs); *attr && !error; (++i, ++attr))
 		error = sysfs_add_file_mode_ns(parent, *attr, (*attr)->mode,
 					       uid, gid, NULL);
-- 
2.42.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 2/3] sysfs: Add a attr_is_visible function to attribute_group
  2023-08-31  8:31           ` Greg KH
@ 2023-08-31 14:36             ` Greg KH
  2023-09-01 21:00               ` Greg KH
  0 siblings, 1 reply; 28+ messages in thread
From: Greg KH @ 2023-08-31 14:36 UTC (permalink / raw)
  To: Alistair Francis
  Cc: bhelgaas, linux-pci, Jonathan.Cameron, lukas, alex.williamson,
	christian.koenig, kch, logang, linux-kernel, chaitanyak, rdunlap,
	Alistair Francis

On Thu, Aug 31, 2023 at 10:31:07AM +0200, Greg KH wrote:
> On Mon, Aug 28, 2023 at 03:05:41PM +1000, Alistair Francis wrote:
> > On Wed, Aug 23, 2023 at 5:02 PM Greg KH <gregkh@linuxfoundation.org> wrote:
> > >
> > > On Tue, Aug 22, 2023 at 04:20:06PM -0400, Alistair Francis wrote:
> > > > On Sat, Aug 19, 2023 at 6:57 AM Greg KH <gregkh@linuxfoundation.org> wrote:
> > > > >
> > > > > On Thu, Aug 17, 2023 at 07:58:09PM -0400, Alistair Francis wrote:
> > > > > > The documentation for sysfs_merge_group() specifically says
> > > > > >
> > > > > >     This function returns an error if the group doesn't exist or any of the
> > > > > >     files already exist in that group, in which case none of the new files
> > > > > >     are created.
> > > > > >
> > > > > > So just not adding the group if it's empty doesn't work, at least not
> > > > > > with the code we currently have. The code can be changed to support
> > > > > > this, but it is difficult to determine how this will affect existing use
> > > > > > cases.
> > > > >
> > > > > Did you try?  I'd really really really prefer we do it this way as it's
> > > > > much simpler overall to have the sysfs core "do the right thing
> > > > > automatically" than to force each and every bus/subsystem to have to
> > > > > manually add this type of attribute.
> > > > >
> > > > > Also, on a personal level, I want this function to work as it will allow
> > > > > us to remove some code in some busses that don't really need to be there
> > > > > (dynamic creation of some device attributes), which will then also allow
> > > > > me to remove some apis in the driver core that should not be used at all
> > > > > anymore (but keep creeping back in as there is still a few users.)
> > > > >
> > > > > So I'll be selfish here and say "please try to get my proposed change to
> > > > > work, it's really the correct thing to do here."
> > > >
> > > > I did try!
> > > >
> > > > This is an attempt:
> > > > https://github.com/alistair23/linux/commit/56b55756a2d7a66f7b6eb8a5692b1b5e2f81a9a9
> > > >
> > > > It is based on your original patch with a bunch of:
> > > >
> > > > if (!parent) {
> > > >     parent = kernfs_create_dir_ns(kobj->sd, grp->name,
> > > >                   S_IRWXU | S_IRUGO | S_IXUGO,
> > > >                   uid, gid, kobj, NULL);
> > > >     ...
> > > >     }
> > > >
> > > >
> > > > added throughout the code base.
> > > >
> > > > Very basic testing shows that it does what I need it to do and I don't
> > > > see any kernel oops on boot.
> > >
> > > Nice!
> > >
> > > Mind if I take it and clean it up a bit and test with it here?  Again, I
> > > need this functionality for other stuff as well, so getting it merged
> > > for your feature is fine with me.
> > 
> > Sure! Go ahead. Sorry I was travelling last week.
> > 
> > >
> > > > I prefer the approach I have in this mailing list patch. But if you
> > > > like the commit mentioned above I can tidy and clean it up and then
> > > > use that instead
> > >
> > > I would rather do it this way.  I can work on this on Friday if you want
> > > me to.
> > 
> > Yeah, that's fine with me. If you aren't able to let me know and I can
> > finish up the patch and send it with this series
> 
> Great, and for the email record, as github links are not stable, here's
> the patch that you have above attached below.  I'll test this out and
> clean it up a bit more and see how it goes...
> 
> thanks,
> 
> greg k-h
> 
> 
> From 2929d17b58d02dcf52d0345fa966c616e09a5afa Mon Sep 17 00:00:00 2001
> From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Date: Wed, 24 Aug 2022 15:45:36 +0200
> Subject: [PATCH] sysfs: do not create empty directories if no attributes are
>  present
> 
> When creating an attribute group, if it is named a subdirectory is
> created and the sysfs files are placed into that subdirectory.  If no
> files are created, normally the directory would still be present, but it
> would be empty.  Clean this up by removing the directory if no files
> were successfully created in the group at all.
> 
> Co-developed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Co-developed-by: Alistair Francis <alistair.francis@wdc.com>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  fs/sysfs/file.c  | 14 ++++++++++--
>  fs/sysfs/group.c | 56 ++++++++++++++++++++++++++++++++++++------------
>  2 files changed, 54 insertions(+), 16 deletions(-)
> 
> diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
> index a12ac0356c69..7aab6c09662c 100644
> --- a/fs/sysfs/file.c
> +++ b/fs/sysfs/file.c
> @@ -391,8 +391,18 @@ int sysfs_add_file_to_group(struct kobject *kobj,
>  		kernfs_get(parent);
>  	}
>  
> -	if (!parent)
> -		return -ENOENT;
> +	if (!parent) {
> +		parent = kernfs_create_dir_ns(kobj->sd, group,
> +					  S_IRWXU | S_IRUGO | S_IXUGO,
> +					  uid, gid, kobj, NULL);
> +		if (IS_ERR(parent)) {
> +			if (PTR_ERR(parent) == -EEXIST)
> +				sysfs_warn_dup(kobj->sd, group);
> +			return PTR_ERR(parent);
> +		}
> +
> +		kernfs_get(parent);
> +	}
>  
>  	kobject_get_ownership(kobj, &uid, &gid);
>  	error = sysfs_add_file_mode_ns(parent, attr, attr->mode, uid, gid,
> diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
> index 138676463336..013fa333cd3c 100644
> --- a/fs/sysfs/group.c
> +++ b/fs/sysfs/group.c
> @@ -31,12 +31,14 @@ static void remove_files(struct kernfs_node *parent,
>  			kernfs_remove_by_name(parent, (*bin_attr)->attr.name);
>  }
>  
> +/* returns -ERROR if error, or >= 0 for number of files actually created */
>  static int create_files(struct kernfs_node *parent, struct kobject *kobj,
>  			kuid_t uid, kgid_t gid,
>  			const struct attribute_group *grp, int update)
>  {
>  	struct attribute *const *attr;
>  	struct bin_attribute *const *bin_attr;
> +	int files_created = 0;
>  	int error = 0, i;
>  
>  	if (grp->attrs) {
> @@ -65,6 +67,8 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
>  						       gid, NULL);
>  			if (unlikely(error))
>  				break;
> +
> +			files_created++;
>  		}
>  		if (error) {
>  			remove_files(parent, grp);
> @@ -95,12 +99,15 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
>  							   NULL);
>  			if (error)
>  				break;
> +			files_created++;
>  		}
>  		if (error)
>  			remove_files(parent, grp);
>  	}
>  exit:
> -	return error;
> +	if (error)
> +		return error;
> +	return files_created;
>  }
>  
>  
> @@ -130,9 +137,14 @@ static int internal_create_group(struct kobject *kobj, int update,
>  		if (update) {
>  			kn = kernfs_find_and_get(kobj->sd, grp->name);
>  			if (!kn) {
> -				pr_warn("Can't update unknown attr grp name: %s/%s\n",
> -					kobj->name, grp->name);
> -				return -EINVAL;
> +				kn = kernfs_create_dir_ns(kobj->sd, grp->name,
> +							  S_IRWXU | S_IRUGO | S_IXUGO,
> +							  uid, gid, kobj, NULL);
> +				if (IS_ERR(kn)) {
> +					if (PTR_ERR(kn) == -EEXIST)
> +						sysfs_warn_dup(kobj->sd, grp->name);
> +					return PTR_ERR(kn);
> +				}
>  			}
>  		} else {
>  			kn = kernfs_create_dir_ns(kobj->sd, grp->name,
> @@ -150,11 +162,18 @@ static int internal_create_group(struct kobject *kobj, int update,
>  
>  	kernfs_get(kn);
>  	error = create_files(kn, kobj, uid, gid, grp, update);
> -	if (error) {
> +	if (error <= 0) {
> +		/*
> +		 * If an error happened _OR_ if no files were created in the
> +		 * attribute group, and we have a name for this group, delete
> +		 * the name so there's not an empty directory.
> +		 */
>  		if (grp->name)
>  			kernfs_remove(kn);
> +	} else {
> +		error = 0;
> +		kernfs_put(kn);
>  	}
> -	kernfs_put(kn);
>  
>  	if (grp->name && update)
>  		kernfs_put(kn);
> @@ -318,13 +337,12 @@ void sysfs_remove_groups(struct kobject *kobj,
>  EXPORT_SYMBOL_GPL(sysfs_remove_groups);
>  
>  /**
> - * sysfs_merge_group - merge files into a pre-existing attribute group.
> + * sysfs_merge_group - merge files into a attribute group.
>   * @kobj:	The kobject containing the group.
>   * @grp:	The files to create and the attribute group they belong to.
>   *
> - * This function returns an error if the group doesn't exist or any of the
> - * files already exist in that group, in which case none of the new files
> - * are created.
> + * This function returns an error if any of the files already exist in
> + * that group, in which case none of the new files are created.
>   */
>  int sysfs_merge_group(struct kobject *kobj,
>  		       const struct attribute_group *grp)
> @@ -336,12 +354,22 @@ int sysfs_merge_group(struct kobject *kobj,
>  	struct attribute *const *attr;
>  	int i;
>  
> -	parent = kernfs_find_and_get(kobj->sd, grp->name);
> -	if (!parent)
> -		return -ENOENT;
> -
>  	kobject_get_ownership(kobj, &uid, &gid);
>  
> +	parent = kernfs_find_and_get(kobj->sd, grp->name);
> +	if (!parent) {
> +		parent = kernfs_create_dir_ns(kobj->sd, grp->name,
> +					  S_IRWXU | S_IRUGO | S_IXUGO,
> +					  uid, gid, kobj, NULL);
> +		if (IS_ERR(parent)) {
> +			if (PTR_ERR(parent) == -EEXIST)
> +				sysfs_warn_dup(kobj->sd, grp->name);
> +			return PTR_ERR(parent);
> +		}
> +
> +		kernfs_get(parent);
> +	}
> +
>  	for ((i = 0, attr = grp->attrs); *attr && !error; (++i, ++attr))
>  		error = sysfs_add_file_mode_ns(parent, *attr, (*attr)->mode,
>  					       uid, gid, NULL);
> -- 
> 2.42.0
> 

And as the 0-day bot just showed, this patch isn't going to work
properly, the uid/gid stuff isn't all hooked up properly, I'll work on
fixing that up when I get some cycles...

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 2/3] sysfs: Add a attr_is_visible function to attribute_group
  2023-08-31 14:36             ` Greg KH
@ 2023-09-01 21:00               ` Greg KH
  2023-10-05 13:05                 ` Greg KH
  0 siblings, 1 reply; 28+ messages in thread
From: Greg KH @ 2023-09-01 21:00 UTC (permalink / raw)
  To: Alistair Francis
  Cc: bhelgaas, linux-pci, Jonathan.Cameron, lukas, alex.williamson,
	christian.koenig, kch, logang, linux-kernel, chaitanyak, rdunlap,
	Alistair Francis

On Thu, Aug 31, 2023 at 04:36:13PM +0200, Greg KH wrote:
> On Thu, Aug 31, 2023 at 10:31:07AM +0200, Greg KH wrote:
> > On Mon, Aug 28, 2023 at 03:05:41PM +1000, Alistair Francis wrote:
> > > On Wed, Aug 23, 2023 at 5:02 PM Greg KH <gregkh@linuxfoundation.org> wrote:
> > > >
> > > > On Tue, Aug 22, 2023 at 04:20:06PM -0400, Alistair Francis wrote:
> > > > > On Sat, Aug 19, 2023 at 6:57 AM Greg KH <gregkh@linuxfoundation.org> wrote:
> > > > > >
> > > > > > On Thu, Aug 17, 2023 at 07:58:09PM -0400, Alistair Francis wrote:
> > > > > > > The documentation for sysfs_merge_group() specifically says
> > > > > > >
> > > > > > >     This function returns an error if the group doesn't exist or any of the
> > > > > > >     files already exist in that group, in which case none of the new files
> > > > > > >     are created.
> > > > > > >
> > > > > > > So just not adding the group if it's empty doesn't work, at least not
> > > > > > > with the code we currently have. The code can be changed to support
> > > > > > > this, but it is difficult to determine how this will affect existing use
> > > > > > > cases.
> > > > > >
> > > > > > Did you try?  I'd really really really prefer we do it this way as it's
> > > > > > much simpler overall to have the sysfs core "do the right thing
> > > > > > automatically" than to force each and every bus/subsystem to have to
> > > > > > manually add this type of attribute.
> > > > > >
> > > > > > Also, on a personal level, I want this function to work as it will allow
> > > > > > us to remove some code in some busses that don't really need to be there
> > > > > > (dynamic creation of some device attributes), which will then also allow
> > > > > > me to remove some apis in the driver core that should not be used at all
> > > > > > anymore (but keep creeping back in as there is still a few users.)
> > > > > >
> > > > > > So I'll be selfish here and say "please try to get my proposed change to
> > > > > > work, it's really the correct thing to do here."
> > > > >
> > > > > I did try!
> > > > >
> > > > > This is an attempt:
> > > > > https://github.com/alistair23/linux/commit/56b55756a2d7a66f7b6eb8a5692b1b5e2f81a9a9
> > > > >
> > > > > It is based on your original patch with a bunch of:
> > > > >
> > > > > if (!parent) {
> > > > >     parent = kernfs_create_dir_ns(kobj->sd, grp->name,
> > > > >                   S_IRWXU | S_IRUGO | S_IXUGO,
> > > > >                   uid, gid, kobj, NULL);
> > > > >     ...
> > > > >     }
> > > > >
> > > > >
> > > > > added throughout the code base.
> > > > >
> > > > > Very basic testing shows that it does what I need it to do and I don't
> > > > > see any kernel oops on boot.
> > > >
> > > > Nice!
> > > >
> > > > Mind if I take it and clean it up a bit and test with it here?  Again, I
> > > > need this functionality for other stuff as well, so getting it merged
> > > > for your feature is fine with me.
> > > 
> > > Sure! Go ahead. Sorry I was travelling last week.
> > > 
> > > >
> > > > > I prefer the approach I have in this mailing list patch. But if you
> > > > > like the commit mentioned above I can tidy and clean it up and then
> > > > > use that instead
> > > >
> > > > I would rather do it this way.  I can work on this on Friday if you want
> > > > me to.
> > > 
> > > Yeah, that's fine with me. If you aren't able to let me know and I can
> > > finish up the patch and send it with this series
> > 
> > Great, and for the email record, as github links are not stable, here's
> > the patch that you have above attached below.  I'll test this out and
> > clean it up a bit more and see how it goes...
> > 
> > thanks,
> > 
> > greg k-h
> > 
> > 
> > From 2929d17b58d02dcf52d0345fa966c616e09a5afa Mon Sep 17 00:00:00 2001
> > From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > Date: Wed, 24 Aug 2022 15:45:36 +0200
> > Subject: [PATCH] sysfs: do not create empty directories if no attributes are
> >  present
> > 
> > When creating an attribute group, if it is named a subdirectory is
> > created and the sysfs files are placed into that subdirectory.  If no
> > files are created, normally the directory would still be present, but it
> > would be empty.  Clean this up by removing the directory if no files
> > were successfully created in the group at all.
> > 
> > Co-developed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > Co-developed-by: Alistair Francis <alistair.francis@wdc.com>
> > Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> > ---
> >  fs/sysfs/file.c  | 14 ++++++++++--
> >  fs/sysfs/group.c | 56 ++++++++++++++++++++++++++++++++++++------------
> >  2 files changed, 54 insertions(+), 16 deletions(-)
> > 
> > diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
> > index a12ac0356c69..7aab6c09662c 100644
> > --- a/fs/sysfs/file.c
> > +++ b/fs/sysfs/file.c
> > @@ -391,8 +391,18 @@ int sysfs_add_file_to_group(struct kobject *kobj,
> >  		kernfs_get(parent);
> >  	}
> >  
> > -	if (!parent)
> > -		return -ENOENT;
> > +	if (!parent) {
> > +		parent = kernfs_create_dir_ns(kobj->sd, group,
> > +					  S_IRWXU | S_IRUGO | S_IXUGO,
> > +					  uid, gid, kobj, NULL);
> > +		if (IS_ERR(parent)) {
> > +			if (PTR_ERR(parent) == -EEXIST)
> > +				sysfs_warn_dup(kobj->sd, group);
> > +			return PTR_ERR(parent);
> > +		}
> > +
> > +		kernfs_get(parent);
> > +	}
> >  
> >  	kobject_get_ownership(kobj, &uid, &gid);
> >  	error = sysfs_add_file_mode_ns(parent, attr, attr->mode, uid, gid,
> > diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
> > index 138676463336..013fa333cd3c 100644
> > --- a/fs/sysfs/group.c
> > +++ b/fs/sysfs/group.c
> > @@ -31,12 +31,14 @@ static void remove_files(struct kernfs_node *parent,
> >  			kernfs_remove_by_name(parent, (*bin_attr)->attr.name);
> >  }
> >  
> > +/* returns -ERROR if error, or >= 0 for number of files actually created */
> >  static int create_files(struct kernfs_node *parent, struct kobject *kobj,
> >  			kuid_t uid, kgid_t gid,
> >  			const struct attribute_group *grp, int update)
> >  {
> >  	struct attribute *const *attr;
> >  	struct bin_attribute *const *bin_attr;
> > +	int files_created = 0;
> >  	int error = 0, i;
> >  
> >  	if (grp->attrs) {
> > @@ -65,6 +67,8 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
> >  						       gid, NULL);
> >  			if (unlikely(error))
> >  				break;
> > +
> > +			files_created++;
> >  		}
> >  		if (error) {
> >  			remove_files(parent, grp);
> > @@ -95,12 +99,15 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
> >  							   NULL);
> >  			if (error)
> >  				break;
> > +			files_created++;
> >  		}
> >  		if (error)
> >  			remove_files(parent, grp);
> >  	}
> >  exit:
> > -	return error;
> > +	if (error)
> > +		return error;
> > +	return files_created;
> >  }
> >  
> >  
> > @@ -130,9 +137,14 @@ static int internal_create_group(struct kobject *kobj, int update,
> >  		if (update) {
> >  			kn = kernfs_find_and_get(kobj->sd, grp->name);
> >  			if (!kn) {
> > -				pr_warn("Can't update unknown attr grp name: %s/%s\n",
> > -					kobj->name, grp->name);
> > -				return -EINVAL;
> > +				kn = kernfs_create_dir_ns(kobj->sd, grp->name,
> > +							  S_IRWXU | S_IRUGO | S_IXUGO,
> > +							  uid, gid, kobj, NULL);
> > +				if (IS_ERR(kn)) {
> > +					if (PTR_ERR(kn) == -EEXIST)
> > +						sysfs_warn_dup(kobj->sd, grp->name);
> > +					return PTR_ERR(kn);
> > +				}
> >  			}
> >  		} else {
> >  			kn = kernfs_create_dir_ns(kobj->sd, grp->name,
> > @@ -150,11 +162,18 @@ static int internal_create_group(struct kobject *kobj, int update,
> >  
> >  	kernfs_get(kn);
> >  	error = create_files(kn, kobj, uid, gid, grp, update);
> > -	if (error) {
> > +	if (error <= 0) {
> > +		/*
> > +		 * If an error happened _OR_ if no files were created in the
> > +		 * attribute group, and we have a name for this group, delete
> > +		 * the name so there's not an empty directory.
> > +		 */
> >  		if (grp->name)
> >  			kernfs_remove(kn);
> > +	} else {
> > +		error = 0;
> > +		kernfs_put(kn);
> >  	}
> > -	kernfs_put(kn);
> >  
> >  	if (grp->name && update)
> >  		kernfs_put(kn);
> > @@ -318,13 +337,12 @@ void sysfs_remove_groups(struct kobject *kobj,
> >  EXPORT_SYMBOL_GPL(sysfs_remove_groups);
> >  
> >  /**
> > - * sysfs_merge_group - merge files into a pre-existing attribute group.
> > + * sysfs_merge_group - merge files into a attribute group.
> >   * @kobj:	The kobject containing the group.
> >   * @grp:	The files to create and the attribute group they belong to.
> >   *
> > - * This function returns an error if the group doesn't exist or any of the
> > - * files already exist in that group, in which case none of the new files
> > - * are created.
> > + * This function returns an error if any of the files already exist in
> > + * that group, in which case none of the new files are created.
> >   */
> >  int sysfs_merge_group(struct kobject *kobj,
> >  		       const struct attribute_group *grp)
> > @@ -336,12 +354,22 @@ int sysfs_merge_group(struct kobject *kobj,
> >  	struct attribute *const *attr;
> >  	int i;
> >  
> > -	parent = kernfs_find_and_get(kobj->sd, grp->name);
> > -	if (!parent)
> > -		return -ENOENT;
> > -
> >  	kobject_get_ownership(kobj, &uid, &gid);
> >  
> > +	parent = kernfs_find_and_get(kobj->sd, grp->name);
> > +	if (!parent) {
> > +		parent = kernfs_create_dir_ns(kobj->sd, grp->name,
> > +					  S_IRWXU | S_IRUGO | S_IXUGO,
> > +					  uid, gid, kobj, NULL);
> > +		if (IS_ERR(parent)) {
> > +			if (PTR_ERR(parent) == -EEXIST)
> > +				sysfs_warn_dup(kobj->sd, grp->name);
> > +			return PTR_ERR(parent);
> > +		}
> > +
> > +		kernfs_get(parent);
> > +	}
> > +
> >  	for ((i = 0, attr = grp->attrs); *attr && !error; (++i, ++attr))
> >  		error = sysfs_add_file_mode_ns(parent, *attr, (*attr)->mode,
> >  					       uid, gid, NULL);
> > -- 
> > 2.42.0
> > 
> 
> And as the 0-day bot just showed, this patch isn't going to work
> properly, the uid/gid stuff isn't all hooked up properly, I'll work on
> fixing that up when I get some cycles...

Oops, nope, that was my fault in applying this to my tree, sorry for the
noise...

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 2/3] sysfs: Add a attr_is_visible function to attribute_group
  2023-09-01 21:00               ` Greg KH
@ 2023-10-05 13:05                 ` Greg KH
  2023-10-11  5:10                   ` Alistair Francis
  0 siblings, 1 reply; 28+ messages in thread
From: Greg KH @ 2023-10-05 13:05 UTC (permalink / raw)
  To: Alistair Francis
  Cc: bhelgaas, linux-pci, Jonathan.Cameron, lukas, alex.williamson,
	christian.koenig, kch, logang, linux-kernel, chaitanyak, rdunlap,
	Alistair Francis

On Fri, Sep 01, 2023 at 11:00:59PM +0200, Greg KH wrote:
> On Thu, Aug 31, 2023 at 04:36:13PM +0200, Greg KH wrote:
> > On Thu, Aug 31, 2023 at 10:31:07AM +0200, Greg KH wrote:
> > > On Mon, Aug 28, 2023 at 03:05:41PM +1000, Alistair Francis wrote:
> > > > On Wed, Aug 23, 2023 at 5:02 PM Greg KH <gregkh@linuxfoundation.org> wrote:
> > > > >
> > > > > On Tue, Aug 22, 2023 at 04:20:06PM -0400, Alistair Francis wrote:
> > > > > > On Sat, Aug 19, 2023 at 6:57 AM Greg KH <gregkh@linuxfoundation.org> wrote:
> > > > > > >
> > > > > > > On Thu, Aug 17, 2023 at 07:58:09PM -0400, Alistair Francis wrote:
> > > > > > > > The documentation for sysfs_merge_group() specifically says
> > > > > > > >
> > > > > > > >     This function returns an error if the group doesn't exist or any of the
> > > > > > > >     files already exist in that group, in which case none of the new files
> > > > > > > >     are created.
> > > > > > > >
> > > > > > > > So just not adding the group if it's empty doesn't work, at least not
> > > > > > > > with the code we currently have. The code can be changed to support
> > > > > > > > this, but it is difficult to determine how this will affect existing use
> > > > > > > > cases.
> > > > > > >
> > > > > > > Did you try?  I'd really really really prefer we do it this way as it's
> > > > > > > much simpler overall to have the sysfs core "do the right thing
> > > > > > > automatically" than to force each and every bus/subsystem to have to
> > > > > > > manually add this type of attribute.
> > > > > > >
> > > > > > > Also, on a personal level, I want this function to work as it will allow
> > > > > > > us to remove some code in some busses that don't really need to be there
> > > > > > > (dynamic creation of some device attributes), which will then also allow
> > > > > > > me to remove some apis in the driver core that should not be used at all
> > > > > > > anymore (but keep creeping back in as there is still a few users.)
> > > > > > >
> > > > > > > So I'll be selfish here and say "please try to get my proposed change to
> > > > > > > work, it's really the correct thing to do here."
> > > > > >
> > > > > > I did try!
> > > > > >
> > > > > > This is an attempt:
> > > > > > https://github.com/alistair23/linux/commit/56b55756a2d7a66f7b6eb8a5692b1b5e2f81a9a9
> > > > > >
> > > > > > It is based on your original patch with a bunch of:
> > > > > >
> > > > > > if (!parent) {
> > > > > >     parent = kernfs_create_dir_ns(kobj->sd, grp->name,
> > > > > >                   S_IRWXU | S_IRUGO | S_IXUGO,
> > > > > >                   uid, gid, kobj, NULL);
> > > > > >     ...
> > > > > >     }
> > > > > >
> > > > > >
> > > > > > added throughout the code base.
> > > > > >
> > > > > > Very basic testing shows that it does what I need it to do and I don't
> > > > > > see any kernel oops on boot.
> > > > >
> > > > > Nice!
> > > > >
> > > > > Mind if I take it and clean it up a bit and test with it here?  Again, I
> > > > > need this functionality for other stuff as well, so getting it merged
> > > > > for your feature is fine with me.
> > > > 
> > > > Sure! Go ahead. Sorry I was travelling last week.
> > > > 
> > > > >
> > > > > > I prefer the approach I have in this mailing list patch. But if you
> > > > > > like the commit mentioned above I can tidy and clean it up and then
> > > > > > use that instead
> > > > >
> > > > > I would rather do it this way.  I can work on this on Friday if you want
> > > > > me to.
> > > > 
> > > > Yeah, that's fine with me. If you aren't able to let me know and I can
> > > > finish up the patch and send it with this series
> > > 
> > > Great, and for the email record, as github links are not stable, here's
> > > the patch that you have above attached below.  I'll test this out and
> > > clean it up a bit more and see how it goes...
> > > 
> > > thanks,
> > > 
> > > greg k-h
> > > 
> > > 
> > > From 2929d17b58d02dcf52d0345fa966c616e09a5afa Mon Sep 17 00:00:00 2001
> > > From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > > Date: Wed, 24 Aug 2022 15:45:36 +0200
> > > Subject: [PATCH] sysfs: do not create empty directories if no attributes are
> > >  present
> > > 
> > > When creating an attribute group, if it is named a subdirectory is
> > > created and the sysfs files are placed into that subdirectory.  If no
> > > files are created, normally the directory would still be present, but it
> > > would be empty.  Clean this up by removing the directory if no files
> > > were successfully created in the group at all.
> > > 
> > > Co-developed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > > Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > > Co-developed-by: Alistair Francis <alistair.francis@wdc.com>
> > > Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> > > ---
> > >  fs/sysfs/file.c  | 14 ++++++++++--
> > >  fs/sysfs/group.c | 56 ++++++++++++++++++++++++++++++++++++------------
> > >  2 files changed, 54 insertions(+), 16 deletions(-)
> > > 
> > > diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
> > > index a12ac0356c69..7aab6c09662c 100644
> > > --- a/fs/sysfs/file.c
> > > +++ b/fs/sysfs/file.c
> > > @@ -391,8 +391,18 @@ int sysfs_add_file_to_group(struct kobject *kobj,
> > >  		kernfs_get(parent);
> > >  	}
> > >  
> > > -	if (!parent)
> > > -		return -ENOENT;
> > > +	if (!parent) {
> > > +		parent = kernfs_create_dir_ns(kobj->sd, group,
> > > +					  S_IRWXU | S_IRUGO | S_IXUGO,
> > > +					  uid, gid, kobj, NULL);
> > > +		if (IS_ERR(parent)) {
> > > +			if (PTR_ERR(parent) == -EEXIST)
> > > +				sysfs_warn_dup(kobj->sd, group);
> > > +			return PTR_ERR(parent);
> > > +		}
> > > +
> > > +		kernfs_get(parent);
> > > +	}
> > >  
> > >  	kobject_get_ownership(kobj, &uid, &gid);
> > >  	error = sysfs_add_file_mode_ns(parent, attr, attr->mode, uid, gid,
> > > diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
> > > index 138676463336..013fa333cd3c 100644
> > > --- a/fs/sysfs/group.c
> > > +++ b/fs/sysfs/group.c
> > > @@ -31,12 +31,14 @@ static void remove_files(struct kernfs_node *parent,
> > >  			kernfs_remove_by_name(parent, (*bin_attr)->attr.name);
> > >  }
> > >  
> > > +/* returns -ERROR if error, or >= 0 for number of files actually created */
> > >  static int create_files(struct kernfs_node *parent, struct kobject *kobj,
> > >  			kuid_t uid, kgid_t gid,
> > >  			const struct attribute_group *grp, int update)
> > >  {
> > >  	struct attribute *const *attr;
> > >  	struct bin_attribute *const *bin_attr;
> > > +	int files_created = 0;
> > >  	int error = 0, i;
> > >  
> > >  	if (grp->attrs) {
> > > @@ -65,6 +67,8 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
> > >  						       gid, NULL);
> > >  			if (unlikely(error))
> > >  				break;
> > > +
> > > +			files_created++;
> > >  		}
> > >  		if (error) {
> > >  			remove_files(parent, grp);
> > > @@ -95,12 +99,15 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
> > >  							   NULL);
> > >  			if (error)
> > >  				break;
> > > +			files_created++;
> > >  		}
> > >  		if (error)
> > >  			remove_files(parent, grp);
> > >  	}
> > >  exit:
> > > -	return error;
> > > +	if (error)
> > > +		return error;
> > > +	return files_created;
> > >  }
> > >  
> > >  
> > > @@ -130,9 +137,14 @@ static int internal_create_group(struct kobject *kobj, int update,
> > >  		if (update) {
> > >  			kn = kernfs_find_and_get(kobj->sd, grp->name);
> > >  			if (!kn) {
> > > -				pr_warn("Can't update unknown attr grp name: %s/%s\n",
> > > -					kobj->name, grp->name);
> > > -				return -EINVAL;
> > > +				kn = kernfs_create_dir_ns(kobj->sd, grp->name,
> > > +							  S_IRWXU | S_IRUGO | S_IXUGO,
> > > +							  uid, gid, kobj, NULL);
> > > +				if (IS_ERR(kn)) {
> > > +					if (PTR_ERR(kn) == -EEXIST)
> > > +						sysfs_warn_dup(kobj->sd, grp->name);
> > > +					return PTR_ERR(kn);
> > > +				}
> > >  			}
> > >  		} else {
> > >  			kn = kernfs_create_dir_ns(kobj->sd, grp->name,
> > > @@ -150,11 +162,18 @@ static int internal_create_group(struct kobject *kobj, int update,
> > >  
> > >  	kernfs_get(kn);
> > >  	error = create_files(kn, kobj, uid, gid, grp, update);
> > > -	if (error) {
> > > +	if (error <= 0) {
> > > +		/*
> > > +		 * If an error happened _OR_ if no files were created in the
> > > +		 * attribute group, and we have a name for this group, delete
> > > +		 * the name so there's not an empty directory.
> > > +		 */
> > >  		if (grp->name)
> > >  			kernfs_remove(kn);
> > > +	} else {
> > > +		error = 0;
> > > +		kernfs_put(kn);
> > >  	}
> > > -	kernfs_put(kn);
> > >  
> > >  	if (grp->name && update)
> > >  		kernfs_put(kn);
> > > @@ -318,13 +337,12 @@ void sysfs_remove_groups(struct kobject *kobj,
> > >  EXPORT_SYMBOL_GPL(sysfs_remove_groups);
> > >  
> > >  /**
> > > - * sysfs_merge_group - merge files into a pre-existing attribute group.
> > > + * sysfs_merge_group - merge files into a attribute group.
> > >   * @kobj:	The kobject containing the group.
> > >   * @grp:	The files to create and the attribute group they belong to.
> > >   *
> > > - * This function returns an error if the group doesn't exist or any of the
> > > - * files already exist in that group, in which case none of the new files
> > > - * are created.
> > > + * This function returns an error if any of the files already exist in
> > > + * that group, in which case none of the new files are created.
> > >   */
> > >  int sysfs_merge_group(struct kobject *kobj,
> > >  		       const struct attribute_group *grp)
> > > @@ -336,12 +354,22 @@ int sysfs_merge_group(struct kobject *kobj,
> > >  	struct attribute *const *attr;
> > >  	int i;
> > >  
> > > -	parent = kernfs_find_and_get(kobj->sd, grp->name);
> > > -	if (!parent)
> > > -		return -ENOENT;
> > > -
> > >  	kobject_get_ownership(kobj, &uid, &gid);
> > >  
> > > +	parent = kernfs_find_and_get(kobj->sd, grp->name);
> > > +	if (!parent) {
> > > +		parent = kernfs_create_dir_ns(kobj->sd, grp->name,
> > > +					  S_IRWXU | S_IRUGO | S_IXUGO,
> > > +					  uid, gid, kobj, NULL);
> > > +		if (IS_ERR(parent)) {
> > > +			if (PTR_ERR(parent) == -EEXIST)
> > > +				sysfs_warn_dup(kobj->sd, grp->name);
> > > +			return PTR_ERR(parent);
> > > +		}
> > > +
> > > +		kernfs_get(parent);
> > > +	}
> > > +
> > >  	for ((i = 0, attr = grp->attrs); *attr && !error; (++i, ++attr))
> > >  		error = sysfs_add_file_mode_ns(parent, *attr, (*attr)->mode,
> > >  					       uid, gid, NULL);
> > > -- 
> > > 2.42.0
> > > 
> > 
> > And as the 0-day bot just showed, this patch isn't going to work
> > properly, the uid/gid stuff isn't all hooked up properly, I'll work on
> > fixing that up when I get some cycles...
> 
> Oops, nope, that was my fault in applying this to my tree, sorry for the
> noise...

And I just got around to testing this, and it does not boot at all.
Below is the patch I am using, are you sure you got this to boot for
you?

thanks,

greg k-h

From db537de5a5af649b594604e2de177527f890878d Mon Sep 17 00:00:00 2001
From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Date: Wed, 24 Aug 2022 15:45:36 +0200
Subject: [PATCH] sysfs: do not create empty directories if no attributes are
 present

When creating an attribute group, if it is named a subdirectory is
created and the sysfs files are placed into that subdirectory.  If no
files are created, normally the directory would still be present, but it
would be empty.  Clean this up by removing the directory if no files
were successfully created in the group at all.

Co-developed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Co-developed-by: Alistair Francis <alistair.francis@wdc.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 fs/sysfs/file.c  | 16 +++++++++++---
 fs/sysfs/group.c | 56 ++++++++++++++++++++++++++++++++++++------------
 2 files changed, 55 insertions(+), 17 deletions(-)

diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index a12ac0356c69..9f79ec193ffe 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -391,10 +391,20 @@ int sysfs_add_file_to_group(struct kobject *kobj,
 		kernfs_get(parent);
 	}
 
-	if (!parent)
-		return -ENOENT;
-
 	kobject_get_ownership(kobj, &uid, &gid);
+	if (!parent) {
+		parent = kernfs_create_dir_ns(kobj->sd, group,
+					  S_IRWXU | S_IRUGO | S_IXUGO,
+					  uid, gid, kobj, NULL);
+		if (IS_ERR(parent)) {
+			if (PTR_ERR(parent) == -EEXIST)
+				sysfs_warn_dup(kobj->sd, group);
+			return PTR_ERR(parent);
+		}
+
+		kernfs_get(parent);
+	}
+
 	error = sysfs_add_file_mode_ns(parent, attr, attr->mode, uid, gid,
 				       NULL);
 	kernfs_put(parent);
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
index 138676463336..013fa333cd3c 100644
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -31,12 +31,14 @@ static void remove_files(struct kernfs_node *parent,
 			kernfs_remove_by_name(parent, (*bin_attr)->attr.name);
 }
 
+/* returns -ERROR if error, or >= 0 for number of files actually created */
 static int create_files(struct kernfs_node *parent, struct kobject *kobj,
 			kuid_t uid, kgid_t gid,
 			const struct attribute_group *grp, int update)
 {
 	struct attribute *const *attr;
 	struct bin_attribute *const *bin_attr;
+	int files_created = 0;
 	int error = 0, i;
 
 	if (grp->attrs) {
@@ -65,6 +67,8 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
 						       gid, NULL);
 			if (unlikely(error))
 				break;
+
+			files_created++;
 		}
 		if (error) {
 			remove_files(parent, grp);
@@ -95,12 +99,15 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
 							   NULL);
 			if (error)
 				break;
+			files_created++;
 		}
 		if (error)
 			remove_files(parent, grp);
 	}
 exit:
-	return error;
+	if (error)
+		return error;
+	return files_created;
 }
 
 
@@ -130,9 +137,14 @@ static int internal_create_group(struct kobject *kobj, int update,
 		if (update) {
 			kn = kernfs_find_and_get(kobj->sd, grp->name);
 			if (!kn) {
-				pr_warn("Can't update unknown attr grp name: %s/%s\n",
-					kobj->name, grp->name);
-				return -EINVAL;
+				kn = kernfs_create_dir_ns(kobj->sd, grp->name,
+							  S_IRWXU | S_IRUGO | S_IXUGO,
+							  uid, gid, kobj, NULL);
+				if (IS_ERR(kn)) {
+					if (PTR_ERR(kn) == -EEXIST)
+						sysfs_warn_dup(kobj->sd, grp->name);
+					return PTR_ERR(kn);
+				}
 			}
 		} else {
 			kn = kernfs_create_dir_ns(kobj->sd, grp->name,
@@ -150,11 +162,18 @@ static int internal_create_group(struct kobject *kobj, int update,
 
 	kernfs_get(kn);
 	error = create_files(kn, kobj, uid, gid, grp, update);
-	if (error) {
+	if (error <= 0) {
+		/*
+		 * If an error happened _OR_ if no files were created in the
+		 * attribute group, and we have a name for this group, delete
+		 * the name so there's not an empty directory.
+		 */
 		if (grp->name)
 			kernfs_remove(kn);
+	} else {
+		error = 0;
+		kernfs_put(kn);
 	}
-	kernfs_put(kn);
 
 	if (grp->name && update)
 		kernfs_put(kn);
@@ -318,13 +337,12 @@ void sysfs_remove_groups(struct kobject *kobj,
 EXPORT_SYMBOL_GPL(sysfs_remove_groups);
 
 /**
- * sysfs_merge_group - merge files into a pre-existing attribute group.
+ * sysfs_merge_group - merge files into a attribute group.
  * @kobj:	The kobject containing the group.
  * @grp:	The files to create and the attribute group they belong to.
  *
- * This function returns an error if the group doesn't exist or any of the
- * files already exist in that group, in which case none of the new files
- * are created.
+ * This function returns an error if any of the files already exist in
+ * that group, in which case none of the new files are created.
  */
 int sysfs_merge_group(struct kobject *kobj,
 		       const struct attribute_group *grp)
@@ -336,12 +354,22 @@ int sysfs_merge_group(struct kobject *kobj,
 	struct attribute *const *attr;
 	int i;
 
-	parent = kernfs_find_and_get(kobj->sd, grp->name);
-	if (!parent)
-		return -ENOENT;
-
 	kobject_get_ownership(kobj, &uid, &gid);
 
+	parent = kernfs_find_and_get(kobj->sd, grp->name);
+	if (!parent) {
+		parent = kernfs_create_dir_ns(kobj->sd, grp->name,
+					  S_IRWXU | S_IRUGO | S_IXUGO,
+					  uid, gid, kobj, NULL);
+		if (IS_ERR(parent)) {
+			if (PTR_ERR(parent) == -EEXIST)
+				sysfs_warn_dup(kobj->sd, grp->name);
+			return PTR_ERR(parent);
+		}
+
+		kernfs_get(parent);
+	}
+
 	for ((i = 0, attr = grp->attrs); *attr && !error; (++i, ++attr))
 		error = sysfs_add_file_mode_ns(parent, *attr, (*attr)->mode,
 					       uid, gid, NULL);
-- 
2.42.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 2/3] sysfs: Add a attr_is_visible function to attribute_group
  2023-10-05 13:05                 ` Greg KH
@ 2023-10-11  5:10                   ` Alistair Francis
  2023-10-11  6:44                     ` Greg KH
  0 siblings, 1 reply; 28+ messages in thread
From: Alistair Francis @ 2023-10-11  5:10 UTC (permalink / raw)
  To: Greg KH
  Cc: bhelgaas, linux-pci, Jonathan.Cameron, lukas, alex.williamson,
	christian.koenig, kch, logang, linux-kernel, chaitanyak, rdunlap,
	Alistair Francis

On Thu, Oct 5, 2023 at 11:05 PM Greg KH <gregkh@linuxfoundation.org> wrote:
>
> On Fri, Sep 01, 2023 at 11:00:59PM +0200, Greg KH wrote:
> > On Thu, Aug 31, 2023 at 04:36:13PM +0200, Greg KH wrote:
> > > On Thu, Aug 31, 2023 at 10:31:07AM +0200, Greg KH wrote:
> > > > On Mon, Aug 28, 2023 at 03:05:41PM +1000, Alistair Francis wrote:
> > > > > On Wed, Aug 23, 2023 at 5:02 PM Greg KH <gregkh@linuxfoundation.org> wrote:
> > > > > >
> > > > > > On Tue, Aug 22, 2023 at 04:20:06PM -0400, Alistair Francis wrote:
> > > > > > > On Sat, Aug 19, 2023 at 6:57 AM Greg KH <gregkh@linuxfoundation.org> wrote:
> > > > > > > >
> > > > > > > > On Thu, Aug 17, 2023 at 07:58:09PM -0400, Alistair Francis wrote:
> > > > > > > > > The documentation for sysfs_merge_group() specifically says
> > > > > > > > >
> > > > > > > > >     This function returns an error if the group doesn't exist or any of the
> > > > > > > > >     files already exist in that group, in which case none of the new files
> > > > > > > > >     are created.
> > > > > > > > >
> > > > > > > > > So just not adding the group if it's empty doesn't work, at least not
> > > > > > > > > with the code we currently have. The code can be changed to support
> > > > > > > > > this, but it is difficult to determine how this will affect existing use
> > > > > > > > > cases.
> > > > > > > >
> > > > > > > > Did you try?  I'd really really really prefer we do it this way as it's
> > > > > > > > much simpler overall to have the sysfs core "do the right thing
> > > > > > > > automatically" than to force each and every bus/subsystem to have to
> > > > > > > > manually add this type of attribute.
> > > > > > > >
> > > > > > > > Also, on a personal level, I want this function to work as it will allow
> > > > > > > > us to remove some code in some busses that don't really need to be there
> > > > > > > > (dynamic creation of some device attributes), which will then also allow
> > > > > > > > me to remove some apis in the driver core that should not be used at all
> > > > > > > > anymore (but keep creeping back in as there is still a few users.)
> > > > > > > >
> > > > > > > > So I'll be selfish here and say "please try to get my proposed change to
> > > > > > > > work, it's really the correct thing to do here."
> > > > > > >
> > > > > > > I did try!
> > > > > > >
> > > > > > > This is an attempt:
> > > > > > > https://github.com/alistair23/linux/commit/56b55756a2d7a66f7b6eb8a5692b1b5e2f81a9a9
> > > > > > >
> > > > > > > It is based on your original patch with a bunch of:
> > > > > > >
> > > > > > > if (!parent) {
> > > > > > >     parent = kernfs_create_dir_ns(kobj->sd, grp->name,
> > > > > > >                   S_IRWXU | S_IRUGO | S_IXUGO,
> > > > > > >                   uid, gid, kobj, NULL);
> > > > > > >     ...
> > > > > > >     }
> > > > > > >
> > > > > > >
> > > > > > > added throughout the code base.
> > > > > > >
> > > > > > > Very basic testing shows that it does what I need it to do and I don't
> > > > > > > see any kernel oops on boot.
> > > > > >
> > > > > > Nice!
> > > > > >
> > > > > > Mind if I take it and clean it up a bit and test with it here?  Again, I
> > > > > > need this functionality for other stuff as well, so getting it merged
> > > > > > for your feature is fine with me.
> > > > >
> > > > > Sure! Go ahead. Sorry I was travelling last week.
> > > > >
> > > > > >
> > > > > > > I prefer the approach I have in this mailing list patch. But if you
> > > > > > > like the commit mentioned above I can tidy and clean it up and then
> > > > > > > use that instead
> > > > > >
> > > > > > I would rather do it this way.  I can work on this on Friday if you want
> > > > > > me to.
> > > > >
> > > > > Yeah, that's fine with me. If you aren't able to let me know and I can
> > > > > finish up the patch and send it with this series
> > > >
> > > > Great, and for the email record, as github links are not stable, here's
> > > > the patch that you have above attached below.  I'll test this out and
> > > > clean it up a bit more and see how it goes...
> > > >
> > > > thanks,
> > > >
> > > > greg k-h
> > > >
> > > >
> > > > From 2929d17b58d02dcf52d0345fa966c616e09a5afa Mon Sep 17 00:00:00 2001
> > > > From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > > > Date: Wed, 24 Aug 2022 15:45:36 +0200
> > > > Subject: [PATCH] sysfs: do not create empty directories if no attributes are
> > > >  present
> > > >
> > > > When creating an attribute group, if it is named a subdirectory is
> > > > created and the sysfs files are placed into that subdirectory.  If no
> > > > files are created, normally the directory would still be present, but it
> > > > would be empty.  Clean this up by removing the directory if no files
> > > > were successfully created in the group at all.
> > > >
> > > > Co-developed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > > > Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > > > Co-developed-by: Alistair Francis <alistair.francis@wdc.com>
> > > > Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> > > > ---
> > > >  fs/sysfs/file.c  | 14 ++++++++++--
> > > >  fs/sysfs/group.c | 56 ++++++++++++++++++++++++++++++++++++------------
> > > >  2 files changed, 54 insertions(+), 16 deletions(-)
> > > >
> > > > diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
> > > > index a12ac0356c69..7aab6c09662c 100644
> > > > --- a/fs/sysfs/file.c
> > > > +++ b/fs/sysfs/file.c
> > > > @@ -391,8 +391,18 @@ int sysfs_add_file_to_group(struct kobject *kobj,
> > > >           kernfs_get(parent);
> > > >   }
> > > >
> > > > - if (!parent)
> > > > -         return -ENOENT;
> > > > + if (!parent) {
> > > > +         parent = kernfs_create_dir_ns(kobj->sd, group,
> > > > +                                   S_IRWXU | S_IRUGO | S_IXUGO,
> > > > +                                   uid, gid, kobj, NULL);
> > > > +         if (IS_ERR(parent)) {
> > > > +                 if (PTR_ERR(parent) == -EEXIST)
> > > > +                         sysfs_warn_dup(kobj->sd, group);
> > > > +                 return PTR_ERR(parent);
> > > > +         }
> > > > +
> > > > +         kernfs_get(parent);
> > > > + }
> > > >
> > > >   kobject_get_ownership(kobj, &uid, &gid);
> > > >   error = sysfs_add_file_mode_ns(parent, attr, attr->mode, uid, gid,
> > > > diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
> > > > index 138676463336..013fa333cd3c 100644
> > > > --- a/fs/sysfs/group.c
> > > > +++ b/fs/sysfs/group.c
> > > > @@ -31,12 +31,14 @@ static void remove_files(struct kernfs_node *parent,
> > > >                   kernfs_remove_by_name(parent, (*bin_attr)->attr.name);
> > > >  }
> > > >
> > > > +/* returns -ERROR if error, or >= 0 for number of files actually created */
> > > >  static int create_files(struct kernfs_node *parent, struct kobject *kobj,
> > > >                   kuid_t uid, kgid_t gid,
> > > >                   const struct attribute_group *grp, int update)
> > > >  {
> > > >   struct attribute *const *attr;
> > > >   struct bin_attribute *const *bin_attr;
> > > > + int files_created = 0;
> > > >   int error = 0, i;
> > > >
> > > >   if (grp->attrs) {
> > > > @@ -65,6 +67,8 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
> > > >                                                  gid, NULL);
> > > >                   if (unlikely(error))
> > > >                           break;
> > > > +
> > > > +                 files_created++;
> > > >           }
> > > >           if (error) {
> > > >                   remove_files(parent, grp);
> > > > @@ -95,12 +99,15 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
> > > >                                                      NULL);
> > > >                   if (error)
> > > >                           break;
> > > > +                 files_created++;
> > > >           }
> > > >           if (error)
> > > >                   remove_files(parent, grp);
> > > >   }
> > > >  exit:
> > > > - return error;
> > > > + if (error)
> > > > +         return error;
> > > > + return files_created;
> > > >  }
> > > >
> > > >
> > > > @@ -130,9 +137,14 @@ static int internal_create_group(struct kobject *kobj, int update,
> > > >           if (update) {
> > > >                   kn = kernfs_find_and_get(kobj->sd, grp->name);
> > > >                   if (!kn) {
> > > > -                         pr_warn("Can't update unknown attr grp name: %s/%s\n",
> > > > -                                 kobj->name, grp->name);
> > > > -                         return -EINVAL;
> > > > +                         kn = kernfs_create_dir_ns(kobj->sd, grp->name,
> > > > +                                                   S_IRWXU | S_IRUGO | S_IXUGO,
> > > > +                                                   uid, gid, kobj, NULL);
> > > > +                         if (IS_ERR(kn)) {
> > > > +                                 if (PTR_ERR(kn) == -EEXIST)
> > > > +                                         sysfs_warn_dup(kobj->sd, grp->name);
> > > > +                                 return PTR_ERR(kn);
> > > > +                         }
> > > >                   }
> > > >           } else {
> > > >                   kn = kernfs_create_dir_ns(kobj->sd, grp->name,
> > > > @@ -150,11 +162,18 @@ static int internal_create_group(struct kobject *kobj, int update,
> > > >
> > > >   kernfs_get(kn);
> > > >   error = create_files(kn, kobj, uid, gid, grp, update);
> > > > - if (error) {
> > > > + if (error <= 0) {
> > > > +         /*
> > > > +          * If an error happened _OR_ if no files were created in the
> > > > +          * attribute group, and we have a name for this group, delete
> > > > +          * the name so there's not an empty directory.
> > > > +          */
> > > >           if (grp->name)
> > > >                   kernfs_remove(kn);
> > > > + } else {
> > > > +         error = 0;
> > > > +         kernfs_put(kn);
> > > >   }
> > > > - kernfs_put(kn);
> > > >
> > > >   if (grp->name && update)
> > > >           kernfs_put(kn);
> > > > @@ -318,13 +337,12 @@ void sysfs_remove_groups(struct kobject *kobj,
> > > >  EXPORT_SYMBOL_GPL(sysfs_remove_groups);
> > > >
> > > >  /**
> > > > - * sysfs_merge_group - merge files into a pre-existing attribute group.
> > > > + * sysfs_merge_group - merge files into a attribute group.
> > > >   * @kobj:        The kobject containing the group.
> > > >   * @grp: The files to create and the attribute group they belong to.
> > > >   *
> > > > - * This function returns an error if the group doesn't exist or any of the
> > > > - * files already exist in that group, in which case none of the new files
> > > > - * are created.
> > > > + * This function returns an error if any of the files already exist in
> > > > + * that group, in which case none of the new files are created.
> > > >   */
> > > >  int sysfs_merge_group(struct kobject *kobj,
> > > >                  const struct attribute_group *grp)
> > > > @@ -336,12 +354,22 @@ int sysfs_merge_group(struct kobject *kobj,
> > > >   struct attribute *const *attr;
> > > >   int i;
> > > >
> > > > - parent = kernfs_find_and_get(kobj->sd, grp->name);
> > > > - if (!parent)
> > > > -         return -ENOENT;
> > > > -
> > > >   kobject_get_ownership(kobj, &uid, &gid);
> > > >
> > > > + parent = kernfs_find_and_get(kobj->sd, grp->name);
> > > > + if (!parent) {
> > > > +         parent = kernfs_create_dir_ns(kobj->sd, grp->name,
> > > > +                                   S_IRWXU | S_IRUGO | S_IXUGO,
> > > > +                                   uid, gid, kobj, NULL);
> > > > +         if (IS_ERR(parent)) {
> > > > +                 if (PTR_ERR(parent) == -EEXIST)
> > > > +                         sysfs_warn_dup(kobj->sd, grp->name);
> > > > +                 return PTR_ERR(parent);
> > > > +         }
> > > > +
> > > > +         kernfs_get(parent);
> > > > + }
> > > > +
> > > >   for ((i = 0, attr = grp->attrs); *attr && !error; (++i, ++attr))
> > > >           error = sysfs_add_file_mode_ns(parent, *attr, (*attr)->mode,
> > > >                                          uid, gid, NULL);
> > > > --
> > > > 2.42.0
> > > >
> > >
> > > And as the 0-day bot just showed, this patch isn't going to work
> > > properly, the uid/gid stuff isn't all hooked up properly, I'll work on
> > > fixing that up when I get some cycles...
> >
> > Oops, nope, that was my fault in applying this to my tree, sorry for the
> > noise...
>
> And I just got around to testing this, and it does not boot at all.
> Below is the patch I am using, are you sure you got this to boot for
> you?

I just checked again and it boots for me. What failure are you seeing?

Alistair

>
> thanks,
>
> greg k-h
>
> From db537de5a5af649b594604e2de177527f890878d Mon Sep 17 00:00:00 2001
> From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Date: Wed, 24 Aug 2022 15:45:36 +0200
> Subject: [PATCH] sysfs: do not create empty directories if no attributes are
>  present
>
> When creating an attribute group, if it is named a subdirectory is
> created and the sysfs files are placed into that subdirectory.  If no
> files are created, normally the directory would still be present, but it
> would be empty.  Clean this up by removing the directory if no files
> were successfully created in the group at all.
>
> Co-developed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Co-developed-by: Alistair Francis <alistair.francis@wdc.com>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  fs/sysfs/file.c  | 16 +++++++++++---
>  fs/sysfs/group.c | 56 ++++++++++++++++++++++++++++++++++++------------
>  2 files changed, 55 insertions(+), 17 deletions(-)
>
> diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
> index a12ac0356c69..9f79ec193ffe 100644
> --- a/fs/sysfs/file.c
> +++ b/fs/sysfs/file.c
> @@ -391,10 +391,20 @@ int sysfs_add_file_to_group(struct kobject *kobj,
>                 kernfs_get(parent);
>         }
>
> -       if (!parent)
> -               return -ENOENT;
> -
>         kobject_get_ownership(kobj, &uid, &gid);
> +       if (!parent) {
> +               parent = kernfs_create_dir_ns(kobj->sd, group,
> +                                         S_IRWXU | S_IRUGO | S_IXUGO,
> +                                         uid, gid, kobj, NULL);
> +               if (IS_ERR(parent)) {
> +                       if (PTR_ERR(parent) == -EEXIST)
> +                               sysfs_warn_dup(kobj->sd, group);
> +                       return PTR_ERR(parent);
> +               }
> +
> +               kernfs_get(parent);
> +       }
> +
>         error = sysfs_add_file_mode_ns(parent, attr, attr->mode, uid, gid,
>                                        NULL);
>         kernfs_put(parent);
> diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
> index 138676463336..013fa333cd3c 100644
> --- a/fs/sysfs/group.c
> +++ b/fs/sysfs/group.c
> @@ -31,12 +31,14 @@ static void remove_files(struct kernfs_node *parent,
>                         kernfs_remove_by_name(parent, (*bin_attr)->attr.name);
>  }
>
> +/* returns -ERROR if error, or >= 0 for number of files actually created */
>  static int create_files(struct kernfs_node *parent, struct kobject *kobj,
>                         kuid_t uid, kgid_t gid,
>                         const struct attribute_group *grp, int update)
>  {
>         struct attribute *const *attr;
>         struct bin_attribute *const *bin_attr;
> +       int files_created = 0;
>         int error = 0, i;
>
>         if (grp->attrs) {
> @@ -65,6 +67,8 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
>                                                        gid, NULL);
>                         if (unlikely(error))
>                                 break;
> +
> +                       files_created++;
>                 }
>                 if (error) {
>                         remove_files(parent, grp);
> @@ -95,12 +99,15 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
>                                                            NULL);
>                         if (error)
>                                 break;
> +                       files_created++;
>                 }
>                 if (error)
>                         remove_files(parent, grp);
>         }
>  exit:
> -       return error;
> +       if (error)
> +               return error;
> +       return files_created;
>  }
>
>
> @@ -130,9 +137,14 @@ static int internal_create_group(struct kobject *kobj, int update,
>                 if (update) {
>                         kn = kernfs_find_and_get(kobj->sd, grp->name);
>                         if (!kn) {
> -                               pr_warn("Can't update unknown attr grp name: %s/%s\n",
> -                                       kobj->name, grp->name);
> -                               return -EINVAL;
> +                               kn = kernfs_create_dir_ns(kobj->sd, grp->name,
> +                                                         S_IRWXU | S_IRUGO | S_IXUGO,
> +                                                         uid, gid, kobj, NULL);
> +                               if (IS_ERR(kn)) {
> +                                       if (PTR_ERR(kn) == -EEXIST)
> +                                               sysfs_warn_dup(kobj->sd, grp->name);
> +                                       return PTR_ERR(kn);
> +                               }
>                         }
>                 } else {
>                         kn = kernfs_create_dir_ns(kobj->sd, grp->name,
> @@ -150,11 +162,18 @@ static int internal_create_group(struct kobject *kobj, int update,
>
>         kernfs_get(kn);
>         error = create_files(kn, kobj, uid, gid, grp, update);
> -       if (error) {
> +       if (error <= 0) {
> +               /*
> +                * If an error happened _OR_ if no files were created in the
> +                * attribute group, and we have a name for this group, delete
> +                * the name so there's not an empty directory.
> +                */
>                 if (grp->name)
>                         kernfs_remove(kn);
> +       } else {
> +               error = 0;
> +               kernfs_put(kn);
>         }
> -       kernfs_put(kn);
>
>         if (grp->name && update)
>                 kernfs_put(kn);
> @@ -318,13 +337,12 @@ void sysfs_remove_groups(struct kobject *kobj,
>  EXPORT_SYMBOL_GPL(sysfs_remove_groups);
>
>  /**
> - * sysfs_merge_group - merge files into a pre-existing attribute group.
> + * sysfs_merge_group - merge files into a attribute group.
>   * @kobj:      The kobject containing the group.
>   * @grp:       The files to create and the attribute group they belong to.
>   *
> - * This function returns an error if the group doesn't exist or any of the
> - * files already exist in that group, in which case none of the new files
> - * are created.
> + * This function returns an error if any of the files already exist in
> + * that group, in which case none of the new files are created.
>   */
>  int sysfs_merge_group(struct kobject *kobj,
>                        const struct attribute_group *grp)
> @@ -336,12 +354,22 @@ int sysfs_merge_group(struct kobject *kobj,
>         struct attribute *const *attr;
>         int i;
>
> -       parent = kernfs_find_and_get(kobj->sd, grp->name);
> -       if (!parent)
> -               return -ENOENT;
> -
>         kobject_get_ownership(kobj, &uid, &gid);
>
> +       parent = kernfs_find_and_get(kobj->sd, grp->name);
> +       if (!parent) {
> +               parent = kernfs_create_dir_ns(kobj->sd, grp->name,
> +                                         S_IRWXU | S_IRUGO | S_IXUGO,
> +                                         uid, gid, kobj, NULL);
> +               if (IS_ERR(parent)) {
> +                       if (PTR_ERR(parent) == -EEXIST)
> +                               sysfs_warn_dup(kobj->sd, grp->name);
> +                       return PTR_ERR(parent);
> +               }
> +
> +               kernfs_get(parent);
> +       }
> +
>         for ((i = 0, attr = grp->attrs); *attr && !error; (++i, ++attr))
>                 error = sysfs_add_file_mode_ns(parent, *attr, (*attr)->mode,
>                                                uid, gid, NULL);
> --
> 2.42.0
>

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 2/3] sysfs: Add a attr_is_visible function to attribute_group
  2023-10-11  5:10                   ` Alistair Francis
@ 2023-10-11  6:44                     ` Greg KH
  2023-10-12  4:31                       ` Alistair Francis
  0 siblings, 1 reply; 28+ messages in thread
From: Greg KH @ 2023-10-11  6:44 UTC (permalink / raw)
  To: Alistair Francis
  Cc: bhelgaas, linux-pci, Jonathan.Cameron, lukas, alex.williamson,
	christian.koenig, kch, logang, linux-kernel, chaitanyak, rdunlap,
	Alistair Francis

On Wed, Oct 11, 2023 at 03:10:39PM +1000, Alistair Francis wrote:
> On Thu, Oct 5, 2023 at 11:05 PM Greg KH <gregkh@linuxfoundation.org> wrote:
> >
> > On Fri, Sep 01, 2023 at 11:00:59PM +0200, Greg KH wrote:
> > > On Thu, Aug 31, 2023 at 04:36:13PM +0200, Greg KH wrote:
> > > > On Thu, Aug 31, 2023 at 10:31:07AM +0200, Greg KH wrote:
> > > > > On Mon, Aug 28, 2023 at 03:05:41PM +1000, Alistair Francis wrote:
> > > > > > On Wed, Aug 23, 2023 at 5:02 PM Greg KH <gregkh@linuxfoundation.org> wrote:
> > > > > > >
> > > > > > > On Tue, Aug 22, 2023 at 04:20:06PM -0400, Alistair Francis wrote:
> > > > > > > > On Sat, Aug 19, 2023 at 6:57 AM Greg KH <gregkh@linuxfoundation.org> wrote:
> > > > > > > > >
> > > > > > > > > On Thu, Aug 17, 2023 at 07:58:09PM -0400, Alistair Francis wrote:
> > > > > > > > > > The documentation for sysfs_merge_group() specifically says
> > > > > > > > > >
> > > > > > > > > >     This function returns an error if the group doesn't exist or any of the
> > > > > > > > > >     files already exist in that group, in which case none of the new files
> > > > > > > > > >     are created.
> > > > > > > > > >
> > > > > > > > > > So just not adding the group if it's empty doesn't work, at least not
> > > > > > > > > > with the code we currently have. The code can be changed to support
> > > > > > > > > > this, but it is difficult to determine how this will affect existing use
> > > > > > > > > > cases.
> > > > > > > > >
> > > > > > > > > Did you try?  I'd really really really prefer we do it this way as it's
> > > > > > > > > much simpler overall to have the sysfs core "do the right thing
> > > > > > > > > automatically" than to force each and every bus/subsystem to have to
> > > > > > > > > manually add this type of attribute.
> > > > > > > > >
> > > > > > > > > Also, on a personal level, I want this function to work as it will allow
> > > > > > > > > us to remove some code in some busses that don't really need to be there
> > > > > > > > > (dynamic creation of some device attributes), which will then also allow
> > > > > > > > > me to remove some apis in the driver core that should not be used at all
> > > > > > > > > anymore (but keep creeping back in as there is still a few users.)
> > > > > > > > >
> > > > > > > > > So I'll be selfish here and say "please try to get my proposed change to
> > > > > > > > > work, it's really the correct thing to do here."
> > > > > > > >
> > > > > > > > I did try!
> > > > > > > >
> > > > > > > > This is an attempt:
> > > > > > > > https://github.com/alistair23/linux/commit/56b55756a2d7a66f7b6eb8a5692b1b5e2f81a9a9
> > > > > > > >
> > > > > > > > It is based on your original patch with a bunch of:
> > > > > > > >
> > > > > > > > if (!parent) {
> > > > > > > >     parent = kernfs_create_dir_ns(kobj->sd, grp->name,
> > > > > > > >                   S_IRWXU | S_IRUGO | S_IXUGO,
> > > > > > > >                   uid, gid, kobj, NULL);
> > > > > > > >     ...
> > > > > > > >     }
> > > > > > > >
> > > > > > > >
> > > > > > > > added throughout the code base.
> > > > > > > >
> > > > > > > > Very basic testing shows that it does what I need it to do and I don't
> > > > > > > > see any kernel oops on boot.
> > > > > > >
> > > > > > > Nice!
> > > > > > >
> > > > > > > Mind if I take it and clean it up a bit and test with it here?  Again, I
> > > > > > > need this functionality for other stuff as well, so getting it merged
> > > > > > > for your feature is fine with me.
> > > > > >
> > > > > > Sure! Go ahead. Sorry I was travelling last week.
> > > > > >
> > > > > > >
> > > > > > > > I prefer the approach I have in this mailing list patch. But if you
> > > > > > > > like the commit mentioned above I can tidy and clean it up and then
> > > > > > > > use that instead
> > > > > > >
> > > > > > > I would rather do it this way.  I can work on this on Friday if you want
> > > > > > > me to.
> > > > > >
> > > > > > Yeah, that's fine with me. If you aren't able to let me know and I can
> > > > > > finish up the patch and send it with this series
> > > > >
> > > > > Great, and for the email record, as github links are not stable, here's
> > > > > the patch that you have above attached below.  I'll test this out and
> > > > > clean it up a bit more and see how it goes...
> > > > >
> > > > > thanks,
> > > > >
> > > > > greg k-h
> > > > >
> > > > >
> > > > > From 2929d17b58d02dcf52d0345fa966c616e09a5afa Mon Sep 17 00:00:00 2001
> > > > > From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > > > > Date: Wed, 24 Aug 2022 15:45:36 +0200
> > > > > Subject: [PATCH] sysfs: do not create empty directories if no attributes are
> > > > >  present
> > > > >
> > > > > When creating an attribute group, if it is named a subdirectory is
> > > > > created and the sysfs files are placed into that subdirectory.  If no
> > > > > files are created, normally the directory would still be present, but it
> > > > > would be empty.  Clean this up by removing the directory if no files
> > > > > were successfully created in the group at all.
> > > > >
> > > > > Co-developed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > > > > Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > > > > Co-developed-by: Alistair Francis <alistair.francis@wdc.com>
> > > > > Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> > > > > ---
> > > > >  fs/sysfs/file.c  | 14 ++++++++++--
> > > > >  fs/sysfs/group.c | 56 ++++++++++++++++++++++++++++++++++++------------
> > > > >  2 files changed, 54 insertions(+), 16 deletions(-)
> > > > >
> > > > > diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
> > > > > index a12ac0356c69..7aab6c09662c 100644
> > > > > --- a/fs/sysfs/file.c
> > > > > +++ b/fs/sysfs/file.c
> > > > > @@ -391,8 +391,18 @@ int sysfs_add_file_to_group(struct kobject *kobj,
> > > > >           kernfs_get(parent);
> > > > >   }
> > > > >
> > > > > - if (!parent)
> > > > > -         return -ENOENT;
> > > > > + if (!parent) {
> > > > > +         parent = kernfs_create_dir_ns(kobj->sd, group,
> > > > > +                                   S_IRWXU | S_IRUGO | S_IXUGO,
> > > > > +                                   uid, gid, kobj, NULL);
> > > > > +         if (IS_ERR(parent)) {
> > > > > +                 if (PTR_ERR(parent) == -EEXIST)
> > > > > +                         sysfs_warn_dup(kobj->sd, group);
> > > > > +                 return PTR_ERR(parent);
> > > > > +         }
> > > > > +
> > > > > +         kernfs_get(parent);
> > > > > + }
> > > > >
> > > > >   kobject_get_ownership(kobj, &uid, &gid);
> > > > >   error = sysfs_add_file_mode_ns(parent, attr, attr->mode, uid, gid,
> > > > > diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
> > > > > index 138676463336..013fa333cd3c 100644
> > > > > --- a/fs/sysfs/group.c
> > > > > +++ b/fs/sysfs/group.c
> > > > > @@ -31,12 +31,14 @@ static void remove_files(struct kernfs_node *parent,
> > > > >                   kernfs_remove_by_name(parent, (*bin_attr)->attr.name);
> > > > >  }
> > > > >
> > > > > +/* returns -ERROR if error, or >= 0 for number of files actually created */
> > > > >  static int create_files(struct kernfs_node *parent, struct kobject *kobj,
> > > > >                   kuid_t uid, kgid_t gid,
> > > > >                   const struct attribute_group *grp, int update)
> > > > >  {
> > > > >   struct attribute *const *attr;
> > > > >   struct bin_attribute *const *bin_attr;
> > > > > + int files_created = 0;
> > > > >   int error = 0, i;
> > > > >
> > > > >   if (grp->attrs) {
> > > > > @@ -65,6 +67,8 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
> > > > >                                                  gid, NULL);
> > > > >                   if (unlikely(error))
> > > > >                           break;
> > > > > +
> > > > > +                 files_created++;
> > > > >           }
> > > > >           if (error) {
> > > > >                   remove_files(parent, grp);
> > > > > @@ -95,12 +99,15 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
> > > > >                                                      NULL);
> > > > >                   if (error)
> > > > >                           break;
> > > > > +                 files_created++;
> > > > >           }
> > > > >           if (error)
> > > > >                   remove_files(parent, grp);
> > > > >   }
> > > > >  exit:
> > > > > - return error;
> > > > > + if (error)
> > > > > +         return error;
> > > > > + return files_created;
> > > > >  }
> > > > >
> > > > >
> > > > > @@ -130,9 +137,14 @@ static int internal_create_group(struct kobject *kobj, int update,
> > > > >           if (update) {
> > > > >                   kn = kernfs_find_and_get(kobj->sd, grp->name);
> > > > >                   if (!kn) {
> > > > > -                         pr_warn("Can't update unknown attr grp name: %s/%s\n",
> > > > > -                                 kobj->name, grp->name);
> > > > > -                         return -EINVAL;
> > > > > +                         kn = kernfs_create_dir_ns(kobj->sd, grp->name,
> > > > > +                                                   S_IRWXU | S_IRUGO | S_IXUGO,
> > > > > +                                                   uid, gid, kobj, NULL);
> > > > > +                         if (IS_ERR(kn)) {
> > > > > +                                 if (PTR_ERR(kn) == -EEXIST)
> > > > > +                                         sysfs_warn_dup(kobj->sd, grp->name);
> > > > > +                                 return PTR_ERR(kn);
> > > > > +                         }
> > > > >                   }
> > > > >           } else {
> > > > >                   kn = kernfs_create_dir_ns(kobj->sd, grp->name,
> > > > > @@ -150,11 +162,18 @@ static int internal_create_group(struct kobject *kobj, int update,
> > > > >
> > > > >   kernfs_get(kn);
> > > > >   error = create_files(kn, kobj, uid, gid, grp, update);
> > > > > - if (error) {
> > > > > + if (error <= 0) {
> > > > > +         /*
> > > > > +          * If an error happened _OR_ if no files were created in the
> > > > > +          * attribute group, and we have a name for this group, delete
> > > > > +          * the name so there's not an empty directory.
> > > > > +          */
> > > > >           if (grp->name)
> > > > >                   kernfs_remove(kn);
> > > > > + } else {
> > > > > +         error = 0;
> > > > > +         kernfs_put(kn);
> > > > >   }
> > > > > - kernfs_put(kn);
> > > > >
> > > > >   if (grp->name && update)
> > > > >           kernfs_put(kn);
> > > > > @@ -318,13 +337,12 @@ void sysfs_remove_groups(struct kobject *kobj,
> > > > >  EXPORT_SYMBOL_GPL(sysfs_remove_groups);
> > > > >
> > > > >  /**
> > > > > - * sysfs_merge_group - merge files into a pre-existing attribute group.
> > > > > + * sysfs_merge_group - merge files into a attribute group.
> > > > >   * @kobj:        The kobject containing the group.
> > > > >   * @grp: The files to create and the attribute group they belong to.
> > > > >   *
> > > > > - * This function returns an error if the group doesn't exist or any of the
> > > > > - * files already exist in that group, in which case none of the new files
> > > > > - * are created.
> > > > > + * This function returns an error if any of the files already exist in
> > > > > + * that group, in which case none of the new files are created.
> > > > >   */
> > > > >  int sysfs_merge_group(struct kobject *kobj,
> > > > >                  const struct attribute_group *grp)
> > > > > @@ -336,12 +354,22 @@ int sysfs_merge_group(struct kobject *kobj,
> > > > >   struct attribute *const *attr;
> > > > >   int i;
> > > > >
> > > > > - parent = kernfs_find_and_get(kobj->sd, grp->name);
> > > > > - if (!parent)
> > > > > -         return -ENOENT;
> > > > > -
> > > > >   kobject_get_ownership(kobj, &uid, &gid);
> > > > >
> > > > > + parent = kernfs_find_and_get(kobj->sd, grp->name);
> > > > > + if (!parent) {
> > > > > +         parent = kernfs_create_dir_ns(kobj->sd, grp->name,
> > > > > +                                   S_IRWXU | S_IRUGO | S_IXUGO,
> > > > > +                                   uid, gid, kobj, NULL);
> > > > > +         if (IS_ERR(parent)) {
> > > > > +                 if (PTR_ERR(parent) == -EEXIST)
> > > > > +                         sysfs_warn_dup(kobj->sd, grp->name);
> > > > > +                 return PTR_ERR(parent);
> > > > > +         }
> > > > > +
> > > > > +         kernfs_get(parent);
> > > > > + }
> > > > > +
> > > > >   for ((i = 0, attr = grp->attrs); *attr && !error; (++i, ++attr))
> > > > >           error = sysfs_add_file_mode_ns(parent, *attr, (*attr)->mode,
> > > > >                                          uid, gid, NULL);
> > > > > --
> > > > > 2.42.0
> > > > >
> > > >
> > > > And as the 0-day bot just showed, this patch isn't going to work
> > > > properly, the uid/gid stuff isn't all hooked up properly, I'll work on
> > > > fixing that up when I get some cycles...
> > >
> > > Oops, nope, that was my fault in applying this to my tree, sorry for the
> > > noise...
> >
> > And I just got around to testing this, and it does not boot at all.
> > Below is the patch I am using, are you sure you got this to boot for
> > you?
> 
> I just checked again and it boots for me. What failure are you seeing?

Block devices were not created properly in sysfs.

Did you test your patch, or my modified one that I attached on this
email?  That might be the difference.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 2/3] sysfs: Add a attr_is_visible function to attribute_group
  2023-10-11  6:44                     ` Greg KH
@ 2023-10-12  4:31                       ` Alistair Francis
  2024-01-23  4:04                         ` Alistair Francis
  0 siblings, 1 reply; 28+ messages in thread
From: Alistair Francis @ 2023-10-12  4:31 UTC (permalink / raw)
  To: Greg KH
  Cc: bhelgaas, linux-pci, Jonathan.Cameron, lukas, alex.williamson,
	christian.koenig, kch, logang, linux-kernel, chaitanyak, rdunlap,
	Alistair Francis

On Wed, Oct 11, 2023 at 4:44 PM Greg KH <gregkh@linuxfoundation.org> wrote:
>
> On Wed, Oct 11, 2023 at 03:10:39PM +1000, Alistair Francis wrote:
> > On Thu, Oct 5, 2023 at 11:05 PM Greg KH <gregkh@linuxfoundation.org> wrote:
> > >
> > > On Fri, Sep 01, 2023 at 11:00:59PM +0200, Greg KH wrote:
> > > > On Thu, Aug 31, 2023 at 04:36:13PM +0200, Greg KH wrote:
> > > > > On Thu, Aug 31, 2023 at 10:31:07AM +0200, Greg KH wrote:
> > > > > > On Mon, Aug 28, 2023 at 03:05:41PM +1000, Alistair Francis wrote:
> > > > > > > On Wed, Aug 23, 2023 at 5:02 PM Greg KH <gregkh@linuxfoundation.org> wrote:
> > > > > > > >
> > > > > > > > On Tue, Aug 22, 2023 at 04:20:06PM -0400, Alistair Francis wrote:
> > > > > > > > > On Sat, Aug 19, 2023 at 6:57 AM Greg KH <gregkh@linuxfoundation.org> wrote:
> > > > > > > > > >
> > > > > > > > > > On Thu, Aug 17, 2023 at 07:58:09PM -0400, Alistair Francis wrote:
> > > > > > > > > > > The documentation for sysfs_merge_group() specifically says
> > > > > > > > > > >
> > > > > > > > > > >     This function returns an error if the group doesn't exist or any of the
> > > > > > > > > > >     files already exist in that group, in which case none of the new files
> > > > > > > > > > >     are created.
> > > > > > > > > > >
> > > > > > > > > > > So just not adding the group if it's empty doesn't work, at least not
> > > > > > > > > > > with the code we currently have. The code can be changed to support
> > > > > > > > > > > this, but it is difficult to determine how this will affect existing use
> > > > > > > > > > > cases.
> > > > > > > > > >
> > > > > > > > > > Did you try?  I'd really really really prefer we do it this way as it's
> > > > > > > > > > much simpler overall to have the sysfs core "do the right thing
> > > > > > > > > > automatically" than to force each and every bus/subsystem to have to
> > > > > > > > > > manually add this type of attribute.
> > > > > > > > > >
> > > > > > > > > > Also, on a personal level, I want this function to work as it will allow
> > > > > > > > > > us to remove some code in some busses that don't really need to be there
> > > > > > > > > > (dynamic creation of some device attributes), which will then also allow
> > > > > > > > > > me to remove some apis in the driver core that should not be used at all
> > > > > > > > > > anymore (but keep creeping back in as there is still a few users.)
> > > > > > > > > >
> > > > > > > > > > So I'll be selfish here and say "please try to get my proposed change to
> > > > > > > > > > work, it's really the correct thing to do here."
> > > > > > > > >
> > > > > > > > > I did try!
> > > > > > > > >
> > > > > > > > > This is an attempt:
> > > > > > > > > https://github.com/alistair23/linux/commit/56b55756a2d7a66f7b6eb8a5692b1b5e2f81a9a9
> > > > > > > > >
> > > > > > > > > It is based on your original patch with a bunch of:
> > > > > > > > >
> > > > > > > > > if (!parent) {
> > > > > > > > >     parent = kernfs_create_dir_ns(kobj->sd, grp->name,
> > > > > > > > >                   S_IRWXU | S_IRUGO | S_IXUGO,
> > > > > > > > >                   uid, gid, kobj, NULL);
> > > > > > > > >     ...
> > > > > > > > >     }
> > > > > > > > >
> > > > > > > > >
> > > > > > > > > added throughout the code base.
> > > > > > > > >
> > > > > > > > > Very basic testing shows that it does what I need it to do and I don't
> > > > > > > > > see any kernel oops on boot.
> > > > > > > >
> > > > > > > > Nice!
> > > > > > > >
> > > > > > > > Mind if I take it and clean it up a bit and test with it here?  Again, I
> > > > > > > > need this functionality for other stuff as well, so getting it merged
> > > > > > > > for your feature is fine with me.
> > > > > > >
> > > > > > > Sure! Go ahead. Sorry I was travelling last week.
> > > > > > >
> > > > > > > >
> > > > > > > > > I prefer the approach I have in this mailing list patch. But if you
> > > > > > > > > like the commit mentioned above I can tidy and clean it up and then
> > > > > > > > > use that instead
> > > > > > > >
> > > > > > > > I would rather do it this way.  I can work on this on Friday if you want
> > > > > > > > me to.
> > > > > > >
> > > > > > > Yeah, that's fine with me. If you aren't able to let me know and I can
> > > > > > > finish up the patch and send it with this series
> > > > > >
> > > > > > Great, and for the email record, as github links are not stable, here's
> > > > > > the patch that you have above attached below.  I'll test this out and
> > > > > > clean it up a bit more and see how it goes...
> > > > > >
> > > > > > thanks,
> > > > > >
> > > > > > greg k-h
> > > > > >
> > > > > >
> > > > > > From 2929d17b58d02dcf52d0345fa966c616e09a5afa Mon Sep 17 00:00:00 2001
> > > > > > From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > > > > > Date: Wed, 24 Aug 2022 15:45:36 +0200
> > > > > > Subject: [PATCH] sysfs: do not create empty directories if no attributes are
> > > > > >  present
> > > > > >
> > > > > > When creating an attribute group, if it is named a subdirectory is
> > > > > > created and the sysfs files are placed into that subdirectory.  If no
> > > > > > files are created, normally the directory would still be present, but it
> > > > > > would be empty.  Clean this up by removing the directory if no files
> > > > > > were successfully created in the group at all.
> > > > > >
> > > > > > Co-developed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > > > > > Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > > > > > Co-developed-by: Alistair Francis <alistair.francis@wdc.com>
> > > > > > Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> > > > > > ---
> > > > > >  fs/sysfs/file.c  | 14 ++++++++++--
> > > > > >  fs/sysfs/group.c | 56 ++++++++++++++++++++++++++++++++++++------------
> > > > > >  2 files changed, 54 insertions(+), 16 deletions(-)
> > > > > >
> > > > > > diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
> > > > > > index a12ac0356c69..7aab6c09662c 100644
> > > > > > --- a/fs/sysfs/file.c
> > > > > > +++ b/fs/sysfs/file.c
> > > > > > @@ -391,8 +391,18 @@ int sysfs_add_file_to_group(struct kobject *kobj,
> > > > > >           kernfs_get(parent);
> > > > > >   }
> > > > > >
> > > > > > - if (!parent)
> > > > > > -         return -ENOENT;
> > > > > > + if (!parent) {
> > > > > > +         parent = kernfs_create_dir_ns(kobj->sd, group,
> > > > > > +                                   S_IRWXU | S_IRUGO | S_IXUGO,
> > > > > > +                                   uid, gid, kobj, NULL);
> > > > > > +         if (IS_ERR(parent)) {
> > > > > > +                 if (PTR_ERR(parent) == -EEXIST)
> > > > > > +                         sysfs_warn_dup(kobj->sd, group);
> > > > > > +                 return PTR_ERR(parent);
> > > > > > +         }
> > > > > > +
> > > > > > +         kernfs_get(parent);
> > > > > > + }
> > > > > >
> > > > > >   kobject_get_ownership(kobj, &uid, &gid);
> > > > > >   error = sysfs_add_file_mode_ns(parent, attr, attr->mode, uid, gid,
> > > > > > diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
> > > > > > index 138676463336..013fa333cd3c 100644
> > > > > > --- a/fs/sysfs/group.c
> > > > > > +++ b/fs/sysfs/group.c
> > > > > > @@ -31,12 +31,14 @@ static void remove_files(struct kernfs_node *parent,
> > > > > >                   kernfs_remove_by_name(parent, (*bin_attr)->attr.name);
> > > > > >  }
> > > > > >
> > > > > > +/* returns -ERROR if error, or >= 0 for number of files actually created */
> > > > > >  static int create_files(struct kernfs_node *parent, struct kobject *kobj,
> > > > > >                   kuid_t uid, kgid_t gid,
> > > > > >                   const struct attribute_group *grp, int update)
> > > > > >  {
> > > > > >   struct attribute *const *attr;
> > > > > >   struct bin_attribute *const *bin_attr;
> > > > > > + int files_created = 0;
> > > > > >   int error = 0, i;
> > > > > >
> > > > > >   if (grp->attrs) {
> > > > > > @@ -65,6 +67,8 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
> > > > > >                                                  gid, NULL);
> > > > > >                   if (unlikely(error))
> > > > > >                           break;
> > > > > > +
> > > > > > +                 files_created++;
> > > > > >           }
> > > > > >           if (error) {
> > > > > >                   remove_files(parent, grp);
> > > > > > @@ -95,12 +99,15 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
> > > > > >                                                      NULL);
> > > > > >                   if (error)
> > > > > >                           break;
> > > > > > +                 files_created++;
> > > > > >           }
> > > > > >           if (error)
> > > > > >                   remove_files(parent, grp);
> > > > > >   }
> > > > > >  exit:
> > > > > > - return error;
> > > > > > + if (error)
> > > > > > +         return error;
> > > > > > + return files_created;
> > > > > >  }
> > > > > >
> > > > > >
> > > > > > @@ -130,9 +137,14 @@ static int internal_create_group(struct kobject *kobj, int update,
> > > > > >           if (update) {
> > > > > >                   kn = kernfs_find_and_get(kobj->sd, grp->name);
> > > > > >                   if (!kn) {
> > > > > > -                         pr_warn("Can't update unknown attr grp name: %s/%s\n",
> > > > > > -                                 kobj->name, grp->name);
> > > > > > -                         return -EINVAL;
> > > > > > +                         kn = kernfs_create_dir_ns(kobj->sd, grp->name,
> > > > > > +                                                   S_IRWXU | S_IRUGO | S_IXUGO,
> > > > > > +                                                   uid, gid, kobj, NULL);
> > > > > > +                         if (IS_ERR(kn)) {
> > > > > > +                                 if (PTR_ERR(kn) == -EEXIST)
> > > > > > +                                         sysfs_warn_dup(kobj->sd, grp->name);
> > > > > > +                                 return PTR_ERR(kn);
> > > > > > +                         }
> > > > > >                   }
> > > > > >           } else {
> > > > > >                   kn = kernfs_create_dir_ns(kobj->sd, grp->name,
> > > > > > @@ -150,11 +162,18 @@ static int internal_create_group(struct kobject *kobj, int update,
> > > > > >
> > > > > >   kernfs_get(kn);
> > > > > >   error = create_files(kn, kobj, uid, gid, grp, update);
> > > > > > - if (error) {
> > > > > > + if (error <= 0) {
> > > > > > +         /*
> > > > > > +          * If an error happened _OR_ if no files were created in the
> > > > > > +          * attribute group, and we have a name for this group, delete
> > > > > > +          * the name so there's not an empty directory.
> > > > > > +          */
> > > > > >           if (grp->name)
> > > > > >                   kernfs_remove(kn);
> > > > > > + } else {
> > > > > > +         error = 0;
> > > > > > +         kernfs_put(kn);
> > > > > >   }
> > > > > > - kernfs_put(kn);
> > > > > >
> > > > > >   if (grp->name && update)
> > > > > >           kernfs_put(kn);
> > > > > > @@ -318,13 +337,12 @@ void sysfs_remove_groups(struct kobject *kobj,
> > > > > >  EXPORT_SYMBOL_GPL(sysfs_remove_groups);
> > > > > >
> > > > > >  /**
> > > > > > - * sysfs_merge_group - merge files into a pre-existing attribute group.
> > > > > > + * sysfs_merge_group - merge files into a attribute group.
> > > > > >   * @kobj:        The kobject containing the group.
> > > > > >   * @grp: The files to create and the attribute group they belong to.
> > > > > >   *
> > > > > > - * This function returns an error if the group doesn't exist or any of the
> > > > > > - * files already exist in that group, in which case none of the new files
> > > > > > - * are created.
> > > > > > + * This function returns an error if any of the files already exist in
> > > > > > + * that group, in which case none of the new files are created.
> > > > > >   */
> > > > > >  int sysfs_merge_group(struct kobject *kobj,
> > > > > >                  const struct attribute_group *grp)
> > > > > > @@ -336,12 +354,22 @@ int sysfs_merge_group(struct kobject *kobj,
> > > > > >   struct attribute *const *attr;
> > > > > >   int i;
> > > > > >
> > > > > > - parent = kernfs_find_and_get(kobj->sd, grp->name);
> > > > > > - if (!parent)
> > > > > > -         return -ENOENT;
> > > > > > -
> > > > > >   kobject_get_ownership(kobj, &uid, &gid);
> > > > > >
> > > > > > + parent = kernfs_find_and_get(kobj->sd, grp->name);
> > > > > > + if (!parent) {
> > > > > > +         parent = kernfs_create_dir_ns(kobj->sd, grp->name,
> > > > > > +                                   S_IRWXU | S_IRUGO | S_IXUGO,
> > > > > > +                                   uid, gid, kobj, NULL);
> > > > > > +         if (IS_ERR(parent)) {
> > > > > > +                 if (PTR_ERR(parent) == -EEXIST)
> > > > > > +                         sysfs_warn_dup(kobj->sd, grp->name);
> > > > > > +                 return PTR_ERR(parent);
> > > > > > +         }
> > > > > > +
> > > > > > +         kernfs_get(parent);
> > > > > > + }
> > > > > > +
> > > > > >   for ((i = 0, attr = grp->attrs); *attr && !error; (++i, ++attr))
> > > > > >           error = sysfs_add_file_mode_ns(parent, *attr, (*attr)->mode,
> > > > > >                                          uid, gid, NULL);
> > > > > > --
> > > > > > 2.42.0
> > > > > >
> > > > >
> > > > > And as the 0-day bot just showed, this patch isn't going to work
> > > > > properly, the uid/gid stuff isn't all hooked up properly, I'll work on
> > > > > fixing that up when I get some cycles...
> > > >
> > > > Oops, nope, that was my fault in applying this to my tree, sorry for the
> > > > noise...
> > >
> > > And I just got around to testing this, and it does not boot at all.
> > > Below is the patch I am using, are you sure you got this to boot for
> > > you?
> >
> > I just checked again and it boots for me. What failure are you seeing?
>
> Block devices were not created properly in sysfs.

Strange. I have tested this on a QEMU virtual machine and a x86 PC and
I don't see any issues on either.

>
> Did you test your patch, or my modified one that I attached on this
> email?  That might be the difference.

I'm using your modified one.

Are you able to provide logs? There must be some driver that is
causing the issue. I can try to reproduce it if I know where it's
failing.

Alistair

>
> thanks,
>
> greg k-h

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 2/3] sysfs: Add a attr_is_visible function to attribute_group
  2023-10-12  4:31                       ` Alistair Francis
@ 2024-01-23  4:04                         ` Alistair Francis
  2024-01-23 12:25                           ` Greg KH
  0 siblings, 1 reply; 28+ messages in thread
From: Alistair Francis @ 2024-01-23  4:04 UTC (permalink / raw)
  To: Greg KH
  Cc: bhelgaas, linux-pci, Jonathan.Cameron, lukas, alex.williamson,
	christian.koenig, kch, logang, linux-kernel, chaitanyak, rdunlap,
	Alistair Francis

On Thu, Oct 12, 2023 at 2:31 PM Alistair Francis <alistair23@gmail.com> wrote:
>
> On Wed, Oct 11, 2023 at 4:44 PM Greg KH <gregkh@linuxfoundation.org> wrote:
> >
> > On Wed, Oct 11, 2023 at 03:10:39PM +1000, Alistair Francis wrote:
> > > On Thu, Oct 5, 2023 at 11:05 PM Greg KH <gregkh@linuxfoundation.org> wrote:
> > > >
> > > > On Fri, Sep 01, 2023 at 11:00:59PM +0200, Greg KH wrote:
> > > > > On Thu, Aug 31, 2023 at 04:36:13PM +0200, Greg KH wrote:
> > > > > > On Thu, Aug 31, 2023 at 10:31:07AM +0200, Greg KH wrote:
> > > > > > > On Mon, Aug 28, 2023 at 03:05:41PM +1000, Alistair Francis wrote:
> > > > > > > > On Wed, Aug 23, 2023 at 5:02 PM Greg KH <gregkh@linuxfoundation.org> wrote:
> > > > > > > > >
> > > > > > > > > On Tue, Aug 22, 2023 at 04:20:06PM -0400, Alistair Francis wrote:
> > > > > > > > > > On Sat, Aug 19, 2023 at 6:57 AM Greg KH <gregkh@linuxfoundation.org> wrote:
> > > > > > > > > > >
> > > > > > > > > > > On Thu, Aug 17, 2023 at 07:58:09PM -0400, Alistair Francis wrote:
> > > > > > > > > > > > The documentation for sysfs_merge_group() specifically says
> > > > > > > > > > > >
> > > > > > > > > > > >     This function returns an error if the group doesn't exist or any of the
> > > > > > > > > > > >     files already exist in that group, in which case none of the new files
> > > > > > > > > > > >     are created.
> > > > > > > > > > > >
> > > > > > > > > > > > So just not adding the group if it's empty doesn't work, at least not
> > > > > > > > > > > > with the code we currently have. The code can be changed to support
> > > > > > > > > > > > this, but it is difficult to determine how this will affect existing use
> > > > > > > > > > > > cases.
> > > > > > > > > > >
> > > > > > > > > > > Did you try?  I'd really really really prefer we do it this way as it's
> > > > > > > > > > > much simpler overall to have the sysfs core "do the right thing
> > > > > > > > > > > automatically" than to force each and every bus/subsystem to have to
> > > > > > > > > > > manually add this type of attribute.
> > > > > > > > > > >
> > > > > > > > > > > Also, on a personal level, I want this function to work as it will allow
> > > > > > > > > > > us to remove some code in some busses that don't really need to be there
> > > > > > > > > > > (dynamic creation of some device attributes), which will then also allow
> > > > > > > > > > > me to remove some apis in the driver core that should not be used at all
> > > > > > > > > > > anymore (but keep creeping back in as there is still a few users.)
> > > > > > > > > > >
> > > > > > > > > > > So I'll be selfish here and say "please try to get my proposed change to
> > > > > > > > > > > work, it's really the correct thing to do here."
> > > > > > > > > >
> > > > > > > > > > I did try!
> > > > > > > > > >
> > > > > > > > > > This is an attempt:
> > > > > > > > > > https://github.com/alistair23/linux/commit/56b55756a2d7a66f7b6eb8a5692b1b5e2f81a9a9
> > > > > > > > > >
> > > > > > > > > > It is based on your original patch with a bunch of:
> > > > > > > > > >
> > > > > > > > > > if (!parent) {
> > > > > > > > > >     parent = kernfs_create_dir_ns(kobj->sd, grp->name,
> > > > > > > > > >                   S_IRWXU | S_IRUGO | S_IXUGO,
> > > > > > > > > >                   uid, gid, kobj, NULL);
> > > > > > > > > >     ...
> > > > > > > > > >     }
> > > > > > > > > >
> > > > > > > > > >
> > > > > > > > > > added throughout the code base.
> > > > > > > > > >
> > > > > > > > > > Very basic testing shows that it does what I need it to do and I don't
> > > > > > > > > > see any kernel oops on boot.
> > > > > > > > >
> > > > > > > > > Nice!
> > > > > > > > >
> > > > > > > > > Mind if I take it and clean it up a bit and test with it here?  Again, I
> > > > > > > > > need this functionality for other stuff as well, so getting it merged
> > > > > > > > > for your feature is fine with me.
> > > > > > > >
> > > > > > > > Sure! Go ahead. Sorry I was travelling last week.
> > > > > > > >
> > > > > > > > >
> > > > > > > > > > I prefer the approach I have in this mailing list patch. But if you
> > > > > > > > > > like the commit mentioned above I can tidy and clean it up and then
> > > > > > > > > > use that instead
> > > > > > > > >
> > > > > > > > > I would rather do it this way.  I can work on this on Friday if you want
> > > > > > > > > me to.
> > > > > > > >
> > > > > > > > Yeah, that's fine with me. If you aren't able to let me know and I can
> > > > > > > > finish up the patch and send it with this series
> > > > > > >
> > > > > > > Great, and for the email record, as github links are not stable, here's
> > > > > > > the patch that you have above attached below.  I'll test this out and
> > > > > > > clean it up a bit more and see how it goes...
> > > > > > >
> > > > > > > thanks,
> > > > > > >
> > > > > > > greg k-h
> > > > > > >
> > > > > > >
> > > > > > > From 2929d17b58d02dcf52d0345fa966c616e09a5afa Mon Sep 17 00:00:00 2001
> > > > > > > From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > > > > > > Date: Wed, 24 Aug 2022 15:45:36 +0200
> > > > > > > Subject: [PATCH] sysfs: do not create empty directories if no attributes are
> > > > > > >  present
> > > > > > >
> > > > > > > When creating an attribute group, if it is named a subdirectory is
> > > > > > > created and the sysfs files are placed into that subdirectory.  If no
> > > > > > > files are created, normally the directory would still be present, but it
> > > > > > > would be empty.  Clean this up by removing the directory if no files
> > > > > > > were successfully created in the group at all.
> > > > > > >
> > > > > > > Co-developed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > > > > > > Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > > > > > > Co-developed-by: Alistair Francis <alistair.francis@wdc.com>
> > > > > > > Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> > > > > > > ---
> > > > > > >  fs/sysfs/file.c  | 14 ++++++++++--
> > > > > > >  fs/sysfs/group.c | 56 ++++++++++++++++++++++++++++++++++++------------
> > > > > > >  2 files changed, 54 insertions(+), 16 deletions(-)
> > > > > > >
> > > > > > > diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
> > > > > > > index a12ac0356c69..7aab6c09662c 100644
> > > > > > > --- a/fs/sysfs/file.c
> > > > > > > +++ b/fs/sysfs/file.c
> > > > > > > @@ -391,8 +391,18 @@ int sysfs_add_file_to_group(struct kobject *kobj,
> > > > > > >           kernfs_get(parent);
> > > > > > >   }
> > > > > > >
> > > > > > > - if (!parent)
> > > > > > > -         return -ENOENT;
> > > > > > > + if (!parent) {
> > > > > > > +         parent = kernfs_create_dir_ns(kobj->sd, group,
> > > > > > > +                                   S_IRWXU | S_IRUGO | S_IXUGO,
> > > > > > > +                                   uid, gid, kobj, NULL);
> > > > > > > +         if (IS_ERR(parent)) {
> > > > > > > +                 if (PTR_ERR(parent) == -EEXIST)
> > > > > > > +                         sysfs_warn_dup(kobj->sd, group);
> > > > > > > +                 return PTR_ERR(parent);
> > > > > > > +         }
> > > > > > > +
> > > > > > > +         kernfs_get(parent);
> > > > > > > + }
> > > > > > >
> > > > > > >   kobject_get_ownership(kobj, &uid, &gid);
> > > > > > >   error = sysfs_add_file_mode_ns(parent, attr, attr->mode, uid, gid,
> > > > > > > diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
> > > > > > > index 138676463336..013fa333cd3c 100644
> > > > > > > --- a/fs/sysfs/group.c
> > > > > > > +++ b/fs/sysfs/group.c
> > > > > > > @@ -31,12 +31,14 @@ static void remove_files(struct kernfs_node *parent,
> > > > > > >                   kernfs_remove_by_name(parent, (*bin_attr)->attr.name);
> > > > > > >  }
> > > > > > >
> > > > > > > +/* returns -ERROR if error, or >= 0 for number of files actually created */
> > > > > > >  static int create_files(struct kernfs_node *parent, struct kobject *kobj,
> > > > > > >                   kuid_t uid, kgid_t gid,
> > > > > > >                   const struct attribute_group *grp, int update)
> > > > > > >  {
> > > > > > >   struct attribute *const *attr;
> > > > > > >   struct bin_attribute *const *bin_attr;
> > > > > > > + int files_created = 0;
> > > > > > >   int error = 0, i;
> > > > > > >
> > > > > > >   if (grp->attrs) {
> > > > > > > @@ -65,6 +67,8 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
> > > > > > >                                                  gid, NULL);
> > > > > > >                   if (unlikely(error))
> > > > > > >                           break;
> > > > > > > +
> > > > > > > +                 files_created++;
> > > > > > >           }
> > > > > > >           if (error) {
> > > > > > >                   remove_files(parent, grp);
> > > > > > > @@ -95,12 +99,15 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
> > > > > > >                                                      NULL);
> > > > > > >                   if (error)
> > > > > > >                           break;
> > > > > > > +                 files_created++;
> > > > > > >           }
> > > > > > >           if (error)
> > > > > > >                   remove_files(parent, grp);
> > > > > > >   }
> > > > > > >  exit:
> > > > > > > - return error;
> > > > > > > + if (error)
> > > > > > > +         return error;
> > > > > > > + return files_created;
> > > > > > >  }
> > > > > > >
> > > > > > >
> > > > > > > @@ -130,9 +137,14 @@ static int internal_create_group(struct kobject *kobj, int update,
> > > > > > >           if (update) {
> > > > > > >                   kn = kernfs_find_and_get(kobj->sd, grp->name);
> > > > > > >                   if (!kn) {
> > > > > > > -                         pr_warn("Can't update unknown attr grp name: %s/%s\n",
> > > > > > > -                                 kobj->name, grp->name);
> > > > > > > -                         return -EINVAL;
> > > > > > > +                         kn = kernfs_create_dir_ns(kobj->sd, grp->name,
> > > > > > > +                                                   S_IRWXU | S_IRUGO | S_IXUGO,
> > > > > > > +                                                   uid, gid, kobj, NULL);
> > > > > > > +                         if (IS_ERR(kn)) {
> > > > > > > +                                 if (PTR_ERR(kn) == -EEXIST)
> > > > > > > +                                         sysfs_warn_dup(kobj->sd, grp->name);
> > > > > > > +                                 return PTR_ERR(kn);
> > > > > > > +                         }
> > > > > > >                   }
> > > > > > >           } else {
> > > > > > >                   kn = kernfs_create_dir_ns(kobj->sd, grp->name,
> > > > > > > @@ -150,11 +162,18 @@ static int internal_create_group(struct kobject *kobj, int update,
> > > > > > >
> > > > > > >   kernfs_get(kn);
> > > > > > >   error = create_files(kn, kobj, uid, gid, grp, update);
> > > > > > > - if (error) {
> > > > > > > + if (error <= 0) {
> > > > > > > +         /*
> > > > > > > +          * If an error happened _OR_ if no files were created in the
> > > > > > > +          * attribute group, and we have a name for this group, delete
> > > > > > > +          * the name so there's not an empty directory.
> > > > > > > +          */
> > > > > > >           if (grp->name)
> > > > > > >                   kernfs_remove(kn);
> > > > > > > + } else {
> > > > > > > +         error = 0;
> > > > > > > +         kernfs_put(kn);
> > > > > > >   }
> > > > > > > - kernfs_put(kn);
> > > > > > >
> > > > > > >   if (grp->name && update)
> > > > > > >           kernfs_put(kn);
> > > > > > > @@ -318,13 +337,12 @@ void sysfs_remove_groups(struct kobject *kobj,
> > > > > > >  EXPORT_SYMBOL_GPL(sysfs_remove_groups);
> > > > > > >
> > > > > > >  /**
> > > > > > > - * sysfs_merge_group - merge files into a pre-existing attribute group.
> > > > > > > + * sysfs_merge_group - merge files into a attribute group.
> > > > > > >   * @kobj:        The kobject containing the group.
> > > > > > >   * @grp: The files to create and the attribute group they belong to.
> > > > > > >   *
> > > > > > > - * This function returns an error if the group doesn't exist or any of the
> > > > > > > - * files already exist in that group, in which case none of the new files
> > > > > > > - * are created.
> > > > > > > + * This function returns an error if any of the files already exist in
> > > > > > > + * that group, in which case none of the new files are created.
> > > > > > >   */
> > > > > > >  int sysfs_merge_group(struct kobject *kobj,
> > > > > > >                  const struct attribute_group *grp)
> > > > > > > @@ -336,12 +354,22 @@ int sysfs_merge_group(struct kobject *kobj,
> > > > > > >   struct attribute *const *attr;
> > > > > > >   int i;
> > > > > > >
> > > > > > > - parent = kernfs_find_and_get(kobj->sd, grp->name);
> > > > > > > - if (!parent)
> > > > > > > -         return -ENOENT;
> > > > > > > -
> > > > > > >   kobject_get_ownership(kobj, &uid, &gid);
> > > > > > >
> > > > > > > + parent = kernfs_find_and_get(kobj->sd, grp->name);
> > > > > > > + if (!parent) {
> > > > > > > +         parent = kernfs_create_dir_ns(kobj->sd, grp->name,
> > > > > > > +                                   S_IRWXU | S_IRUGO | S_IXUGO,
> > > > > > > +                                   uid, gid, kobj, NULL);
> > > > > > > +         if (IS_ERR(parent)) {
> > > > > > > +                 if (PTR_ERR(parent) == -EEXIST)
> > > > > > > +                         sysfs_warn_dup(kobj->sd, grp->name);
> > > > > > > +                 return PTR_ERR(parent);
> > > > > > > +         }
> > > > > > > +
> > > > > > > +         kernfs_get(parent);
> > > > > > > + }
> > > > > > > +
> > > > > > >   for ((i = 0, attr = grp->attrs); *attr && !error; (++i, ++attr))
> > > > > > >           error = sysfs_add_file_mode_ns(parent, *attr, (*attr)->mode,
> > > > > > >                                          uid, gid, NULL);
> > > > > > > --
> > > > > > > 2.42.0
> > > > > > >
> > > > > >
> > > > > > And as the 0-day bot just showed, this patch isn't going to work
> > > > > > properly, the uid/gid stuff isn't all hooked up properly, I'll work on
> > > > > > fixing that up when I get some cycles...
> > > > >
> > > > > Oops, nope, that was my fault in applying this to my tree, sorry for the
> > > > > noise...
> > > >
> > > > And I just got around to testing this, and it does not boot at all.
> > > > Below is the patch I am using, are you sure you got this to boot for
> > > > you?
> > >
> > > I just checked again and it boots for me. What failure are you seeing?
> >
> > Block devices were not created properly in sysfs.
>
> Strange. I have tested this on a QEMU virtual machine and a x86 PC and
> I don't see any issues on either.
>
> >
> > Did you test your patch, or my modified one that I attached on this
> > email?  That might be the difference.
>
> I'm using your modified one.
>
> Are you able to provide logs? There must be some driver that is
> causing the issue. I can try to reproduce it if I know where it's
> failing.

Hey Greg,

I wanted to follow up on this and see if you are able to provide more
details for reproducing or if you are able to look into it?

Alistair

>
> Alistair
>
> >
> > thanks,
> >
> > greg k-h

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 2/3] sysfs: Add a attr_is_visible function to attribute_group
  2024-01-23  4:04                         ` Alistair Francis
@ 2024-01-23 12:25                           ` Greg KH
  2024-01-24 20:31                             ` Dan Williams
  0 siblings, 1 reply; 28+ messages in thread
From: Greg KH @ 2024-01-23 12:25 UTC (permalink / raw)
  To: Alistair Francis
  Cc: bhelgaas, linux-pci, Jonathan.Cameron, lukas, alex.williamson,
	christian.koenig, kch, logang, linux-kernel, chaitanyak, rdunlap,
	Alistair Francis

On Tue, Jan 23, 2024 at 02:04:14PM +1000, Alistair Francis wrote:
> On Thu, Oct 12, 2023 at 2:31 PM Alistair Francis <alistair23@gmail.com> wrote:
> >
> > On Wed, Oct 11, 2023 at 4:44 PM Greg KH <gregkh@linuxfoundation.org> wrote:
> > >
> > > On Wed, Oct 11, 2023 at 03:10:39PM +1000, Alistair Francis wrote:
> > > > On Thu, Oct 5, 2023 at 11:05 PM Greg KH <gregkh@linuxfoundation.org> wrote:
> > > > >
> > > > > On Fri, Sep 01, 2023 at 11:00:59PM +0200, Greg KH wrote:
> > > > > > On Thu, Aug 31, 2023 at 04:36:13PM +0200, Greg KH wrote:
> > > > > > > On Thu, Aug 31, 2023 at 10:31:07AM +0200, Greg KH wrote:
> > > > > > > > On Mon, Aug 28, 2023 at 03:05:41PM +1000, Alistair Francis wrote:
> > > > > > > > > On Wed, Aug 23, 2023 at 5:02 PM Greg KH <gregkh@linuxfoundation.org> wrote:
> > > > > > > > > >
> > > > > > > > > > On Tue, Aug 22, 2023 at 04:20:06PM -0400, Alistair Francis wrote:
> > > > > > > > > > > On Sat, Aug 19, 2023 at 6:57 AM Greg KH <gregkh@linuxfoundation.org> wrote:
> > > > > > > > > > > >
> > > > > > > > > > > > On Thu, Aug 17, 2023 at 07:58:09PM -0400, Alistair Francis wrote:
> > > > > > > > > > > > > The documentation for sysfs_merge_group() specifically says
> > > > > > > > > > > > >
> > > > > > > > > > > > >     This function returns an error if the group doesn't exist or any of the
> > > > > > > > > > > > >     files already exist in that group, in which case none of the new files
> > > > > > > > > > > > >     are created.
> > > > > > > > > > > > >
> > > > > > > > > > > > > So just not adding the group if it's empty doesn't work, at least not
> > > > > > > > > > > > > with the code we currently have. The code can be changed to support
> > > > > > > > > > > > > this, but it is difficult to determine how this will affect existing use
> > > > > > > > > > > > > cases.
> > > > > > > > > > > >
> > > > > > > > > > > > Did you try?  I'd really really really prefer we do it this way as it's
> > > > > > > > > > > > much simpler overall to have the sysfs core "do the right thing
> > > > > > > > > > > > automatically" than to force each and every bus/subsystem to have to
> > > > > > > > > > > > manually add this type of attribute.
> > > > > > > > > > > >
> > > > > > > > > > > > Also, on a personal level, I want this function to work as it will allow
> > > > > > > > > > > > us to remove some code in some busses that don't really need to be there
> > > > > > > > > > > > (dynamic creation of some device attributes), which will then also allow
> > > > > > > > > > > > me to remove some apis in the driver core that should not be used at all
> > > > > > > > > > > > anymore (but keep creeping back in as there is still a few users.)
> > > > > > > > > > > >
> > > > > > > > > > > > So I'll be selfish here and say "please try to get my proposed change to
> > > > > > > > > > > > work, it's really the correct thing to do here."
> > > > > > > > > > >
> > > > > > > > > > > I did try!
> > > > > > > > > > >
> > > > > > > > > > > This is an attempt:
> > > > > > > > > > > https://github.com/alistair23/linux/commit/56b55756a2d7a66f7b6eb8a5692b1b5e2f81a9a9
> > > > > > > > > > >
> > > > > > > > > > > It is based on your original patch with a bunch of:
> > > > > > > > > > >
> > > > > > > > > > > if (!parent) {
> > > > > > > > > > >     parent = kernfs_create_dir_ns(kobj->sd, grp->name,
> > > > > > > > > > >                   S_IRWXU | S_IRUGO | S_IXUGO,
> > > > > > > > > > >                   uid, gid, kobj, NULL);
> > > > > > > > > > >     ...
> > > > > > > > > > >     }
> > > > > > > > > > >
> > > > > > > > > > >
> > > > > > > > > > > added throughout the code base.
> > > > > > > > > > >
> > > > > > > > > > > Very basic testing shows that it does what I need it to do and I don't
> > > > > > > > > > > see any kernel oops on boot.
> > > > > > > > > >
> > > > > > > > > > Nice!
> > > > > > > > > >
> > > > > > > > > > Mind if I take it and clean it up a bit and test with it here?  Again, I
> > > > > > > > > > need this functionality for other stuff as well, so getting it merged
> > > > > > > > > > for your feature is fine with me.
> > > > > > > > >
> > > > > > > > > Sure! Go ahead. Sorry I was travelling last week.
> > > > > > > > >
> > > > > > > > > >
> > > > > > > > > > > I prefer the approach I have in this mailing list patch. But if you
> > > > > > > > > > > like the commit mentioned above I can tidy and clean it up and then
> > > > > > > > > > > use that instead
> > > > > > > > > >
> > > > > > > > > > I would rather do it this way.  I can work on this on Friday if you want
> > > > > > > > > > me to.
> > > > > > > > >
> > > > > > > > > Yeah, that's fine with me. If you aren't able to let me know and I can
> > > > > > > > > finish up the patch and send it with this series
> > > > > > > >
> > > > > > > > Great, and for the email record, as github links are not stable, here's
> > > > > > > > the patch that you have above attached below.  I'll test this out and
> > > > > > > > clean it up a bit more and see how it goes...
> > > > > > > >
> > > > > > > > thanks,
> > > > > > > >
> > > > > > > > greg k-h
> > > > > > > >
> > > > > > > >
> > > > > > > > From 2929d17b58d02dcf52d0345fa966c616e09a5afa Mon Sep 17 00:00:00 2001
> > > > > > > > From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > > > > > > > Date: Wed, 24 Aug 2022 15:45:36 +0200
> > > > > > > > Subject: [PATCH] sysfs: do not create empty directories if no attributes are
> > > > > > > >  present
> > > > > > > >
> > > > > > > > When creating an attribute group, if it is named a subdirectory is
> > > > > > > > created and the sysfs files are placed into that subdirectory.  If no
> > > > > > > > files are created, normally the directory would still be present, but it
> > > > > > > > would be empty.  Clean this up by removing the directory if no files
> > > > > > > > were successfully created in the group at all.
> > > > > > > >
> > > > > > > > Co-developed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > > > > > > > Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > > > > > > > Co-developed-by: Alistair Francis <alistair.francis@wdc.com>
> > > > > > > > Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> > > > > > > > ---
> > > > > > > >  fs/sysfs/file.c  | 14 ++++++++++--
> > > > > > > >  fs/sysfs/group.c | 56 ++++++++++++++++++++++++++++++++++++------------
> > > > > > > >  2 files changed, 54 insertions(+), 16 deletions(-)
> > > > > > > >
> > > > > > > > diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
> > > > > > > > index a12ac0356c69..7aab6c09662c 100644
> > > > > > > > --- a/fs/sysfs/file.c
> > > > > > > > +++ b/fs/sysfs/file.c
> > > > > > > > @@ -391,8 +391,18 @@ int sysfs_add_file_to_group(struct kobject *kobj,
> > > > > > > >           kernfs_get(parent);
> > > > > > > >   }
> > > > > > > >
> > > > > > > > - if (!parent)
> > > > > > > > -         return -ENOENT;
> > > > > > > > + if (!parent) {
> > > > > > > > +         parent = kernfs_create_dir_ns(kobj->sd, group,
> > > > > > > > +                                   S_IRWXU | S_IRUGO | S_IXUGO,
> > > > > > > > +                                   uid, gid, kobj, NULL);
> > > > > > > > +         if (IS_ERR(parent)) {
> > > > > > > > +                 if (PTR_ERR(parent) == -EEXIST)
> > > > > > > > +                         sysfs_warn_dup(kobj->sd, group);
> > > > > > > > +                 return PTR_ERR(parent);
> > > > > > > > +         }
> > > > > > > > +
> > > > > > > > +         kernfs_get(parent);
> > > > > > > > + }
> > > > > > > >
> > > > > > > >   kobject_get_ownership(kobj, &uid, &gid);
> > > > > > > >   error = sysfs_add_file_mode_ns(parent, attr, attr->mode, uid, gid,
> > > > > > > > diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
> > > > > > > > index 138676463336..013fa333cd3c 100644
> > > > > > > > --- a/fs/sysfs/group.c
> > > > > > > > +++ b/fs/sysfs/group.c
> > > > > > > > @@ -31,12 +31,14 @@ static void remove_files(struct kernfs_node *parent,
> > > > > > > >                   kernfs_remove_by_name(parent, (*bin_attr)->attr.name);
> > > > > > > >  }
> > > > > > > >
> > > > > > > > +/* returns -ERROR if error, or >= 0 for number of files actually created */
> > > > > > > >  static int create_files(struct kernfs_node *parent, struct kobject *kobj,
> > > > > > > >                   kuid_t uid, kgid_t gid,
> > > > > > > >                   const struct attribute_group *grp, int update)
> > > > > > > >  {
> > > > > > > >   struct attribute *const *attr;
> > > > > > > >   struct bin_attribute *const *bin_attr;
> > > > > > > > + int files_created = 0;
> > > > > > > >   int error = 0, i;
> > > > > > > >
> > > > > > > >   if (grp->attrs) {
> > > > > > > > @@ -65,6 +67,8 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
> > > > > > > >                                                  gid, NULL);
> > > > > > > >                   if (unlikely(error))
> > > > > > > >                           break;
> > > > > > > > +
> > > > > > > > +                 files_created++;
> > > > > > > >           }
> > > > > > > >           if (error) {
> > > > > > > >                   remove_files(parent, grp);
> > > > > > > > @@ -95,12 +99,15 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
> > > > > > > >                                                      NULL);
> > > > > > > >                   if (error)
> > > > > > > >                           break;
> > > > > > > > +                 files_created++;
> > > > > > > >           }
> > > > > > > >           if (error)
> > > > > > > >                   remove_files(parent, grp);
> > > > > > > >   }
> > > > > > > >  exit:
> > > > > > > > - return error;
> > > > > > > > + if (error)
> > > > > > > > +         return error;
> > > > > > > > + return files_created;
> > > > > > > >  }
> > > > > > > >
> > > > > > > >
> > > > > > > > @@ -130,9 +137,14 @@ static int internal_create_group(struct kobject *kobj, int update,
> > > > > > > >           if (update) {
> > > > > > > >                   kn = kernfs_find_and_get(kobj->sd, grp->name);
> > > > > > > >                   if (!kn) {
> > > > > > > > -                         pr_warn("Can't update unknown attr grp name: %s/%s\n",
> > > > > > > > -                                 kobj->name, grp->name);
> > > > > > > > -                         return -EINVAL;
> > > > > > > > +                         kn = kernfs_create_dir_ns(kobj->sd, grp->name,
> > > > > > > > +                                                   S_IRWXU | S_IRUGO | S_IXUGO,
> > > > > > > > +                                                   uid, gid, kobj, NULL);
> > > > > > > > +                         if (IS_ERR(kn)) {
> > > > > > > > +                                 if (PTR_ERR(kn) == -EEXIST)
> > > > > > > > +                                         sysfs_warn_dup(kobj->sd, grp->name);
> > > > > > > > +                                 return PTR_ERR(kn);
> > > > > > > > +                         }
> > > > > > > >                   }
> > > > > > > >           } else {
> > > > > > > >                   kn = kernfs_create_dir_ns(kobj->sd, grp->name,
> > > > > > > > @@ -150,11 +162,18 @@ static int internal_create_group(struct kobject *kobj, int update,
> > > > > > > >
> > > > > > > >   kernfs_get(kn);
> > > > > > > >   error = create_files(kn, kobj, uid, gid, grp, update);
> > > > > > > > - if (error) {
> > > > > > > > + if (error <= 0) {
> > > > > > > > +         /*
> > > > > > > > +          * If an error happened _OR_ if no files were created in the
> > > > > > > > +          * attribute group, and we have a name for this group, delete
> > > > > > > > +          * the name so there's not an empty directory.
> > > > > > > > +          */
> > > > > > > >           if (grp->name)
> > > > > > > >                   kernfs_remove(kn);
> > > > > > > > + } else {
> > > > > > > > +         error = 0;
> > > > > > > > +         kernfs_put(kn);
> > > > > > > >   }
> > > > > > > > - kernfs_put(kn);
> > > > > > > >
> > > > > > > >   if (grp->name && update)
> > > > > > > >           kernfs_put(kn);
> > > > > > > > @@ -318,13 +337,12 @@ void sysfs_remove_groups(struct kobject *kobj,
> > > > > > > >  EXPORT_SYMBOL_GPL(sysfs_remove_groups);
> > > > > > > >
> > > > > > > >  /**
> > > > > > > > - * sysfs_merge_group - merge files into a pre-existing attribute group.
> > > > > > > > + * sysfs_merge_group - merge files into a attribute group.
> > > > > > > >   * @kobj:        The kobject containing the group.
> > > > > > > >   * @grp: The files to create and the attribute group they belong to.
> > > > > > > >   *
> > > > > > > > - * This function returns an error if the group doesn't exist or any of the
> > > > > > > > - * files already exist in that group, in which case none of the new files
> > > > > > > > - * are created.
> > > > > > > > + * This function returns an error if any of the files already exist in
> > > > > > > > + * that group, in which case none of the new files are created.
> > > > > > > >   */
> > > > > > > >  int sysfs_merge_group(struct kobject *kobj,
> > > > > > > >                  const struct attribute_group *grp)
> > > > > > > > @@ -336,12 +354,22 @@ int sysfs_merge_group(struct kobject *kobj,
> > > > > > > >   struct attribute *const *attr;
> > > > > > > >   int i;
> > > > > > > >
> > > > > > > > - parent = kernfs_find_and_get(kobj->sd, grp->name);
> > > > > > > > - if (!parent)
> > > > > > > > -         return -ENOENT;
> > > > > > > > -
> > > > > > > >   kobject_get_ownership(kobj, &uid, &gid);
> > > > > > > >
> > > > > > > > + parent = kernfs_find_and_get(kobj->sd, grp->name);
> > > > > > > > + if (!parent) {
> > > > > > > > +         parent = kernfs_create_dir_ns(kobj->sd, grp->name,
> > > > > > > > +                                   S_IRWXU | S_IRUGO | S_IXUGO,
> > > > > > > > +                                   uid, gid, kobj, NULL);
> > > > > > > > +         if (IS_ERR(parent)) {
> > > > > > > > +                 if (PTR_ERR(parent) == -EEXIST)
> > > > > > > > +                         sysfs_warn_dup(kobj->sd, grp->name);
> > > > > > > > +                 return PTR_ERR(parent);
> > > > > > > > +         }
> > > > > > > > +
> > > > > > > > +         kernfs_get(parent);
> > > > > > > > + }
> > > > > > > > +
> > > > > > > >   for ((i = 0, attr = grp->attrs); *attr && !error; (++i, ++attr))
> > > > > > > >           error = sysfs_add_file_mode_ns(parent, *attr, (*attr)->mode,
> > > > > > > >                                          uid, gid, NULL);
> > > > > > > > --
> > > > > > > > 2.42.0
> > > > > > > >
> > > > > > >
> > > > > > > And as the 0-day bot just showed, this patch isn't going to work
> > > > > > > properly, the uid/gid stuff isn't all hooked up properly, I'll work on
> > > > > > > fixing that up when I get some cycles...
> > > > > >
> > > > > > Oops, nope, that was my fault in applying this to my tree, sorry for the
> > > > > > noise...
> > > > >
> > > > > And I just got around to testing this, and it does not boot at all.
> > > > > Below is the patch I am using, are you sure you got this to boot for
> > > > > you?
> > > >
> > > > I just checked again and it boots for me. What failure are you seeing?
> > >
> > > Block devices were not created properly in sysfs.
> >
> > Strange. I have tested this on a QEMU virtual machine and a x86 PC and
> > I don't see any issues on either.
> >
> > >
> > > Did you test your patch, or my modified one that I attached on this
> > > email?  That might be the difference.
> >
> > I'm using your modified one.
> >
> > Are you able to provide logs? There must be some driver that is
> > causing the issue. I can try to reproduce it if I know where it's
> > failing.
> 
> Hey Greg,
> 
> I wanted to follow up on this and see if you are able to provide more
> details for reproducing or if you are able to look into it?

Last I tried this, it still crashed and would not boot either on my
laptop or my workstation.  I don't know how it is working properly for
you, what systems have you tried it on?

I'm not going to be able to look at this for many weeks due to
conference stuff, so if you want to take the series and test it and
hopefully catch my error, that would be great, I'd love to move forward
and get this merged someday.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 2/3] sysfs: Add a attr_is_visible function to attribute_group
  2024-01-23 12:25                           ` Greg KH
@ 2024-01-24 20:31                             ` Dan Williams
  2024-01-26 18:58                               ` Dan Williams
  0 siblings, 1 reply; 28+ messages in thread
From: Dan Williams @ 2024-01-24 20:31 UTC (permalink / raw)
  To: Greg KH, Alistair Francis
  Cc: bhelgaas, linux-pci, Jonathan.Cameron, lukas, alex.williamson,
	christian.koenig, kch, logang, linux-kernel, chaitanyak, rdunlap,
	Alistair Francis

Greg KH wrote:
[..]
> > 
> > Hey Greg,
> > 
> > I wanted to follow up on this and see if you are able to provide more
> > details for reproducing or if you are able to look into it?
> 
> Last I tried this, it still crashed and would not boot either on my
> laptop or my workstation.  I don't know how it is working properly for
> you, what systems have you tried it on?
> 
> I'm not going to be able to look at this for many weeks due to
> conference stuff, so if you want to take the series and test it and
> hopefully catch my error, that would be great, I'd love to move forward
> and get this merged someday.

I mentioned to Lukas that I was working on a "sysfs group visibility"
patch and he pointed me to this thread. I will note that I tried to make
the "hide group if all attributes are invisible" approach work, but
reverted to a "new is_group_visible() callback" approach. I did read
through the thread and try to improve the argument in the changelog
accordingly.

I do admit to liking the cleanliness (not touching 'struct
attribute_group') of the "hide if no visible attribute" approch, but see
the criticism of that alternative below, and let me know if it is
convincing. I tested it locally with the following hack to make the
group disappear every other sysfs_update_group() event:

diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
index 3e817a6f94c6..a5c4e8f3e93b 100644
--- a/drivers/cxl/core/region.c
+++ b/drivers/cxl/core/region.c
@@ -2022,9 +2022,20 @@ static umode_t cxl_region_target_visible(struct kobject *kobj,
        return 0;
 }
 
+static umode_t cxl_region_target_group_visible(struct kobject *kobj)
+{
+       static u32 visible;
+
+       if (visible++ & 1)
+               return 0755;
+       return 0;
+}
+
 static const struct attribute_group cxl_region_target_group = {
+       .name = "target_group",
        .attrs = target_attrs,
        .is_visible = cxl_region_target_visible,
+       .is_group_visible = cxl_region_target_group_visible,
 };
 
 static const struct attribute_group *get_cxl_region_target_group(void)


-- >8 --
From 18d6fdf1465f4ce5f561a35797c1313276993af0 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Tue, 23 Jan 2024 20:20:39 -0800
Subject: [PATCH] sysfs: Introduce is_group_visible() for attribute_groups

Add a method to 'struct attribute_group' to determine the visibility of
an entire named sysfs group relative to the state of its parent kobject.

The motivation for this capability is to centralize PCI device
authentication in the PCI core with a named sysfs group while keeping
that group hidden for devices and platforms that do not meet the
requirements. In a PCI topology, most devices will not support
authentication, a small subset will support just PCI CMA (Component
Measurement and Authentication), a smaller subset will support PCI CMA +
PCIe IDE (Link Integrity and Encryption), and only next generation
server hosts will start to include a platform TSM (TEE Security
Manager).

Without this capability the alternatives are:

- Check if all attributes are invisible and if so, hide the directory.
  Beyond trouble getting this to work [1], this is an ABI change for
  scenarios if userspace happens to depend on group visibility absent any
  attributes. I.e. this new capability avoids regression since it does
  not retroactively apply to existing cases.

- Publish an empty /sys/bus/pci/devices/$pdev/tsm/ directory for all PCI
  devices (i.e. for the case when TSM platform support is present, but
  device support is absent). Unfortunate that this will be a vestigial
  empty directory in the vast majority of cases.

- Reintroduce usage of runtime calls to sysfs_{create,remove}_group()
  in the PCI core. Bjorn has already indicated that he does not want to
  see any growth of pci_sysfs_init() [2].

- Drop the named group and simulate a directory by prefixing all
  TSM-related attributes with "tsm_". Unfortunate to not use the naming
  capability of a sysfs group as intended.

The downside of the alternatives seem worse than the maintenance burden
of this new capability. Otherwise, this facility also brings support for
changing permissions on sysfs directories from the 0755 default for
potential cases where only root is expected to be able to enumerate.
That may prove useful as PCI sysfs picks up more security sensitive
enumeration.

The size increase of 'struct attribute_group' is a concern. Longer term
this could be reduced by consolidating the 3 is_visible() callbacks into
one that takes a parameter for "attr", "bin_attr", or "group". For now
the support is gated behind CONFIG_SYSFS_GROUP_VISIBLE so it can be
compiled out when not needed.

Link: https://lore.kernel.org/all/2024012321-envious-procedure-4a58@gregkh/ [1]
Link: https://lore.kernel.org/linux-pci/20231019200110.GA1410324@bhelgaas/ [2]
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 fs/sysfs/Kconfig      |  3 +++
 fs/sysfs/group.c      | 50 +++++++++++++++++++++++++++++++++++--------
 include/linux/sysfs.h | 34 +++++++++++++++++++++++++++++
 3 files changed, 78 insertions(+), 9 deletions(-)

diff --git a/fs/sysfs/Kconfig b/fs/sysfs/Kconfig
index b0fe1cce33a0..d5de8e54a06f 100644
--- a/fs/sysfs/Kconfig
+++ b/fs/sysfs/Kconfig
@@ -23,3 +23,6 @@ config SYSFS
 	example, "root=03:01" for /dev/hda1.
 
 	Designers of embedded systems may wish to say N here to conserve space.
+
+config SYSFS_GROUP_VISIBLE
+	bool
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
index 138676463336..0a977064e118 100644
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -127,16 +127,36 @@ static int internal_create_group(struct kobject *kobj, int update,
 
 	kobject_get_ownership(kobj, &uid, &gid);
 	if (grp->name) {
+		umode_t mode = S_IRWXU | S_IRUGO | S_IXUGO;
+
+		if (has_group_visible(grp))
+			mode = is_group_visible(grp, kobj);
+
 		if (update) {
 			kn = kernfs_find_and_get(kobj->sd, grp->name);
 			if (!kn) {
-				pr_warn("Can't update unknown attr grp name: %s/%s\n",
-					kobj->name, grp->name);
-				return -EINVAL;
+				if (!has_group_visible(grp)) {
+					pr_warn("Can't update unknown attr grp name: %s/%s\n",
+						kobj->name, grp->name);
+					return -EINVAL;
+				}
+				/* may have been invisible prior to this update */
+				update = 0;
+			} else {
+				/* need to change the visibility of the entire group */
+				sysfs_remove_group(kobj, grp);
+				if (mode == 0) {
+					kernfs_put(kn);
+					return 0;
+				}
+				update = 0;
 			}
-		} else {
-			kn = kernfs_create_dir_ns(kobj->sd, grp->name,
-						  S_IRWXU | S_IRUGO | S_IXUGO,
+		}
+
+		if (!update) {
+			if (mode == 0)
+				return 0;
+			kn = kernfs_create_dir_ns(kobj->sd, grp->name, mode,
 						  uid, gid, kobj, NULL);
 			if (IS_ERR(kn)) {
 				if (PTR_ERR(kn) == -EEXIST)
@@ -262,6 +282,20 @@ int sysfs_update_group(struct kobject *kobj,
 }
 EXPORT_SYMBOL_GPL(sysfs_update_group);
 
+static void warn_group_not_found(const struct attribute_group *grp,
+				 struct kobject *kobj)
+{
+	if (has_group_visible(grp)) {
+		/* may have never been created */
+		pr_debug("sysfs group '%s' not found for kobject '%s'\n",
+			 grp->name, kobject_name(kobj));
+		return;
+	}
+
+	WARN(1, KERN_WARNING "sysfs group '%s' not found for kobject '%s'\n",
+	     grp->name, kobject_name(kobj));
+}
+
 /**
  * sysfs_remove_group: remove a group from a kobject
  * @kobj:	kobject to remove the group from
@@ -279,9 +313,7 @@ void sysfs_remove_group(struct kobject *kobj,
 	if (grp->name) {
 		kn = kernfs_find_and_get(parent, grp->name);
 		if (!kn) {
-			WARN(!kn, KERN_WARNING
-			     "sysfs group '%s' not found for kobject '%s'\n",
-			     grp->name, kobject_name(kobj));
+			warn_group_not_found(grp, kobj);
 			return;
 		}
 	} else {
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index b717a70219f6..31f3dd6fc946 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -77,6 +77,12 @@ do {							\
  *		return 0 if a binary attribute is not visible. The returned
  *		value will replace static permissions defined in
  *		struct bin_attribute.
+ * @is_group_visible:
+ * 		Optional: Function to return permissions associated with
+ * 		directory created for named groups. When this returns 0
+ * 		all attributes are removed on update, or otherwise the
+ * 		directory is not created in the first instance. When not
+ * 		specified the default permissions of 0755 are applied.
  * @attrs:	Pointer to NULL terminated list of attributes.
  * @bin_attrs:	Pointer to NULL terminated list of binary attributes.
  *		Either attrs or bin_attrs or both must be provided.
@@ -87,10 +93,38 @@ struct attribute_group {
 					      struct attribute *, int);
 	umode_t			(*is_bin_visible)(struct kobject *,
 						  struct bin_attribute *, int);
+#ifdef CONFIG_SYSFS_GROUP_VISIBLE
+	umode_t			(*is_group_visible)(struct kobject *);
+#endif
+
 	struct attribute	**attrs;
 	struct bin_attribute	**bin_attrs;
 };
 
+#ifdef CONFIG_SYSFS_GROUP_VISIBLE
+static inline bool has_group_visible(const struct attribute_group *grp)
+{
+	return grp->is_group_visible != NULL;
+}
+
+static inline umode_t is_group_visible(const struct attribute_group *grp,
+				       struct kobject *kobj)
+{
+	return grp->is_group_visible(kobj);
+}
+#else
+static inline bool has_group_visible(const struct attribute_group *grp)
+{
+	return false;
+}
+
+static inline umode_t is_group_visible(const struct attribute_group *grp,
+				       struct kobject *kobj)
+{
+	return 0755;
+}
+#endif
+
 /*
  * Use these macros to make defining attributes easier.
  * See include/linux/device.h for examples..
-- 
2.43.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 2/3] sysfs: Add a attr_is_visible function to attribute_group
  2024-01-24 20:31                             ` Dan Williams
@ 2024-01-26 18:58                               ` Dan Williams
  2024-01-26 19:07                                 ` Greg KH
  0 siblings, 1 reply; 28+ messages in thread
From: Dan Williams @ 2024-01-26 18:58 UTC (permalink / raw)
  To: Dan Williams, Greg KH, Alistair Francis
  Cc: bhelgaas, linux-pci, Jonathan.Cameron, lukas, alex.williamson,
	christian.koenig, kch, logang, linux-kernel, chaitanyak, rdunlap,
	Alistair Francis

Dan Williams wrote:
> Greg KH wrote:
> [..]
> > > 
> > > Hey Greg,
> > > 
> > > I wanted to follow up on this and see if you are able to provide more
> > > details for reproducing or if you are able to look into it?
> > 
> > Last I tried this, it still crashed and would not boot either on my
> > laptop or my workstation.  I don't know how it is working properly for
> > you, what systems have you tried it on?
> > 
> > I'm not going to be able to look at this for many weeks due to
> > conference stuff, so if you want to take the series and test it and
> > hopefully catch my error, that would be great, I'd love to move forward
> > and get this merged someday.
> 
> I mentioned to Lukas that I was working on a "sysfs group visibility"
> patch and he pointed me to this thread. I will note that I tried to make
> the "hide group if all attributes are invisible" approach work, but
> reverted to a "new is_group_visible() callback" approach. I did read
> through the thread and try to improve the argument in the changelog
> accordingly.
> 
> I do admit to liking the cleanliness (not touching 'struct
> attribute_group') of the "hide if no visible attribute" approch, but see
> the criticism of that alternative below, and let me know if it is
> convincing. I tested it locally with the following hack to make the
> group disappear every other sysfs_update_group() event:

Hey Greg,

Ignore this version:

---
From: Dan Williams <dan.j.williams@intel.com>
Date: Tue, 23 Jan 2024 20:20:39 -0800
Subject: [PATCH] sysfs: Introduce is_group_visible() for attribute_groups
---

I am going back to your approach without a new callback, and some fixups
to avoid unintended directory removal. I will post that shortly with its
consumer.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 2/3] sysfs: Add a attr_is_visible function to attribute_group
  2024-01-26 18:58                               ` Dan Williams
@ 2024-01-26 19:07                                 ` Greg KH
  2024-01-26 20:08                                   ` Dan Williams
  0 siblings, 1 reply; 28+ messages in thread
From: Greg KH @ 2024-01-26 19:07 UTC (permalink / raw)
  To: Dan Williams
  Cc: Alistair Francis, bhelgaas, linux-pci, Jonathan.Cameron, lukas,
	alex.williamson, christian.koenig, kch, logang, linux-kernel,
	chaitanyak, rdunlap, Alistair Francis

On Fri, Jan 26, 2024 at 10:58:07AM -0800, Dan Williams wrote:
> Dan Williams wrote:
> > Greg KH wrote:
> > [..]
> > > > 
> > > > Hey Greg,
> > > > 
> > > > I wanted to follow up on this and see if you are able to provide more
> > > > details for reproducing or if you are able to look into it?
> > > 
> > > Last I tried this, it still crashed and would not boot either on my
> > > laptop or my workstation.  I don't know how it is working properly for
> > > you, what systems have you tried it on?
> > > 
> > > I'm not going to be able to look at this for many weeks due to
> > > conference stuff, so if you want to take the series and test it and
> > > hopefully catch my error, that would be great, I'd love to move forward
> > > and get this merged someday.
> > 
> > I mentioned to Lukas that I was working on a "sysfs group visibility"
> > patch and he pointed me to this thread. I will note that I tried to make
> > the "hide group if all attributes are invisible" approach work, but
> > reverted to a "new is_group_visible() callback" approach. I did read
> > through the thread and try to improve the argument in the changelog
> > accordingly.
> > 
> > I do admit to liking the cleanliness (not touching 'struct
> > attribute_group') of the "hide if no visible attribute" approch, but see
> > the criticism of that alternative below, and let me know if it is
> > convincing. I tested it locally with the following hack to make the
> > group disappear every other sysfs_update_group() event:
> 
> Hey Greg,
> 
> Ignore this version:
> 
> ---
> From: Dan Williams <dan.j.williams@intel.com>
> Date: Tue, 23 Jan 2024 20:20:39 -0800
> Subject: [PATCH] sysfs: Introduce is_group_visible() for attribute_groups
> ---
> 
> I am going back to your approach without a new callback, and some fixups
> to avoid unintended directory removal. I will post that shortly with its
> consumer.

Ignore it?  I was just about to write an email that said "maybe this is
the right way forward" :)

What happened to cause it to not be ok?  And if you can find the bug in
the posted patch here, that would be great as well.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 2/3] sysfs: Add a attr_is_visible function to attribute_group
  2024-01-26 19:07                                 ` Greg KH
@ 2024-01-26 20:08                                   ` Dan Williams
  2024-01-27  3:00                                     ` Dan Williams
  0 siblings, 1 reply; 28+ messages in thread
From: Dan Williams @ 2024-01-26 20:08 UTC (permalink / raw)
  To: Greg KH, Dan Williams
  Cc: Alistair Francis, bhelgaas, linux-pci, Jonathan.Cameron, lukas,
	alex.williamson, christian.koenig, kch, logang, linux-kernel,
	chaitanyak, rdunlap, Alistair Francis

Greg KH wrote:
> On Fri, Jan 26, 2024 at 10:58:07AM -0800, Dan Williams wrote:
> > Dan Williams wrote:
> > > Greg KH wrote:
> > > [..]
> > > > > 
> > > > > Hey Greg,
> > > > > 
> > > > > I wanted to follow up on this and see if you are able to provide more
> > > > > details for reproducing or if you are able to look into it?
> > > > 
> > > > Last I tried this, it still crashed and would not boot either on my
> > > > laptop or my workstation.  I don't know how it is working properly for
> > > > you, what systems have you tried it on?
> > > > 
> > > > I'm not going to be able to look at this for many weeks due to
> > > > conference stuff, so if you want to take the series and test it and
> > > > hopefully catch my error, that would be great, I'd love to move forward
> > > > and get this merged someday.
> > > 
> > > I mentioned to Lukas that I was working on a "sysfs group visibility"
> > > patch and he pointed me to this thread. I will note that I tried to make
> > > the "hide group if all attributes are invisible" approach work, but
> > > reverted to a "new is_group_visible() callback" approach. I did read
> > > through the thread and try to improve the argument in the changelog
> > > accordingly.
> > > 
> > > I do admit to liking the cleanliness (not touching 'struct
> > > attribute_group') of the "hide if no visible attribute" approch, but see
> > > the criticism of that alternative below, and let me know if it is
> > > convincing. I tested it locally with the following hack to make the
> > > group disappear every other sysfs_update_group() event:
> > 
> > Hey Greg,
> > 
> > Ignore this version:
> > 
> > ---
> > From: Dan Williams <dan.j.williams@intel.com>
> > Date: Tue, 23 Jan 2024 20:20:39 -0800
> > Subject: [PATCH] sysfs: Introduce is_group_visible() for attribute_groups
> > ---
> > 
> > I am going back to your approach without a new callback, and some fixups
> > to avoid unintended directory removal. I will post that shortly with its
> > consumer.
> 
> Ignore it?  I was just about to write an email that said "maybe this is
> the right way forward" :)
> 
> What happened to cause it to not be ok? And if you can find the bug in
> the posted patch here, that would be great as well.

It was an aha moment this morning that I could rely on something like:

#define SYSFS_GROUP_INVISIBLE ((umode_t)-1)

...as the return value from either is_visible() or attr_is_visible() and
not need to define a new is_group_visible() callback.

The only downside I can see is that there is no way to know if the
is_visible() handler might return SYSFS_GROUP_INVISIBLE to decide when
to warn about deletion not finding anything to delete, or update not
finding the existing node to update.

I'll type it up and see how it looks, but if you're not worried about
the is_group_visible() addition to 'struct atttribute_group' I think
that way is less hacky than the above.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 2/3] sysfs: Add a attr_is_visible function to attribute_group
  2024-01-26 20:08                                   ` Dan Williams
@ 2024-01-27  3:00                                     ` Dan Williams
  2024-01-28  0:21                                       ` Greg KH
  0 siblings, 1 reply; 28+ messages in thread
From: Dan Williams @ 2024-01-27  3:00 UTC (permalink / raw)
  To: Dan Williams, Greg KH
  Cc: Alistair Francis, bhelgaas, linux-pci, Jonathan.Cameron, lukas,
	alex.williamson, christian.koenig, kch, logang, linux-kernel,
	chaitanyak, rdunlap, Alistair Francis

Dan Williams wrote:
> > > Hey Greg,
> > > 
> > > Ignore this version:
> > > 
> > > ---
> > > From: Dan Williams <dan.j.williams@intel.com>
> > > Date: Tue, 23 Jan 2024 20:20:39 -0800
> > > Subject: [PATCH] sysfs: Introduce is_group_visible() for attribute_groups
> > > ---
> > > 
> > > I am going back to your approach without a new callback, and some fixups
> > > to avoid unintended directory removal. I will post that shortly with its
> > > consumer.
> > 
> > Ignore it?  I was just about to write an email that said "maybe this is
> > the right way forward" :)
> > 
> > What happened to cause it to not be ok? And if you can find the bug in
> > the posted patch here, that would be great as well.
> 
> It was an aha moment this morning that I could rely on something like:
> 
> #define SYSFS_GROUP_INVISIBLE ((umode_t)-1)
> 
> ...as the return value from either is_visible() or attr_is_visible() and
> not need to define a new is_group_visible() callback.
> 
> The only downside I can see is that there is no way to know if the
> is_visible() handler might return SYSFS_GROUP_INVISIBLE to decide when
> to warn about deletion not finding anything to delete, or update not
> finding the existing node to update.
> 
> I'll type it up and see how it looks, but if you're not worried about
> the is_group_visible() addition to 'struct atttribute_group' I think
> that way is less hacky than the above.

Ok, here it is (below the scissors line). I ended up including a way to
determine if an attribute_group is opting into this new capability, and
I do think this is more in line with your direction to just reuse
existing is_visible() callbacks. This was tested with the following hack
to a dynamic visibility group in CXL:

diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
index 3e817a6f94c6..286b91e29c88 100644
--- a/drivers/cxl/core/region.c
+++ b/drivers/cxl/core/region.c
@@ -2010,8 +2010,8 @@ static struct attribute *target_attrs[] = {
 	NULL,
 };
 
-static umode_t cxl_region_target_visible(struct kobject *kobj,
-					 struct attribute *a, int n)
+static umode_t cxl_region_target_attr_visible(struct kobject *kobj,
+					      struct attribute *a, int n)
 {
 	struct device *dev = kobj_to_dev(kobj);
 	struct cxl_region *cxlr = to_cxl_region(dev);
@@ -2022,9 +2022,22 @@ static umode_t cxl_region_target_visible(struct kobject *kobj,
 	return 0;
 }
 
+static bool cxl_region_target_group_visible(struct kobject *kobj)
+{
+	struct device *dev = kobj_to_dev(kobj);
+	struct cxl_region *cxlr = to_cxl_region(dev);
+	struct cxl_region_params *p = &cxlr->params;
+
+	if (!p->interleave_ways || p->interleave_ways > 2)
+		return false;
+	return true;
+}
+DEFINE_SYSFS_GROUP_VISIBLE(cxl_region_target);
+
 static const struct attribute_group cxl_region_target_group = {
+	.name = "target_group",
 	.attrs = target_attrs,
-	.is_visible = cxl_region_target_visible,
+	.is_visible = SYSFS_GROUP_VISIBLE(cxl_region_target),
 };
 
 static const struct attribute_group *get_cxl_region_target_group(void)

-- >8 --
From 293a9b1d451cba5e7f95897de8c980fddead43ab Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Fri, 26 Jan 2024 18:17:53 -0800
Subject: [PATCH v2] sysfs: Introduce a mechanism to hide static attribute_groups

Add a mechanism for named attribute_groups to hide their directory at
sysfs_update_group() time, or otherwise skip emitting the group
directory when the group is first registered. It piggybacks on
is_visible() in a similar manner as SYSFS_PREALLOC, i.e. special flags
in the upper bits of the returned mode. To use it, specify a symbol
prefix to DEFINE_SYSFS_GROUP_VISIBLE(), and then pass that same prefix
to SYSFS_GROUP_VISIBLE() when assigning the @is_visible() callback:

	DEFINE_SYSFS_GROUP_VISIBLE($prefix)

	struct attribute_group $prefix_group = {
		.name = $name,
		.is_visible = SYSFS_GROUP_VISIBLE($prefix),
	};

SYSFS_GROUP_VISIBLE() expects a definition of $prefix_group_visible()
and $prefix_attr_visible(), where $prefix_group_visible() just returns
true / false and $prefix_attr_visible() behaves as normal.

The motivation for this capability is to centralize PCI device
authentication in the PCI core with a named sysfs group while keeping
that group hidden for devices and platforms that do not meet the
requirements. In a PCI topology, most devices will not support
authentication, a small subset will support just PCI CMA (Component
Measurement and Authentication), a smaller subset will support PCI CMA +
PCIe IDE (Link Integrity and Encryption), and only next generation
server hosts will start to include a platform TSM (TEE Security
Manager).

Without this capability the alternatives are:

* Check if all attributes are invisible and if so, hide the directory.
  Beyond trouble getting this to work [1], this is an ABI change for
  scenarios if userspace happens to depend on group visibility absent any
  attributes. I.e. this new capability avoids regression since it does
  not retroactively apply to existing cases.

* Publish an empty /sys/bus/pci/devices/$pdev/tsm/ directory for all PCI
  devices (i.e. for the case when TSM platform support is present, but
  device support is absent). Unfortunate that this will be a vestigial
  empty directory in the vast majority of cases.

* Reintroduce usage of runtime calls to sysfs_{create,remove}_group()
  in the PCI core. Bjorn has already indicated that he does not want to
  see any growth of pci_sysfs_init() [2].

* Drop the named group and simulate a directory by prefixing all
  TSM-related attributes with "tsm_". Unfortunate to not use the naming
  capability of a sysfs group as intended.

In comparison, there is a small potential for regression if for some
reason an @is_visible() callback had dependencies on how many times it
was called.

Link: https://lore.kernel.org/all/2024012321-envious-procedure-4a58@gregkh/ [1]
Link: https://lore.kernel.org/linux-pci/20231019200110.GA1410324@bhelgaas/ [2]
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 fs/sysfs/group.c      | 64 ++++++++++++++++++++++++++++++++------
 include/linux/sysfs.h | 71 +++++++++++++++++++++++++++++++++++--------
 2 files changed, 114 insertions(+), 21 deletions(-)

diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
index 138676463336..90dd98c82776 100644
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -31,6 +31,17 @@ static void remove_files(struct kernfs_node *parent,
 			kernfs_remove_by_name(parent, (*bin_attr)->attr.name);
 }
 
+static umode_t __first_visible(const struct attribute_group *grp, struct kobject *kobj)
+{
+	if (grp->attrs && grp->is_visible)
+		return grp->is_visible(kobj, grp->attrs[0], 0);
+
+	if (grp->bin_attrs && grp->is_bin_visible)
+		return grp->is_bin_visible(kobj, grp->bin_attrs[0], 0);
+
+	return 0;
+}
+
 static int create_files(struct kernfs_node *parent, struct kobject *kobj,
 			kuid_t uid, kgid_t gid,
 			const struct attribute_group *grp, int update)
@@ -52,6 +63,7 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
 				kernfs_remove_by_name(parent, (*attr)->name);
 			if (grp->is_visible) {
 				mode = grp->is_visible(kobj, *attr, i);
+				mode &= ~SYSFS_GROUP_VISIBLE_MASK;
 				if (!mode)
 					continue;
 			}
@@ -81,6 +93,7 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
 						(*bin_attr)->attr.name);
 			if (grp->is_bin_visible) {
 				mode = grp->is_bin_visible(kobj, *bin_attr, i);
+				mode &= ~SYSFS_GROUP_VISIBLE_MASK;
 				if (!mode)
 					continue;
 			}
@@ -127,16 +140,35 @@ static int internal_create_group(struct kobject *kobj, int update,
 
 	kobject_get_ownership(kobj, &uid, &gid);
 	if (grp->name) {
+		umode_t mode = __first_visible(grp, kobj);
+		bool has_group_visible = mode & SYSFS_HAS_GROUP_VISIBLE;
+
+		if (has_group_visible && (mode & SYSFS_GROUP_INVISIBLE))
+			mode = 0;
+		else
+			mode = S_IRWXU | S_IRUGO | S_IXUGO;
+
 		if (update) {
 			kn = kernfs_find_and_get(kobj->sd, grp->name);
 			if (!kn) {
-				pr_warn("Can't update unknown attr grp name: %s/%s\n",
-					kobj->name, grp->name);
-				return -EINVAL;
+				if (!has_group_visible) {
+					pr_warn("Can't update unknown attr grp name: %s/%s\n",
+						kobj->name, grp->name);
+					return -EINVAL;
+				}
+				/* may have been invisible prior to this update */
+				update = 0;
+			} else if (!mode) {
+				sysfs_remove_group(kobj, grp);
+				kernfs_put(kn);
+				return 0;
 			}
-		} else {
-			kn = kernfs_create_dir_ns(kobj->sd, grp->name,
-						  S_IRWXU | S_IRUGO | S_IXUGO,
+		}
+
+		if (!update) {
+			if (!mode)
+				return 0;
+			kn = kernfs_create_dir_ns(kobj->sd, grp->name, mode,
 						  uid, gid, kobj, NULL);
 			if (IS_ERR(kn)) {
 				if (PTR_ERR(kn) == -EEXIST)
@@ -262,6 +294,22 @@ int sysfs_update_group(struct kobject *kobj,
 }
 EXPORT_SYMBOL_GPL(sysfs_update_group);
 
+static void warn_group_not_found(const struct attribute_group *grp,
+				 struct kobject *kobj)
+{
+	umode_t mode = __first_visible(grp, kobj);
+
+	if (mode & SYSFS_HAS_GROUP_VISIBLE) {
+		/* may have never been created */
+		pr_debug("sysfs group '%s' not found for kobject '%s'\n",
+			 grp->name, kobject_name(kobj));
+		return;
+	}
+
+	WARN(1, KERN_WARNING "sysfs group '%s' not found for kobject '%s'\n",
+	     grp->name, kobject_name(kobj));
+}
+
 /**
  * sysfs_remove_group: remove a group from a kobject
  * @kobj:	kobject to remove the group from
@@ -279,9 +327,7 @@ void sysfs_remove_group(struct kobject *kobj,
 	if (grp->name) {
 		kn = kernfs_find_and_get(parent, grp->name);
 		if (!kn) {
-			WARN(!kn, KERN_WARNING
-			     "sysfs group '%s' not found for kobject '%s'\n",
-			     grp->name, kobject_name(kobj));
+			warn_group_not_found(grp, kobj);
 			return;
 		}
 	} else {
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index b717a70219f6..4fb4f4da003a 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -62,21 +62,32 @@ do {							\
  * struct attribute_group - data structure used to declare an attribute group.
  * @name:	Optional: Attribute group name
  *		If specified, the attribute group will be created in
- *		a new subdirectory with this name.
+ *		a new subdirectory with this name. Additionally when a
+ *		group is named, @is_visible and @is_bin_visible may
+ *		return SYSFS_HAS_GROUP_VISIBLE | SYSFS_GROUP_INVISIBLE
+ *		to control visibility of the directory itself. If
+ *		SYSFS_GROUP_INVISIBLE is ever to be returned,
+ *		SYSFS_HAS_GROUP_VISIBLE must always be included in the
+ *		return value from @is_visible and @is_bin_visible. See
+ *		the DEFINE_SYSFS_GROUP_VISIBLE() helper.
  * @is_visible:	Optional: Function to return permissions associated with an
- *		attribute of the group. Will be called repeatedly for each
- *		non-binary attribute in the group. Only read/write
- *		permissions as well as SYSFS_PREALLOC are accepted. Must
- *		return 0 if an attribute is not visible. The returned value
- *		will replace static permissions defined in struct attribute.
+ *		attribute of the group. Will be called repeatedly for
+ *		each non-binary attribute in the group. Only read/write
+ *		permissions as well as SYSFS_PREALLOC (and the
+ *		visibility flags for named groups) are accepted. Must
+ *		return 0 (or just SYSFS_HAS_GROUP_VISIBLE) if an
+ *		attribute is not visible. The returned value will
+ *		replace static permissions defined in struct attribute.
  * @is_bin_visible:
  *		Optional: Function to return permissions associated with a
  *		binary attribute of the group. Will be called repeatedly
  *		for each binary attribute in the group. Only read/write
- *		permissions as well as SYSFS_PREALLOC are accepted. Must
- *		return 0 if a binary attribute is not visible. The returned
- *		value will replace static permissions defined in
- *		struct bin_attribute.
+ *		permissions as well as SYSFS_PREALLOC (and the
+ *		visibility flags for named groups) are accepted. Must
+ *		return 0 (or just SYSFS_HAS_GROUP_VISIBLE) if a binary
+ *		attribute is not visible. The returned value will
+ *		replace static permissions defined in struct
+ *		bin_attribute.
  * @attrs:	Pointer to NULL terminated list of attributes.
  * @bin_attrs:	Pointer to NULL terminated list of binary attributes.
  *		Either attrs or bin_attrs or both must be provided.
@@ -91,13 +102,49 @@ struct attribute_group {
 	struct bin_attribute	**bin_attrs;
 };
 
+#define SYSFS_PREALLOC		010000
+#define SYSFS_HAS_GROUP_VISIBLE 020000
+#define SYSFS_GROUP_INVISIBLE	040000
+#define SYSFS_GROUP_VISIBLE_MASK (SYSFS_HAS_GROUP_VISIBLE|SYSFS_GROUP_INVISIBLE)
+
+static inline umode_t sysfs_group_visible(umode_t mode)
+{
+	return mode | SYSFS_HAS_GROUP_VISIBLE;
+}
+
+/*
+ * The first call to is_visible() in the create / update path may
+ * indicate visibility for the entire group
+ */
+#define DEFINE_SYSFS_GROUP_VISIBLE(name)                                \
+static inline umode_t sysfs_group_visible_##name(                       \
+	struct kobject *kobj, struct attribute *attr, int n)            \
+{                                                                       \
+	if (n == 0 && !name##_group_visible(kobj))			\
+		return sysfs_group_visible(SYSFS_GROUP_INVISIBLE);      \
+	return sysfs_group_visible(name##_attr_visible(kobj, attr, n)); \
+}
+
+/*
+ * Same as DEFINE_SYSFS_GROUP_VISIBLE, but for groups with only binary
+ * attributes
+ */
+#define DEFINE_SYSFS_BIN_GROUP_VISIBLE(name)                            \
+static inline umode_t sysfs_group_visible_##name(                       \
+	struct kobject *kobj, struct bin_attribute *attr, int n)        \
+{                                                                       \
+	if (n == 0 && !name##_group_visible(kobj))		        \
+		return sysfs_group_visible(SYSFS_GROUP_INVISIBLE);      \
+	return sysfs_group_visible(name##_attr_visible(kobj, attr, n)); \
+}
+
+#define SYSFS_GROUP_VISIBLE(fn) sysfs_group_visible_##fn
+
 /*
  * Use these macros to make defining attributes easier.
  * See include/linux/device.h for examples..
  */
 
-#define SYSFS_PREALLOC 010000
-
 #define __ATTR(_name, _mode, _show, _store) {				\
 	.attr = {.name = __stringify(_name),				\
 		 .mode = VERIFY_OCTAL_PERMISSIONS(_mode) },		\
-- 
2.43.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 2/3] sysfs: Add a attr_is_visible function to attribute_group
  2024-01-27  3:00                                     ` Dan Williams
@ 2024-01-28  0:21                                       ` Greg KH
  2024-01-28  1:42                                         ` Dan Williams
  0 siblings, 1 reply; 28+ messages in thread
From: Greg KH @ 2024-01-28  0:21 UTC (permalink / raw)
  To: Dan Williams
  Cc: Alistair Francis, bhelgaas, linux-pci, Jonathan.Cameron, lukas,
	alex.williamson, christian.koenig, kch, logang, linux-kernel,
	chaitanyak, rdunlap, Alistair Francis

On Fri, Jan 26, 2024 at 07:00:30PM -0800, Dan Williams wrote:
> > I'll type it up and see how it looks, but if you're not worried about
> > the is_group_visible() addition to 'struct atttribute_group' I think
> > that way is less hacky than the above.
> 
> Ok, here it is (below the scissors line). I ended up including a way to
> determine if an attribute_group is opting into this new capability, and
> I do think this is more in line with your direction to just reuse
> existing is_visible() callbacks. This was tested with the following hack
> to a dynamic visibility group in CXL:

At first glance, I like this, but your example here:

> diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
> index 3e817a6f94c6..286b91e29c88 100644
> --- a/drivers/cxl/core/region.c
> +++ b/drivers/cxl/core/region.c
> @@ -2010,8 +2010,8 @@ static struct attribute *target_attrs[] = {
>  	NULL,
>  };
>  
> -static umode_t cxl_region_target_visible(struct kobject *kobj,
> -					 struct attribute *a, int n)
> +static umode_t cxl_region_target_attr_visible(struct kobject *kobj,
> +					      struct attribute *a, int n)
>  {
>  	struct device *dev = kobj_to_dev(kobj);
>  	struct cxl_region *cxlr = to_cxl_region(dev);
> @@ -2022,9 +2022,22 @@ static umode_t cxl_region_target_visible(struct kobject *kobj,
>  	return 0;
>  }
>  
> +static bool cxl_region_target_group_visible(struct kobject *kobj)
> +{
> +	struct device *dev = kobj_to_dev(kobj);
> +	struct cxl_region *cxlr = to_cxl_region(dev);
> +	struct cxl_region_params *p = &cxlr->params;
> +
> +	if (!p->interleave_ways || p->interleave_ways > 2)
> +		return false;
> +	return true;
> +}
> +DEFINE_SYSFS_GROUP_VISIBLE(cxl_region_target);
> +
>  static const struct attribute_group cxl_region_target_group = {
> +	.name = "target_group",
>  	.attrs = target_attrs,
> -	.is_visible = cxl_region_target_visible,
> +	.is_visible = SYSFS_GROUP_VISIBLE(cxl_region_target),
>  };
>  
>  static const struct attribute_group *get_cxl_region_target_group(void)
> 

Seems to not match the documentation in the patch itself, but maybe I'm
reading it wrong.

If all that is needed is the above type of change, I'm all for this,
comments on the implementation below:

> -- >8 --
> >From 293a9b1d451cba5e7f95897de8c980fddead43ab Mon Sep 17 00:00:00 2001
> From: Dan Williams <dan.j.williams@intel.com>
> Date: Fri, 26 Jan 2024 18:17:53 -0800
> Subject: [PATCH v2] sysfs: Introduce a mechanism to hide static attribute_groups
> 
> Add a mechanism for named attribute_groups to hide their directory at
> sysfs_update_group() time, or otherwise skip emitting the group
> directory when the group is first registered. It piggybacks on
> is_visible() in a similar manner as SYSFS_PREALLOC, i.e. special flags
> in the upper bits of the returned mode. To use it, specify a symbol
> prefix to DEFINE_SYSFS_GROUP_VISIBLE(), and then pass that same prefix
> to SYSFS_GROUP_VISIBLE() when assigning the @is_visible() callback:
> 
> 	DEFINE_SYSFS_GROUP_VISIBLE($prefix)
> 
> 	struct attribute_group $prefix_group = {
> 		.name = $name,
> 		.is_visible = SYSFS_GROUP_VISIBLE($prefix),
> 	};
> 
> SYSFS_GROUP_VISIBLE() expects a definition of $prefix_group_visible()
> and $prefix_attr_visible(), where $prefix_group_visible() just returns
> true / false and $prefix_attr_visible() behaves as normal.
> 
> The motivation for this capability is to centralize PCI device
> authentication in the PCI core with a named sysfs group while keeping
> that group hidden for devices and platforms that do not meet the
> requirements. In a PCI topology, most devices will not support
> authentication, a small subset will support just PCI CMA (Component
> Measurement and Authentication), a smaller subset will support PCI CMA +
> PCIe IDE (Link Integrity and Encryption), and only next generation
> server hosts will start to include a platform TSM (TEE Security
> Manager).
> 
> Without this capability the alternatives are:
> 
> * Check if all attributes are invisible and if so, hide the directory.
>   Beyond trouble getting this to work [1], this is an ABI change for
>   scenarios if userspace happens to depend on group visibility absent any
>   attributes. I.e. this new capability avoids regression since it does
>   not retroactively apply to existing cases.
> 
> * Publish an empty /sys/bus/pci/devices/$pdev/tsm/ directory for all PCI
>   devices (i.e. for the case when TSM platform support is present, but
>   device support is absent). Unfortunate that this will be a vestigial
>   empty directory in the vast majority of cases.
> 
> * Reintroduce usage of runtime calls to sysfs_{create,remove}_group()
>   in the PCI core. Bjorn has already indicated that he does not want to
>   see any growth of pci_sysfs_init() [2].
> 
> * Drop the named group and simulate a directory by prefixing all
>   TSM-related attributes with "tsm_". Unfortunate to not use the naming
>   capability of a sysfs group as intended.
> 
> In comparison, there is a small potential for regression if for some
> reason an @is_visible() callback had dependencies on how many times it
> was called.

Great changelog, thanks for all of that.

> 
> Link: https://lore.kernel.org/all/2024012321-envious-procedure-4a58@gregkh/ [1]
> Link: https://lore.kernel.org/linux-pci/20231019200110.GA1410324@bhelgaas/ [2]
> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
> ---
>  fs/sysfs/group.c      | 64 ++++++++++++++++++++++++++++++++------
>  include/linux/sysfs.h | 71 +++++++++++++++++++++++++++++++++++--------
>  2 files changed, 114 insertions(+), 21 deletions(-)
> 
> diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
> index 138676463336..90dd98c82776 100644
> --- a/fs/sysfs/group.c
> +++ b/fs/sysfs/group.c
> @@ -31,6 +31,17 @@ static void remove_files(struct kernfs_node *parent,
>  			kernfs_remove_by_name(parent, (*bin_attr)->attr.name);
>  }
>  
> +static umode_t __first_visible(const struct attribute_group *grp, struct kobject *kobj)
> +{
> +	if (grp->attrs && grp->is_visible)
> +		return grp->is_visible(kobj, grp->attrs[0], 0);
> +
> +	if (grp->bin_attrs && grp->is_bin_visible)
> +		return grp->is_bin_visible(kobj, grp->bin_attrs[0], 0);

This kind of makes sense, but why the first attribute only?  I guess we
have to pick one?

> +
> +	return 0;
> +}
> +
>  static int create_files(struct kernfs_node *parent, struct kobject *kobj,
>  			kuid_t uid, kgid_t gid,
>  			const struct attribute_group *grp, int update)
> @@ -52,6 +63,7 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
>  				kernfs_remove_by_name(parent, (*attr)->name);
>  			if (grp->is_visible) {
>  				mode = grp->is_visible(kobj, *attr, i);
> +				mode &= ~SYSFS_GROUP_VISIBLE_MASK;
>  				if (!mode)
>  					continue;
>  			}
> @@ -81,6 +93,7 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
>  						(*bin_attr)->attr.name);
>  			if (grp->is_bin_visible) {
>  				mode = grp->is_bin_visible(kobj, *bin_attr, i);
> +				mode &= ~SYSFS_GROUP_VISIBLE_MASK;
>  				if (!mode)
>  					continue;
>  			}
> @@ -127,16 +140,35 @@ static int internal_create_group(struct kobject *kobj, int update,
>  
>  	kobject_get_ownership(kobj, &uid, &gid);
>  	if (grp->name) {
> +		umode_t mode = __first_visible(grp, kobj);
> +		bool has_group_visible = mode & SYSFS_HAS_GROUP_VISIBLE;
> +
> +		if (has_group_visible && (mode & SYSFS_GROUP_INVISIBLE))

These new SYSFS_*_GROUP values are confusing me, more below:

> +			mode = 0;
> +		else
> +			mode = S_IRWXU | S_IRUGO | S_IXUGO;
> +
>  		if (update) {
>  			kn = kernfs_find_and_get(kobj->sd, grp->name);
>  			if (!kn) {
> -				pr_warn("Can't update unknown attr grp name: %s/%s\n",
> -					kobj->name, grp->name);
> -				return -EINVAL;
> +				if (!has_group_visible) {
> +					pr_warn("Can't update unknown attr grp name: %s/%s\n",
> +						kobj->name, grp->name);
> +					return -EINVAL;
> +				}
> +				/* may have been invisible prior to this update */
> +				update = 0;
> +			} else if (!mode) {
> +				sysfs_remove_group(kobj, grp);
> +				kernfs_put(kn);
> +				return 0;
>  			}
> -		} else {
> -			kn = kernfs_create_dir_ns(kobj->sd, grp->name,
> -						  S_IRWXU | S_IRUGO | S_IXUGO,
> +		}
> +
> +		if (!update) {
> +			if (!mode)
> +				return 0;
> +			kn = kernfs_create_dir_ns(kobj->sd, grp->name, mode,
>  						  uid, gid, kobj, NULL);
>  			if (IS_ERR(kn)) {
>  				if (PTR_ERR(kn) == -EEXIST)
> @@ -262,6 +294,22 @@ int sysfs_update_group(struct kobject *kobj,
>  }
>  EXPORT_SYMBOL_GPL(sysfs_update_group);
>  
> +static void warn_group_not_found(const struct attribute_group *grp,
> +				 struct kobject *kobj)
> +{
> +	umode_t mode = __first_visible(grp, kobj);
> +
> +	if (mode & SYSFS_HAS_GROUP_VISIBLE) {
> +		/* may have never been created */
> +		pr_debug("sysfs group '%s' not found for kobject '%s'\n",
> +			 grp->name, kobject_name(kobj));
> +		return;

So if the group is visible somehow, but not found, then it's ok?  But:


> +	}
> +
> +	WARN(1, KERN_WARNING "sysfs group '%s' not found for kobject '%s'\n",
> +	     grp->name, kobject_name(kobj));

We crash the box if it was not visible and not found?


> +}
> +
>  /**
>   * sysfs_remove_group: remove a group from a kobject
>   * @kobj:	kobject to remove the group from
> @@ -279,9 +327,7 @@ void sysfs_remove_group(struct kobject *kobj,
>  	if (grp->name) {
>  		kn = kernfs_find_and_get(parent, grp->name);
>  		if (!kn) {
> -			WARN(!kn, KERN_WARNING
> -			     "sysfs group '%s' not found for kobject '%s'\n",
> -			     grp->name, kobject_name(kobj));
> +			warn_group_not_found(grp, kobj);

We really should not WARN(), but I guess we don't ever get reports of
this so it's ok.

>  			return;
>  		}
>  	} else {
> diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
> index b717a70219f6..4fb4f4da003a 100644
> --- a/include/linux/sysfs.h
> +++ b/include/linux/sysfs.h
> @@ -62,21 +62,32 @@ do {							\
>   * struct attribute_group - data structure used to declare an attribute group.
>   * @name:	Optional: Attribute group name
>   *		If specified, the attribute group will be created in
> - *		a new subdirectory with this name.
> + *		a new subdirectory with this name. Additionally when a
> + *		group is named, @is_visible and @is_bin_visible may
> + *		return SYSFS_HAS_GROUP_VISIBLE | SYSFS_GROUP_INVISIBLE
> + *		to control visibility of the directory itself. If
> + *		SYSFS_GROUP_INVISIBLE is ever to be returned,
> + *		SYSFS_HAS_GROUP_VISIBLE must always be included in the
> + *		return value from @is_visible and @is_bin_visible. See
> + *		the DEFINE_SYSFS_GROUP_VISIBLE() helper.

Here it gets confusing for me.  Why are you saying things like
SYSFS_HAS_GROUP_VISIBLE and SYSFS_GROUP_INVISIBLE, when your example
shows none of that at all?  Shouldn't this all be internal-to-sysfs
stuff?  Why list it here?


>   * @is_visible:	Optional: Function to return permissions associated with an
> - *		attribute of the group. Will be called repeatedly for each
> - *		non-binary attribute in the group. Only read/write
> - *		permissions as well as SYSFS_PREALLOC are accepted. Must
> - *		return 0 if an attribute is not visible. The returned value
> - *		will replace static permissions defined in struct attribute.
> + *		attribute of the group. Will be called repeatedly for
> + *		each non-binary attribute in the group. Only read/write
> + *		permissions as well as SYSFS_PREALLOC (and the
> + *		visibility flags for named groups) are accepted. Must
> + *		return 0 (or just SYSFS_HAS_GROUP_VISIBLE) if an
> + *		attribute is not visible. The returned value will
> + *		replace static permissions defined in struct attribute.
>   * @is_bin_visible:
>   *		Optional: Function to return permissions associated with a
>   *		binary attribute of the group. Will be called repeatedly
>   *		for each binary attribute in the group. Only read/write
> - *		permissions as well as SYSFS_PREALLOC are accepted. Must
> - *		return 0 if a binary attribute is not visible. The returned
> - *		value will replace static permissions defined in
> - *		struct bin_attribute.
> + *		permissions as well as SYSFS_PREALLOC (and the
> + *		visibility flags for named groups) are accepted. Must
> + *		return 0 (or just SYSFS_HAS_GROUP_VISIBLE) if a binary
> + *		attribute is not visible. The returned value will
> + *		replace static permissions defined in struct
> + *		bin_attribute.
>   * @attrs:	Pointer to NULL terminated list of attributes.
>   * @bin_attrs:	Pointer to NULL terminated list of binary attributes.
>   *		Either attrs or bin_attrs or both must be provided.
> @@ -91,13 +102,49 @@ struct attribute_group {
>  	struct bin_attribute	**bin_attrs;
>  };
>  
> +#define SYSFS_PREALLOC		010000
> +#define SYSFS_HAS_GROUP_VISIBLE 020000

Nit, forgot a tab :(

> +#define SYSFS_GROUP_INVISIBLE	040000
> +#define SYSFS_GROUP_VISIBLE_MASK (SYSFS_HAS_GROUP_VISIBLE|SYSFS_GROUP_INVISIBLE)

Ackward defines, "HAS_GROUP_VISABLE" vs. "GROUP_INVISIBLE"?  Why not
just "GROUP_VISIBLE" and "GROUP_INVISIBLE"?


> +
> +static inline umode_t sysfs_group_visible(umode_t mode)
> +{
> +	return mode | SYSFS_HAS_GROUP_VISIBLE;

So if mode is 0, then we return visible?  is that really correct?

> +}
> +
> +/*
> + * The first call to is_visible() in the create / update path may
> + * indicate visibility for the entire group
> + */
> +#define DEFINE_SYSFS_GROUP_VISIBLE(name)                                \
> +static inline umode_t sysfs_group_visible_##name(                       \
> +	struct kobject *kobj, struct attribute *attr, int n)            \
> +{                                                                       \
> +	if (n == 0 && !name##_group_visible(kobj))			\
> +		return sysfs_group_visible(SYSFS_GROUP_INVISIBLE);      \

This reads really funny, we are passing in "invisible" to a "visible"
function call :)

Why pass anything in here?  I really have a hard time parsing this,
maybe because of the negative of the "*_group_visible()" call?


> +	return sysfs_group_visible(name##_attr_visible(kobj, attr, n)); \

But you only call this on the first attribute, right?  I kind of
understand that, but documenting it a bit better here might help?

Anyway, basic structure I like, changes for a driver to use this I love,
but implementation confuses me, and if I have to maintain it for the
next 20+ years, and can't understand it on day 1, I'm going to be in
trouble soon, which makes me wary to take this as-is.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 2/3] sysfs: Add a attr_is_visible function to attribute_group
  2024-01-28  0:21                                       ` Greg KH
@ 2024-01-28  1:42                                         ` Dan Williams
  2024-01-28 14:53                                           ` Greg KH
  0 siblings, 1 reply; 28+ messages in thread
From: Dan Williams @ 2024-01-28  1:42 UTC (permalink / raw)
  To: Greg KH, Dan Williams
  Cc: Alistair Francis, bhelgaas, linux-pci, Jonathan.Cameron, lukas,
	alex.williamson, christian.koenig, kch, logang, linux-kernel,
	chaitanyak, rdunlap, Alistair Francis

Greg KH wrote:
[..]
> > diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
> > index 138676463336..90dd98c82776 100644
> > --- a/fs/sysfs/group.c
> > +++ b/fs/sysfs/group.c
> > @@ -31,6 +31,17 @@ static void remove_files(struct kernfs_node *parent,
> >  			kernfs_remove_by_name(parent, (*bin_attr)->attr.name);
> >  }
> >  
> > +static umode_t __first_visible(const struct attribute_group *grp, struct kobject *kobj)
> > +{
> > +	if (grp->attrs && grp->is_visible)
> > +		return grp->is_visible(kobj, grp->attrs[0], 0);
> > +
> > +	if (grp->bin_attrs && grp->is_bin_visible)
> > +		return grp->is_bin_visible(kobj, grp->bin_attrs[0], 0);
> 
> This kind of makes sense, but why the first attribute only?  I guess we
> have to pick one?

Yeah, to not confuse existing implementations is_visible() must always be
passed a valid @attr argument, so might as well pick first available.

> > +
> > +	return 0;
> > +}
> > +
> >  static int create_files(struct kernfs_node *parent, struct kobject *kobj,
> >  			kuid_t uid, kgid_t gid,
> >  			const struct attribute_group *grp, int update)
> > @@ -52,6 +63,7 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
> >  				kernfs_remove_by_name(parent, (*attr)->name);
> >  			if (grp->is_visible) {
> >  				mode = grp->is_visible(kobj, *attr, i);
> > +				mode &= ~SYSFS_GROUP_VISIBLE_MASK;
> >  				if (!mode)
> >  					continue;
> >  			}
> > @@ -81,6 +93,7 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
> >  						(*bin_attr)->attr.name);
> >  			if (grp->is_bin_visible) {
> >  				mode = grp->is_bin_visible(kobj, *bin_attr, i);
> > +				mode &= ~SYSFS_GROUP_VISIBLE_MASK;
> >  				if (!mode)
> >  					continue;
> >  			}
> > @@ -127,16 +140,35 @@ static int internal_create_group(struct kobject *kobj, int update,
> >  
> >  	kobject_get_ownership(kobj, &uid, &gid);
> >  	if (grp->name) {
> > +		umode_t mode = __first_visible(grp, kobj);
> > +		bool has_group_visible = mode & SYSFS_HAS_GROUP_VISIBLE;
> > +
> > +		if (has_group_visible && (mode & SYSFS_GROUP_INVISIBLE))
> 
> These new SYSFS_*_GROUP values are confusing me, more below:

Ok, SYSFS_HAS_GROUP_VISIBLE is mainly about preserving the long standing
WARN() behavior that flags broken usage of sysfs. If you are open to
dropping strictness I think this can be simplified.

> 
> > +			mode = 0;
> > +		else
> > +			mode = S_IRWXU | S_IRUGO | S_IXUGO;
> > +
> >  		if (update) {
> >  			kn = kernfs_find_and_get(kobj->sd, grp->name);
> >  			if (!kn) {
> > -				pr_warn("Can't update unknown attr grp name: %s/%s\n",
> > -					kobj->name, grp->name);
> > -				return -EINVAL;
> > +				if (!has_group_visible) {
> > +					pr_warn("Can't update unknown attr grp name: %s/%s\n",
> > +						kobj->name, grp->name);
> > +					return -EINVAL;
> > +				}
> > +				/* may have been invisible prior to this update */
> > +				update = 0;
> > +			} else if (!mode) {
> > +				sysfs_remove_group(kobj, grp);
> > +				kernfs_put(kn);
> > +				return 0;
> >  			}
> > -		} else {
> > -			kn = kernfs_create_dir_ns(kobj->sd, grp->name,
> > -						  S_IRWXU | S_IRUGO | S_IXUGO,
> > +		}
> > +
> > +		if (!update) {
> > +			if (!mode)
> > +				return 0;
> > +			kn = kernfs_create_dir_ns(kobj->sd, grp->name, mode,
> >  						  uid, gid, kobj, NULL);
> >  			if (IS_ERR(kn)) {
> >  				if (PTR_ERR(kn) == -EEXIST)
> > @@ -262,6 +294,22 @@ int sysfs_update_group(struct kobject *kobj,
> >  }
> >  EXPORT_SYMBOL_GPL(sysfs_update_group);
> >  
> > +static void warn_group_not_found(const struct attribute_group *grp,
> > +				 struct kobject *kobj)
> > +{
> > +	umode_t mode = __first_visible(grp, kobj);
> > +
> > +	if (mode & SYSFS_HAS_GROUP_VISIBLE) {
> > +		/* may have never been created */
> > +		pr_debug("sysfs group '%s' not found for kobject '%s'\n",
> > +			 grp->name, kobject_name(kobj));
> > +		return;
> 
> So if the group is visible somehow, but not found, then it's ok?  But:
> 
> 
> > +	}
> > +
> > +	WARN(1, KERN_WARNING "sysfs group '%s' not found for kobject '%s'\n",
> > +	     grp->name, kobject_name(kobj));
> 
> We crash the box if it was not visible and not found?

Yes, but only for preservation of legacy strictness. In other words,
without the new "has" flag this is as an unambiguous misuse of sysfs
APIs. With the "has" flag it is no long definitive that someone messed
up.

My preference is delete the WARN() and the "has" flag if you're open to
that.

> > +}
> > +
> >  /**
> >   * sysfs_remove_group: remove a group from a kobject
> >   * @kobj:	kobject to remove the group from
> > @@ -279,9 +327,7 @@ void sysfs_remove_group(struct kobject *kobj,
> >  	if (grp->name) {
> >  		kn = kernfs_find_and_get(parent, grp->name);
> >  		if (!kn) {
> > -			WARN(!kn, KERN_WARNING
> > -			     "sysfs group '%s' not found for kobject '%s'\n",
> > -			     grp->name, kobject_name(kobj));
> > +			warn_group_not_found(grp, kobj);
> 
> We really should not WARN(), but I guess we don't ever get reports of
> this so it's ok.

It's one of those "should only fire on the kernel developer's system
during development" WARN()s, and per above if it's not adding value, it
is now adding complexity for this group visibility feature.

> 
> >  			return;
> >  		}
> >  	} else {
> > diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
> > index b717a70219f6..4fb4f4da003a 100644
> > --- a/include/linux/sysfs.h
> > +++ b/include/linux/sysfs.h
> > @@ -62,21 +62,32 @@ do {							\
> >   * struct attribute_group - data structure used to declare an attribute group.
> >   * @name:	Optional: Attribute group name
> >   *		If specified, the attribute group will be created in
> > - *		a new subdirectory with this name.
> > + *		a new subdirectory with this name. Additionally when a
> > + *		group is named, @is_visible and @is_bin_visible may
> > + *		return SYSFS_HAS_GROUP_VISIBLE | SYSFS_GROUP_INVISIBLE
> > + *		to control visibility of the directory itself. If
> > + *		SYSFS_GROUP_INVISIBLE is ever to be returned,
> > + *		SYSFS_HAS_GROUP_VISIBLE must always be included in the
> > + *		return value from @is_visible and @is_bin_visible. See
> > + *		the DEFINE_SYSFS_GROUP_VISIBLE() helper.
> 
> Here it gets confusing for me.  Why are you saying things like
> SYSFS_HAS_GROUP_VISIBLE and SYSFS_GROUP_INVISIBLE, when your example
> shows none of that at all?  Shouldn't this all be internal-to-sysfs
> stuff?  Why list it here?

True. I took my cue from the fact that SYSFS_PREALLOC is mentioned in
the documentation even though it is only ever used internally by the
attribute definition macros. I can trim to only the user documentation.

> >   * @is_visible:	Optional: Function to return permissions associated with an
> > - *		attribute of the group. Will be called repeatedly for each
> > - *		non-binary attribute in the group. Only read/write
> > - *		permissions as well as SYSFS_PREALLOC are accepted. Must
> > - *		return 0 if an attribute is not visible. The returned value
> > - *		will replace static permissions defined in struct attribute.
> > + *		attribute of the group. Will be called repeatedly for
> > + *		each non-binary attribute in the group. Only read/write
> > + *		permissions as well as SYSFS_PREALLOC (and the
> > + *		visibility flags for named groups) are accepted. Must
> > + *		return 0 (or just SYSFS_HAS_GROUP_VISIBLE) if an
> > + *		attribute is not visible. The returned value will
> > + *		replace static permissions defined in struct attribute.
> >   * @is_bin_visible:
> >   *		Optional: Function to return permissions associated with a
> >   *		binary attribute of the group. Will be called repeatedly
> >   *		for each binary attribute in the group. Only read/write
> > - *		permissions as well as SYSFS_PREALLOC are accepted. Must
> > - *		return 0 if a binary attribute is not visible. The returned
> > - *		value will replace static permissions defined in
> > - *		struct bin_attribute.
> > + *		permissions as well as SYSFS_PREALLOC (and the
> > + *		visibility flags for named groups) are accepted. Must
> > + *		return 0 (or just SYSFS_HAS_GROUP_VISIBLE) if a binary
> > + *		attribute is not visible. The returned value will
> > + *		replace static permissions defined in struct
> > + *		bin_attribute.
> >   * @attrs:	Pointer to NULL terminated list of attributes.
> >   * @bin_attrs:	Pointer to NULL terminated list of binary attributes.
> >   *		Either attrs or bin_attrs or both must be provided.
> > @@ -91,13 +102,49 @@ struct attribute_group {
> >  	struct bin_attribute	**bin_attrs;
> >  };
> >  
> > +#define SYSFS_PREALLOC		010000
> > +#define SYSFS_HAS_GROUP_VISIBLE 020000
> 
> Nit, forgot a tab :(

Fixed.

> > +#define SYSFS_GROUP_INVISIBLE	040000
> > +#define SYSFS_GROUP_VISIBLE_MASK (SYSFS_HAS_GROUP_VISIBLE|SYSFS_GROUP_INVISIBLE)
> 
> Ackward defines, "HAS_GROUP_VISABLE" vs. "GROUP_INVISIBLE"?  Why not
> just "GROUP_VISIBLE" and "GROUP_INVISIBLE"?

Yeah, this "has" thing is only about preserving the WARN regime, the
other is reflecting the state.

> > +
> > +static inline umode_t sysfs_group_visible(umode_t mode)
> > +{
> > +	return mode | SYSFS_HAS_GROUP_VISIBLE;
> 
> So if mode is 0, then we return visible?  is that really correct?

If the mode is zero we return, "oh by the way, this attribute group
potentially has variable visibility, so don't assume that failures to
find the directory already created at sysfs_update_group() time are
fatal"

Just explaining it that way convinces me it is time for those failure
cases to go.

> > +/*
> > + * The first call to is_visible() in the create / update path may
> > + * indicate visibility for the entire group
> > + */
> > +#define DEFINE_SYSFS_GROUP_VISIBLE(name)                                \
> > +static inline umode_t sysfs_group_visible_##name(                       \
> > +	struct kobject *kobj, struct attribute *attr, int n)            \
> > +{                                                                       \
> > +	if (n == 0 && !name##_group_visible(kobj))			\
> > +		return sysfs_group_visible(SYSFS_GROUP_INVISIBLE);      \
> 
> This reads really funny, we are passing in "invisible" to a "visible"
> function call :)
> 
> Why pass anything in here?  I really have a hard time parsing this,
> maybe because of the negative of the "*_group_visible()" call?
> 
> 
> > +	return sysfs_group_visible(name##_attr_visible(kobj, attr, n)); \
> 
> But you only call this on the first attribute, right?  I kind of
> understand that, but documenting it a bit better here might help?
> 
> Anyway, basic structure I like, changes for a driver to use this I love,
> but implementation confuses me, and if I have to maintain it for the
> next 20+ years, and can't understand it on day 1, I'm going to be in
> trouble soon, which makes me wary to take this as-is.

Here it is again without being beholden to keeping the old
WARN()/pr_warn() regime when the group directory is not found.

-- >8 --
From 8fe87d28bb9517e4010d567ec7025acf2b8b2440 Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Sat, 27 Jan 2024 17:37:44 -0800
Subject: [PATCH v3] sysfs: Introduce a mechanism to hide static attribute_groups

Add a mechanism for named attribute_groups to hide their directory at
sysfs_update_group() time, or otherwise skip emitting the group
directory when the group is first registered. It piggybacks on
is_visible() in a similar manner as SYSFS_PREALLOC, i.e. special flags
in the upper bits of the returned mode. To use it, specify a symbol
prefix to DEFINE_SYSFS_GROUP_VISIBLE(), and then pass that same prefix
to SYSFS_GROUP_VISIBLE() when assigning the @is_visible() callback:

	DEFINE_SYSFS_GROUP_VISIBLE($prefix)

	struct attribute_group $prefix_group = {
		.name = $name,
		.is_visible = SYSFS_GROUP_VISIBLE($prefix),
	};

SYSFS_GROUP_VISIBLE() expects a definition of $prefix_group_visible()
and $prefix_attr_visible(), where $prefix_group_visible() just returns
true / false and $prefix_attr_visible() behaves as normal.

The motivation for this capability is to centralize PCI device
authentication in the PCI core with a named sysfs group while keeping
that group hidden for devices and platforms that do not meet the
requirements. In a PCI topology, most devices will not support
authentication, a small subset will support just PCI CMA (Component
Measurement and Authentication), a smaller subset will support PCI CMA +
PCIe IDE (Link Integrity and Encryption), and only next generation
server hosts will start to include a platform TSM (TEE Security
Manager).

Without this capability the alternatives are:

* Check if all attributes are invisible and if so, hide the directory.
  Beyond trouble getting this to work [1], this is an ABI change for
  scenarios if userspace happens to depend on group visibility absent any
  attributes. I.e. this new capability avoids regression since it does
  not retroactively apply to existing cases.

* Publish an empty /sys/bus/pci/devices/$pdev/tsm/ directory for all PCI
  devices (i.e. for the case when TSM platform support is present, but
  device support is absent). Unfortunate that this will be a vestigial
  empty directory in the vast majority of cases.

* Reintroduce usage of runtime calls to sysfs_{create,remove}_group()
  in the PCI core. Bjorn has already indicated that he does not want to
  see any growth of pci_sysfs_init() [2].

* Drop the named group and simulate a directory by prefixing all
  TSM-related attributes with "tsm_". Unfortunate to not use the naming
  capability of a sysfs group as intended.

In comparison, there is a small potential for regression if for some
reason an @is_visible() callback had dependencies on how many times it
was called. Additionally, it is no longer an error to update a group
that does not have its directory already present, and it is no longer a
WARN() to remove a group that was never visible.

Link: https://lore.kernel.org/all/2024012321-envious-procedure-4a58@gregkh/ [1]
Link: https://lore.kernel.org/linux-pci/20231019200110.GA1410324@bhelgaas/ [2]
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 fs/sysfs/group.c      | 45 ++++++++++++++++++++++++-------
 include/linux/sysfs.h | 63 ++++++++++++++++++++++++++++++++++---------
 2 files changed, 87 insertions(+), 21 deletions(-)

diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
index 138676463336..ccb275cdabcb 100644
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -31,6 +31,17 @@ static void remove_files(struct kernfs_node *parent,
 			kernfs_remove_by_name(parent, (*bin_attr)->attr.name);
 }
 
+static umode_t __first_visible(const struct attribute_group *grp, struct kobject *kobj)
+{
+	if (grp->attrs && grp->is_visible)
+		return grp->is_visible(kobj, grp->attrs[0], 0);
+
+	if (grp->bin_attrs && grp->is_bin_visible)
+		return grp->is_bin_visible(kobj, grp->bin_attrs[0], 0);
+
+	return 0;
+}
+
 static int create_files(struct kernfs_node *parent, struct kobject *kobj,
 			kuid_t uid, kgid_t gid,
 			const struct attribute_group *grp, int update)
@@ -52,6 +63,7 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
 				kernfs_remove_by_name(parent, (*attr)->name);
 			if (grp->is_visible) {
 				mode = grp->is_visible(kobj, *attr, i);
+				mode &= ~SYSFS_GROUP_INVISIBLE;
 				if (!mode)
 					continue;
 			}
@@ -81,6 +93,7 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
 						(*bin_attr)->attr.name);
 			if (grp->is_bin_visible) {
 				mode = grp->is_bin_visible(kobj, *bin_attr, i);
+				mode &= ~SYSFS_GROUP_INVISIBLE;
 				if (!mode)
 					continue;
 			}
@@ -127,16 +140,31 @@ static int internal_create_group(struct kobject *kobj, int update,
 
 	kobject_get_ownership(kobj, &uid, &gid);
 	if (grp->name) {
+		umode_t mode = __first_visible(grp, kobj);
+
+		if (mode & SYSFS_GROUP_INVISIBLE)
+			mode = 0;
+		else
+			mode = S_IRWXU | S_IRUGO | S_IXUGO;
+
 		if (update) {
 			kn = kernfs_find_and_get(kobj->sd, grp->name);
 			if (!kn) {
-				pr_warn("Can't update unknown attr grp name: %s/%s\n",
-					kobj->name, grp->name);
-				return -EINVAL;
+				pr_debug("attr grp %s/%s not created yet\n",
+					 kobj->name, grp->name);
+				/* may have been invisible prior to this update */
+				update = 0;
+			} else if (!mode) {
+				sysfs_remove_group(kobj, grp);
+				kernfs_put(kn);
+				return 0;
 			}
-		} else {
-			kn = kernfs_create_dir_ns(kobj->sd, grp->name,
-						  S_IRWXU | S_IRUGO | S_IXUGO,
+		}
+
+		if (!update) {
+			if (!mode)
+				return 0;
+			kn = kernfs_create_dir_ns(kobj->sd, grp->name, mode,
 						  uid, gid, kobj, NULL);
 			if (IS_ERR(kn)) {
 				if (PTR_ERR(kn) == -EEXIST)
@@ -279,9 +307,8 @@ void sysfs_remove_group(struct kobject *kobj,
 	if (grp->name) {
 		kn = kernfs_find_and_get(parent, grp->name);
 		if (!kn) {
-			WARN(!kn, KERN_WARNING
-			     "sysfs group '%s' not found for kobject '%s'\n",
-			     grp->name, kobject_name(kobj));
+			pr_debug("sysfs group '%s' not found for kobject '%s'\n",
+				 grp->name, kobject_name(kobj));
 			return;
 		}
 	} else {
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index b717a70219f6..a42642b277dd 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -61,22 +61,32 @@ do {							\
 /**
  * struct attribute_group - data structure used to declare an attribute group.
  * @name:	Optional: Attribute group name
- *		If specified, the attribute group will be created in
- *		a new subdirectory with this name.
+ *		If specified, the attribute group will be created in a
+ *		new subdirectory with this name. Additionally when a
+ *		group is named, @is_visible and @is_bin_visible may
+ *		return SYSFS_GROUP_INVISIBLE to control visibility of
+ *		the directory itself.
  * @is_visible:	Optional: Function to return permissions associated with an
- *		attribute of the group. Will be called repeatedly for each
- *		non-binary attribute in the group. Only read/write
+ *		attribute of the group. Will be called repeatedly for
+ *		each non-binary attribute in the group. Only read/write
  *		permissions as well as SYSFS_PREALLOC are accepted. Must
- *		return 0 if an attribute is not visible. The returned value
- *		will replace static permissions defined in struct attribute.
+ *		return 0 if an attribute is not visible. The returned
+ *		value will replace static permissions defined in struct
+ *		attribute. Use SYSFS_GROUP_VISIBLE() when assigning this
+ *		callback to specify separate _group_visible() and
+ *		_attr_visible() handlers.
  * @is_bin_visible:
  *		Optional: Function to return permissions associated with a
  *		binary attribute of the group. Will be called repeatedly
  *		for each binary attribute in the group. Only read/write
- *		permissions as well as SYSFS_PREALLOC are accepted. Must
- *		return 0 if a binary attribute is not visible. The returned
- *		value will replace static permissions defined in
- *		struct bin_attribute.
+ *		permissions as well as SYSFS_PREALLOC (and the
+ *		visibility flags for named groups) are accepted. Must
+ *		return 0 if a binary attribute is not visible. The
+ *		returned value will replace static permissions defined
+ *		in struct bin_attribute. If @is_visible is not set, Use
+ *		SYSFS_GROUP_VISIBLE() when assigning this callback to
+ *		specify separate _group_visible() and _attr_visible()
+ *		handlers.
  * @attrs:	Pointer to NULL terminated list of attributes.
  * @bin_attrs:	Pointer to NULL terminated list of binary attributes.
  *		Either attrs or bin_attrs or both must be provided.
@@ -91,13 +101,42 @@ struct attribute_group {
 	struct bin_attribute	**bin_attrs;
 };
 
+#define SYSFS_PREALLOC		010000
+#define SYSFS_GROUP_INVISIBLE	020000
+
+/*
+ * The first call to is_visible() in the create / update path may
+ * indicate visibility for the entire group
+ */
+#define DEFINE_SYSFS_GROUP_VISIBLE(name)                             \
+	static inline umode_t sysfs_group_visible_##name(            \
+		struct kobject *kobj, struct attribute *attr, int n) \
+	{                                                            \
+		if (n == 0 && !name##_group_visible(kobj))           \
+			return SYSFS_GROUP_INVISIBLE;                \
+		return name##_attr_visible(kobj, attr, n);           \
+	}
+
+/*
+ * Same as DEFINE_SYSFS_GROUP_VISIBLE, but for groups with only binary
+ * attributes
+ */
+#define DEFINE_SYSFS_BIN_GROUP_VISIBLE(name)                             \
+	static inline umode_t sysfs_group_visible_##name(                \
+		struct kobject *kobj, struct bin_attribute *attr, int n) \
+	{                                                                \
+		if (n == 0 && !name##_group_visible(kobj))               \
+			return SYSFS_GROUP_INVISIBLE;                    \
+		return name##_attr_visible(kobj, attr, n);               \
+	}
+
+#define SYSFS_GROUP_VISIBLE(fn) sysfs_group_visible_##fn
+
 /*
  * Use these macros to make defining attributes easier.
  * See include/linux/device.h for examples..
  */
 
-#define SYSFS_PREALLOC 010000
-
 #define __ATTR(_name, _mode, _show, _store) {				\
 	.attr = {.name = __stringify(_name),				\
 		 .mode = VERIFY_OCTAL_PERMISSIONS(_mode) },		\
-- 
2.43.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 2/3] sysfs: Add a attr_is_visible function to attribute_group
  2024-01-28  1:42                                         ` Dan Williams
@ 2024-01-28 14:53                                           ` Greg KH
  0 siblings, 0 replies; 28+ messages in thread
From: Greg KH @ 2024-01-28 14:53 UTC (permalink / raw)
  To: Dan Williams
  Cc: Alistair Francis, bhelgaas, linux-pci, Jonathan.Cameron, lukas,
	alex.williamson, christian.koenig, kch, logang, linux-kernel,
	chaitanyak, rdunlap, Alistair Francis

On Sat, Jan 27, 2024 at 05:42:54PM -0800, Dan Williams wrote:
> Here it is again without being beholden to keeping the old
> WARN()/pr_warn() regime when the group directory is not found.

Thanks for all of the response to my questions, much appreciated.  I
think this looks great, let me test it here and add it to the patch
series which caused me to want to do this in the first place and see how
it goes.  Give me a day or so, thanks so much I owe you a lot for
digging into this!

greg k-h

^ permalink raw reply	[flat|nested] 28+ messages in thread

end of thread, other threads:[~2024-01-28 14:53 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-17 23:58 [PATCH v6 1/3] PCI/DOE: Expose the DOE features via sysfs Alistair Francis
2023-08-17 23:58 ` [PATCH v6 2/3] sysfs: Add a attr_is_visible function to attribute_group Alistair Francis
2023-08-18  0:35   ` Damien Le Moal
2023-08-19 10:57   ` Greg KH
2023-08-22 20:20     ` Alistair Francis
2023-08-23  7:02       ` Greg KH
2023-08-28  5:05         ` Alistair Francis
2023-08-31  8:31           ` Greg KH
2023-08-31 14:36             ` Greg KH
2023-09-01 21:00               ` Greg KH
2023-10-05 13:05                 ` Greg KH
2023-10-11  5:10                   ` Alistair Francis
2023-10-11  6:44                     ` Greg KH
2023-10-12  4:31                       ` Alistair Francis
2024-01-23  4:04                         ` Alistair Francis
2024-01-23 12:25                           ` Greg KH
2024-01-24 20:31                             ` Dan Williams
2024-01-26 18:58                               ` Dan Williams
2024-01-26 19:07                                 ` Greg KH
2024-01-26 20:08                                   ` Dan Williams
2024-01-27  3:00                                     ` Dan Williams
2024-01-28  0:21                                       ` Greg KH
2024-01-28  1:42                                         ` Dan Williams
2024-01-28 14:53                                           ` Greg KH
2023-08-17 23:58 ` [PATCH v6 3/3] PCI/DOE: Only expose the sysfs attribute group if DOE is supported Alistair Francis
2023-08-18  4:52 ` [PATCH v6 1/3] PCI/DOE: Expose the DOE features via sysfs Chaitanya Kulkarni
2023-08-18  5:48 ` kernel test robot
2023-08-21 21:07 ` kernel test robot

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.