Author: mav
Date: Sat Nov 22 09:05:54 2014
New Revision: 274843
URL: https://svnweb.freebsd.org/changeset/base/274843

Log:
  Move icl_pdu_get_data() and xpt_done() out of initiator's session lock.
  
  During heavy reads data copying in icl_pdu_get_data() may consume large
  percent of CPU time.  Moving it out of the lock significantly reduces
  lock hold time and respectively lock congestion on read operations.
  
  MFC after:    2 weeks

Modified:
  head/sys/dev/iscsi/iscsi.c

Modified: head/sys/dev/iscsi/iscsi.c
==============================================================================
--- head/sys/dev/iscsi/iscsi.c  Sat Nov 22 08:47:04 2014        (r274842)
+++ head/sys/dev/iscsi/iscsi.c  Sat Nov 22 09:05:54 2014        (r274843)
@@ -139,6 +139,7 @@ static uma_zone_t iscsi_outstanding_zone
 #define ISCSI_SESSION_LOCK(X)          mtx_lock(&X->is_lock)
 #define ISCSI_SESSION_UNLOCK(X)                mtx_unlock(&X->is_lock)
 #define ISCSI_SESSION_LOCK_ASSERT(X)   mtx_assert(&X->is_lock, MA_OWNED)
+#define ISCSI_SESSION_LOCK_ASSERT_NOT(X) mtx_assert(&X->is_lock, MA_NOTOWNED)
 
 static int     iscsi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg,
                    int mode, struct thread *td);
@@ -709,37 +710,46 @@ iscsi_receive_callback(struct icl_pdu *r
        switch (response->ip_bhs->bhs_opcode) {
        case ISCSI_BHS_OPCODE_NOP_IN:
                iscsi_pdu_handle_nop_in(response);
+               ISCSI_SESSION_UNLOCK(is);
                break;
        case ISCSI_BHS_OPCODE_SCSI_RESPONSE:
                iscsi_pdu_handle_scsi_response(response);
+               /* Session lock dropped inside. */
+               ISCSI_SESSION_LOCK_ASSERT_NOT(is);
                break;
        case ISCSI_BHS_OPCODE_TASK_RESPONSE:
                iscsi_pdu_handle_task_response(response);
+               ISCSI_SESSION_UNLOCK(is);
                break;
        case ISCSI_BHS_OPCODE_SCSI_DATA_IN:
                iscsi_pdu_handle_data_in(response);
+               /* Session lock dropped inside. */
+               ISCSI_SESSION_LOCK_ASSERT_NOT(is);
                break;
        case ISCSI_BHS_OPCODE_LOGOUT_RESPONSE:
                iscsi_pdu_handle_logout_response(response);
+               ISCSI_SESSION_UNLOCK(is);
                break;
        case ISCSI_BHS_OPCODE_R2T:
                iscsi_pdu_handle_r2t(response);
+               ISCSI_SESSION_UNLOCK(is);
                break;
        case ISCSI_BHS_OPCODE_ASYNC_MESSAGE:
                iscsi_pdu_handle_async_message(response);
+               ISCSI_SESSION_UNLOCK(is);
                break;
        case ISCSI_BHS_OPCODE_REJECT:
                iscsi_pdu_handle_reject(response);
+               ISCSI_SESSION_UNLOCK(is);
                break;
        default:
                ISCSI_SESSION_WARN(is, "received PDU with unsupported "
                    "opcode 0x%x; reconnecting",
                    response->ip_bhs->bhs_opcode);
                iscsi_session_reconnect(is);
+               ISCSI_SESSION_UNLOCK(is);
                icl_pdu_free(response);
        }
-
-       ISCSI_SESSION_UNLOCK(is);
 }
 
 static void
@@ -840,9 +850,13 @@ iscsi_pdu_handle_scsi_response(struct ic
                ISCSI_SESSION_WARN(is, "bad itt 0x%x", 
bhssr->bhssr_initiator_task_tag);
                icl_pdu_free(response);
                iscsi_session_reconnect(is);
+               ISCSI_SESSION_UNLOCK(is);
                return;
        }
 
+       iscsi_outstanding_remove(is, io);
+       ISCSI_SESSION_UNLOCK(is);
+
        if (bhssr->bhssr_response != BHSSR_RESPONSE_COMMAND_COMPLETED) {
                ISCSI_SESSION_WARN(is, "service response 0x%x", 
bhssr->bhssr_response);
                if ((io->io_ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
@@ -861,15 +875,7 @@ iscsi_pdu_handle_scsi_response(struct ic
                io->io_ccb->csio.scsi_status = bhssr->bhssr_status;
        }
 
-       if (bhssr->bhssr_flags & BHSSR_FLAGS_RESIDUAL_OVERFLOW) {
-               ISCSI_SESSION_WARN(is, "target indicated residual overflow");
-               icl_pdu_free(response);
-               iscsi_session_reconnect(is);
-               return;
-       }
-
        csio = &io->io_ccb->csio;
-
        data_segment_len = icl_pdu_data_segment_length(response);
        if (data_segment_len > 0) {
                if (data_segment_len < sizeof(sense_len)) {
@@ -931,7 +937,6 @@ out:
        }
 
        xpt_done(io->io_ccb);
-       iscsi_outstanding_remove(is, io);
        icl_pdu_free(response);
 }
 
@@ -974,7 +979,7 @@ iscsi_pdu_handle_data_in(struct icl_pdu 
        struct iscsi_outstanding *io;
        struct iscsi_session *is;
        struct ccb_scsiio *csio;
-       size_t data_segment_len;
+       size_t data_segment_len, received;
        
        is = PDU_SESSION(response);
        bhsdi = (struct iscsi_bhs_data_in *)response->ip_bhs;
@@ -983,6 +988,7 @@ iscsi_pdu_handle_data_in(struct icl_pdu 
                ISCSI_SESSION_WARN(is, "bad itt 0x%x", 
bhsdi->bhsdi_initiator_task_tag);
                icl_pdu_free(response);
                iscsi_session_reconnect(is);
+               ISCSI_SESSION_UNLOCK(is);
                return;
        }
 
@@ -993,6 +999,7 @@ iscsi_pdu_handle_data_in(struct icl_pdu 
                 * but initiators and targets MUST be able to properly receive
                 * 0 length data segments."
                 */
+               ISCSI_SESSION_UNLOCK(is);
                icl_pdu_free(response);
                return;
        }
@@ -1007,6 +1014,7 @@ iscsi_pdu_handle_data_in(struct icl_pdu 
                    io->io_received, (size_t)ntohl(bhsdi->bhsdi_buffer_offset));
                icl_pdu_free(response);
                iscsi_session_reconnect(is);
+               ISCSI_SESSION_UNLOCK(is);
                return;
        }
 
@@ -1018,11 +1026,17 @@ iscsi_pdu_handle_data_in(struct icl_pdu 
                    data_segment_len, io->io_received, csio->dxfer_len);
                icl_pdu_free(response);
                iscsi_session_reconnect(is);
+               ISCSI_SESSION_UNLOCK(is);
                return;
        }
 
-       icl_pdu_get_data(response, 0, csio->data_ptr + io->io_received, 
data_segment_len);
+       received = io->io_received;
        io->io_received += data_segment_len;
+       if ((bhsdi->bhsdi_flags & BHSDI_FLAGS_S) != 0)
+               iscsi_outstanding_remove(is, io);
+       ISCSI_SESSION_UNLOCK(is);
+
+       icl_pdu_get_data(response, 0, csio->data_ptr + received, 
data_segment_len);
 
        /*
         * XXX: Check DataSN.
@@ -1064,7 +1078,6 @@ iscsi_pdu_handle_data_in(struct icl_pdu 
        }
 
        xpt_done(io->io_ccb);
-       iscsi_outstanding_remove(is, io);
        icl_pdu_free(response);
 }
 
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to