Page MenuHomeFreeBSD

D7279.id18648.diff
No OneTemporary

D7279.id18648.diff

Index: sys/cam/ctl/ctl_frontend_iscsi.h
===================================================================
--- sys/cam/ctl/ctl_frontend_iscsi.h
+++ sys/cam/ctl/ctl_frontend_iscsi.h
@@ -84,7 +84,8 @@
struct cv cs_maintenance_cv;
bool cs_terminating;
bool cs_tasks_aborted;
- size_t cs_max_data_segment_length;
+ size_t cs_max_recv_data_segment_length;
+ size_t cs_max_send_data_segment_length;
size_t cs_max_burst_length;
size_t cs_first_burst_length;
bool cs_immediate_data;
Index: sys/cam/ctl/ctl_frontend_iscsi.c
===================================================================
--- sys/cam/ctl/ctl_frontend_iscsi.c
+++ sys/cam/ctl/ctl_frontend_iscsi.c
@@ -1512,7 +1512,8 @@
*/
cs->cs_cmdsn = cihp->cmdsn;
cs->cs_statsn = cihp->statsn;
- cs->cs_max_data_segment_length = cihp->max_recv_data_segment_length;
+ cs->cs_max_recv_data_segment_length = cihp->max_recv_data_segment_length;
+ cs->cs_max_send_data_segment_length = cihp->max_send_data_segment_length;
cs->cs_max_burst_length = cihp->max_burst_length;
cs->cs_first_burst_length = cihp->first_burst_length;
cs->cs_immediate_data = !!cihp->immediate_data;
@@ -1652,7 +1653,8 @@
"<target_portal_group_tag>%u</target_portal_group_tag>"
"<header_digest>%s</header_digest>"
"<data_digest>%s</data_digest>"
- "<max_data_segment_length>%zd</max_data_segment_length>"
+ "<max_recv_data_segment_length>%zd</max_recv_data_segment_length>"
+ "<max_send_data_segment_length>%zd</max_send_data_segment_length>"
"<max_burst_length>%zd</max_burst_length>"
"<first_burst_length>%zd</first_burst_length>"
"<immediate_data>%d</immediate_data>"
@@ -1665,7 +1667,8 @@
cs->cs_target->ct_tag,
cs->cs_conn->ic_header_crc32c ? "CRC32C" : "None",
cs->cs_conn->ic_data_crc32c ? "CRC32C" : "None",
- cs->cs_max_data_segment_length,
+ cs->cs_max_recv_data_segment_length,
+ cs->cs_max_send_data_segment_length,
cs->cs_max_burst_length,
cs->cs_first_burst_length,
cs->cs_immediate_data,
@@ -1794,12 +1797,12 @@
cfiscsi_ioctl_limits(struct ctl_iscsi *ci)
{
struct ctl_iscsi_limits_params *cilp;
+ struct icl_drv_limits idl;
int error;
cilp = (struct ctl_iscsi_limits_params *)&(ci->data);
- error = icl_limits(cilp->offload, false,
- &cilp->data_segment_limit);
+ error = icl_limits(cilp->offload, false, &idl);
if (error != 0) {
ci->status = CTL_ISCSI_ERROR;
snprintf(ci->error_str, sizeof(ci->error_str),
@@ -1808,6 +1811,11 @@
return;
}
+ cilp->max_recv_data_segment_length = idl.max_recv_data_segment_length;
+ cilp->max_send_data_segment_length = idl.max_send_data_segment_length;
+ cilp->max_burst_length = idl.max_burst_length;
+ cilp->first_burst_length = idl.first_burst_length;
+
ci->status = CTL_ISCSI_OK;
}
@@ -2466,12 +2474,12 @@
/*
* Truncate to maximum data segment length.
*/
- KASSERT(response->ip_data_len < cs->cs_max_data_segment_length,
- ("ip_data_len %zd >= max_data_segment_length %zd",
- response->ip_data_len, cs->cs_max_data_segment_length));
+ KASSERT(response->ip_data_len < cs->cs_max_send_data_segment_length,
+ ("ip_data_len %zd >= max_send_data_segment_length %zd",
+ response->ip_data_len, cs->cs_max_send_data_segment_length));
if (response->ip_data_len + len >
- cs->cs_max_data_segment_length) {
- len = cs->cs_max_data_segment_length -
+ cs->cs_max_send_data_segment_length) {
+ len = cs->cs_max_send_data_segment_length -
response->ip_data_len;
KASSERT(len <= sg_len, ("len %zd > sg_len %zd",
len, sg_len));
@@ -2529,7 +2537,7 @@
i++;
}
- if (response->ip_data_len == cs->cs_max_data_segment_length) {
+ if (response->ip_data_len == cs->cs_max_send_data_segment_length) {
/*
* Can't stuff more data into the current PDU;
* queue it. Note that's not enough to check
Index: sys/cam/ctl/ctl_ioctl.h
===================================================================
--- sys/cam/ctl/ctl_ioctl.h
+++ sys/cam/ctl/ctl_ioctl.h
@@ -622,7 +622,7 @@
char target_name[CTL_ISCSI_NAME_LEN];
int socket;
int portal_group_tag;
-
+
/*
* Connection parameters negotiated by ctld(8).
*/
@@ -637,10 +637,10 @@
char offload[CTL_ISCSI_OFFLOAD_LEN];
#ifdef ICL_KERNEL_PROXY
int connection_id;
- int spare[1];
#else
- int spare[2];
+ int spare;
#endif
+ int max_send_data_segment_length;
};
struct ctl_iscsi_list_params {
@@ -671,11 +671,15 @@
};
struct ctl_iscsi_limits_params {
+ /* passed to kernel */
char offload[CTL_ISCSI_OFFLOAD_LEN];
- /* passed to kernel */
- size_t data_segment_limit;
- /* passed to userland */
- int spare[4];
+
+ /* passed to userland */
+ size_t spare;
+ int max_recv_data_segment_length;
+ int max_send_data_segment_length;
+ int max_burst_length;
+ int first_burst_length;
};
#ifdef ICL_KERNEL_PROXY
Index: sys/dev/cxgbe/cxgbei/icl_cxgbei.c
===================================================================
--- sys/dev/cxgbe/cxgbei/icl_cxgbei.c
+++ sys/dev/cxgbe/cxgbei/icl_cxgbei.c
@@ -832,10 +832,13 @@
}
static int
-icl_cxgbei_limits(size_t *limitp)
+icl_cxgbei_limits(struct icl_drv_limits *idl)
{
- *limitp = CXGBEI_MAX_DSL;
+ idl->max_recv_data_segment_length = CXGBEI_MAX_DSL;
+ idl->max_send_data_segment_length = CXGBEI_MAX_DSL;
+ idl->max_burst_length = 2 * 1024 * 1024;
+ idl->first_burst_length = CXGBEI_MAX_DSL;
return (0);
}
Index: sys/dev/iscsi/icl.h
===================================================================
--- sys/dev/iscsi/icl.h
+++ sys/dev/iscsi/icl.h
@@ -126,12 +126,19 @@
void *ic_prv0;
};
+struct icl_drv_limits {
+ int max_recv_data_segment_length;
+ int max_send_data_segment_length;
+ int max_burst_length;
+ int first_burst_length;
+};
+
struct icl_conn *icl_new_conn(const char *offload, bool iser, const char *name,
struct mtx *lock);
-int icl_limits(const char *offload, bool iser, size_t *limitp);
-
+int icl_limits(const char *offload, bool iser,
+ struct icl_drv_limits *idl);
int icl_register(const char *offload, bool iser, int priority,
- int (*limits)(size_t *),
+ int (*limits)(struct icl_drv_limits *),
struct icl_conn *(*new_conn)(const char *, struct mtx *));
int icl_unregister(const char *offload, bool rdma);
Index: sys/dev/iscsi/icl.c
===================================================================
--- sys/dev/iscsi/icl.c
+++ sys/dev/iscsi/icl.c
@@ -59,7 +59,7 @@
char *im_name;
bool im_iser;
int im_priority;
- int (*im_limits)(size_t *limitp);
+ int (*im_limits)(struct icl_drv_limits *idl);
struct icl_conn *(*im_new_conn)(const char *name,
struct mtx *lock);
};
@@ -182,11 +182,12 @@
}
int
-icl_limits(const char *offload, bool iser, size_t *limitp)
+icl_limits(const char *offload, bool iser, struct icl_drv_limits *idl)
{
struct icl_module *im;
int error;
+ bzero(idl, sizeof(*idl));
sx_slock(&sc->sc_lock);
im = icl_find(offload, iser, false);
if (im == NULL) {
@@ -194,14 +195,42 @@
return (ENXIO);
}
- error = im->im_limits(limitp);
+ error = im->im_limits(idl);
sx_sunlock(&sc->sc_lock);
+ /*
+ * Validate the limits provided by the driver against values allowed by
+ * the iSCSI RFC. 0 means iscsid/ctld should pick a reasonable value.
+ *
+ * Note that max_send_dsl is an internal implementation detail and not
+ * part of the RFC.
+ */
+#define OUT_OF_RANGE(x, lo, hi) ((x) != 0 && ((x) < (lo) || (x) > (hi)))
+ if (error == 0 &&
+ (OUT_OF_RANGE(idl->max_recv_data_segment_length, 512, 16777215) ||
+ OUT_OF_RANGE(idl->max_send_data_segment_length, 512, 16777215) ||
+ OUT_OF_RANGE(idl->max_burst_length, 512, 16777215) ||
+ OUT_OF_RANGE(idl->first_burst_length, 512, 16777215))) {
+ error = EINVAL;
+ }
+#undef OUT_OF_RANGE
+
+ /*
+ * If both first_burst and max_burst are provided then first_burst must
+ * not exceed max_burst.
+ */
+ if (error == 0 && idl->first_burst_length > 0 &&
+ idl->max_burst_length > 0 &&
+ idl->first_burst_length > idl->max_burst_length) {
+ error = EINVAL;
+ }
+
return (error);
}
int
-icl_register(const char *offload, bool iser, int priority, int (*limits)(size_t *),
+icl_register(const char *offload, bool iser, int priority,
+ int (*limits)(struct icl_drv_limits *),
struct icl_conn *(*new_conn)(const char *, struct mtx *))
{
struct icl_module *im;
Index: sys/dev/iscsi/icl_soft.c
===================================================================
--- sys/dev/iscsi/icl_soft.c
+++ sys/dev/iscsi/icl_soft.c
@@ -1474,10 +1474,10 @@
}
static int
-icl_soft_limits(size_t *limitp)
+icl_soft_limits(struct icl_drv_limits *idl)
{
- *limitp = 128 * 1024;
+ idl->max_recv_data_segment_length = 128 * 1024;
return (0);
}
Index: sys/dev/iscsi/iscsi.h
===================================================================
--- sys/dev/iscsi/iscsi.h
+++ sys/dev/iscsi/iscsi.h
@@ -67,7 +67,8 @@
uint8_t is_isid[6];
uint16_t is_tsih;
bool is_immediate_data;
- size_t is_max_data_segment_length;
+ size_t is_max_recv_data_segment_length;
+ size_t is_max_send_data_segment_length;
char is_target_alias[ISCSI_ALIAS_LEN];
TAILQ_HEAD(, iscsi_outstanding) is_outstanding;
Index: sys/dev/iscsi/iscsi.c
===================================================================
--- sys/dev/iscsi/iscsi.c
+++ sys/dev/iscsi/iscsi.c
@@ -1204,8 +1204,8 @@
for (;;) {
len = total_len;
- if (len > is->is_max_data_segment_length)
- len = is->is_max_data_segment_length;
+ if (len > is->is_max_send_data_segment_length)
+ len = is->is_max_send_data_segment_length;
if (off + len > csio->dxfer_len) {
ISCSI_SESSION_WARN(is, "target requested invalid "
@@ -1313,6 +1313,7 @@
struct iscsi_daemon_request *request)
{
struct iscsi_session *is;
+ struct icl_drv_limits idl;
int error;
sx_slock(&sc->sc_lock);
@@ -1352,10 +1353,9 @@
request->idr_tsih = 0; /* New or reinstated session. */
memcpy(&request->idr_conf, &is->is_conf,
sizeof(request->idr_conf));
-
+
error = icl_limits(is->is_conf.isc_offload,
- is->is_conf.isc_iser,
- &request->idr_limits.isl_max_data_segment_length);
+ is->is_conf.isc_iser, &idl);
if (error != 0) {
ISCSI_SESSION_WARN(is, "icl_limits for offload \"%s\" "
"failed with error %d", is->is_conf.isc_offload,
@@ -1363,6 +1363,13 @@
sx_sunlock(&sc->sc_lock);
return (error);
}
+ request->idr_limits.isl_max_recv_data_segment_length =
+ idl.max_recv_data_segment_length;
+ request->idr_limits.isl_max_send_data_segment_length =
+ idl.max_recv_data_segment_length;
+ request->idr_limits.isl_max_burst_length = idl.max_burst_length;
+ request->idr_limits.isl_first_burst_length =
+ idl.first_burst_length;
sx_sunlock(&sc->sc_lock);
return (0);
@@ -1417,12 +1424,12 @@
is->is_initial_r2t = handoff->idh_initial_r2t;
is->is_immediate_data = handoff->idh_immediate_data;
- /*
- * Cap MaxRecvDataSegmentLength obtained from the target to the maximum
- * size supported by our ICL module.
- */
- is->is_max_data_segment_length = min(ic->ic_max_data_segment_length,
- handoff->idh_max_data_segment_length);
+ /* XXXNP: what is icl_max_data_segment_length for anyway? */
+ MPASS(is->is_max_recv_data_segment_length <= ic->ic_max_data_segment_length);
+ is->is_max_recv_data_segment_length =
+ handoff->idh_max_recv_data_segment_length;
+ is->is_max_send_data_segment_length =
+ handoff->idh_max_send_data_segment_length;
is->is_max_burst_length = handoff->idh_max_burst_length;
is->is_first_burst_length = handoff->idh_first_burst_length;
@@ -1634,7 +1641,7 @@
return (EIO);
datalen = ids->ids_data_segment_len;
- if (datalen > ISCSI_MAX_DATA_SEGMENT_LENGTH)
+ if (datalen > is->is_max_send_data_segment_length)
return (EINVAL);
if (datalen > 0) {
data = malloc(datalen, M_ISCSI, M_WAITOK);
@@ -1933,12 +1940,13 @@
else
iss.iss_data_digest = ISCSI_DIGEST_NONE;
- iss.iss_max_data_segment_length = is->is_max_data_segment_length;
+ iss.iss_max_send_data_segment_length = is->is_max_send_data_segment_length;
+ iss.iss_max_recv_data_segment_length = is->is_max_recv_data_segment_length;
iss.iss_max_burst_length = is->is_max_burst_length;
iss.iss_first_burst_length = is->is_first_burst_length;
iss.iss_immediate_data = is->is_immediate_data;
iss.iss_connected = is->is_connected;
-
+
error = copyout(&iss, isl->isl_pstates + i, sizeof(iss));
if (error != 0) {
sx_sunlock(&sc->sc_lock);
@@ -2262,9 +2270,9 @@
ISCSI_SESSION_DEBUG(is, "len %zd -> %zd", len, is->is_first_burst_length);
len = is->is_first_burst_length;
}
- if (len > is->is_max_data_segment_length) {
- ISCSI_SESSION_DEBUG(is, "len %zd -> %zd", len, is->is_max_data_segment_length);
- len = is->is_max_data_segment_length;
+ if (len > is->is_max_send_data_segment_length) {
+ ISCSI_SESSION_DEBUG(is, "len %zd -> %zd", len, is->is_max_send_data_segment_length);
+ len = is->is_max_send_data_segment_length;
}
error = icl_pdu_append_data(request, csio->data_ptr, len, M_NOWAIT);
Index: sys/dev/iscsi/iscsi_ioctl.h
===================================================================
--- sys/dev/iscsi/iscsi_ioctl.h
+++ sys/dev/iscsi/iscsi_ioctl.h
@@ -76,8 +76,12 @@
* iscsid(8) must obey those when negotiating operational parameters.
*/
struct iscsi_session_limits {
- size_t isl_max_data_segment_length;
- int isl_spare[8];
+ size_t isl_spare0;
+ int isl_max_recv_data_segment_length;
+ int isl_max_send_data_segment_length;
+ int isl_max_burst_length;
+ int isl_first_burst_length;
+ int isl_spare[4];
};
/*
@@ -89,14 +93,15 @@
char iss_target_alias[ISCSI_ALIAS_LEN];
int iss_header_digest;
int iss_data_digest;
- int iss_max_data_segment_length;
+ int iss_max_recv_data_segment_length;
int iss_max_burst_length;
int iss_first_burst_length;
int iss_immediate_data;
int iss_connected;
char iss_reason[ISCSI_REASON_LEN];
char iss_offload[ISCSI_OFFLOAD_LEN];
- int iss_spare[4];
+ int iss_max_send_data_segment_length;
+ int iss_spare[3];
};
/*
@@ -122,12 +127,14 @@
uint32_t idh_statsn;
int idh_header_digest;
int idh_data_digest;
- size_t idh_max_data_segment_length;
+ size_t spare;
size_t idh_max_burst_length;
size_t idh_first_burst_length;
int idh_immediate_data;
int idh_initial_r2t;
- int idh_spare[4];
+ int idh_max_recv_data_segment_length;
+ int idh_max_send_data_segment_length;
+ int idh_spare2[2];
};
struct iscsi_daemon_fail {
Index: sys/dev/iser/icl_iser.c
===================================================================
--- sys/dev/iser/icl_iser.c
+++ sys/dev/iser/icl_iser.c
@@ -483,9 +483,9 @@
}
static int
-iser_limits(size_t *limitp)
+iser_limits(struct icl_drv_limits *idl)
{
- *limitp = 128 * 1024;
+ idl->max_recv_data_segment_length = 128 * 1024;
return (0);
}
Index: usr.bin/iscsictl/iscsictl.c
===================================================================
--- usr.bin/iscsictl/iscsictl.c
+++ usr.bin/iscsictl/iscsictl.c
@@ -565,8 +565,10 @@
"Data digest:",
state->iss_data_digest == ISCSI_DIGEST_CRC32C ?
"CRC32C" : "None");
- xo_emit("{L:/%-18s}{V:dataSegmentLen/%d}\n",
- "DataSegmentLen:", state->iss_max_data_segment_length);
+ xo_emit("{L:/%-18s}{V:recvDataSegmentLen/%d}\n",
+ "MaxRecvDSL:", state->iss_max_recv_data_segment_length);
+ xo_emit("{L:/%-18s}{V:sendDataSegmentLen/%d}\n",
+ "MaxSendDSL:", state->iss_max_send_data_segment_length);
xo_emit("{L:/%-18s}{V:maxBurstLen/%d}\n",
"MaxBurstLen:", state->iss_max_burst_length);
xo_emit("{L:/%-18s}{V:firstBurstLen/%d}\n",
Index: usr.sbin/ctladm/ctladm.c
===================================================================
--- usr.sbin/ctladm/ctladm.c
+++ usr.sbin/ctladm/ctladm.c
@@ -2794,7 +2794,8 @@
char *target_alias;
char *header_digest;
char *data_digest;
- char *max_data_segment_length;
+ char *max_recv_data_segment_length;
+ char *max_send_data_segment_length;
char *max_burst_length;
char *first_burst_length;
char *offload;
@@ -2908,8 +2909,11 @@
} else if (strcmp(name, "data_digest") == 0) {
cur_conn->data_digest = str;
str = NULL;
- } else if (strcmp(name, "max_data_segment_length") == 0) {
- cur_conn->max_data_segment_length = str;
+ } else if (strcmp(name, "max_recv_data_segment_length") == 0) {
+ cur_conn->max_recv_data_segment_length = str;
+ str = NULL;
+ } else if (strcmp(name, "max_send_data_segment_length") == 0) {
+ cur_conn->max_send_data_segment_length = str;
str = NULL;
} else if (strcmp(name, "max_burst_length") == 0) {
cur_conn->max_burst_length = str;
@@ -3038,7 +3042,8 @@
printf("Target alias: %s\n", conn->target_alias);
printf("Header digest: %s\n", conn->header_digest);
printf("Data digest: %s\n", conn->data_digest);
- printf("DataSegmentLen: %s\n", conn->max_data_segment_length);
+ printf("MaxRecvDSL: %s\n", conn->max_recv_data_segment_length);
+ printf("MaxSendDSL: %s\n", conn->max_send_data_segment_length);
printf("MaxBurstLen: %s\n", conn->max_burst_length);
printf("FirstBurstLen: %s\n", conn->first_burst_length);
printf("ImmediateData: %s\n", conn->immediate_data ? "Yes" : "No");
Index: usr.sbin/ctld/ctld.h
===================================================================
--- usr.sbin/ctld/ctld.h
+++ usr.sbin/ctld/ctld.h
@@ -242,8 +242,8 @@
struct sockaddr_storage conn_initiator_sa;
uint32_t conn_cmdsn;
uint32_t conn_statsn;
- size_t conn_data_segment_limit;
- size_t conn_max_data_segment_length;
+ size_t conn_max_recv_data_segment_length;
+ size_t conn_max_send_data_segment_length;
size_t conn_max_burst_length;
size_t conn_first_burst_length;
int conn_immediate_data;
@@ -404,7 +404,10 @@
int kernel_lun_remove(struct lun *lun);
void kernel_handoff(struct connection *conn);
void kernel_limits(const char *offload,
- size_t *max_data_segment_length);
+ size_t *max_recv_data_segment_length,
+ size_t *max_send_data_segment_length,
+ size_t *max_burst_length,
+ size_t *first_burst_length);
int kernel_port_add(struct port *port);
int kernel_port_update(struct port *port, struct port *old);
int kernel_port_remove(struct port *port);
Index: usr.sbin/ctld/ctld.c
===================================================================
--- usr.sbin/ctld/ctld.c
+++ usr.sbin/ctld/ctld.c
@@ -1578,8 +1578,9 @@
/*
* Default values, from RFC 3720, section 12.
*/
- conn->conn_max_data_segment_length = 8192;
+ conn->conn_max_recv_data_segment_length = 8192;
conn->conn_max_burst_length = 262144;
+ conn->conn_first_burst_length = 65536;
conn->conn_immediate_data = true;
return (conn);
Index: usr.sbin/ctld/kernel.c
===================================================================
--- usr.sbin/ctld/kernel.c
+++ usr.sbin/ctld/kernel.c
@@ -898,7 +898,9 @@
req.data.handoff.cmdsn = conn->conn_cmdsn;
req.data.handoff.statsn = conn->conn_statsn;
req.data.handoff.max_recv_data_segment_length =
- conn->conn_max_data_segment_length;
+ conn->conn_max_recv_data_segment_length;
+ req.data.handoff.max_send_data_segment_length =
+ conn->conn_max_send_data_segment_length;
req.data.handoff.max_burst_length = conn->conn_max_burst_length;
req.data.handoff.first_burst_length = conn->conn_first_burst_length;
req.data.handoff.immediate_data = conn->conn_immediate_data;
@@ -915,16 +917,18 @@
}
void
-kernel_limits(const char *offload, size_t *max_data_segment_length)
+kernel_limits(const char *offload, size_t *max_recv_dsl, size_t *max_send_dsl,
+ size_t *max_burst_length, size_t *first_burst_length)
{
struct ctl_iscsi req;
+ struct ctl_iscsi_limits_params *cilp;
bzero(&req, sizeof(req));
req.type = CTL_ISCSI_LIMITS;
+ cilp = (struct ctl_iscsi_limits_params *)&(req.data.limits);
if (offload != NULL) {
- strlcpy(req.data.limits.offload, offload,
- sizeof(req.data.limits.offload));
+ strlcpy(cilp->offload, offload, sizeof(cilp->offload));
}
if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) {
@@ -937,13 +941,31 @@
"%s; dropping connection", req.error_str);
}
- *max_data_segment_length = req.data.limits.data_segment_limit;
+ if (cilp->max_recv_data_segment_length != 0) {
+ *max_recv_dsl = cilp->max_recv_data_segment_length;
+ *max_send_dsl = cilp->max_recv_data_segment_length;
+ }
+ if (cilp->max_send_data_segment_length != 0)
+ *max_send_dsl = cilp->max_send_data_segment_length;
+ if (cilp->max_burst_length != 0)
+ *max_burst_length = cilp->max_burst_length;
+ if (cilp->first_burst_length != 0)
+ *first_burst_length = cilp->first_burst_length;
+ if (*max_burst_length < *first_burst_length)
+ *first_burst_length = *max_burst_length;
+
if (offload != NULL) {
- log_debugx("MaxRecvDataSegment kernel limit for offload "
- "\"%s\" is %zd", offload, *max_data_segment_length);
+ log_debugx("Kernel limits for offload \"%s\" are "
+ "MaxRecvDataSegment=%zd, max_send_dsl=%zd, "
+ "MaxBurstLength=%zd, FirstBurstLength=%zd",
+ offload, *max_recv_dsl, *max_send_dsl, *max_burst_length,
+ *first_burst_length);
} else {
- log_debugx("MaxRecvDataSegment kernel limit is %zd",
- *max_data_segment_length);
+ log_debugx("Kernel limits are "
+ "MaxRecvDataSegment=%zd, max_send_dsl=%zd, "
+ "MaxBurstLength=%zd, FirstBurstLength=%zd",
+ *max_recv_dsl, *max_send_dsl, *max_burst_length,
+ *first_burst_length);
}
}
@@ -1217,18 +1239,21 @@
void
kernel_receive(struct pdu *pdu)
{
+ struct connection *conn;
struct ctl_iscsi req;
- pdu->pdu_data = malloc(MAX_DATA_SEGMENT_LENGTH);
+ conn = pdu->pdu_connection;
+ pdu->pdu_data = malloc(conn->conn_max_recv_data_segment_length);
if (pdu->pdu_data == NULL)
log_err(1, "malloc");
bzero(&req, sizeof(req));
req.type = CTL_ISCSI_RECEIVE;
- req.data.receive.connection_id = pdu->pdu_connection->conn_socket;
+ req.data.receive.connection_id = conn->conn_socket;
req.data.receive.bhs = pdu->pdu_bhs;
- req.data.receive.data_segment_len = MAX_DATA_SEGMENT_LENGTH;
+ req.data.receive.data_segment_len =
+ conn->conn_max_recv_data_segment_length;
req.data.receive.data_segment = pdu->pdu_data;
if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) {
Index: usr.sbin/ctld/login.c
===================================================================
--- usr.sbin/ctld/login.c
+++ usr.sbin/ctld/login.c
@@ -550,23 +550,31 @@
log_errx(1, "received invalid "
"MaxRecvDataSegmentLength");
}
- if (tmp > conn->conn_data_segment_limit) {
- log_debugx("capping MaxRecvDataSegmentLength "
- "from %zd to %zd", tmp, conn->conn_data_segment_limit);
- tmp = conn->conn_data_segment_limit;
+
+ /*
+ * MaxRecvDataSegmentLength is a direction-specific parameter.
+ * We'll limit our _send_ to what the initiator can handle but
+ * our MaxRecvDataSegmentLength is not influenced by the
+ * initiator in any way.
+ */
+ if (tmp > conn->conn_max_send_data_segment_length) {
+ log_debugx("capping max_send_data_segment_length "
+ "from %zd to %zd", tmp,
+ conn->conn_max_send_data_segment_length);
+ conn->conn_max_send_data_segment_length = tmp;
}
- conn->conn_max_data_segment_length = tmp;
- keys_add_int(response_keys, name, conn->conn_data_segment_limit);
+ keys_add_int(response_keys, name,
+ conn->conn_max_recv_data_segment_length);
} else if (strcmp(name, "MaxBurstLength") == 0) {
tmp = strtoul(value, NULL, 10);
if (tmp <= 0) {
login_send_error(request, 0x02, 0x00);
log_errx(1, "received invalid MaxBurstLength");
}
- if (tmp > MAX_BURST_LENGTH) {
- log_debugx("capping MaxBurstLength from %zd to %d",
- tmp, MAX_BURST_LENGTH);
- tmp = MAX_BURST_LENGTH;
+ if (tmp > conn->conn_max_burst_length) {
+ log_debugx("capping MaxBurstLength from %zd to %zd",
+ tmp, conn->conn_max_burst_length);
+ tmp = conn->conn_max_burst_length;
}
conn->conn_max_burst_length = tmp;
keys_add(response_keys, name, value);
@@ -576,10 +584,10 @@
login_send_error(request, 0x02, 0x00);
log_errx(1, "received invalid FirstBurstLength");
}
- if (tmp > FIRST_BURST_LENGTH) {
- log_debugx("capping FirstBurstLength from %zd to %d",
- tmp, FIRST_BURST_LENGTH);
- tmp = FIRST_BURST_LENGTH;
+ if (tmp > conn->conn_first_burst_length) {
+ log_debugx("capping FirstBurstLength from %zd to %zd",
+ tmp, conn->conn_first_burst_length);
+ tmp = conn->conn_first_burst_length;
}
conn->conn_first_burst_length = tmp;
keys_add_int(response_keys, name, tmp);
@@ -681,14 +689,30 @@
if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) {
/*
- * Query the kernel for MaxDataSegmentLength it can handle.
- * In case of offload, it depends on hardware capabilities.
+ * Query the kernel for various size limits. In case of
+ * offload, it depends on hardware capabilities.
*/
assert(conn->conn_target != NULL);
kernel_limits(conn->conn_portal->p_portal_group->pg_offload,
- &conn->conn_data_segment_limit);
+ &conn->conn_max_recv_data_segment_length,
+ &conn->conn_max_send_data_segment_length,
+ &conn->conn_max_burst_length,
+ &conn->conn_first_burst_length);
+
+ /* We expect legal, usable values at this point. */
+ assert(conn->conn_max_recv_data_segment_length >= 512);
+ assert(conn->conn_max_recv_data_segment_length < (1 << 24));
+ assert(conn->conn_max_burst_length >= 512);
+ assert(conn->conn_max_burst_length < (1 << 24));
+ assert(conn->conn_first_burst_length >= 512);
+ assert(conn->conn_first_burst_length < (1 << 24));
+ assert(conn->conn_first_burst_length <=
+ conn->conn_max_burst_length);
} else {
- conn->conn_data_segment_limit = MAX_DATA_SEGMENT_LENGTH;
+ conn->conn_max_recv_data_segment_length =
+ MAX_DATA_SEGMENT_LENGTH;
+ conn->conn_max_send_data_segment_length =
+ MAX_DATA_SEGMENT_LENGTH;
}
if (request == NULL) {
@@ -739,6 +763,18 @@
response_keys);
}
+ /*
+ * We'd started with usable values at our end. But a bad initiator
+ * could have presented a large FirstBurstLength and then a smaller
+ * MaxBurstLength (in that order) and because we process the key/value
+ * pairs in the order they are in the request we might have ended up
+ * with iLLegal values here.
+ */
+ if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL &&
+ conn->conn_first_burst_length > conn->conn_max_burst_length) {
+ log_errx(1, "initiator sent FirstBurstLength > MaxBurstLength");
+ }
+
log_debugx("operational parameter negotiation done; "
"transitioning to Full Feature Phase");
Index: usr.sbin/ctld/pdu.c
===================================================================
--- usr.sbin/ctld/pdu.c
+++ usr.sbin/ctld/pdu.c
@@ -117,7 +117,7 @@
log_errx(1, "protocol error: non-empty AHS");
len = pdu_data_segment_length(pdu);
- assert(len <= MAX_DATA_SEGMENT_LENGTH);
+ assert(len <= pdu->pdu_connection->conn_max_recv_data_segment_length);
pdu->pdu_data_len = len;
}
@@ -164,6 +164,7 @@
void
pdu_receive(struct pdu *pdu)
{
+ struct connection *conn;
size_t len, padding;
char dummy[4];
@@ -173,9 +174,10 @@
#endif
assert(proxy_mode == false);
+ conn = pdu->pdu_connection;
- pdu_read(pdu->pdu_connection->conn_socket,
- (char *)pdu->pdu_bhs, sizeof(*pdu->pdu_bhs));
+ pdu_read(conn->conn_socket, (char *)pdu->pdu_bhs,
+ sizeof(*pdu->pdu_bhs));
len = pdu_ahs_length(pdu);
if (len > 0)
@@ -183,10 +185,10 @@
len = pdu_data_segment_length(pdu);
if (len > 0) {
- if (len > MAX_DATA_SEGMENT_LENGTH) {
+ if (len > conn->conn_max_recv_data_segment_length) {
log_errx(1, "protocol error: received PDU "
- "with DataSegmentLength exceeding %d",
- MAX_DATA_SEGMENT_LENGTH);
+ "with DataSegmentLength exceeding %zd",
+ conn->conn_max_recv_data_segment_length);
}
pdu->pdu_data_len = len;
@@ -194,14 +196,13 @@
if (pdu->pdu_data == NULL)
log_err(1, "malloc");
- pdu_read(pdu->pdu_connection->conn_socket,
- (char *)pdu->pdu_data, pdu->pdu_data_len);
+ pdu_read(conn->conn_socket, (char *)pdu->pdu_data,
+ pdu->pdu_data_len);
padding = pdu_padding(pdu);
if (padding != 0) {
assert(padding < sizeof(dummy));
- pdu_read(pdu->pdu_connection->conn_socket,
- (char *)dummy, padding);
+ pdu_read(conn->conn_socket, (char *)dummy, padding);
}
}
}
Index: usr.sbin/iscsid/iscsid.h
===================================================================
--- usr.sbin/iscsid/iscsid.h
+++ usr.sbin/iscsid/iscsid.h
@@ -61,7 +61,8 @@
int conn_data_digest;
bool conn_initial_r2t;
bool conn_immediate_data;
- size_t conn_max_data_segment_length;
+ size_t conn_max_recv_data_segment_length;
+ size_t conn_max_send_data_segment_length;
size_t conn_max_burst_length;
size_t conn_first_burst_length;
struct chap *conn_mutual_chap;
Index: usr.sbin/iscsid/iscsid.c
===================================================================
--- usr.sbin/iscsid/iscsid.c
+++ usr.sbin/iscsid/iscsid.c
@@ -153,6 +153,7 @@
connection_new(int iscsi_fd, const struct iscsi_daemon_request *request)
{
struct connection *conn;
+ struct iscsi_session_limits *isl;
struct addrinfo *from_ai, *to_ai;
const char *from_addr, *to_addr;
#ifdef ICL_KERNEL_PROXY
@@ -171,16 +172,49 @@
conn->conn_data_digest = CONN_DIGEST_NONE;
conn->conn_initial_r2t = true;
conn->conn_immediate_data = true;
- conn->conn_max_data_segment_length = 8192;
- conn->conn_max_burst_length = 262144;
- conn->conn_first_burst_length = 65536;
+ conn->conn_max_burst_length = MAX_BURST_LENGTH;
+ conn->conn_first_burst_length = FIRST_BURST_LENGTH;
conn->conn_iscsi_fd = iscsi_fd;
conn->conn_session_id = request->idr_session_id;
memcpy(&conn->conn_conf, &request->idr_conf, sizeof(conn->conn_conf));
memcpy(&conn->conn_isid, &request->idr_isid, sizeof(conn->conn_isid));
conn->conn_tsih = request->idr_tsih;
- memcpy(&conn->conn_limits, &request->idr_limits, sizeof(conn->conn_limits));
+
+ /*
+ * Read the driver limits and provide reasonable defaults for the ones
+ * the driver doesn't care about. If a max_snd_dsl is not explicitly
+ * provided by the driver then we'll make sure both conn->max_snd_dsl
+ * and isl->max_snd_dsl are set to the rcv_dsl. This preserves historic
+ * behavior.
+ */
+ isl = &conn->conn_limits;
+ memcpy(isl, &request->idr_limits, sizeof(*isl));
+ if (isl->isl_max_recv_data_segment_length == 0) {
+ conn->conn_max_recv_data_segment_length = 8192;
+ conn->conn_max_send_data_segment_length = 8192;
+ isl->isl_max_recv_data_segment_length = 8192;
+ } else {
+ conn->conn_max_recv_data_segment_length =
+ isl->isl_max_recv_data_segment_length;
+ conn->conn_max_send_data_segment_length =
+ isl->isl_max_recv_data_segment_length;
+ }
+ if (isl->isl_max_send_data_segment_length == 0) {
+ isl->isl_max_send_data_segment_length =
+ isl->isl_max_recv_data_segment_length;
+ } else {
+ conn->conn_max_send_data_segment_length =
+ isl->isl_max_send_data_segment_length;
+ }
+ if (isl->isl_max_burst_length == 0)
+ isl->isl_max_burst_length = conn->conn_max_burst_length;
+ if (isl->isl_first_burst_length == 0) {
+ if (isl->isl_max_burst_length < (int)conn->conn_first_burst_length)
+ isl->isl_first_burst_length = isl->isl_max_burst_length;
+ else
+ isl->isl_first_burst_length = conn->conn_first_burst_length;
+ }
from_addr = conn->conn_conf.isc_initiator_addr;
to_addr = conn->conn_conf.isc_target_addr;
@@ -277,7 +311,10 @@
idh.idh_data_digest = conn->conn_data_digest;
idh.idh_initial_r2t = conn->conn_initial_r2t;
idh.idh_immediate_data = conn->conn_immediate_data;
- idh.idh_max_data_segment_length = conn->conn_max_data_segment_length;
+ idh.idh_max_recv_data_segment_length =
+ conn->conn_max_recv_data_segment_length;
+ idh.idh_max_send_data_segment_length =
+ conn->conn_max_send_data_segment_length;
idh.idh_max_burst_length = conn->conn_max_burst_length;
idh.idh_first_burst_length = conn->conn_first_burst_length;
Index: usr.sbin/iscsid/login.c
===================================================================
--- usr.sbin/iscsid/login.c
+++ usr.sbin/iscsid/login.c
@@ -330,8 +330,10 @@
login_negotiate_key(struct connection *conn, const char *name,
const char *value)
{
+ struct iscsi_session_limits *isl;
int which, tmp;
+ isl = &conn->conn_limits;
if (strcmp(name, "TargetAlias") == 0) {
strlcpy(conn->conn_target_alias, value,
sizeof(conn->conn_target_alias));
@@ -388,30 +390,31 @@
if (tmp <= 0)
log_errx(1, "received invalid "
"MaxRecvDataSegmentLength");
- if (tmp > ISCSI_MAX_DATA_SEGMENT_LENGTH) {
- log_debugx("capping MaxRecvDataSegmentLength "
- "from %d to %d", tmp, ISCSI_MAX_DATA_SEGMENT_LENGTH);
- tmp = ISCSI_MAX_DATA_SEGMENT_LENGTH;
+ if (tmp > isl->isl_max_send_data_segment_length) {
+ log_debugx("capping max_send_data_segment_length "
+ "from %d to %d", tmp,
+ isl->isl_max_send_data_segment_length);
+ tmp = isl->isl_max_send_data_segment_length;
}
- conn->conn_max_data_segment_length = tmp;
+ conn->conn_max_send_data_segment_length = tmp;
} else if (strcmp(name, "MaxBurstLength") == 0) {
tmp = strtoul(value, NULL, 10);
if (tmp <= 0)
log_errx(1, "received invalid MaxBurstLength");
- if (tmp > MAX_BURST_LENGTH) {
+ if (tmp > isl->isl_max_burst_length) {
log_debugx("capping MaxBurstLength "
- "from %d to %d", tmp, MAX_BURST_LENGTH);
- tmp = MAX_BURST_LENGTH;
+ "from %d to %d", tmp, isl->isl_max_burst_length);
+ tmp = isl->isl_max_burst_length;
}
conn->conn_max_burst_length = tmp;
} else if (strcmp(name, "FirstBurstLength") == 0) {
tmp = strtoul(value, NULL, 10);
if (tmp <= 0)
log_errx(1, "received invalid FirstBurstLength");
- if (tmp > FIRST_BURST_LENGTH) {
+ if (tmp > isl->isl_first_burst_length) {
log_debugx("capping FirstBurstLength "
- "from %d to %d", tmp, FIRST_BURST_LENGTH);
- tmp = FIRST_BURST_LENGTH;
+ "from %d to %d", tmp, isl->isl_first_burst_length);
+ tmp = isl->isl_first_burst_length;
}
conn->conn_first_burst_length = tmp;
} else if (strcmp(name, "DefaultTime2Wait") == 0) {
@@ -440,13 +443,13 @@
if (tmp <= 0)
log_errx(1, "received invalid "
"InitiatorRecvDataSegmentLength");
- if ((size_t)tmp > conn->conn_limits.isl_max_data_segment_length) {
+ if ((int)tmp > isl->isl_max_recv_data_segment_length) {
log_debugx("capping InitiatorRecvDataSegmentLength "
"from %d to %zd", tmp,
- conn->conn_limits.isl_max_data_segment_length);
- tmp = conn->conn_limits.isl_max_data_segment_length;
+ isl->isl_max_recv_data_segment_length);
+ tmp = isl->isl_max_recv_data_segment_length;
}
- conn->conn_max_data_segment_length = tmp;
+ conn->conn_max_recv_data_segment_length = tmp;
} else if (strcmp(name, "TargetPortalGroupTag") == 0) {
/* Ignore */
} else if (strcmp(name, "TargetRecvDataSegmentLength") == 0) {
@@ -455,13 +458,13 @@
log_errx(1,
"received invalid TargetRecvDataSegmentLength");
}
- if ((size_t)tmp > conn->conn_limits.isl_max_data_segment_length) {
+ if (tmp > isl->isl_max_send_data_segment_length) {
log_debugx("capping TargetRecvDataSegmentLength "
"from %d to %zd", tmp,
- conn->conn_limits.isl_max_data_segment_length);
- tmp = conn->conn_limits.isl_max_data_segment_length;
+ isl->isl_max_send_data_segment_length);
+ tmp = isl->isl_max_send_data_segment_length;
}
- conn->conn_max_data_segment_length = tmp;
+ conn->conn_max_send_data_segment_length = tmp;
} else {
log_debugx("unknown key \"%s\"; ignoring", name);
}
@@ -474,14 +477,19 @@
struct keys *request_keys, *response_keys;
struct iscsi_bhs_login_response *bhslr;
int i, nrequests = 0;
+ struct iscsi_session_limits *isl;
log_debugx("beginning operational parameter negotiation");
request = login_new_request(conn, BHSLR_STAGE_OPERATIONAL_NEGOTIATION);
request_keys = keys_new();
- log_debugx("offload \"%s\" limits MaxRecvDataSegmentLength to %zd",
- conn->conn_conf.isc_offload,
- conn->conn_limits.isl_max_data_segment_length);
+ isl = &conn->conn_limits;
+ log_debugx("Limits for offload \"%s\" are "
+ "MaxRecvDataSegment=%zd, max_send_dsl=%zd, "
+ "MaxBurstLength=%zd, FirstBurstLength=%zd",
+ conn->conn_conf.isc_offload, isl->isl_max_recv_data_segment_length,
+ isl->isl_max_send_data_segment_length, isl->isl_max_burst_length,
+ isl->isl_first_burst_length);
/*
* The following keys are irrelevant for discovery sessions.
@@ -497,25 +505,27 @@
keys_add(request_keys, "DataDigest", "None");
keys_add(request_keys, "ImmediateData", "Yes");
- keys_add_int(request_keys, "MaxBurstLength", MAX_BURST_LENGTH);
- keys_add_int(request_keys, "FirstBurstLength", FIRST_BURST_LENGTH);
+ keys_add_int(request_keys, "MaxBurstLength",
+ isl->isl_max_burst_length);
+ keys_add_int(request_keys, "FirstBurstLength",
+ isl->isl_first_burst_length);
keys_add(request_keys, "InitialR2T", "Yes");
keys_add(request_keys, "MaxOutstandingR2T", "1");
if (conn->conn_conf.isc_iser == 1) {
keys_add_int(request_keys, "InitiatorRecvDataSegmentLength",
- conn->conn_limits.isl_max_data_segment_length);
+ isl->isl_max_recv_data_segment_length);
keys_add_int(request_keys, "TargetRecvDataSegmentLength",
- conn->conn_limits.isl_max_data_segment_length);
+ isl->isl_max_send_data_segment_length);
keys_add(request_keys, "RDMAExtensions", "Yes");
} else {
keys_add_int(request_keys, "MaxRecvDataSegmentLength",
- conn->conn_limits.isl_max_data_segment_length);
+ isl->isl_max_recv_data_segment_length);
}
} else {
keys_add(request_keys, "HeaderDigest", "None");
keys_add(request_keys, "DataDigest", "None");
keys_add_int(request_keys, "MaxRecvDataSegmentLength",
- conn->conn_limits.isl_max_data_segment_length);
+ isl->isl_max_recv_data_segment_length);
}
keys_add(request_keys, "DefaultTime2Wait", "0");

File Metadata

Mime Type
text/plain
Expires
Sat, Feb 22, 5:19 PM (3 h, 14 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16775650
Default Alt Text
D7279.id18648.diff (37 KB)

Event Timeline