Message ID | 2024013028-deflator-flaring-ec62@gregkh (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Soundwire: clean up sysfs group creation | expand |
On 1/30/24 19:46, Greg Kroah-Hartman wrote: > From: Dan Williams <dan.j.williams@intel.com> > > 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> > Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> This patch seems to introduce a regression on our Lunar Lake test devices, where we can't boot to an ssh shell. No issues on older devices [1]. Bard Liao and I reproduced the same results on different boards. We'll need to find someone with direct device access to provide more information on the problem, remote testing without ssh is a self-negating proposition. Is there a dependency on other patches? Our tests are still based on 6.7.0-rc3 due to other upstream issues we're currently working through. [1] https://github.com/thesofproject/linux/pull/4799
On Wed, Jan 31, 2024 at 02:05:04PM +0100, Pierre-Louis Bossart wrote: > > > On 1/30/24 19:46, Greg Kroah-Hartman wrote: > > From: Dan Williams <dan.j.williams@intel.com> > > > > 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> > > Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> > > This patch seems to introduce a regression on our Lunar Lake test > devices, where we can't boot to an ssh shell. No issues on older devices > [1]. Bard Liao and I reproduced the same results on different boards. > > We'll need to find someone with direct device access to provide more > information on the problem, remote testing without ssh is a > self-negating proposition. > > Is there a dependency on other patches? Our tests are still based on > 6.7.0-rc3 due to other upstream issues we're currently working through. This should be totally stand-alone and not cause any problems, especially if you don't have any other patches applied. I did make this against 6.8-rc2, perhaps that's the issue? thanks, greg k-h
Pierre-Louis Bossart wrote: > > > On 1/30/24 19:46, Greg Kroah-Hartman wrote: > > From: Dan Williams <dan.j.williams@intel.com> > > > > 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> > > Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> > > This patch seems to introduce a regression on our Lunar Lake test > devices, where we can't boot to an ssh shell. No issues on older devices > [1]. Bard Liao and I reproduced the same results on different boards. > > We'll need to find someone with direct device access to provide more > information on the problem, remote testing without ssh is a > self-negating proposition. > > Is there a dependency on other patches? Our tests are still based on > 6.7.0-rc3 due to other upstream issues we're currently working through. The only behavior change I can imagine with this patch is that ->is_visble() callbacks get called extra times for named attribute groups. ...or if an is_visible() callback was inadvertantly already using the SYSFS_GROUP_INVISIBLE flag in umode_t result.
Dan Williams wrote: > Pierre-Louis Bossart wrote: > > > > > > On 1/30/24 19:46, Greg Kroah-Hartman wrote: > > > From: Dan Williams <dan.j.williams@intel.com> > > > > > > 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> > > > Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> > > > > This patch seems to introduce a regression on our Lunar Lake test > > devices, where we can't boot to an ssh shell. No issues on older devices > > [1]. Bard Liao and I reproduced the same results on different boards. > > > > We'll need to find someone with direct device access to provide more > > information on the problem, remote testing without ssh is a > > self-negating proposition. > > > > Is there a dependency on other patches? Our tests are still based on > > 6.7.0-rc3 due to other upstream issues we're currently working through. > > The only behavior change I can imagine with this patch is that > ->is_visble() callbacks get called extra times for named attribute > groups. > > ...or if an is_visible() callback was inadvertantly already using the > SYSFS_GROUP_INVISIBLE flag in umode_t result. Are you able to get kernel logs? A before and after with this patch applied might highlight which attribute does not appreciate the extra callback... diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index ccb275cdabcb..683c0b10990b 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c @@ -33,11 +33,17 @@ static void remove_files(struct kernfs_node *parent, static umode_t __first_visible(const struct attribute_group *grp, struct kobject *kobj) { - if (grp->attrs && grp->is_visible) + if (grp->attrs && grp->is_visible) { + pr_info("kobj: %s is_visible: %pS\n", kobj->name, + grp->is_visible); return grp->is_visible(kobj, grp->attrs[0], 0); + } - if (grp->bin_attrs && grp->is_bin_visible) + if (grp->bin_attrs && grp->is_bin_visible) { + pr_info("kobj: %s is_bin_visible: %pS\n", kobj->name, + grp->is_bin_visible); return grp->is_bin_visible(kobj, grp->bin_attrs[0], 0); + } return 0; } @@ -62,6 +68,8 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj, if (update) kernfs_remove_by_name(parent, (*attr)->name); if (grp->is_visible) { + pr_info("kobj: %s is_visible: %pS\n", + kobj->name, grp->is_visible); mode = grp->is_visible(kobj, *attr, i); mode &= ~SYSFS_GROUP_INVISIBLE; if (!mode) @@ -92,6 +100,8 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj, kernfs_remove_by_name(parent, (*bin_attr)->attr.name); if (grp->is_bin_visible) { + pr_info("kobj: %s is_bin_visible: %pS\n", + kobj->name, grp->is_bin_visible); mode = grp->is_bin_visible(kobj, *bin_attr, i); mode &= ~SYSFS_GROUP_INVISIBLE; if (!mode)
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) }, \