lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Tue, 13 Aug 2013 11:08:37 +0200
From:	Benedikt Spranger <b.spranger@...utronix.de>
To:	netdev@...r.kernel.org
Cc:	Alexander Frank <Alexander.Frank@...rspaecher.com>,
	Sebastian Andrzej Siewior <bigeasy@...utronix.de>,
	Benedikt Spranger <b.spranger@...utronix.de>,
	"Hans J. Koch" <hjk@...sjkoch.de>,
	Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
	Holger Dengler <dengler@...utronix.de>
Subject: [PATCH 2/7] uio: Allow to create custom UIO attributes

This patch the struct uio_attribute which represents a custom UIO
attribute. The non-standard attributes are stored in a "attr" directory.
This will be used by the flexcard driver which creates a UIO device that
is using the "uio_pdrv" and requires one additional value to be read /
written by the user.

Cc: "Hans J. Koch" <hjk@...sjkoch.de>
Cc: Greg Kroah-Hartman <gregkh@...uxfoundation.org>
Signed-off-by: Benedikt Spranger <b.spranger@...utronix.de>
Signed-off-by: Holger Dengler <dengler@...utronix.de>
---
 drivers/uio/uio.c          | 106 ++++++++++++++++++++++++++++++++++++++++++++-
 include/linux/uio_driver.h |  36 +++++++++++----
 2 files changed, 133 insertions(+), 9 deletions(-)

diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index 9a95220..d66784a 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -39,6 +39,7 @@ struct uio_device {
 	struct uio_info		*info;
 	struct kobject		*map_dir;
 	struct kobject		*portio_dir;
+	struct kobject		attr_dir;
 };
 
 static int uio_major;
@@ -252,6 +253,49 @@ static struct device_attribute uio_class_attributes[] = {
 	{}
 };
 
+static ssize_t uio_type_show(struct kobject *kobj, struct attribute *attr,
+			     char *buf)
+{
+	struct uio_device *idev;
+	struct uio_info *info;
+	struct uio_attribute *entry;
+
+	idev = container_of(kobj, struct uio_device, attr_dir);
+	info = idev->info;
+	entry = container_of(attr, struct uio_attribute, attr);
+
+	if (!entry->show)
+		return -EIO;
+
+	return entry->show(info, buf);
+}
+
+static ssize_t uio_type_store(struct kobject *kobj, struct attribute *attr,
+			      const char *buf, size_t count)
+{
+	struct uio_device *idev;
+	struct uio_info *info;
+	struct uio_attribute *entry;
+
+	idev = container_of(kobj, struct uio_device, attr_dir);
+	info = idev->info;
+	entry = container_of(attr, struct uio_attribute, attr);
+
+	if (!entry->store)
+		return -EIO;
+
+	return entry->store(info, buf, count);
+}
+
+static const struct sysfs_ops uio_sysfs_ops = {
+	.show = uio_type_show,
+	.store = uio_type_store,
+};
+
+static struct kobj_type uio_attr_type = {
+	.sysfs_ops	= &uio_sysfs_ops,
+};
+
 /* UIO class infrastructure */
 static struct class uio_class = {
 	.name = "uio",
@@ -323,8 +367,16 @@ static int uio_dev_add_attributes(struct uio_device *idev)
 			goto err_portio;
 	}
 
+	ret = kobject_init_and_add(&idev->attr_dir, &uio_attr_type,
+				   &idev->dev->kobj, "attr");
+	if (ret)
+		goto err_attr;
+
 	return 0;
 
+err_attr:
+	kobject_put(&idev->attr_dir);
+
 err_portio:
 	for (pi--; pi >= 0; pi--) {
 		port = &idev->info->port[pi];
@@ -364,6 +416,7 @@ static void uio_dev_del_attributes(struct uio_device *idev)
 		kobject_put(&port->portio->kobj);
 	}
 	kobject_put(idev->portio_dir);
+	kobject_put(&idev->attr_dir);
 }
 
 static int uio_get_minor(struct uio_device *idev)
@@ -391,6 +444,50 @@ static void uio_free_minor(struct uio_device *idev)
 }
 
 /**
+ * uio_add_user_attributes - add an extra UIO attribute
+ * @info: UIO device capabilities
+ */
+static int uio_add_user_attributes(struct uio_info *info)
+{
+	struct uio_device *idev = info->uio_dev;
+	const struct uio_attribute **uio_attr;
+	int i;
+	int ret = 0;
+
+	uio_attr = info->attributes;
+	if (!uio_attr)
+		return 0;
+
+	for (i = 0; uio_attr[i]; i++) {
+
+		ret = sysfs_create_file(&idev->attr_dir, &uio_attr[i]->attr);
+		if (ret)
+			break;
+	}
+	if (ret) {
+		while (--i >= 0)
+			sysfs_remove_file(&idev->attr_dir, &uio_attr[i]->attr);
+	}
+	return ret;
+}
+
+/**
+ * uio_del_user_attributes - delete an extra UIO attribute
+ * @info: UIO device capabilities
+ */
+static void uio_del_user_attributes(struct uio_info *info)
+{
+	struct uio_device *idev = info->uio_dev;
+	const struct uio_attribute **uio_attr;
+	int i;
+
+	uio_attr = info->attributes;
+
+	for (i = 0; uio_attr[i]; i++)
+		sysfs_remove_file(&idev->attr_dir, &uio_attr[i]->attr);
+}
+
+/**
  * uio_event_notify - trigger an interrupt event
  * @info: UIO device capabilities
  */
@@ -846,8 +943,14 @@ int __uio_register_device(struct module *owner,
 			goto err_request_irq;
 	}
 
-	return 0;
+	ret = uio_add_user_attributes(info);
+	if (ret)
+		goto err_free_irq;
 
+	return 0;
+err_free_irq:
+	if (info->irq && (info->irq != UIO_IRQ_CUSTOM))
+		free_irq(info->irq, idev);
 err_request_irq:
 	uio_dev_del_attributes(idev);
 err_uio_dev_add_attributes:
@@ -881,6 +984,7 @@ void uio_unregister_device(struct uio_info *info)
 		free_irq(info->irq, idev);
 
 	uio_dev_del_attributes(idev);
+	uio_del_user_attributes(idev->info);
 
 	device_destroy(&uio_class, MKDEV(uio_major, idev->minor));
 	kfree(idev);
diff --git a/include/linux/uio_driver.h b/include/linux/uio_driver.h
index 99f1696..2e7543e 100644
--- a/include/linux/uio_driver.h
+++ b/include/linux/uio_driver.h
@@ -64,6 +64,7 @@ struct uio_port {
 #define MAX_UIO_PORT_REGIONS	5
 
 struct uio_device;
+struct uio_attribute;
 
 /**
  * struct uio_info - UIO device capabilities
@@ -72,6 +73,7 @@ struct uio_device;
  * @version:		device driver version
  * @mem:		list of mappable memory regions, size==0 for end of list
  * @port:		list of port regions, size==0 for end of list
+ * @attributes:		list of additional attributes, NULL for end of list
  * @irq:		interrupt number or UIO_IRQ_CUSTOM
  * @irq_flags:		flags for request_irq()
  * @priv:		optional private data
@@ -83,14 +85,15 @@ struct uio_device;
  * @owner:		module which created the uio device incase
  */
 struct uio_info {
-	struct uio_device	*uio_dev;
-	const char		*name;
-	const char		*version;
-	struct uio_mem		mem[MAX_UIO_MAPS];
-	struct uio_port		port[MAX_UIO_PORT_REGIONS];
-	long			irq;
-	unsigned long		irq_flags;
-	void			*priv;
+	struct uio_device		*uio_dev;
+	const char			*name;
+	const char			*version;
+	struct uio_mem			mem[MAX_UIO_MAPS];
+	struct uio_port			port[MAX_UIO_PORT_REGIONS];
+	const struct uio_attribute	**attributes;
+	long				irq;
+	unsigned long			irq_flags;
+	void				*priv;
 	irqreturn_t (*handler)(int irq, struct uio_info *dev_info);
 	int (*mmap)(struct uio_info *info, struct vm_area_struct *vma);
 	int (*open)(struct uio_info *info, struct inode *inode);
@@ -99,6 +102,23 @@ struct uio_info {
 	struct module			*owner;
 };
 
+/**
+ * struct uio_attribute - UIO attribute
+ * @attr:		the attribute
+ * @show:		attribute show function
+ * @store:		attribute store function
+ */
+struct uio_attribute {
+	struct attribute attr;
+	ssize_t (*show)(struct uio_info *info, char *buf);
+	ssize_t (*store)(struct uio_info *info, const char *buf, size_t count);
+};
+
+#define UIO_ATTR(_name, _mode, _show, _store)   \
+	struct uio_attribute uio_attr_##_name = \
+		__ATTR(_name, _mode, _show, _store)
+
+
 extern int __must_check
 	__uio_register_device(struct module *owner,
 			      struct device *parent,
-- 
1.8.4.rc2

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists