Close file descriptor passed into the kernel on success.

Fix locking of file handle. More cleanup on error paths.
Keep track of CCBs, so they cannot be used after a session ends.
Handle CCB timeouts even when the connection is terminated.
Compute firstdata, firstimmed correctly.
This commit is contained in:
mlelstv 2012-06-09 06:19:58 +00:00
parent d7fc161785
commit d1c48dff5a
6 changed files with 92 additions and 57 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: iscsi_globals.h,v 1.3 2012/06/02 16:52:11 mlelstv Exp $ */
/* $NetBSD: iscsi_globals.h,v 1.4 2012/06/09 06:19:58 mlelstv Exp $ */
/*-
* Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc.
@ -387,6 +387,7 @@ struct connection_s {
/* if closing down: status */
int recover; /* recovery count */
/* (reset on first successful data transfer) */
int usecount; /* number of active CCBs */
bool destroy; /* conn will be destroyed */
bool in_session;

View File

@ -1,4 +1,4 @@
/* $NetBSD: iscsi_ioctl.c,v 1.2 2012/01/27 19:48:39 para Exp $ */
/* $NetBSD: iscsi_ioctl.c,v 1.3 2012/06/09 06:19:58 mlelstv Exp $ */
/*-
* Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc.
@ -207,7 +207,8 @@ check_event(iscsi_wait_event_parameters_t *par, bool wait)
}
handler->waiter = par;
splx(s);
tsleep(par, PRIBIO, "iscsievtwait", 0);
if (tsleep(par, PRIBIO | PCATCH, "iscsievtwait", 0))
return;
}
} while (evt == NULL);
@ -324,15 +325,34 @@ get_socket(int fdes, struct file **fpp)
if (fp->f_type != DTYPE_SOCKET) {
return ENOTSOCK;
}
/* Add the reference */
fp->f_count++;
/*simple_unlock (&fp->f_slock); */
/* Add the reference */
mutex_enter(&fp->f_lock);
fp->f_count++;
mutex_exit(&fp->f_lock);
*fpp = fp;
return 0;
}
/*
* release_socket:
* Release the file pointer from the socket handle passed into login.
*
* Parameter:
* fp IN: The pointer to the resulting file pointer
*
*/
STATIC void
release_socket(struct file *fp)
{
/* Add the reference */
mutex_enter(&fp->f_lock);
fp->f_count--;
mutex_exit(&fp->f_lock);
}
/*
* find_session:
@ -635,6 +655,7 @@ create_connection(iscsi_login_parameters_t *par, session_t *session,
"ConnRcv")) != 0) {
DEBOUT(("Can't create rcv thread (rc %d)\n", rc));
release_socket(connection->sock);
free(connection, M_DEVBUF);
par->status = ISCSI_STATUS_NO_RESOURCES;
return rc;
@ -653,18 +674,15 @@ create_connection(iscsi_login_parameters_t *par, session_t *session,
*/
DEBC(connection, 1,
("Closing Socket %p\n", connection->sock));
#if __NetBSD_Version__ > 500000000
mutex_enter(&connection->sock->f_lock);
connection->sock->f_count += 1;
mutex_exit(&connection->sock->f_lock);
#else
FILE_USE(connection->sock);
#endif
closef(connection->sock);
/* give receive thread time to exit */
tsleep(connection, PWAIT, "settle", 20);
release_socket(connection->sock);
free(connection, M_DEVBUF);
par->status = ISCSI_STATUS_NO_RESOURCES;
return rc;
@ -698,6 +716,9 @@ create_connection(iscsi_login_parameters_t *par, session_t *session,
session->mru_connection = connection;
CS_END;
/* close the file descriptor */
fd_close(par->socket);
DEBC(connection, 5, ("Connection created successfully!\n"));
return 0;
}
@ -809,6 +830,10 @@ recreate_connection(iscsi_login_parameters_t *par, session_t *session,
DEBC(connection, 5, ("Connection ReCreated successfully - status %d\n",
par->status));
/* close the file descriptor */
fd_close(par->socket);
return 0;
}
@ -1463,9 +1488,8 @@ iscsi_cleanup_thread(void *par)
while (conn->sendproc || conn->rcvproc)
tsleep(conn, PWAIT, "termwait", 20);
/* just in case any CCB is still being processed */
/* that references this connection */
tsleep(conn, PWAIT, "finalwait", 20);
while (conn->usecount > 0)
tsleep(conn, PWAIT, "finalwait", 20);
free(conn, M_DEVBUF);

View File

@ -449,7 +449,6 @@ iscsi_done(ccb_t *ccb)
case ISCSI_STATUS_CHECK_CONDITION:
xs->error = XS_SENSE;
xs->error = XS_SENSE;
#ifdef ISCSI_DEBUG
{
uint8_t *s = (uint8_t *) (&xs->sense);

View File

@ -1,4 +1,4 @@
/* $NetBSD: iscsi_send.c,v 1.2 2012/06/05 16:36:07 mhitch Exp $ */
/* $NetBSD: iscsi_send.c,v 1.3 2012/06/09 06:19:58 mlelstv Exp $ */
/*-
* Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc.
@ -199,6 +199,8 @@ reassign_tasks(connection_t *oldconn)
ccb->pdu_waiting = pdu;
ccb->connection = conn;
ccb->num_timeouts = 0;
oldconn->usecount--;
conn->usecount++;
DEBC(conn, 1, ("CCB %p: Copied PDU %p to %p\n",
ccb, opdu, pdu));
@ -341,25 +343,15 @@ iscsi_send_thread(void *par)
fp = conn->sock;
DEBC(conn, 9, ("Closing Socket %p\n", conn->sock));
/*
* We must close the socket here to force the receive
* thread to wake up
*/
DEBC(conn, 9, ("Closing Socket %p\n", conn->sock));
solock((struct socket *) fp->f_data);
soshutdown((struct socket *) fp->f_data, SHUT_RDWR);
sounlock((struct socket *) fp->f_data);
#if __NetBSD_Version__ > 500000000
mutex_enter(&fp->f_lock);
fp->f_count += 1;
mutex_exit(&fp->f_lock);
closef(fp);
#else
simple_lock(&fp->f_slock);
FILE_USE(fp);
closef(fp, NULL);
#endif
/* wake up any non-reassignable waiting CCBs */
for (ccb = TAILQ_FIRST(&conn->ccbs_waiting); ccb != NULL; ccb = nccb) {
@ -791,9 +783,13 @@ start_text_negotiation(connection_t *conn)
ccb_t *ccb;
ccb = get_ccb(conn, TRUE);
pdu = get_pdu(conn);
if (ccb == NULL || pdu == NULL)
if (ccb == NULL)
return;
pdu = get_pdu(conn);
if (pdu == NULL) {
free_ccb(ccb);
return;
}
if (init_text_parameters(conn, ccb)) {
free_ccb(ccb);
@ -887,10 +883,13 @@ send_send_targets(session_t *session, uint8_t *key)
: ISCSI_STATUS_CONNECTION_FAILED;
ccb = get_ccb(conn, TRUE);
pdu = get_pdu(conn);
/* can only happen if terminating... */
if (ccb == NULL || pdu == NULL)
if (ccb == NULL)
return conn->terminating;
pdu = get_pdu(conn);
if (pdu == NULL) {
free_ccb(ccb);
return conn->terminating;
}
ccb->flags |= CCBF_SENDTARGET;
@ -1105,12 +1104,15 @@ send_login(connection_t *conn)
DEBC(conn, 9, ("Send_login\n"));
ccb = get_ccb(conn, TRUE);
pdu = get_pdu(conn);
/* only if terminating (which couldn't possibly happen here, but...) */
if (ccb == NULL || pdu == NULL) {
if (ccb == NULL)
return conn->terminating;
pdu = get_pdu(conn);
if (pdu == NULL) {
free_ccb(ccb);
return conn->terminating;
}
if ((rc = assemble_login_parameters(conn, ccb, pdu)) >= 0) {
init_login_pdu(conn, pdu, !rc);
setup_tx_uio(pdu, pdu->temp_data_len, pdu->temp_data, FALSE);
@ -1148,10 +1150,14 @@ send_logout(connection_t *conn, connection_t *refconn, int reason,
DEBC(conn, 5, ("Send_logout\n"));
ccb = get_ccb(conn, TRUE);
ppdu = get_pdu(conn);
/* can only happen if terminating... */
if (ccb == NULL || ppdu == NULL)
if (ccb == NULL)
return conn->terminating;
ppdu = get_pdu(conn);
if (ppdu == NULL) {
free_ccb(ccb);
return conn->terminating;
}
pdu = &ppdu->pdu;
pdu->Opcode = IOP_Logout_Request | OP_IMMEDIATE;
@ -1211,10 +1217,14 @@ send_task_management(connection_t *conn, ccb_t *ref_ccb, struct scsipi_xfer *xs,
return ISCSI_STATUS_CANT_REASSIGN;
ccb = get_ccb(conn, xs == NULL);
ppdu = get_pdu(conn);
/* can only happen if terminating... */
if (ccb == NULL || ppdu == NULL)
if (ccb == NULL)
return conn->terminating;
ppdu = get_pdu(conn);
if (ppdu == NULL) {
free_ccb(ccb);
return conn->terminating;
}
ccb->xs = xs;
@ -1392,12 +1402,11 @@ send_command(ccb_t *ccb, ccb_disp_t disp, bool waitok, bool immed)
totlen = 0;
} else {
pdu->Flags = FLAG_WRITE;
/* immediate data we can send */
len = min(totlen, conn->max_firstimmed);
/* this means InitialR2T=Yes or FirstBurstLength=0 */
if (!len)
totlen = 0;
else
totlen -= len;
/* can we send more unsolicited data ? */
totlen = conn->max_firstdata ? totlen - len : 0;
}
}
@ -1459,7 +1468,7 @@ send_run_xfer(session_t *session, struct scsipi_xfer *xs)
conn = assign_connection(session, waitok);
if (conn == NULL || conn->terminating || conn->state != ST_FULL_FEATURE) {
xs->error = XS_REQUEUE;
xs->error = XS_SELTIMEOUT;
DEBC(conn, 10, ("run_xfer on dead connection\n"));
scsipi_done(xs);
return;
@ -1500,6 +1509,7 @@ send_run_xfer(session_t *session, struct scsipi_xfer *xs)
ccb->lun += 0x1000000000000LL;
ccb->cmd[1] += 0x10;
#endif
ccb->disp = CCBDISP_SCSIPI;
send_command(ccb, CCBDISP_SCSIPI, waitok, FALSE);
}
@ -1615,23 +1625,19 @@ ccb_timeout(void *par)
{
ccb_t *ccb = (ccb_t *) par;
connection_t *conn = ccb->connection;
PDEBC(conn, 1, ("CCB Timeout, ccb=%x, num_timeouts=%d\n",
(int) ccb, ccb->num_timeouts));
/* ignore CCB timeouts outside full feature phase */
if (conn->state != ST_FULL_FEATURE)
return;
ccb->total_tries++;
if (++ccb->num_timeouts > MAX_CCB_TIMEOUTS ||
ccb->total_tries > MAX_CCB_TRIES ||
ccb->disp <= CCBDISP_FREE ||
!ccb->session->ErrorRecoveryLevel) {
handle_connection_error(conn, ISCSI_STATUS_TIMEOUT,
(ccb->total_tries <= MAX_CCB_TRIES) ? RECOVER_CONNECTION
: LOGOUT_CONNECTION);
ccb->status = ISCSI_STATUS_TIMEOUT;
complete_ccb(ccb);
handle_connection_error(conn, ISCSI_STATUS_TIMEOUT, RECOVER_CONNECTION);
} else {
if (ccb->data_in && ccb->xfer_len < ccb->data_len) {
/* request resend of all missing data */

View File

@ -1,4 +1,4 @@
/* $NetBSD: iscsi_text.c,v 1.3 2011/12/17 20:05:39 tls Exp $ */
/* $NetBSD: iscsi_text.c,v 1.4 2012/06/09 06:19:58 mlelstv Exp $ */
/*-
* Copyright (c) 2005,2006,2011 The NetBSD Foundation, Inc.
@ -1773,11 +1773,12 @@ set_negotiated_parameters(ccb_t *ccb)
state->FirstBurstLength, state->InitialR2T,
state->ImmediateData));
conn->max_transfer = min(sess->MaxBurstLength,
conn->MaxRecvDataSegmentLength);
conn->max_transfer = min(sess->MaxBurstLength, conn->MaxRecvDataSegmentLength);
conn->max_firstimmed = (!sess->ImmediateData) ? 0 :
min(sess->FirstBurstLength, conn->max_transfer);
conn->max_firstdata = (sess->InitialR2T) ? 0 : sess->FirstBurstLength;
conn->max_firstdata = (sess->InitialR2T || sess->FirstBurstLength < conn->max_firstimmed) ? 0 :
min(sess->FirstBurstLength - conn->max_firstimmed, conn->max_transfer);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: iscsi_utils.c,v 1.1 2011/10/23 21:15:02 agc Exp $ */
/* $NetBSD: iscsi_utils.c,v 1.2 2012/06/09 06:19:58 mlelstv Exp $ */
/*-
* Copyright (c) 2004,2005,2006,2008 The NetBSD Foundation, Inc.
@ -244,6 +244,7 @@ get_ccb(connection_t *conn, bool waitok)
ccb->ITT = (ccb->ITT & 0xffffff) | (++sess->itt_id << 24);
ccb->disp = CCBDISP_NOWAIT;
ccb->connection = conn;
conn->usecount++;
return ccb;
}
@ -261,6 +262,9 @@ free_ccb(ccb_t *ccb)
session_t *sess = ccb->session;
pdu_t *pdu;
ccb->connection->usecount--;
ccb->connection = NULL;
ccb->disp = CCBDISP_UNUSED;
/* free temporary data */