Commit b8643e1b authored by Steve French's avatar Steve French Committed by Linus Torvalds

[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: default avatarLinus Torvalds <torvalds@osdl.org>
parent c81156dd
/* /*
* fs/cifs_debug.c * fs/cifs_debug.c
* *
* Copyright (C) International Business Machines Corp., 2000,2003 * Copyright (C) International Business Machines Corp., 2000,2005
* *
* Modified by Steve French (sfrench@us.ibm.com) * Modified by Steve French (sfrench@us.ibm.com)
* *
...@@ -92,8 +92,10 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, ...@@ -92,8 +92,10 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
length = length =
sprintf(buf, sprintf(buf,
"\n%d) Name: %s Domain: %s Mounts: %d ServerOS: %s \n\tServerNOS: %s\tCapabilities: 0x%x\n\tSMB session status: %d\t", "\n%d) Name: %s Domain: %s Mounts: %d ServerOS: %s \n\tServerNOS: %s\tCapabilities: 0x%x\n\tSMB session status: %d\t",
i, ses->serverName, ses->serverDomain, atomic_read(&ses->inUse), i, ses->serverName, ses->serverDomain,
ses->serverOS, ses->serverNOS, ses->capabilities,ses->status); atomic_read(&ses->inUse),
ses->serverOS, ses->serverNOS,
ses->capabilities,ses->status);
buf += length; buf += length;
if(ses->server) { if(ses->server) {
buf += sprintf(buf, "TCP status: %d\n\tLocal Users To Server: %d SecMode: 0x%x Req Active: %d", buf += sprintf(buf, "TCP status: %d\n\tLocal Users To Server: %d SecMode: 0x%x Req Active: %d",
...@@ -207,7 +209,8 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset, ...@@ -207,7 +209,8 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
buf += item_length; buf += item_length;
item_length = item_length =
sprintf(buf,"SMB Request/Response Buffer: %d Pool size: %d\n", sprintf(buf,"SMB Request/Response Buffer: %d Pool size: %d\n",
bufAllocCount.counter,cifs_min_rcv + tcpSesAllocCount.counter); bufAllocCount.counter,
cifs_min_rcv + tcpSesAllocCount.counter);
length += item_length; length += item_length;
buf += item_length; buf += item_length;
item_length = item_length =
......
/* /*
* fs/cifs/connect.c * fs/cifs/connect.c
* *
* Copyright (C) International Business Machines Corp., 2002,2004 * Copyright (C) International Business Machines Corp., 2002,2005
* Author(s): Steve French (sfrench@us.ibm.com) * Author(s): Steve French (sfrench@us.ibm.com)
* *
* This library is free software; you can redistribute it and/or modify * This library is free software; you can redistribute it and/or modify
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/utsname.h> #include <linux/utsname.h>
#include <linux/mempool.h> #include <linux/mempool.h>
#include <linux/delay.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/processor.h> #include <asm/processor.h>
#include "cifspdu.h" #include "cifspdu.h"
...@@ -198,6 +199,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -198,6 +199,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
int length; int length;
unsigned int pdu_length, total_read; unsigned int pdu_length, total_read;
struct smb_hdr *smb_buffer = NULL; struct smb_hdr *smb_buffer = NULL;
struct smb_hdr *bigbuf = NULL;
struct smb_hdr *smallbuf = NULL;
struct msghdr smb_msg; struct msghdr smb_msg;
struct kvec iov; struct kvec iov;
struct socket *csocket = server->ssocket; struct socket *csocket = server->ssocket;
...@@ -206,6 +209,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -206,6 +209,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
struct task_struct *task_to_wake = NULL; struct task_struct *task_to_wake = NULL;
struct mid_q_entry *mid_entry; struct mid_q_entry *mid_entry;
char *temp; char *temp;
int isLargeBuf = FALSE;
daemonize("cifsd"); daemonize("cifsd");
allow_signal(SIGKILL); allow_signal(SIGKILL);
...@@ -223,17 +227,33 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -223,17 +227,33 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
} }
while (server->tcpStatus != CifsExiting) { while (server->tcpStatus != CifsExiting) {
if (smb_buffer == NULL) if (bigbuf == NULL) {
smb_buffer = cifs_buf_get(); bigbuf = cifs_buf_get();
else if(bigbuf == NULL) {
memset(smb_buffer, 0, sizeof (struct smb_hdr)); cERROR(1,("No memory for large SMB response"));
msleep(3000);
/* retry will check if exiting */
continue;
}
} else if(isLargeBuf) {
/* we are reusing a dirtry large buf, clear its start */
memset(bigbuf, 0, sizeof (struct smb_hdr));
}
if (smb_buffer == NULL) { if (smallbuf == NULL) {
cERROR(1,("Can not get memory for SMB response")); smallbuf = cifs_small_buf_get();
set_current_state(TASK_INTERRUPTIBLE); if(smallbuf == NULL) {
schedule_timeout(HZ * 3); /* give system time to free memory */ cERROR(1,("No memory for SMB response"));
msleep(1000);
/* retry will check if exiting */
continue; continue;
} }
/* beginning of smb buffer is cleared in our buf_get */
} else /* if existing small buf clear beginning */
memset(smallbuf, 0, sizeof (struct smb_hdr));
isLargeBuf = FALSE;
smb_buffer = smallbuf;
iov.iov_base = smb_buffer; iov.iov_base = smb_buffer;
iov.iov_len = 4; iov.iov_len = 4;
smb_msg.msg_control = NULL; smb_msg.msg_control = NULL;
...@@ -251,8 +271,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -251,8 +271,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
csocket = server->ssocket; csocket = server->ssocket;
continue; continue;
} else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) { } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
set_current_state(TASK_INTERRUPTIBLE); msleep(1); /* minimum sleep to prevent looping
schedule_timeout(1); /* minimum sleep to prevent looping
allowing socket to clear and app threads to set allowing socket to clear and app threads to set
tcpStatus CifsNeedReconnect if server hung */ tcpStatus CifsNeedReconnect if server hung */
continue; continue;
...@@ -295,8 +314,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -295,8 +314,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
} else { } else {
/* give server a second to /* give server a second to
clean up before reconnect attempt */ clean up before reconnect attempt */
set_current_state(TASK_INTERRUPTIBLE); msleep(1000);
schedule_timeout(HZ);
/* always try 445 first on reconnect /* always try 445 first on reconnect
since we get NACK on some if we ever since we get NACK on some if we ever
connected to port 139 (the NACK is connected to port 139 (the NACK is
...@@ -325,6 +343,11 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -325,6 +343,11 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
wake_up(&server->response_q); wake_up(&server->response_q);
continue; continue;
} else { /* length ok */ } else { /* length ok */
if(pdu_length > MAX_CIFS_HDR_SIZE - 4) {
isLargeBuf = TRUE;
memcpy(bigbuf, smallbuf, 4);
smb_buffer = bigbuf;
}
length = 0; length = 0;
iov.iov_base = 4 + (char *)smb_buffer; iov.iov_base = 4 + (char *)smb_buffer;
iov.iov_len = pdu_length; iov.iov_len = pdu_length;
...@@ -377,6 +400,10 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -377,6 +400,10 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
} }
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
if (task_to_wake) { if (task_to_wake) {
if(isLargeBuf)
bigbuf = NULL;
else
smallbuf = NULL;
smb_buffer = NULL; /* will be freed by users thread after he is done */ smb_buffer = NULL; /* will be freed by users thread after he is done */
wake_up_process(task_to_wake); wake_up_process(task_to_wake);
} else if (is_valid_oplock_break(smb_buffer) == FALSE) { } else if (is_valid_oplock_break(smb_buffer) == FALSE) {
...@@ -406,15 +433,17 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -406,15 +433,17 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
and get out of SendReceive. */ and get out of SendReceive. */
wake_up_all(&server->request_q); wake_up_all(&server->request_q);
/* give those requests time to exit */ /* give those requests time to exit */
set_current_state(TASK_INTERRUPTIBLE); msleep(125);
schedule_timeout(HZ/8);
if(server->ssocket) { if(server->ssocket) {
sock_release(csocket); sock_release(csocket);
server->ssocket = NULL; server->ssocket = NULL;
} }
if (smb_buffer) /* buffer usually freed in free_mid - need to free it on error or exit */ /* buffer usuallly freed in free_mid - need to free it here on exit */
cifs_buf_release(smb_buffer); if (bigbuf != NULL)
cifs_buf_release(bigbuf);
if (smallbuf != NULL)
cifs_small_buf_release(smallbuf);
read_lock(&GlobalSMBSeslock); read_lock(&GlobalSMBSeslock);
if (list_empty(&server->pending_mid_q)) { if (list_empty(&server->pending_mid_q)) {
...@@ -444,17 +473,15 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -444,17 +473,15 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
} }
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
read_unlock(&GlobalSMBSeslock); read_unlock(&GlobalSMBSeslock);
set_current_state(TASK_INTERRUPTIBLE);
/* 1/8th of sec is more than enough time for them to exit */ /* 1/8th of sec is more than enough time for them to exit */
schedule_timeout(HZ/8); msleep(125);
} }
if (list_empty(&server->pending_mid_q)) { if (list_empty(&server->pending_mid_q)) {
/* mpx threads have not exited yet give them /* mpx threads have not exited yet give them
at least the smb send timeout time for long ops */ at least the smb send timeout time for long ops */
cFYI(1, ("Wait for exit from demultiplex thread")); cFYI(1, ("Wait for exit from demultiplex thread"));
set_current_state(TASK_INTERRUPTIBLE); msleep(46);
schedule_timeout(46 * HZ);
/* if threads still have not exited they are probably never /* if threads still have not exited they are probably never
coming home not much else we can do but free the memory */ coming home not much else we can do but free the memory */
} }
...@@ -470,8 +497,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -470,8 +497,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
GFP_KERNEL); GFP_KERNEL);
} }
set_current_state(TASK_INTERRUPTIBLE); msleep(250);
schedule_timeout(HZ/4);
return 0; return 0;
} }
......
/* /*
* fs/cifs/transport.c * fs/cifs/transport.c
* *
* Copyright (C) International Business Machines Corp., 2002,2004 * Copyright (C) International Business Machines Corp., 2002,2005
* Author(s): Steve French (sfrench@us.ibm.com) * Author(s): Steve French (sfrench@us.ibm.com)
* *
* This library is free software; you can redistribute it and/or modify * This library is free software; you can redistribute it and/or modify
...@@ -79,7 +79,10 @@ DeleteMidQEntry(struct mid_q_entry *midEntry) ...@@ -79,7 +79,10 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
list_del(&midEntry->qhead); list_del(&midEntry->qhead);
atomic_dec(&midCount); atomic_dec(&midCount);
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
if(midEntry->largeBuf)
cifs_buf_release(midEntry->resp_buf); cifs_buf_release(midEntry->resp_buf);
else
cifs_small_buf_release(midEntry->resp_buf);
mempool_free(midEntry, cifs_mid_poolp); mempool_free(midEntry, cifs_mid_poolp);
} }
......
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