svn commit: r210907 - projects/ofed/head/sys/ofed/include/linux

Jeff Roberson jeff at FreeBSD.org
Fri Aug 6 02:17:32 UTC 2010


Author: jeff
Date: Fri Aug  6 02:17:32 2010
New Revision: 210907
URL: http://svn.freebsd.org/changeset/base/210907

Log:
   - Add Linux kobj objects to the sysctl namespace in sys to mirror the
     /sysfs filesystem.  All linux objects are treated as strings with
     a custom proc that calls the show and store interface methods.
   - Add all device attributes and class attributes.
   - Complete adding ktypes for classes and devices so they are now properly
     reference counted.
  
  Sponsored by:	Isilon Systems, iX Systems, and Panasas.

Modified:
  projects/ofed/head/sys/ofed/include/linux/device.h
  projects/ofed/head/sys/ofed/include/linux/kobject.h
  projects/ofed/head/sys/ofed/include/linux/linux_compat.c
  projects/ofed/head/sys/ofed/include/linux/miscdevice.h
  projects/ofed/head/sys/ofed/include/linux/pci.h
  projects/ofed/head/sys/ofed/include/linux/sysfs.h

Modified: projects/ofed/head/sys/ofed/include/linux/device.h
==============================================================================
--- projects/ofed/head/sys/ofed/include/linux/device.h	Fri Aug  6 01:08:12 2010	(r210906)
+++ projects/ofed/head/sys/ofed/include/linux/device.h	Fri Aug  6 02:17:32 2010	(r210907)
@@ -47,7 +47,10 @@ typedef enum irqreturn	irqreturn_t;
 struct class {
 	const char	*name;
 	struct module	*owner;
+	struct kobject	kobj;
 	devclass_t	bsdclass;
+	void		(*class_release)(struct class *class);
+	void		(*dev_release)(struct device *dev);
 };
 
 struct device {
@@ -65,12 +68,13 @@ struct device {
 
 };
 
-/* #define	device	linux_device */
+extern struct device linux_rootdev;
+extern struct kobject class_root;
 
 struct class_attribute {
 	struct attribute	attr;
         ssize_t			(*show)(struct class *, char *);
-        ssize_t			(*store)(struct class *, char *, size_t);
+        ssize_t			(*store)(struct class *, const char *, size_t);
 };
 #define	CLASS_ATTR(_name, _mode, _show, _store)				\
 	struct class_attribute class_attr_##_name =			\
@@ -81,7 +85,8 @@ struct device_attribute {
 	ssize_t			(*show)(struct device *,
 				    struct device_attribute *, char *);
 	ssize_t			(*store)(struct device *,
-				    struct device_attribute *, const char *, size_t);
+				    struct device_attribute *, const char *,
+				    size_t);
 };
 
 #define	DEVICE_ATTR(_name, _mode, _show, _store)			\
@@ -126,7 +131,7 @@ dev_name(const struct device *dev)
 }
 
 #define	dev_set_name(_dev, _fmt, ...)					\
-	kobject_set_name(&(_dev)->kobj, (_fmt), #__VA_ARGS__)
+	kobject_set_name(&(_dev)->kobj, (_fmt), ##__VA_ARGS__)
 
 static inline void
 put_device(struct device *dev)
@@ -136,21 +141,121 @@ put_device(struct device *dev)
 		kobject_put(&dev->kobj);
 }
 
+static inline ssize_t
+class_show(struct kobject *kobj, struct attribute *attr, char *buf)
+{
+	struct class_attribute *dattr;
+	ssize_t error;
+
+	dattr = container_of(attr, struct class_attribute, attr);
+	error = -EIO;
+	if (dattr->show)
+		error = dattr->show(container_of(kobj, struct class, kobj),
+		    buf);
+	return (error);
+}
+
+static inline ssize_t
+class_store(struct kobject *kobj, struct attribute *attr, const char *buf,
+    size_t count)
+{
+	struct class_attribute *dattr;
+	ssize_t error;
+
+	dattr = container_of(attr, struct class_attribute, attr);
+	error = -EIO;
+	if (dattr->store)
+		error = dattr->store(container_of(kobj, struct class, kobj),
+		    buf, count);
+	return (error);
+}
+
+static inline void
+class_release(struct kobject *kobj)
+{
+	struct class *class;
+
+	class = container_of(kobj, struct class, kobj);
+	if (class->class_release)
+		class->class_release(class);
+}
+
+static struct sysfs_ops class_sysfs = {
+	.show  = class_show,
+	.store = class_store,
+};
+static struct kobj_type class_ktype = {
+	.release = class_release,
+	.sysfs_ops = &class_sysfs
+};
+
 static inline int
 class_register(struct class *class)
 {
 
 	class->bsdclass = devclass_create(class->name);
-	return 0;
+	kobject_init(&class->kobj, &class_ktype);
+	kobject_set_name(&class->kobj, class->name);
+	kobject_add(&class->kobj, &class_root, class->name);
+
+	return (0);
 }
 
 static inline void
 class_unregister(struct class *class)
 {
 
-	return;
+	kobject_put(&class->kobj);
 }
 
+static inline void
+device_release(struct kobject *kobj)
+{
+	struct device *dev;
+
+	dev = container_of(kobj, struct device, kobj);
+	/* This is the precedence defined by linux. */
+	if (dev->release)
+		dev->release(dev);
+	else if (dev->class && dev->class->dev_release)
+		dev->class->dev_release(dev);
+}
+
+static inline ssize_t
+dev_show(struct kobject *kobj, struct attribute *attr, char *buf)
+{
+	struct device_attribute *dattr;
+	ssize_t error;
+
+	dattr = container_of(attr, struct device_attribute, attr);
+	error = -EIO;
+	if (dattr->show)
+		error = dattr->show(container_of(kobj, struct device, kobj),
+		    dattr, buf);
+	return (error);
+}
+
+static inline ssize_t
+dev_store(struct kobject *kobj, struct attribute *attr, const char *buf,
+    size_t count)
+{
+	struct device_attribute *dattr;
+	ssize_t error;
+
+	dattr = container_of(attr, struct device_attribute, attr);
+	error = -EIO;
+	if (dattr->store)
+		error = dattr->store(container_of(kobj, struct device, kobj),
+		    dattr, buf, count);
+	return (error);
+}
+
+static struct sysfs_ops dev_sysfs = { .show  = dev_show, .store = dev_store, };
+static struct kobj_type dev_ktype = {
+	.release = device_release,
+	.sysfs_ops = &dev_sysfs
+};
+
 /*
  * Devices are registered and created for exporting to sysfs.  create
  * implies register and register assumes the device fields have been
@@ -177,7 +282,8 @@ device_register(struct device *dev)
 		device_set_softc(bsddev, dev);
 	}
 	dev->bsddev = bsddev;
-	kobject_init(&dev->kobj, NULL);
+	kobject_init(&dev->kobj, &dev_ktype);
+	kobject_add(&dev->kobj, &dev->class->kobj, dev_name(dev));
 	get_device(dev);
 
 	return (0);
@@ -215,14 +321,28 @@ device_destroy(struct class *class, dev_
 	}
 }
 
+static inline void
+class_kfree(struct class *class)
+{
+
+	kfree(class);
+}
+
 static inline struct class *
 class_create(struct module *owner, const char *name)
 {
 	struct class *class;
+	int error;
 
 	class = kzalloc(sizeof(*class), M_WAITOK);
 	class->owner = owner;
 	class->name= name;
+	class->class_release = class_kfree;
+	error = class_register(class);
+	if (error) {
+		kfree(class);
+		return (NULL);
+	}
 
 	return (class);
 }
@@ -230,36 +350,44 @@ class_create(struct module *owner, const
 static inline void
 class_destroy(struct class *class)
 {
-	/* XXX Missing ref count. */
-	kfree(class);
+
+	if (class == NULL)
+		return;
+	class_unregister(class);
 }
 
-/*
- * These are supposed to create the sysfs entry for the attribute.  Should
- * instead create a sysctl tree. XXX
- */
 static inline int
-device_create_file(struct device *device, const struct device_attribute *entry)
+device_create_file(struct device *dev, const struct device_attribute *attr)
 {
-	return (0);
+
+	if (dev)
+		return sysfs_create_file(&dev->kobj, &attr->attr);
+	return -EINVAL;
 }
 
 static inline void
 device_remove_file(struct device *dev, const struct device_attribute *attr)
 {
-	return;
+
+	if (dev)
+		sysfs_remove_file(&dev->kobj, &attr->attr);
 }
 
 static inline int
 class_create_file(struct class *class, const struct class_attribute *attr)
 {
-	return (0);
+
+	if (class)
+		return sysfs_create_file(&class->kobj, &attr->attr);
+	return -EINVAL;
 }
 
 static inline void
 class_remove_file(struct class *class, const struct class_attribute *attr)
 {
-	return;
+
+	if (class)
+		sysfs_remove_file(&class->kobj, &attr->attr);
 }
 
 #endif	/* _LINUX_DEVICE_H_ */

Modified: projects/ofed/head/sys/ofed/include/linux/kobject.h
==============================================================================
--- projects/ofed/head/sys/ofed/include/linux/kobject.h	Fri Aug  6 01:08:12 2010	(r210906)
+++ projects/ofed/head/sys/ofed/include/linux/kobject.h	Fri Aug  6 02:17:32 2010	(r210907)
@@ -35,6 +35,7 @@
 #include <linux/slab.h>
 
 struct kobject;
+struct sysctl_oid;
 
 struct kobj_type {
 	void (*release)(struct kobject *kobj);
@@ -42,11 +43,15 @@ struct kobj_type {
 	struct attribute **default_attrs;
 };
 
+extern struct kobj_type kfree_type;
+
 struct kobject {
 	struct kobject		*parent;
 	char			*name;
 	struct kref		kref;
 	struct kobj_type	*ktype;
+	struct list_head	entry;
+	struct sysctl_oid	*oidp;
 };
 
 static inline void
@@ -54,20 +59,13 @@ kobject_init(struct kobject *kobj, struc
 {
 
 	kref_init(&kobj->kref);
+	INIT_LIST_HEAD(&kobj->entry);
 	kobj->ktype = ktype;
-	kobj->name = NULL;
-	kobj->parent = NULL;
+	kobj->oidp = NULL;
 }
 
-static inline void
-kobject_release(struct kref *kref)
-{
-	struct kobject *kobj;
-
-	kobj = container_of(kref, struct kobject, kref);
-	if (kobj->ktype && kobj->ktype->release)
-		kobj->ktype->release(kobj);
-}
+static inline void kobject_put(struct kobject *kobj);
+void kobject_release(struct kref *kref);
 
 static inline void
 kobject_put(struct kobject *kobj)
@@ -109,24 +107,42 @@ kobject_set_name_vargs(struct kobject *k
 	return (0);
 }
 
-static inline int
-kobject_add(struct kobject *kobj, struct kobject *parent, const char *fmt, ...)
+int	kobject_add(struct kobject *kobj, struct kobject *parent,
+	    const char *fmt, ...);
+
+static inline struct kobject *
+kobject_create(void)
 {
-	va_list args;
-	int error;
+	struct kobject *kobj;
 
-	va_start(args, fmt);
-	error = kobject_set_name_vargs(kobj, fmt, args);
-	va_end(args);
-	kobj->parent = parent;
+	kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
+	if (kobj == NULL)
+		return (NULL);
+	kobject_init(kobj, &kfree_type);
 
-	return (error);
+	return (kobj);
+}
+
+static inline struct kobject *
+kobject_create_and_add(const char *name, struct kobject *parent)
+{
+	struct kobject *kobj;
+
+	kobj = kobject_create();
+	if (kobj == NULL)
+		return (NULL);
+	if (kobject_add(kobj, parent, "%s", name) == 0)
+		return (kobj);
+	kobject_put(kobj);
+
+	return (NULL);
 }
 
 
 static inline char *
 kobject_name(const struct kobject *kobj)
 {
+
 	return kobj->name;
 }
 

Modified: projects/ofed/head/sys/ofed/include/linux/linux_compat.c
==============================================================================
--- projects/ofed/head/sys/ofed/include/linux/linux_compat.c	Fri Aug  6 01:08:12 2010	(r210906)
+++ projects/ofed/head/sys/ofed/include/linux/linux_compat.c	Fri Aug  6 02:17:32 2010	(r210907)
@@ -41,17 +41,23 @@
 #include <linux/device.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/cdev.h>
+#include <linux/file.h>
+#include <linux/sysfs.h>
 
 MALLOC_DEFINE(M_KMALLOC, "linux", "Linux kmalloc compat");
-MALLOC_DEFINE(M_LINUX_DMA, "lnxdma", "Linux DMA compat");
+
+struct fileops linuxfileops;
+struct cdevsw linuxcdevsw;
 
 #include <linux/rbtree.h>
 /* Undo Linux compat change. */
 #undef RB_ROOT
 #define	RB_ROOT(head)	(head)->rbh_root
 
+struct kobject class_root;
+struct device linux_rootdev;
 struct class miscclass;
-struct device miscroot;
 struct list_head pci_drivers;
 
 int
@@ -75,6 +81,71 @@ kobject_set_name(struct kobject *kobj, c
 	return (error);
 }
 
+static inline int
+kobject_add_complete(struct kobject *kobj, struct kobject *parent)
+{
+	struct kobj_type *t;
+	int error;
+
+	kobj->parent = kobject_get(parent);
+	error = sysfs_create_dir(kobj);
+	if (error == 0 && kobj->ktype && kobj->ktype->default_attrs) {
+		struct attribute **attr;
+		t = kobj->ktype;
+
+		for (attr = t->default_attrs; *attr != NULL; attr++) {
+			error = sysfs_create_file(kobj, *attr);
+			if (error)
+				break;
+		}
+		if (error)
+			sysfs_remove_dir(kobj);
+		
+	}
+	return (error);
+}
+
+int
+kobject_add(struct kobject *kobj, struct kobject *parent, const char *fmt, ...)
+{
+	va_list args;
+	int error;
+
+	va_start(args, fmt);
+	error = kobject_set_name_vargs(kobj, fmt, args);
+	va_end(args);
+	if (error)
+		return (error);
+
+	return kobject_add_complete(kobj, parent);
+}
+
+void
+kobject_release(struct kref *kref)
+{
+	struct kobject *kobj;
+	char *name;
+
+	kobj = container_of(kref, struct kobject, kref);
+	sysfs_remove_dir(kobj);
+	if (kobj->parent)
+		kobject_put(kobj->parent);
+	kobj->parent = NULL;
+	name = kobj->name;
+	if (kobj->ktype && kobj->ktype->release)
+		kobj->ktype->release(kobj);
+	kfree(name);
+}
+
+static void
+kobject_kfree(struct kobject *kobj)
+{
+
+	kfree(kobj);
+}
+
+struct kobj_type kfree_type = { .release = kobject_kfree };
+
 struct device *
 device_create(struct class *class, struct device *parent, dev_t devt,
     void *drvdata, const char *fmt, ...)
@@ -84,6 +155,7 @@ device_create(struct class *class, struc
 
 	dev = kzalloc(sizeof(*dev), M_WAITOK);
 	dev->parent = parent;
+	dev->class = class;
 	dev->devt = devt;
 	dev->driver_data = drvdata;
 	va_start(args, fmt);
@@ -109,17 +181,31 @@ kobject_init_and_add(struct kobject *kob
 	va_start(args, fmt);
 	error = kobject_set_name_vargs(kobj, fmt, args);
 	va_end(args);
-
-	return error;
+	if (error)
+		return (error);
+	return kobject_add_complete(kobj, parent);
 }
 
 static void
 linux_compat_init(void)
 {
+	struct sysctl_oid *rootoid;
+
+	rootoid = SYSCTL_ADD_NODE(NULL, SYSCTL_STATIC_CHILDREN(),
+	    OID_AUTO, "sys", CTLFLAG_RD|CTLFLAG_MPSAFE, NULL, "sys");
+	kobject_init(&class_root, &class_ktype);
+	kobject_set_name(&class_root, "class");
+	class_root.oidp = SYSCTL_ADD_NODE(NULL, SYSCTL_CHILDREN(rootoid),
+	    OID_AUTO, "class", CTLFLAG_RD|CTLFLAG_MPSAFE, NULL, "class");
+	kobject_init(&linux_rootdev.kobj, &dev_ktype);
+	kobject_set_name(&linux_rootdev.kobj, "device");
+	linux_rootdev.kobj.oidp = SYSCTL_ADD_NODE(NULL,
+	    SYSCTL_CHILDREN(rootoid), OID_AUTO, "device", CTLFLAG_RD, NULL,
+	    "device");
+	linux_rootdev.bsddev = root_bus;
 	miscclass.name = "misc";
 	class_register(&miscclass);
-	miscroot.bsddev = root_bus;
 	INIT_LIST_HEAD(&pci_drivers);
 }
 
-module_init(linux_compat_init);
+SYSINIT(linux_compat, SI_SUB_DRIVERS, SI_ORDER_SECOND, linux_compat_init, NULL);

Modified: projects/ofed/head/sys/ofed/include/linux/miscdevice.h
==============================================================================
--- projects/ofed/head/sys/ofed/include/linux/miscdevice.h	Fri Aug  6 01:08:12 2010	(r210906)
+++ projects/ofed/head/sys/ofed/include/linux/miscdevice.h	Fri Aug  6 02:17:32 2010	(r210907)
@@ -41,7 +41,6 @@ struct miscdevice  {
 };
 
 extern struct class	miscclass;
-extern struct device	miscroot;
 
 /*
  * XXX Missing cdev.
@@ -49,7 +48,7 @@ extern struct device	miscroot;
 static inline int
 misc_register(struct miscdevice *misc)
 {
-	misc->this_device = device_create(&miscclass, &miscroot, 0, misc, 
+	misc->this_device = device_create(&miscclass, &linux_rootdev, 0, misc, 
 	    misc->name);
 	return (0);
 }

Modified: projects/ofed/head/sys/ofed/include/linux/pci.h
==============================================================================
--- projects/ofed/head/sys/ofed/include/linux/pci.h	Fri Aug  6 01:08:12 2010	(r210906)
+++ projects/ofed/head/sys/ofed/include/linux/pci.h	Fri Aug  6 02:17:32 2010	(r210907)
@@ -373,12 +373,15 @@ linux_pci_attach(device_t dev)
 
 	pdrv = linux_pci_find(dev, &id);
 	pdev = device_get_softc(dev);
+	pdev->dev.parent = &linux_rootdev;
 	pdev->dev.bsddev = dev;
 	pdev->device = device_get_unit(dev);
 	pdev->dev.dma_mask = &pdev->dma_mask;
 	pdev->pdrv = pdrv;
-	kobject_init(&pdev->dev.kobj, NULL);
+	kobject_init(&pdev->dev.kobj, &dev_ktype);
 	kobject_set_name(&pdev->dev.kobj, device_get_nameunit(dev));
+	kobject_add(&pdev->dev.kobj, &linux_rootdev.kobj,
+	    kobject_name(&pdev->dev.kobj));
 	rle = _pci_get_rle(pdev, SYS_RES_IRQ, 0);
 	if (rle)
 		pdev->irq = rle->start;

Modified: projects/ofed/head/sys/ofed/include/linux/sysfs.h
==============================================================================
--- projects/ofed/head/sys/ofed/include/linux/sysfs.h	Fri Aug  6 01:08:12 2010	(r210906)
+++ projects/ofed/head/sys/ofed/include/linux/sysfs.h	Fri Aug  6 02:17:32 2010	(r210907)
@@ -29,6 +29,8 @@
 #ifndef	_LINUX_SYSFS_H_
 #define	_LINUX_SYSFS_H_
 
+#include <sys/sysctl.h>
+
 struct attribute {
 	const char 	*name;
 	struct module	*owner;
@@ -60,4 +62,121 @@ struct attribute_group {
 
 #define	__ATTR_NULL	{ .attr = { .name = NULL } }
 
+/*
+ * Handle our generic '\0' terminated 'C' string.
+ * Two cases:
+ *      a variable string:  point arg1 at it, arg2 is max length.
+ *      a constant string:  point arg1 at it, arg2 is zero.
+ */
+
+static inline int
+sysctl_handle_attr(SYSCTL_HANDLER_ARGS)
+{
+	struct kobject *kobj;
+	struct attribute *attr;
+	const struct sysfs_ops *ops;
+	void *buf;
+	int error;
+	ssize_t len;
+
+	kobj = arg1;
+	attr = (struct attribute *)arg2;
+	buf = (void *)get_zeroed_page(GFP_KERNEL);
+	len = 1;	/* Copy out a NULL byte at least. */
+	if (kobj->ktype == NULL || kobj->ktype->sysfs_ops == NULL)
+		return (ENODEV);
+	ops = kobj->ktype->sysfs_ops;
+	if (buf == NULL)
+		return (ENOMEM);
+	if (ops->show) {
+		len = ops->show(kobj, attr, buf);
+		/*
+		 * It's valid not to have a 'show' so we just return 1 byte
+		 * of NULL.
+	 	 */
+		if (len < 0) {
+			error = -len;
+			len = 1;
+			if (error != EIO)
+				goto out;
+		}
+	}
+	error = SYSCTL_OUT(req, buf, len);
+	if (error || !req->newptr || ops->store == NULL)
+		goto out;
+	error = SYSCTL_IN(req, buf, PAGE_SIZE);
+	if (error)
+		goto out;
+	len = ops->store(kobj, attr, buf, req->newlen);
+	if (len < 0)
+		error = -len;
+out:
+	free_page((unsigned long)buf);
+
+	return (error);
+}
+
+static inline int
+sysfs_create_file(struct kobject *kobj, const struct attribute *attr)
+{
+
+	sysctl_add_oid(NULL, SYSCTL_CHILDREN(kobj->oidp), OID_AUTO,
+	    attr->name, CTLTYPE_STRING|CTLFLAG_RW|CTLFLAG_MPSAFE, kobj,
+	    (uintptr_t)attr, sysctl_handle_attr, "A", "");
+
+	return (0);
+}
+
+static inline void
+sysfs_remove_file(struct kobject *kobj, const struct attribute *attr)
+{
+
+	if (kobj->oidp)
+		sysctl_remove_name(kobj->oidp, attr->name, 1, 1);
+}
+
+static inline void
+sysfs_remove_group(struct kobject *kobj, const struct attribute_group *grp)
+{
+
+	if (kobj->oidp)
+		sysctl_remove_name(kobj->oidp, grp->name, 1, 1);
+}
+
+static inline int
+sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp)
+{
+	struct attribute **attr;
+	struct sysctl_oid *oidp;
+
+	oidp = SYSCTL_ADD_NODE(NULL, SYSCTL_CHILDREN(kobj->oidp),
+	    OID_AUTO, grp->name, CTLFLAG_RD|CTLFLAG_MPSAFE, NULL, grp->name);
+	for (attr = grp->attrs; *attr != NULL; attr++) {
+		sysctl_add_oid(NULL, SYSCTL_CHILDREN(oidp), OID_AUTO,
+		    (*attr)->name, CTLTYPE_STRING|CTLFLAG_RW|CTLFLAG_MPSAFE,
+		    kobj, (uintptr_t)*attr, sysctl_handle_attr, "A", "");
+	}
+
+	return (0);
+}
+
+static inline int
+sysfs_create_dir(struct kobject *kobj)
+{
+
+	kobj->oidp = SYSCTL_ADD_NODE(NULL, SYSCTL_CHILDREN(kobj->parent->oidp),
+	    OID_AUTO, kobj->name, CTLFLAG_RD|CTLFLAG_MPSAFE, NULL, kobj->name);
+
+        return (0);
+}
+
+static inline void
+sysfs_remove_dir(struct kobject *kobj)
+{
+
+	if (kobj->oidp == NULL)
+		return;
+	sysctl_remove_oid(kobj->oidp, 1, 1);
+}
+
 #endif	/* _LINUX_SYSFS_H_ */


More information about the svn-src-projects mailing list