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); | |
c988cabe | 169 | iscsi_boot_rd_attr(eth_prefix, prefix-len, ISCSI_BOOT_ETH_PREFIX_LEN); |
ba4ee30c MC |
170 | iscsi_boot_rd_attr(eth_subnet, subnet-mask, ISCSI_BOOT_ETH_SUBNET_MASK); |
171 | iscsi_boot_rd_attr(eth_origin, origin, ISCSI_BOOT_ETH_ORIGIN); | |
172 | iscsi_boot_rd_attr(eth_gateway, gateway, ISCSI_BOOT_ETH_GATEWAY); | |
173 | iscsi_boot_rd_attr(eth_primary_dns, primary-dns, ISCSI_BOOT_ETH_PRIMARY_DNS); | |
174 | iscsi_boot_rd_attr(eth_secondary_dns, secondary-dns, | |
175 | ISCSI_BOOT_ETH_SECONDARY_DNS); | |
176 | iscsi_boot_rd_attr(eth_dhcp, dhcp, ISCSI_BOOT_ETH_DHCP); | |
177 | iscsi_boot_rd_attr(eth_vlan, vlan, ISCSI_BOOT_ETH_VLAN); | |
178 | iscsi_boot_rd_attr(eth_mac, mac, ISCSI_BOOT_ETH_MAC); | |
179 | iscsi_boot_rd_attr(eth_hostname, hostname, ISCSI_BOOT_ETH_HOSTNAME); | |
180 | ||
181 | static struct attribute *ethernet_attrs[] = { | |
182 | &iscsi_boot_attr_eth_index.attr, | |
183 | &iscsi_boot_attr_eth_flags.attr, | |
184 | &iscsi_boot_attr_eth_ip.attr, | |
c988cabe | 185 | &iscsi_boot_attr_eth_prefix.attr, |
ba4ee30c MC |
186 | &iscsi_boot_attr_eth_subnet.attr, |
187 | &iscsi_boot_attr_eth_origin.attr, | |
188 | &iscsi_boot_attr_eth_gateway.attr, | |
189 | &iscsi_boot_attr_eth_primary_dns.attr, | |
190 | &iscsi_boot_attr_eth_secondary_dns.attr, | |
191 | &iscsi_boot_attr_eth_dhcp.attr, | |
192 | &iscsi_boot_attr_eth_vlan.attr, | |
193 | &iscsi_boot_attr_eth_mac.attr, | |
194 | &iscsi_boot_attr_eth_hostname.attr, | |
195 | NULL | |
196 | }; | |
197 | ||
587a1f16 | 198 | static umode_t iscsi_boot_eth_attr_is_visible(struct kobject *kobj, |
ba4ee30c MC |
199 | struct attribute *attr, int i) |
200 | { | |
201 | struct iscsi_boot_kobj *boot_kobj = | |
202 | container_of(kobj, struct iscsi_boot_kobj, kobj); | |
203 | ||
204 | if (attr == &iscsi_boot_attr_eth_index.attr) | |
205 | return boot_kobj->is_visible(boot_kobj->data, | |
206 | ISCSI_BOOT_ETH_INDEX); | |
207 | else if (attr == &iscsi_boot_attr_eth_flags.attr) | |
208 | return boot_kobj->is_visible(boot_kobj->data, | |
209 | ISCSI_BOOT_ETH_FLAGS); | |
210 | else if (attr == &iscsi_boot_attr_eth_ip.attr) | |
211 | return boot_kobj->is_visible(boot_kobj->data, | |
212 | ISCSI_BOOT_ETH_IP_ADDR); | |
c988cabe HR |
213 | else if (attr == &iscsi_boot_attr_eth_prefix.attr) |
214 | return boot_kobj->is_visible(boot_kobj->data, | |
215 | ISCSI_BOOT_ETH_PREFIX_LEN); | |
ba4ee30c MC |
216 | else if (attr == &iscsi_boot_attr_eth_subnet.attr) |
217 | return boot_kobj->is_visible(boot_kobj->data, | |
218 | ISCSI_BOOT_ETH_SUBNET_MASK); | |
219 | else if (attr == &iscsi_boot_attr_eth_origin.attr) | |
220 | return boot_kobj->is_visible(boot_kobj->data, | |
221 | ISCSI_BOOT_ETH_ORIGIN); | |
222 | else if (attr == &iscsi_boot_attr_eth_gateway.attr) | |
223 | return boot_kobj->is_visible(boot_kobj->data, | |
224 | ISCSI_BOOT_ETH_GATEWAY); | |
225 | else if (attr == &iscsi_boot_attr_eth_primary_dns.attr) | |
226 | return boot_kobj->is_visible(boot_kobj->data, | |
227 | ISCSI_BOOT_ETH_PRIMARY_DNS); | |
228 | else if (attr == &iscsi_boot_attr_eth_secondary_dns.attr) | |
229 | return boot_kobj->is_visible(boot_kobj->data, | |
230 | ISCSI_BOOT_ETH_SECONDARY_DNS); | |
231 | else if (attr == &iscsi_boot_attr_eth_dhcp.attr) | |
232 | return boot_kobj->is_visible(boot_kobj->data, | |
233 | ISCSI_BOOT_ETH_DHCP); | |
234 | else if (attr == &iscsi_boot_attr_eth_vlan.attr) | |
235 | return boot_kobj->is_visible(boot_kobj->data, | |
236 | ISCSI_BOOT_ETH_VLAN); | |
237 | else if (attr == &iscsi_boot_attr_eth_mac.attr) | |
238 | return boot_kobj->is_visible(boot_kobj->data, | |
239 | ISCSI_BOOT_ETH_MAC); | |
240 | else if (attr == &iscsi_boot_attr_eth_hostname.attr) | |
241 | return boot_kobj->is_visible(boot_kobj->data, | |
242 | ISCSI_BOOT_ETH_HOSTNAME); | |
243 | return 0; | |
244 | } | |
245 | ||
246 | static struct attribute_group iscsi_boot_ethernet_attr_group = { | |
247 | .attrs = ethernet_attrs, | |
248 | .is_visible = iscsi_boot_eth_attr_is_visible, | |
249 | }; | |
250 | ||
251 | /* Initiator attrs */ | |
252 | iscsi_boot_rd_attr(ini_index, index, ISCSI_BOOT_INI_INDEX); | |
253 | iscsi_boot_rd_attr(ini_flags, flags, ISCSI_BOOT_INI_FLAGS); | |
254 | iscsi_boot_rd_attr(ini_isns, isns-server, ISCSI_BOOT_INI_ISNS_SERVER); | |
255 | iscsi_boot_rd_attr(ini_slp, slp-server, ISCSI_BOOT_INI_SLP_SERVER); | |
256 | iscsi_boot_rd_attr(ini_primary_radius, pri-radius-server, | |
257 | ISCSI_BOOT_INI_PRI_RADIUS_SERVER); | |
258 | iscsi_boot_rd_attr(ini_secondary_radius, sec-radius-server, | |
259 | ISCSI_BOOT_INI_SEC_RADIUS_SERVER); | |
260 | iscsi_boot_rd_attr(ini_name, initiator-name, ISCSI_BOOT_INI_INITIATOR_NAME); | |
261 | ||
262 | static struct attribute *initiator_attrs[] = { | |
263 | &iscsi_boot_attr_ini_index.attr, | |
264 | &iscsi_boot_attr_ini_flags.attr, | |
265 | &iscsi_boot_attr_ini_isns.attr, | |
266 | &iscsi_boot_attr_ini_slp.attr, | |
267 | &iscsi_boot_attr_ini_primary_radius.attr, | |
268 | &iscsi_boot_attr_ini_secondary_radius.attr, | |
269 | &iscsi_boot_attr_ini_name.attr, | |
270 | NULL | |
271 | }; | |
272 | ||
587a1f16 | 273 | static umode_t iscsi_boot_ini_attr_is_visible(struct kobject *kobj, |
ba4ee30c MC |
274 | struct attribute *attr, int i) |
275 | { | |
276 | struct iscsi_boot_kobj *boot_kobj = | |
277 | container_of(kobj, struct iscsi_boot_kobj, kobj); | |
278 | ||
279 | if (attr == &iscsi_boot_attr_ini_index.attr) | |
280 | return boot_kobj->is_visible(boot_kobj->data, | |
281 | ISCSI_BOOT_INI_INDEX); | |
282 | if (attr == &iscsi_boot_attr_ini_flags.attr) | |
283 | return boot_kobj->is_visible(boot_kobj->data, | |
284 | ISCSI_BOOT_INI_FLAGS); | |
285 | if (attr == &iscsi_boot_attr_ini_isns.attr) | |
286 | return boot_kobj->is_visible(boot_kobj->data, | |
287 | ISCSI_BOOT_INI_ISNS_SERVER); | |
288 | if (attr == &iscsi_boot_attr_ini_slp.attr) | |
289 | return boot_kobj->is_visible(boot_kobj->data, | |
290 | ISCSI_BOOT_INI_SLP_SERVER); | |
291 | if (attr == &iscsi_boot_attr_ini_primary_radius.attr) | |
292 | return boot_kobj->is_visible(boot_kobj->data, | |
293 | ISCSI_BOOT_INI_PRI_RADIUS_SERVER); | |
294 | if (attr == &iscsi_boot_attr_ini_secondary_radius.attr) | |
295 | return boot_kobj->is_visible(boot_kobj->data, | |
296 | ISCSI_BOOT_INI_SEC_RADIUS_SERVER); | |
297 | if (attr == &iscsi_boot_attr_ini_name.attr) | |
298 | return boot_kobj->is_visible(boot_kobj->data, | |
299 | ISCSI_BOOT_INI_INITIATOR_NAME); | |
300 | ||
301 | return 0; | |
302 | } | |
303 | ||
304 | static struct attribute_group iscsi_boot_initiator_attr_group = { | |
305 | .attrs = initiator_attrs, | |
306 | .is_visible = iscsi_boot_ini_attr_is_visible, | |
307 | }; | |
308 | ||
309 | static struct iscsi_boot_kobj * | |
310 | iscsi_boot_create_kobj(struct iscsi_boot_kset *boot_kset, | |
311 | struct attribute_group *attr_group, | |
312 | const char *name, int index, void *data, | |
313 | ssize_t (*show) (void *data, int type, char *buf), | |
587a1f16 | 314 | umode_t (*is_visible) (void *data, int type), |
f457a46f | 315 | void (*release) (void *data)) |
ba4ee30c MC |
316 | { |
317 | struct iscsi_boot_kobj *boot_kobj; | |
318 | ||
319 | boot_kobj = kzalloc(sizeof(*boot_kobj), GFP_KERNEL); | |
320 | if (!boot_kobj) | |
321 | return NULL; | |
322 | INIT_LIST_HEAD(&boot_kobj->list); | |
323 | ||
324 | boot_kobj->kobj.kset = boot_kset->kset; | |
325 | if (kobject_init_and_add(&boot_kobj->kobj, &iscsi_boot_ktype, | |
326 | NULL, name, index)) { | |
327 | kfree(boot_kobj); | |
328 | return NULL; | |
329 | } | |
330 | boot_kobj->data = data; | |
331 | boot_kobj->show = show; | |
332 | boot_kobj->is_visible = is_visible; | |
f457a46f | 333 | boot_kobj->release = release; |
ba4ee30c MC |
334 | |
335 | if (sysfs_create_group(&boot_kobj->kobj, attr_group)) { | |
336 | /* | |
337 | * We do not want to free this because the caller | |
338 | * will assume that since the creation call failed | |
339 | * the boot kobj was not setup and the normal release | |
340 | * path is not being run. | |
341 | */ | |
f457a46f | 342 | boot_kobj->release = NULL; |
ba4ee30c MC |
343 | kobject_put(&boot_kobj->kobj); |
344 | return NULL; | |
345 | } | |
346 | boot_kobj->attr_group = attr_group; | |
347 | ||
348 | kobject_uevent(&boot_kobj->kobj, KOBJ_ADD); | |
349 | /* Nothing broke so lets add it to the list. */ | |
350 | list_add_tail(&boot_kobj->list, &boot_kset->kobj_list); | |
351 | return boot_kobj; | |
352 | } | |
353 | ||
354 | static void iscsi_boot_remove_kobj(struct iscsi_boot_kobj *boot_kobj) | |
355 | { | |
356 | list_del(&boot_kobj->list); | |
357 | sysfs_remove_group(&boot_kobj->kobj, boot_kobj->attr_group); | |
358 | kobject_put(&boot_kobj->kobj); | |
359 | } | |
360 | ||
361 | /** | |
362 | * iscsi_boot_create_target() - create boot target sysfs dir | |
363 | * @boot_kset: boot kset | |
364 | * @index: the target id | |
365 | * @data: driver specific data for target | |
366 | * @show: attr show function | |
367 | * @is_visible: attr visibility function | |
f457a46f | 368 | * @release: release function |
ba4ee30c MC |
369 | * |
370 | * Note: The boot sysfs lib will free the data passed in for the caller | |
371 | * when all refs to the target kobject have been released. | |
372 | */ | |
373 | struct iscsi_boot_kobj * | |
374 | iscsi_boot_create_target(struct iscsi_boot_kset *boot_kset, int index, | |
375 | void *data, | |
376 | ssize_t (*show) (void *data, int type, char *buf), | |
587a1f16 | 377 | umode_t (*is_visible) (void *data, int type), |
f457a46f | 378 | void (*release) (void *data)) |
ba4ee30c MC |
379 | { |
380 | return iscsi_boot_create_kobj(boot_kset, &iscsi_boot_target_attr_group, | |
f457a46f MC |
381 | "target%d", index, data, show, is_visible, |
382 | release); | |
ba4ee30c MC |
383 | } |
384 | EXPORT_SYMBOL_GPL(iscsi_boot_create_target); | |
385 | ||
386 | /** | |
387 | * iscsi_boot_create_initiator() - create boot initiator sysfs dir | |
388 | * @boot_kset: boot kset | |
389 | * @index: the initiator id | |
390 | * @data: driver specific data | |
391 | * @show: attr show function | |
392 | * @is_visible: attr visibility function | |
f457a46f | 393 | * @release: release function |
ba4ee30c MC |
394 | * |
395 | * Note: The boot sysfs lib will free the data passed in for the caller | |
396 | * when all refs to the initiator kobject have been released. | |
397 | */ | |
398 | struct iscsi_boot_kobj * | |
399 | iscsi_boot_create_initiator(struct iscsi_boot_kset *boot_kset, int index, | |
400 | void *data, | |
401 | ssize_t (*show) (void *data, int type, char *buf), | |
587a1f16 | 402 | umode_t (*is_visible) (void *data, int type), |
f457a46f | 403 | void (*release) (void *data)) |
ba4ee30c MC |
404 | { |
405 | return iscsi_boot_create_kobj(boot_kset, | |
406 | &iscsi_boot_initiator_attr_group, | |
407 | "initiator", index, data, show, | |
f457a46f | 408 | is_visible, release); |
ba4ee30c MC |
409 | } |
410 | EXPORT_SYMBOL_GPL(iscsi_boot_create_initiator); | |
411 | ||
412 | /** | |
413 | * iscsi_boot_create_ethernet() - create boot ethernet sysfs dir | |
414 | * @boot_kset: boot kset | |
415 | * @index: the ethernet device id | |
416 | * @data: driver specific data | |
417 | * @show: attr show function | |
418 | * @is_visible: attr visibility function | |
f457a46f | 419 | * @release: release function |
ba4ee30c MC |
420 | * |
421 | * Note: The boot sysfs lib will free the data passed in for the caller | |
422 | * when all refs to the ethernet kobject have been released. | |
423 | */ | |
424 | struct iscsi_boot_kobj * | |
425 | iscsi_boot_create_ethernet(struct iscsi_boot_kset *boot_kset, int index, | |
426 | void *data, | |
427 | ssize_t (*show) (void *data, int type, char *buf), | |
587a1f16 | 428 | umode_t (*is_visible) (void *data, int type), |
f457a46f | 429 | void (*release) (void *data)) |
ba4ee30c MC |
430 | { |
431 | return iscsi_boot_create_kobj(boot_kset, | |
432 | &iscsi_boot_ethernet_attr_group, | |
433 | "ethernet%d", index, data, show, | |
f457a46f | 434 | is_visible, release); |
ba4ee30c MC |
435 | } |
436 | EXPORT_SYMBOL_GPL(iscsi_boot_create_ethernet); | |
437 | ||
438 | /** | |
439 | * iscsi_boot_create_kset() - creates root sysfs tree | |
440 | * @set_name: name of root dir | |
441 | */ | |
442 | struct iscsi_boot_kset *iscsi_boot_create_kset(const char *set_name) | |
443 | { | |
444 | struct iscsi_boot_kset *boot_kset; | |
445 | ||
446 | boot_kset = kzalloc(sizeof(*boot_kset), GFP_KERNEL); | |
447 | if (!boot_kset) | |
448 | return NULL; | |
449 | ||
450 | boot_kset->kset = kset_create_and_add(set_name, NULL, firmware_kobj); | |
451 | if (!boot_kset->kset) { | |
452 | kfree(boot_kset); | |
453 | return NULL; | |
454 | } | |
455 | ||
456 | INIT_LIST_HEAD(&boot_kset->kobj_list); | |
457 | return boot_kset; | |
458 | } | |
459 | EXPORT_SYMBOL_GPL(iscsi_boot_create_kset); | |
460 | ||
461 | /** | |
462 | * iscsi_boot_create_host_kset() - creates root sysfs tree for a scsi host | |
463 | * @hostno: host number of scsi host | |
464 | */ | |
465 | struct iscsi_boot_kset *iscsi_boot_create_host_kset(unsigned int hostno) | |
466 | { | |
467 | struct iscsi_boot_kset *boot_kset; | |
468 | char *set_name; | |
469 | ||
470 | set_name = kasprintf(GFP_KERNEL, "iscsi_boot%u", hostno); | |
471 | if (!set_name) | |
472 | return NULL; | |
473 | ||
474 | boot_kset = iscsi_boot_create_kset(set_name); | |
475 | kfree(set_name); | |
476 | return boot_kset; | |
477 | } | |
478 | EXPORT_SYMBOL_GPL(iscsi_boot_create_host_kset); | |
479 | ||
480 | /** | |
481 | * iscsi_boot_destroy_kset() - destroy kset and kobjects under it | |
482 | * @boot_kset: boot kset | |
483 | * | |
484 | * This will remove the kset and kobjects and attrs under it. | |
485 | */ | |
486 | void iscsi_boot_destroy_kset(struct iscsi_boot_kset *boot_kset) | |
487 | { | |
488 | struct iscsi_boot_kobj *boot_kobj, *tmp_kobj; | |
489 | ||
9d045163 MC |
490 | if (!boot_kset) |
491 | return; | |
492 | ||
ba4ee30c MC |
493 | list_for_each_entry_safe(boot_kobj, tmp_kobj, |
494 | &boot_kset->kobj_list, list) | |
495 | iscsi_boot_remove_kobj(boot_kobj); | |
496 | ||
497 | kset_unregister(boot_kset->kset); | |
9cb48e7b | 498 | kfree(boot_kset); |
ba4ee30c MC |
499 | } |
500 | EXPORT_SYMBOL_GPL(iscsi_boot_destroy_kset); |