}
 EXPORT_SYMBOL_GPL(kobject_get_path);
 
-static void kobject_init_internal(struct kobject * kobj)
+/* add the kobject to its kset's list */
+static void kobj_kset_join(struct kobject *kobj)
 {
-       if (!kobj)
+       if (!kobj->kset)
                return;
-       kref_init(&kobj->kref);
-       INIT_LIST_HEAD(&kobj->entry);
+
+       kset_get(kobj->kset);
+       spin_lock(&kobj->kset->list_lock);
+       list_add_tail(&kobj->entry, &kobj->kset->list);
+       spin_unlock(&kobj->kset->list_lock);
 }
 
+/* remove the kobject from its kset's list */
+static void kobj_kset_leave(struct kobject *kobj)
+{
+       if (!kobj->kset)
+               return;
 
-/**
- *     unlink - remove kobject from kset list.
- *     @kobj:  kobject.
- *
- *     Remove the kobject from the kset list and decrement
- *     its parent's refcount.
- *     This is separated out, so we can use it in both 
- *     kobject_del() and kobject_add_internal() on error.
- */
+       spin_lock(&kobj->kset->list_lock);
+       list_del_init(&kobj->entry);
+       spin_unlock(&kobj->kset->list_lock);
+       kset_put(kobj->kset);
+}
 
-static void unlink(struct kobject * kobj)
+static void kobject_init_internal(struct kobject * kobj)
 {
-       struct kobject *parent = kobj->parent;
-
-       if (kobj->kset) {
-               spin_lock(&kobj->kset->list_lock);
-               list_del_init(&kobj->entry);
-               spin_unlock(&kobj->kset->list_lock);
-       }
-       kobj->parent = NULL;
-       kobject_put(kobj);
-       kobject_put(parent);
+       if (!kobj)
+               return;
+       kref_init(&kobj->kref);
+       INIT_LIST_HEAD(&kobj->entry);
 }
 
+
 static int kobject_add_internal(struct kobject *kobj)
 {
        int error = 0;
        struct kobject * parent;
 
-       if (!(kobj = kobject_get(kobj)))
+       if (!kobj)
                return -ENOENT;
-       if (!kobj->k_name)
-               kobject_set_name(kobj, "NO_NAME");
-       if (!*kobj->k_name) {
-               pr_debug("kobject (%p) attempted to be registered with no "
+
+       if (!kobj->k_name || !kobj->k_name[0]) {
+               pr_debug("kobject: (%p): attempted to be registered with empty "
                         "name!\n", kobj);
                WARN_ON(1);
-               kobject_put(kobj);
                return -EINVAL;
        }
-       parent = kobject_get(kobj->parent);
 
-       pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",
-                kobject_name(kobj), kobj, __FUNCTION__,
-                parent ? kobject_name(parent) : "<NULL>",
-                kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>" );
+       parent = kobject_get(kobj->parent);
 
+       /* join kset if set, use it as parent if we do not already have one */
        if (kobj->kset) {
-               kobj->kset = kset_get(kobj->kset);
-
-               if (!parent) {
+               if (!parent)
                        parent = kobject_get(&kobj->kset->kobj);
-                       /*
-                        * If the kset is our parent, get a second
-                        * reference, we drop both the kset and the
-                        * parent ref on cleanup
-                        */
-                       kobject_get(parent);
-               }
-
-               spin_lock(&kobj->kset->list_lock);
-               list_add_tail(&kobj->entry, &kobj->kset->list);
-               spin_unlock(&kobj->kset->list_lock);
+               kobj_kset_join(kobj);
                kobj->parent = parent;
        }
 
+       pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",
+                kobject_name(kobj), kobj, __FUNCTION__,
+                parent ? kobject_name(parent) : "<NULL>",
+                kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>" );
+
        error = create_dir(kobj);
        if (error) {
-               /* unlink does the kobject_put() for us */
-               unlink(kobj);
+               kobj_kset_leave(kobj);
+               kobject_put(parent);
+               kobj->parent = NULL;
 
                /* be noisy on error issues */
                if (error == -EEXIST)
                        printk(KERN_ERR "%s failed for %s (%d)\n",
                               __FUNCTION__, kobject_name(kobj), error);
                dump_stack();
-       }
+       } else
+               kobj->state_in_sysfs = 1;
 
        return error;
 }
        if (!name)
                return -ENOMEM;
 
+
        /* Free the old name, if necessary. */
        kfree(kobj->k_name);
 
        /* Now, set the new name */
        kobj->k_name = name;
+       kobj->state_name_set = 1;
 
        return 0;
 }
                err_str = "must have a ktype to be initialized properly!\n";
                goto error;
        }
-       if (atomic_read(&kobj->kref.refcount)) {
+       if (kobj->state_initialized) {
                /* do not error out as sometimes we can recover */
-               printk(KERN_ERR "kobject: reference count is already set, "
-                      "something is seriously wrong.\n");
+               printk(KERN_ERR "kobject (%p): tried to init an initialized "
+                      "object, something is seriously wrong.\n", kobj);
                dump_stack();
        }
 
        kref_init(&kobj->kref);
        INIT_LIST_HEAD(&kobj->entry);
        kobj->ktype = ktype;
+       kobj->state_name_set = 0;
+       kobj->state_in_sysfs = 0;
+       kobj->state_add_uevent_sent = 0;
+       kobj->state_remove_uevent_sent = 0;
+       kobj->state_initialized = 1;
        return;
 
 error:
-       printk(KERN_ERR "kobject: %s\n", err_str);
+       printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str);
        dump_stack();
 }
 EXPORT_SYMBOL(kobject_init);
  *
  * If this function returns an error, kobject_put() must be called to
  * properly clean up the memory associated with the object.
- *
- * If the function is successful, the only way to properly clean up the
- * memory is with a call to kobject_del(), in which case, a call to
- * kobject_put() is not necessary (kobject_del() does the final
- * kobject_put() to call the release function in the ktype's release
- * pointer.)
- *
  * Under no instance should the kobject that is passed to this function
  * be directly freed with a call to kfree(), that can leak memory.
  *
- * Note, no uevent will be created with this call, the caller should set
+ * Note, no "add" uevent will be created with this call, the caller should set
  * up all of the necessary sysfs files for the object and then call
  * kobject_uevent() with the UEVENT_ADD parameter to ensure that
  * userspace is properly notified of this kobject's creation.
        if (!kobj)
                return -EINVAL;
 
+       if (!kobj->state_initialized) {
+               printk(KERN_ERR "kobject '%s' (%p): tried to add an "
+                      "uninitialized object, something is seriously wrong.\n",
+                      kobject_name(kobj), kobj);
+               dump_stack();
+               return -EINVAL;
+       }
        va_start(args, fmt);
        retval = kobject_add_varg(kobj, parent, fmt, args);
        va_end(args);
 {
        if (!kobj)
                return;
+
        sysfs_remove_dir(kobj);
-       unlink(kobj);
+       kobj->state_in_sysfs = 0;
+       kobj_kset_leave(kobj);
+       kobject_put(kobj->parent);
+       kobj->parent = NULL;
 }
 
 /**
  */
 static void kobject_cleanup(struct kobject *kobj)
 {
-       struct kobj_type * t = get_ktype(kobj);
-       struct kset * s = kobj->kset;
+       struct kobj_type *t = get_ktype(kobj);
        const char *name = kobj->k_name;
+       int name_set = kobj->state_name_set;
 
        pr_debug("kobject: '%s' (%p): %s\n",
                 kobject_name(kobj), kobj, __FUNCTION__);
+
+       if (t && !t->release)
+               pr_debug("kobject: '%s' (%p): does not have a release() "
+                        "function, it is broken and must be fixed.\n",
+                        kobject_name(kobj), kobj);
+
+       /* send "remove" if the caller did not do it but sent "add" */
+       if (kobj->state_add_uevent_sent && !kobj->state_remove_uevent_sent) {
+               pr_debug("kobject: '%s' (%p): auto cleanup 'remove' event\n",
+                        kobject_name(kobj), kobj);
+               kobject_uevent(kobj, KOBJ_REMOVE);
+       }
+
+       /* remove from sysfs if the caller did not do it */
+       if (kobj->state_in_sysfs) {
+               pr_debug("kobject: '%s' (%p): auto cleanup kobject_del\n",
+                        kobject_name(kobj), kobj);
+               kobject_del(kobj);
+       }
+
        if (t && t->release) {
+               pr_debug("kobject: '%s' (%p): calling ktype release\n",
+                        kobject_name(kobj), kobj);
                t->release(kobj);
-               /* If we have a release function, we can guess that this was
-                * not a statically allocated kobject, so we should be safe to
-                * free the name */
+       }
+
+       /* free name if we allocated it */
+       if (name_set && name) {
+               pr_debug("kobject: '%s': free name\n", name);
                kfree(name);
        }
-       if (s)
-               kset_put(s);
 }
 
 static void kobject_release(struct kref *kref)
 
 static void dynamic_kobj_release(struct kobject *kobj)
 {
-       pr_debug("kobject: '%s' (%p): %s\n",
-                kobject_name(kobj), kobj, __FUNCTION__);
+       pr_debug("kobject: (%p): %s\n", kobj, __FUNCTION__);
        kfree(kobj);
 }