diff options
Diffstat (limited to 'fs/cifs/transport.c')
-rw-r--r-- | fs/cifs/transport.c | 331 |
1 files changed, 255 insertions, 76 deletions
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 0046c219833d..981ea0d8b9cd 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 { |
@@ -58,7 +59,9 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) | |||
58 | temp->pid = current->pid; | 59 | temp->pid = current->pid; |
59 | temp->command = smb_buffer->Command; | 60 | temp->command = smb_buffer->Command; |
60 | cFYI(1, ("For smb_command %d", temp->command)); | 61 | cFYI(1, ("For smb_command %d", temp->command)); |
61 | do_gettimeofday(&temp->when_sent); | 62 | /* do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */ |
63 | /* when mid allocated can be before when sent */ | ||
64 | temp->when_alloc = jiffies; | ||
62 | temp->ses = ses; | 65 | temp->ses = ses; |
63 | temp->tsk = current; | 66 | temp->tsk = current; |
64 | } | 67 | } |
@@ -74,6 +77,9 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) | |||
74 | static void | 77 | static void |
75 | DeleteMidQEntry(struct mid_q_entry *midEntry) | 78 | DeleteMidQEntry(struct mid_q_entry *midEntry) |
76 | { | 79 | { |
80 | #ifdef CONFIG_CIFS_STATS2 | ||
81 | unsigned long now; | ||
82 | #endif | ||
77 | spin_lock(&GlobalMid_Lock); | 83 | spin_lock(&GlobalMid_Lock); |
78 | midEntry->midState = MID_FREE; | 84 | midEntry->midState = MID_FREE; |
79 | list_del(&midEntry->qhead); | 85 | list_del(&midEntry->qhead); |
@@ -83,6 +89,22 @@ DeleteMidQEntry(struct mid_q_entry *midEntry) | |||
83 | cifs_buf_release(midEntry->resp_buf); | 89 | cifs_buf_release(midEntry->resp_buf); |
84 | else | 90 | else |
85 | cifs_small_buf_release(midEntry->resp_buf); | 91 | cifs_small_buf_release(midEntry->resp_buf); |
92 | #ifdef CONFIG_CIFS_STATS2 | ||
93 | now = jiffies; | ||
94 | /* commands taking longer than one second are indications that | ||
95 | something is wrong, unless it is quite a slow link or server */ | ||
96 | if((now - midEntry->when_alloc) > HZ) { | ||
97 | if((cifsFYI & CIFS_TIMER) && | ||
98 | (midEntry->command != SMB_COM_LOCKING_ANDX)) { | ||
99 | printk(KERN_DEBUG " CIFS slow rsp: cmd %d mid %d", | ||
100 | midEntry->command, midEntry->mid); | ||
101 | printk(" A: 0x%lx S: 0x%lx R: 0x%lx\n", | ||
102 | now - midEntry->when_alloc, | ||
103 | now - midEntry->when_sent, | ||
104 | now - midEntry->when_received); | ||
105 | } | ||
106 | } | ||
107 | #endif | ||
86 | mempool_free(midEntry, cifs_mid_poolp); | 108 | mempool_free(midEntry, cifs_mid_poolp); |
87 | } | 109 | } |
88 | 110 | ||
@@ -146,32 +168,37 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, | |||
146 | Flags2 is converted in SendReceive */ | 168 | Flags2 is converted in SendReceive */ |
147 | 169 | ||
148 | smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); | 170 | smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); |
149 | cFYI(1, ("Sending smb of length %d ", smb_buf_length)); | 171 | cFYI(1, ("Sending smb of length %d", smb_buf_length)); |
150 | dump_smb(smb_buffer, len); | 172 | dump_smb(smb_buffer, len); |
151 | 173 | ||
152 | while (len > 0) { | 174 | while (len > 0) { |
153 | rc = kernel_sendmsg(ssocket, &smb_msg, &iov, 1, len); | 175 | rc = kernel_sendmsg(ssocket, &smb_msg, &iov, 1, len); |
154 | if ((rc == -ENOSPC) || (rc == -EAGAIN)) { | 176 | if ((rc == -ENOSPC) || (rc == -EAGAIN)) { |
155 | i++; | 177 | i++; |
156 | if(i > 60) { | 178 | /* smaller timeout here than send2 since smaller size */ |
179 | /* Although it may not be required, this also is smaller | ||
180 | oplock break time */ | ||
181 | if(i > 12) { | ||
157 | cERROR(1, | 182 | cERROR(1, |
158 | ("sends on sock %p stuck for 30 seconds", | 183 | ("sends on sock %p stuck for 7 seconds", |
159 | ssocket)); | 184 | ssocket)); |
160 | rc = -EAGAIN; | 185 | rc = -EAGAIN; |
161 | break; | 186 | break; |
162 | } | 187 | } |
163 | msleep(500); | 188 | msleep(1 << i); |
164 | continue; | 189 | continue; |
165 | } | 190 | } |
166 | if (rc < 0) | 191 | if (rc < 0) |
167 | break; | 192 | break; |
193 | else | ||
194 | i = 0; /* reset i after each successful send */ | ||
168 | iov.iov_base += rc; | 195 | iov.iov_base += rc; |
169 | iov.iov_len -= rc; | 196 | iov.iov_len -= rc; |
170 | len -= rc; | 197 | len -= rc; |
171 | } | 198 | } |
172 | 199 | ||
173 | if (rc < 0) { | 200 | if (rc < 0) { |
174 | cERROR(1,("Error %d sending data on socket to server.", rc)); | 201 | cERROR(1,("Error %d sending data on socket to server", rc)); |
175 | } else { | 202 | } else { |
176 | rc = 0; | 203 | rc = 0; |
177 | } | 204 | } |
@@ -179,26 +206,21 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, | |||
179 | return rc; | 206 | return rc; |
180 | } | 207 | } |
181 | 208 | ||
182 | #ifdef CIFS_EXPERIMENTAL | 209 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
183 | /* BB finish off this function, adding support for writing set of pages as iovec */ | 210 | static int |
184 | /* and also adding support for operations that need to parse the response smb */ | 211 | smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, |
185 | 212 | struct sockaddr *sin) | |
186 | int | ||
187 | smb_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 | { | 213 | { |
191 | int rc = 0; | 214 | int rc = 0; |
192 | int i = 0; | 215 | int i = 0; |
193 | struct msghdr smb_msg; | 216 | struct msghdr smb_msg; |
194 | number_of_pages += 1; /* account for SMB header */ | 217 | struct smb_hdr *smb_buffer = iov[0].iov_base; |
195 | struct kvec * piov = kmalloc(number_of_pages * sizeof(struct kvec)); | 218 | unsigned int len = iov[0].iov_len; |
196 | unsigned len = smb_buf_length + 4; | 219 | unsigned int total_len; |
197 | 220 | int first_vec = 0; | |
221 | |||
198 | if(ssocket == NULL) | 222 | if(ssocket == NULL) |
199 | return -ENOTSOCK; /* BB eventually add reconnect code here */ | 223 | return -ENOTSOCK; /* BB eventually add reconnect code here */ |
200 | iov.iov_base = smb_buffer; | ||
201 | iov.iov_len = len; | ||
202 | 224 | ||
203 | smb_msg.msg_name = sin; | 225 | smb_msg.msg_name = sin; |
204 | smb_msg.msg_namelen = sizeof (struct sockaddr); | 226 | smb_msg.msg_namelen = sizeof (struct sockaddr); |
@@ -211,49 +233,80 @@ smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer, | |||
211 | cifssmb.c and RFC1001 len is converted to bigendian in smb_send | 233 | cifssmb.c and RFC1001 len is converted to bigendian in smb_send |
212 | Flags2 is converted in SendReceive */ | 234 | Flags2 is converted in SendReceive */ |
213 | 235 | ||
236 | |||
237 | total_len = 0; | ||
238 | for (i = 0; i < n_vec; i++) | ||
239 | total_len += iov[i].iov_len; | ||
240 | |||
214 | smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); | 241 | smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); |
215 | cFYI(1, ("Sending smb of length %d ", smb_buf_length)); | 242 | cFYI(1, ("Sending smb: total_len %d", total_len)); |
216 | dump_smb(smb_buffer, len); | 243 | dump_smb(smb_buffer, len); |
217 | 244 | ||
218 | while (len > 0) { | 245 | while (total_len) { |
219 | rc = kernel_sendmsg(ssocket, &smb_msg, &iov, number_of_pages, | 246 | rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec], |
220 | len); | 247 | n_vec - first_vec, total_len); |
221 | if ((rc == -ENOSPC) || (rc == -EAGAIN)) { | 248 | if ((rc == -ENOSPC) || (rc == -EAGAIN)) { |
222 | i++; | 249 | i++; |
223 | if(i > 60) { | 250 | if(i >= 14) { |
224 | cERROR(1, | 251 | cERROR(1, |
225 | ("sends on sock %p stuck for 30 seconds", | 252 | ("sends on sock %p stuck for 15 seconds", |
226 | ssocket)); | 253 | ssocket)); |
227 | rc = -EAGAIN; | 254 | rc = -EAGAIN; |
228 | break; | 255 | break; |
229 | } | 256 | } |
230 | msleep(500); | 257 | msleep(1 << i); |
231 | continue; | 258 | continue; |
232 | } | 259 | } |
233 | if (rc < 0) | 260 | if (rc < 0) |
234 | break; | 261 | break; |
235 | iov.iov_base += rc; | 262 | |
236 | iov.iov_len -= rc; | 263 | if (rc >= total_len) { |
237 | len -= rc; | 264 | WARN_ON(rc > total_len); |
265 | break; | ||
266 | } | ||
267 | if(rc == 0) { | ||
268 | /* should never happen, letting socket clear before | ||
269 | retrying is our only obvious option here */ | ||
270 | cERROR(1,("tcp sent no data")); | ||
271 | msleep(500); | ||
272 | continue; | ||
273 | } | ||
274 | total_len -= rc; | ||
275 | /* the line below resets i */ | ||
276 | for (i = first_vec; i < n_vec; i++) { | ||
277 | if (iov[i].iov_len) { | ||
278 | if (rc > iov[i].iov_len) { | ||
279 | rc -= iov[i].iov_len; | ||
280 | iov[i].iov_len = 0; | ||
281 | } else { | ||
282 | iov[i].iov_base += rc; | ||
283 | iov[i].iov_len -= rc; | ||
284 | first_vec = i; | ||
285 | break; | ||
286 | } | ||
287 | } | ||
288 | } | ||
289 | i = 0; /* in case we get ENOSPC on the next send */ | ||
238 | } | 290 | } |
239 | 291 | ||
240 | if (rc < 0) { | 292 | if (rc < 0) { |
241 | cERROR(1,("Error %d sending data on socket to server.", rc)); | 293 | cERROR(1,("Error %d sending data on socket to server", rc)); |
242 | } else { | 294 | } else |
243 | rc = 0; | 295 | rc = 0; |
244 | } | ||
245 | 296 | ||
246 | return rc; | 297 | return rc; |
247 | } | 298 | } |
248 | 299 | ||
249 | |||
250 | int | 300 | int |
251 | CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, | 301 | SendReceive2(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) | 302 | struct kvec *iov, int n_vec, int *pbytes_returned, |
303 | const int long_op) | ||
253 | { | 304 | { |
254 | int rc = 0; | 305 | int rc = 0; |
255 | unsigned long timeout = 15 * HZ; | 306 | unsigned int receive_len; |
256 | struct mid_q_entry *midQ = NULL; | 307 | unsigned long timeout; |
308 | struct mid_q_entry *midQ; | ||
309 | struct smb_hdr *in_buf = iov[0].iov_base; | ||
257 | 310 | ||
258 | if (ses == NULL) { | 311 | if (ses == NULL) { |
259 | cERROR(1,("Null smb session")); | 312 | cERROR(1,("Null smb session")); |
@@ -263,14 +316,8 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, | |||
263 | cERROR(1,("Null tcp session")); | 316 | cERROR(1,("Null tcp session")); |
264 | return -EIO; | 317 | return -EIO; |
265 | } | 318 | } |
266 | if(pbytes_returned == NULL) | ||
267 | return -EIO; | ||
268 | else | ||
269 | *pbytes_returned = 0; | ||
270 | 319 | ||
271 | 320 | if(ses->server->tcpStatus == CifsExiting) | |
272 | |||
273 | if(ses->server->tcpStatus == CIFS_EXITING) | ||
274 | return -ENOENT; | 321 | return -ENOENT; |
275 | 322 | ||
276 | /* Ensure that we do not send more than 50 overlapping requests | 323 | /* Ensure that we do not send more than 50 overlapping requests |
@@ -282,11 +329,18 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, | |||
282 | } else { | 329 | } else { |
283 | spin_lock(&GlobalMid_Lock); | 330 | spin_lock(&GlobalMid_Lock); |
284 | while(1) { | 331 | while(1) { |
285 | if(atomic_read(&ses->server->inFlight) >= cifs_max_pending){ | 332 | if(atomic_read(&ses->server->inFlight) >= |
333 | cifs_max_pending){ | ||
286 | spin_unlock(&GlobalMid_Lock); | 334 | spin_unlock(&GlobalMid_Lock); |
335 | #ifdef CONFIG_CIFS_STATS2 | ||
336 | atomic_inc(&ses->server->num_waiters); | ||
337 | #endif | ||
287 | wait_event(ses->server->request_q, | 338 | wait_event(ses->server->request_q, |
288 | atomic_read(&ses->server->inFlight) | 339 | atomic_read(&ses->server->inFlight) |
289 | < cifs_max_pending); | 340 | < cifs_max_pending); |
341 | #ifdef CONFIG_CIFS_STATS2 | ||
342 | atomic_dec(&ses->server->num_waiters); | ||
343 | #endif | ||
290 | spin_lock(&GlobalMid_Lock); | 344 | spin_lock(&GlobalMid_Lock); |
291 | } else { | 345 | } else { |
292 | if(ses->server->tcpStatus == CifsExiting) { | 346 | if(ses->server->tcpStatus == CifsExiting) { |
@@ -314,17 +368,17 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, | |||
314 | 368 | ||
315 | if (ses->server->tcpStatus == CifsExiting) { | 369 | if (ses->server->tcpStatus == CifsExiting) { |
316 | rc = -ENOENT; | 370 | rc = -ENOENT; |
317 | goto cifs_out_label; | 371 | goto out_unlock2; |
318 | } else if (ses->server->tcpStatus == CifsNeedReconnect) { | 372 | } else if (ses->server->tcpStatus == CifsNeedReconnect) { |
319 | cFYI(1,("tcp session dead - return to caller to retry")); | 373 | cFYI(1,("tcp session dead - return to caller to retry")); |
320 | rc = -EAGAIN; | 374 | rc = -EAGAIN; |
321 | goto cifs_out_label; | 375 | goto out_unlock2; |
322 | } else if (ses->status != CifsGood) { | 376 | } else if (ses->status != CifsGood) { |
323 | /* check if SMB session is bad because we are setting it up */ | 377 | /* check if SMB session is bad because we are setting it up */ |
324 | if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && | 378 | if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && |
325 | (in_buf->Command != SMB_COM_NEGOTIATE)) { | 379 | (in_buf->Command != SMB_COM_NEGOTIATE)) { |
326 | rc = -EAGAIN; | 380 | rc = -EAGAIN; |
327 | goto cifs_out_label; | 381 | goto out_unlock2; |
328 | } /* else ok - we are setting up session */ | 382 | } /* else ok - we are setting up session */ |
329 | } | 383 | } |
330 | midQ = AllocMidQEntry(in_buf, ses); | 384 | midQ = AllocMidQEntry(in_buf, ses); |
@@ -338,51 +392,162 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, | |||
338 | return -ENOMEM; | 392 | return -ENOMEM; |
339 | } | 393 | } |
340 | 394 | ||
341 | if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { | 395 | /* BB FIXME */ |
342 | up(&ses->server->tcpSem); | 396 | /* rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); */ |
343 | cERROR(1, | 397 | |
344 | ("Illegal length, greater than maximum frame, %d ", | 398 | midQ->midState = MID_REQUEST_SUBMITTED; |
345 | in_buf->smb_buf_length)); | 399 | #ifdef CONFIG_CIFS_STATS2 |
400 | atomic_inc(&ses->server->inSend); | ||
401 | #endif | ||
402 | rc = smb_send2(ses->server->ssocket, iov, n_vec, | ||
403 | (struct sockaddr *) &(ses->server->addr.sockAddr)); | ||
404 | #ifdef CONFIG_CIFS_STATS2 | ||
405 | atomic_dec(&ses->server->inSend); | ||
406 | midQ->when_sent = jiffies; | ||
407 | #endif | ||
408 | if(rc < 0) { | ||
346 | DeleteMidQEntry(midQ); | 409 | DeleteMidQEntry(midQ); |
410 | up(&ses->server->tcpSem); | ||
347 | /* If not lock req, update # of requests on wire to server */ | 411 | /* If not lock req, update # of requests on wire to server */ |
348 | if(long_op < 3) { | 412 | if(long_op < 3) { |
349 | atomic_dec(&ses->server->inFlight); | 413 | atomic_dec(&ses->server->inFlight); |
350 | wake_up(&ses->server->request_q); | 414 | wake_up(&ses->server->request_q); |
351 | } | 415 | } |
352 | return -EIO; | 416 | return rc; |
417 | } else | ||
418 | up(&ses->server->tcpSem); | ||
419 | if (long_op == -1) | ||
420 | goto cifs_no_response_exit2; | ||
421 | else if (long_op == 2) /* writes past end of file can take loong time */ | ||
422 | timeout = 180 * HZ; | ||
423 | else if (long_op == 1) | ||
424 | timeout = 45 * HZ; /* should be greater than | ||
425 | servers oplock break timeout (about 43 seconds) */ | ||
426 | else if (long_op > 2) { | ||
427 | timeout = MAX_SCHEDULE_TIMEOUT; | ||
428 | } else | ||
429 | timeout = 15 * HZ; | ||
430 | /* wait for 15 seconds or until woken up due to response arriving or | ||
431 | due to last connection to this server being unmounted */ | ||
432 | if (signal_pending(current)) { | ||
433 | /* if signal pending do not hold up user for full smb timeout | ||
434 | but we still give response a change to complete */ | ||
435 | timeout = 2 * HZ; | ||
436 | } | ||
437 | |||
438 | /* No user interrupts in wait - wreaks havoc with performance */ | ||
439 | if(timeout != MAX_SCHEDULE_TIMEOUT) { | ||
440 | timeout += jiffies; | ||
441 | wait_event(ses->server->response_q, | ||
442 | (!(midQ->midState & MID_REQUEST_SUBMITTED)) || | ||
443 | time_after(jiffies, timeout) || | ||
444 | ((ses->server->tcpStatus != CifsGood) && | ||
445 | (ses->server->tcpStatus != CifsNew))); | ||
446 | } else { | ||
447 | wait_event(ses->server->response_q, | ||
448 | (!(midQ->midState & MID_REQUEST_SUBMITTED)) || | ||
449 | ((ses->server->tcpStatus != CifsGood) && | ||
450 | (ses->server->tcpStatus != CifsNew))); | ||
353 | } | 451 | } |
354 | 452 | ||
355 | /* BB can we sign efficiently in this path? */ | 453 | spin_lock(&GlobalMid_Lock); |
356 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); | 454 | if (midQ->resp_buf) { |
455 | spin_unlock(&GlobalMid_Lock); | ||
456 | receive_len = midQ->resp_buf->smb_buf_length; | ||
457 | } else { | ||
458 | cERROR(1,("No response to cmd %d mid %d", | ||
459 | midQ->command, midQ->mid)); | ||
460 | if(midQ->midState == MID_REQUEST_SUBMITTED) { | ||
461 | if(ses->server->tcpStatus == CifsExiting) | ||
462 | rc = -EHOSTDOWN; | ||
463 | else { | ||
464 | ses->server->tcpStatus = CifsNeedReconnect; | ||
465 | midQ->midState = MID_RETRY_NEEDED; | ||
466 | } | ||
467 | } | ||
357 | 468 | ||
358 | midQ->midState = MID_REQUEST_SUBMITTED; | 469 | if (rc != -EHOSTDOWN) { |
359 | /* rc = smb_sendv(ses->server->ssocket, in_buf, in_buf->smb_buf_length, | 470 | if(midQ->midState == MID_RETRY_NEEDED) { |
360 | piovec, | 471 | rc = -EAGAIN; |
361 | (struct sockaddr *) &(ses->server->addr.sockAddr));*/ | 472 | cFYI(1,("marking request for retry")); |
362 | if(rc < 0) { | 473 | } else { |
474 | rc = -EIO; | ||
475 | } | ||
476 | } | ||
477 | spin_unlock(&GlobalMid_Lock); | ||
363 | DeleteMidQEntry(midQ); | 478 | DeleteMidQEntry(midQ); |
364 | up(&ses->server->tcpSem); | ||
365 | /* If not lock req, update # of requests on wire to server */ | 479 | /* If not lock req, update # of requests on wire to server */ |
366 | if(long_op < 3) { | 480 | if(long_op < 3) { |
367 | atomic_dec(&ses->server->inFlight); | 481 | atomic_dec(&ses->server->inFlight); |
368 | wake_up(&ses->server->request_q); | 482 | wake_up(&ses->server->request_q); |
369 | } | 483 | } |
370 | return rc; | 484 | return rc; |
371 | } else | 485 | } |
372 | up(&ses->server->tcpSem); | 486 | |
373 | cifs_out_label: | 487 | if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { |
374 | if(midQ) | 488 | cERROR(1, ("Frame too large received. Length: %d Xid: %d", |
375 | DeleteMidQEntry(midQ); | 489 | receive_len, xid)); |
376 | 490 | rc = -EIO; | |
491 | } else { /* rcvd frame is ok */ | ||
492 | |||
493 | if (midQ->resp_buf && | ||
494 | (midQ->midState == MID_RESPONSE_RECEIVED)) { | ||
495 | in_buf->smb_buf_length = receive_len; | ||
496 | /* BB verify that length would not overrun small buf */ | ||
497 | memcpy((char *)in_buf + 4, | ||
498 | (char *)midQ->resp_buf + 4, | ||
499 | receive_len); | ||
500 | |||
501 | dump_smb(in_buf, 80); | ||
502 | /* convert the length into a more usable form */ | ||
503 | if((receive_len > 24) && | ||
504 | (ses->server->secMode & (SECMODE_SIGN_REQUIRED | | ||
505 | SECMODE_SIGN_ENABLED))) { | ||
506 | rc = cifs_verify_signature(in_buf, | ||
507 | ses->server->mac_signing_key, | ||
508 | midQ->sequence_number+1); | ||
509 | if(rc) { | ||
510 | cERROR(1,("Unexpected SMB signature")); | ||
511 | /* BB FIXME add code to kill session */ | ||
512 | } | ||
513 | } | ||
514 | |||
515 | *pbytes_returned = in_buf->smb_buf_length; | ||
516 | |||
517 | /* BB special case reconnect tid and uid here? */ | ||
518 | rc = map_smb_to_linux_error(in_buf); | ||
519 | |||
520 | /* convert ByteCount if necessary */ | ||
521 | if (receive_len >= | ||
522 | sizeof (struct smb_hdr) - | ||
523 | 4 /* do not count RFC1001 header */ + | ||
524 | (2 * in_buf->WordCount) + 2 /* bcc */ ) | ||
525 | BCC(in_buf) = le16_to_cpu(BCC(in_buf)); | ||
526 | } else { | ||
527 | rc = -EIO; | ||
528 | cFYI(1,("Bad MID state?")); | ||
529 | } | ||
530 | } | ||
531 | cifs_no_response_exit2: | ||
532 | DeleteMidQEntry(midQ); | ||
533 | |||
377 | if(long_op < 3) { | 534 | if(long_op < 3) { |
378 | atomic_dec(&ses->server->inFlight); | 535 | atomic_dec(&ses->server->inFlight); |
379 | wake_up(&ses->server->request_q); | 536 | wake_up(&ses->server->request_q); |
380 | } | 537 | } |
381 | 538 | ||
382 | return rc; | 539 | return rc; |
383 | } | ||
384 | 540 | ||
541 | out_unlock2: | ||
542 | up(&ses->server->tcpSem); | ||
543 | /* If not lock req, update # of requests on wire to server */ | ||
544 | if(long_op < 3) { | ||
545 | atomic_dec(&ses->server->inFlight); | ||
546 | wake_up(&ses->server->request_q); | ||
547 | } | ||
385 | 548 | ||
549 | return rc; | ||
550 | } | ||
386 | #endif /* CIFS_EXPERIMENTAL */ | 551 | #endif /* CIFS_EXPERIMENTAL */ |
387 | 552 | ||
388 | int | 553 | int |
@@ -419,9 +584,15 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
419 | if(atomic_read(&ses->server->inFlight) >= | 584 | if(atomic_read(&ses->server->inFlight) >= |
420 | cifs_max_pending){ | 585 | cifs_max_pending){ |
421 | spin_unlock(&GlobalMid_Lock); | 586 | spin_unlock(&GlobalMid_Lock); |
587 | #ifdef CONFIG_CIFS_STATS2 | ||
588 | atomic_inc(&ses->server->num_waiters); | ||
589 | #endif | ||
422 | wait_event(ses->server->request_q, | 590 | wait_event(ses->server->request_q, |
423 | atomic_read(&ses->server->inFlight) | 591 | atomic_read(&ses->server->inFlight) |
424 | < cifs_max_pending); | 592 | < cifs_max_pending); |
593 | #ifdef CONFIG_CIFS_STATS2 | ||
594 | atomic_dec(&ses->server->num_waiters); | ||
595 | #endif | ||
425 | spin_lock(&GlobalMid_Lock); | 596 | spin_lock(&GlobalMid_Lock); |
426 | } else { | 597 | } else { |
427 | if(ses->server->tcpStatus == CifsExiting) { | 598 | if(ses->server->tcpStatus == CifsExiting) { |
@@ -490,8 +661,15 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
490 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); | 661 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); |
491 | 662 | ||
492 | midQ->midState = MID_REQUEST_SUBMITTED; | 663 | midQ->midState = MID_REQUEST_SUBMITTED; |
664 | #ifdef CONFIG_CIFS_STATS2 | ||
665 | atomic_inc(&ses->server->inSend); | ||
666 | #endif | ||
493 | rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, | 667 | rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, |
494 | (struct sockaddr *) &(ses->server->addr.sockAddr)); | 668 | (struct sockaddr *) &(ses->server->addr.sockAddr)); |
669 | #ifdef CONFIG_CIFS_STATS2 | ||
670 | atomic_dec(&ses->server->inSend); | ||
671 | midQ->when_sent = jiffies; | ||
672 | #endif | ||
495 | if(rc < 0) { | 673 | if(rc < 0) { |
496 | DeleteMidQEntry(midQ); | 674 | DeleteMidQEntry(midQ); |
497 | up(&ses->server->tcpSem); | 675 | up(&ses->server->tcpSem); |
@@ -506,7 +684,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
506 | if (long_op == -1) | 684 | if (long_op == -1) |
507 | goto cifs_no_response_exit; | 685 | goto cifs_no_response_exit; |
508 | else if (long_op == 2) /* writes past end of file can take loong time */ | 686 | else if (long_op == 2) /* writes past end of file can take loong time */ |
509 | timeout = 300 * HZ; | 687 | timeout = 180 * HZ; |
510 | else if (long_op == 1) | 688 | else if (long_op == 1) |
511 | timeout = 45 * HZ; /* should be greater than | 689 | timeout = 45 * HZ; /* should be greater than |
512 | servers oplock break timeout (about 43 seconds) */ | 690 | servers oplock break timeout (about 43 seconds) */ |
@@ -540,9 +718,10 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
540 | spin_lock(&GlobalMid_Lock); | 718 | spin_lock(&GlobalMid_Lock); |
541 | if (midQ->resp_buf) { | 719 | if (midQ->resp_buf) { |
542 | spin_unlock(&GlobalMid_Lock); | 720 | spin_unlock(&GlobalMid_Lock); |
543 | receive_len = be32_to_cpu(*(__be32 *)midQ->resp_buf); | 721 | receive_len = midQ->resp_buf->smb_buf_length; |
544 | } else { | 722 | } else { |
545 | cERROR(1,("No response buffer")); | 723 | cERROR(1,("No response for cmd %d mid %d", |
724 | midQ->command, midQ->mid)); | ||
546 | if(midQ->midState == MID_REQUEST_SUBMITTED) { | 725 | if(midQ->midState == MID_REQUEST_SUBMITTED) { |
547 | if(ses->server->tcpStatus == CifsExiting) | 726 | if(ses->server->tcpStatus == CifsExiting) |
548 | rc = -EHOSTDOWN; | 727 | rc = -EHOSTDOWN; |
@@ -610,7 +789,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
610 | BCC(out_buf) = le16_to_cpu(BCC(out_buf)); | 789 | BCC(out_buf) = le16_to_cpu(BCC(out_buf)); |
611 | } else { | 790 | } else { |
612 | rc = -EIO; | 791 | rc = -EIO; |
613 | cFYI(1,("Bad MID state? ")); | 792 | cERROR(1,("Bad MID state? ")); |
614 | } | 793 | } |
615 | } | 794 | } |
616 | cifs_no_response_exit: | 795 | cifs_no_response_exit: |