[SCSI] iscsi_ibft, be2iscsi, iscsi_boot: fix boot kobj data lifetime management
be2iscsi passes the boot functions its phba object which is
allocated in the shost, but iscsi_ibft passes in a object
allocated for each item to display. The problem is that
iscsi_boot_sysfs was managing the lifetime of the object
passed in and doing a kfree on release. This causes a double
free for be2iscsi which frees the shost in its pci_remove.
This patch fixes the problem by adding a release callback
which the drivers can call kfree or a put() type of function
(needed for be2iscsi which will do a get/put on the shost).
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
diff --git a/drivers/scsi/iscsi_boot_sysfs.c b/drivers/scsi/iscsi_boot_sysfs.c
index 4274ce9..89700cb 100644
--- a/drivers/scsi/iscsi_boot_sysfs.c
+++ b/drivers/scsi/iscsi_boot_sysfs.c
@@ -64,7 +64,8 @@
struct iscsi_boot_kobj *boot_kobj =
container_of(kobj, struct iscsi_boot_kobj, kobj);
- kfree(boot_kobj->data);
+ if (boot_kobj->release)
+ boot_kobj->release(boot_kobj->data);
kfree(boot_kobj);
}
@@ -305,7 +306,8 @@
struct attribute_group *attr_group,
const char *name, int index, void *data,
ssize_t (*show) (void *data, int type, char *buf),
- mode_t (*is_visible) (void *data, int type))
+ mode_t (*is_visible) (void *data, int type),
+ void (*release) (void *data))
{
struct iscsi_boot_kobj *boot_kobj;
@@ -323,6 +325,7 @@
boot_kobj->data = data;
boot_kobj->show = show;
boot_kobj->is_visible = is_visible;
+ boot_kobj->release = release;
if (sysfs_create_group(&boot_kobj->kobj, attr_group)) {
/*
@@ -331,7 +334,7 @@
* the boot kobj was not setup and the normal release
* path is not being run.
*/
- boot_kobj->data = NULL;
+ boot_kobj->release = NULL;
kobject_put(&boot_kobj->kobj);
return NULL;
}
@@ -357,6 +360,7 @@
* @data: driver specific data for target
* @show: attr show function
* @is_visible: attr visibility function
+ * @release: release function
*
* Note: The boot sysfs lib will free the data passed in for the caller
* when all refs to the target kobject have been released.
@@ -365,10 +369,12 @@
iscsi_boot_create_target(struct iscsi_boot_kset *boot_kset, int index,
void *data,
ssize_t (*show) (void *data, int type, char *buf),
- mode_t (*is_visible) (void *data, int type))
+ mode_t (*is_visible) (void *data, int type),
+ void (*release) (void *data))
{
return iscsi_boot_create_kobj(boot_kset, &iscsi_boot_target_attr_group,
- "target%d", index, data, show, is_visible);
+ "target%d", index, data, show, is_visible,
+ release);
}
EXPORT_SYMBOL_GPL(iscsi_boot_create_target);
@@ -379,6 +385,7 @@
* @data: driver specific data
* @show: attr show function
* @is_visible: attr visibility function
+ * @release: release function
*
* Note: The boot sysfs lib will free the data passed in for the caller
* when all refs to the initiator kobject have been released.
@@ -387,12 +394,13 @@
iscsi_boot_create_initiator(struct iscsi_boot_kset *boot_kset, int index,
void *data,
ssize_t (*show) (void *data, int type, char *buf),
- mode_t (*is_visible) (void *data, int type))
+ mode_t (*is_visible) (void *data, int type),
+ void (*release) (void *data))
{
return iscsi_boot_create_kobj(boot_kset,
&iscsi_boot_initiator_attr_group,
"initiator", index, data, show,
- is_visible);
+ is_visible, release);
}
EXPORT_SYMBOL_GPL(iscsi_boot_create_initiator);
@@ -403,6 +411,7 @@
* @data: driver specific data
* @show: attr show function
* @is_visible: attr visibility function
+ * @release: release function
*
* Note: The boot sysfs lib will free the data passed in for the caller
* when all refs to the ethernet kobject have been released.
@@ -411,12 +420,13 @@
iscsi_boot_create_ethernet(struct iscsi_boot_kset *boot_kset, int index,
void *data,
ssize_t (*show) (void *data, int type, char *buf),
- mode_t (*is_visible) (void *data, int type))
+ mode_t (*is_visible) (void *data, int type),
+ void (*release) (void *data))
{
return iscsi_boot_create_kobj(boot_kset,
&iscsi_boot_ethernet_attr_group,
"ethernet%d", index, data, show,
- is_visible);
+ is_visible, release);
}
EXPORT_SYMBOL_GPL(iscsi_boot_create_ethernet);