aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/connect.c
diff options
context:
space:
mode:
authorSteve French <smfrench@austin.rr.com>2005-04-29 01:41:07 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-29 01:41:07 -0400
commitb8643e1b5253a6a51da5574a55a2f9148e255cfd (patch)
tree7be4a4dc45e83e793f729a69d94b9970d08a2092 /fs/cifs/connect.c
parentc81156dd217818c143a09b6a744e797a04571e99 (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.c80
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