aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/be2iscsi/be_iscsi.c
diff options
context:
space:
mode:
authorMike Christie <michaelc@cs.wisc.edu>2010-06-09 04:30:08 -0400
committerJames Bottomley <James.Bottomley@suse.de>2010-07-27 13:01:39 -0400
commitfa95d206e4a4fb549bdb9fe71091417f4912178f (patch)
tree1d4adc8b1e38b5b9d0dc836d00c8322631f426eb /drivers/scsi/be2iscsi/be_iscsi.c
parent2cae179486a356aca2a2617f0399f04c66598d8b (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.c123
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 */
449static 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 */
461static 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 */
518static 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 */
530static 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); 537free_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
587free_ep: 591free_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 */
640void 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 */
680void beiscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) 661void 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}