From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: htejun@gmail.com, linux-kernel@vger.kernel.org
Subject: [PATCH] sysfs: add devm_sysfs_create_group() and friends
Date: Fri, 30 Oct 2015 04:47:06 -0700 [thread overview]
Message-ID: <20151030114706.GA2243@localhost> (raw)
Many drivers create additional driver-specific device attributes when
binding to the device and providing managed version of sysfs_create_group()
will simplify unbinding and error handling in probe path for such drivers.
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
fs/sysfs/group.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/sysfs.h | 10 ++++
2 files changed, 134 insertions(+)
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
index 39a0199..9511437 100644
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -13,6 +13,7 @@
#include <linux/kobject.h>
#include <linux/module.h>
#include <linux/dcache.h>
+#include <linux/device.h>
#include <linux/namei.h>
#include <linux/err.h>
#include "sysfs.h"
@@ -352,3 +353,126 @@ void sysfs_remove_link_from_group(struct kobject *kobj, const char *group_name,
}
}
EXPORT_SYMBOL_GPL(sysfs_remove_link_from_group);
+
+struct sysfs_group_devres {
+ const struct attribute_group *group;
+};
+
+static int devm_sysfs_group_match(struct device *dev, void *res, void *data)
+{
+ return ((struct sysfs_group_devres *)res)->group == data;
+}
+
+static void devm_sysfs_group_remove_group(struct device *dev, void *res)
+{
+ struct sysfs_group_devres *devres = res;
+ const struct attribute_group *group = devres->group;
+
+ dev_dbg(dev, "%s: removing group %p\n", __func__, group);
+ sysfs_remove_group(&dev->kobj, group);
+}
+
+/**
+ * devm_sysfs_create_group - given a device, create a managed attribute group
+ * @dev: The device to create the group for
+ * @grp: The attribute group to create
+ *
+ * This function creates a group for the first time. It will explicitly
+ * warn and error if any of the attribute files being created already exist.
+ *
+ * Returns 0 on success or error code on failure.
+ */
+int devm_sysfs_create_group(struct device *dev,
+ const struct attribute_group *grp)
+{
+ struct sysfs_group_devres *devres;
+ int error;
+
+ devres = devres_alloc(devm_sysfs_group_remove_group,
+ sizeof(*devres), GFP_KERNEL);
+ if (!devres)
+ return -ENOMEM;
+
+ error = sysfs_create_group(&dev->kobj, grp);
+ if (error) {
+ devres_free(devres);
+ return error;
+ }
+
+ devres_add(dev, devres);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(devm_sysfs_create_group);
+
+/**
+ * devm_sysfs_create_groups - create a bunch of managed attribute groups
+ * @dev: The device to create the group for
+ * @groups: The attribute groups to create, NULL terminated
+ *
+ * This function creates a bunch of managed attribute groups. If an error
+ * occurs when creating a group, all previously created groups will be
+ * removed, unwinding everything back to the original state when this
+ * function was called. It will explicitly warn and error if any of the
+ * attribute files being created already exist.
+ *
+ * Returns 0 on success or error code from sysfs_create_group on failure.
+ */
+int devm_sysfs_create_groups(struct device *dev,
+ const struct attribute_group **groups)
+{
+ int error;
+ int i;
+
+ if (!groups)
+ return 0;
+
+ for (i = 0; groups[i]; i++) {
+ error = devm_sysfs_create_group(dev, groups[i]);
+ if (error) {
+ while (--i >= 0)
+ devm_sysfs_remove_group(dev, groups[i]);
+ return error;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(devm_sysfs_create_groups);
+
+/**
+ * devm_sysfs_remove_group: remove a managed group from a device
+ * @dev: device to remove the group from
+ * @grp: group to remove
+ *
+ * This function removes a group of attributes from a device. The attributes
+ * previously have to have been created for this group, otherwise it will fail.
+ */
+void devm_sysfs_remove_group(struct device *dev,
+ const struct attribute_group *grp)
+{
+ WARN_ON(devres_release(dev, devm_sysfs_group_remove_group,
+ devm_sysfs_group_match,
+ /* cast away const */ (void *)grp));
+}
+EXPORT_SYMBOL_GPL(devm_sysfs_remove_group);
+
+/**
+ * devm_sysfs_remove_groups - remove a list of managed groups
+ *
+ * @dev: The device for the groups to be removed from
+ * @groups: NULL terminated list of groups to be removed
+ *
+ * If groups is not NULL, remove the specified groups from the device.
+ */
+void devm_sysfs_remove_groups(struct device *dev,
+ const struct attribute_group **groups)
+{
+ int i;
+
+ if (!groups)
+ return;
+
+ for (i = 0; groups[i]; i++)
+ devm_sysfs_remove_group(dev, groups[i]);
+}
+EXPORT_SYMBOL_GPL(devm_sysfs_remove_groups);
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index 9f65758..b59a913 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -269,6 +269,16 @@ int sysfs_add_link_to_group(struct kobject *kobj, const char *group_name,
void sysfs_remove_link_from_group(struct kobject *kobj, const char *group_name,
const char *link_name);
+struct device;
+int __must_check devm_sysfs_create_group(struct device *dev,
+ const struct attribute_group *grp);
+int __must_check devm_sysfs_create_groups(struct device *dev,
+ const struct attribute_group **groups);
+void devm_sysfs_remove_group(struct device *dev,
+ const struct attribute_group *grp);
+void devm_sysfs_remove_groups(struct device *dev,
+ const struct attribute_group **groups);
+
void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr);
int __must_check sysfs_init(void);
--
1.9.1
--
Dmitry
next reply other threads:[~2015-10-30 11:47 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-10-30 11:47 Dmitry Torokhov [this message]
2015-10-30 14:40 ` [PATCH] sysfs: add devm_sysfs_create_group() and friends Greg Kroah-Hartman
2015-10-30 15:13 ` Dmitry Torokhov
2015-11-07 0:24 ` Greg Kroah-Hartman
2015-11-07 7:23 ` Dmitry Torokhov
2017-06-07 17:12 ` Dmitry Torokhov
2017-06-17 19:28 ` Greg Kroah-Hartman
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20151030114706.GA2243@localhost \
--to=dmitry.torokhov@gmail.com \
--cc=gregkh@linuxfoundation.org \
--cc=htejun@gmail.com \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.