Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F110669641
D7279.id18648.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
37 KB
Referenced Files
None
Subscribers
None
D7279.id18648.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D7279: Make the iSCSI parameter negotiation more flexible.
Attached
Detach File
Event Timeline
Log In to Comment