Parcourir la source

Clean up connection closing and permanent failure logic.

tags/v0.9.3
Michael Brown il y a 18 ans
Parent
révision
76525294ee
2 fichiers modifiés avec 69 ajouts et 32 suppressions
  1. 7
    0
      src/include/gpxe/iscsi.h
  2. 62
    32
      src/net/tcp/iscsi.c

+ 7
- 0
src/include/gpxe/iscsi.h Voir le fichier

@@ -592,6 +592,13 @@ struct iscsi_session {
592 592
 	struct scsi_command *command;
593 593
 	/** Asynchronous operation for the current iSCSI operation */
594 594
 	struct async_operation aop;
595
+	/** Instant return code
596
+	 *
597
+	 * Set to a non-zero value if all requests should return
598
+	 * immediately.  This can be used to e.g. avoid retrying
599
+	 * logins that are doomed to fail authentication.
600
+	 */
601
+	int instant_rc;
595 602
 };
596 603
 
597 604
 /** iSCSI session is currently in the security negotiation phase */

+ 62
- 32
src/net/tcp/iscsi.c Voir le fichier

@@ -78,6 +78,28 @@ static void iscsi_rx_buffered_data_done ( struct iscsi_session *iscsi ) {
78 78
 	iscsi->rx_buffer = NULL;
79 79
 }
80 80
 
81
+/**
82
+ * Close iSCSI connection
83
+ *
84
+ * @v iscsi		iSCSI session
85
+ */
86
+static void iscsi_close ( struct iscsi_session *iscsi ) {
87
+
88
+	/* Close TCP connection */
89
+	tcp_close ( &iscsi->tcp );
90
+
91
+	/* Clear connection status */
92
+	iscsi->status = 0;
93
+
94
+	/* Reset TX and RX state machines */
95
+	iscsi->tx_state = ISCSI_TX_IDLE;
96
+	iscsi->rx_state = ISCSI_RX_BHS;
97
+
98
+	/* Free any dynamically allocated memory */
99
+	chap_finish ( &iscsi->chap );
100
+	iscsi_rx_buffered_data_done ( iscsi );
101
+}
102
+
81 103
 /**
82 104
  * Mark iSCSI operation as complete
83 105
  *
@@ -93,13 +115,13 @@ static void iscsi_rx_buffered_data_done ( struct iscsi_session *iscsi ) {
93 115
  */
94 116
 static void iscsi_done ( struct iscsi_session *iscsi, int rc ) {
95 117
 
118
+	assert ( iscsi->tx_state == ISCSI_TX_IDLE );
119
+	assert ( iscsi->rx_state == ISCSI_RX_BHS );
120
+	assert ( iscsi->rx_offset == 0 );
121
+
96 122
 	/* Clear current SCSI command */
97 123
 	iscsi->command = NULL;
98 124
 
99
-	/* Free any dynamically allocated memory */
100
-	chap_finish ( &iscsi->chap );
101
-	iscsi_rx_buffered_data_done ( iscsi );
102
-
103 125
 	/* Mark asynchronous operation as complete */
104 126
 	async_done ( &iscsi->aop, rc );
105 127
 }
@@ -470,6 +492,9 @@ static void iscsi_login_request_done ( struct iscsi_session *iscsi ) {
470 492
 
471 493
 	/* Clear any "strings to send" flags */
472 494
 	iscsi->status &= ~ISCSI_STATUS_STRINGS_MASK;
495
+
496
+	/* Free any dynamically allocated storage used for login */
497
+	chap_finish ( &iscsi->chap );
473 498
 }
474 499
 
475 500
 /**
@@ -547,6 +572,7 @@ static void iscsi_handle_chap_a_value ( struct iscsi_session *iscsi,
547 572
 	/* Prepare for CHAP with MD5 */
548 573
 	if ( ( rc = chap_init ( &iscsi->chap, &md5_algorithm ) ) != 0 ) {
549 574
 		DBG ( "iSCSI %p could not initialise CHAP\n", iscsi );
575
+		iscsi_close ( iscsi );
550 576
 		iscsi_done ( iscsi, rc );
551 577
 	}
552 578
 }
@@ -707,6 +733,7 @@ static void iscsi_rx_login_response ( struct iscsi_session *iscsi, void *data,
707 733
 	/* Buffer up the PDU data */
708 734
 	if ( ( rc = iscsi_rx_buffered_data ( iscsi, data, len ) ) != 0 ) {
709 735
 		DBG ( "iSCSI %p could not buffer login response\n", iscsi );
736
+		iscsi_close ( iscsi );
710 737
 		iscsi_done ( iscsi, rc );
711 738
 		return;
712 739
 	}
@@ -720,8 +747,7 @@ static void iscsi_rx_login_response ( struct iscsi_session *iscsi, void *data,
720 747
 	/* Check for login redirection */
721 748
 	if ( response->status_class == ISCSI_STATUS_REDIRECT ) {
722 749
 		DBG ( "iSCSI %p redirecting to new server\n", iscsi );
723
-		tcp_close ( &iscsi->tcp );
724
-		iscsi->status = 0;
750
+		iscsi_close ( iscsi );
725 751
 		if ( ( rc = tcp_connect ( &iscsi->tcp, &iscsi->target,
726 752
 					  0 ) ) != 0 ) {
727 753
 			DBG ( "iSCSI %p could not open TCP connection\n",
@@ -735,6 +761,8 @@ static void iscsi_rx_login_response ( struct iscsi_session *iscsi, void *data,
735 761
 	if ( response->status_class != 0 ) {
736 762
 		DBG ( "iSCSI login failure: class %02x detail %02x\n",
737 763
 		      response->status_class, response->status_detail );
764
+		iscsi->instant_rc = -EPERM;
765
+		iscsi_close ( iscsi );
738 766
 		iscsi_done ( iscsi, -EPERM );
739 767
 		return;
740 768
 	}
@@ -753,6 +781,7 @@ static void iscsi_rx_login_response ( struct iscsi_session *iscsi, void *data,
753 781
 		default:
754 782
 			DBG ( "iSCSI %p got invalid response flags %02x\n",
755 783
 			      iscsi, response->flags );
784
+			iscsi_close ( iscsi );
756 785
 			iscsi_done ( iscsi, -EIO );
757 786
 			return;
758 787
 		}
@@ -767,6 +796,9 @@ static void iscsi_rx_login_response ( struct iscsi_session *iscsi, void *data,
767 796
 		return;
768 797
 	}
769 798
 
799
+	/* Reset retry count */
800
+	iscsi->retry_count = 0;
801
+
770 802
 	/* Record TSIH for future reference */
771 803
 	iscsi->tsih = ntohl ( response->tsih );
772 804
 	
@@ -986,7 +1018,8 @@ static void iscsi_rx_data ( struct iscsi_session *iscsi, void *data,
986 1018
 	default:
987 1019
 		if ( remaining )
988 1020
 			return;
989
-		printf ( "Unknown iSCSI opcode %02x\n", response->opcode );
1021
+		DBG ( "Unknown iSCSI opcode %02x\n", response->opcode );
1022
+		iscsi_close ( iscsi );
990 1023
 		iscsi_done ( iscsi, -EOPNOTSUPP );
991 1024
 		break;
992 1025
 	}
@@ -1112,19 +1145,25 @@ static void iscsi_closed ( struct tcp_application *app, int status ) {
1112 1145
 	struct iscsi_session *iscsi = tcp_to_iscsi ( app );
1113 1146
 	int rc;
1114 1147
 
1115
-	/* Clear session status */
1116
-	iscsi->status = 0;
1148
+	/* Even a graceful close counts as an error for iSCSI */
1149
+	if ( ! status )
1150
+		status = -ECONNRESET;
1151
+
1152
+	/* Close session cleanly */
1153
+	iscsi_close ( iscsi );
1117 1154
 
1118 1155
 	/* Retry connection if within the retry limit, otherwise fail */
1119 1156
 	if ( ++iscsi->retry_count <= ISCSI_MAX_RETRIES ) {
1120
-		DBG ( "iSCSI %p retrying connection\n", iscsi );
1157
+		DBG ( "iSCSI %p retrying connection (retry #%d)\n",
1158
+		      iscsi, iscsi->retry_count );
1121 1159
 		if ( ( rc = tcp_connect ( app, &iscsi->target, 0 ) ) != 0 ) {
1122 1160
 			DBG ( "iSCSI %p could not open TCP connection\n",
1123 1161
 			      iscsi );
1124 1162
 			iscsi_done ( iscsi, rc );
1125 1163
 		}
1126 1164
 	} else {
1127
-		printf ( "iSCSI %p retry count exceeded\n", iscsi );
1165
+		DBG ( "iSCSI %p retry count exceeded\n", iscsi );
1166
+		iscsi->instant_rc = status;
1128 1167
 		iscsi_done ( iscsi, status );
1129 1168
 	}
1130 1169
 }
@@ -1138,14 +1177,12 @@ static void iscsi_closed ( struct tcp_application *app, int status ) {
1138 1177
 static void iscsi_connected ( struct tcp_application *app ) {
1139 1178
 	struct iscsi_session *iscsi = tcp_to_iscsi ( app );
1140 1179
 
1141
-	/* Set connected flag and reset retry count */
1180
+	assert ( iscsi->rx_state == ISCSI_RX_BHS );
1181
+	assert ( iscsi->rx_offset == 0 );
1182
+
1183
+	/* Enter security negotiation phase */
1142 1184
 	iscsi->status = ( ISCSI_STATUS_SECURITY_NEGOTIATION_PHASE |
1143 1185
 			  ISCSI_STATUS_STRINGS_SECURITY );
1144
-	iscsi->retry_count = 0;
1145
-
1146
-	/* Prepare to receive PDUs. */
1147
-	iscsi->rx_state = ISCSI_RX_BHS;
1148
-	iscsi->rx_offset = 0;
1149 1186
 
1150 1187
 	/* Assign fresh initiator task tag */
1151 1188
 	iscsi->itt++;
@@ -1177,19 +1214,13 @@ struct async_operation * iscsi_issue ( struct iscsi_session *iscsi,
1177 1214
 	assert ( iscsi->command == NULL );
1178 1215
 	iscsi->command = command;
1179 1216
 
1180
-	if ( iscsi->status ) {
1181
-		if ( ( iscsi->status & ISCSI_STATUS_PHASE_MASK ) ==
1182
-		     ISCSI_STATUS_FULL_FEATURE_PHASE ) {
1183
-			/* Session already open: issue command */
1184
-			iscsi_start_command ( iscsi );
1185
-			tcp_senddata ( &iscsi->tcp );
1186
-		} else {
1187
-			/* Session failed to reach full feature phase:
1188
-			 * abort immediately rather than retrying the
1189
-			 * login.
1190
-			 */
1191
-			iscsi_done ( iscsi, -EPERM );
1192
-		}
1217
+	if ( iscsi->instant_rc ) {
1218
+		/* Abort immediately rather than retrying */
1219
+		iscsi_done ( iscsi, iscsi->instant_rc );
1220
+	} else if ( iscsi->status ) {
1221
+		/* Session already open: issue command */
1222
+		iscsi_start_command ( iscsi );
1223
+		tcp_senddata ( &iscsi->tcp );
1193 1224
 	} else {
1194 1225
 		/* Session not open: initiate login */
1195 1226
 		iscsi->tcp.tcp_op = &iscsi_tcp_operations;
@@ -1211,6 +1242,5 @@ struct async_operation * iscsi_issue ( struct iscsi_session *iscsi,
1211 1242
  * @ret aop		Asynchronous operation
1212 1243
  */
1213 1244
 void iscsi_shutdown ( struct iscsi_session *iscsi ) {
1214
-	iscsi->status = 0;
1215
-	tcp_close ( &iscsi->tcp );
1245
+	iscsi_close ( iscsi );
1216 1246
 }

Chargement…
Annuler
Enregistrer