Commit | Line | Data |
---|---|---|
ba4ee30c MC |
1 | /* |
2 | * Export the iSCSI boot info to userland via sysfs. | |
3 | * | |
4 | * Copyright (C) 2010 Red Hat, Inc. All rights reserved. | |
5 | * Copyright (C) 2010 Mike Christie | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License v2.0 as published by | |
9 | * the Free Software Foundation | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | */ | |
16 | ||
17 | #include <linux/module.h> | |
18 | #include <linux/string.h> | |
19 | #include <linux/slab.h> | |
20 | #include <linux/sysfs.h> | |
21 | #include <linux/capability.h> | |
22 | #include <linux/iscsi_boot_sysfs.h> | |
23 | ||
24 | ||
25 | MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>"); | |
26 | MODULE_DESCRIPTION("sysfs interface and helpers to export iSCSI boot information"); | |
27 | MODULE_LICENSE("GPL"); | |
28 | /* | |
29 | * The kobject and attribute structures. | |
30 | */ | |
31 | struct iscsi_boot_attr { | |
32 | struct attribute attr; | |
33 | int type; | |
34 | ssize_t (*show) (void *data, int type, char *buf); | |
35 | }; | |
36 | ||
37 | /* | |
38 | * The routine called for all sysfs attributes. | |
39 | */ | |
40 | static ssize_t iscsi_boot_show_attribute(struct kobject *kobj, | |
41 | struct attribute *attr, char *buf) | |
42 | { | |
43 | struct iscsi_boot_kobj *boot_kobj = | |
44 | container_of(kobj, struct iscsi_boot_kobj, kobj); | |
45 | struct iscsi_boot_attr *boot_attr = | |
46 | container_of(attr, struct iscsi_boot_attr, attr); | |
47 | ssize_t ret = -EIO; | |
48 | char *str = buf; | |
49 | ||
50 | if (!capable(CAP_SYS_ADMIN)) | |
51 | return -EACCES; | |
52 | ||
53 | if (boot_kobj->show) | |
54 | ret = boot_kobj->show(boot_kobj->data, boot_attr->type, str); | |
55 | return ret; | |
56 | } | |
57 | ||
58 | static const struct sysfs_ops iscsi_boot_attr_ops = { | |
59 | .show = iscsi_boot_show_attribute, | |
60 | }; | |
61 | ||
62 | static void iscsi_boot_kobj_release(struct kobject *kobj) | |
63 | { | |
64 | struct iscsi_boot_kobj *boot_kobj = | |
65 | container_of(kobj, struct iscsi_boot_kobj, kobj); | |
66 | ||
f457a46f MC |
67 | if (boot_kobj->release) |
68 | boot_kobj->release(boot_kobj->data); | |
ba4ee30c MC |
69 | kfree(boot_kobj); |
70 | } | |
71 | ||
72 | static struct kobj_type iscsi_boot_ktype = { | |
73 | .release = iscsi_boot_kobj_release, | |
74 | .sysfs_ops = &iscsi_boot_attr_ops, | |
75 | }; | |
76 | ||
77 | #define iscsi_boot_rd_attr(fnname, sysfs_name, attr_type) \ | |
78 | static struct iscsi_boot_attr iscsi_boot_attr_##fnname = { \ | |
79 | .attr = { .name = __stringify(sysfs_name), .mode = 0444 }, \ | |
80 | .type = attr_type, \ | |
81 | } | |
82 | ||
83 | /* Target attrs */ | |
84 | iscsi_boot_rd_attr(tgt_index, index, ISCSI_BOOT_TGT_INDEX); | |
85 | iscsi_boot_rd_attr(tgt_flags, flags, ISCSI_BOOT_TGT_FLAGS); | |
86 | iscsi_boot_rd_attr(tgt_ip, ip-addr, ISCSI_BOOT_TGT_IP_ADDR); | |
87 | iscsi_boot_rd_attr(tgt_port, port, ISCSI_BOOT_TGT_PORT); | |
88 | iscsi_boot_rd_attr(tgt_lun, lun, ISCSI_BOOT_TGT_LUN); | |
89 | iscsi_boot_rd_attr(tgt_chap, chap-type, ISCSI_BOOT_TGT_CHAP_TYPE); | |
90 | iscsi_boot_rd_attr(tgt_nic, nic-assoc, ISCSI_BOOT_TGT_NIC_ASSOC); | |
91 | iscsi_boot_rd_attr(tgt_name, target-name, ISCSI_BOOT_TGT_NAME); | |
92 | iscsi_boot_rd_attr(tgt_chap_name, chap-name, ISCSI_BOOT_TGT_CHAP_NAME); | |
93 | iscsi_boot_rd_attr(tgt_chap_secret, chap-secret, ISCSI_BOOT_TGT_CHAP_SECRET); | |
94 | iscsi_boot_rd_attr(tgt_chap_rev_name, rev-chap-name, | |
95 | ISCSI_BOOT_TGT_REV_CHAP_NAME); | |
96 | iscsi_boot_rd_attr(tgt_chap_rev_secret, rev-chap-name-secret, | |
97 | ISCSI_BOOT_TGT_REV_CHAP_SECRET); | |
98 | ||
99 | static struct attribute *target_attrs[] = { | |
100 | &iscsi_boot_attr_tgt_index.attr, | |
101 | &iscsi_boot_attr_tgt_flags.attr, | |
102 | &iscsi_boot_attr_tgt_ip.attr, | |
103 | &iscsi_boot_attr_tgt_port.attr, | |
104 | &iscsi_boot_attr_tgt_lun.attr, | |
105 | &iscsi_boot_attr_tgt_chap.attr, | |
106 | &iscsi_boot_attr_tgt_nic.attr, | |
107 | &iscsi_boot_attr_tgt_name.attr, | |
108 | &iscsi_boot_attr_tgt_chap_name.attr, | |
109 | &iscsi_boot_attr_tgt_chap_secret.attr, | |
110 | &iscsi_boot_attr_tgt_chap_rev_name.attr, | |
111 | &iscsi_boot_attr_tgt_chap_rev_secret.attr, | |
112 | NULL | |
113 | }; | |
114 | ||
587a1f16 | 115 | static umode_t iscsi_boot_tgt_attr_is_visible(struct kobject *kobj, |
ba4ee30c MC |
116 | struct attribute *attr, int i) |
117 | { | |
118 | struct iscsi_boot_kobj *boot_kobj = | |
119 | container_of(kobj, struct iscsi_boot_kobj, kobj); | |
120 | ||
121 | if (attr == &iscsi_boot_attr_tgt_index.attr) | |
122 | return boot_kobj->is_visible(boot_kobj->data, | |
123 | ISCSI_BOOT_TGT_INDEX); | |
124 | else if (attr == &iscsi_boot_attr_tgt_flags.attr) | |
125 | return boot_kobj->is_visible(boot_kobj->data, | |
126 | ISCSI_BOOT_TGT_FLAGS); | |
127 | else if (attr == &iscsi_boot_attr_tgt_ip.attr) | |
128 | return boot_kobj->is_visible(boot_kobj->data, | |
129 | ISCSI_BOOT_TGT_IP_ADDR); | |
130 | else if (attr == &iscsi_boot_attr_tgt_port.attr) | |
131 | return boot_kobj->is_visible(boot_kobj->data, | |
132 | ISCSI_BOOT_TGT_PORT); | |
133 | else if (attr == &iscsi_boot_attr_tgt_lun.attr) | |
134 | return boot_kobj->is_visible(boot_kobj->data, | |
135 | ISCSI_BOOT_TGT_LUN); | |
136 | else if (attr == &iscsi_boot_attr_tgt_chap.attr) | |
137 | return boot_kobj->is_visible(boot_kobj->data, | |
138 | ISCSI_BOOT_TGT_CHAP_TYPE); | |
139 | else if (attr == &iscsi_boot_attr_tgt_nic.attr) | |
140 | return boot_kobj->is_visible(boot_kobj->data, | |
141 | ISCSI_BOOT_TGT_NIC_ASSOC); | |
142 | else if (attr == &iscsi_boot_attr_tgt_name.attr) | |
143 | return boot_kobj->is_visible(boot_kobj->data, | |
144 | ISCSI_BOOT_TGT_NAME); | |
145 | else if (attr == &iscsi_boot_attr_tgt_chap_name.attr) | |
146 | return boot_kobj->is_visible(boot_kobj->data, | |
147 | ISCSI_BOOT_TGT_CHAP_NAME); | |
148 | else if (attr == &iscsi_boot_attr_tgt_chap_secret.attr) | |
149 | return boot_kobj->is_visible(boot_kobj->data, | |
150 | ISCSI_BOOT_TGT_CHAP_SECRET); | |
151 | else if (attr == &iscsi_boot_attr_tgt_chap_rev_name.attr) | |
152 | return boot_kobj->is_visible(boot_kobj->data, | |
153 | ISCSI_BOOT_TGT_REV_CHAP_NAME); | |
154 | else if (attr == &iscsi_boot_attr_tgt_chap_rev_secret.attr) | |
155 | return boot_kobj->is_visible(boot_kobj->data, | |
156 | ISCSI_BOOT_TGT_REV_CHAP_SECRET); | |
157 | return 0; | |
158 | } | |
159 | ||
160 | static struct attribute_group iscsi_boot_target_attr_group = { | |
161 | .attrs = target_attrs, | |
162 | .is_visible = iscsi_boot_tgt_attr_is_visible, | |
163 | }; | |
164 | ||
165 | /* Ethernet attrs */ | |
166 | iscsi_boot_rd_attr(eth_index, index, ISCSI_BOOT_ETH_INDEX); | |
167 | iscsi_boot_rd_attr(eth_flags, flags, ISCSI_BOOT_ETH_FLAGS); | |
168 | iscsi_boot_rd_attr(eth_ip, ip-addr, ISCSI_BOOT_ETH_IP_ADDR); | |
169 | iscsi_boot_rd_attr(eth_subnet, subnet-mask, ISCSI_BOOT_ETH_SUBNET_MASK); | |
170 | iscsi_boot_rd_attr(eth_origin, origin, ISCSI_BOOT_ETH_ORIGIN); | |
171 | iscsi_boot_rd_attr(eth_gateway, gateway, ISCSI_BOOT_ETH_GATEWAY); | |
172 | iscsi_boot_rd_attr(eth_primary_dns, primary-dns, ISCSI_BOOT_ETH_PRIMARY_DNS); | |
173 | iscsi_boot_rd_attr(eth_secondary_dns, secondary-dns, | |
174 | ISCSI_BOOT_ETH_SECONDARY_DNS); | |
175 | iscsi_boot_rd_attr(eth_dhcp, dhcp, ISCSI_BOOT_ETH_DHCP); | |
176 | iscsi_boot_rd_attr(eth_vlan, vlan, ISCSI_BOOT_ETH_VLAN); | |
177 | iscsi_boot_rd_attr(eth_mac, mac, ISCSI_BOOT_ETH_MAC); | |
178 | iscsi_boot_rd_attr(eth_hostname, hostname, ISCSI_BOOT_ETH_HOSTNAME); | |
179 | ||
180 | static struct attribute *ethernet_attrs[] = { | |
181 | &iscsi_boot_attr_eth_index.attr, | |
182 | &iscsi_boot_attr_eth_flags.attr, | |
183 | &iscsi_boot_attr_eth_ip.attr, | |
184 | &iscsi_boot_attr_eth_subnet.attr, | |
185 | &iscsi_boot_attr_eth_origin.attr, | |
186 | &iscsi_boot_attr_eth_gateway.attr, | |
187 | &iscsi_boot_attr_eth_primary_dns.attr, | |
188 | &iscsi_boot_attr_eth_secondary_dns.attr, | |
189 | &iscsi_boot_attr_eth_dhcp.attr, | |
190 | &iscsi_boot_attr_eth_vlan.attr, | |
191 | &iscsi_boot_attr_eth_mac.attr, | |
192 | &iscsi_boot_attr_eth_hostname.attr, | |
193 | NULL | |
194 | }; | |
195 | ||
587a1f16 | 196 | static umode_t iscsi_boot_eth_attr_is_visible(struct kobject *kobj, |
ba4ee30c MC |
197 | struct attribute *attr, int i) |
198 | { | |
199 | struct iscsi_boot_kobj *boot_kobj = | |
200 | container_of(kobj, struct iscsi_boot_kobj, kobj); | |
201 | ||
202 | if (attr == &iscsi_boot_attr_eth_index.attr) | |
203 | return boot_kobj->is_visible(boot_kobj->data, | |
204 | ISCSI_BOOT_ETH_INDEX); | |
205 | else if (attr == &iscsi_boot_attr_eth_flags.attr) | |
206 | return boot_kobj->is_visible(boot_kobj->data, | |
207 | ISCSI_BOOT_ETH_FLAGS); | |
208 | else if (attr == &iscsi_boot_attr_eth_ip.attr) | |
209 | return boot_kobj->is_visible(boot_kobj->data, | |
210 | ISCSI_BOOT_ETH_IP_ADDR); | |
211 | else if (attr == &iscsi_boot_attr_eth_subnet.attr) | |
212 | return boot_kobj->is_visible(boot_kobj->data, | |
213 | ISCSI_BOOT_ETH_SUBNET_MASK); | |
214 | else if (attr == &iscsi_boot_attr_eth_origin.attr) | |
215 | return boot_kobj->is_visible(boot_kobj->data, | |
216 | ISCSI_BOOT_ETH_ORIGIN); | |
217 | else if (attr == &iscsi_boot_attr_eth_gateway.attr) | |
218 | return boot_kobj->is_visible(boot_kobj->data, | |
219 | ISCSI_BOOT_ETH_GATEWAY); | |
220 | else if (attr == &iscsi_boot_attr_eth_primary_dns.attr) | |
221 | return boot_kobj->is_visible(boot_kobj->data, | |
222 | ISCSI_BOOT_ETH_PRIMARY_DNS); | |
223 | else if (attr == &iscsi_boot_attr_eth_secondary_dns.attr) | |
224 | return boot_kobj->is_visible(boot_kobj->data, | |
225 | ISCSI_BOOT_ETH_SECONDARY_DNS); | |
226 | else if (attr == &iscsi_boot_attr_eth_dhcp.attr) | |
227 | return boot_kobj->is_visible(boot_kobj->data, | |
228 | ISCSI_BOOT_ETH_DHCP); | |
229 | else if (attr == &iscsi_boot_attr_eth_vlan.attr) | |
230 | return boot_kobj->is_visible(boot_kobj->data, | |
231 | ISCSI_BOOT_ETH_VLAN); | |
232 | else if (attr == &iscsi_boot_attr_eth_mac.attr) | |
233 | return boot_kobj->is_visible(boot_kobj->data, | |
234 | ISCSI_BOOT_ETH_MAC); | |
235 | else if (attr == &iscsi_boot_attr_eth_hostname.attr) | |
236 | return boot_kobj->is_visible(boot_kobj->data, | |
237 | ISCSI_BOOT_ETH_HOSTNAME); | |
238 | return 0; | |
239 | } | |
240 | ||
241 | static struct attribute_group iscsi_boot_ethernet_attr_group = { | |
242 | .attrs = ethernet_attrs, | |
243 | .is_visible = iscsi_boot_eth_attr_is_visible, | |
244 | }; | |
245 | ||
246 | /* Initiator attrs */ | |
247 | iscsi_boot_rd_attr(ini_index, index, ISCSI_BOOT_INI_INDEX); | |
248 | iscsi_boot_rd_attr(ini_flags, flags, ISCSI_BOOT_INI_FLAGS); | |
249 | iscsi_boot_rd_attr(ini_isns, isns-server, ISCSI_BOOT_INI_ISNS_SERVER); | |
250 | iscsi_boot_rd_attr(ini_slp, slp-server, ISCSI_BOOT_INI_SLP_SERVER); | |
251 | iscsi_boot_rd_attr(ini_primary_radius, pri-radius-server, | |
252 | ISCSI_BOOT_INI_PRI_RADIUS_SERVER); | |
253 | iscsi_boot_rd_attr(ini_secondary_radius, sec-radius-server, | |
254 | ISCSI_BOOT_INI_SEC_RADIUS_SERVER); | |
255 | iscsi_boot_rd_attr(ini_name, initiator-name, ISCSI_BOOT_INI_INITIATOR_NAME); | |
256 | ||
257 | static struct attribute *initiator_attrs[] = { | |
258 | &iscsi_boot_attr_ini_index.attr, | |
259 | &iscsi_boot_attr_ini_flags.attr, | |
260 | &iscsi_boot_attr_ini_isns.attr, | |
261 | &iscsi_boot_attr_ini_slp.attr, | |
262 | &iscsi_boot_attr_ini_primary_radius.attr, | |
263 | &iscsi_boot_attr_ini_secondary_radius.attr, | |
264 | &iscsi_boot_attr_ini_name.attr, | |
265 | NULL | |
266 | }; | |
267 | ||
587a1f16 | 268 | static umode_t iscsi_boot_ini_attr_is_visible(struct kobject *kobj, |
ba4ee30c MC |
269 | struct attribute *attr, int i) |
270 | { | |
271 | struct iscsi_boot_kobj *boot_kobj = | |
272 | container_of(kobj, struct iscsi_boot_kobj, kobj); | |
273 | ||
274 | if (attr == &iscsi_boot_attr_ini_index.attr) | |
275 | return boot_kobj->is_visible(boot_kobj->data, | |
276 | ISCSI_BOOT_INI_INDEX); | |
277 | if (attr == &iscsi_boot_attr_ini_flags.attr) | |
278 | return boot_kobj->is_visible(boot_kobj->data, | |
279 | ISCSI_BOOT_INI_FLAGS); | |
280 | if (attr == &iscsi_boot_attr_ini_isns.attr) | |
281 | return boot_kobj->is_visible(boot_kobj->data, | |
282 | ISCSI_BOOT_INI_ISNS_SERVER); | |
283 | if (attr == &iscsi_boot_attr_ini_slp.attr) | |
284 | return boot_kobj->is_visible(boot_kobj->data, | |
285 | ISCSI_BOOT_INI_SLP_SERVER); | |
286 | if (attr == &iscsi_boot_attr_ini_primary_radius.attr) | |
287 | return boot_kobj->is_visible(boot_kobj->data, | |
288 | ISCSI_BOOT_INI_PRI_RADIUS_SERVER); | |
289 | if (attr == &iscsi_boot_attr_ini_secondary_radius.attr) | |
290 | return boot_kobj->is_visible(boot_kobj->data, | |
291 | ISCSI_BOOT_INI_SEC_RADIUS_SERVER); | |
292 | if (attr == &iscsi_boot_attr_ini_name.attr) | |
293 | return boot_kobj->is_visible(boot_kobj->data, | |
294 | ISCSI_BOOT_INI_INITIATOR_NAME); | |
295 | ||
296 | return 0; | |
297 | } | |
298 | ||
299 | static struct attribute_group iscsi_boot_initiator_attr_group = { | |
300 | .attrs = initiator_attrs, | |
301 | .is_visible = iscsi_boot_ini_attr_is_visible, | |
302 | }; | |
303 | ||
304 | static struct iscsi_boot_kobj * | |
305 | iscsi_boot_create_kobj(struct iscsi_boot_kset *boot_kset, | |
306 | struct attribute_group *attr_group, | |
307 | const char *name, int index, void *data, | |
308 | ssize_t (*show) (void *data, int type, char *buf), | |
587a1f16 | 309 | umode_t (*is_visible) (void *data, int type), |
f457a46f | 310 | void (*release) (void *data)) |
ba4ee30c MC |
311 | { |
312 | struct iscsi_boot_kobj *boot_kobj; | |
313 | ||
314 | boot_kobj = kzalloc(sizeof(*boot_kobj), GFP_KERNEL); | |
315 | if (!boot_kobj) | |
316 | return NULL; | |
317 | INIT_LIST_HEAD(&boot_kobj->list); | |
318 | ||
319 | boot_kobj->kobj.kset = boot_kset->kset; | |
320 | if (kobject_init_and_add(&boot_kobj->kobj, &iscsi_boot_ktype, | |
321 | NULL, name, index)) { | |
322 | kfree(boot_kobj); | |
323 | return NULL; | |
324 | } | |
325 | boot_kobj->data = data; | |
326 | boot_kobj->show = show; | |
327 | boot_kobj->is_visible = is_visible; | |
f457a46f | 328 | boot_kobj->release = release; |
ba4ee30c MC |
329 | |
330 | if (sysfs_create_group(&boot_kobj->kobj, attr_group)) { | |
331 | /* | |
332 | * We do not want to free this because the caller | |
333 | * will assume that since the creation call failed | |
334 | * the boot kobj was not setup and the normal release | |
335 | * path is not being run. | |
336 | */ | |
f457a46f | 337 | boot_kobj->release = NULL; |
ba4ee30c MC |
338 | kobject_put(&boot_kobj->kobj); |
339 | return NULL; | |
340 | } | |
341 | boot_kobj->attr_group = attr_group; | |
342 | ||
343 | kobject_uevent(&boot_kobj->kobj, KOBJ_ADD); | |
344 | /* Nothing broke so lets add it to the list. */ | |
345 | list_add_tail(&boot_kobj->list, &boot_kset->kobj_list); | |
346 | return boot_kobj; | |
347 | } | |
348 | ||
349 | static void iscsi_boot_remove_kobj(struct iscsi_boot_kobj *boot_kobj) | |
350 | { | |
351 | list_del(&boot_kobj->list); | |
352 | sysfs_remove_group(&boot_kobj->kobj, boot_kobj->attr_group); | |
353 | kobject_put(&boot_kobj->kobj); | |
354 | } | |
355 | ||
356 | /** | |
357 | * iscsi_boot_create_target() - create boot target sysfs dir | |
358 | * @boot_kset: boot kset | |
359 | * @index: the target id | |
360 | * @data: driver specific data for target | |
361 | * @show: attr show function | |
362 | * @is_visible: attr visibility function | |
f457a46f | 363 | * @release: release function |
ba4ee30c MC |
364 | * |
365 | * Note: The boot sysfs lib will free the data passed in for the caller | |
366 | * when all refs to the target kobject have been released. | |
367 | */ | |
368 | struct iscsi_boot_kobj * | |
369 | iscsi_boot_create_target(struct iscsi_boot_kset *boot_kset, int index, | |
370 | void *data, | |
371 | ssize_t (*show) (void *data, int type, char *buf), | |
587a1f16 | 372 | umode_t (*is_visible) (void *data, int type), |
f457a46f | 373 | void (*release) (void *data)) |
ba4ee30c MC |
374 | { |
375 | return iscsi_boot_create_kobj(boot_kset, &iscsi_boot_target_attr_group, | |
f457a46f MC |
376 | "target%d", index, data, show, is_visible, |
377 | release); | |
ba4ee30c MC |
378 | } |
379 | EXPORT_SYMBOL_GPL(iscsi_boot_create_target); | |
380 | ||
381 | /** | |
382 | * iscsi_boot_create_initiator() - create boot initiator sysfs dir | |
383 | * @boot_kset: boot kset | |
384 | * @index: the initiator id | |
385 | * @data: driver specific data | |
386 | * @show: attr show function | |
387 | * @is_visible: attr visibility function | |
f457a46f | 388 | * @release: release function |
ba4ee30c MC |
389 | * |
390 | * Note: The boot sysfs lib will free the data passed in for the caller | |
391 | * when all refs to the initiator kobject have been released. | |
392 | */ | |
393 | struct iscsi_boot_kobj * | |
394 | iscsi_boot_create_initiator(struct iscsi_boot_kset *boot_kset, int index, | |
395 | void *data, | |
396 | ssize_t (*show) (void *data, int type, char *buf), | |
587a1f16 | 397 | umode_t (*is_visible) (void *data, int type), |
f457a46f | 398 | void (*release) (void *data)) |
ba4ee30c MC |
399 | { |
400 | return iscsi_boot_create_kobj(boot_kset, | |
401 | &iscsi_boot_initiator_attr_group, | |
402 | "initiator", index, data, show, | |
f457a46f | 403 | is_visible, release); |
ba4ee30c MC |
404 | } |
405 | EXPORT_SYMBOL_GPL(iscsi_boot_create_initiator); | |
406 | ||
407 | /** | |
408 | * iscsi_boot_create_ethernet() - create boot ethernet sysfs dir | |
409 | * @boot_kset: boot kset | |
410 | * @index: the ethernet device id | |
411 | * @data: driver specific data | |
412 | * @show: attr show function | |
413 | * @is_visible: attr visibility function | |
f457a46f | 414 | * @release: release function |
ba4ee30c MC |
415 | * |
416 | * Note: The boot sysfs lib will free the data passed in for the caller | |
417 | * when all refs to the ethernet kobject have been released. | |
418 | */ | |
419 | struct iscsi_boot_kobj * | |
420 | iscsi_boot_create_ethernet(struct iscsi_boot_kset *boot_kset, int index, | |
421 | void *data, | |
422 | ssize_t (*show) (void *data, int type, char *buf), | |
587a1f16 | 423 | umode_t (*is_visible) (void *data, int type), |
f457a46f | 424 | void (*release) (void *data)) |
ba4ee30c MC |
425 | { |
426 | return iscsi_boot_create_kobj(boot_kset, | |
427 | &iscsi_boot_ethernet_attr_group, | |
428 | "ethernet%d", index, data, show, | |
f457a46f | 429 | is_visible, release); |
ba4ee30c MC |
430 | } |
431 | EXPORT_SYMBOL_GPL(iscsi_boot_create_ethernet); | |
432 | ||
433 | /** | |
434 | * iscsi_boot_create_kset() - creates root sysfs tree | |
435 | * @set_name: name of root dir | |
436 | */ | |
437 | struct iscsi_boot_kset *iscsi_boot_create_kset(const char *set_name) | |
438 | { | |
439 | struct iscsi_boot_kset *boot_kset; | |
440 | ||
441 | boot_kset = kzalloc(sizeof(*boot_kset), GFP_KERNEL); | |
442 | if (!boot_kset) | |
443 | return NULL; | |
444 | ||
445 | boot_kset->kset = kset_create_and_add(set_name, NULL, firmware_kobj); | |
446 | if (!boot_kset->kset) { | |
447 | kfree(boot_kset); | |
448 | return NULL; | |
449 | } | |
450 | ||
451 | INIT_LIST_HEAD(&boot_kset->kobj_list); | |
452 | return boot_kset; | |
453 | } | |
454 | EXPORT_SYMBOL_GPL(iscsi_boot_create_kset); | |
455 | ||
456 | /** | |
457 | * iscsi_boot_create_host_kset() - creates root sysfs tree for a scsi host | |
458 | * @hostno: host number of scsi host | |
459 | */ | |
460 | struct iscsi_boot_kset *iscsi_boot_create_host_kset(unsigned int hostno) | |
461 | { | |
462 | struct iscsi_boot_kset *boot_kset; | |
463 | char *set_name; | |
464 | ||
465 | set_name = kasprintf(GFP_KERNEL, "iscsi_boot%u", hostno); | |
466 | if (!set_name) | |
467 | return NULL; | |
468 | ||
469 | boot_kset = iscsi_boot_create_kset(set_name); | |
470 | kfree(set_name); | |
471 | return boot_kset; | |
472 | } | |
473 | EXPORT_SYMBOL_GPL(iscsi_boot_create_host_kset); | |
474 | ||
475 | /** | |
476 | * iscsi_boot_destroy_kset() - destroy kset and kobjects under it | |
477 | * @boot_kset: boot kset | |
478 | * | |
479 | * This will remove the kset and kobjects and attrs under it. | |
480 | */ | |
481 | void iscsi_boot_destroy_kset(struct iscsi_boot_kset *boot_kset) | |
482 | { | |
483 | struct iscsi_boot_kobj *boot_kobj, *tmp_kobj; | |
484 | ||
9d045163 MC |
485 | if (!boot_kset) |
486 | return; | |
487 | ||
ba4ee30c MC |
488 | list_for_each_entry_safe(boot_kobj, tmp_kobj, |
489 | &boot_kset->kobj_list, list) | |
490 | iscsi_boot_remove_kobj(boot_kobj); | |
491 | ||
492 | kset_unregister(boot_kset->kset); | |
9cb48e7b | 493 | kfree(boot_kset); |
ba4ee30c MC |
494 | } |
495 | EXPORT_SYMBOL_GPL(iscsi_boot_destroy_kset); |