Commit 81e7c6a6 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

UIO: fix kobject usage

The uio kobject code is "wierd".  This patch should hopefully fix it up
to be sane and not leak memory anymore.


Cc: Kay Sievers <kay.sievers@vrfy.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Benedikt Spranger <b.spranger@linutronix.de>
Signed-off-by: default avatarHans J. Koch <hjk@linutronix.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 9f66fa2a
...@@ -34,7 +34,7 @@ struct uio_device { ...@@ -34,7 +34,7 @@ struct uio_device {
wait_queue_head_t wait; wait_queue_head_t wait;
int vma_count; int vma_count;
struct uio_info *info; struct uio_info *info;
struct kset map_attr_kset; struct kobject *map_dir;
}; };
static int uio_major; static int uio_major;
...@@ -51,47 +51,48 @@ static struct uio_class { ...@@ -51,47 +51,48 @@ static struct uio_class {
* attributes * attributes
*/ */
static struct attribute attr_addr = { struct uio_map {
.name = "addr", struct kobject kobj;
.mode = S_IRUGO, struct uio_mem *mem;
};
static struct attribute attr_size = {
.name = "size",
.mode = S_IRUGO,
}; };
#define to_map(map) container_of(map, struct uio_map, kobj)
static struct attribute* map_attrs[] = {
&attr_addr, &attr_size, NULL
};
static ssize_t map_attr_show(struct kobject *kobj, struct attribute *attr, static ssize_t map_attr_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf) char *buf)
{ {
struct uio_mem *mem = container_of(kobj, struct uio_mem, kobj); struct uio_map *map = to_map(kobj);
struct uio_mem *mem = map->mem;
if (strncmp(attr->name,"addr",4) == 0) if (strncmp(attr->attr.name, "addr", 4) == 0)
return sprintf(buf, "0x%lx\n", mem->addr); return sprintf(buf, "0x%lx\n", mem->addr);
if (strncmp(attr->name,"size",4) == 0) if (strncmp(attr->attr.name, "size", 4) == 0)
return sprintf(buf, "0x%lx\n", mem->size); return sprintf(buf, "0x%lx\n", mem->size);
return -ENODEV; return -ENODEV;
} }
static void map_attr_release(struct kobject *kobj) static struct kobj_attribute attr_attribute =
{ __ATTR(addr, S_IRUGO, map_attr_show, NULL);
/* TODO ??? */ static struct kobj_attribute size_attribute =
} __ATTR(size, S_IRUGO, map_attr_show, NULL);
static struct sysfs_ops map_attr_ops = { static struct attribute *attrs[] = {
.show = map_attr_show, &attr_attribute.attr,
&size_attribute.attr,
NULL, /* need to NULL terminate the list of attributes */
}; };
static void map_release(struct kobject *kobj)
{
struct uio_map *map = to_map(kobj);
kfree(map);
}
static struct kobj_type map_attr_type = { static struct kobj_type map_attr_type = {
.release = map_attr_release, .release = map_release,
.sysfs_ops = &map_attr_ops, .default_attrs = attrs,
.default_attrs = map_attrs,
}; };
static ssize_t show_name(struct device *dev, static ssize_t show_name(struct device *dev,
...@@ -148,6 +149,7 @@ static int uio_dev_add_attributes(struct uio_device *idev) ...@@ -148,6 +149,7 @@ static int uio_dev_add_attributes(struct uio_device *idev)
int mi; int mi;
int map_found = 0; int map_found = 0;
struct uio_mem *mem; struct uio_mem *mem;
struct uio_map *map;
ret = sysfs_create_group(&idev->dev->kobj, &uio_attr_grp); ret = sysfs_create_group(&idev->dev->kobj, &uio_attr_grp);
if (ret) if (ret)
...@@ -159,31 +161,34 @@ static int uio_dev_add_attributes(struct uio_device *idev) ...@@ -159,31 +161,34 @@ static int uio_dev_add_attributes(struct uio_device *idev)
break; break;
if (!map_found) { if (!map_found) {
map_found = 1; map_found = 1;
kobject_set_name(&idev->map_attr_kset.kobj,"maps"); idev->map_dir = kobject_create_and_add("maps",
idev->map_attr_kset.kobj.ktype = &map_attr_type; &idev->dev->kobj);
idev->map_attr_kset.kobj.parent = &idev->dev->kobj; if (!idev->map_dir)
ret = kset_register(&idev->map_attr_kset); goto err;
if (ret)
goto err_remove_group;
} }
kobject_init(&mem->kobj); map = kzalloc(sizeof(*map), GFP_KERNEL);
kobject_set_name(&mem->kobj,"map%d",mi); if (!map)
mem->kobj.parent = &idev->map_attr_kset.kobj; goto err;
mem->kobj.kset = &idev->map_attr_kset; kobject_init_ng(&map->kobj, &map_attr_type);
ret = kobject_add(&mem->kobj); map->mem = mem;
mem->map = map;
ret = kobject_add_ng(&map->kobj, idev->map_dir, "map%d", mi);
if (ret)
goto err;
ret = kobject_uevent(&map->kobj, KOBJ_ADD);
if (ret) if (ret)
goto err_remove_maps; goto err;
} }
return 0; return 0;
err_remove_maps: err:
for (mi--; mi>=0; mi--) { for (mi--; mi>=0; mi--) {
mem = &idev->info->mem[mi]; mem = &idev->info->mem[mi];
kobject_unregister(&mem->kobj); map = mem->map;
kobject_unregister(&map->kobj);
} }
kset_unregister(&idev->map_attr_kset); /* Needed ? */ kobject_unregister(idev->map_dir);
err_remove_group:
sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp); sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp);
err_group: err_group:
dev_err(idev->dev, "error creating sysfs files (%d)\n", ret); dev_err(idev->dev, "error creating sysfs files (%d)\n", ret);
...@@ -198,9 +203,9 @@ static void uio_dev_del_attributes(struct uio_device *idev) ...@@ -198,9 +203,9 @@ static void uio_dev_del_attributes(struct uio_device *idev)
mem = &idev->info->mem[mi]; mem = &idev->info->mem[mi];
if (mem->size == 0) if (mem->size == 0)
break; break;
kobject_unregister(&mem->kobj); kobject_unregister(&mem->map->kobj);
} }
kset_unregister(&idev->map_attr_kset); kobject_unregister(idev->map_dir);
sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp); sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp);
} }
......
...@@ -18,20 +18,22 @@ ...@@ -18,20 +18,22 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
struct uio_map;
/** /**
* struct uio_mem - description of a UIO memory region * struct uio_mem - description of a UIO memory region
* @kobj: kobject for this mapping
* @addr: address of the device's memory * @addr: address of the device's memory
* @size: size of IO * @size: size of IO
* @memtype: type of memory addr points to * @memtype: type of memory addr points to
* @internal_addr: ioremap-ped version of addr, for driver internal use * @internal_addr: ioremap-ped version of addr, for driver internal use
* @map: for use by the UIO core only.
*/ */
struct uio_mem { struct uio_mem {
struct kobject kobj;
unsigned long addr; unsigned long addr;
unsigned long size; unsigned long size;
int memtype; int memtype;
void __iomem *internal_addr; void __iomem *internal_addr;
struct uio_map *map;
}; };
#define MAX_UIO_MAPS 5 #define MAX_UIO_MAPS 5
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment