#include <linux/export.h>
#include <linux/stat.h>
#include <linux/slab.h>
+#include <linux/random.h>
+
+/**
+ * kobject_namespace - return @kobj's namespace tag
+ * @kobj: kobject in question
+ *
+ * Returns namespace tag of @kobj if its parent has namespace ops enabled
+ * and thus @kobj should have a namespace tag associated with it. Returns
+ * %NULL otherwise.
+ */
+const void *kobject_namespace(struct kobject *kobj)
+{
+ const struct kobj_ns_type_operations *ns_ops = kobj_ns_ops(kobj);
+
+ if (!ns_ops || ns_ops->type == KOBJ_NS_TYPE_NONE)
+ return NULL;
+
+ return kobj->ktype->namespace(kobj);
+}
/*
* populate_dir - populate directory with attributes.
static int create_dir(struct kobject *kobj)
{
- int error = 0;
- error = sysfs_create_dir(kobj);
- if (!error) {
- error = populate_dir(kobj);
- if (error)
- sysfs_remove_dir(kobj);
+ const struct kobj_ns_type_operations *ops;
+ int error;
+
+ error = sysfs_create_dir_ns(kobj, kobject_namespace(kobj));
+ if (error)
+ return error;
+
+ error = populate_dir(kobj);
+ if (error) {
+ sysfs_remove_dir(kobj);
+ return error;
}
- return error;
+
+ /*
+ * @kobj->sd may be deleted by an ancestor going away. Hold an
+ * extra reference so that it stays until @kobj is gone.
+ */
+ sysfs_get(kobj->sd);
+
+ /*
+ * 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)
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, '/')))
*
* 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.
*
goto out;
}
- error = sysfs_rename_dir(kobj, new_name);
+ error = sysfs_rename_dir_ns(kobj, new_name, kobject_namespace(kobj));
if (error)
goto out;
if (kobj->kset)
new_parent = kobject_get(&kobj->kset->kobj);
}
+
/* old object path */
devpath = kobject_get_path(kobj, GFP_KERNEL);
if (!devpath) {
sprintf(devpath_string, "DEVPATH_OLD=%s", devpath);
envp[0] = devpath_string;
envp[1] = NULL;
- error = sysfs_move_dir(kobj, new_parent);
+ error = sysfs_move_dir_ns(kobj, new_parent, kobject_namespace(kobj));
if (error)
goto out;
old_parent = kobj->parent;
*/
void kobject_del(struct kobject *kobj)
{
+ struct kernfs_node *sd;
+
if (!kobj)
return;
+ sd = kobj->sd;
sysfs_remove_dir(kobj);
+ sysfs_put(sd);
+
kobj->state_in_sysfs = 0;
kobj_kset_leave(kobj);
kobject_put(kobj->parent);
{
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
{
if (!k)
return;
+ kobject_del(&k->kobj);
kobject_put(&k->kobj);
}