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