diff options
author | Steve French <smfrench@austin.rr.com> | 2005-04-29 01:41:07 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-29 01:41:07 -0400 |
commit | b8643e1b5253a6a51da5574a55a2f9148e255cfd (patch) | |
tree | 7be4a4dc45e83e793f729a69d94b9970d08a2092 /fs/cifs/connect.c | |
parent | c81156dd217818c143a09b6a744e797a04571e99 (diff) |
[PATCH] cifs: Do not use large smb buffers in response path
unless response is larger than 256 bytes. This cuts more than 1/3 of
the large memory allocations that cifs does and should be a huge help to
memory pressure under stress.
Signed-off-by: Steve French (sfrench@us.ibm.com)
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/cifs/connect.c')
-rw-r--r-- | fs/cifs/connect.c | 80 |
1 files changed, 53 insertions, 27 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 383e55fa7d26..390f22fa3439 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * fs/cifs/connect.c | 2 | * fs/cifs/connect.c |
3 | * | 3 | * |
4 | * Copyright (C) International Business Machines Corp., 2002,2004 | 4 | * Copyright (C) International Business Machines Corp., 2002,2005 |
5 | * Author(s): Steve French (sfrench@us.ibm.com) | 5 | * Author(s): Steve French (sfrench@us.ibm.com) |
6 | * | 6 | * |
7 | * This library is free software; you can redistribute it and/or modify | 7 | * This library is free software; you can redistribute it and/or modify |
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/ctype.h> | 28 | #include <linux/ctype.h> |
29 | #include <linux/utsname.h> | 29 | #include <linux/utsname.h> |
30 | #include <linux/mempool.h> | 30 | #include <linux/mempool.h> |
31 | #include <linux/delay.h> | ||
31 | #include <asm/uaccess.h> | 32 | #include <asm/uaccess.h> |
32 | #include <asm/processor.h> | 33 | #include <asm/processor.h> |
33 | #include "cifspdu.h" | 34 | #include "cifspdu.h" |
@@ -198,6 +199,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
198 | int length; | 199 | int length; |
199 | unsigned int pdu_length, total_read; | 200 | unsigned int pdu_length, total_read; |
200 | struct smb_hdr *smb_buffer = NULL; | 201 | struct smb_hdr *smb_buffer = NULL; |
202 | struct smb_hdr *bigbuf = NULL; | ||
203 | struct smb_hdr *smallbuf = NULL; | ||
201 | struct msghdr smb_msg; | 204 | struct msghdr smb_msg; |
202 | struct kvec iov; | 205 | struct kvec iov; |
203 | struct socket *csocket = server->ssocket; | 206 | struct socket *csocket = server->ssocket; |
@@ -206,6 +209,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
206 | struct task_struct *task_to_wake = NULL; | 209 | struct task_struct *task_to_wake = NULL; |
207 | struct mid_q_entry *mid_entry; | 210 | struct mid_q_entry *mid_entry; |
208 | char *temp; | 211 | char *temp; |
212 | int isLargeBuf = FALSE; | ||
209 | 213 | ||
210 | daemonize("cifsd"); | 214 | daemonize("cifsd"); |
211 | allow_signal(SIGKILL); | 215 | allow_signal(SIGKILL); |
@@ -223,17 +227,33 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
223 | } | 227 | } |
224 | 228 | ||
225 | while (server->tcpStatus != CifsExiting) { | 229 | while (server->tcpStatus != CifsExiting) { |
226 | if (smb_buffer == NULL) | 230 | if (bigbuf == NULL) { |
227 | smb_buffer = cifs_buf_get(); | 231 | bigbuf = cifs_buf_get(); |
228 | else | 232 | if(bigbuf == NULL) { |
229 | memset(smb_buffer, 0, sizeof (struct smb_hdr)); | 233 | cERROR(1,("No memory for large SMB response")); |
230 | 234 | msleep(3000); | |
231 | if (smb_buffer == NULL) { | 235 | /* retry will check if exiting */ |
232 | cERROR(1,("Can not get memory for SMB response")); | 236 | continue; |
233 | set_current_state(TASK_INTERRUPTIBLE); | 237 | } |
234 | schedule_timeout(HZ * 3); /* give system time to free memory */ | 238 | } else if(isLargeBuf) { |
235 | continue; | 239 | /* we are reusing a dirtry large buf, clear its start */ |
240 | memset(bigbuf, 0, sizeof (struct smb_hdr)); | ||
236 | } | 241 | } |
242 | |||
243 | if (smallbuf == NULL) { | ||
244 | smallbuf = cifs_small_buf_get(); | ||
245 | if(smallbuf == NULL) { | ||
246 | cERROR(1,("No memory for SMB response")); | ||
247 | msleep(1000); | ||
248 | /* retry will check if exiting */ | ||
249 | continue; | ||
250 | } | ||
251 | /* beginning of smb buffer is cleared in our buf_get */ | ||
252 | } else /* if existing small buf clear beginning */ | ||
253 | memset(smallbuf, 0, sizeof (struct smb_hdr)); | ||
254 | |||
255 | isLargeBuf = FALSE; | ||
256 | smb_buffer = smallbuf; | ||
237 | iov.iov_base = smb_buffer; | 257 | iov.iov_base = smb_buffer; |
238 | iov.iov_len = 4; | 258 | iov.iov_len = 4; |
239 | smb_msg.msg_control = NULL; | 259 | smb_msg.msg_control = NULL; |
@@ -251,8 +271,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
251 | csocket = server->ssocket; | 271 | csocket = server->ssocket; |
252 | continue; | 272 | continue; |
253 | } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) { | 273 | } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) { |
254 | set_current_state(TASK_INTERRUPTIBLE); | 274 | msleep(1); /* minimum sleep to prevent looping |
255 | schedule_timeout(1); /* minimum sleep to prevent looping | ||
256 | allowing socket to clear and app threads to set | 275 | allowing socket to clear and app threads to set |
257 | tcpStatus CifsNeedReconnect if server hung */ | 276 | tcpStatus CifsNeedReconnect if server hung */ |
258 | continue; | 277 | continue; |
@@ -295,8 +314,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
295 | } else { | 314 | } else { |
296 | /* give server a second to | 315 | /* give server a second to |
297 | clean up before reconnect attempt */ | 316 | clean up before reconnect attempt */ |
298 | set_current_state(TASK_INTERRUPTIBLE); | 317 | msleep(1000); |
299 | schedule_timeout(HZ); | ||
300 | /* always try 445 first on reconnect | 318 | /* always try 445 first on reconnect |
301 | since we get NACK on some if we ever | 319 | since we get NACK on some if we ever |
302 | connected to port 139 (the NACK is | 320 | connected to port 139 (the NACK is |
@@ -325,6 +343,11 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
325 | wake_up(&server->response_q); | 343 | wake_up(&server->response_q); |
326 | continue; | 344 | continue; |
327 | } else { /* length ok */ | 345 | } else { /* length ok */ |
346 | if(pdu_length > MAX_CIFS_HDR_SIZE - 4) { | ||
347 | isLargeBuf = TRUE; | ||
348 | memcpy(bigbuf, smallbuf, 4); | ||
349 | smb_buffer = bigbuf; | ||
350 | } | ||
328 | length = 0; | 351 | length = 0; |
329 | iov.iov_base = 4 + (char *)smb_buffer; | 352 | iov.iov_base = 4 + (char *)smb_buffer; |
330 | iov.iov_len = pdu_length; | 353 | iov.iov_len = pdu_length; |
@@ -377,6 +400,10 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
377 | } | 400 | } |
378 | spin_unlock(&GlobalMid_Lock); | 401 | spin_unlock(&GlobalMid_Lock); |
379 | if (task_to_wake) { | 402 | if (task_to_wake) { |
403 | if(isLargeBuf) | ||
404 | bigbuf = NULL; | ||
405 | else | ||
406 | smallbuf = NULL; | ||
380 | smb_buffer = NULL; /* will be freed by users thread after he is done */ | 407 | smb_buffer = NULL; /* will be freed by users thread after he is done */ |
381 | wake_up_process(task_to_wake); | 408 | wake_up_process(task_to_wake); |
382 | } else if (is_valid_oplock_break(smb_buffer) == FALSE) { | 409 | } else if (is_valid_oplock_break(smb_buffer) == FALSE) { |
@@ -406,15 +433,17 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
406 | and get out of SendReceive. */ | 433 | and get out of SendReceive. */ |
407 | wake_up_all(&server->request_q); | 434 | wake_up_all(&server->request_q); |
408 | /* give those requests time to exit */ | 435 | /* give those requests time to exit */ |
409 | set_current_state(TASK_INTERRUPTIBLE); | 436 | msleep(125); |
410 | schedule_timeout(HZ/8); | 437 | |
411 | |||
412 | if(server->ssocket) { | 438 | if(server->ssocket) { |
413 | sock_release(csocket); | 439 | sock_release(csocket); |
414 | server->ssocket = NULL; | 440 | server->ssocket = NULL; |
415 | } | 441 | } |
416 | if (smb_buffer) /* buffer usually freed in free_mid - need to free it on error or exit */ | 442 | /* buffer usuallly freed in free_mid - need to free it here on exit */ |
417 | cifs_buf_release(smb_buffer); | 443 | if (bigbuf != NULL) |
444 | cifs_buf_release(bigbuf); | ||
445 | if (smallbuf != NULL) | ||
446 | cifs_small_buf_release(smallbuf); | ||
418 | 447 | ||
419 | read_lock(&GlobalSMBSeslock); | 448 | read_lock(&GlobalSMBSeslock); |
420 | if (list_empty(&server->pending_mid_q)) { | 449 | if (list_empty(&server->pending_mid_q)) { |
@@ -444,17 +473,15 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
444 | } | 473 | } |
445 | spin_unlock(&GlobalMid_Lock); | 474 | spin_unlock(&GlobalMid_Lock); |
446 | read_unlock(&GlobalSMBSeslock); | 475 | read_unlock(&GlobalSMBSeslock); |
447 | set_current_state(TASK_INTERRUPTIBLE); | ||
448 | /* 1/8th of sec is more than enough time for them to exit */ | 476 | /* 1/8th of sec is more than enough time for them to exit */ |
449 | schedule_timeout(HZ/8); | 477 | msleep(125); |
450 | } | 478 | } |
451 | 479 | ||
452 | if (list_empty(&server->pending_mid_q)) { | 480 | if (list_empty(&server->pending_mid_q)) { |
453 | /* mpx threads have not exited yet give them | 481 | /* mpx threads have not exited yet give them |
454 | at least the smb send timeout time for long ops */ | 482 | at least the smb send timeout time for long ops */ |
455 | cFYI(1, ("Wait for exit from demultiplex thread")); | 483 | cFYI(1, ("Wait for exit from demultiplex thread")); |
456 | set_current_state(TASK_INTERRUPTIBLE); | 484 | msleep(46); |
457 | schedule_timeout(46 * HZ); | ||
458 | /* if threads still have not exited they are probably never | 485 | /* if threads still have not exited they are probably never |
459 | coming home not much else we can do but free the memory */ | 486 | coming home not much else we can do but free the memory */ |
460 | } | 487 | } |
@@ -469,9 +496,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
469 | length + cifs_min_rcv, | 496 | length + cifs_min_rcv, |
470 | GFP_KERNEL); | 497 | GFP_KERNEL); |
471 | } | 498 | } |
472 | 499 | ||
473 | set_current_state(TASK_INTERRUPTIBLE); | 500 | msleep(250); |
474 | schedule_timeout(HZ/4); | ||
475 | return 0; | 501 | return 0; |
476 | } | 502 | } |
477 | 503 | ||