diff options
author | Mike Christie <michaelc@cs.wisc.edu> | 2006-05-30 01:37:28 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2006-06-05 19:12:25 -0400 |
commit | 3219e5294150aee7d389e19029f49b44fb6b5c9f (patch) | |
tree | 44236fd9f2eb40d5622cadb126e9f2672b129486 /drivers/scsi/libiscsi.c | |
parent | 040515f53c09047c76ad074dc6a280984dc84b04 (diff) |
[SCSI] iscsi: fix writepsace race
We can race and misset the suspend bit if iscsi_write_space is
called then iscsi_send returns with a failure indicating
there is no space.
To handle this this patch returns a error upwards allowing xmitworker
to decide if we need to try and transmit again. For the no
write space case xmitworker will not retry, and instead
let iscsi_write_space queue it back up if needed (this relies
on the work queue code to properly requeue us if needed).
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/libiscsi.c')
-rw-r--r-- | drivers/scsi/libiscsi.c | 31 |
1 files changed, 19 insertions, 12 deletions
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 256b87a85978..2673a11a9495 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c | |||
@@ -513,10 +513,11 @@ EXPORT_SYMBOL_GPL(iscsi_conn_failure); | |||
513 | static int iscsi_data_xmit(struct iscsi_conn *conn) | 513 | static int iscsi_data_xmit(struct iscsi_conn *conn) |
514 | { | 514 | { |
515 | struct iscsi_transport *tt; | 515 | struct iscsi_transport *tt; |
516 | int rc = 0; | ||
516 | 517 | ||
517 | if (unlikely(conn->suspend_tx)) { | 518 | if (unlikely(conn->suspend_tx)) { |
518 | debug_scsi("conn %d Tx suspended!\n", conn->id); | 519 | debug_scsi("conn %d Tx suspended!\n", conn->id); |
519 | return 0; | 520 | return -ENODATA; |
520 | } | 521 | } |
521 | tt = conn->session->tt; | 522 | tt = conn->session->tt; |
522 | 523 | ||
@@ -536,13 +537,15 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) | |||
536 | BUG_ON(conn->ctask && conn->mtask); | 537 | BUG_ON(conn->ctask && conn->mtask); |
537 | 538 | ||
538 | if (conn->ctask) { | 539 | if (conn->ctask) { |
539 | if (tt->xmit_cmd_task(conn, conn->ctask)) | 540 | rc = tt->xmit_cmd_task(conn, conn->ctask); |
541 | if (rc) | ||
540 | goto again; | 542 | goto again; |
541 | /* done with this in-progress ctask */ | 543 | /* done with this in-progress ctask */ |
542 | conn->ctask = NULL; | 544 | conn->ctask = NULL; |
543 | } | 545 | } |
544 | if (conn->mtask) { | 546 | if (conn->mtask) { |
545 | if (tt->xmit_mgmt_task(conn, conn->mtask)) | 547 | rc = tt->xmit_mgmt_task(conn, conn->mtask); |
548 | if (rc) | ||
546 | goto again; | 549 | goto again; |
547 | /* done with this in-progress mtask */ | 550 | /* done with this in-progress mtask */ |
548 | conn->mtask = NULL; | 551 | conn->mtask = NULL; |
@@ -556,7 +559,8 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) | |||
556 | list_add_tail(&conn->mtask->running, | 559 | list_add_tail(&conn->mtask->running, |
557 | &conn->mgmt_run_list); | 560 | &conn->mgmt_run_list); |
558 | spin_unlock_bh(&conn->session->lock); | 561 | spin_unlock_bh(&conn->session->lock); |
559 | if (tt->xmit_mgmt_task(conn, conn->mtask)) | 562 | rc = tt->xmit_mgmt_task(conn, conn->mtask); |
563 | if (rc) | ||
560 | goto again; | 564 | goto again; |
561 | } | 565 | } |
562 | /* done with this mtask */ | 566 | /* done with this mtask */ |
@@ -574,7 +578,8 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) | |||
574 | if (list_empty(&conn->ctask->running)) | 578 | if (list_empty(&conn->ctask->running)) |
575 | list_add_tail(&conn->ctask->running, &conn->run_list); | 579 | list_add_tail(&conn->ctask->running, &conn->run_list); |
576 | spin_unlock_bh(&conn->session->lock); | 580 | spin_unlock_bh(&conn->session->lock); |
577 | if (tt->xmit_cmd_task(conn, conn->ctask)) | 581 | rc = tt->xmit_cmd_task(conn, conn->ctask); |
582 | if (rc) | ||
578 | goto again; | 583 | goto again; |
579 | } | 584 | } |
580 | /* done with this ctask */ | 585 | /* done with this ctask */ |
@@ -588,32 +593,34 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) | |||
588 | list_add_tail(&conn->mtask->running, | 593 | list_add_tail(&conn->mtask->running, |
589 | &conn->mgmt_run_list); | 594 | &conn->mgmt_run_list); |
590 | spin_unlock_bh(&conn->session->lock); | 595 | spin_unlock_bh(&conn->session->lock); |
591 | if (tt->xmit_mgmt_task(conn, conn->mtask)) | 596 | rc = tt->xmit_mgmt_task(conn, conn->mtask); |
597 | if (rc) | ||
592 | goto again; | 598 | goto again; |
593 | } | 599 | } |
594 | /* done with this mtask */ | 600 | /* done with this mtask */ |
595 | conn->mtask = NULL; | 601 | conn->mtask = NULL; |
596 | } | 602 | } |
597 | 603 | ||
598 | return 0; | 604 | return -ENODATA; |
599 | 605 | ||
600 | again: | 606 | again: |
601 | if (unlikely(conn->suspend_tx)) | 607 | if (unlikely(conn->suspend_tx)) |
602 | return 0; | 608 | return -ENODATA; |
603 | 609 | ||
604 | return -EAGAIN; | 610 | return rc; |
605 | } | 611 | } |
606 | 612 | ||
607 | static void iscsi_xmitworker(void *data) | 613 | static void iscsi_xmitworker(void *data) |
608 | { | 614 | { |
609 | struct iscsi_conn *conn = data; | 615 | struct iscsi_conn *conn = data; |
610 | 616 | int rc; | |
611 | /* | 617 | /* |
612 | * serialize Xmit worker on a per-connection basis. | 618 | * serialize Xmit worker on a per-connection basis. |
613 | */ | 619 | */ |
614 | mutex_lock(&conn->xmitmutex); | 620 | mutex_lock(&conn->xmitmutex); |
615 | if (iscsi_data_xmit(conn)) | 621 | do { |
616 | scsi_queue_work(conn->session->host, &conn->xmitwork); | 622 | rc = iscsi_data_xmit(conn); |
623 | } while (rc >= 0 || rc == -EAGAIN); | ||
617 | mutex_unlock(&conn->xmitmutex); | 624 | mutex_unlock(&conn->xmitmutex); |
618 | } | 625 | } |
619 | 626 | ||