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 *
kobject_create(void)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
kobject_set_name_vargs(struct kobject * kobj,const char * fmt,va_list args)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
kobject_set_name(struct kobject * kobj,const char * fmt,...)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
kobject_add_complete(struct kobject * kobj)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
kobject_add(struct kobject * kobj,struct kobject * parent,const char * fmt,...)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
kobject_init_and_add(struct kobject * kobj,const struct kobj_type * ktype,struct kobject * parent,const char * fmt,...)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
linux_kobject_release(struct kref * kref)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
linux_kobject_kfree(struct kobject * kobj)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
linux_kobject_kfree_name(struct kobject * kobj)201 linux_kobject_kfree_name(struct kobject *kobj)
202 {
203 if (kobj) {
204 kfree(kobj->name);
205 }
206 }
207
208 static ssize_t
lkpi_kobj_attr_show(struct kobject * kobj,struct attribute * attr,char * buf)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
lkpi_kobj_attr_store(struct kobject * kobj,struct attribute * attr,const char * buf,size_t count)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 *
kset_create(const char * name,const struct kset_uevent_ops * uevent_ops,struct kobject * parent_kobj)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
kset_init(struct kset * kset)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
kset_join(struct kobject * kobj)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
kset_leave(struct kobject * kobj)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 *
kset_create_and_add(const char * name,const struct kset_uevent_ops * u,struct kobject * parent_kobj)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
kset_register(struct kset * kset)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
kset_unregister(struct kset * kset)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
kset_kfree(struct kobject * kobj)348 kset_kfree(struct kobject *kobj)
349 {
350 struct kset *kset;
351
352 kset = to_kset(kobj);
353 kfree(kset);
354 }
355