diff options
author | Steve French <sfrench@us.ibm.com> | 2005-10-03 16:37:24 -0400 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2005-10-03 16:37:24 -0400 |
commit | 3e84469d0101456caceffc6b22218a49017fcd3f (patch) | |
tree | 2e52687ade7f3e52b5621142997ca6e7b38df70a /fs/cifs/transport.c | |
parent | 70ca734a14366b634224a1e4586d43b36b65ab67 (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.c | 95 |
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 |
184 | static int | 187 | static int |
185 | smb_send2(struct socket *ssocket, struct smb_hdr *smb_buffer, | 188 | smb_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 | ||
261 | int | 275 | int |
262 | SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | 276 | SendReceive2(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); |