1 /*- 2 * Copyright (c) 2010 Isilon Systems, Inc. 3 * Copyright (c) 2010 iX Systems, Inc. 4 * Copyright (c) 2010 Panasas, Inc. 5 * Copyright (c) 2013-2021 Mellanox Technologies, Ltd. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice unmodified, this list of conditions, and the following 13 * disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <linux/kobject.h> 31 #include <linux/sysfs.h> 32 33 struct kobject * 34 kobject_create(void) 35 { 36 struct kobject *kobj; 37 38 kobj = kzalloc(sizeof(*kobj), GFP_KERNEL); 39 if (kobj == NULL) 40 return (NULL); 41 kobject_init(kobj, &linux_kfree_type); 42 43 return (kobj); 44 } 45 46 47 int 48 kobject_set_name_vargs(struct kobject *kobj, const char *fmt, va_list args) 49 { 50 va_list tmp_va; 51 int len; 52 char *old; 53 char *name; 54 char dummy; 55 56 old = kobj->name; 57 58 if (old && fmt == NULL) 59 return (0); 60 61 /* compute length of string */ 62 va_copy(tmp_va, args); 63 len = vsnprintf(&dummy, 0, fmt, tmp_va); 64 va_end(tmp_va); 65 66 /* account for zero termination */ 67 len++; 68 69 /* check for error */ 70 if (len < 1) 71 return (-EINVAL); 72 73 /* allocate memory for string */ 74 name = kzalloc(len, GFP_KERNEL); 75 if (name == NULL) 76 return (-ENOMEM); 77 vsnprintf(name, len, fmt, args); 78 kobj->name = name; 79 80 /* free old string */ 81 kfree(old); 82 83 /* filter new string */ 84 for (; *name != '\0'; name++) 85 if (*name == '/') 86 *name = '!'; 87 return (0); 88 } 89 90 int 91 kobject_set_name(struct kobject *kobj, const char *fmt, ...) 92 { 93 va_list args; 94 int error; 95 96 va_start(args, fmt); 97 error = kobject_set_name_vargs(kobj, fmt, args); 98 va_end(args); 99 100 return (error); 101 } 102 103 static int 104 kobject_add_complete(struct kobject *kobj, struct kobject *parent) 105 { 106 const struct kobj_type *t; 107 int error; 108 109 kobj->parent = parent; 110 error = sysfs_create_dir(kobj); 111 if (error == 0 && kobj->ktype && kobj->ktype->default_attrs) { 112 struct attribute **attr; 113 t = kobj->ktype; 114 115 for (attr = t->default_attrs; *attr != NULL; attr++) { 116 error = sysfs_create_file(kobj, *attr); 117 if (error) 118 break; 119 } 120 if (error) 121 sysfs_remove_dir(kobj); 122 } 123 return (error); 124 } 125 126 int 127 kobject_add(struct kobject *kobj, struct kobject *parent, const char *fmt, ...) 128 { 129 va_list args; 130 int error; 131 132 va_start(args, fmt); 133 error = kobject_set_name_vargs(kobj, fmt, args); 134 va_end(args); 135 if (error) 136 return (error); 137 138 return kobject_add_complete(kobj, parent); 139 } 140 141 int 142 kobject_init_and_add(struct kobject *kobj, const struct kobj_type *ktype, 143 struct kobject *parent, const char *fmt, ...) 144 { 145 va_list args; 146 int error; 147 148 kobject_init(kobj, ktype); 149 kobj->ktype = ktype; 150 kobj->parent = parent; 151 kobj->name = NULL; 152 153 va_start(args, fmt); 154 error = kobject_set_name_vargs(kobj, fmt, args); 155 va_end(args); 156 if (error) 157 return (error); 158 return kobject_add_complete(kobj, parent); 159 } 160 161 void 162 linux_kobject_release(struct kref *kref) 163 { 164 struct kobject *kobj; 165 char *name; 166 167 kobj = container_of(kref, struct kobject, kref); 168 sysfs_remove_dir(kobj); 169 name = kobj->name; 170 if (kobj->ktype && kobj->ktype->release) 171 kobj->ktype->release(kobj); 172 kfree(name); 173 } 174 175 static void 176 linux_kobject_kfree(struct kobject *kobj) 177 { 178 kfree(kobj); 179 } 180 181 const struct kobj_type linux_kfree_type = { 182 .release = linux_kobject_kfree 183 }; 184 185 void 186 linux_kobject_kfree_name(struct kobject *kobj) 187 { 188 if (kobj) { 189 kfree(kobj->name); 190 } 191 } 192 193 static ssize_t 194 lkpi_kobj_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) 195 { 196 struct kobj_attribute *ka = 197 container_of(attr, struct kobj_attribute, attr); 198 199 if (ka->show == NULL) 200 return (-EIO); 201 202 return (ka->show(kobj, ka, buf)); 203 } 204 205 static ssize_t 206 lkpi_kobj_attr_store(struct kobject *kobj, struct attribute *attr, 207 const char *buf, size_t count) 208 { 209 struct kobj_attribute *ka = 210 container_of(attr, struct kobj_attribute, attr); 211 212 if (ka->store == NULL) 213 return (-EIO); 214 215 return (ka->store(kobj, ka, buf, count)); 216 } 217 218 const struct sysfs_ops kobj_sysfs_ops = { 219 .show = lkpi_kobj_attr_show, 220 .store = lkpi_kobj_attr_store, 221 }; 222