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, 2014 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 | * $FreeBSD$ |
---|
30 | */ |
---|
31 | #ifndef _LINUX_SYSFS_H_ |
---|
32 | #define _LINUX_SYSFS_H_ |
---|
33 | |
---|
34 | #if 0 |
---|
35 | #include <sys/sysctl.h> |
---|
36 | |
---|
37 | struct attribute { |
---|
38 | const char *name; |
---|
39 | struct module *owner; |
---|
40 | mode_t mode; |
---|
41 | }; |
---|
42 | |
---|
43 | struct sysfs_ops { |
---|
44 | ssize_t (*show)(struct kobject *, struct attribute *, char *); |
---|
45 | ssize_t (*store)(struct kobject *, struct attribute *, const char *, |
---|
46 | size_t); |
---|
47 | }; |
---|
48 | |
---|
49 | struct attribute_group { |
---|
50 | const char *name; |
---|
51 | mode_t (*is_visible)(struct kobject *, |
---|
52 | struct attribute *, int); |
---|
53 | struct attribute **attrs; |
---|
54 | }; |
---|
55 | |
---|
56 | #define __ATTR(_name, _mode, _show, _store) { \ |
---|
57 | .attr = { .name = __stringify(_name), .mode = _mode }, \ |
---|
58 | .show = _show, .store = _store, \ |
---|
59 | } |
---|
60 | |
---|
61 | #define __ATTR_RO(_name) { \ |
---|
62 | .attr = { .name = __stringify(_name), .mode = 0444 }, \ |
---|
63 | .show = _name##_show, \ |
---|
64 | } |
---|
65 | |
---|
66 | #define __ATTR_NULL { .attr = { .name = NULL } } |
---|
67 | |
---|
68 | /* |
---|
69 | * Handle our generic '\0' terminated 'C' string. |
---|
70 | * Two cases: |
---|
71 | * a variable string: point arg1 at it, arg2 is max length. |
---|
72 | * a constant string: point arg1 at it, arg2 is zero. |
---|
73 | */ |
---|
74 | |
---|
75 | static inline int |
---|
76 | sysctl_handle_attr(SYSCTL_HANDLER_ARGS) |
---|
77 | { |
---|
78 | struct kobject *kobj; |
---|
79 | struct attribute *attr; |
---|
80 | const struct sysfs_ops *ops; |
---|
81 | char *buf; |
---|
82 | int error; |
---|
83 | ssize_t len; |
---|
84 | |
---|
85 | kobj = arg1; |
---|
86 | attr = (struct attribute *)arg2; |
---|
87 | if (kobj->ktype == NULL || kobj->ktype->sysfs_ops == NULL) |
---|
88 | return (ENODEV); |
---|
89 | buf = (char *)get_zeroed_page(GFP_KERNEL); |
---|
90 | if (buf == NULL) |
---|
91 | return (ENOMEM); |
---|
92 | ops = kobj->ktype->sysfs_ops; |
---|
93 | if (ops->show) { |
---|
94 | len = ops->show(kobj, attr, buf); |
---|
95 | /* |
---|
96 | * It's valid to not have a 'show' so just return an |
---|
97 | * empty string. |
---|
98 | */ |
---|
99 | if (len < 0) { |
---|
100 | error = -len; |
---|
101 | if (error != EIO) |
---|
102 | goto out; |
---|
103 | buf[0] = '\0'; |
---|
104 | } else if (len) { |
---|
105 | len--; |
---|
106 | if (len >= PAGE_SIZE) |
---|
107 | len = PAGE_SIZE - 1; |
---|
108 | /* Trim trailing newline. */ |
---|
109 | buf[len] = '\0'; |
---|
110 | } |
---|
111 | } |
---|
112 | |
---|
113 | /* Leave one trailing byte to append a newline. */ |
---|
114 | error = sysctl_handle_string(oidp, buf, PAGE_SIZE - 1, req); |
---|
115 | if (error != 0 || req->newptr == NULL || ops->store == NULL) |
---|
116 | goto out; |
---|
117 | len = strlcat(buf, "\n", PAGE_SIZE); |
---|
118 | KASSERT(len < PAGE_SIZE, ("new attribute truncated")); |
---|
119 | len = ops->store(kobj, attr, buf, len); |
---|
120 | if (len < 0) |
---|
121 | error = -len; |
---|
122 | out: |
---|
123 | free_page((unsigned long)buf); |
---|
124 | |
---|
125 | return (error); |
---|
126 | } |
---|
127 | |
---|
128 | static inline int |
---|
129 | sysfs_create_file(struct kobject *kobj, const struct attribute *attr) |
---|
130 | { |
---|
131 | |
---|
132 | sysctl_add_oid(NULL, SYSCTL_CHILDREN(kobj->oidp), OID_AUTO, |
---|
133 | attr->name, CTLTYPE_STRING|CTLFLAG_RW|CTLFLAG_MPSAFE, kobj, |
---|
134 | (uintptr_t)attr, sysctl_handle_attr, "A", ""); |
---|
135 | |
---|
136 | return (0); |
---|
137 | } |
---|
138 | |
---|
139 | static inline void |
---|
140 | sysfs_remove_file(struct kobject *kobj, const struct attribute *attr) |
---|
141 | { |
---|
142 | |
---|
143 | if (kobj->oidp) |
---|
144 | sysctl_remove_name(kobj->oidp, attr->name, 1, 1); |
---|
145 | } |
---|
146 | |
---|
147 | static inline void |
---|
148 | sysfs_remove_group(struct kobject *kobj, const struct attribute_group *grp) |
---|
149 | { |
---|
150 | |
---|
151 | if (kobj->oidp) |
---|
152 | sysctl_remove_name(kobj->oidp, grp->name, 1, 1); |
---|
153 | } |
---|
154 | |
---|
155 | static inline int |
---|
156 | sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp) |
---|
157 | { |
---|
158 | struct attribute **attr; |
---|
159 | struct sysctl_oid *oidp; |
---|
160 | |
---|
161 | oidp = SYSCTL_ADD_NODE(NULL, SYSCTL_CHILDREN(kobj->oidp), |
---|
162 | OID_AUTO, grp->name, CTLFLAG_RD|CTLFLAG_MPSAFE, NULL, grp->name); |
---|
163 | for (attr = grp->attrs; *attr != NULL; attr++) { |
---|
164 | sysctl_add_oid(NULL, SYSCTL_CHILDREN(oidp), OID_AUTO, |
---|
165 | (*attr)->name, CTLTYPE_STRING|CTLFLAG_RW|CTLFLAG_MPSAFE, |
---|
166 | kobj, (uintptr_t)*attr, sysctl_handle_attr, "A", ""); |
---|
167 | } |
---|
168 | |
---|
169 | return (0); |
---|
170 | } |
---|
171 | |
---|
172 | static inline int |
---|
173 | sysfs_create_dir(struct kobject *kobj) |
---|
174 | { |
---|
175 | |
---|
176 | kobj->oidp = SYSCTL_ADD_NODE(NULL, SYSCTL_CHILDREN(kobj->parent->oidp), |
---|
177 | OID_AUTO, kobj->name, CTLFLAG_RD|CTLFLAG_MPSAFE, NULL, kobj->name); |
---|
178 | |
---|
179 | return (0); |
---|
180 | } |
---|
181 | |
---|
182 | static inline void |
---|
183 | sysfs_remove_dir(struct kobject *kobj) |
---|
184 | { |
---|
185 | |
---|
186 | if (kobj->oidp == NULL) |
---|
187 | return; |
---|
188 | sysctl_remove_oid(kobj->oidp, 1, 1); |
---|
189 | } |
---|
190 | |
---|
191 | #define sysfs_attr_init(attr) do {} while(0) |
---|
192 | #endif |
---|
193 | |
---|
194 | #endif /* _LINUX_SYSFS_H_ */ |
---|