Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux...
[sfrench/cifs-2.6.git] / lib / kobject.c
index 03512a40a3ef9e93387a3217617bc8f9927ebcbe..cb14aeac4ccaeedfe537d423c41c3d0b021e1c9f 100644 (file)
  */
 
 #include <linux/kobject.h>
-#include <linux/kobj_completion.h>
 #include <linux/string.h>
 #include <linux/export.h>
 #include <linux/stat.h>
 #include <linux/slab.h>
+#include <linux/random.h>
 
 /**
  * kobject_namespace - return @kobj's namespace tag
@@ -65,13 +65,17 @@ static int populate_dir(struct kobject *kobj)
 
 static int create_dir(struct kobject *kobj)
 {
+       const struct kobj_ns_type_operations *ops;
        int error;
 
        error = sysfs_create_dir_ns(kobj, kobject_namespace(kobj));
-       if (!error) {
-               error = populate_dir(kobj);
-               if (error)
-                       sysfs_remove_dir(kobj);
+       if (error)
+               return error;
+
+       error = populate_dir(kobj);
+       if (error) {
+               sysfs_remove_dir(kobj);
+               return error;
        }
 
        /*
@@ -80,7 +84,20 @@ static int create_dir(struct kobject *kobj)
         */
        sysfs_get(kobj->sd);
 
-       return error;
+       /*
+        * If @kobj has ns_ops, its children need to be filtered based on
+        * their namespace tags.  Enable namespace support on @kobj->sd.
+        */
+       ops = kobj_child_ns_ops(kobj);
+       if (ops) {
+               BUG_ON(ops->type <= KOBJ_NS_TYPE_NONE);
+               BUG_ON(ops->type >= KOBJ_NS_TYPES);
+               BUG_ON(!kobj_ns_type_registered(ops->type));
+
+               kernfs_enable_ns(kobj->sd);
+       }
+
+       return 0;
 }
 
 static int get_kobj_path_length(struct kobject *kobj)
@@ -247,8 +264,10 @@ int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,
                return 0;
 
        kobj->name = kvasprintf(GFP_KERNEL, fmt, vargs);
-       if (!kobj->name)
+       if (!kobj->name) {
+               kobj->name = old_name;
                return -ENOMEM;
+       }
 
        /* ewww... some of these buggers have '/' in the name ... */
        while ((s = strchr(kobj->name, '/')))
@@ -346,7 +365,7 @@ static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,
  *
  * If @parent is set, then the parent of the @kobj will be set to it.
  * If @parent is NULL, then the parent of the @kobj will be set to the
- * kobject associted with the kset assigned to this kobject.  If no kset
+ * kobject associated with the kset assigned to this kobject.  If no kset
  * is assigned to the kobject, then the kobject will be located in the
  * root of the sysfs tree.
  *
@@ -536,7 +555,7 @@ out:
  */
 void kobject_del(struct kobject *kobj)
 {
-       struct sysfs_dirent *sd;
+       struct kernfs_node *sd;
 
        if (!kobj)
                return;
@@ -625,10 +644,12 @@ static void kobject_release(struct kref *kref)
 {
        struct kobject *kobj = container_of(kref, struct kobject, kref);
 #ifdef CONFIG_DEBUG_KOBJECT_RELEASE
-       pr_info("kobject: '%s' (%p): %s, parent %p (delayed)\n",
-                kobject_name(kobj), kobj, __func__, kobj->parent);
+       unsigned long delay = HZ + HZ * (get_random_int() & 0x3);
+       pr_info("kobject: '%s' (%p): %s, parent %p (delayed %ld)\n",
+                kobject_name(kobj), kobj, __func__, kobj->parent, delay);
        INIT_DELAYED_WORK(&kobj->release, kobject_delayed_cleanup);
-       schedule_delayed_work(&kobj->release, HZ);
+
+       schedule_delayed_work(&kobj->release, delay);
 #else
        kobject_cleanup(kobj);
 #endif
@@ -760,55 +781,6 @@ const struct sysfs_ops kobj_sysfs_ops = {
 };
 EXPORT_SYMBOL_GPL(kobj_sysfs_ops);
 
-/**
- * kobj_completion_init - initialize a kobj_completion object.
- * @kc: kobj_completion
- * @ktype: type of kobject to initialize
- *
- * kobj_completion structures can be embedded within structures with different
- * lifetime rules.  During the release of the enclosing object, we can
- * wait on the release of the kobject so that we don't free it while it's
- * still busy.
- */
-void kobj_completion_init(struct kobj_completion *kc, struct kobj_type *ktype)
-{
-       init_completion(&kc->kc_unregister);
-       kobject_init(&kc->kc_kobj, ktype);
-}
-EXPORT_SYMBOL_GPL(kobj_completion_init);
-
-/**
- * kobj_completion_release - release a kobj_completion object
- * @kobj: kobject embedded in kobj_completion
- *
- * Used with kobject_release to notify waiters that the kobject has been
- * released.
- */
-void kobj_completion_release(struct kobject *kobj)
-{
-       struct kobj_completion *kc = kobj_to_kobj_completion(kobj);
-       complete(&kc->kc_unregister);
-}
-EXPORT_SYMBOL_GPL(kobj_completion_release);
-
-/**
- * kobj_completion_del_and_wait - release the kobject and wait for it
- * @kc: kobj_completion object to release
- *
- * Delete the kobject from sysfs and drop the reference count.  Then wait
- * until any other outstanding references are also dropped.  This routine
- * is only necessary once other references may have been taken on the
- * kobject.  Typically this happens when the kobject has been published
- * to sysfs via kobject_add.
- */
-void kobj_completion_del_and_wait(struct kobj_completion *kc)
-{
-       kobject_del(&kc->kc_kobj);
-       kobject_put(&kc->kc_kobj);
-       wait_for_completion(&kc->kc_unregister);
-}
-EXPORT_SYMBOL_GPL(kobj_completion_del_and_wait);
-
 /**
  * kset_register - initialize and add a kset.
  * @k: kset.
@@ -836,6 +808,7 @@ void kset_unregister(struct kset *k)
 {
        if (!k)
                return;
+       kobject_del(&k->kobj);
        kobject_put(&k->kobj);
 }