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: Hans J. Koch <hjk@linutronix.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
9f66fa2a46
commit
81e7c6a636
2 changed files with 52 additions and 45 deletions
|
@ -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 {
|
||||||
* attributes
|
* attributes
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static struct attribute attr_addr = {
|
struct uio_map {
|
||||||
.name = "addr",
|
struct kobject kobj;
|
||||||
.mode = S_IRUGO,
|
struct uio_mem *mem;
|
||||||
};
|
};
|
||||||
|
#define to_map(map) container_of(map, struct uio_map, kobj)
|
||||||
|
|
||||||
static struct attribute attr_size = {
|
|
||||||
.name = "size",
|
|
||||||
.mode = S_IRUGO,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct attribute* map_attrs[] = {
|
static ssize_t map_attr_show(struct kobject *kobj, struct kobj_attribute *attr,
|
||||||
&attr_addr, &attr_size, NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
static ssize_t map_attr_show(struct kobject *kobj, struct 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)
|
||||||
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)
|
||||||
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)
|
if (ret)
|
||||||
goto err_remove_maps;
|
goto err;
|
||||||
|
ret = kobject_uevent(&map->kobj, KOBJ_ADD);
|
||||||
|
if (ret)
|
||||||
|
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)
|
||||||
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 @@
|
||||||
#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
|
||||||
|
|
Loading…
Reference in a new issue