summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorCharles Ting <Charles.Ting@Sun.COM>2009-08-05 15:31:33 -0400
committerCharles Ting <Charles.Ting@Sun.COM>2009-08-05 15:31:33 -0400
commit562610838fe0b8fdbe99a91a1dc13e77da2b6546 (patch)
tree8eb494ff80713ae7dfd23159de670ec4c9aa120f /usr/src
parent89f9eb8701145fa396cfc2ac0b468bd5c8466494 (diff)
downloadillumos-joyent-562610838fe0b8fdbe99a91a1dc13e77da2b6546.tar.gz
6740060 iscsit does not send or handle MaxRecvDataSegmentLength key properly
6862789 memory leak in stmfGetSessionList()
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/lib/libstmf/common/stmf.c11
-rw-r--r--usr/src/uts/common/io/comstar/port/iscsit/iscsit.h1
-rw-r--r--usr/src/uts/common/io/comstar/port/iscsit/iscsit_login.c89
-rw-r--r--usr/src/uts/common/io/ib/clients/iser/iser_idm.c30
-rw-r--r--usr/src/uts/common/io/idm/idm.c14
-rw-r--r--usr/src/uts/common/io/idm/idm_so.c71
-rw-r--r--usr/src/uts/common/sys/idm/idm.h4
-rw-r--r--usr/src/uts/common/sys/idm/idm_impl.h3
-rw-r--r--usr/src/uts/common/sys/idm/idm_transport.h5
9 files changed, 206 insertions, 22 deletions
diff --git a/usr/src/lib/libstmf/common/stmf.c b/usr/src/lib/libstmf/common/stmf.c
index d3fdef86ad..0ee2bebc38 100644
--- a/usr/src/lib/libstmf/common/stmf.c
+++ b/usr/src/lib/libstmf/common/stmf.c
@@ -3541,7 +3541,7 @@ stmfGetSessionList(stmfDevid *devid, stmfSessionList **sessionList)
int cmd = STMF_IOCTL_SESSION_LIST;
int i;
stmf_iocdata_t stmfIoctl;
- slist_scsi_session_t *fSessionList;
+ slist_scsi_session_t *fSessionList, *fSessionListP = NULL;
uint8_t ident[260];
uint32_t fSessionListSize;
@@ -3567,8 +3567,10 @@ stmfGetSessionList(stmfDevid *devid, stmfSessionList **sessionList)
fSessionListSize = ALLOC_SESSION;
fSessionListSize = fSessionListSize * (sizeof (slist_scsi_session_t));
fSessionList = (slist_scsi_session_t *)calloc(1, fSessionListSize);
+ fSessionListP = fSessionList;
if (fSessionList == NULL) {
- return (STMF_ERROR_NOMEM);
+ ret = STMF_ERROR_NOMEM;
+ goto done;
}
ident[IDENT_LENGTH_BYTE] = devid->identLength;
@@ -3611,8 +3613,10 @@ stmfGetSessionList(stmfDevid *devid, stmfSessionList **sessionList)
sizeof (slist_scsi_session_t);
fSessionList = realloc(fSessionList, fSessionListSize);
if (fSessionList == NULL) {
- return (STMF_ERROR_NOMEM);
+ ret = STMF_ERROR_NOMEM;
+ goto done;
}
+ fSessionListP = fSessionList;
stmfIoctl.stmf_obuf_size = fSessionListSize;
stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fSessionList;
ioctlRet = ioctl(fd, cmd, &stmfIoctl);
@@ -3667,6 +3671,7 @@ stmfGetSessionList(stmfDevid *devid, stmfSessionList **sessionList)
}
done:
(void) close(fd);
+ free(fSessionListP);
return (ret);
}
diff --git a/usr/src/uts/common/io/comstar/port/iscsit/iscsit.h b/usr/src/uts/common/io/comstar/port/iscsit/iscsit.h
index 1c8fd4c447..057a8fdd00 100644
--- a/usr/src/uts/common/io/comstar/port/iscsit/iscsit.h
+++ b/usr/src/uts/common/io/comstar/port/iscsit/iscsit.h
@@ -44,6 +44,7 @@
#define ISCSIT_MAX_TIME2RETAIN ISCSI_DEFAULT_TIME_TO_RETAIN
#define ISCSIT_MAX_OUTSTANDING_R2T ISCSI_DEFAULT_MAX_OUT_R2T
#define ISCSIT_MAX_ERROR_RECOVERY_LEVEL 0
+#define ISCSIT_MAX_OUTSTANDING_UNEXPECTED_PDUS 0
#define ISCSIT_DEFAULT_TPG "iscsit-default-tpg"
#define ISCSIT_DEFAULT_TPGT 1
diff --git a/usr/src/uts/common/io/comstar/port/iscsit/iscsit_login.c b/usr/src/uts/common/io/comstar/port/iscsit/iscsit_login.c
index 17bd889f64..63d519ffb7 100644
--- a/usr/src/uts/common/io/comstar/port/iscsit/iscsit_login.c
+++ b/usr/src/uts/common/io/comstar/port/iscsit/iscsit_login.c
@@ -189,6 +189,11 @@ iscsit_process_negotiated_values(iscsit_conn_t *ict);
static void
login_resp_complete_cb(idm_pdu_t *pdu, idm_status_t status);
+static idm_status_t
+iscsit_add_declarative_keys(iscsit_conn_t *ict);
+
+uint64_t max_dataseglen_target = ISCSIT_MAX_RECV_DATA_SEGMENT_LENGTH;
+
idm_status_t
iscsit_login_sm_init(iscsit_conn_t *ict)
{
@@ -1000,6 +1005,10 @@ login_sm_process_request(iscsit_conn_t *ict)
(void) iscsit_reply_numerical(ict,
"TargetPortalGroupTag",
(uint64_t)lsm->icl_tpgt_tag);
+ if (iscsit_add_declarative_keys(ict) !=
+ IDM_STATUS_SUCCESS) {
+ goto request_fail;
+ }
}
ict->ict_op.op_initial_params_set = B_TRUE;
@@ -2261,11 +2270,12 @@ iscsit_handle_operational_key(iscsit_conn_t *ict, nvpair_t *nvp,
ISCSI_MAX_CONNECTIONS,
ISCSIT_MAX_CONNECTIONS);
break;
+ /* this is a declartive param */
case KI_MAX_RECV_DATA_SEGMENT_LENGTH:
kvrc = iscsit_handle_numerical(ict, nvp, num_val, ikvx,
ISCSI_MIN_RECV_DATA_SEGMENT_LENGTH,
ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH,
- ISCSIT_MAX_RECV_DATA_SEGMENT_LENGTH);
+ ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH);
break;
case KI_MAX_BURST_LENGTH:
kvrc = iscsit_handle_numerical(ict, nvp, num_val, ikvx,
@@ -2412,22 +2422,27 @@ iscsit_handle_boolean(iscsit_conn_t *ict, nvpair_t *nvp, boolean_t value,
kv_status_t kvrc;
int nvrc;
- if (value != iscsit_value) {
- /* Respond back to initiator with our value */
- value = iscsit_value;
- lsm->icl_login_transit = B_FALSE;
- nvrc = 0;
+ if (ikvx->ik_declarative) {
+ nvrc = nvlist_add_nvpair(lsm->icl_negotiated_values, nvp);
} else {
- /* Add this to our negotiated values */
- nvrc = nvlist_add_nvpair(lsm->icl_negotiated_values,
- nvp);
- }
+ if (value != iscsit_value) {
+ /* Respond back to initiator with our value */
+ value = iscsit_value;
+ lsm->icl_login_transit = B_FALSE;
+ nvrc = 0;
+ } else {
+ /* Add this to our negotiated values */
+ nvrc = nvlist_add_nvpair(lsm->icl_negotiated_values,
+ nvp);
+ }
- /* Response of Simple-value Negotiation */
- if (nvrc == 0 && !ikvx->ik_declarative) {
- nvrc = nvlist_add_boolean_value(
- lsm->icl_response_nvlist, ikvx->ik_key_name, value);
+ /* Response of Simple-value Negotiation */
+ if (nvrc == 0) {
+ nvrc = nvlist_add_boolean_value(
+ lsm->icl_response_nvlist, ikvx->ik_key_name, value);
+ }
}
+
kvrc = idm_nvstat_to_kvstat(nvrc);
return (kvrc);
@@ -2446,6 +2461,9 @@ iscsit_handle_numerical(iscsit_conn_t *ict, nvpair_t *nvp, uint64_t value,
/* Validate against standard */
if ((value < iscsi_min_value) || (value > iscsi_max_value)) {
kvrc = KV_VALUE_ERROR;
+ } else if (ikvx->ik_declarative) {
+ nvrc = nvlist_add_nvpair(lsm->icl_negotiated_values, nvp);
+ kvrc = idm_nvstat_to_kvstat(nvrc);
} else {
if (value > iscsit_max_value) {
/* Respond back to initiator with our value */
@@ -2459,7 +2477,7 @@ iscsit_handle_numerical(iscsit_conn_t *ict, nvpair_t *nvp, uint64_t value,
}
/* Response of Simple-value Negotiation */
- if (nvrc == 0 && !ikvx->ik_declarative) {
+ if (nvrc == 0) {
nvrc = nvlist_add_uint64(lsm->icl_response_nvlist,
ikvx->ik_key_name, value);
}
@@ -2577,3 +2595,44 @@ iscsit_process_negotiated_values(iscsit_conn_t *ict)
ict->ict_op.op_error_recovery_level = uint64_val;
}
}
+
+static idm_status_t
+iscsit_add_declarative_keys(iscsit_conn_t *ict)
+{
+ nvlist_t *cfg_nv = NULL;
+ kv_status_t kvrc;
+ int nvrc;
+ iscsit_conn_login_t *lsm = &ict->ict_login_sm;
+ uint8_t error_class;
+ uint8_t error_detail;
+ idm_status_t idm_status;
+
+ if ((nvrc = nvlist_alloc(&cfg_nv, NV_UNIQUE_NAME, KM_NOSLEEP)) != 0) {
+ kvrc = idm_nvstat_to_kvstat(nvrc);
+ goto alloc_fail;
+ }
+ if ((nvrc = nvlist_add_uint64(cfg_nv, "MaxRecvDataSegmentLength",
+ max_dataseglen_target)) != 0) {
+ kvrc = idm_nvstat_to_kvstat(nvrc);
+ goto done;
+ }
+ if ((nvrc = nvlist_add_uint64(cfg_nv, "MaxOutstandingUnexpectedPDUs",
+ ISCSIT_MAX_OUTSTANDING_UNEXPECTED_PDUS)) != 0) {
+ kvrc = idm_nvstat_to_kvstat(nvrc);
+ goto done;
+ }
+
+ kvrc = idm_declare_key_values(ict->ict_ic, cfg_nv,
+ lsm->icl_response_nvlist);
+done:
+ nvlist_free(cfg_nv);
+alloc_fail:
+ idm_kvstat_to_error(kvrc, &error_class, &error_detail);
+ if (error_class == ISCSI_STATUS_CLASS_SUCCESS) {
+ idm_status = IDM_STATUS_SUCCESS;
+ } else {
+ SET_LOGIN_ERROR(ict, error_class, error_detail);
+ idm_status = IDM_STATUS_FAIL;
+ }
+ return (idm_status);
+}
diff --git a/usr/src/uts/common/io/ib/clients/iser/iser_idm.c b/usr/src/uts/common/io/ib/clients/iser/iser_idm.c
index a153a6e94d..c1610ab738 100644
--- a/usr/src/uts/common/io/ib/clients/iser/iser_idm.c
+++ b/usr/src/uts/common/io/ib/clients/iser/iser_idm.c
@@ -48,6 +48,8 @@ static idm_status_t iser_tgt_enable_datamover(idm_conn_t *ic);
static idm_status_t iser_ini_enable_datamover(idm_conn_t *ic);
static void iser_notice_key_values(struct idm_conn_s *ic,
nvlist_t *negotiated_nvl);
+static kv_status_t iser_declare_key_values(struct idm_conn_s *ic,
+ nvlist_t *config_nvl, nvlist_t *outgoing_nvl);
static idm_status_t iser_free_task_rsrcs(idm_task_t *idt);
static kv_status_t iser_negotiate_key_values(idm_conn_t *ic,
nvlist_t *request_nvl, nvlist_t *response_nvl, nvlist_t *negotiated_nvl);
@@ -114,7 +116,8 @@ idm_transport_ops_t iser_transport_ops = {
&iser_ini_conn_create, /* it_ini_conn_create */
&iser_conn_destroy, /* it_ini_conn_destroy */
&iser_ini_conn_connect, /* it_ini_conn_connect */
- &iser_conn_disconnect /* it_ini_conn_disconnect */
+ &iser_conn_disconnect, /* it_ini_conn_disconnect */
+ &iser_declare_key_values /* it_declare_key_values */
};
/*
@@ -841,6 +844,31 @@ iser_handle_numerical(nvpair_t *nvp, uint64_t value, const idm_kv_xlate_t *ikvx,
}
/*
+ * iser_declare_key_values() declares the declarative key values for
+ * this connection.
+ */
+/* ARGSUSED */
+static kv_status_t
+iser_declare_key_values(idm_conn_t *ic, nvlist_t *config_nvl,
+ nvlist_t *outgoing_nvl)
+{
+ kv_status_t kvrc;
+ int nvrc;
+ uint64_t uint64_val;
+
+ if ((nvrc = nvlist_lookup_uint64(config_nvl,
+ ISER_KV_KEY_NAME_MAX_OUTSTANDING_PDU, &uint64_val)) != ENOENT) {
+ ASSERT(nvrc == 0);
+ if (outgoing_nvl) {
+ nvrc = nvlist_add_uint64(outgoing_nvl,
+ ISER_KV_KEY_NAME_MAX_OUTSTANDING_PDU, uint64_val);
+ }
+ }
+ kvrc = idm_nvstat_to_kvstat(nvrc);
+ return (kvrc);
+}
+
+/*
* iser_notice_key_values() activates the negotiated key values for
* this connection.
*/
diff --git a/usr/src/uts/common/io/idm/idm.c b/usr/src/uts/common/io/idm/idm.c
index e739f381bb..8e3810c2a7 100644
--- a/usr/src/uts/common/io/idm/idm.c
+++ b/usr/src/uts/common/io/idm/idm.c
@@ -656,6 +656,20 @@ idm_notice_key_values(idm_conn_t *ic, nvlist_t *negotiated_nvl)
}
/*
+ * idm_declare_key_values()
+ * Activate an operational set of declarative parameters from the config_nvl,
+ * and return the selected values in the outgoing_nvl.
+ */
+kv_status_t
+idm_declare_key_values(idm_conn_t *ic, nvlist_t *config_nvl,
+ nvlist_t *outgoing_nvl)
+{
+ ASSERT(ic->ic_transport_ops != NULL);
+ return (ic->ic_transport_ops->it_declare_key_values(ic, config_nvl,
+ outgoing_nvl));
+}
+
+/*
* idm_buf_tx_to_ini
*
* This is IDM's implementation of the 'Put_Data' operational primitive.
diff --git a/usr/src/uts/common/io/idm/idm_so.c b/usr/src/uts/common/io/idm/idm_so.c
index 3de76e352e..c032e1d328 100644
--- a/usr/src/uts/common/io/idm/idm_so.c
+++ b/usr/src/uts/common/io/idm/idm_so.c
@@ -46,6 +46,7 @@
#include <net/if.h>
#include <sys/sockio.h>
#include <sys/ksocket.h>
+#include <sys/iscsi_protocol.h>
#include <sys/idm/idm.h>
#include <sys/idm/idm_so.h>
#include <sys/idm/idm_text.h>
@@ -101,6 +102,8 @@ static kv_status_t idm_so_negotiate_key_values(idm_conn_t *it,
nvlist_t *request_nvl, nvlist_t *response_nvl, nvlist_t *negotiated_nvl);
static void idm_so_notice_key_values(idm_conn_t *it,
nvlist_t *negotiated_nvl);
+static kv_status_t idm_so_declare_key_values(idm_conn_t *it,
+ nvlist_t *config_nvl, nvlist_t *outgoing_nvl);
static boolean_t idm_so_conn_is_capable(idm_conn_req_t *ic,
idm_transport_caps_t *caps);
static idm_status_t idm_so_buf_alloc(idm_buf_t *idb, uint64_t buflen);
@@ -152,7 +155,8 @@ idm_transport_ops_t idm_so_transport_ops = {
idm_so_ini_conn_create, /* it_ini_conn_create */
idm_so_ini_conn_destroy, /* it_ini_conn_destroy */
idm_so_ini_conn_connect, /* it_ini_conn_connect */
- idm_so_conn_disconnect /* it_ini_conn_disconnect */
+ idm_so_conn_disconnect, /* it_ini_conn_disconnect */
+ idm_so_declare_key_values /* it_declare_key_values */
};
/*
@@ -760,6 +764,12 @@ idm_sorecvhdr(idm_conn_t *ic, idm_pdu_t *pdu)
pdu->isp_hdrlen = sizeof (iscsi_hdr_t) +
(bhs->hlength * sizeof (uint32_t));
pdu->isp_datalen = n2h24(bhs->dlength);
+ if (ic->ic_conn_type == CONN_TYPE_TGT &&
+ pdu->isp_datalen > ic->ic_conn_params.max_recv_dataseglen) {
+ IDM_CONN_LOG(CE_WARN,
+ "idm_sorecvhdr: exceeded the max data segment length");
+ return (IDM_STATUS_FAIL);
+ }
if (bhs->hlength > IDM_SORX_CACHE_AHSLEN) {
/* Allocate a new header segment and change the callback */
new_hdr = kmem_alloc(pdu->isp_hdrlen, KM_SLEEP);
@@ -985,6 +995,10 @@ idm_so_conn_create_common(idm_conn_t *ic, ksocket_t new_so)
/* Set the scoreboarding flag on this connection */
ic->ic_conn_flags |= IDM_CONN_USE_SCOREBOARD;
+ ic->ic_conn_params.max_recv_dataseglen =
+ ISCSI_DEFAULT_MAX_RECV_SEG_LEN;
+ ic->ic_conn_params.max_xmit_dataseglen =
+ ISCSI_DEFAULT_MAX_XMIT_SEG_LEN;
/*
* Initialize tx thread mutex and list
@@ -1380,6 +1394,7 @@ idm_so_notice_key_values(idm_conn_t *it, nvlist_t *negotiated_nvl)
int nvrc;
idm_status_t idm_status;
const idm_kv_xlate_t *ikvx;
+ uint64_t num_val;
for (nvp = nvlist_next_nvpair(negotiated_nvl, NULL);
nvp != NULL; nvp = next_nvp) {
@@ -1398,12 +1413,64 @@ idm_so_notice_key_values(idm_conn_t *it, nvlist_t *negotiated_nvl)
negotiated_nvl, ikvx->ik_key_name);
ASSERT(nvrc == 0);
break;
+ case KI_MAX_RECV_DATA_SEGMENT_LENGTH:
+ /*
+ * Just pass the value down to idm layer.
+ * No need to remove it from negotiated_nvl list here.
+ */
+ nvrc = nvpair_value_uint64(nvp, &num_val);
+ ASSERT(nvrc == 0);
+ it->ic_conn_params.max_xmit_dataseglen =
+ (uint32_t)num_val;
+ break;
default:
break;
}
}
}
+/*
+ * idm_so_declare_key_values() declares the key values for this connection
+ */
+/* ARGSUSED */
+static kv_status_t
+idm_so_declare_key_values(idm_conn_t *it, nvlist_t *config_nvl,
+ nvlist_t *outgoing_nvl)
+{
+ char *nvp_name;
+ nvpair_t *nvp;
+ nvpair_t *next_nvp;
+ kv_status_t kvrc;
+ int nvrc = 0;
+ const idm_kv_xlate_t *ikvx;
+ uint64_t num_val;
+
+ for (nvp = nvlist_next_nvpair(config_nvl, NULL);
+ nvp != NULL && nvrc == 0; nvp = next_nvp) {
+ next_nvp = nvlist_next_nvpair(config_nvl, nvp);
+ nvp_name = nvpair_name(nvp);
+
+ ikvx = idm_lookup_kv_xlate(nvp_name, strlen(nvp_name));
+ switch (ikvx->ik_key_id) {
+ case KI_MAX_RECV_DATA_SEGMENT_LENGTH:
+ if ((nvrc = nvpair_value_uint64(nvp, &num_val)) != 0) {
+ break;
+ }
+ if (outgoing_nvl &&
+ (nvrc = nvlist_add_uint64(outgoing_nvl,
+ nvp_name, num_val)) != 0) {
+ break;
+ }
+ it->ic_conn_params.max_recv_dataseglen =
+ (uint32_t)num_val;
+ break;
+ default:
+ break;
+ }
+ }
+ kvrc = idm_nvstat_to_kvstat(nvrc);
+ return (kvrc);
+}
static idm_status_t
idm_so_handle_digest(idm_conn_t *it, nvpair_t *digest_choice,
@@ -2489,7 +2556,7 @@ idm_so_send_buf_region(idm_task_t *idt, idm_buf_t *idb,
ic = idt->idt_ic;
- max_dataseglen = 8192; /* Need value from login negotiation */
+ max_dataseglen = ic->ic_conn_params.max_xmit_dataseglen;
remainder = buf_region_length;
while (remainder) {
diff --git a/usr/src/uts/common/sys/idm/idm.h b/usr/src/uts/common/sys/idm/idm.h
index 3ce26a064b..cb5e256ef3 100644
--- a/usr/src/uts/common/sys/idm/idm.h
+++ b/usr/src/uts/common/sys/idm/idm.h
@@ -380,6 +380,10 @@ idm_negotiate_key_values(idm_conn_t *ic, nvlist_t *request_nvl,
void
idm_notice_key_values(idm_conn_t *ic, nvlist_t *negotiated_nvl);
+kv_status_t
+idm_declare_key_values(idm_conn_t *ic, nvlist_t *config_nvl,
+ nvlist_t *outgoing_nvl);
+
/*
* Buffer services
*/
diff --git a/usr/src/uts/common/sys/idm/idm_impl.h b/usr/src/uts/common/sys/idm/idm_impl.h
index b2e70264f1..ef507ed3be 100644
--- a/usr/src/uts/common/sys/idm/idm_impl.h
+++ b/usr/src/uts/common/sys/idm/idm_impl.h
@@ -122,7 +122,8 @@ typedef struct idm_refcnt_s {
* connection create, or during key-value negotiation at login
*/
typedef struct idm_conn_params_s {
- uint32_t max_dataseglen;
+ uint32_t max_recv_dataseglen;
+ uint32_t max_xmit_dataseglen;
uint32_t conn_login_max;
uint32_t conn_login_interval;
boolean_t nonblock_socket;
diff --git a/usr/src/uts/common/sys/idm/idm_transport.h b/usr/src/uts/common/sys/idm/idm_transport.h
index 4ad106e84a..03bdb00d77 100644
--- a/usr/src/uts/common/sys/idm/idm_transport.h
+++ b/usr/src/uts/common/sys/idm/idm_transport.h
@@ -109,6 +109,10 @@ typedef kv_status_t (transport_negotiate_key_values_op_t)(struct
typedef void (transport_notice_key_values_op_t)(struct idm_conn_s *ic,
nvlist_t *negotiated_nvl);
+/* Declare the declarative key value pairs */
+typedef kv_status_t (transport_declare_key_values_op_t)(struct idm_conn_s *ic,
+ nvlist_t *config_nvl, nvlist_t *outgoing_nvl);
+
/* Transport capability probe */
typedef boolean_t (transport_conn_is_capable_op_t)(idm_conn_req_t *ic,
struct idm_transport_caps_s *caps);
@@ -178,6 +182,7 @@ typedef struct idm_transport_ops_s {
transport_ini_conn_destroy_op_t *it_ini_conn_destroy;
transport_ini_conn_connect_op_t *it_ini_conn_connect;
transport_ini_conn_disconnect_op_t *it_ini_conn_disconnect;
+ transport_declare_key_values_op_t *it_declare_key_values;
} idm_transport_ops_t;
/*