diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/kobject.c | 170 | ||||
-rw-r--r-- | lib/kobject_uevent.c | 11 |
2 files changed, 107 insertions, 74 deletions
diff --git a/lib/kobject.c b/lib/kobject.c index c321f1910cc2..4fce5ca42c2e 100644 --- a/lib/kobject.c +++ b/lib/kobject.c | |||
@@ -124,85 +124,74 @@ char *kobject_get_path(struct kobject *kobj, gfp_t gfp_mask) | |||
124 | } | 124 | } |
125 | EXPORT_SYMBOL_GPL(kobject_get_path); | 125 | EXPORT_SYMBOL_GPL(kobject_get_path); |
126 | 126 | ||
127 | static void kobject_init_internal(struct kobject * kobj) | 127 | /* add the kobject to its kset's list */ |
128 | static void kobj_kset_join(struct kobject *kobj) | ||
128 | { | 129 | { |
129 | if (!kobj) | 130 | if (!kobj->kset) |
130 | return; | 131 | return; |
131 | kref_init(&kobj->kref); | 132 | |
132 | INIT_LIST_HEAD(&kobj->entry); | 133 | kset_get(kobj->kset); |
134 | spin_lock(&kobj->kset->list_lock); | ||
135 | list_add_tail(&kobj->entry, &kobj->kset->list); | ||
136 | spin_unlock(&kobj->kset->list_lock); | ||
133 | } | 137 | } |
134 | 138 | ||
139 | /* remove the kobject from its kset's list */ | ||
140 | static void kobj_kset_leave(struct kobject *kobj) | ||
141 | { | ||
142 | if (!kobj->kset) | ||
143 | return; | ||
135 | 144 | ||
136 | /** | 145 | spin_lock(&kobj->kset->list_lock); |
137 | * unlink - remove kobject from kset list. | 146 | list_del_init(&kobj->entry); |
138 | * @kobj: kobject. | 147 | spin_unlock(&kobj->kset->list_lock); |
139 | * | 148 | kset_put(kobj->kset); |
140 | * Remove the kobject from the kset list and decrement | 149 | } |
141 | * its parent's refcount. | ||
142 | * This is separated out, so we can use it in both | ||
143 | * kobject_del() and kobject_add_internal() on error. | ||
144 | */ | ||
145 | 150 | ||
146 | static void unlink(struct kobject * kobj) | 151 | static void kobject_init_internal(struct kobject * kobj) |
147 | { | 152 | { |
148 | struct kobject *parent = kobj->parent; | 153 | if (!kobj) |
149 | 154 | return; | |
150 | if (kobj->kset) { | 155 | kref_init(&kobj->kref); |
151 | spin_lock(&kobj->kset->list_lock); | 156 | INIT_LIST_HEAD(&kobj->entry); |
152 | list_del_init(&kobj->entry); | ||
153 | spin_unlock(&kobj->kset->list_lock); | ||
154 | } | ||
155 | kobj->parent = NULL; | ||
156 | kobject_put(kobj); | ||
157 | kobject_put(parent); | ||
158 | } | 157 | } |
159 | 158 | ||
159 | |||
160 | static int kobject_add_internal(struct kobject *kobj) | 160 | static int kobject_add_internal(struct kobject *kobj) |
161 | { | 161 | { |
162 | int error = 0; | 162 | int error = 0; |
163 | struct kobject * parent; | 163 | struct kobject * parent; |
164 | 164 | ||
165 | if (!(kobj = kobject_get(kobj))) | 165 | if (!kobj) |
166 | return -ENOENT; | 166 | return -ENOENT; |
167 | if (!kobj->k_name) | 167 | |
168 | kobject_set_name(kobj, "NO_NAME"); | 168 | if (!kobj->k_name || !kobj->k_name[0]) { |
169 | if (!*kobj->k_name) { | 169 | pr_debug("kobject: (%p): attempted to be registered with empty " |
170 | pr_debug("kobject (%p) attempted to be registered with no " | ||
171 | "name!\n", kobj); | 170 | "name!\n", kobj); |
172 | WARN_ON(1); | 171 | WARN_ON(1); |
173 | kobject_put(kobj); | ||
174 | return -EINVAL; | 172 | return -EINVAL; |
175 | } | 173 | } |
176 | parent = kobject_get(kobj->parent); | ||
177 | 174 | ||
178 | pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n", | 175 | parent = kobject_get(kobj->parent); |
179 | kobject_name(kobj), kobj, __FUNCTION__, | ||
180 | parent ? kobject_name(parent) : "<NULL>", | ||
181 | kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>" ); | ||
182 | 176 | ||
177 | /* join kset if set, use it as parent if we do not already have one */ | ||
183 | if (kobj->kset) { | 178 | if (kobj->kset) { |
184 | kobj->kset = kset_get(kobj->kset); | 179 | if (!parent) |
185 | |||
186 | if (!parent) { | ||
187 | parent = kobject_get(&kobj->kset->kobj); | 180 | parent = kobject_get(&kobj->kset->kobj); |
188 | /* | 181 | kobj_kset_join(kobj); |
189 | * If the kset is our parent, get a second | ||
190 | * reference, we drop both the kset and the | ||
191 | * parent ref on cleanup | ||
192 | */ | ||
193 | kobject_get(parent); | ||
194 | } | ||
195 | |||
196 | spin_lock(&kobj->kset->list_lock); | ||
197 | list_add_tail(&kobj->entry, &kobj->kset->list); | ||
198 | spin_unlock(&kobj->kset->list_lock); | ||
199 | kobj->parent = parent; | 182 | kobj->parent = parent; |
200 | } | 183 | } |
201 | 184 | ||
185 | pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n", | ||
186 | kobject_name(kobj), kobj, __FUNCTION__, | ||
187 | parent ? kobject_name(parent) : "<NULL>", | ||
188 | kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>" ); | ||
189 | |||
202 | error = create_dir(kobj); | 190 | error = create_dir(kobj); |
203 | if (error) { | 191 | if (error) { |
204 | /* unlink does the kobject_put() for us */ | 192 | kobj_kset_leave(kobj); |
205 | unlink(kobj); | 193 | kobject_put(parent); |
194 | kobj->parent = NULL; | ||
206 | 195 | ||
207 | /* be noisy on error issues */ | 196 | /* be noisy on error issues */ |
208 | if (error == -EEXIST) | 197 | if (error == -EEXIST) |
@@ -214,7 +203,8 @@ static int kobject_add_internal(struct kobject *kobj) | |||
214 | printk(KERN_ERR "%s failed for %s (%d)\n", | 203 | printk(KERN_ERR "%s failed for %s (%d)\n", |
215 | __FUNCTION__, kobject_name(kobj), error); | 204 | __FUNCTION__, kobject_name(kobj), error); |
216 | dump_stack(); | 205 | dump_stack(); |
217 | } | 206 | } else |
207 | kobj->state_in_sysfs = 1; | ||
218 | 208 | ||
219 | return error; | 209 | return error; |
220 | } | 210 | } |
@@ -238,11 +228,13 @@ static int kobject_set_name_vargs(struct kobject *kobj, const char *fmt, | |||
238 | if (!name) | 228 | if (!name) |
239 | return -ENOMEM; | 229 | return -ENOMEM; |
240 | 230 | ||
231 | |||
241 | /* Free the old name, if necessary. */ | 232 | /* Free the old name, if necessary. */ |
242 | kfree(kobj->k_name); | 233 | kfree(kobj->k_name); |
243 | 234 | ||
244 | /* Now, set the new name */ | 235 | /* Now, set the new name */ |
245 | kobj->k_name = name; | 236 | kobj->k_name = name; |
237 | kobj->state_name_set = 1; | ||
246 | 238 | ||
247 | return 0; | 239 | return 0; |
248 | } | 240 | } |
@@ -293,20 +285,25 @@ void kobject_init(struct kobject *kobj, struct kobj_type *ktype) | |||
293 | err_str = "must have a ktype to be initialized properly!\n"; | 285 | err_str = "must have a ktype to be initialized properly!\n"; |
294 | goto error; | 286 | goto error; |
295 | } | 287 | } |
296 | if (atomic_read(&kobj->kref.refcount)) { | 288 | if (kobj->state_initialized) { |
297 | /* do not error out as sometimes we can recover */ | 289 | /* do not error out as sometimes we can recover */ |
298 | printk(KERN_ERR "kobject: reference count is already set, " | 290 | printk(KERN_ERR "kobject (%p): tried to init an initialized " |
299 | "something is seriously wrong.\n"); | 291 | "object, something is seriously wrong.\n", kobj); |
300 | dump_stack(); | 292 | dump_stack(); |
301 | } | 293 | } |
302 | 294 | ||
303 | kref_init(&kobj->kref); | 295 | kref_init(&kobj->kref); |
304 | INIT_LIST_HEAD(&kobj->entry); | 296 | INIT_LIST_HEAD(&kobj->entry); |
305 | kobj->ktype = ktype; | 297 | kobj->ktype = ktype; |
298 | kobj->state_name_set = 0; | ||
299 | kobj->state_in_sysfs = 0; | ||
300 | kobj->state_add_uevent_sent = 0; | ||
301 | kobj->state_remove_uevent_sent = 0; | ||
302 | kobj->state_initialized = 1; | ||
306 | return; | 303 | return; |
307 | 304 | ||
308 | error: | 305 | error: |
309 | printk(KERN_ERR "kobject: %s\n", err_str); | 306 | printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str); |
310 | dump_stack(); | 307 | dump_stack(); |
311 | } | 308 | } |
312 | EXPORT_SYMBOL(kobject_init); | 309 | EXPORT_SYMBOL(kobject_init); |
@@ -345,17 +342,10 @@ static int kobject_add_varg(struct kobject *kobj, struct kobject *parent, | |||
345 | * | 342 | * |
346 | * If this function returns an error, kobject_put() must be called to | 343 | * If this function returns an error, kobject_put() must be called to |
347 | * properly clean up the memory associated with the object. | 344 | * properly clean up the memory associated with the object. |
348 | * | ||
349 | * If the function is successful, the only way to properly clean up the | ||
350 | * memory is with a call to kobject_del(), in which case, a call to | ||
351 | * kobject_put() is not necessary (kobject_del() does the final | ||
352 | * kobject_put() to call the release function in the ktype's release | ||
353 | * pointer.) | ||
354 | * | ||
355 | * Under no instance should the kobject that is passed to this function | 345 | * Under no instance should the kobject that is passed to this function |
356 | * be directly freed with a call to kfree(), that can leak memory. | 346 | * be directly freed with a call to kfree(), that can leak memory. |
357 | * | 347 | * |
358 | * Note, no uevent will be created with this call, the caller should set | 348 | * Note, no "add" uevent will be created with this call, the caller should set |
359 | * up all of the necessary sysfs files for the object and then call | 349 | * up all of the necessary sysfs files for the object and then call |
360 | * kobject_uevent() with the UEVENT_ADD parameter to ensure that | 350 | * kobject_uevent() with the UEVENT_ADD parameter to ensure that |
361 | * userspace is properly notified of this kobject's creation. | 351 | * userspace is properly notified of this kobject's creation. |
@@ -369,6 +359,13 @@ int kobject_add(struct kobject *kobj, struct kobject *parent, | |||
369 | if (!kobj) | 359 | if (!kobj) |
370 | return -EINVAL; | 360 | return -EINVAL; |
371 | 361 | ||
362 | if (!kobj->state_initialized) { | ||
363 | printk(KERN_ERR "kobject '%s' (%p): tried to add an " | ||
364 | "uninitialized object, something is seriously wrong.\n", | ||
365 | kobject_name(kobj), kobj); | ||
366 | dump_stack(); | ||
367 | return -EINVAL; | ||
368 | } | ||
372 | va_start(args, fmt); | 369 | va_start(args, fmt); |
373 | retval = kobject_add_varg(kobj, parent, fmt, args); | 370 | retval = kobject_add_varg(kobj, parent, fmt, args); |
374 | va_end(args); | 371 | va_end(args); |
@@ -527,8 +524,12 @@ void kobject_del(struct kobject * kobj) | |||
527 | { | 524 | { |
528 | if (!kobj) | 525 | if (!kobj) |
529 | return; | 526 | return; |
527 | |||
530 | sysfs_remove_dir(kobj); | 528 | sysfs_remove_dir(kobj); |
531 | unlink(kobj); | 529 | kobj->state_in_sysfs = 0; |
530 | kobj_kset_leave(kobj); | ||
531 | kobject_put(kobj->parent); | ||
532 | kobj->parent = NULL; | ||
532 | } | 533 | } |
533 | 534 | ||
534 | /** | 535 | /** |
@@ -565,21 +566,43 @@ struct kobject * kobject_get(struct kobject * kobj) | |||
565 | */ | 566 | */ |
566 | static void kobject_cleanup(struct kobject *kobj) | 567 | static void kobject_cleanup(struct kobject *kobj) |
567 | { | 568 | { |
568 | struct kobj_type * t = get_ktype(kobj); | 569 | struct kobj_type *t = get_ktype(kobj); |
569 | struct kset * s = kobj->kset; | ||
570 | const char *name = kobj->k_name; | 570 | const char *name = kobj->k_name; |
571 | int name_set = kobj->state_name_set; | ||
571 | 572 | ||
572 | pr_debug("kobject: '%s' (%p): %s\n", | 573 | pr_debug("kobject: '%s' (%p): %s\n", |
573 | kobject_name(kobj), kobj, __FUNCTION__); | 574 | kobject_name(kobj), kobj, __FUNCTION__); |
575 | |||
576 | if (t && !t->release) | ||
577 | pr_debug("kobject: '%s' (%p): does not have a release() " | ||
578 | "function, it is broken and must be fixed.\n", | ||
579 | kobject_name(kobj), kobj); | ||
580 | |||
581 | /* send "remove" if the caller did not do it but sent "add" */ | ||
582 | if (kobj->state_add_uevent_sent && !kobj->state_remove_uevent_sent) { | ||
583 | pr_debug("kobject: '%s' (%p): auto cleanup 'remove' event\n", | ||
584 | kobject_name(kobj), kobj); | ||
585 | kobject_uevent(kobj, KOBJ_REMOVE); | ||
586 | } | ||
587 | |||
588 | /* remove from sysfs if the caller did not do it */ | ||
589 | if (kobj->state_in_sysfs) { | ||
590 | pr_debug("kobject: '%s' (%p): auto cleanup kobject_del\n", | ||
591 | kobject_name(kobj), kobj); | ||
592 | kobject_del(kobj); | ||
593 | } | ||
594 | |||
574 | if (t && t->release) { | 595 | if (t && t->release) { |
596 | pr_debug("kobject: '%s' (%p): calling ktype release\n", | ||
597 | kobject_name(kobj), kobj); | ||
575 | t->release(kobj); | 598 | t->release(kobj); |
576 | /* If we have a release function, we can guess that this was | 599 | } |
577 | * not a statically allocated kobject, so we should be safe to | 600 | |
578 | * free the name */ | 601 | /* free name if we allocated it */ |
602 | if (name_set && name) { | ||
603 | pr_debug("kobject: '%s': free name\n", name); | ||
579 | kfree(name); | 604 | kfree(name); |
580 | } | 605 | } |
581 | if (s) | ||
582 | kset_put(s); | ||
583 | } | 606 | } |
584 | 607 | ||
585 | static void kobject_release(struct kref *kref) | 608 | static void kobject_release(struct kref *kref) |
@@ -601,8 +624,7 @@ void kobject_put(struct kobject * kobj) | |||
601 | 624 | ||
602 | static void dynamic_kobj_release(struct kobject *kobj) | 625 | static void dynamic_kobj_release(struct kobject *kobj) |
603 | { | 626 | { |
604 | pr_debug("kobject: '%s' (%p): %s\n", | 627 | pr_debug("kobject: (%p): %s\n", kobj, __FUNCTION__); |
605 | kobject_name(kobj), kobj, __FUNCTION__); | ||
606 | kfree(kobj); | 628 | kfree(kobj); |
607 | } | 629 | } |
608 | 630 | ||
diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index 51dc4d287add..b021e67c4294 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c | |||
@@ -180,6 +180,17 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, | |||
180 | } | 180 | } |
181 | } | 181 | } |
182 | 182 | ||
183 | /* | ||
184 | * Mark "add" and "remove" events in the object to ensure proper | ||
185 | * events to userspace during automatic cleanup. If the object did | ||
186 | * send an "add" event, "remove" will automatically generated by | ||
187 | * the core, if not already done by the caller. | ||
188 | */ | ||
189 | if (action == KOBJ_ADD) | ||
190 | kobj->state_add_uevent_sent = 1; | ||
191 | else if (action == KOBJ_REMOVE) | ||
192 | kobj->state_remove_uevent_sent = 1; | ||
193 | |||
183 | /* we will send an event, so request a new sequence number */ | 194 | /* we will send an event, so request a new sequence number */ |
184 | spin_lock(&sequence_lock); | 195 | spin_lock(&sequence_lock); |
185 | seq = ++uevent_seqnum; | 196 | seq = ++uevent_seqnum; |