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