Commit adeb964d authored by Tom Talpey's avatar Tom Talpey Committed by Steve French

Handle variable number of SGEs in client smbdirect send.

If/when an outgoing request contains more scatter/gather segments
than can be mapped in a single RDMA send work request, use smbdirect
fragments to send it in multiple packets.
Acked-by: default avatarPaulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: default avatarTom Talpey <tom@talpey.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 3c62df55
...@@ -1984,10 +1984,11 @@ int smbd_send(struct TCP_Server_Info *server, ...@@ -1984,10 +1984,11 @@ int smbd_send(struct TCP_Server_Info *server,
int num_rqst, struct smb_rqst *rqst_array) int num_rqst, struct smb_rqst *rqst_array)
{ {
struct smbd_connection *info = server->smbd_conn; struct smbd_connection *info = server->smbd_conn;
struct kvec vec; struct kvec vecs[SMBDIRECT_MAX_SEND_SGE - 1];
int nvecs; int nvecs;
int size; int size;
unsigned int buflen, remaining_data_length; unsigned int buflen, remaining_data_length;
unsigned int offset, remaining_vec_data_length;
int start, i, j; int start, i, j;
int max_iov_size = int max_iov_size =
info->max_send_size - sizeof(struct smbd_data_transfer); info->max_send_size - sizeof(struct smbd_data_transfer);
...@@ -1996,10 +1997,8 @@ int smbd_send(struct TCP_Server_Info *server, ...@@ -1996,10 +1997,8 @@ int smbd_send(struct TCP_Server_Info *server,
struct smb_rqst *rqst; struct smb_rqst *rqst;
int rqst_idx; int rqst_idx;
if (info->transport_status != SMBD_CONNECTED) { if (info->transport_status != SMBD_CONNECTED)
rc = -EAGAIN; return -EAGAIN;
goto done;
}
/* /*
* Add in the page array if there is one. The caller needs to set * Add in the page array if there is one. The caller needs to set
...@@ -2010,125 +2009,95 @@ int smbd_send(struct TCP_Server_Info *server, ...@@ -2010,125 +2009,95 @@ int smbd_send(struct TCP_Server_Info *server,
for (i = 0; i < num_rqst; i++) for (i = 0; i < num_rqst; i++)
remaining_data_length += smb_rqst_len(server, &rqst_array[i]); remaining_data_length += smb_rqst_len(server, &rqst_array[i]);
if (remaining_data_length > info->max_fragmented_send_size) { if (unlikely(remaining_data_length > info->max_fragmented_send_size)) {
/* assertion: payload never exceeds negotiated maximum */
log_write(ERR, "payload size %d > max size %d\n", log_write(ERR, "payload size %d > max size %d\n",
remaining_data_length, info->max_fragmented_send_size); remaining_data_length, info->max_fragmented_send_size);
rc = -EINVAL; return -EINVAL;
goto done;
} }
log_write(INFO, "num_rqst=%d total length=%u\n", log_write(INFO, "num_rqst=%d total length=%u\n",
num_rqst, remaining_data_length); num_rqst, remaining_data_length);
rqst_idx = 0; rqst_idx = 0;
next_rqst: do {
rqst = &rqst_array[rqst_idx]; rqst = &rqst_array[rqst_idx];
iov = rqst->rq_iov; iov = rqst->rq_iov;
cifs_dbg(FYI, "Sending smb (RDMA): idx=%d smb_len=%lu\n", cifs_dbg(FYI, "Sending smb (RDMA): idx=%d smb_len=%lu\n",
rqst_idx, smb_rqst_len(server, rqst)); rqst_idx, smb_rqst_len(server, rqst));
for (i = 0; i < rqst->rq_nvec; i++) remaining_vec_data_length = 0;
dump_smb(iov[i].iov_base, iov[i].iov_len); for (i = 0; i < rqst->rq_nvec; i++) {
remaining_vec_data_length += iov[i].iov_len;
dump_smb(iov[i].iov_base, iov[i].iov_len);
log_write(INFO, "rqst_idx=%d nvec=%d rqst->rq_npages=%d rq_pagesz=%d rq_tailsz=%d buflen=%lu\n", }
rqst_idx, rqst->rq_nvec, rqst->rq_npages, rqst->rq_pagesz,
rqst->rq_tailsz, smb_rqst_len(server, rqst)); log_write(INFO, "rqst_idx=%d nvec=%d rqst->rq_npages=%d rq_pagesz=%d rq_tailsz=%d buflen=%lu\n",
rqst_idx, rqst->rq_nvec,
start = i = 0; rqst->rq_npages, rqst->rq_pagesz,
buflen = 0; rqst->rq_tailsz, smb_rqst_len(server, rqst));
while (true) {
buflen += iov[i].iov_len; start = 0;
if (buflen > max_iov_size) { offset = 0;
if (i > start) { do {
remaining_data_length -= buflen = 0;
(buflen-iov[i].iov_len); i = start;
log_write(INFO, "sending iov[] from start=%d i=%d nvecs=%d remaining_data_length=%d\n", j = 0;
start, i, i - start, while (i < rqst->rq_nvec &&
remaining_data_length); j < SMBDIRECT_MAX_SEND_SGE - 1 &&
rc = smbd_post_send_data( buflen < max_iov_size) {
info, &iov[start], i-start,
remaining_data_length); vecs[j].iov_base = iov[i].iov_base + offset;
if (rc) if (buflen + iov[i].iov_len > max_iov_size) {
goto done; vecs[j].iov_len =
} else { max_iov_size - iov[i].iov_len;
/* iov[start] is too big, break it */ buflen = max_iov_size;
nvecs = (buflen+max_iov_size-1)/max_iov_size; offset = vecs[j].iov_len;
log_write(INFO, "iov[%d] iov_base=%p buflen=%d break to %d vectors\n", } else {
start, iov[start].iov_base, vecs[j].iov_len =
buflen, nvecs); iov[i].iov_len - offset;
for (j = 0; j < nvecs; j++) { buflen += vecs[j].iov_len;
vec.iov_base = offset = 0;
(char *)iov[start].iov_base + ++i;
j*max_iov_size;
vec.iov_len = max_iov_size;
if (j == nvecs-1)
vec.iov_len =
buflen -
max_iov_size*(nvecs-1);
remaining_data_length -= vec.iov_len;
log_write(INFO,
"sending vec j=%d iov_base=%p iov_len=%zu remaining_data_length=%d\n",
j, vec.iov_base, vec.iov_len,
remaining_data_length);
rc = smbd_post_send_data(
info, &vec, 1,
remaining_data_length);
if (rc)
goto done;
} }
i++; ++j;
if (i == rqst->rq_nvec)
break;
} }
remaining_vec_data_length -= buflen;
remaining_data_length -= buflen;
log_write(INFO, "sending %s iov[%d] from start=%d nvecs=%d remaining_data_length=%d\n",
remaining_vec_data_length > 0 ?
"partial" : "complete",
rqst->rq_nvec, start, j,
remaining_data_length);
start = i; start = i;
buflen = 0; rc = smbd_post_send_data(info, vecs, j, remaining_data_length);
} else { if (rc)
i++; goto done;
if (i == rqst->rq_nvec) { } while (remaining_vec_data_length > 0);
/* send out all remaining vecs */
remaining_data_length -= buflen; /* now sending pages if there are any */
log_write(INFO, "sending iov[] from start=%d i=%d nvecs=%d remaining_data_length=%d\n", for (i = 0; i < rqst->rq_npages; i++) {
start, i, i - start, rqst_page_get_length(rqst, i, &buflen, &offset);
nvecs = (buflen + max_iov_size - 1) / max_iov_size;
log_write(INFO, "sending pages buflen=%d nvecs=%d\n",
buflen, nvecs);
for (j = 0; j < nvecs; j++) {
size = min_t(unsigned int, max_iov_size, remaining_data_length);
remaining_data_length -= size;
log_write(INFO, "sending pages i=%d offset=%d size=%d remaining_data_length=%d\n",
i, j * max_iov_size + offset, size,
remaining_data_length); remaining_data_length);
rc = smbd_post_send_data(info, &iov[start], rc = smbd_post_send_page(
i-start, remaining_data_length); info, rqst->rq_pages[i],
j*max_iov_size + offset,
size, remaining_data_length);
if (rc) if (rc)
goto done; goto done;
break;
} }
} }
log_write(INFO, "looping i=%d buflen=%d\n", i, buflen); } while (++rqst_idx < num_rqst);
}
/* now sending pages if there are any */
for (i = 0; i < rqst->rq_npages; i++) {
unsigned int offset;
rqst_page_get_length(rqst, i, &buflen, &offset);
nvecs = (buflen + max_iov_size - 1) / max_iov_size;
log_write(INFO, "sending pages buflen=%d nvecs=%d\n",
buflen, nvecs);
for (j = 0; j < nvecs; j++) {
size = max_iov_size;
if (j == nvecs-1)
size = buflen - j*max_iov_size;
remaining_data_length -= size;
log_write(INFO, "sending pages i=%d offset=%d size=%d remaining_data_length=%d\n",
i, j * max_iov_size + offset, size,
remaining_data_length);
rc = smbd_post_send_page(
info, rqst->rq_pages[i],
j*max_iov_size + offset,
size, remaining_data_length);
if (rc)
goto done;
}
}
rqst_idx++;
if (rqst_idx < num_rqst)
goto next_rqst;
done: done:
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment