diff options
| author | Mike Christie <michaelc@cs.wisc.edu> | 2011-06-24 16:11:53 -0400 |
|---|---|---|
| committer | James Bottomley <JBottomley@Parallels.com> | 2011-06-29 17:43:06 -0400 |
| commit | f457a46f179df41b0f6d80dee33b6e629945f276 (patch) | |
| tree | acbeac8630b898610fe71295f11cbc71f956b8ba | |
| parent | 9d04516310aaef3970c642a54531a52123001178 (diff) | |
[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>
| -rw-r--r-- | drivers/firmware/iscsi_ibft.c | 14 | ||||
| -rw-r--r-- | drivers/scsi/be2iscsi/be_main.c | 190 | ||||
| -rw-r--r-- | drivers/scsi/iscsi_boot_sysfs.c | 28 | ||||
| -rw-r--r-- | include/linux/iscsi_boot_sysfs.h | 16 |
4 files changed, 142 insertions, 106 deletions
diff --git a/drivers/firmware/iscsi_ibft.c b/drivers/firmware/iscsi_ibft.c index ce33f4626957..c811cb107904 100644 --- a/drivers/firmware/iscsi_ibft.c +++ b/drivers/firmware/iscsi_ibft.c | |||
| @@ -566,6 +566,11 @@ static mode_t __init ibft_check_initiator_for(void *data, int type) | |||
| 566 | return rc; | 566 | return rc; |
| 567 | } | 567 | } |
| 568 | 568 | ||
| 569 | static void ibft_kobj_release(void *data) | ||
| 570 | { | ||
| 571 | kfree(data); | ||
| 572 | } | ||
| 573 | |||
| 569 | /* | 574 | /* |
| 570 | * Helper function for ibft_register_kobjects. | 575 | * Helper function for ibft_register_kobjects. |
| 571 | */ | 576 | */ |
| @@ -595,7 +600,8 @@ static int __init ibft_create_kobject(struct acpi_table_ibft *header, | |||
| 595 | boot_kobj = iscsi_boot_create_initiator(boot_kset, hdr->index, | 600 | boot_kobj = iscsi_boot_create_initiator(boot_kset, hdr->index, |
| 596 | ibft_kobj, | 601 | ibft_kobj, |
| 597 | ibft_attr_show_initiator, | 602 | ibft_attr_show_initiator, |
| 598 | ibft_check_initiator_for); | 603 | ibft_check_initiator_for, |
| 604 | ibft_kobj_release); | ||
| 599 | if (!boot_kobj) { | 605 | if (!boot_kobj) { |
| 600 | rc = -ENOMEM; | 606 | rc = -ENOMEM; |
| 601 | goto free_ibft_obj; | 607 | goto free_ibft_obj; |
| @@ -610,7 +616,8 @@ static int __init ibft_create_kobject(struct acpi_table_ibft *header, | |||
| 610 | boot_kobj = iscsi_boot_create_ethernet(boot_kset, hdr->index, | 616 | boot_kobj = iscsi_boot_create_ethernet(boot_kset, hdr->index, |
| 611 | ibft_kobj, | 617 | ibft_kobj, |
| 612 | ibft_attr_show_nic, | 618 | ibft_attr_show_nic, |
| 613 | ibft_check_nic_for); | 619 | ibft_check_nic_for, |
| 620 | ibft_kobj_release); | ||
| 614 | if (!boot_kobj) { | 621 | if (!boot_kobj) { |
| 615 | rc = -ENOMEM; | 622 | rc = -ENOMEM; |
| 616 | goto free_ibft_obj; | 623 | goto free_ibft_obj; |
| @@ -625,7 +632,8 @@ static int __init ibft_create_kobject(struct acpi_table_ibft *header, | |||
| 625 | boot_kobj = iscsi_boot_create_target(boot_kset, hdr->index, | 632 | boot_kobj = iscsi_boot_create_target(boot_kset, hdr->index, |
| 626 | ibft_kobj, | 633 | ibft_kobj, |
| 627 | ibft_attr_show_target, | 634 | ibft_attr_show_target, |
| 628 | ibft_check_tgt_for); | 635 | ibft_check_tgt_for, |
| 636 | ibft_kobj_release); | ||
| 629 | if (!boot_kobj) { | 637 | if (!boot_kobj) { |
| 630 | rc = -ENOMEM; | 638 | rc = -ENOMEM; |
| 631 | goto free_ibft_obj; | 639 | goto free_ibft_obj; |
diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 2e214390c63b..0a9bdfa3d939 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c | |||
| @@ -215,73 +215,62 @@ unlock: | |||
| 215 | static ssize_t beiscsi_show_boot_tgt_info(void *data, int type, char *buf) | 215 | static ssize_t beiscsi_show_boot_tgt_info(void *data, int type, char *buf) |
| 216 | { | 216 | { |
| 217 | struct beiscsi_hba *phba = data; | 217 | struct beiscsi_hba *phba = data; |
| 218 | struct mgmt_session_info *boot_sess = &phba->boot_sess; | ||
| 219 | struct mgmt_conn_info *boot_conn = &boot_sess->conn_list[0]; | ||
| 218 | char *str = buf; | 220 | char *str = buf; |
| 219 | int rc; | 221 | int rc; |
| 220 | 222 | ||
| 221 | switch (type) { | 223 | switch (type) { |
| 222 | case ISCSI_BOOT_TGT_NAME: | 224 | case ISCSI_BOOT_TGT_NAME: |
| 223 | rc = sprintf(buf, "%.*s\n", | 225 | rc = sprintf(buf, "%.*s\n", |
| 224 | (int)strlen(phba->boot_sess.target_name), | 226 | (int)strlen(boot_sess->target_name), |
| 225 | (char *)&phba->boot_sess.target_name); | 227 | (char *)&boot_sess->target_name); |
| 226 | break; | 228 | break; |
| 227 | case ISCSI_BOOT_TGT_IP_ADDR: | 229 | case ISCSI_BOOT_TGT_IP_ADDR: |
| 228 | if (phba->boot_sess.conn_list[0].dest_ipaddr.ip_type == 0x1) | 230 | if (boot_conn->dest_ipaddr.ip_type == 0x1) |
| 229 | rc = sprintf(buf, "%pI4\n", | 231 | rc = sprintf(buf, "%pI4\n", |
| 230 | (char *)&phba->boot_sess.conn_list[0]. | 232 | (char *)&boot_conn->dest_ipaddr.ip_address); |
| 231 | dest_ipaddr.ip_address); | ||
| 232 | else | 233 | else |
| 233 | rc = sprintf(str, "%pI6\n", | 234 | rc = sprintf(str, "%pI6\n", |
| 234 | (char *)&phba->boot_sess.conn_list[0]. | 235 | (char *)&boot_conn->dest_ipaddr.ip_address); |
| 235 | dest_ipaddr.ip_address); | ||
| 236 | break; | 236 | break; |
| 237 | case ISCSI_BOOT_TGT_PORT: | 237 | case ISCSI_BOOT_TGT_PORT: |
| 238 | rc = sprintf(str, "%d\n", phba->boot_sess.conn_list[0]. | 238 | rc = sprintf(str, "%d\n", boot_conn->dest_port); |
| 239 | dest_port); | ||
| 240 | break; | 239 | break; |
| 241 | 240 | ||
| 242 | case ISCSI_BOOT_TGT_CHAP_NAME: | 241 | case ISCSI_BOOT_TGT_CHAP_NAME: |
| 243 | rc = sprintf(str, "%.*s\n", | 242 | rc = sprintf(str, "%.*s\n", |
| 244 | phba->boot_sess.conn_list[0]. | 243 | boot_conn->negotiated_login_options.auth_data.chap. |
| 245 | negotiated_login_options.auth_data.chap. | 244 | target_chap_name_length, |
| 246 | target_chap_name_length, | 245 | (char *)&boot_conn->negotiated_login_options. |
| 247 | (char *)&phba->boot_sess.conn_list[0]. | 246 | auth_data.chap.target_chap_name); |
| 248 | negotiated_login_options.auth_data.chap. | ||
| 249 | target_chap_name); | ||
| 250 | break; | 247 | break; |
| 251 | case ISCSI_BOOT_TGT_CHAP_SECRET: | 248 | case ISCSI_BOOT_TGT_CHAP_SECRET: |
| 252 | rc = sprintf(str, "%.*s\n", | 249 | rc = sprintf(str, "%.*s\n", |
| 253 | phba->boot_sess.conn_list[0]. | 250 | boot_conn->negotiated_login_options.auth_data.chap. |
| 254 | negotiated_login_options.auth_data.chap. | 251 | target_secret_length, |
| 255 | target_secret_length, | 252 | (char *)&boot_conn->negotiated_login_options. |
| 256 | (char *)&phba->boot_sess.conn_list[0]. | 253 | auth_data.chap.target_secret); |
| 257 | negotiated_login_options.auth_data.chap. | ||
| 258 | target_secret); | ||
| 259 | |||
| 260 | break; | 254 | break; |
| 261 | case ISCSI_BOOT_TGT_REV_CHAP_NAME: | 255 | case ISCSI_BOOT_TGT_REV_CHAP_NAME: |
| 262 | rc = sprintf(str, "%.*s\n", | 256 | rc = sprintf(str, "%.*s\n", |
| 263 | phba->boot_sess.conn_list[0]. | 257 | boot_conn->negotiated_login_options.auth_data.chap. |
| 264 | negotiated_login_options.auth_data.chap. | 258 | intr_chap_name_length, |
| 265 | intr_chap_name_length, | 259 | (char *)&boot_conn->negotiated_login_options. |
| 266 | (char *)&phba->boot_sess.conn_list[0]. | 260 | auth_data.chap.intr_chap_name); |
| 267 | negotiated_login_options.auth_data.chap. | ||
| 268 | intr_chap_name); | ||
| 269 | |||
| 270 | break; | 261 | break; |
| 271 | case ISCSI_BOOT_TGT_REV_CHAP_SECRET: | 262 | case ISCSI_BOOT_TGT_REV_CHAP_SECRET: |
| 272 | rc = sprintf(str, "%.*s\n", | 263 | rc = sprintf(str, "%.*s\n", |
| 273 | phba->boot_sess.conn_list[0]. | 264 | boot_conn->negotiated_login_options.auth_data.chap. |
| 274 | negotiated_login_options.auth_data.chap. | 265 | intr_secret_length, |
| 275 | intr_secret_length, | 266 | (char *)&boot_conn->negotiated_login_options. |
| 276 | (char *)&phba->boot_sess.conn_list[0]. | 267 | auth_data.chap.intr_secret); |
| 277 | negotiated_login_options.auth_data.chap. | ||
| 278 | intr_secret); | ||
| 279 | break; | 268 | break; |
| 280 | case ISCSI_BOOT_TGT_FLAGS: | 269 | case ISCSI_BOOT_TGT_FLAGS: |
| 281 | rc = sprintf(str, "2\n"); | 270 | rc = sprintf(str, "2\n"); |
| 282 | break; | 271 | break; |
| 283 | case ISCSI_BOOT_TGT_NIC_ASSOC: | 272 | case ISCSI_BOOT_TGT_NIC_ASSOC: |
| 284 | rc = sprintf(str, "0\n"); | 273 | rc = sprintf(str, "0\n"); |
| 285 | break; | 274 | break; |
| 286 | default: | 275 | default: |
| 287 | rc = -ENOSYS; | 276 | rc = -ENOSYS; |
| @@ -315,10 +304,10 @@ static ssize_t beiscsi_show_boot_eth_info(void *data, int type, char *buf) | |||
| 315 | 304 | ||
| 316 | switch (type) { | 305 | switch (type) { |
| 317 | case ISCSI_BOOT_ETH_FLAGS: | 306 | case ISCSI_BOOT_ETH_FLAGS: |
| 318 | rc = sprintf(str, "2\n"); | 307 | rc = sprintf(str, "2\n"); |
| 319 | break; | 308 | break; |
| 320 | case ISCSI_BOOT_ETH_INDEX: | 309 | case ISCSI_BOOT_ETH_INDEX: |
| 321 | rc = sprintf(str, "0\n"); | 310 | rc = sprintf(str, "0\n"); |
| 322 | break; | 311 | break; |
| 323 | case ISCSI_BOOT_ETH_MAC: | 312 | case ISCSI_BOOT_ETH_MAC: |
| 324 | rc = beiscsi_get_macaddr(buf, phba); | 313 | rc = beiscsi_get_macaddr(buf, phba); |
| @@ -391,39 +380,6 @@ static mode_t beiscsi_eth_get_attr_visibility(void *data, int type) | |||
| 391 | return rc; | 380 | return rc; |
| 392 | } | 381 | } |
| 393 | 382 | ||
| 394 | static int beiscsi_setup_boot_info(struct beiscsi_hba *phba) | ||
| 395 | { | ||
| 396 | struct iscsi_boot_kobj *boot_kobj; | ||
| 397 | |||
| 398 | phba->boot_kset = iscsi_boot_create_host_kset(phba->shost->host_no); | ||
| 399 | if (!phba->boot_kset) | ||
| 400 | return -ENOMEM; | ||
| 401 | |||
| 402 | /* get boot info using mgmt cmd */ | ||
| 403 | boot_kobj = iscsi_boot_create_target(phba->boot_kset, 0, phba, | ||
| 404 | beiscsi_show_boot_tgt_info, | ||
| 405 | beiscsi_tgt_get_attr_visibility); | ||
| 406 | if (!boot_kobj) | ||
| 407 | goto free_kset; | ||
| 408 | |||
| 409 | boot_kobj = iscsi_boot_create_initiator(phba->boot_kset, 0, phba, | ||
| 410 | beiscsi_show_boot_ini_info, | ||
| 411 | beiscsi_ini_get_attr_visibility); | ||
| 412 | if (!boot_kobj) | ||
| 413 | goto free_kset; | ||
| 414 | |||
| 415 | boot_kobj = iscsi_boot_create_ethernet(phba->boot_kset, 0, phba, | ||
| 416 | beiscsi_show_boot_eth_info, | ||
| 417 | beiscsi_eth_get_attr_visibility); | ||
| 418 | if (!boot_kobj) | ||
| 419 | goto free_kset; | ||
| 420 | return 0; | ||
| 421 | |||
| 422 | free_kset: | ||
| 423 | iscsi_boot_destroy_kset(phba->boot_kset); | ||
| 424 | return -ENOMEM; | ||
| 425 | } | ||
| 426 | |||
| 427 | /*------------------- PCI Driver operations and data ----------------- */ | 383 | /*------------------- PCI Driver operations and data ----------------- */ |
| 428 | static DEFINE_PCI_DEVICE_TABLE(beiscsi_pci_id_table) = { | 384 | static DEFINE_PCI_DEVICE_TABLE(beiscsi_pci_id_table) = { |
| 429 | { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID1) }, | 385 | { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID1) }, |
| @@ -482,14 +438,6 @@ static struct beiscsi_hba *beiscsi_hba_alloc(struct pci_dev *pcidev) | |||
| 482 | if (iscsi_host_add(shost, &phba->pcidev->dev)) | 438 | if (iscsi_host_add(shost, &phba->pcidev->dev)) |
| 483 | goto free_devices; | 439 | goto free_devices; |
| 484 | 440 | ||
| 485 | if (beiscsi_setup_boot_info(phba)) | ||
| 486 | /* | ||
| 487 | * log error but continue, because we may not be using | ||
| 488 | * iscsi boot. | ||
| 489 | */ | ||
| 490 | shost_printk(KERN_ERR, phba->shost, "Could not set up " | ||
| 491 | "iSCSI boot info."); | ||
| 492 | |||
| 493 | return phba; | 441 | return phba; |
| 494 | 442 | ||
| 495 | free_devices: | 443 | free_devices: |
| @@ -3510,6 +3458,7 @@ static int beiscsi_get_boot_info(struct beiscsi_hba *phba) | |||
| 3510 | unsigned int tag, wrb_num; | 3458 | unsigned int tag, wrb_num; |
| 3511 | unsigned short status, extd_status; | 3459 | unsigned short status, extd_status; |
| 3512 | struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; | 3460 | struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; |
| 3461 | int ret = -ENOMEM; | ||
| 3513 | 3462 | ||
| 3514 | tag = beiscsi_get_boot_target(phba); | 3463 | tag = beiscsi_get_boot_target(phba); |
| 3515 | if (!tag) { | 3464 | if (!tag) { |
| @@ -3534,8 +3483,7 @@ static int beiscsi_get_boot_info(struct beiscsi_hba *phba) | |||
| 3534 | boot_resp = embedded_payload(wrb); | 3483 | boot_resp = embedded_payload(wrb); |
| 3535 | 3484 | ||
| 3536 | if (boot_resp->boot_session_handle < 0) { | 3485 | if (boot_resp->boot_session_handle < 0) { |
| 3537 | printk(KERN_ERR "No Boot Session for this pci_func," | 3486 | shost_printk(KERN_INFO, phba->shost, "No Boot Session.\n"); |
| 3538 | "session Hndl = %d\n", boot_resp->boot_session_handle); | ||
| 3539 | return -ENXIO; | 3487 | return -ENXIO; |
| 3540 | } | 3488 | } |
| 3541 | 3489 | ||
| @@ -3573,14 +3521,70 @@ static int beiscsi_get_boot_info(struct beiscsi_hba *phba) | |||
| 3573 | wrb = queue_get_wrb(mccq, wrb_num); | 3521 | wrb = queue_get_wrb(mccq, wrb_num); |
| 3574 | free_mcc_tag(&phba->ctrl, tag); | 3522 | free_mcc_tag(&phba->ctrl, tag); |
| 3575 | session_resp = nonemb_cmd.va ; | 3523 | session_resp = nonemb_cmd.va ; |
| 3524 | |||
| 3576 | memcpy(&phba->boot_sess, &session_resp->session_info, | 3525 | memcpy(&phba->boot_sess, &session_resp->session_info, |
| 3577 | sizeof(struct mgmt_session_info)); | 3526 | sizeof(struct mgmt_session_info)); |
| 3578 | pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, | 3527 | ret = 0; |
| 3579 | nonemb_cmd.va, nonemb_cmd.dma); | 3528 | |
| 3580 | return 0; | ||
| 3581 | boot_freemem: | 3529 | boot_freemem: |
| 3582 | pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, | 3530 | pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, |
| 3583 | nonemb_cmd.va, nonemb_cmd.dma); | 3531 | nonemb_cmd.va, nonemb_cmd.dma); |
| 3532 | return ret; | ||
| 3533 | } | ||
| 3534 | |||
| 3535 | static void beiscsi_boot_release(void *data) | ||
| 3536 | { | ||
| 3537 | struct beiscsi_hba *phba = data; | ||
| 3538 | |||
| 3539 | scsi_host_put(phba->shost); | ||
| 3540 | } | ||
| 3541 | |||
| 3542 | static int beiscsi_setup_boot_info(struct beiscsi_hba *phba) | ||
| 3543 | { | ||
| 3544 | struct iscsi_boot_kobj *boot_kobj; | ||
| 3545 | |||
| 3546 | /* get boot info using mgmt cmd */ | ||
| 3547 | if (beiscsi_get_boot_info(phba)) | ||
| 3548 | /* Try to see if we can carry on without this */ | ||
| 3549 | return 0; | ||
| 3550 | |||
| 3551 | phba->boot_kset = iscsi_boot_create_host_kset(phba->shost->host_no); | ||
| 3552 | if (!phba->boot_kset) | ||
| 3553 | return -ENOMEM; | ||
| 3554 | |||
| 3555 | /* get a ref because the show function will ref the phba */ | ||
| 3556 | if (!scsi_host_get(phba->shost)) | ||
| 3557 | goto free_kset; | ||
| 3558 | boot_kobj = iscsi_boot_create_target(phba->boot_kset, 0, phba, | ||
| 3559 | beiscsi_show_boot_tgt_info, | ||
| 3560 | beiscsi_tgt_get_attr_visibility, | ||
| 3561 | beiscsi_boot_release); | ||
| 3562 | if (!boot_kobj) | ||
| 3563 | goto put_shost; | ||
| 3564 | |||
| 3565 | if (!scsi_host_get(phba->shost)) | ||
| 3566 | goto free_kset; | ||
| 3567 | boot_kobj = iscsi_boot_create_initiator(phba->boot_kset, 0, phba, | ||
| 3568 | beiscsi_show_boot_ini_info, | ||
| 3569 | beiscsi_ini_get_attr_visibility, | ||
| 3570 | beiscsi_boot_release); | ||
| 3571 | if (!boot_kobj) | ||
| 3572 | goto put_shost; | ||
| 3573 | |||
| 3574 | if (!scsi_host_get(phba->shost)) | ||
| 3575 | goto free_kset; | ||
| 3576 | boot_kobj = iscsi_boot_create_ethernet(phba->boot_kset, 0, phba, | ||
| 3577 | beiscsi_show_boot_eth_info, | ||
| 3578 | beiscsi_eth_get_attr_visibility, | ||
| 3579 | beiscsi_boot_release); | ||
| 3580 | if (!boot_kobj) | ||
| 3581 | goto put_shost; | ||
| 3582 | return 0; | ||
| 3583 | |||
| 3584 | put_shost: | ||
| 3585 | scsi_host_put(phba->shost); | ||
| 3586 | free_kset: | ||
| 3587 | iscsi_boot_destroy_kset(phba->boot_kset); | ||
| 3584 | return -ENOMEM; | 3588 | return -ENOMEM; |
| 3585 | } | 3589 | } |
| 3586 | 3590 | ||
| @@ -4307,11 +4311,15 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev, | |||
| 4307 | goto free_blkenbld; | 4311 | goto free_blkenbld; |
| 4308 | } | 4312 | } |
| 4309 | hwi_enable_intr(phba); | 4313 | hwi_enable_intr(phba); |
| 4310 | ret = beiscsi_get_boot_info(phba); | 4314 | |
| 4311 | if (ret < 0) { | 4315 | if (beiscsi_setup_boot_info(phba)) |
| 4312 | shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-" | 4316 | /* |
| 4313 | "No Boot Devices !!!!!\n"); | 4317 | * log error but continue, because we may not be using |
| 4314 | } | 4318 | * iscsi boot. |
| 4319 | */ | ||
| 4320 | shost_printk(KERN_ERR, phba->shost, "Could not set up " | ||
| 4321 | "iSCSI boot info."); | ||
| 4322 | |||
| 4315 | SE_DEBUG(DBG_LVL_8, "\n\n\n SUCCESS - DRIVER LOADED\n\n\n"); | 4323 | SE_DEBUG(DBG_LVL_8, "\n\n\n SUCCESS - DRIVER LOADED\n\n\n"); |
| 4316 | return 0; | 4324 | return 0; |
| 4317 | 4325 | ||
diff --git a/drivers/scsi/iscsi_boot_sysfs.c b/drivers/scsi/iscsi_boot_sysfs.c index 4274ce93d8f2..89700cbca16e 100644 --- a/drivers/scsi/iscsi_boot_sysfs.c +++ b/drivers/scsi/iscsi_boot_sysfs.c | |||
| @@ -64,7 +64,8 @@ static void iscsi_boot_kobj_release(struct kobject *kobj) | |||
| 64 | struct iscsi_boot_kobj *boot_kobj = | 64 | struct iscsi_boot_kobj *boot_kobj = |
| 65 | container_of(kobj, struct iscsi_boot_kobj, kobj); | 65 | container_of(kobj, struct iscsi_boot_kobj, kobj); |
| 66 | 66 | ||
| 67 | kfree(boot_kobj->data); | 67 | if (boot_kobj->release) |
| 68 | boot_kobj->release(boot_kobj->data); | ||
| 68 | kfree(boot_kobj); | 69 | kfree(boot_kobj); |
| 69 | } | 70 | } |
| 70 | 71 | ||
| @@ -305,7 +306,8 @@ iscsi_boot_create_kobj(struct iscsi_boot_kset *boot_kset, | |||
| 305 | struct attribute_group *attr_group, | 306 | struct attribute_group *attr_group, |
| 306 | const char *name, int index, void *data, | 307 | const char *name, int index, void *data, |
| 307 | ssize_t (*show) (void *data, int type, char *buf), | 308 | ssize_t (*show) (void *data, int type, char *buf), |
| 308 | mode_t (*is_visible) (void *data, int type)) | 309 | mode_t (*is_visible) (void *data, int type), |
| 310 | void (*release) (void *data)) | ||
| 309 | { | 311 | { |
| 310 | struct iscsi_boot_kobj *boot_kobj; | 312 | struct iscsi_boot_kobj *boot_kobj; |
| 311 | 313 | ||
| @@ -323,6 +325,7 @@ iscsi_boot_create_kobj(struct iscsi_boot_kset *boot_kset, | |||
| 323 | boot_kobj->data = data; | 325 | boot_kobj->data = data; |
| 324 | boot_kobj->show = show; | 326 | boot_kobj->show = show; |
| 325 | boot_kobj->is_visible = is_visible; | 327 | boot_kobj->is_visible = is_visible; |
| 328 | boot_kobj->release = release; | ||
| 326 | 329 | ||
| 327 | if (sysfs_create_group(&boot_kobj->kobj, attr_group)) { | 330 | if (sysfs_create_group(&boot_kobj->kobj, attr_group)) { |
| 328 | /* | 331 | /* |
| @@ -331,7 +334,7 @@ iscsi_boot_create_kobj(struct iscsi_boot_kset *boot_kset, | |||
| 331 | * the boot kobj was not setup and the normal release | 334 | * the boot kobj was not setup and the normal release |
| 332 | * path is not being run. | 335 | * path is not being run. |
| 333 | */ | 336 | */ |
| 334 | boot_kobj->data = NULL; | 337 | boot_kobj->release = NULL; |
| 335 | kobject_put(&boot_kobj->kobj); | 338 | kobject_put(&boot_kobj->kobj); |
| 336 | return NULL; | 339 | return NULL; |
| 337 | } | 340 | } |
| @@ -357,6 +360,7 @@ static void iscsi_boot_remove_kobj(struct iscsi_boot_kobj *boot_kobj) | |||
| 357 | * @data: driver specific data for target | 360 | * @data: driver specific data for target |
| 358 | * @show: attr show function | 361 | * @show: attr show function |
| 359 | * @is_visible: attr visibility function | 362 | * @is_visible: attr visibility function |
| 363 | * @release: release function | ||
| 360 | * | 364 | * |
| 361 | * Note: The boot sysfs lib will free the data passed in for the caller | 365 | * Note: The boot sysfs lib will free the data passed in for the caller |
| 362 | * when all refs to the target kobject have been released. | 366 | * when all refs to the target kobject have been released. |
| @@ -365,10 +369,12 @@ struct iscsi_boot_kobj * | |||
| 365 | iscsi_boot_create_target(struct iscsi_boot_kset *boot_kset, int index, | 369 | iscsi_boot_create_target(struct iscsi_boot_kset *boot_kset, int index, |
| 366 | void *data, | 370 | void *data, |
| 367 | ssize_t (*show) (void *data, int type, char *buf), | 371 | ssize_t (*show) (void *data, int type, char *buf), |
| 368 | mode_t (*is_visible) (void *data, int type)) | 372 | mode_t (*is_visible) (void *data, int type), |
| 373 | void (*release) (void *data)) | ||
| 369 | { | 374 | { |
| 370 | return iscsi_boot_create_kobj(boot_kset, &iscsi_boot_target_attr_group, | 375 | return iscsi_boot_create_kobj(boot_kset, &iscsi_boot_target_attr_group, |
| 371 | "target%d", index, data, show, is_visible); | 376 | "target%d", index, data, show, is_visible, |
| 377 | release); | ||
| 372 | } | 378 | } |
| 373 | EXPORT_SYMBOL_GPL(iscsi_boot_create_target); | 379 | EXPORT_SYMBOL_GPL(iscsi_boot_create_target); |
| 374 | 380 | ||
| @@ -379,6 +385,7 @@ EXPORT_SYMBOL_GPL(iscsi_boot_create_target); | |||
| 379 | * @data: driver specific data | 385 | * @data: driver specific data |
| 380 | * @show: attr show function | 386 | * @show: attr show function |
| 381 | * @is_visible: attr visibility function | 387 | * @is_visible: attr visibility function |
| 388 | * @release: release function | ||
| 382 | * | 389 | * |
| 383 | * Note: The boot sysfs lib will free the data passed in for the caller | 390 | * Note: The boot sysfs lib will free the data passed in for the caller |
| 384 | * when all refs to the initiator kobject have been released. | 391 | * when all refs to the initiator kobject have been released. |
| @@ -387,12 +394,13 @@ struct iscsi_boot_kobj * | |||
| 387 | iscsi_boot_create_initiator(struct iscsi_boot_kset *boot_kset, int index, | 394 | iscsi_boot_create_initiator(struct iscsi_boot_kset *boot_kset, int index, |
| 388 | void *data, | 395 | void *data, |
| 389 | ssize_t (*show) (void *data, int type, char *buf), | 396 | ssize_t (*show) (void *data, int type, char *buf), |
| 390 | mode_t (*is_visible) (void *data, int type)) | 397 | mode_t (*is_visible) (void *data, int type), |
| 398 | void (*release) (void *data)) | ||
| 391 | { | 399 | { |
| 392 | return iscsi_boot_create_kobj(boot_kset, | 400 | return iscsi_boot_create_kobj(boot_kset, |
| 393 | &iscsi_boot_initiator_attr_group, | 401 | &iscsi_boot_initiator_attr_group, |
| 394 | "initiator", index, data, show, | 402 | "initiator", index, data, show, |
| 395 | is_visible); | 403 | is_visible, release); |
| 396 | } | 404 | } |
| 397 | EXPORT_SYMBOL_GPL(iscsi_boot_create_initiator); | 405 | EXPORT_SYMBOL_GPL(iscsi_boot_create_initiator); |
| 398 | 406 | ||
| @@ -403,6 +411,7 @@ EXPORT_SYMBOL_GPL(iscsi_boot_create_initiator); | |||
| 403 | * @data: driver specific data | 411 | * @data: driver specific data |
| 404 | * @show: attr show function | 412 | * @show: attr show function |
| 405 | * @is_visible: attr visibility function | 413 | * @is_visible: attr visibility function |
| 414 | * @release: release function | ||
| 406 | * | 415 | * |
| 407 | * Note: The boot sysfs lib will free the data passed in for the caller | 416 | * Note: The boot sysfs lib will free the data passed in for the caller |
| 408 | * when all refs to the ethernet kobject have been released. | 417 | * when all refs to the ethernet kobject have been released. |
| @@ -411,12 +420,13 @@ struct iscsi_boot_kobj * | |||
| 411 | iscsi_boot_create_ethernet(struct iscsi_boot_kset *boot_kset, int index, | 420 | iscsi_boot_create_ethernet(struct iscsi_boot_kset *boot_kset, int index, |
| 412 | void *data, | 421 | void *data, |
| 413 | ssize_t (*show) (void *data, int type, char *buf), | 422 | ssize_t (*show) (void *data, int type, char *buf), |
| 414 | mode_t (*is_visible) (void *data, int type)) | 423 | mode_t (*is_visible) (void *data, int type), |
| 424 | void (*release) (void *data)) | ||
| 415 | { | 425 | { |
| 416 | return iscsi_boot_create_kobj(boot_kset, | 426 | return iscsi_boot_create_kobj(boot_kset, |
| 417 | &iscsi_boot_ethernet_attr_group, | 427 | &iscsi_boot_ethernet_attr_group, |
| 418 | "ethernet%d", index, data, show, | 428 | "ethernet%d", index, data, show, |
| 419 | is_visible); | 429 | is_visible, release); |
| 420 | } | 430 | } |
| 421 | EXPORT_SYMBOL_GPL(iscsi_boot_create_ethernet); | 431 | EXPORT_SYMBOL_GPL(iscsi_boot_create_ethernet); |
| 422 | 432 | ||
diff --git a/include/linux/iscsi_boot_sysfs.h b/include/linux/iscsi_boot_sysfs.h index f1e6c184f14f..f0a2f8b0aa13 100644 --- a/include/linux/iscsi_boot_sysfs.h +++ b/include/linux/iscsi_boot_sysfs.h | |||
| @@ -92,6 +92,13 @@ struct iscsi_boot_kobj { | |||
| 92 | * properties. | 92 | * properties. |
| 93 | */ | 93 | */ |
| 94 | mode_t (*is_visible) (void *data, int type); | 94 | mode_t (*is_visible) (void *data, int type); |
| 95 | |||
| 96 | /* | ||
| 97 | * Driver specific release function. | ||
| 98 | * | ||
| 99 | * The function should free the data passed in. | ||
| 100 | */ | ||
| 101 | void (*release) (void *data); | ||
| 95 | }; | 102 | }; |
| 96 | 103 | ||
| 97 | struct iscsi_boot_kset { | 104 | struct iscsi_boot_kset { |
| @@ -103,18 +110,21 @@ struct iscsi_boot_kobj * | |||
| 103 | iscsi_boot_create_initiator(struct iscsi_boot_kset *boot_kset, int index, | 110 | iscsi_boot_create_initiator(struct iscsi_boot_kset *boot_kset, int index, |
| 104 | void *data, | 111 | void *data, |
| 105 | ssize_t (*show) (void *data, int type, char *buf), | 112 | ssize_t (*show) (void *data, int type, char *buf), |
| 106 | mode_t (*is_visible) (void *data, int type)); | 113 | mode_t (*is_visible) (void *data, int type), |
| 114 | void (*release) (void *data)); | ||
| 107 | 115 | ||
| 108 | struct iscsi_boot_kobj * | 116 | struct iscsi_boot_kobj * |
| 109 | iscsi_boot_create_ethernet(struct iscsi_boot_kset *boot_kset, int index, | 117 | iscsi_boot_create_ethernet(struct iscsi_boot_kset *boot_kset, int index, |
| 110 | void *data, | 118 | void *data, |
| 111 | ssize_t (*show) (void *data, int type, char *buf), | 119 | ssize_t (*show) (void *data, int type, char *buf), |
| 112 | mode_t (*is_visible) (void *data, int type)); | 120 | mode_t (*is_visible) (void *data, int type), |
| 121 | void (*release) (void *data)); | ||
| 113 | struct iscsi_boot_kobj * | 122 | struct iscsi_boot_kobj * |
| 114 | iscsi_boot_create_target(struct iscsi_boot_kset *boot_kset, int index, | 123 | iscsi_boot_create_target(struct iscsi_boot_kset *boot_kset, int index, |
| 115 | void *data, | 124 | void *data, |
| 116 | ssize_t (*show) (void *data, int type, char *buf), | 125 | ssize_t (*show) (void *data, int type, char *buf), |
| 117 | mode_t (*is_visible) (void *data, int type)); | 126 | mode_t (*is_visible) (void *data, int type), |
| 127 | void (*release) (void *data)); | ||
| 118 | 128 | ||
| 119 | struct iscsi_boot_kset *iscsi_boot_create_kset(const char *set_name); | 129 | struct iscsi_boot_kset *iscsi_boot_create_kset(const char *set_name); |
| 120 | struct iscsi_boot_kset *iscsi_boot_create_host_kset(unsigned int hostno); | 130 | struct iscsi_boot_kset *iscsi_boot_create_host_kset(unsigned int hostno); |
