brintos

brintos / linux-shallow public Read only

0
0
Text · 18.2 KiB · a64abe3 Raw
555 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*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 Christie7 */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	NULL105};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	NULL188};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	NULL263};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	NULL312};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 caller366		 * will assume that since the creation call failed367		 * the boot kobj was not setup and the normal release368		 * 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 dir391 * @boot_kset: boot kset392 * @index: the target id393 * @data: driver specific data for target394 * @show: attr show function395 * @is_visible: attr visibility function396 * @release: release function397 *398 * Note: The boot sysfs lib will free the data passed in for the caller399 * 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 dir416 * @boot_kset: boot kset417 * @index: the initiator id418 * @data: driver specific data419 * @show: attr show function420 * @is_visible: attr visibility function421 * @release: release function422 *423 * Note: The boot sysfs lib will free the data passed in for the caller424 * 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 dir442 * @boot_kset: boot kset443 * @index: the ethernet device id444 * @data: driver specific data445 * @show: attr show function446 * @is_visible: attr visibility function447 * @release: release function448 *449 * Note: The boot sysfs lib will free the data passed in for the caller450 * 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 dir468 * @boot_kset: boot kset469 * @index: not used470 * @data: driver specific data471 * @show: attr show function472 * @is_visible: attr visibility function473 * @release: release function474 *475 * Note: The boot sysfs lib will free the data passed in for the caller476 * 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 tree494 * @set_name: name of root dir495 */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 host517 * @hostno: host number of scsi host518 */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 it536 * @boot_kset: boot kset537 *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);555