Path: blob/main/sys/compat/linuxkpi/common/src/linux_kobject.c
39586 views
/*-1* Copyright (c) 2010 Isilon Systems, Inc.2* Copyright (c) 2010 iX Systems, Inc.3* Copyright (c) 2010 Panasas, Inc.4* Copyright (c) 2013-2021 Mellanox Technologies, Ltd.5* All rights reserved.6*7* Redistribution and use in source and binary forms, with or without8* modification, are permitted provided that the following conditions9* are met:10* 1. Redistributions of source code must retain the above copyright11* notice unmodified, this list of conditions, and the following12* disclaimer.13* 2. Redistributions in binary form must reproduce the above copyright14* notice, this list of conditions and the following disclaimer in the15* documentation and/or other materials provided with the distribution.16*17* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR18* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES19* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.20* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,21* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT22* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,23* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY24* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT25* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF26* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.27*/2829#include <linux/kobject.h>30#include <linux/sysfs.h>3132static void kset_join(struct kobject *kobj);33static void kset_leave(struct kobject *kobj);34static void kset_kfree(struct kobject *kobj);3536struct kobject *37kobject_create(void)38{39struct kobject *kobj;4041kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);42if (kobj == NULL)43return (NULL);44kobject_init(kobj, &linux_kfree_type);4546return (kobj);47}484950int51kobject_set_name_vargs(struct kobject *kobj, const char *fmt, va_list args)52{53va_list tmp_va;54int len;55char *old;56char *name;57char dummy;5859old = kobj->name;6061if (old && fmt == NULL)62return (0);6364/* compute length of string */65va_copy(tmp_va, args);66len = vsnprintf(&dummy, 0, fmt, tmp_va);67va_end(tmp_va);6869/* account for zero termination */70len++;7172/* check for error */73if (len < 1)74return (-EINVAL);7576/* allocate memory for string */77name = kzalloc(len, GFP_KERNEL);78if (name == NULL)79return (-ENOMEM);80vsnprintf(name, len, fmt, args);81kobj->name = name;8283/* free old string */84kfree(old);8586/* filter new string */87for (; *name != '\0'; name++)88if (*name == '/')89*name = '!';90return (0);91}9293int94kobject_set_name(struct kobject *kobj, const char *fmt, ...)95{96va_list args;97int error;9899va_start(args, fmt);100error = kobject_set_name_vargs(kobj, fmt, args);101va_end(args);102103return (error);104}105106static int107kobject_add_complete(struct kobject *kobj)108{109const struct kobj_type *t;110int error;111112if (kobj->kset != NULL) {113kset_join(kobj);114kobj->parent = &kobj->kset->kobj;115}116117error = sysfs_create_dir(kobj);118if (error == 0 && kobj->ktype && kobj->ktype->default_attrs) {119struct attribute **attr;120t = kobj->ktype;121122for (attr = t->default_attrs; *attr != NULL; attr++) {123error = sysfs_create_file(kobj, *attr);124if (error != 0)125break;126}127if (error != 0)128sysfs_remove_dir(kobj);129}130131if (error != 0)132kset_leave(kobj);133134return (error);135}136137int138kobject_add(struct kobject *kobj, struct kobject *parent, const char *fmt, ...)139{140va_list args;141int error;142143kobj->parent = parent;144145va_start(args, fmt);146error = kobject_set_name_vargs(kobj, fmt, args);147va_end(args);148if (error)149return (error);150151return kobject_add_complete(kobj);152}153154int155kobject_init_and_add(struct kobject *kobj, const struct kobj_type *ktype,156struct kobject *parent, const char *fmt, ...)157{158va_list args;159int error;160161kobject_init(kobj, ktype);162kobj->ktype = ktype;163kobj->parent = parent;164kobj->name = NULL;165166va_start(args, fmt);167error = kobject_set_name_vargs(kobj, fmt, args);168va_end(args);169if (error)170return (error);171return kobject_add_complete(kobj);172}173174void175linux_kobject_release(struct kref *kref)176{177struct kobject *kobj;178char *name;179180kobj = container_of(kref, struct kobject, kref);181sysfs_remove_dir(kobj);182kset_leave(kobj);183name = kobj->name;184if (kobj->ktype && kobj->ktype->release)185kobj->ktype->release(kobj);186kfree(name);187}188189static void190linux_kobject_kfree(struct kobject *kobj)191{192kfree(kobj);193}194195const struct kobj_type linux_kfree_type = {196.release = linux_kobject_kfree197};198199void200linux_kobject_kfree_name(struct kobject *kobj)201{202if (kobj) {203kfree(kobj->name);204}205}206207static ssize_t208lkpi_kobj_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)209{210struct kobj_attribute *ka =211container_of(attr, struct kobj_attribute, attr);212213if (ka->show == NULL)214return (-EIO);215216return (ka->show(kobj, ka, buf));217}218219static ssize_t220lkpi_kobj_attr_store(struct kobject *kobj, struct attribute *attr,221const char *buf, size_t count)222{223struct kobj_attribute *ka =224container_of(attr, struct kobj_attribute, attr);225226if (ka->store == NULL)227return (-EIO);228229return (ka->store(kobj, ka, buf, count));230}231232const struct sysfs_ops kobj_sysfs_ops = {233.show = lkpi_kobj_attr_show,234.store = lkpi_kobj_attr_store,235};236237const struct kobj_type linux_kset_kfree_type = {238.release = kset_kfree239};240241static struct kset *242kset_create(const char *name,243const struct kset_uevent_ops *uevent_ops,244struct kobject *parent_kobj)245{246struct kset *kset;247248kset = kzalloc(sizeof(*kset), GFP_KERNEL);249if (kset == NULL)250return (NULL);251252kset->uevent_ops = uevent_ops;253254kobject_set_name(&kset->kobj, "%s", name);255kset->kobj.parent = parent_kobj;256kset->kobj.kset = NULL;257258return (kset);259}260261void262kset_init(struct kset *kset)263{264kobject_init(&kset->kobj, &linux_kset_kfree_type);265INIT_LIST_HEAD(&kset->list);266spin_lock_init(&kset->list_lock);267}268269static void270kset_join(struct kobject *kobj)271{272struct kset *kset;273274kset = kobj->kset;275if (kset == NULL)276return;277278kset_get(kobj->kset);279280spin_lock(&kset->list_lock);281list_add_tail(&kobj->entry, &kset->list);282spin_unlock(&kset->list_lock);283}284285static void286kset_leave(struct kobject *kobj)287{288struct kset *kset;289290kset = kobj->kset;291if (kset == NULL)292return;293294spin_lock(&kset->list_lock);295list_del_init(&kobj->entry);296spin_unlock(&kset->list_lock);297298kset_put(kobj->kset);299}300301struct kset *302kset_create_and_add(const char *name, const struct kset_uevent_ops *u,303struct kobject *parent_kobj)304{305int ret;306struct kset *kset;307308kset = kset_create(name, u, parent_kobj);309if (kset == NULL)310return (NULL);311312ret = kset_register(kset);313if (ret != 0) {314linux_kobject_kfree_name(&kset->kobj);315kfree(kset);316return (NULL);317}318319return (kset);320}321322int323kset_register(struct kset *kset)324{325int ret;326327if (kset == NULL)328return -EINVAL;329330kset_init(kset);331ret = kobject_add_complete(&kset->kobj);332333return ret;334}335336void337kset_unregister(struct kset *kset)338{339if (kset == NULL)340return;341342kobject_del(&kset->kobj);343kobject_put(&kset->kobj);344}345346static void347kset_kfree(struct kobject *kobj)348{349struct kset *kset;350351kset = to_kset(kobj);352kfree(kset);353}354355356