diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2007-12-04 17:41:54 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2008-01-24 23:40:26 -0500 |
commit | 81e7c6a636c81d9eeaeaa732bfbace44535fab00 (patch) | |
tree | fecb19e67acb96c2c9a11194ebebca63f0139f02 /drivers/uio/uio.c | |
parent | 9f66fa2a4690a16da0dbaae2f44ddfc313802504 (diff) |
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>
Diffstat (limited to 'drivers/uio/uio.c')
-rw-r--r-- | drivers/uio/uio.c | 91 |
1 files changed, 48 insertions, 43 deletions
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index 606aae7490ab..acc387de988f 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c | |||
@@ -34,7 +34,7 @@ struct uio_device { | |||
34 | wait_queue_head_t wait; | 34 | wait_queue_head_t wait; |
35 | int vma_count; | 35 | int vma_count; |
36 | struct uio_info *info; | 36 | struct uio_info *info; |
37 | struct kset map_attr_kset; | 37 | struct kobject *map_dir; |
38 | }; | 38 | }; |
39 | 39 | ||
40 | static int uio_major; | 40 | static int uio_major; |
@@ -51,47 +51,48 @@ static struct uio_class { | |||
51 | * attributes | 51 | * attributes |
52 | */ | 52 | */ |
53 | 53 | ||
54 | static struct attribute attr_addr = { | 54 | struct uio_map { |
55 | .name = "addr", | 55 | struct kobject kobj; |
56 | .mode = S_IRUGO, | 56 | struct uio_mem *mem; |
57 | }; | 57 | }; |
58 | #define to_map(map) container_of(map, struct uio_map, kobj) | ||
58 | 59 | ||
59 | static struct attribute attr_size = { | ||
60 | .name = "size", | ||
61 | .mode = S_IRUGO, | ||
62 | }; | ||
63 | 60 | ||
64 | static struct attribute* map_attrs[] = { | 61 | static ssize_t map_attr_show(struct kobject *kobj, struct kobj_attribute *attr, |
65 | &attr_addr, &attr_size, NULL | ||
66 | }; | ||
67 | |||
68 | static ssize_t map_attr_show(struct kobject *kobj, struct attribute *attr, | ||
69 | char *buf) | 62 | char *buf) |
70 | { | 63 | { |
71 | struct uio_mem *mem = container_of(kobj, struct uio_mem, kobj); | 64 | struct uio_map *map = to_map(kobj); |
65 | struct uio_mem *mem = map->mem; | ||
72 | 66 | ||
73 | if (strncmp(attr->name,"addr",4) == 0) | 67 | if (strncmp(attr->attr.name, "addr", 4) == 0) |
74 | return sprintf(buf, "0x%lx\n", mem->addr); | 68 | return sprintf(buf, "0x%lx\n", mem->addr); |
75 | 69 | ||
76 | if (strncmp(attr->name,"size",4) == 0) | 70 | if (strncmp(attr->attr.name, "size", 4) == 0) |
77 | return sprintf(buf, "0x%lx\n", mem->size); | 71 | return sprintf(buf, "0x%lx\n", mem->size); |
78 | 72 | ||
79 | return -ENODEV; | 73 | return -ENODEV; |
80 | } | 74 | } |
81 | 75 | ||
82 | static void map_attr_release(struct kobject *kobj) | 76 | static struct kobj_attribute attr_attribute = |
83 | { | 77 | __ATTR(addr, S_IRUGO, map_attr_show, NULL); |
84 | /* TODO ??? */ | 78 | static struct kobj_attribute size_attribute = |
85 | } | 79 | __ATTR(size, S_IRUGO, map_attr_show, NULL); |
86 | 80 | ||
87 | static struct sysfs_ops map_attr_ops = { | 81 | static struct attribute *attrs[] = { |
88 | .show = map_attr_show, | 82 | &attr_attribute.attr, |
83 | &size_attribute.attr, | ||
84 | NULL, /* need to NULL terminate the list of attributes */ | ||
89 | }; | 85 | }; |
90 | 86 | ||
87 | static void map_release(struct kobject *kobj) | ||
88 | { | ||
89 | struct uio_map *map = to_map(kobj); | ||
90 | kfree(map); | ||
91 | } | ||
92 | |||
91 | static struct kobj_type map_attr_type = { | 93 | static struct kobj_type map_attr_type = { |
92 | .release = map_attr_release, | 94 | .release = map_release, |
93 | .sysfs_ops = &map_attr_ops, | 95 | .default_attrs = attrs, |
94 | .default_attrs = map_attrs, | ||
95 | }; | 96 | }; |
96 | 97 | ||
97 | static ssize_t show_name(struct device *dev, | 98 | static ssize_t show_name(struct device *dev, |
@@ -148,6 +149,7 @@ static int uio_dev_add_attributes(struct uio_device *idev) | |||
148 | int mi; | 149 | int mi; |
149 | int map_found = 0; | 150 | int map_found = 0; |
150 | struct uio_mem *mem; | 151 | struct uio_mem *mem; |
152 | struct uio_map *map; | ||
151 | 153 | ||
152 | ret = sysfs_create_group(&idev->dev->kobj, &uio_attr_grp); | 154 | ret = sysfs_create_group(&idev->dev->kobj, &uio_attr_grp); |
153 | if (ret) | 155 | if (ret) |
@@ -159,31 +161,34 @@ static int uio_dev_add_attributes(struct uio_device *idev) | |||
159 | break; | 161 | break; |
160 | if (!map_found) { | 162 | if (!map_found) { |
161 | map_found = 1; | 163 | map_found = 1; |
162 | kobject_set_name(&idev->map_attr_kset.kobj,"maps"); | 164 | idev->map_dir = kobject_create_and_add("maps", |
163 | idev->map_attr_kset.kobj.ktype = &map_attr_type; | 165 | &idev->dev->kobj); |
164 | idev->map_attr_kset.kobj.parent = &idev->dev->kobj; | 166 | if (!idev->map_dir) |
165 | ret = kset_register(&idev->map_attr_kset); | 167 | goto err; |
166 | if (ret) | ||
167 | goto err_remove_group; | ||
168 | } | 168 | } |
169 | kobject_init(&mem->kobj); | 169 | map = kzalloc(sizeof(*map), GFP_KERNEL); |
170 | kobject_set_name(&mem->kobj,"map%d",mi); | 170 | if (!map) |
171 | mem->kobj.parent = &idev->map_attr_kset.kobj; | 171 | goto err; |
172 | mem->kobj.kset = &idev->map_attr_kset; | 172 | kobject_init_ng(&map->kobj, &map_attr_type); |
173 | ret = kobject_add(&mem->kobj); | 173 | map->mem = mem; |
174 | mem->map = map; | ||
175 | ret = kobject_add_ng(&map->kobj, idev->map_dir, "map%d", mi); | ||
176 | if (ret) | ||
177 | goto err; | ||
178 | ret = kobject_uevent(&map->kobj, KOBJ_ADD); | ||
174 | if (ret) | 179 | if (ret) |
175 | goto err_remove_maps; | 180 | goto err; |
176 | } | 181 | } |
177 | 182 | ||
178 | return 0; | 183 | return 0; |
179 | 184 | ||
180 | err_remove_maps: | 185 | err: |
181 | for (mi--; mi>=0; mi--) { | 186 | for (mi--; mi>=0; mi--) { |
182 | mem = &idev->info->mem[mi]; | 187 | mem = &idev->info->mem[mi]; |
183 | kobject_unregister(&mem->kobj); | 188 | map = mem->map; |
189 | kobject_unregister(&map->kobj); | ||
184 | } | 190 | } |
185 | kset_unregister(&idev->map_attr_kset); /* Needed ? */ | 191 | kobject_unregister(idev->map_dir); |
186 | err_remove_group: | ||
187 | sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp); | 192 | sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp); |
188 | err_group: | 193 | err_group: |
189 | dev_err(idev->dev, "error creating sysfs files (%d)\n", ret); | 194 | 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 | mem = &idev->info->mem[mi]; | 203 | mem = &idev->info->mem[mi]; |
199 | if (mem->size == 0) | 204 | if (mem->size == 0) |
200 | break; | 205 | break; |
201 | kobject_unregister(&mem->kobj); | 206 | kobject_unregister(&mem->map->kobj); |
202 | } | 207 | } |
203 | kset_unregister(&idev->map_attr_kset); | 208 | kobject_unregister(idev->map_dir); |
204 | sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp); | 209 | sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp); |
205 | } | 210 | } |
206 | 211 | ||