[SCTP]: Fix the SO_REUSEADDR handling to be similar to TCP.
[safe/jmp/linux-2.6] / lib / kobject.c
index 25204a4..cecf2fb 100644 (file)
@@ -44,11 +44,11 @@ static int populate_dir(struct kobject * kobj)
        return error;
 }
 
-static int create_dir(struct kobject * kobj)
+static int create_dir(struct kobject * kobj, struct dentry *shadow_parent)
 {
        int error = 0;
        if (kobject_name(kobj)) {
-               error = sysfs_create_dir(kobj);
+               error = sysfs_create_dir(kobj, shadow_parent);
                if (!error) {
                        if ((error = populate_dir(kobj)))
                                sysfs_remove_dir(kobj);
@@ -97,11 +97,12 @@ static void fill_kobj_path(struct kobject *kobj, char *path, int length)
 }
 
 /**
- * kobject_get_path - generate and return the path associated with a given kobj
- * and kset pair.  The result must be freed by the caller with kfree().
+ * kobject_get_path - generate and return the path associated with a given kobj and kset pair.
  *
  * @kobj:      kobject in question, with which to build the path
  * @gfp_mask:  the allocation type used to allocate the path
+ *
+ * The result must be freed by the caller with kfree().
  */
 char *kobject_get_path(struct kobject *kobj, gfp_t gfp_mask)
 {
@@ -111,14 +112,14 @@ char *kobject_get_path(struct kobject *kobj, gfp_t gfp_mask)
        len = get_kobj_path_length(kobj);
        if (len == 0)
                return NULL;
-       path = kmalloc(len, gfp_mask);
+       path = kzalloc(len, gfp_mask);
        if (!path)
                return NULL;
-       memset(path, 0x00, len);
        fill_kobj_path(kobj, path, len);
 
        return path;
 }
+EXPORT_SYMBOL_GPL(kobject_get_path);
 
 /**
  *     kobject_init - initialize object.
@@ -126,8 +127,11 @@ char *kobject_get_path(struct kobject *kobj, gfp_t gfp_mask)
  */
 void kobject_init(struct kobject * kobj)
 {
+       if (!kobj)
+               return;
        kref_init(&kobj->kref);
        INIT_LIST_HEAD(&kobj->entry);
+       init_waitqueue_head(&kobj->poll);
        kobj->kset = kset_get(kobj->kset);
 }
 
@@ -153,11 +157,12 @@ static void unlink(struct kobject * kobj)
 }
 
 /**
- *     kobject_add - add an object to the hierarchy.
+ *     kobject_shadow_add - add an object to the hierarchy.
  *     @kobj:  object.
+ *     @shadow_parent: sysfs directory to add to.
  */
 
-int kobject_add(struct kobject * kobj)
+int kobject_shadow_add(struct kobject * kobj, struct dentry *shadow_parent)
 {
        int error = 0;
        struct kobject * parent;
@@ -166,9 +171,10 @@ int kobject_add(struct kobject * kobj)
                return -ENOENT;
        if (!kobj->k_name)
                kobj->k_name = kobj->name;
-       if (!kobj->k_name) {
+       if (!*kobj->k_name) {
                pr_debug("kobject attempted to be registered with no name!\n");
                WARN_ON(1);
+               kobject_put(kobj);
                return -EINVAL;
        }
        parent = kobject_get(kobj->parent);
@@ -185,15 +191,14 @@ int kobject_add(struct kobject * kobj)
 
                list_add_tail(&kobj->entry,&kobj->kset->list);
                spin_unlock(&kobj->kset->list_lock);
+               kobj->parent = parent;
        }
-       kobj->parent = parent;
 
-       error = create_dir(kobj);
+       error = create_dir(kobj, shadow_parent);
        if (error) {
                /* unlink does the kobject_put() for us */
                unlink(kobj);
-               if (parent)
-                       kobject_put(parent);
+               kobject_put(parent);
 
                /* be noisy on error issues */
                if (error == -EEXIST)
@@ -204,12 +209,21 @@ int kobject_add(struct kobject * kobj)
                else
                        printk("kobject_add failed for %s (%d)\n",
                               kobject_name(kobj), error);
-               dump_stack();
+                dump_stack();
        }
 
        return error;
 }
 
+/**
+ *     kobject_add - add an object to the hierarchy.
+ *     @kobj:  object.
+ */
+int kobject_add(struct kobject * kobj)
+{
+       return kobject_shadow_add(kobj, NULL);
+}
+
 
 /**
  *     kobject_register - initialize and add an object.
@@ -298,23 +312,130 @@ EXPORT_SYMBOL(kobject_set_name);
 int kobject_rename(struct kobject * kobj, const char *new_name)
 {
        int error = 0;
+       const char *devpath = NULL;
+       char *devpath_string = NULL;
+       char *envp[2];
 
        kobj = kobject_get(kobj);
        if (!kobj)
                return -EINVAL;
-       error = sysfs_rename_dir(kobj, new_name);
+       if (!kobj->parent)
+               return -EINVAL;
+
+       devpath = kobject_get_path(kobj, GFP_KERNEL);
+       if (!devpath) {
+               error = -ENOMEM;
+               goto out;
+       }
+       devpath_string = kmalloc(strlen(devpath) + 15, GFP_KERNEL);
+       if (!devpath_string) {
+               error = -ENOMEM;
+               goto out;
+       }
+       sprintf(devpath_string, "DEVPATH_OLD=%s", devpath);
+       envp[0] = devpath_string;
+       envp[1] = NULL;
+       /* Note : if we want to send the new name alone, not the full path,
+        * we could probably use kobject_name(kobj); */
+
+       error = sysfs_rename_dir(kobj, kobj->parent->dentry, new_name);
+
+       /* This function is mostly/only used for network interface.
+        * Some hotplug package track interfaces by their name and
+        * therefore want to know when the name is changed by the user. */
+       if (!error)
+               kobject_uevent_env(kobj, KOBJ_MOVE, envp);
+
+out:
+       kfree(devpath_string);
+       kfree(devpath);
        kobject_put(kobj);
 
        return error;
 }
 
 /**
+ *     kobject_rename - change the name of an object
+ *     @kobj:  object in question.
+ *     @new_parent: object's new parent
+ *     @new_name: object's new name
+ */
+
+int kobject_shadow_rename(struct kobject * kobj, struct dentry *new_parent,
+                         const char *new_name)
+{
+       int error = 0;
+
+       kobj = kobject_get(kobj);
+       if (!kobj)
+               return -EINVAL;
+       error = sysfs_rename_dir(kobj, new_parent, new_name);
+       kobject_put(kobj);
+
+       return error;
+}
+
+/**
+ *     kobject_move - move object to another parent
+ *     @kobj:  object in question.
+ *     @new_parent: object's new parent (can be NULL)
+ */
+
+int kobject_move(struct kobject *kobj, struct kobject *new_parent)
+{
+       int error;
+       struct kobject *old_parent;
+       const char *devpath = NULL;
+       char *devpath_string = NULL;
+       char *envp[2];
+
+       kobj = kobject_get(kobj);
+       if (!kobj)
+               return -EINVAL;
+       new_parent = kobject_get(new_parent);
+       if (!new_parent) {
+               if (kobj->kset)
+                       new_parent = kobject_get(&kobj->kset->kobj);
+       }
+       /* old object path */
+       devpath = kobject_get_path(kobj, GFP_KERNEL);
+       if (!devpath) {
+               error = -ENOMEM;
+               goto out;
+       }
+       devpath_string = kmalloc(strlen(devpath) + 15, GFP_KERNEL);
+       if (!devpath_string) {
+               error = -ENOMEM;
+               goto out;
+       }
+       sprintf(devpath_string, "DEVPATH_OLD=%s", devpath);
+       envp[0] = devpath_string;
+       envp[1] = NULL;
+       error = sysfs_move_dir(kobj, new_parent);
+       if (error)
+               goto out;
+       old_parent = kobj->parent;
+       kobj->parent = new_parent;
+       new_parent = NULL;
+       kobject_put(old_parent);
+       kobject_uevent_env(kobj, KOBJ_MOVE, envp);
+out:
+       kobject_put(new_parent);
+       kobject_put(kobj);
+       kfree(devpath_string);
+       kfree(devpath);
+       return error;
+}
+
+/**
  *     kobject_del - unlink kobject from hierarchy.
  *     @kobj:  object.
  */
 
 void kobject_del(struct kobject * kobj)
 {
+       if (!kobj)
+               return;
        sysfs_remove_dir(kobj);
        unlink(kobj);
 }
@@ -326,6 +447,8 @@ void kobject_del(struct kobject * kobj)
 
 void kobject_unregister(struct kobject * kobj)
 {
+       if (!kobj)
+               return;
        pr_debug("kobject %s: unregistering\n",kobject_name(kobj));
        kobject_uevent(kobj, KOBJ_REMOVE);
        kobject_del(kobj);
@@ -363,8 +486,7 @@ void kobject_cleanup(struct kobject * kobj)
                t->release(kobj);
        if (s)
                kset_put(s);
-       if (parent) 
-               kobject_put(parent);
+       kobject_put(parent);
 }
 
 static void kobject_release(struct kref *kref)
@@ -397,15 +519,18 @@ static struct kobj_type dir_ktype = {
 };
 
 /**
- *     kobject_add_dir - add sub directory of object.
+ *     kobject_kset_add_dir - add sub directory of object.
+ *     @kset:          kset the directory is belongs to.
  *     @parent:        object in which a directory is created.
  *     @name:  directory name.
  *
  *     Add a plain directory object as child of given object.
  */
-struct kobject *kobject_add_dir(struct kobject *parent, const char *name)
+struct kobject *kobject_kset_add_dir(struct kset *kset,
+                                    struct kobject *parent, const char *name)
 {
        struct kobject *k;
+       int ret;
 
        if (!parent)
                return NULL;
@@ -414,14 +539,32 @@ struct kobject *kobject_add_dir(struct kobject *parent, const char *name)
        if (!k)
                return NULL;
 
+       k->kset = kset;
        k->parent = parent;
        k->ktype = &dir_ktype;
        kobject_set_name(k, name);
-       kobject_register(k);
+       ret = kobject_register(k);
+       if (ret < 0) {
+               printk(KERN_WARNING "%s: kobject_register error: %d\n",
+                       __func__, ret);
+               kobject_del(k);
+               return NULL;
+       }
 
        return k;
 }
-EXPORT_SYMBOL_GPL(kobject_add_dir);
+
+/**
+ *     kobject_add_dir - add sub directory of object.
+ *     @parent:        object in which a directory is created.
+ *     @name:  directory name.
+ *
+ *     Add a plain directory object as child of given object.
+ */
+struct kobject *kobject_add_dir(struct kobject *parent, const char *name)
+{
+       return kobject_kset_add_dir(NULL, parent, name);
+}
 
 /**
  *     kset_init - initialize a kset for use
@@ -466,6 +609,8 @@ int kset_add(struct kset * k)
 
 int kset_register(struct kset * k)
 {
+       if (!k)
+               return -EINVAL;
        kset_init(k);
        return kset_add(k);
 }
@@ -478,6 +623,8 @@ int kset_register(struct kset * k)
 
 void kset_unregister(struct kset * k)
 {
+       if (!k)
+               return;
        kobject_unregister(&k->kobj);
 }
 
@@ -512,7 +659,6 @@ struct kobject * kset_find_obj(struct kset * kset, const char * name)
 
 void subsystem_init(struct subsystem * s)
 {
-       init_rwsem(&s->rwsem);
        kset_init(&s->kset);
 }
 
@@ -521,14 +667,16 @@ void subsystem_init(struct subsystem * s)
  *     @s:     the subsystem we're registering.
  *
  *     Once we register the subsystem, we want to make sure that 
- *     the kset points back to this subsystem for correct usage of 
- *     the rwsem. 
+ *     the kset points back to this subsystem.
  */
 
 int subsystem_register(struct subsystem * s)
 {
        int error;
 
+       if (!s)
+               return -EINVAL;
+
        subsystem_init(s);
        pr_debug("subsystem %s: registering\n",s->kset.kobj.name);
 
@@ -541,6 +689,8 @@ int subsystem_register(struct subsystem * s)
 
 void subsystem_unregister(struct subsystem * s)
 {
+       if (!s)
+               return;
        pr_debug("subsystem %s: unregistering\n",s->kset.kobj.name);
        kset_unregister(&s->kset);
 }
@@ -555,6 +705,10 @@ void subsystem_unregister(struct subsystem * s)
 int subsys_create_file(struct subsystem * s, struct subsys_attribute * a)
 {
        int error = 0;
+
+       if (!s || !a)
+               return -EINVAL;
+
        if (subsys_get(s)) {
                error = sysfs_create_file(&s->kset.kobj,&a->attr);
                subsys_put(s);
@@ -568,7 +722,7 @@ int subsys_create_file(struct subsystem * s, struct subsys_attribute * a)
  *     @s:     subsystem.
  *     @a:     attribute desciptor.
  */
-
+#if 0
 void subsys_remove_file(struct subsystem * s, struct subsys_attribute * a)
 {
        if (subsys_get(s)) {
@@ -576,6 +730,7 @@ void subsys_remove_file(struct subsystem * s, struct subsys_attribute * a)
                subsys_put(s);
        }
 }
+#endif  /*  0  */
 
 EXPORT_SYMBOL(kobject_init);
 EXPORT_SYMBOL(kobject_register);
@@ -587,10 +742,7 @@ EXPORT_SYMBOL(kobject_del);
 
 EXPORT_SYMBOL(kset_register);
 EXPORT_SYMBOL(kset_unregister);
-EXPORT_SYMBOL(kset_find_obj);
 
-EXPORT_SYMBOL(subsystem_init);
 EXPORT_SYMBOL(subsystem_register);
 EXPORT_SYMBOL(subsystem_unregister);
 EXPORT_SYMBOL(subsys_create_file);
-EXPORT_SYMBOL(subsys_remove_file);