diff options
author | Mike Christie <michaelc@cs.wisc.edu> | 2010-06-09 04:30:08 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-07-27 13:01:39 -0400 |
commit | fa95d206e4a4fb549bdb9fe71091417f4912178f (patch) | |
tree | 1d4adc8b1e38b5b9d0dc836d00c8322631f426eb /drivers/scsi/be2iscsi/be_iscsi.c | |
parent | 2cae179486a356aca2a2617f0399f04c66598d8b (diff) |
[SCSI] be2iscsi: fix disconnection cleanup
This patch fixes 4 bugs in the connection connect/disconnect
cleanup path.
1. If beiscsi_open_conn fails beiscsi_free_ep was always being
called, and if beiscsi_open_conn failed because beiscsi_get_cid
failed then we would free an unallocated cid.
2. If beiscsi_ep_connect failed due to a beiscsi_open_conn failure
it was leaking iscsi_endpoints.
3. beiscsi_ep_disconnect was leaking iscsi_endpoints.
beiscsi_ep_disconnect should free the iscsi_endpoint. We cannot
do it in beiscsi_conn_stop because that is only called for
iscsi connection cleanup. If beiscsi_ep_connect returns
success, but then the poll function fails or the connect
times out then beiscsi_ep_disconnect will be called to clean
up the ep. The conn_stop callout will not be called in that path.
4. beiscsi_conn_stop was freeing the iscsi_endpoint then accessing
it a couple lines later.
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/be2iscsi/be_iscsi.c')
-rw-r--r-- | drivers/scsi/be2iscsi/be_iscsi.c | 123 |
1 files changed, 55 insertions, 68 deletions
diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index c3928cb8b042..454027ccbf16 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c | |||
@@ -442,6 +442,31 @@ static int beiscsi_get_cid(struct beiscsi_hba *phba) | |||
442 | } | 442 | } |
443 | 443 | ||
444 | /** | 444 | /** |
445 | * beiscsi_put_cid - Free the cid | ||
446 | * @phba: The phba for which the cid is being freed | ||
447 | * @cid: The cid to free | ||
448 | */ | ||
449 | static void beiscsi_put_cid(struct beiscsi_hba *phba, unsigned short cid) | ||
450 | { | ||
451 | phba->avlbl_cids++; | ||
452 | phba->cid_array[phba->cid_free++] = cid; | ||
453 | if (phba->cid_free == phba->params.cxns_per_ctrl) | ||
454 | phba->cid_free = 0; | ||
455 | } | ||
456 | |||
457 | /** | ||
458 | * beiscsi_free_ep - free endpoint | ||
459 | * @ep: pointer to iscsi endpoint structure | ||
460 | */ | ||
461 | static void beiscsi_free_ep(struct beiscsi_endpoint *beiscsi_ep) | ||
462 | { | ||
463 | struct beiscsi_hba *phba = beiscsi_ep->phba; | ||
464 | |||
465 | beiscsi_put_cid(phba, beiscsi_ep->ep_cid); | ||
466 | beiscsi_ep->phba = NULL; | ||
467 | } | ||
468 | |||
469 | /** | ||
445 | * beiscsi_open_conn - Ask FW to open a TCP connection | 470 | * beiscsi_open_conn - Ask FW to open a TCP connection |
446 | * @ep: endpoint to be used | 471 | * @ep: endpoint to be used |
447 | * @src_addr: The source IP address | 472 | * @src_addr: The source IP address |
@@ -475,7 +500,7 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep, | |||
475 | if (beiscsi_ep->ep_cid > (phba->fw_config.iscsi_cid_start + | 500 | if (beiscsi_ep->ep_cid > (phba->fw_config.iscsi_cid_start + |
476 | phba->params.cxns_per_ctrl * 2)) { | 501 | phba->params.cxns_per_ctrl * 2)) { |
477 | SE_DEBUG(DBG_LVL_1, "Failed in allocate iscsi cid\n"); | 502 | SE_DEBUG(DBG_LVL_1, "Failed in allocate iscsi cid\n"); |
478 | return ret; | 503 | goto free_ep; |
479 | } | 504 | } |
480 | 505 | ||
481 | beiscsi_ep->cid_vld = 0; | 506 | beiscsi_ep->cid_vld = 0; |
@@ -493,10 +518,10 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep, | |||
493 | status = phba->ctrl.mcc_numtag[tag] & 0x000000FF; | 518 | status = phba->ctrl.mcc_numtag[tag] & 0x000000FF; |
494 | if (status || extd_status) { | 519 | if (status || extd_status) { |
495 | SE_DEBUG(DBG_LVL_1, "mgmt_open_connection Failed" | 520 | SE_DEBUG(DBG_LVL_1, "mgmt_open_connection Failed" |
496 | " status = %d extd_status = %d \n", | 521 | " status = %d extd_status = %d\n", |
497 | status, extd_status); | 522 | status, extd_status); |
498 | free_mcc_tag(&phba->ctrl, tag); | 523 | free_mcc_tag(&phba->ctrl, tag); |
499 | return -1; | 524 | goto free_ep; |
500 | } else { | 525 | } else { |
501 | wrb = queue_get_wrb(mccq, wrb_num); | 526 | wrb = queue_get_wrb(mccq, wrb_num); |
502 | free_mcc_tag(&phba->ctrl, tag); | 527 | free_mcc_tag(&phba->ctrl, tag); |
@@ -508,31 +533,10 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep, | |||
508 | SE_DEBUG(DBG_LVL_8, "mgmt_open_connection Success\n"); | 533 | SE_DEBUG(DBG_LVL_8, "mgmt_open_connection Success\n"); |
509 | } | 534 | } |
510 | return 0; | 535 | return 0; |
511 | } | ||
512 | |||
513 | /** | ||
514 | * beiscsi_put_cid - Free the cid | ||
515 | * @phba: The phba for which the cid is being freed | ||
516 | * @cid: The cid to free | ||
517 | */ | ||
518 | static void beiscsi_put_cid(struct beiscsi_hba *phba, unsigned short cid) | ||
519 | { | ||
520 | phba->avlbl_cids++; | ||
521 | phba->cid_array[phba->cid_free++] = cid; | ||
522 | if (phba->cid_free == phba->params.cxns_per_ctrl) | ||
523 | phba->cid_free = 0; | ||
524 | } | ||
525 | |||
526 | /** | ||
527 | * beiscsi_free_ep - free endpoint | ||
528 | * @ep: pointer to iscsi endpoint structure | ||
529 | */ | ||
530 | static void beiscsi_free_ep(struct beiscsi_endpoint *beiscsi_ep) | ||
531 | { | ||
532 | struct beiscsi_hba *phba = beiscsi_ep->phba; | ||
533 | 536 | ||
534 | beiscsi_put_cid(phba, beiscsi_ep->ep_cid); | 537 | free_ep: |
535 | beiscsi_ep->phba = NULL; | 538 | beiscsi_free_ep(beiscsi_ep); |
539 | return -1; | ||
536 | } | 540 | } |
537 | 541 | ||
538 | /** | 542 | /** |
@@ -585,7 +589,7 @@ beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, | |||
585 | return ep; | 589 | return ep; |
586 | 590 | ||
587 | free_ep: | 591 | free_ep: |
588 | beiscsi_free_ep(beiscsi_ep); | 592 | iscsi_destroy_endpoint(ep); |
589 | return ERR_PTR(ret); | 593 | return ERR_PTR(ret); |
590 | } | 594 | } |
591 | 595 | ||
@@ -632,30 +636,6 @@ static int beiscsi_close_conn(struct beiscsi_endpoint *beiscsi_ep, int flag) | |||
632 | } | 636 | } |
633 | 637 | ||
634 | /** | 638 | /** |
635 | * beiscsi_ep_disconnect - Tears down the TCP connection | ||
636 | * @ep: endpoint to be used | ||
637 | * | ||
638 | * Tears down the TCP connection | ||
639 | */ | ||
640 | void beiscsi_ep_disconnect(struct iscsi_endpoint *ep) | ||
641 | { | ||
642 | struct beiscsi_conn *beiscsi_conn; | ||
643 | struct beiscsi_endpoint *beiscsi_ep; | ||
644 | struct beiscsi_hba *phba; | ||
645 | |||
646 | beiscsi_ep = ep->dd_data; | ||
647 | phba = beiscsi_ep->phba; | ||
648 | SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect for ep_cid = %d\n", | ||
649 | beiscsi_ep->ep_cid); | ||
650 | |||
651 | if (beiscsi_ep->conn) { | ||
652 | beiscsi_conn = beiscsi_ep->conn; | ||
653 | iscsi_suspend_queue(beiscsi_conn->conn); | ||
654 | } | ||
655 | |||
656 | } | ||
657 | |||
658 | /** | ||
659 | * beiscsi_unbind_conn_to_cid - Unbind the beiscsi_conn from phba conn table | 639 | * beiscsi_unbind_conn_to_cid - Unbind the beiscsi_conn from phba conn table |
660 | * @phba: The phba instance | 640 | * @phba: The phba instance |
661 | * @cid: The cid to free | 641 | * @cid: The cid to free |
@@ -673,28 +653,35 @@ static int beiscsi_unbind_conn_to_cid(struct beiscsi_hba *phba, | |||
673 | } | 653 | } |
674 | 654 | ||
675 | /** | 655 | /** |
676 | * beiscsi_conn_stop - Invalidate and stop the connection | 656 | * beiscsi_ep_disconnect - Tears down the TCP connection |
677 | * @cls_conn: pointer to get iscsi_conn | 657 | * @ep: endpoint to be used |
678 | * @flag: The type of connection closure | 658 | * |
659 | * Tears down the TCP connection | ||
679 | */ | 660 | */ |
680 | void beiscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) | 661 | void beiscsi_ep_disconnect(struct iscsi_endpoint *ep) |
681 | { | 662 | { |
682 | struct iscsi_conn *conn = cls_conn->dd_data; | 663 | struct beiscsi_conn *beiscsi_conn; |
683 | struct beiscsi_conn *beiscsi_conn = conn->dd_data; | ||
684 | struct beiscsi_endpoint *beiscsi_ep; | 664 | struct beiscsi_endpoint *beiscsi_ep; |
685 | struct iscsi_session *session = conn->session; | 665 | struct beiscsi_hba *phba; |
686 | struct Scsi_Host *shost = iscsi_session_to_shost(session->cls_session); | ||
687 | struct beiscsi_hba *phba = iscsi_host_priv(shost); | ||
688 | unsigned int tag; | 666 | unsigned int tag; |
689 | unsigned short savecfg_flag = CMD_ISCSI_SESSION_SAVE_CFG_ON_FLASH; | 667 | unsigned short savecfg_flag = CMD_ISCSI_SESSION_SAVE_CFG_ON_FLASH; |
690 | 668 | ||
691 | beiscsi_ep = beiscsi_conn->ep; | 669 | beiscsi_ep = ep->dd_data; |
692 | if (!beiscsi_ep) { | 670 | phba = beiscsi_ep->phba; |
693 | SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_stop , no beiscsi_ep\n"); | 671 | SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect for ep_cid = %d\n", |
672 | beiscsi_ep->ep_cid); | ||
673 | |||
674 | if (!beiscsi_ep->conn) { | ||
675 | SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect, no " | ||
676 | "beiscsi_ep\n"); | ||
694 | return; | 677 | return; |
695 | } | 678 | } |
696 | SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_stop ep_cid = %d\n", | 679 | beiscsi_conn = beiscsi_ep->conn; |
697 | beiscsi_ep->ep_cid); | 680 | iscsi_suspend_queue(beiscsi_conn->conn); |
681 | |||
682 | SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect ep_cid = %d\n", | ||
683 | beiscsi_ep->ep_cid); | ||
684 | |||
698 | tag = mgmt_invalidate_connection(phba, beiscsi_ep, | 685 | tag = mgmt_invalidate_connection(phba, beiscsi_ep, |
699 | beiscsi_ep->ep_cid, 1, | 686 | beiscsi_ep->ep_cid, 1, |
700 | savecfg_flag); | 687 | savecfg_flag); |
@@ -707,9 +694,9 @@ void beiscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) | |||
707 | phba->ctrl.mcc_numtag[tag]); | 694 | phba->ctrl.mcc_numtag[tag]); |
708 | free_mcc_tag(&phba->ctrl, tag); | 695 | free_mcc_tag(&phba->ctrl, tag); |
709 | } | 696 | } |
697 | |||
710 | beiscsi_close_conn(beiscsi_ep, CONNECTION_UPLOAD_GRACEFUL); | 698 | beiscsi_close_conn(beiscsi_ep, CONNECTION_UPLOAD_GRACEFUL); |
711 | beiscsi_free_ep(beiscsi_ep); | 699 | beiscsi_free_ep(beiscsi_ep); |
712 | iscsi_destroy_endpoint(beiscsi_ep->openiscsi_ep); | ||
713 | beiscsi_unbind_conn_to_cid(phba, beiscsi_ep->ep_cid); | 700 | beiscsi_unbind_conn_to_cid(phba, beiscsi_ep->ep_cid); |
714 | iscsi_conn_stop(cls_conn, flag); | 701 | iscsi_destroy_endpoint(beiscsi_ep->openiscsi_ep); |
715 | } | 702 | } |