Commit 81e7c6a636c81d9eeaeaa732bfbace44535fab00

Authored by Greg Kroah-Hartman
1 parent 9f66fa2a46

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>

Showing 2 changed files with 52 additions and 45 deletions Side-by-side Diff

... ... @@ -34,7 +34,7 @@
34 34 wait_queue_head_t wait;
35 35 int vma_count;
36 36 struct uio_info *info;
37   - struct kset map_attr_kset;
  37 + struct kobject *map_dir;
38 38 };
39 39  
40 40 static int uio_major;
41 41  
42 42  
43 43  
44 44  
45 45  
46 46  
47 47  
48 48  
49 49  
50 50  
... ... @@ -51,47 +51,48 @@
51 51 * attributes
52 52 */
53 53  
54   -static struct attribute attr_addr = {
55   - .name = "addr",
56   - .mode = S_IRUGO,
  54 +struct uio_map {
  55 + struct kobject kobj;
  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[] = {
65   - &attr_addr, &attr_size, NULL
66   -};
67   -
68   -static ssize_t map_attr_show(struct kobject *kobj, struct attribute *attr,
  61 +static ssize_t map_attr_show(struct kobject *kobj, struct kobj_attribute *attr,
69 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 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 71 return sprintf(buf, "0x%lx\n", mem->size);
78 72  
79 73 return -ENODEV;
80 74 }
81 75  
82   -static void map_attr_release(struct kobject *kobj)
83   -{
84   - /* TODO ??? */
85   -}
  76 +static struct kobj_attribute attr_attribute =
  77 + __ATTR(addr, S_IRUGO, map_attr_show, NULL);
  78 +static struct kobj_attribute size_attribute =
  79 + __ATTR(size, S_IRUGO, map_attr_show, NULL);
86 80  
87   -static struct sysfs_ops map_attr_ops = {
88   - .show = map_attr_show,
  81 +static struct attribute *attrs[] = {
  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 93 static struct kobj_type map_attr_type = {
92   - .release = map_attr_release,
93   - .sysfs_ops = &map_attr_ops,
94   - .default_attrs = map_attrs,
  94 + .release = map_release,
  95 + .default_attrs = attrs,
95 96 };
96 97  
97 98 static ssize_t show_name(struct device *dev,
... ... @@ -148,6 +149,7 @@
148 149 int mi;
149 150 int map_found = 0;
150 151 struct uio_mem *mem;
  152 + struct uio_map *map;
151 153  
152 154 ret = sysfs_create_group(&idev->dev->kobj, &uio_attr_grp);
153 155 if (ret)
154 156  
155 157  
156 158  
157 159  
158 160  
... ... @@ -159,31 +161,34 @@
159 161 break;
160 162 if (!map_found) {
161 163 map_found = 1;
162   - kobject_set_name(&idev->map_attr_kset.kobj,"maps");
163   - idev->map_attr_kset.kobj.ktype = &map_attr_type;
164   - idev->map_attr_kset.kobj.parent = &idev->dev->kobj;
165   - ret = kset_register(&idev->map_attr_kset);
166   - if (ret)
167   - goto err_remove_group;
  164 + idev->map_dir = kobject_create_and_add("maps",
  165 + &idev->dev->kobj);
  166 + if (!idev->map_dir)
  167 + goto err;
168 168 }
169   - kobject_init(&mem->kobj);
170   - kobject_set_name(&mem->kobj,"map%d",mi);
171   - mem->kobj.parent = &idev->map_attr_kset.kobj;
172   - mem->kobj.kset = &idev->map_attr_kset;
173   - ret = kobject_add(&mem->kobj);
  169 + map = kzalloc(sizeof(*map), GFP_KERNEL);
  170 + if (!map)
  171 + goto err;
  172 + kobject_init_ng(&map->kobj, &map_attr_type);
  173 + map->mem = mem;
  174 + mem->map = map;
  175 + ret = kobject_add_ng(&map->kobj, idev->map_dir, "map%d", mi);
174 176 if (ret)
175   - goto err_remove_maps;
  177 + goto err;
  178 + ret = kobject_uevent(&map->kobj, KOBJ_ADD);
  179 + if (ret)
  180 + goto err;
176 181 }
177 182  
178 183 return 0;
179 184  
180   -err_remove_maps:
  185 +err:
181 186 for (mi--; mi>=0; mi--) {
182 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 ? */
186   -err_remove_group:
  191 + kobject_unregister(idev->map_dir);
187 192 sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp);
188 193 err_group:
189 194 dev_err(idev->dev, "error creating sysfs files (%d)\n", ret);
190 195  
... ... @@ -198,9 +203,9 @@
198 203 mem = &idev->info->mem[mi];
199 204 if (mem->size == 0)
200 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 209 sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp);
205 210 }
206 211  
include/linux/uio_driver.h
... ... @@ -18,20 +18,22 @@
18 18 #include <linux/fs.h>
19 19 #include <linux/interrupt.h>
20 20  
  21 +struct uio_map;
  22 +
21 23 /**
22 24 * struct uio_mem - description of a UIO memory region
23   - * @kobj: kobject for this mapping
24 25 * @addr: address of the device's memory
25 26 * @size: size of IO
26 27 * @memtype: type of memory addr points to
27 28 * @internal_addr: ioremap-ped version of addr, for driver internal use
  29 + * @map: for use by the UIO core only.
28 30 */
29 31 struct uio_mem {
30   - struct kobject kobj;
31 32 unsigned long addr;
32 33 unsigned long size;
33 34 int memtype;
34 35 void __iomem *internal_addr;
  36 + struct uio_map *map;
35 37 };
36 38  
37 39 #define MAX_UIO_MAPS 5