162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * kobject.c - library routines for handling generic kernel objects 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2002-2003 Patrick Mochel <mochel@osdl.org> 662306a36Sopenharmony_ci * Copyright (c) 2006-2007 Greg Kroah-Hartman <greg@kroah.com> 762306a36Sopenharmony_ci * Copyright (c) 2006-2007 Novell Inc. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Please see the file Documentation/core-api/kobject.rst for critical information 1062306a36Sopenharmony_ci * about using the kobject interface. 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <linux/kobject.h> 1662306a36Sopenharmony_ci#include <linux/string.h> 1762306a36Sopenharmony_ci#include <linux/export.h> 1862306a36Sopenharmony_ci#include <linux/stat.h> 1962306a36Sopenharmony_ci#include <linux/slab.h> 2062306a36Sopenharmony_ci#include <linux/random.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/** 2362306a36Sopenharmony_ci * kobject_namespace() - Return @kobj's namespace tag. 2462306a36Sopenharmony_ci * @kobj: kobject in question 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * Returns namespace tag of @kobj if its parent has namespace ops enabled 2762306a36Sopenharmony_ci * and thus @kobj should have a namespace tag associated with it. Returns 2862306a36Sopenharmony_ci * %NULL otherwise. 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_ciconst void *kobject_namespace(const struct kobject *kobj) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci const struct kobj_ns_type_operations *ns_ops = kobj_ns_ops(kobj); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci if (!ns_ops || ns_ops->type == KOBJ_NS_TYPE_NONE) 3562306a36Sopenharmony_ci return NULL; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci return kobj->ktype->namespace(kobj); 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/** 4162306a36Sopenharmony_ci * kobject_get_ownership() - Get sysfs ownership data for @kobj. 4262306a36Sopenharmony_ci * @kobj: kobject in question 4362306a36Sopenharmony_ci * @uid: kernel user ID for sysfs objects 4462306a36Sopenharmony_ci * @gid: kernel group ID for sysfs objects 4562306a36Sopenharmony_ci * 4662306a36Sopenharmony_ci * Returns initial uid/gid pair that should be used when creating sysfs 4762306a36Sopenharmony_ci * representation of given kobject. Normally used to adjust ownership of 4862306a36Sopenharmony_ci * objects in a container. 4962306a36Sopenharmony_ci */ 5062306a36Sopenharmony_civoid kobject_get_ownership(const struct kobject *kobj, kuid_t *uid, kgid_t *gid) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci *uid = GLOBAL_ROOT_UID; 5362306a36Sopenharmony_ci *gid = GLOBAL_ROOT_GID; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci if (kobj->ktype->get_ownership) 5662306a36Sopenharmony_ci kobj->ktype->get_ownership(kobj, uid, gid); 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic bool kobj_ns_type_is_valid(enum kobj_ns_type type) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci if ((type <= KOBJ_NS_TYPE_NONE) || (type >= KOBJ_NS_TYPES)) 6262306a36Sopenharmony_ci return false; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci return true; 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic int create_dir(struct kobject *kobj) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci const struct kobj_type *ktype = get_ktype(kobj); 7062306a36Sopenharmony_ci const struct kobj_ns_type_operations *ops; 7162306a36Sopenharmony_ci int error; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci error = sysfs_create_dir_ns(kobj, kobject_namespace(kobj)); 7462306a36Sopenharmony_ci if (error) 7562306a36Sopenharmony_ci return error; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci if (ktype) { 7862306a36Sopenharmony_ci error = sysfs_create_groups(kobj, ktype->default_groups); 7962306a36Sopenharmony_ci if (error) { 8062306a36Sopenharmony_ci sysfs_remove_dir(kobj); 8162306a36Sopenharmony_ci return error; 8262306a36Sopenharmony_ci } 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci /* 8662306a36Sopenharmony_ci * @kobj->sd may be deleted by an ancestor going away. Hold an 8762306a36Sopenharmony_ci * extra reference so that it stays until @kobj is gone. 8862306a36Sopenharmony_ci */ 8962306a36Sopenharmony_ci sysfs_get(kobj->sd); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci /* 9262306a36Sopenharmony_ci * If @kobj has ns_ops, its children need to be filtered based on 9362306a36Sopenharmony_ci * their namespace tags. Enable namespace support on @kobj->sd. 9462306a36Sopenharmony_ci */ 9562306a36Sopenharmony_ci ops = kobj_child_ns_ops(kobj); 9662306a36Sopenharmony_ci if (ops) { 9762306a36Sopenharmony_ci BUG_ON(!kobj_ns_type_is_valid(ops->type)); 9862306a36Sopenharmony_ci BUG_ON(!kobj_ns_type_registered(ops->type)); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci sysfs_enable_ns(kobj->sd); 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci return 0; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic int get_kobj_path_length(const struct kobject *kobj) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci int length = 1; 10962306a36Sopenharmony_ci const struct kobject *parent = kobj; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci /* walk up the ancestors until we hit the one pointing to the 11262306a36Sopenharmony_ci * root. 11362306a36Sopenharmony_ci * Add 1 to strlen for leading '/' of each level. 11462306a36Sopenharmony_ci */ 11562306a36Sopenharmony_ci do { 11662306a36Sopenharmony_ci if (kobject_name(parent) == NULL) 11762306a36Sopenharmony_ci return 0; 11862306a36Sopenharmony_ci length += strlen(kobject_name(parent)) + 1; 11962306a36Sopenharmony_ci parent = parent->parent; 12062306a36Sopenharmony_ci } while (parent); 12162306a36Sopenharmony_ci return length; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic int fill_kobj_path(const struct kobject *kobj, char *path, int length) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci const struct kobject *parent; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci --length; 12962306a36Sopenharmony_ci for (parent = kobj; parent; parent = parent->parent) { 13062306a36Sopenharmony_ci int cur = strlen(kobject_name(parent)); 13162306a36Sopenharmony_ci /* back up enough to print this name with '/' */ 13262306a36Sopenharmony_ci length -= cur; 13362306a36Sopenharmony_ci if (length <= 0) 13462306a36Sopenharmony_ci return -EINVAL; 13562306a36Sopenharmony_ci memcpy(path + length, kobject_name(parent), cur); 13662306a36Sopenharmony_ci *(path + --length) = '/'; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci pr_debug("'%s' (%p): %s: path = '%s'\n", kobject_name(kobj), 14062306a36Sopenharmony_ci kobj, __func__, path); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci return 0; 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci/** 14662306a36Sopenharmony_ci * kobject_get_path() - Allocate memory and fill in the path for @kobj. 14762306a36Sopenharmony_ci * @kobj: kobject in question, with which to build the path 14862306a36Sopenharmony_ci * @gfp_mask: the allocation type used to allocate the path 14962306a36Sopenharmony_ci * 15062306a36Sopenharmony_ci * Return: The newly allocated memory, caller must free with kfree(). 15162306a36Sopenharmony_ci */ 15262306a36Sopenharmony_cichar *kobject_get_path(const struct kobject *kobj, gfp_t gfp_mask) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci char *path; 15562306a36Sopenharmony_ci int len; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ciretry: 15862306a36Sopenharmony_ci len = get_kobj_path_length(kobj); 15962306a36Sopenharmony_ci if (len == 0) 16062306a36Sopenharmony_ci return NULL; 16162306a36Sopenharmony_ci path = kzalloc(len, gfp_mask); 16262306a36Sopenharmony_ci if (!path) 16362306a36Sopenharmony_ci return NULL; 16462306a36Sopenharmony_ci if (fill_kobj_path(kobj, path, len)) { 16562306a36Sopenharmony_ci kfree(path); 16662306a36Sopenharmony_ci goto retry; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci return path; 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kobject_get_path); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci/* add the kobject to its kset's list */ 17462306a36Sopenharmony_cistatic void kobj_kset_join(struct kobject *kobj) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci if (!kobj->kset) 17762306a36Sopenharmony_ci return; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci kset_get(kobj->kset); 18062306a36Sopenharmony_ci spin_lock(&kobj->kset->list_lock); 18162306a36Sopenharmony_ci list_add_tail(&kobj->entry, &kobj->kset->list); 18262306a36Sopenharmony_ci spin_unlock(&kobj->kset->list_lock); 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci/* remove the kobject from its kset's list */ 18662306a36Sopenharmony_cistatic void kobj_kset_leave(struct kobject *kobj) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci if (!kobj->kset) 18962306a36Sopenharmony_ci return; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci spin_lock(&kobj->kset->list_lock); 19262306a36Sopenharmony_ci list_del_init(&kobj->entry); 19362306a36Sopenharmony_ci spin_unlock(&kobj->kset->list_lock); 19462306a36Sopenharmony_ci kset_put(kobj->kset); 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic void kobject_init_internal(struct kobject *kobj) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci if (!kobj) 20062306a36Sopenharmony_ci return; 20162306a36Sopenharmony_ci kref_init(&kobj->kref); 20262306a36Sopenharmony_ci INIT_LIST_HEAD(&kobj->entry); 20362306a36Sopenharmony_ci kobj->state_in_sysfs = 0; 20462306a36Sopenharmony_ci kobj->state_add_uevent_sent = 0; 20562306a36Sopenharmony_ci kobj->state_remove_uevent_sent = 0; 20662306a36Sopenharmony_ci kobj->state_initialized = 1; 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic int kobject_add_internal(struct kobject *kobj) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci int error = 0; 21362306a36Sopenharmony_ci struct kobject *parent; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (!kobj) 21662306a36Sopenharmony_ci return -ENOENT; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci if (!kobj->name || !kobj->name[0]) { 21962306a36Sopenharmony_ci WARN(1, 22062306a36Sopenharmony_ci "kobject: (%p): attempted to be registered with empty name!\n", 22162306a36Sopenharmony_ci kobj); 22262306a36Sopenharmony_ci return -EINVAL; 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci parent = kobject_get(kobj->parent); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci /* join kset if set, use it as parent if we do not already have one */ 22862306a36Sopenharmony_ci if (kobj->kset) { 22962306a36Sopenharmony_ci if (!parent) 23062306a36Sopenharmony_ci parent = kobject_get(&kobj->kset->kobj); 23162306a36Sopenharmony_ci kobj_kset_join(kobj); 23262306a36Sopenharmony_ci kobj->parent = parent; 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci pr_debug("'%s' (%p): %s: parent: '%s', set: '%s'\n", 23662306a36Sopenharmony_ci kobject_name(kobj), kobj, __func__, 23762306a36Sopenharmony_ci parent ? kobject_name(parent) : "<NULL>", 23862306a36Sopenharmony_ci kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>"); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci error = create_dir(kobj); 24162306a36Sopenharmony_ci if (error) { 24262306a36Sopenharmony_ci kobj_kset_leave(kobj); 24362306a36Sopenharmony_ci kobject_put(parent); 24462306a36Sopenharmony_ci kobj->parent = NULL; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci /* be noisy on error issues */ 24762306a36Sopenharmony_ci if (error == -EEXIST) 24862306a36Sopenharmony_ci pr_err("%s failed for %s with -EEXIST, don't try to register things with the same name in the same directory.\n", 24962306a36Sopenharmony_ci __func__, kobject_name(kobj)); 25062306a36Sopenharmony_ci else 25162306a36Sopenharmony_ci pr_err("%s failed for %s (error: %d parent: %s)\n", 25262306a36Sopenharmony_ci __func__, kobject_name(kobj), error, 25362306a36Sopenharmony_ci parent ? kobject_name(parent) : "'none'"); 25462306a36Sopenharmony_ci } else 25562306a36Sopenharmony_ci kobj->state_in_sysfs = 1; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci return error; 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci/** 26162306a36Sopenharmony_ci * kobject_set_name_vargs() - Set the name of a kobject. 26262306a36Sopenharmony_ci * @kobj: struct kobject to set the name of 26362306a36Sopenharmony_ci * @fmt: format string used to build the name 26462306a36Sopenharmony_ci * @vargs: vargs to format the string. 26562306a36Sopenharmony_ci */ 26662306a36Sopenharmony_ciint kobject_set_name_vargs(struct kobject *kobj, const char *fmt, 26762306a36Sopenharmony_ci va_list vargs) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci const char *s; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci if (kobj->name && !fmt) 27262306a36Sopenharmony_ci return 0; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci s = kvasprintf_const(GFP_KERNEL, fmt, vargs); 27562306a36Sopenharmony_ci if (!s) 27662306a36Sopenharmony_ci return -ENOMEM; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci /* 27962306a36Sopenharmony_ci * ewww... some of these buggers have '/' in the name ... If 28062306a36Sopenharmony_ci * that's the case, we need to make sure we have an actual 28162306a36Sopenharmony_ci * allocated copy to modify, since kvasprintf_const may have 28262306a36Sopenharmony_ci * returned something from .rodata. 28362306a36Sopenharmony_ci */ 28462306a36Sopenharmony_ci if (strchr(s, '/')) { 28562306a36Sopenharmony_ci char *t; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci t = kstrdup(s, GFP_KERNEL); 28862306a36Sopenharmony_ci kfree_const(s); 28962306a36Sopenharmony_ci if (!t) 29062306a36Sopenharmony_ci return -ENOMEM; 29162306a36Sopenharmony_ci s = strreplace(t, '/', '!'); 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci kfree_const(kobj->name); 29462306a36Sopenharmony_ci kobj->name = s; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci return 0; 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci/** 30062306a36Sopenharmony_ci * kobject_set_name() - Set the name of a kobject. 30162306a36Sopenharmony_ci * @kobj: struct kobject to set the name of 30262306a36Sopenharmony_ci * @fmt: format string used to build the name 30362306a36Sopenharmony_ci * 30462306a36Sopenharmony_ci * This sets the name of the kobject. If you have already added the 30562306a36Sopenharmony_ci * kobject to the system, you must call kobject_rename() in order to 30662306a36Sopenharmony_ci * change the name of the kobject. 30762306a36Sopenharmony_ci */ 30862306a36Sopenharmony_ciint kobject_set_name(struct kobject *kobj, const char *fmt, ...) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci va_list vargs; 31162306a36Sopenharmony_ci int retval; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci va_start(vargs, fmt); 31462306a36Sopenharmony_ci retval = kobject_set_name_vargs(kobj, fmt, vargs); 31562306a36Sopenharmony_ci va_end(vargs); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci return retval; 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ciEXPORT_SYMBOL(kobject_set_name); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci/** 32262306a36Sopenharmony_ci * kobject_init() - Initialize a kobject structure. 32362306a36Sopenharmony_ci * @kobj: pointer to the kobject to initialize 32462306a36Sopenharmony_ci * @ktype: pointer to the ktype for this kobject. 32562306a36Sopenharmony_ci * 32662306a36Sopenharmony_ci * This function will properly initialize a kobject such that it can then 32762306a36Sopenharmony_ci * be passed to the kobject_add() call. 32862306a36Sopenharmony_ci * 32962306a36Sopenharmony_ci * After this function is called, the kobject MUST be cleaned up by a call 33062306a36Sopenharmony_ci * to kobject_put(), not by a call to kfree directly to ensure that all of 33162306a36Sopenharmony_ci * the memory is cleaned up properly. 33262306a36Sopenharmony_ci */ 33362306a36Sopenharmony_civoid kobject_init(struct kobject *kobj, const struct kobj_type *ktype) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci char *err_str; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci if (!kobj) { 33862306a36Sopenharmony_ci err_str = "invalid kobject pointer!"; 33962306a36Sopenharmony_ci goto error; 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci if (!ktype) { 34262306a36Sopenharmony_ci err_str = "must have a ktype to be initialized properly!\n"; 34362306a36Sopenharmony_ci goto error; 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci if (kobj->state_initialized) { 34662306a36Sopenharmony_ci /* do not error out as sometimes we can recover */ 34762306a36Sopenharmony_ci pr_err("kobject (%p): tried to init an initialized object, something is seriously wrong.\n", 34862306a36Sopenharmony_ci kobj); 34962306a36Sopenharmony_ci dump_stack_lvl(KERN_ERR); 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci kobject_init_internal(kobj); 35362306a36Sopenharmony_ci kobj->ktype = ktype; 35462306a36Sopenharmony_ci return; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cierror: 35762306a36Sopenharmony_ci pr_err("kobject (%p): %s\n", kobj, err_str); 35862306a36Sopenharmony_ci dump_stack_lvl(KERN_ERR); 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ciEXPORT_SYMBOL(kobject_init); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cistatic __printf(3, 0) int kobject_add_varg(struct kobject *kobj, 36362306a36Sopenharmony_ci struct kobject *parent, 36462306a36Sopenharmony_ci const char *fmt, va_list vargs) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci int retval; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci retval = kobject_set_name_vargs(kobj, fmt, vargs); 36962306a36Sopenharmony_ci if (retval) { 37062306a36Sopenharmony_ci pr_err("can not set name properly!\n"); 37162306a36Sopenharmony_ci return retval; 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci kobj->parent = parent; 37462306a36Sopenharmony_ci return kobject_add_internal(kobj); 37562306a36Sopenharmony_ci} 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci/** 37862306a36Sopenharmony_ci * kobject_add() - The main kobject add function. 37962306a36Sopenharmony_ci * @kobj: the kobject to add 38062306a36Sopenharmony_ci * @parent: pointer to the parent of the kobject. 38162306a36Sopenharmony_ci * @fmt: format to name the kobject with. 38262306a36Sopenharmony_ci * 38362306a36Sopenharmony_ci * The kobject name is set and added to the kobject hierarchy in this 38462306a36Sopenharmony_ci * function. 38562306a36Sopenharmony_ci * 38662306a36Sopenharmony_ci * If @parent is set, then the parent of the @kobj will be set to it. 38762306a36Sopenharmony_ci * If @parent is NULL, then the parent of the @kobj will be set to the 38862306a36Sopenharmony_ci * kobject associated with the kset assigned to this kobject. If no kset 38962306a36Sopenharmony_ci * is assigned to the kobject, then the kobject will be located in the 39062306a36Sopenharmony_ci * root of the sysfs tree. 39162306a36Sopenharmony_ci * 39262306a36Sopenharmony_ci * Note, no "add" uevent will be created with this call, the caller should set 39362306a36Sopenharmony_ci * up all of the necessary sysfs files for the object and then call 39462306a36Sopenharmony_ci * kobject_uevent() with the UEVENT_ADD parameter to ensure that 39562306a36Sopenharmony_ci * userspace is properly notified of this kobject's creation. 39662306a36Sopenharmony_ci * 39762306a36Sopenharmony_ci * Return: If this function returns an error, kobject_put() must be 39862306a36Sopenharmony_ci * called to properly clean up the memory associated with the 39962306a36Sopenharmony_ci * object. Under no instance should the kobject that is passed 40062306a36Sopenharmony_ci * to this function be directly freed with a call to kfree(), 40162306a36Sopenharmony_ci * that can leak memory. 40262306a36Sopenharmony_ci * 40362306a36Sopenharmony_ci * If this function returns success, kobject_put() must also be called 40462306a36Sopenharmony_ci * in order to properly clean up the memory associated with the object. 40562306a36Sopenharmony_ci * 40662306a36Sopenharmony_ci * In short, once this function is called, kobject_put() MUST be called 40762306a36Sopenharmony_ci * when the use of the object is finished in order to properly free 40862306a36Sopenharmony_ci * everything. 40962306a36Sopenharmony_ci */ 41062306a36Sopenharmony_ciint kobject_add(struct kobject *kobj, struct kobject *parent, 41162306a36Sopenharmony_ci const char *fmt, ...) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci va_list args; 41462306a36Sopenharmony_ci int retval; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci if (!kobj) 41762306a36Sopenharmony_ci return -EINVAL; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci if (!kobj->state_initialized) { 42062306a36Sopenharmony_ci pr_err("kobject '%s' (%p): tried to add an uninitialized object, something is seriously wrong.\n", 42162306a36Sopenharmony_ci kobject_name(kobj), kobj); 42262306a36Sopenharmony_ci dump_stack_lvl(KERN_ERR); 42362306a36Sopenharmony_ci return -EINVAL; 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci va_start(args, fmt); 42662306a36Sopenharmony_ci retval = kobject_add_varg(kobj, parent, fmt, args); 42762306a36Sopenharmony_ci va_end(args); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci return retval; 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ciEXPORT_SYMBOL(kobject_add); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci/** 43462306a36Sopenharmony_ci * kobject_init_and_add() - Initialize a kobject structure and add it to 43562306a36Sopenharmony_ci * the kobject hierarchy. 43662306a36Sopenharmony_ci * @kobj: pointer to the kobject to initialize 43762306a36Sopenharmony_ci * @ktype: pointer to the ktype for this kobject. 43862306a36Sopenharmony_ci * @parent: pointer to the parent of this kobject. 43962306a36Sopenharmony_ci * @fmt: the name of the kobject. 44062306a36Sopenharmony_ci * 44162306a36Sopenharmony_ci * This function combines the call to kobject_init() and kobject_add(). 44262306a36Sopenharmony_ci * 44362306a36Sopenharmony_ci * If this function returns an error, kobject_put() must be called to 44462306a36Sopenharmony_ci * properly clean up the memory associated with the object. This is the 44562306a36Sopenharmony_ci * same type of error handling after a call to kobject_add() and kobject 44662306a36Sopenharmony_ci * lifetime rules are the same here. 44762306a36Sopenharmony_ci */ 44862306a36Sopenharmony_ciint kobject_init_and_add(struct kobject *kobj, const struct kobj_type *ktype, 44962306a36Sopenharmony_ci struct kobject *parent, const char *fmt, ...) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci va_list args; 45262306a36Sopenharmony_ci int retval; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci kobject_init(kobj, ktype); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci va_start(args, fmt); 45762306a36Sopenharmony_ci retval = kobject_add_varg(kobj, parent, fmt, args); 45862306a36Sopenharmony_ci va_end(args); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci return retval; 46162306a36Sopenharmony_ci} 46262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kobject_init_and_add); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci/** 46562306a36Sopenharmony_ci * kobject_rename() - Change the name of an object. 46662306a36Sopenharmony_ci * @kobj: object in question. 46762306a36Sopenharmony_ci * @new_name: object's new name 46862306a36Sopenharmony_ci * 46962306a36Sopenharmony_ci * It is the responsibility of the caller to provide mutual 47062306a36Sopenharmony_ci * exclusion between two different calls of kobject_rename 47162306a36Sopenharmony_ci * on the same kobject and to ensure that new_name is valid and 47262306a36Sopenharmony_ci * won't conflict with other kobjects. 47362306a36Sopenharmony_ci */ 47462306a36Sopenharmony_ciint kobject_rename(struct kobject *kobj, const char *new_name) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci int error = 0; 47762306a36Sopenharmony_ci const char *devpath = NULL; 47862306a36Sopenharmony_ci const char *dup_name = NULL, *name; 47962306a36Sopenharmony_ci char *devpath_string = NULL; 48062306a36Sopenharmony_ci char *envp[2]; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci kobj = kobject_get(kobj); 48362306a36Sopenharmony_ci if (!kobj) 48462306a36Sopenharmony_ci return -EINVAL; 48562306a36Sopenharmony_ci if (!kobj->parent) { 48662306a36Sopenharmony_ci kobject_put(kobj); 48762306a36Sopenharmony_ci return -EINVAL; 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci devpath = kobject_get_path(kobj, GFP_KERNEL); 49162306a36Sopenharmony_ci if (!devpath) { 49262306a36Sopenharmony_ci error = -ENOMEM; 49362306a36Sopenharmony_ci goto out; 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci devpath_string = kmalloc(strlen(devpath) + 15, GFP_KERNEL); 49662306a36Sopenharmony_ci if (!devpath_string) { 49762306a36Sopenharmony_ci error = -ENOMEM; 49862306a36Sopenharmony_ci goto out; 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci sprintf(devpath_string, "DEVPATH_OLD=%s", devpath); 50162306a36Sopenharmony_ci envp[0] = devpath_string; 50262306a36Sopenharmony_ci envp[1] = NULL; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci name = dup_name = kstrdup_const(new_name, GFP_KERNEL); 50562306a36Sopenharmony_ci if (!name) { 50662306a36Sopenharmony_ci error = -ENOMEM; 50762306a36Sopenharmony_ci goto out; 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci error = sysfs_rename_dir_ns(kobj, new_name, kobject_namespace(kobj)); 51162306a36Sopenharmony_ci if (error) 51262306a36Sopenharmony_ci goto out; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci /* Install the new kobject name */ 51562306a36Sopenharmony_ci dup_name = kobj->name; 51662306a36Sopenharmony_ci kobj->name = name; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci /* This function is mostly/only used for network interface. 51962306a36Sopenharmony_ci * Some hotplug package track interfaces by their name and 52062306a36Sopenharmony_ci * therefore want to know when the name is changed by the user. */ 52162306a36Sopenharmony_ci kobject_uevent_env(kobj, KOBJ_MOVE, envp); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ciout: 52462306a36Sopenharmony_ci kfree_const(dup_name); 52562306a36Sopenharmony_ci kfree(devpath_string); 52662306a36Sopenharmony_ci kfree(devpath); 52762306a36Sopenharmony_ci kobject_put(kobj); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci return error; 53062306a36Sopenharmony_ci} 53162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kobject_rename); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci/** 53462306a36Sopenharmony_ci * kobject_move() - Move object to another parent. 53562306a36Sopenharmony_ci * @kobj: object in question. 53662306a36Sopenharmony_ci * @new_parent: object's new parent (can be NULL) 53762306a36Sopenharmony_ci */ 53862306a36Sopenharmony_ciint kobject_move(struct kobject *kobj, struct kobject *new_parent) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci int error; 54162306a36Sopenharmony_ci struct kobject *old_parent; 54262306a36Sopenharmony_ci const char *devpath = NULL; 54362306a36Sopenharmony_ci char *devpath_string = NULL; 54462306a36Sopenharmony_ci char *envp[2]; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci kobj = kobject_get(kobj); 54762306a36Sopenharmony_ci if (!kobj) 54862306a36Sopenharmony_ci return -EINVAL; 54962306a36Sopenharmony_ci new_parent = kobject_get(new_parent); 55062306a36Sopenharmony_ci if (!new_parent) { 55162306a36Sopenharmony_ci if (kobj->kset) 55262306a36Sopenharmony_ci new_parent = kobject_get(&kobj->kset->kobj); 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci /* old object path */ 55662306a36Sopenharmony_ci devpath = kobject_get_path(kobj, GFP_KERNEL); 55762306a36Sopenharmony_ci if (!devpath) { 55862306a36Sopenharmony_ci error = -ENOMEM; 55962306a36Sopenharmony_ci goto out; 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci devpath_string = kmalloc(strlen(devpath) + 15, GFP_KERNEL); 56262306a36Sopenharmony_ci if (!devpath_string) { 56362306a36Sopenharmony_ci error = -ENOMEM; 56462306a36Sopenharmony_ci goto out; 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci sprintf(devpath_string, "DEVPATH_OLD=%s", devpath); 56762306a36Sopenharmony_ci envp[0] = devpath_string; 56862306a36Sopenharmony_ci envp[1] = NULL; 56962306a36Sopenharmony_ci error = sysfs_move_dir_ns(kobj, new_parent, kobject_namespace(kobj)); 57062306a36Sopenharmony_ci if (error) 57162306a36Sopenharmony_ci goto out; 57262306a36Sopenharmony_ci old_parent = kobj->parent; 57362306a36Sopenharmony_ci kobj->parent = new_parent; 57462306a36Sopenharmony_ci new_parent = NULL; 57562306a36Sopenharmony_ci kobject_put(old_parent); 57662306a36Sopenharmony_ci kobject_uevent_env(kobj, KOBJ_MOVE, envp); 57762306a36Sopenharmony_ciout: 57862306a36Sopenharmony_ci kobject_put(new_parent); 57962306a36Sopenharmony_ci kobject_put(kobj); 58062306a36Sopenharmony_ci kfree(devpath_string); 58162306a36Sopenharmony_ci kfree(devpath); 58262306a36Sopenharmony_ci return error; 58362306a36Sopenharmony_ci} 58462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kobject_move); 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_cistatic void __kobject_del(struct kobject *kobj) 58762306a36Sopenharmony_ci{ 58862306a36Sopenharmony_ci struct kernfs_node *sd; 58962306a36Sopenharmony_ci const struct kobj_type *ktype; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci sd = kobj->sd; 59262306a36Sopenharmony_ci ktype = get_ktype(kobj); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci if (ktype) 59562306a36Sopenharmony_ci sysfs_remove_groups(kobj, ktype->default_groups); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci /* send "remove" if the caller did not do it but sent "add" */ 59862306a36Sopenharmony_ci if (kobj->state_add_uevent_sent && !kobj->state_remove_uevent_sent) { 59962306a36Sopenharmony_ci pr_debug("'%s' (%p): auto cleanup 'remove' event\n", 60062306a36Sopenharmony_ci kobject_name(kobj), kobj); 60162306a36Sopenharmony_ci kobject_uevent(kobj, KOBJ_REMOVE); 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci sysfs_remove_dir(kobj); 60562306a36Sopenharmony_ci sysfs_put(sd); 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci kobj->state_in_sysfs = 0; 60862306a36Sopenharmony_ci kobj_kset_leave(kobj); 60962306a36Sopenharmony_ci kobj->parent = NULL; 61062306a36Sopenharmony_ci} 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci/** 61362306a36Sopenharmony_ci * kobject_del() - Unlink kobject from hierarchy. 61462306a36Sopenharmony_ci * @kobj: object. 61562306a36Sopenharmony_ci * 61662306a36Sopenharmony_ci * This is the function that should be called to delete an object 61762306a36Sopenharmony_ci * successfully added via kobject_add(). 61862306a36Sopenharmony_ci */ 61962306a36Sopenharmony_civoid kobject_del(struct kobject *kobj) 62062306a36Sopenharmony_ci{ 62162306a36Sopenharmony_ci struct kobject *parent; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci if (!kobj) 62462306a36Sopenharmony_ci return; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci parent = kobj->parent; 62762306a36Sopenharmony_ci __kobject_del(kobj); 62862306a36Sopenharmony_ci kobject_put(parent); 62962306a36Sopenharmony_ci} 63062306a36Sopenharmony_ciEXPORT_SYMBOL(kobject_del); 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci/** 63362306a36Sopenharmony_ci * kobject_get() - Increment refcount for object. 63462306a36Sopenharmony_ci * @kobj: object. 63562306a36Sopenharmony_ci */ 63662306a36Sopenharmony_cistruct kobject *kobject_get(struct kobject *kobj) 63762306a36Sopenharmony_ci{ 63862306a36Sopenharmony_ci if (kobj) { 63962306a36Sopenharmony_ci if (!kobj->state_initialized) 64062306a36Sopenharmony_ci WARN(1, KERN_WARNING 64162306a36Sopenharmony_ci "kobject: '%s' (%p): is not initialized, yet kobject_get() is being called.\n", 64262306a36Sopenharmony_ci kobject_name(kobj), kobj); 64362306a36Sopenharmony_ci kref_get(&kobj->kref); 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci return kobj; 64662306a36Sopenharmony_ci} 64762306a36Sopenharmony_ciEXPORT_SYMBOL(kobject_get); 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_cistruct kobject * __must_check kobject_get_unless_zero(struct kobject *kobj) 65062306a36Sopenharmony_ci{ 65162306a36Sopenharmony_ci if (!kobj) 65262306a36Sopenharmony_ci return NULL; 65362306a36Sopenharmony_ci if (!kref_get_unless_zero(&kobj->kref)) 65462306a36Sopenharmony_ci kobj = NULL; 65562306a36Sopenharmony_ci return kobj; 65662306a36Sopenharmony_ci} 65762306a36Sopenharmony_ciEXPORT_SYMBOL(kobject_get_unless_zero); 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci/* 66062306a36Sopenharmony_ci * kobject_cleanup - free kobject resources. 66162306a36Sopenharmony_ci * @kobj: object to cleanup 66262306a36Sopenharmony_ci */ 66362306a36Sopenharmony_cistatic void kobject_cleanup(struct kobject *kobj) 66462306a36Sopenharmony_ci{ 66562306a36Sopenharmony_ci struct kobject *parent = kobj->parent; 66662306a36Sopenharmony_ci const struct kobj_type *t = get_ktype(kobj); 66762306a36Sopenharmony_ci const char *name = kobj->name; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci pr_debug("'%s' (%p): %s, parent %p\n", 67062306a36Sopenharmony_ci kobject_name(kobj), kobj, __func__, kobj->parent); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci if (t && !t->release) 67362306a36Sopenharmony_ci pr_debug("'%s' (%p): does not have a release() function, it is broken and must be fixed. See Documentation/core-api/kobject.rst.\n", 67462306a36Sopenharmony_ci kobject_name(kobj), kobj); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci /* remove from sysfs if the caller did not do it */ 67762306a36Sopenharmony_ci if (kobj->state_in_sysfs) { 67862306a36Sopenharmony_ci pr_debug("'%s' (%p): auto cleanup kobject_del\n", 67962306a36Sopenharmony_ci kobject_name(kobj), kobj); 68062306a36Sopenharmony_ci __kobject_del(kobj); 68162306a36Sopenharmony_ci } else { 68262306a36Sopenharmony_ci /* avoid dropping the parent reference unnecessarily */ 68362306a36Sopenharmony_ci parent = NULL; 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci if (t && t->release) { 68762306a36Sopenharmony_ci pr_debug("'%s' (%p): calling ktype release\n", 68862306a36Sopenharmony_ci kobject_name(kobj), kobj); 68962306a36Sopenharmony_ci t->release(kobj); 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci /* free name if we allocated it */ 69362306a36Sopenharmony_ci if (name) { 69462306a36Sopenharmony_ci pr_debug("'%s': free name\n", name); 69562306a36Sopenharmony_ci kfree_const(name); 69662306a36Sopenharmony_ci } 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci kobject_put(parent); 69962306a36Sopenharmony_ci} 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_KOBJECT_RELEASE 70262306a36Sopenharmony_cistatic void kobject_delayed_cleanup(struct work_struct *work) 70362306a36Sopenharmony_ci{ 70462306a36Sopenharmony_ci kobject_cleanup(container_of(to_delayed_work(work), 70562306a36Sopenharmony_ci struct kobject, release)); 70662306a36Sopenharmony_ci} 70762306a36Sopenharmony_ci#endif 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_cistatic void kobject_release(struct kref *kref) 71062306a36Sopenharmony_ci{ 71162306a36Sopenharmony_ci struct kobject *kobj = container_of(kref, struct kobject, kref); 71262306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_KOBJECT_RELEASE 71362306a36Sopenharmony_ci unsigned long delay = HZ + HZ * get_random_u32_below(4); 71462306a36Sopenharmony_ci pr_info("'%s' (%p): %s, parent %p (delayed %ld)\n", 71562306a36Sopenharmony_ci kobject_name(kobj), kobj, __func__, kobj->parent, delay); 71662306a36Sopenharmony_ci INIT_DELAYED_WORK(&kobj->release, kobject_delayed_cleanup); 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci schedule_delayed_work(&kobj->release, delay); 71962306a36Sopenharmony_ci#else 72062306a36Sopenharmony_ci kobject_cleanup(kobj); 72162306a36Sopenharmony_ci#endif 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci/** 72562306a36Sopenharmony_ci * kobject_put() - Decrement refcount for object. 72662306a36Sopenharmony_ci * @kobj: object. 72762306a36Sopenharmony_ci * 72862306a36Sopenharmony_ci * Decrement the refcount, and if 0, call kobject_cleanup(). 72962306a36Sopenharmony_ci */ 73062306a36Sopenharmony_civoid kobject_put(struct kobject *kobj) 73162306a36Sopenharmony_ci{ 73262306a36Sopenharmony_ci if (kobj) { 73362306a36Sopenharmony_ci if (!kobj->state_initialized) 73462306a36Sopenharmony_ci WARN(1, KERN_WARNING 73562306a36Sopenharmony_ci "kobject: '%s' (%p): is not initialized, yet kobject_put() is being called.\n", 73662306a36Sopenharmony_ci kobject_name(kobj), kobj); 73762306a36Sopenharmony_ci kref_put(&kobj->kref, kobject_release); 73862306a36Sopenharmony_ci } 73962306a36Sopenharmony_ci} 74062306a36Sopenharmony_ciEXPORT_SYMBOL(kobject_put); 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_cistatic void dynamic_kobj_release(struct kobject *kobj) 74362306a36Sopenharmony_ci{ 74462306a36Sopenharmony_ci pr_debug("(%p): %s\n", kobj, __func__); 74562306a36Sopenharmony_ci kfree(kobj); 74662306a36Sopenharmony_ci} 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_cistatic const struct kobj_type dynamic_kobj_ktype = { 74962306a36Sopenharmony_ci .release = dynamic_kobj_release, 75062306a36Sopenharmony_ci .sysfs_ops = &kobj_sysfs_ops, 75162306a36Sopenharmony_ci}; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci/** 75462306a36Sopenharmony_ci * kobject_create() - Create a struct kobject dynamically. 75562306a36Sopenharmony_ci * 75662306a36Sopenharmony_ci * This function creates a kobject structure dynamically and sets it up 75762306a36Sopenharmony_ci * to be a "dynamic" kobject with a default release function set up. 75862306a36Sopenharmony_ci * 75962306a36Sopenharmony_ci * If the kobject was not able to be created, NULL will be returned. 76062306a36Sopenharmony_ci * The kobject structure returned from here must be cleaned up with a 76162306a36Sopenharmony_ci * call to kobject_put() and not kfree(), as kobject_init() has 76262306a36Sopenharmony_ci * already been called on this structure. 76362306a36Sopenharmony_ci */ 76462306a36Sopenharmony_cistatic struct kobject *kobject_create(void) 76562306a36Sopenharmony_ci{ 76662306a36Sopenharmony_ci struct kobject *kobj; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci kobj = kzalloc(sizeof(*kobj), GFP_KERNEL); 76962306a36Sopenharmony_ci if (!kobj) 77062306a36Sopenharmony_ci return NULL; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci kobject_init(kobj, &dynamic_kobj_ktype); 77362306a36Sopenharmony_ci return kobj; 77462306a36Sopenharmony_ci} 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci/** 77762306a36Sopenharmony_ci * kobject_create_and_add() - Create a struct kobject dynamically and 77862306a36Sopenharmony_ci * register it with sysfs. 77962306a36Sopenharmony_ci * @name: the name for the kobject 78062306a36Sopenharmony_ci * @parent: the parent kobject of this kobject, if any. 78162306a36Sopenharmony_ci * 78262306a36Sopenharmony_ci * This function creates a kobject structure dynamically and registers it 78362306a36Sopenharmony_ci * with sysfs. When you are finished with this structure, call 78462306a36Sopenharmony_ci * kobject_put() and the structure will be dynamically freed when 78562306a36Sopenharmony_ci * it is no longer being used. 78662306a36Sopenharmony_ci * 78762306a36Sopenharmony_ci * If the kobject was not able to be created, NULL will be returned. 78862306a36Sopenharmony_ci */ 78962306a36Sopenharmony_cistruct kobject *kobject_create_and_add(const char *name, struct kobject *parent) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci struct kobject *kobj; 79262306a36Sopenharmony_ci int retval; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci kobj = kobject_create(); 79562306a36Sopenharmony_ci if (!kobj) 79662306a36Sopenharmony_ci return NULL; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci retval = kobject_add(kobj, parent, "%s", name); 79962306a36Sopenharmony_ci if (retval) { 80062306a36Sopenharmony_ci pr_warn("%s: kobject_add error: %d\n", __func__, retval); 80162306a36Sopenharmony_ci kobject_put(kobj); 80262306a36Sopenharmony_ci kobj = NULL; 80362306a36Sopenharmony_ci } 80462306a36Sopenharmony_ci return kobj; 80562306a36Sopenharmony_ci} 80662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kobject_create_and_add); 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci/** 80962306a36Sopenharmony_ci * kset_init() - Initialize a kset for use. 81062306a36Sopenharmony_ci * @k: kset 81162306a36Sopenharmony_ci */ 81262306a36Sopenharmony_civoid kset_init(struct kset *k) 81362306a36Sopenharmony_ci{ 81462306a36Sopenharmony_ci kobject_init_internal(&k->kobj); 81562306a36Sopenharmony_ci INIT_LIST_HEAD(&k->list); 81662306a36Sopenharmony_ci spin_lock_init(&k->list_lock); 81762306a36Sopenharmony_ci} 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci/* default kobject attribute operations */ 82062306a36Sopenharmony_cistatic ssize_t kobj_attr_show(struct kobject *kobj, struct attribute *attr, 82162306a36Sopenharmony_ci char *buf) 82262306a36Sopenharmony_ci{ 82362306a36Sopenharmony_ci struct kobj_attribute *kattr; 82462306a36Sopenharmony_ci ssize_t ret = -EIO; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci kattr = container_of(attr, struct kobj_attribute, attr); 82762306a36Sopenharmony_ci if (kattr->show) 82862306a36Sopenharmony_ci ret = kattr->show(kobj, kattr, buf); 82962306a36Sopenharmony_ci return ret; 83062306a36Sopenharmony_ci} 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_cistatic ssize_t kobj_attr_store(struct kobject *kobj, struct attribute *attr, 83362306a36Sopenharmony_ci const char *buf, size_t count) 83462306a36Sopenharmony_ci{ 83562306a36Sopenharmony_ci struct kobj_attribute *kattr; 83662306a36Sopenharmony_ci ssize_t ret = -EIO; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci kattr = container_of(attr, struct kobj_attribute, attr); 83962306a36Sopenharmony_ci if (kattr->store) 84062306a36Sopenharmony_ci ret = kattr->store(kobj, kattr, buf, count); 84162306a36Sopenharmony_ci return ret; 84262306a36Sopenharmony_ci} 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ciconst struct sysfs_ops kobj_sysfs_ops = { 84562306a36Sopenharmony_ci .show = kobj_attr_show, 84662306a36Sopenharmony_ci .store = kobj_attr_store, 84762306a36Sopenharmony_ci}; 84862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kobj_sysfs_ops); 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci/** 85162306a36Sopenharmony_ci * kset_register() - Initialize and add a kset. 85262306a36Sopenharmony_ci * @k: kset. 85362306a36Sopenharmony_ci * 85462306a36Sopenharmony_ci * NOTE: On error, the kset.kobj.name allocated by() kobj_set_name() 85562306a36Sopenharmony_ci * is freed, it can not be used any more. 85662306a36Sopenharmony_ci */ 85762306a36Sopenharmony_ciint kset_register(struct kset *k) 85862306a36Sopenharmony_ci{ 85962306a36Sopenharmony_ci int err; 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci if (!k) 86262306a36Sopenharmony_ci return -EINVAL; 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci if (!k->kobj.ktype) { 86562306a36Sopenharmony_ci pr_err("must have a ktype to be initialized properly!\n"); 86662306a36Sopenharmony_ci return -EINVAL; 86762306a36Sopenharmony_ci } 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci kset_init(k); 87062306a36Sopenharmony_ci err = kobject_add_internal(&k->kobj); 87162306a36Sopenharmony_ci if (err) { 87262306a36Sopenharmony_ci kfree_const(k->kobj.name); 87362306a36Sopenharmony_ci /* Set it to NULL to avoid accessing bad pointer in callers. */ 87462306a36Sopenharmony_ci k->kobj.name = NULL; 87562306a36Sopenharmony_ci return err; 87662306a36Sopenharmony_ci } 87762306a36Sopenharmony_ci kobject_uevent(&k->kobj, KOBJ_ADD); 87862306a36Sopenharmony_ci return 0; 87962306a36Sopenharmony_ci} 88062306a36Sopenharmony_ciEXPORT_SYMBOL(kset_register); 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci/** 88362306a36Sopenharmony_ci * kset_unregister() - Remove a kset. 88462306a36Sopenharmony_ci * @k: kset. 88562306a36Sopenharmony_ci */ 88662306a36Sopenharmony_civoid kset_unregister(struct kset *k) 88762306a36Sopenharmony_ci{ 88862306a36Sopenharmony_ci if (!k) 88962306a36Sopenharmony_ci return; 89062306a36Sopenharmony_ci kobject_del(&k->kobj); 89162306a36Sopenharmony_ci kobject_put(&k->kobj); 89262306a36Sopenharmony_ci} 89362306a36Sopenharmony_ciEXPORT_SYMBOL(kset_unregister); 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci/** 89662306a36Sopenharmony_ci * kset_find_obj() - Search for object in kset. 89762306a36Sopenharmony_ci * @kset: kset we're looking in. 89862306a36Sopenharmony_ci * @name: object's name. 89962306a36Sopenharmony_ci * 90062306a36Sopenharmony_ci * Lock kset via @kset->subsys, and iterate over @kset->list, 90162306a36Sopenharmony_ci * looking for a matching kobject. If matching object is found 90262306a36Sopenharmony_ci * take a reference and return the object. 90362306a36Sopenharmony_ci */ 90462306a36Sopenharmony_cistruct kobject *kset_find_obj(struct kset *kset, const char *name) 90562306a36Sopenharmony_ci{ 90662306a36Sopenharmony_ci struct kobject *k; 90762306a36Sopenharmony_ci struct kobject *ret = NULL; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci spin_lock(&kset->list_lock); 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci list_for_each_entry(k, &kset->list, entry) { 91262306a36Sopenharmony_ci if (kobject_name(k) && !strcmp(kobject_name(k), name)) { 91362306a36Sopenharmony_ci ret = kobject_get_unless_zero(k); 91462306a36Sopenharmony_ci break; 91562306a36Sopenharmony_ci } 91662306a36Sopenharmony_ci } 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci spin_unlock(&kset->list_lock); 91962306a36Sopenharmony_ci return ret; 92062306a36Sopenharmony_ci} 92162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kset_find_obj); 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_cistatic void kset_release(struct kobject *kobj) 92462306a36Sopenharmony_ci{ 92562306a36Sopenharmony_ci struct kset *kset = container_of(kobj, struct kset, kobj); 92662306a36Sopenharmony_ci pr_debug("'%s' (%p): %s\n", 92762306a36Sopenharmony_ci kobject_name(kobj), kobj, __func__); 92862306a36Sopenharmony_ci kfree(kset); 92962306a36Sopenharmony_ci} 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_cistatic void kset_get_ownership(const struct kobject *kobj, kuid_t *uid, kgid_t *gid) 93262306a36Sopenharmony_ci{ 93362306a36Sopenharmony_ci if (kobj->parent) 93462306a36Sopenharmony_ci kobject_get_ownership(kobj->parent, uid, gid); 93562306a36Sopenharmony_ci} 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_cistatic const struct kobj_type kset_ktype = { 93862306a36Sopenharmony_ci .sysfs_ops = &kobj_sysfs_ops, 93962306a36Sopenharmony_ci .release = kset_release, 94062306a36Sopenharmony_ci .get_ownership = kset_get_ownership, 94162306a36Sopenharmony_ci}; 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci/** 94462306a36Sopenharmony_ci * kset_create() - Create a struct kset dynamically. 94562306a36Sopenharmony_ci * 94662306a36Sopenharmony_ci * @name: the name for the kset 94762306a36Sopenharmony_ci * @uevent_ops: a struct kset_uevent_ops for the kset 94862306a36Sopenharmony_ci * @parent_kobj: the parent kobject of this kset, if any. 94962306a36Sopenharmony_ci * 95062306a36Sopenharmony_ci * This function creates a kset structure dynamically. This structure can 95162306a36Sopenharmony_ci * then be registered with the system and show up in sysfs with a call to 95262306a36Sopenharmony_ci * kset_register(). When you are finished with this structure, if 95362306a36Sopenharmony_ci * kset_register() has been called, call kset_unregister() and the 95462306a36Sopenharmony_ci * structure will be dynamically freed when it is no longer being used. 95562306a36Sopenharmony_ci * 95662306a36Sopenharmony_ci * If the kset was not able to be created, NULL will be returned. 95762306a36Sopenharmony_ci */ 95862306a36Sopenharmony_cistatic struct kset *kset_create(const char *name, 95962306a36Sopenharmony_ci const struct kset_uevent_ops *uevent_ops, 96062306a36Sopenharmony_ci struct kobject *parent_kobj) 96162306a36Sopenharmony_ci{ 96262306a36Sopenharmony_ci struct kset *kset; 96362306a36Sopenharmony_ci int retval; 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci kset = kzalloc(sizeof(*kset), GFP_KERNEL); 96662306a36Sopenharmony_ci if (!kset) 96762306a36Sopenharmony_ci return NULL; 96862306a36Sopenharmony_ci retval = kobject_set_name(&kset->kobj, "%s", name); 96962306a36Sopenharmony_ci if (retval) { 97062306a36Sopenharmony_ci kfree(kset); 97162306a36Sopenharmony_ci return NULL; 97262306a36Sopenharmony_ci } 97362306a36Sopenharmony_ci kset->uevent_ops = uevent_ops; 97462306a36Sopenharmony_ci kset->kobj.parent = parent_kobj; 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci /* 97762306a36Sopenharmony_ci * The kobject of this kset will have a type of kset_ktype and belong to 97862306a36Sopenharmony_ci * no kset itself. That way we can properly free it when it is 97962306a36Sopenharmony_ci * finished being used. 98062306a36Sopenharmony_ci */ 98162306a36Sopenharmony_ci kset->kobj.ktype = &kset_ktype; 98262306a36Sopenharmony_ci kset->kobj.kset = NULL; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci return kset; 98562306a36Sopenharmony_ci} 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci/** 98862306a36Sopenharmony_ci * kset_create_and_add() - Create a struct kset dynamically and add it to sysfs. 98962306a36Sopenharmony_ci * 99062306a36Sopenharmony_ci * @name: the name for the kset 99162306a36Sopenharmony_ci * @uevent_ops: a struct kset_uevent_ops for the kset 99262306a36Sopenharmony_ci * @parent_kobj: the parent kobject of this kset, if any. 99362306a36Sopenharmony_ci * 99462306a36Sopenharmony_ci * This function creates a kset structure dynamically and registers it 99562306a36Sopenharmony_ci * with sysfs. When you are finished with this structure, call 99662306a36Sopenharmony_ci * kset_unregister() and the structure will be dynamically freed when it 99762306a36Sopenharmony_ci * is no longer being used. 99862306a36Sopenharmony_ci * 99962306a36Sopenharmony_ci * If the kset was not able to be created, NULL will be returned. 100062306a36Sopenharmony_ci */ 100162306a36Sopenharmony_cistruct kset *kset_create_and_add(const char *name, 100262306a36Sopenharmony_ci const struct kset_uevent_ops *uevent_ops, 100362306a36Sopenharmony_ci struct kobject *parent_kobj) 100462306a36Sopenharmony_ci{ 100562306a36Sopenharmony_ci struct kset *kset; 100662306a36Sopenharmony_ci int error; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci kset = kset_create(name, uevent_ops, parent_kobj); 100962306a36Sopenharmony_ci if (!kset) 101062306a36Sopenharmony_ci return NULL; 101162306a36Sopenharmony_ci error = kset_register(kset); 101262306a36Sopenharmony_ci if (error) { 101362306a36Sopenharmony_ci kfree(kset); 101462306a36Sopenharmony_ci return NULL; 101562306a36Sopenharmony_ci } 101662306a36Sopenharmony_ci return kset; 101762306a36Sopenharmony_ci} 101862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kset_create_and_add); 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_cistatic DEFINE_SPINLOCK(kobj_ns_type_lock); 102262306a36Sopenharmony_cistatic const struct kobj_ns_type_operations *kobj_ns_ops_tbl[KOBJ_NS_TYPES]; 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ciint kobj_ns_type_register(const struct kobj_ns_type_operations *ops) 102562306a36Sopenharmony_ci{ 102662306a36Sopenharmony_ci enum kobj_ns_type type = ops->type; 102762306a36Sopenharmony_ci int error; 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci spin_lock(&kobj_ns_type_lock); 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci error = -EINVAL; 103262306a36Sopenharmony_ci if (!kobj_ns_type_is_valid(type)) 103362306a36Sopenharmony_ci goto out; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci error = -EBUSY; 103662306a36Sopenharmony_ci if (kobj_ns_ops_tbl[type]) 103762306a36Sopenharmony_ci goto out; 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci error = 0; 104062306a36Sopenharmony_ci kobj_ns_ops_tbl[type] = ops; 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ciout: 104362306a36Sopenharmony_ci spin_unlock(&kobj_ns_type_lock); 104462306a36Sopenharmony_ci return error; 104562306a36Sopenharmony_ci} 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ciint kobj_ns_type_registered(enum kobj_ns_type type) 104862306a36Sopenharmony_ci{ 104962306a36Sopenharmony_ci int registered = 0; 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci spin_lock(&kobj_ns_type_lock); 105262306a36Sopenharmony_ci if (kobj_ns_type_is_valid(type)) 105362306a36Sopenharmony_ci registered = kobj_ns_ops_tbl[type] != NULL; 105462306a36Sopenharmony_ci spin_unlock(&kobj_ns_type_lock); 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci return registered; 105762306a36Sopenharmony_ci} 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ciconst struct kobj_ns_type_operations *kobj_child_ns_ops(const struct kobject *parent) 106062306a36Sopenharmony_ci{ 106162306a36Sopenharmony_ci const struct kobj_ns_type_operations *ops = NULL; 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci if (parent && parent->ktype && parent->ktype->child_ns_type) 106462306a36Sopenharmony_ci ops = parent->ktype->child_ns_type(parent); 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci return ops; 106762306a36Sopenharmony_ci} 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ciconst struct kobj_ns_type_operations *kobj_ns_ops(const struct kobject *kobj) 107062306a36Sopenharmony_ci{ 107162306a36Sopenharmony_ci return kobj_child_ns_ops(kobj->parent); 107262306a36Sopenharmony_ci} 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_cibool kobj_ns_current_may_mount(enum kobj_ns_type type) 107562306a36Sopenharmony_ci{ 107662306a36Sopenharmony_ci bool may_mount = true; 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci spin_lock(&kobj_ns_type_lock); 107962306a36Sopenharmony_ci if (kobj_ns_type_is_valid(type) && kobj_ns_ops_tbl[type]) 108062306a36Sopenharmony_ci may_mount = kobj_ns_ops_tbl[type]->current_may_mount(); 108162306a36Sopenharmony_ci spin_unlock(&kobj_ns_type_lock); 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci return may_mount; 108462306a36Sopenharmony_ci} 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_civoid *kobj_ns_grab_current(enum kobj_ns_type type) 108762306a36Sopenharmony_ci{ 108862306a36Sopenharmony_ci void *ns = NULL; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci spin_lock(&kobj_ns_type_lock); 109162306a36Sopenharmony_ci if (kobj_ns_type_is_valid(type) && kobj_ns_ops_tbl[type]) 109262306a36Sopenharmony_ci ns = kobj_ns_ops_tbl[type]->grab_current_ns(); 109362306a36Sopenharmony_ci spin_unlock(&kobj_ns_type_lock); 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci return ns; 109662306a36Sopenharmony_ci} 109762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kobj_ns_grab_current); 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ciconst void *kobj_ns_netlink(enum kobj_ns_type type, struct sock *sk) 110062306a36Sopenharmony_ci{ 110162306a36Sopenharmony_ci const void *ns = NULL; 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci spin_lock(&kobj_ns_type_lock); 110462306a36Sopenharmony_ci if (kobj_ns_type_is_valid(type) && kobj_ns_ops_tbl[type]) 110562306a36Sopenharmony_ci ns = kobj_ns_ops_tbl[type]->netlink_ns(sk); 110662306a36Sopenharmony_ci spin_unlock(&kobj_ns_type_lock); 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci return ns; 110962306a36Sopenharmony_ci} 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ciconst void *kobj_ns_initial(enum kobj_ns_type type) 111262306a36Sopenharmony_ci{ 111362306a36Sopenharmony_ci const void *ns = NULL; 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci spin_lock(&kobj_ns_type_lock); 111662306a36Sopenharmony_ci if (kobj_ns_type_is_valid(type) && kobj_ns_ops_tbl[type]) 111762306a36Sopenharmony_ci ns = kobj_ns_ops_tbl[type]->initial_ns(); 111862306a36Sopenharmony_ci spin_unlock(&kobj_ns_type_lock); 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci return ns; 112162306a36Sopenharmony_ci} 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_civoid kobj_ns_drop(enum kobj_ns_type type, void *ns) 112462306a36Sopenharmony_ci{ 112562306a36Sopenharmony_ci spin_lock(&kobj_ns_type_lock); 112662306a36Sopenharmony_ci if (kobj_ns_type_is_valid(type) && 112762306a36Sopenharmony_ci kobj_ns_ops_tbl[type] && kobj_ns_ops_tbl[type]->drop_ns) 112862306a36Sopenharmony_ci kobj_ns_ops_tbl[type]->drop_ns(ns); 112962306a36Sopenharmony_ci spin_unlock(&kobj_ns_type_lock); 113062306a36Sopenharmony_ci} 113162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kobj_ns_drop); 1132