aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/transport.c
diff options
context:
space:
mode:
authorSteve French <sfrench@us.ibm.com>2005-06-13 14:24:43 -0400
committerSteve French <sfrench@us.ibm.com>2005-06-13 14:24:43 -0400
commitd6e04ae64c6b06ef76a5d4fb49106b393b7fa50a (patch)
tree0ae0d4e7c94ccbba95e55d7512eb628d845eff20 /fs/cifs/transport.c
parent2830077f7ae93ef2f7a312e3e489110963612e77 (diff)
[CIFS] CIFS writepage improvements - eliminate double copy
Signed-off-by: Steve French (sfrench@us.ibm.com)
Diffstat (limited to 'fs/cifs/transport.c')
-rw-r--r--fs/cifs/transport.c223
1 files changed, 173 insertions, 50 deletions
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 0046c219833d..04f4af07fdd4 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -49,7 +49,8 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
49 return NULL; 49 return NULL;
50 } 50 }
51 51
52 temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,SLAB_KERNEL | SLAB_NOFS); 52 temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,
53 SLAB_KERNEL | SLAB_NOFS);
53 if (temp == NULL) 54 if (temp == NULL)
54 return temp; 55 return temp;
55 else { 56 else {
@@ -179,27 +180,24 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
179 return rc; 180 return rc;
180} 181}
181 182
182#ifdef CIFS_EXPERIMENTAL 183#ifdef CONFIG_CIFS_EXPERIMENTAL
183/* BB finish off this function, adding support for writing set of pages as iovec */ 184static int
184/* and also adding support for operations that need to parse the response smb */ 185smb_send2(struct socket *ssocket, struct smb_hdr *smb_buffer,
185 186 unsigned int smb_hdr_length, const char * data, unsigned int datalen,
186int 187 struct sockaddr *sin)
187smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer,
188 unsigned int smb_buf_length, struct kvec * write_vector
189 /* page list */, struct sockaddr *sin)
190{ 188{
191 int rc = 0; 189 int rc = 0;
192 int i = 0; 190 int i = 0;
193 struct msghdr smb_msg; 191 struct msghdr smb_msg;
194 number_of_pages += 1; /* account for SMB header */ 192 struct kvec iov[2];
195 struct kvec * piov = kmalloc(number_of_pages * sizeof(struct kvec)); 193 unsigned len = smb_hdr_length + 4;
196 unsigned len = smb_buf_length + 4; 194
197
198 if(ssocket == NULL) 195 if(ssocket == NULL)
199 return -ENOTSOCK; /* BB eventually add reconnect code here */ 196 return -ENOTSOCK; /* BB eventually add reconnect code here */
200 iov.iov_base = smb_buffer; 197 iov[0].iov_base = smb_buffer;
201 iov.iov_len = len; 198 iov[0].iov_len = len;
202 199 iov[1].iov_base = data;
200 iov[2].iov_len = datalen;
203 smb_msg.msg_name = sin; 201 smb_msg.msg_name = sin;
204 smb_msg.msg_namelen = sizeof (struct sockaddr); 202 smb_msg.msg_namelen = sizeof (struct sockaddr);
205 smb_msg.msg_control = NULL; 203 smb_msg.msg_control = NULL;
@@ -212,12 +210,11 @@ smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer,
212 Flags2 is converted in SendReceive */ 210 Flags2 is converted in SendReceive */
213 211
214 smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); 212 smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
215 cFYI(1, ("Sending smb of length %d ", smb_buf_length)); 213 cFYI(1, ("Sending smb of length %d ", len + datalen));
216 dump_smb(smb_buffer, len); 214 dump_smb(smb_buffer, len);
217 215
218 while (len > 0) { 216 while (len + datalen > 0) {
219 rc = kernel_sendmsg(ssocket, &smb_msg, &iov, number_of_pages, 217 rc = kernel_sendmsg(ssocket, &smb_msg, iov, 2, len);
220 len);
221 if ((rc == -ENOSPC) || (rc == -EAGAIN)) { 218 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
222 i++; 219 i++;
223 if(i > 60) { 220 if(i > 60) {
@@ -232,9 +229,22 @@ smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer,
232 } 229 }
233 if (rc < 0) 230 if (rc < 0)
234 break; 231 break;
235 iov.iov_base += rc; 232 if(iov[0].iov_len > 0) {
236 iov.iov_len -= rc; 233 if(rc >= len) {
237 len -= rc; 234 iov[0].iov_len = 0;
235 rc -= len;
236 } else { /* some of hdr was not sent */
237 len -= rc;
238 iov[0].iov_len -= rc;
239 iov[0].iov_base += rc;
240 continue;
241 }
242 }
243 if((iov[0].iov_len == 0) && (rc > 0)){
244 iov[1].iov_base += rc;
245 iov[1].iov_len -= rc;
246 datalen -= rc;
247 }
238 } 248 }
239 249
240 if (rc < 0) { 250 if (rc < 0) {
@@ -246,14 +256,15 @@ smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer,
246 return rc; 256 return rc;
247} 257}
248 258
249
250int 259int
251CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, 260SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
252 struct smb_hdr *in_buf, struct kvec * write_vector /* page list */, int *pbytes_returned, const int long_op) 261 struct smb_hdr *in_buf, int hdrlen, const char * data,
262 int datalen, int *pbytes_returned, const int long_op)
253{ 263{
254 int rc = 0; 264 int rc = 0;
255 unsigned long timeout = 15 * HZ; 265 unsigned int receive_len;
256 struct mid_q_entry *midQ = NULL; 266 unsigned long timeout;
267 struct mid_q_entry *midQ;
257 268
258 if (ses == NULL) { 269 if (ses == NULL) {
259 cERROR(1,("Null smb session")); 270 cERROR(1,("Null smb session"));
@@ -263,14 +274,8 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
263 cERROR(1,("Null tcp session")); 274 cERROR(1,("Null tcp session"));
264 return -EIO; 275 return -EIO;
265 } 276 }
266 if(pbytes_returned == NULL)
267 return -EIO;
268 else
269 *pbytes_returned = 0;
270 277
271 278 if(ses->server->tcpStatus == CifsExiting)
272
273 if(ses->server->tcpStatus == CIFS_EXITING)
274 return -ENOENT; 279 return -ENOENT;
275 280
276 /* Ensure that we do not send more than 50 overlapping requests 281 /* Ensure that we do not send more than 50 overlapping requests
@@ -282,7 +287,8 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
282 } else { 287 } else {
283 spin_lock(&GlobalMid_Lock); 288 spin_lock(&GlobalMid_Lock);
284 while(1) { 289 while(1) {
285 if(atomic_read(&ses->server->inFlight) >= cifs_max_pending){ 290 if(atomic_read(&ses->server->inFlight) >=
291 cifs_max_pending){
286 spin_unlock(&GlobalMid_Lock); 292 spin_unlock(&GlobalMid_Lock);
287 wait_event(ses->server->request_q, 293 wait_event(ses->server->request_q,
288 atomic_read(&ses->server->inFlight) 294 atomic_read(&ses->server->inFlight)
@@ -314,17 +320,17 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
314 320
315 if (ses->server->tcpStatus == CifsExiting) { 321 if (ses->server->tcpStatus == CifsExiting) {
316 rc = -ENOENT; 322 rc = -ENOENT;
317 goto cifs_out_label; 323 goto out_unlock2;
318 } else if (ses->server->tcpStatus == CifsNeedReconnect) { 324 } else if (ses->server->tcpStatus == CifsNeedReconnect) {
319 cFYI(1,("tcp session dead - return to caller to retry")); 325 cFYI(1,("tcp session dead - return to caller to retry"));
320 rc = -EAGAIN; 326 rc = -EAGAIN;
321 goto cifs_out_label; 327 goto out_unlock2;
322 } else if (ses->status != CifsGood) { 328 } else if (ses->status != CifsGood) {
323 /* check if SMB session is bad because we are setting it up */ 329 /* check if SMB session is bad because we are setting it up */
324 if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && 330 if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
325 (in_buf->Command != SMB_COM_NEGOTIATE)) { 331 (in_buf->Command != SMB_COM_NEGOTIATE)) {
326 rc = -EAGAIN; 332 rc = -EAGAIN;
327 goto cifs_out_label; 333 goto out_unlock2;
328 } /* else ok - we are setting up session */ 334 } /* else ok - we are setting up session */
329 } 335 }
330 midQ = AllocMidQEntry(in_buf, ses); 336 midQ = AllocMidQEntry(in_buf, ses);
@@ -352,13 +358,12 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
352 return -EIO; 358 return -EIO;
353 } 359 }
354 360
355 /* BB can we sign efficiently in this path? */ 361/* BB FIXME */
356 rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); 362/* rc = cifs_sign_smb2(in_buf, data, ses->server, &midQ->sequence_number); */
357 363
358 midQ->midState = MID_REQUEST_SUBMITTED; 364 midQ->midState = MID_REQUEST_SUBMITTED;
359/* rc = smb_sendv(ses->server->ssocket, in_buf, in_buf->smb_buf_length, 365 rc = smb_send2(ses->server->ssocket, in_buf, hdrlen, data, datalen,
360 piovec, 366 (struct sockaddr *) &(ses->server->addr.sockAddr));
361 (struct sockaddr *) &(ses->server->addr.sockAddr));*/
362 if(rc < 0) { 367 if(rc < 0) {
363 DeleteMidQEntry(midQ); 368 DeleteMidQEntry(midQ);
364 up(&ses->server->tcpSem); 369 up(&ses->server->tcpSem);
@@ -370,19 +375,137 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
370 return rc; 375 return rc;
371 } else 376 } else
372 up(&ses->server->tcpSem); 377 up(&ses->server->tcpSem);
373cifs_out_label: 378 if (long_op == -1)
374 if(midQ) 379 goto cifs_no_response_exit2;
375 DeleteMidQEntry(midQ); 380 else if (long_op == 2) /* writes past end of file can take loong time */
376 381 timeout = 300 * HZ;
382 else if (long_op == 1)
383 timeout = 45 * HZ; /* should be greater than
384 servers oplock break timeout (about 43 seconds) */
385 else if (long_op > 2) {
386 timeout = MAX_SCHEDULE_TIMEOUT;
387 } else
388 timeout = 15 * HZ;
389 /* wait for 15 seconds or until woken up due to response arriving or
390 due to last connection to this server being unmounted */
391 if (signal_pending(current)) {
392 /* if signal pending do not hold up user for full smb timeout
393 but we still give response a change to complete */
394 timeout = 2 * HZ;
395 }
396
397 /* No user interrupts in wait - wreaks havoc with performance */
398 if(timeout != MAX_SCHEDULE_TIMEOUT) {
399 timeout += jiffies;
400 wait_event(ses->server->response_q,
401 (!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
402 time_after(jiffies, timeout) ||
403 ((ses->server->tcpStatus != CifsGood) &&
404 (ses->server->tcpStatus != CifsNew)));
405 } else {
406 wait_event(ses->server->response_q,
407 (!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
408 ((ses->server->tcpStatus != CifsGood) &&
409 (ses->server->tcpStatus != CifsNew)));
410 }
411
412 spin_lock(&GlobalMid_Lock);
413 if (midQ->resp_buf) {
414 spin_unlock(&GlobalMid_Lock);
415 receive_len = be32_to_cpu(*(__be32 *)midQ->resp_buf);
416 } else {
417 cERROR(1,("No response buffer"));
418 if(midQ->midState == MID_REQUEST_SUBMITTED) {
419 if(ses->server->tcpStatus == CifsExiting)
420 rc = -EHOSTDOWN;
421 else {
422 ses->server->tcpStatus = CifsNeedReconnect;
423 midQ->midState = MID_RETRY_NEEDED;
424 }
425 }
426
427 if (rc != -EHOSTDOWN) {
428 if(midQ->midState == MID_RETRY_NEEDED) {
429 rc = -EAGAIN;
430 cFYI(1,("marking request for retry"));
431 } else {
432 rc = -EIO;
433 }
434 }
435 spin_unlock(&GlobalMid_Lock);
436 DeleteMidQEntry(midQ);
437 /* If not lock req, update # of requests on wire to server */
438 if(long_op < 3) {
439 atomic_dec(&ses->server->inFlight);
440 wake_up(&ses->server->request_q);
441 }
442 return rc;
443 }
444
445 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
446 cERROR(1, ("Frame too large received. Length: %d Xid: %d",
447 receive_len, xid));
448 rc = -EIO;
449 } else { /* rcvd frame is ok */
450
451 if (midQ->resp_buf &&
452 (midQ->midState == MID_RESPONSE_RECEIVED)) {
453 in_buf->smb_buf_length = receive_len;
454 /* BB verify that length would not overrun small buf */
455 memcpy((char *)in_buf + 4,
456 (char *)midQ->resp_buf + 4,
457 receive_len);
458
459 dump_smb(in_buf, 80);
460 /* convert the length into a more usable form */
461 if((receive_len > 24) &&
462 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
463 SECMODE_SIGN_ENABLED))) {
464 rc = cifs_verify_signature(in_buf,
465 ses->server->mac_signing_key,
466 midQ->sequence_number+1);
467 if(rc) {
468 cERROR(1,("Unexpected SMB signature"));
469 /* BB FIXME add code to kill session */
470 }
471 }
472
473 *pbytes_returned = in_buf->smb_buf_length;
474
475 /* BB special case reconnect tid and uid here? */
476 rc = map_smb_to_linux_error(in_buf);
477
478 /* convert ByteCount if necessary */
479 if (receive_len >=
480 sizeof (struct smb_hdr) -
481 4 /* do not count RFC1001 header */ +
482 (2 * in_buf->WordCount) + 2 /* bcc */ )
483 BCC(in_buf) = le16_to_cpu(BCC(in_buf));
484 } else {
485 rc = -EIO;
486 cFYI(1,("Bad MID state? "));
487 }
488 }
489cifs_no_response_exit2:
490 DeleteMidQEntry(midQ);
491
377 if(long_op < 3) { 492 if(long_op < 3) {
378 atomic_dec(&ses->server->inFlight); 493 atomic_dec(&ses->server->inFlight);
379 wake_up(&ses->server->request_q); 494 wake_up(&ses->server->request_q);
380 } 495 }
381 496
382 return rc; 497 return rc;
383}
384 498
499out_unlock2:
500 up(&ses->server->tcpSem);
501 /* If not lock req, update # of requests on wire to server */
502 if(long_op < 3) {
503 atomic_dec(&ses->server->inFlight);
504 wake_up(&ses->server->request_q);
505 }
385 506
507 return rc;
508}
386#endif /* CIFS_EXPERIMENTAL */ 509#endif /* CIFS_EXPERIMENTAL */
387 510
388int 511int