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 static void kset_join(struct kobject *kobj); 34 static void kset_leave(struct kobject *kobj); 35 static void kset_kfree(struct kobject *kobj); 36 37 struct kobject * 38 kobject_create(void) 39 { 40 struct kobject *kobj; 41 42 kobj = kzalloc(sizeof(*kobj), GFP_KERNEL); 43 if (kobj == NULL) 44 return (NULL); 45 kobject_init(kobj, &linux_kfree_type); 46 47 return (kobj); 48 } 49 50 51 int 52 kobject_set_name_vargs(struct kobject *kobj, const char *fmt, va_list args) 53 { 54 va_list tmp_va; 55 int len; 56 char *old; 57 char *name; 58 char dummy; 59 60 old = kobj->name; 61 62 if (old && fmt == NULL) 63 return (0); 64 65 /* compute length of string */ 66 va_copy(tmp_va, args); 67 len = vsnprintf(&dummy, 0, fmt, tmp_va); 68 va_end(tmp_va); 69 70 /* account for zero termination */ 71 len++; 72 73 /* check for error */ 74 if (len < 1) 75 return (-EINVAL); 76 77 /* allocate memory for string */ 78 name = kzalloc(len, GFP_KERNEL); 79 if (name == NULL) 80 return (-ENOMEM); 81 vsnprintf(name, len, fmt, args); 82 kobj->name = name; 83 84 /* free old string */ 85 kfree(old); 86 87 /* filter new string */ 88 for (; *name != '\0'; name++) 89 if (*name == '/') 90 *name = '!'; 91 return (0); 92 } 93 94 int 95 kobject_set_name(struct kobject *kobj, const char *fmt, ...) 96 { 97 va_list args; 98 int error; 99 100 va_start(args, fmt); 101 error = kobject_set_name_vargs(kobj, fmt, args); 102 va_end(args); 103 104 return (error); 105 } 106 107 static int 108 kobject_add_complete(struct kobject *kobj) 109 { 110 const struct kobj_type *t; 111 int error; 112 113 if (kobj->kset != NULL) { 114 kset_join(kobj); 115 kobj->parent = &kobj->kset->kobj; 116 } 117 118 error = sysfs_create_dir(kobj); 119 if (error == 0 && kobj->ktype && kobj->ktype->default_attrs) { 120 struct attribute **attr; 121 t = kobj->ktype; 122 123 for (attr = t->default_attrs; *attr != NULL; attr++) { 124 error = sysfs_create_file(kobj, *attr); 125 if (error) 126 break; 127 } 128 if (error) 129 sysfs_remove_dir(kobj); 130 } 131 132 if (error != 0) 133 kset_leave(kobj); 134 135 return (error); 136 } 137 138 int 139 kobject_add(struct kobject *kobj, struct kobject *parent, const char *fmt, ...) 140 { 141 va_list args; 142 int error; 143 144 kobj->parent = parent; 145 146 va_start(args, fmt); 147 error = kobject_set_name_vargs(kobj, fmt, args); 148 va_end(args); 149 if (error) 150 return (error); 151 152 return kobject_add_complete(kobj); 153 } 154 155 int 156 kobject_init_and_add(struct kobject *kobj, const struct kobj_type *ktype, 157 struct kobject *parent, const char *fmt, ...) 158 { 159 va_list args; 160 int error; 161 162 kobject_init(kobj, ktype); 163 kobj->ktype = ktype; 164 kobj->parent = parent; 165 kobj->name = NULL; 166 167 va_start(args, fmt); 168 error = kobject_set_name_vargs(kobj, fmt, args); 169 va_end(args); 170 if (error) 171 return (error); 172 return kobject_add_complete(kobj); 173 } 174 175 void 176 linux_kobject_release(struct kref *kref) 177 { 178 struct kobject *kobj; 179 char *name; 180 181 kobj = container_of(kref, struct kobject, kref); 182 sysfs_remove_dir(kobj); 183 kset_leave(kobj); 184 name = kobj->name; 185 if (kobj->ktype && kobj->ktype->release) 186 kobj->ktype->release(kobj); 187 kfree(name); 188 } 189 190 static void 191 linux_kobject_kfree(struct kobject *kobj) 192 { 193 kfree(kobj); 194 } 195 196 const struct kobj_type linux_kfree_type = { 197 .release = linux_kobject_kfree 198 }; 199 200 void 201 linux_kobject_kfree_name(struct kobject *kobj) 202 { 203 if (kobj) { 204 kfree(kobj->name); 205 } 206 } 207 208 static ssize_t 209 lkpi_kobj_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) 210 { 211 struct kobj_attribute *ka = 212 container_of(attr, struct kobj_attribute, attr); 213 214 if (ka->show == NULL) 215 return (-EIO); 216 217 return (ka->show(kobj, ka, buf)); 218 } 219 220 static ssize_t 221 lkpi_kobj_attr_store(struct kobject *kobj, struct attribute *attr, 222 const char *buf, size_t count) 223 { 224 struct kobj_attribute *ka = 225 container_of(attr, struct kobj_attribute, attr); 226 227 if (ka->store == NULL) 228 return (-EIO); 229 230 return (ka->store(kobj, ka, buf, count)); 231 } 232 233 const struct sysfs_ops kobj_sysfs_ops = { 234 .show = lkpi_kobj_attr_show, 235 .store = lkpi_kobj_attr_store, 236 }; 237 238 const struct kobj_type linux_kset_kfree_type = { 239 .release = kset_kfree 240 }; 241 242 static struct kset * 243 kset_create(const char *name, 244 const struct kset_uevent_ops *uevent_ops, 245 struct kobject *parent_kobj) 246 { 247 struct kset *kset; 248 249 kset = kzalloc(sizeof(*kset), GFP_KERNEL); 250 if (kset == NULL) 251 return (NULL); 252 253 kset->uevent_ops = uevent_ops; 254 255 kobject_set_name(&kset->kobj, "%s", name); 256 kset->kobj.parent = parent_kobj; 257 kset->kobj.kset = NULL; 258 259 return (kset); 260 } 261 262 void 263 kset_init(struct kset *kset) 264 { 265 kobject_init(&kset->kobj, &linux_kset_kfree_type); 266 INIT_LIST_HEAD(&kset->list); 267 spin_lock_init(&kset->list_lock); 268 } 269 270 static void 271 kset_join(struct kobject *kobj) 272 { 273 struct kset *kset; 274 275 kset = kobj->kset; 276 if (kset == NULL) 277 return; 278 279 kset_get(kobj->kset); 280 281 spin_lock(&kset->list_lock); 282 list_add_tail(&kobj->entry, &kset->list); 283 spin_unlock(&kset->list_lock); 284 } 285 286 static void 287 kset_leave(struct kobject *kobj) 288 { 289 struct kset *kset; 290 291 kset = kobj->kset; 292 if (kset == NULL) 293 return; 294 295 spin_lock(&kset->list_lock); 296 list_del_init(&kobj->entry); 297 spin_unlock(&kset->list_lock); 298 299 kset_put(kobj->kset); 300 } 301 302 struct kset * 303 kset_create_and_add(const char *name, const struct kset_uevent_ops *u, 304 struct kobject *parent_kobj) 305 { 306 int ret; 307 struct kset *kset; 308 309 kset = kset_create(name, u, parent_kobj); 310 if (kset == NULL) 311 return (NULL); 312 313 ret = kset_register(kset); 314 if (ret != 0) { 315 linux_kobject_kfree_name(&kset->kobj); 316 kfree(kset); 317 return (NULL); 318 } 319 320 return (kset); 321 } 322 323 int 324 kset_register(struct kset *kset) 325 { 326 int ret; 327 328 if (kset == NULL) 329 return -EINVAL; 330 331 kset_init(kset); 332 ret = kobject_add_complete(&kset->kobj); 333 334 return ret; 335 } 336 337 void 338 kset_unregister(struct kset *kset) 339 { 340 if (kset == NULL) 341 return; 342 343 kobject_del(&kset->kobj); 344 kobject_put(&kset->kobj); 345 } 346 347 static void 348 kset_kfree(struct kobject *kobj) 349 { 350 struct kset *kset; 351 352 kset = to_kset(kobj); 353 kfree(kset); 354 } 355