aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/transport.c
diff options
context:
space:
mode:
authorSteve French <sfrench@us.ibm.com>2005-10-03 16:37:24 -0400
committerSteve French <sfrench@us.ibm.com>2005-10-03 16:37:24 -0400
commit3e84469d0101456caceffc6b22218a49017fcd3f (patch)
tree2e52687ade7f3e52b5621142997ca6e7b38df70a /fs/cifs/transport.c
parent70ca734a14366b634224a1e4586d43b36b65ab67 (diff)
[CIFS] Add writepages support to shrink memory usage on writes,
eliminate the double copy, and improve cifs write performance and help the server by upping the typical write size from 4K to 16K (or even larger if wsize set explicitly) for servers which support this. Part 1 of 2 Signed-off-by: Dave Kleikamp <shaggy@austin.ibm.com> Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs/transport.c')
-rw-r--r--fs/cifs/transport.c95
1 files changed, 55 insertions, 40 deletions
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 9e8e85a8d186..38b3b2463ae4 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -147,16 +147,19 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
147 Flags2 is converted in SendReceive */ 147 Flags2 is converted in SendReceive */
148 148
149 smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); 149 smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
150 cFYI(1, ("Sending smb of length %d ", smb_buf_length)); 150 cFYI(1, ("Sending smb of length %d", smb_buf_length));
151 dump_smb(smb_buffer, len); 151 dump_smb(smb_buffer, len);
152 152
153 while (len > 0) { 153 while (len > 0) {
154 rc = kernel_sendmsg(ssocket, &smb_msg, &iov, 1, len); 154 rc = kernel_sendmsg(ssocket, &smb_msg, &iov, 1, len);
155 if ((rc == -ENOSPC) || (rc == -EAGAIN)) { 155 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
156 i++; 156 i++;
157 if(i > 60) { 157 /* smaller timeout here than send2 since smaller size */
158 /* Although it may not be required, this also is smaller
159 oplock break time */
160 if(i > 30) {
158 cERROR(1, 161 cERROR(1,
159 ("sends on sock %p stuck for 30 seconds", 162 ("sends on sock %p stuck for 15 seconds",
160 ssocket)); 163 ssocket));
161 rc = -EAGAIN; 164 rc = -EAGAIN;
162 break; 165 break;
@@ -172,7 +175,7 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
172 } 175 }
173 176
174 if (rc < 0) { 177 if (rc < 0) {
175 cERROR(1,("Error %d sending data on socket to server.", rc)); 178 cERROR(1,("Error %d sending data on socket to server", rc));
176 } else { 179 } else {
177 rc = 0; 180 rc = 0;
178 } 181 }
@@ -182,22 +185,20 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
182 185
183#ifdef CONFIG_CIFS_EXPERIMENTAL 186#ifdef CONFIG_CIFS_EXPERIMENTAL
184static int 187static int
185smb_send2(struct socket *ssocket, struct smb_hdr *smb_buffer, 188smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
186 unsigned int smb_hdr_length, const char * data, unsigned int datalen, 189 struct sockaddr *sin)
187 struct sockaddr *sin)
188{ 190{
189 int rc = 0; 191 int rc = 0;
190 int i = 0; 192 int i = 0;
191 struct msghdr smb_msg; 193 struct msghdr smb_msg;
192 struct kvec iov[2]; 194 struct smb_hdr *smb_buffer = iov[0].iov_base;
193 unsigned len = smb_hdr_length + 4; 195 unsigned int len = iov[0].iov_len;
196 unsigned int total_len;
197 int first_vec = 0;
194 198
195 if(ssocket == NULL) 199 if(ssocket == NULL)
196 return -ENOTSOCK; /* BB eventually add reconnect code here */ 200 return -ENOTSOCK; /* BB eventually add reconnect code here */
197 iov[0].iov_base = smb_buffer; 201
198 iov[0].iov_len = len;
199 iov[1].iov_base = data;
200 iov[1].iov_len = datalen;
201 smb_msg.msg_name = sin; 202 smb_msg.msg_name = sin;
202 smb_msg.msg_namelen = sizeof (struct sockaddr); 203 smb_msg.msg_namelen = sizeof (struct sockaddr);
203 smb_msg.msg_control = NULL; 204 smb_msg.msg_control = NULL;
@@ -209,18 +210,23 @@ smb_send2(struct socket *ssocket, struct smb_hdr *smb_buffer,
209 cifssmb.c and RFC1001 len is converted to bigendian in smb_send 210 cifssmb.c and RFC1001 len is converted to bigendian in smb_send
210 Flags2 is converted in SendReceive */ 211 Flags2 is converted in SendReceive */
211 212
213
214 total_len = 0;
215 for (i = 0; i < n_vec; i++)
216 total_len += iov[i].iov_len;
217
212 smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); 218 smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
213 cFYI(1, ("Sending smb: hdrlen %d datalen %d", 219 cFYI(1, ("Sending smb: total_len %d", total_len));
214 smb_hdr_length,datalen));
215 dump_smb(smb_buffer, len); 220 dump_smb(smb_buffer, len);
216 221
217 while (len + datalen > 0) { 222 while (total_len) {
218 rc = kernel_sendmsg(ssocket, &smb_msg, iov, 2, len); 223 rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
224 n_vec - first_vec, total_len);
219 if ((rc == -ENOSPC) || (rc == -EAGAIN)) { 225 if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
220 i++; 226 i++;
221 if(i > 60) { 227 if(i > 40) {
222 cERROR(1, 228 cERROR(1,
223 ("sends on sock %p stuck for 30 seconds", 229 ("sends on sock %p stuck for 20 seconds",
224 ssocket)); 230 ssocket));
225 rc = -EAGAIN; 231 rc = -EAGAIN;
226 break; 232 break;
@@ -230,43 +236,52 @@ smb_send2(struct socket *ssocket, struct smb_hdr *smb_buffer,
230 } 236 }
231 if (rc < 0) 237 if (rc < 0)
232 break; 238 break;
233 if(iov[0].iov_len > 0) { 239
234 if(rc >= len) { 240 if (rc >= total_len) {
235 iov[0].iov_len = 0; 241 WARN_ON(rc > total_len);
236 rc -= len; 242 break;
237 len = 0; 243 }
238 } else { /* some of hdr was not sent */ 244 if(rc == 0) {
239 len -= rc; 245 /* should never happen, letting socket clear before
240 iov[0].iov_len -= rc; 246 retrying is our only obvious option here */
241 iov[0].iov_base += rc; 247 cERROR(1,("tcp sent no data");
242 continue; 248 msleep(500);
243 } 249 continue;
244 } 250 }
245 if((iov[0].iov_len == 0) && (rc > 0)){ 251 total_len -= rc;
246 iov[1].iov_base += rc; 252 for (i = first_vec; i < n_vec; i++) {
247 iov[1].iov_len -= rc; 253 if (iov[i].iov_len) {
248 datalen -= rc; 254 if (rc > iov[i].iov_len) {
255 rc -= iov[i].iov_len;
256 iov[i].iov_len = 0;
257 } else {
258 iov[i].iov_base += rc;
259 iov[i].iov_len -= rc;
260 first_vec = i;
261 break;
262 }
263 }
249 } 264 }
250 } 265 }
251 266
252 if (rc < 0) { 267 if (rc < 0) {
253 cERROR(1,("Error %d sending data on socket to server.", rc)); 268 cERROR(1,("Error %d sending data on socket to server", rc));
254 } else { 269 } else
255 rc = 0; 270 rc = 0;
256 }
257 271
258 return rc; 272 return rc;
259} 273}
260 274
261int 275int
262SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, 276SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
263 struct smb_hdr *in_buf, int hdrlen, const char * data, 277 struct kvec *iov, int n_vec, int *pbytes_returned,
264 int datalen, int *pbytes_returned, const int long_op) 278 const int long_op)
265{ 279{
266 int rc = 0; 280 int rc = 0;
267 unsigned int receive_len; 281 unsigned int receive_len;
268 unsigned long timeout; 282 unsigned long timeout;
269 struct mid_q_entry *midQ; 283 struct mid_q_entry *midQ;
284 struct smb_hdr *in_buf = iov[0].iov_base;
270 285
271 if (ses == NULL) { 286 if (ses == NULL) {
272 cERROR(1,("Null smb session")); 287 cERROR(1,("Null smb session"));
@@ -364,7 +379,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
364/* rc = cifs_sign_smb2(in_buf, data, ses->server, &midQ->sequence_number); */ 379/* rc = cifs_sign_smb2(in_buf, data, ses->server, &midQ->sequence_number); */
365 380
366 midQ->midState = MID_REQUEST_SUBMITTED; 381 midQ->midState = MID_REQUEST_SUBMITTED;
367 rc = smb_send2(ses->server->ssocket, in_buf, hdrlen, data, datalen, 382 rc = smb_send2(ses->server->ssocket, iov, n_vec,
368 (struct sockaddr *) &(ses->server->addr.sockAddr)); 383 (struct sockaddr *) &(ses->server->addr.sockAddr));
369 if(rc < 0) { 384 if(rc < 0) {
370 DeleteMidQEntry(midQ); 385 DeleteMidQEntry(midQ);