diff options
-rw-r--r-- | fs/cifs/cifsproto.h | 5 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 41 | ||||
-rw-r--r-- | fs/cifs/connect.c | 4 | ||||
-rw-r--r-- | fs/cifs/file.c | 16 | ||||
-rw-r--r-- | fs/cifs/transport.c | 95 |
5 files changed, 89 insertions, 72 deletions
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index dc5a6a6ff2f9..fb3e76043c50 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -48,8 +48,7 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, | |||
48 | struct smb_hdr * /* out */ , | 48 | struct smb_hdr * /* out */ , |
49 | int * /* bytes returned */ , const int long_op); | 49 | int * /* bytes returned */ , const int long_op); |
50 | extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *, | 50 | extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *, |
51 | struct smb_hdr * /* input */ , int hdr_len, | 51 | struct kvec *, int /* nvec */, |
52 | const char * /* SMB data to send */ , int data_len, | ||
53 | int * /* bytes returned */ , const int long_op); | 52 | int * /* bytes returned */ , const int long_op); |
54 | extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); | 53 | extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); |
55 | extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); | 54 | extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); |
@@ -241,7 +240,7 @@ extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
241 | extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | 240 | extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, |
242 | const int netfid, const unsigned int count, | 241 | const int netfid, const unsigned int count, |
243 | const __u64 offset, unsigned int *nbytes, | 242 | const __u64 offset, unsigned int *nbytes, |
244 | const char *buf,const int long_op); | 243 | struct kvec *iov, const int nvec, const int long_op); |
245 | extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, | 244 | extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, |
246 | const unsigned char *searchName, __u64 * inode_number, | 245 | const unsigned char *searchName, __u64 * inode_number, |
247 | const struct nls_table *nls_codepage, | 246 | const struct nls_table *nls_codepage, |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 52caac063a77..365949c14646 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -125,6 +125,9 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
125 | rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon | 125 | rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon |
126 | , nls_codepage); | 126 | , nls_codepage); |
127 | up(&tcon->ses->sesSem); | 127 | up(&tcon->ses->sesSem); |
128 | /* BB FIXME add code to check if wsize needs | ||
129 | update due to negotiated smb buffer size | ||
130 | shrinking */ | ||
128 | if(rc == 0) | 131 | if(rc == 0) |
129 | atomic_inc(&tconInfoReconnectCount); | 132 | atomic_inc(&tconInfoReconnectCount); |
130 | 133 | ||
@@ -220,6 +223,9 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
220 | rc = CIFSTCon(0, tcon->ses, tcon->treeName, | 223 | rc = CIFSTCon(0, tcon->ses, tcon->treeName, |
221 | tcon, nls_codepage); | 224 | tcon, nls_codepage); |
222 | up(&tcon->ses->sesSem); | 225 | up(&tcon->ses->sesSem); |
226 | /* BB FIXME add code to check if wsize needs | ||
227 | update due to negotiated smb buffer size | ||
228 | shrinking */ | ||
223 | if(rc == 0) | 229 | if(rc == 0) |
224 | atomic_inc(&tconInfoReconnectCount); | 230 | atomic_inc(&tconInfoReconnectCount); |
225 | 231 | ||
@@ -1128,15 +1134,13 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
1128 | int | 1134 | int |
1129 | CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | 1135 | CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, |
1130 | const int netfid, const unsigned int count, | 1136 | const int netfid, const unsigned int count, |
1131 | const __u64 offset, unsigned int *nbytes, const char *buf, | 1137 | const __u64 offset, unsigned int *nbytes, struct kvec *iov, |
1132 | const int long_op) | 1138 | int n_vec, const int long_op) |
1133 | { | 1139 | { |
1134 | int rc = -EACCES; | 1140 | int rc = -EACCES; |
1135 | WRITE_REQ *pSMB = NULL; | 1141 | WRITE_REQ *pSMB = NULL; |
1136 | int bytes_returned; | 1142 | int bytes_returned; |
1137 | int smb_hdr_len; | 1143 | int smb_hdr_len; |
1138 | __u32 bytes_sent; | ||
1139 | __u16 byte_count; | ||
1140 | 1144 | ||
1141 | cFYI(1,("write2 at %lld %d bytes",offset,count)); /* BB removeme BB */ | 1145 | cFYI(1,("write2 at %lld %d bytes",offset,count)); /* BB removeme BB */ |
1142 | rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB); | 1146 | rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB); |
@@ -1154,31 +1158,20 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | |||
1154 | pSMB->WriteMode = 0; | 1158 | pSMB->WriteMode = 0; |
1155 | pSMB->Remaining = 0; | 1159 | pSMB->Remaining = 0; |
1156 | 1160 | ||
1157 | /* Can increase buffer size if buffer is big enough in some cases - ie | ||
1158 | can send more if LARGE_WRITE_X capability returned by the server and if | ||
1159 | our buffer is big enough or if we convert to iovecs on socket writes | ||
1160 | and eliminate the copy to the CIFS buffer */ | ||
1161 | if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) { | ||
1162 | bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count); | ||
1163 | } else { | ||
1164 | bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) | ||
1165 | & ~0xFF; | ||
1166 | } | ||
1167 | |||
1168 | if (bytes_sent > count) | ||
1169 | bytes_sent = count; | ||
1170 | pSMB->DataOffset = | 1161 | pSMB->DataOffset = |
1171 | cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4); | 1162 | cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4); |
1172 | 1163 | ||
1173 | byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */ | 1164 | pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF); |
1174 | pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF); | 1165 | pSMB->DataLengthHigh = cpu_to_le16(count >> 16); |
1175 | pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16); | ||
1176 | smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */ | 1166 | smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */ |
1177 | pSMB->hdr.smb_buf_length += bytes_sent+1; | 1167 | pSMB->hdr.smb_buf_length += count+1; |
1178 | pSMB->ByteCount = cpu_to_le16(byte_count); | 1168 | pSMB->ByteCount = cpu_to_le16(count + 1); |
1169 | |||
1170 | iov[0].iov_base = pSMB; | ||
1171 | iov[0].iov_len = smb_hdr_len + 4; | ||
1179 | 1172 | ||
1180 | rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB, smb_hdr_len, | 1173 | rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &bytes_returned, |
1181 | buf, bytes_sent, &bytes_returned, long_op); | 1174 | long_op); |
1182 | cifs_stats_inc(&tcon->num_writes); | 1175 | cifs_stats_inc(&tcon->num_writes); |
1183 | if (rc) { | 1176 | if (rc) { |
1184 | cFYI(1, ("Send error in write = %d", rc)); | 1177 | cFYI(1, ("Send error in write = %d", rc)); |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index e27e5ad8b591..f05d9e2016d5 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -1891,6 +1891,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1891 | } | 1891 | } |
1892 | } | 1892 | } |
1893 | } | 1893 | } |
1894 | if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X)) | ||
1895 | cifs_sb->wsize = min(cifs_sb->wsize, | ||
1896 | (tcon->ses->server->maxBuf - | ||
1897 | MAX_CIFS_HDR_SIZE)); | ||
1894 | } | 1898 | } |
1895 | 1899 | ||
1896 | /* volume_info.password is freed above when existing session found | 1900 | /* volume_info.password is freed above when existing session found |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 3766db2bb7f2..941108352547 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -849,13 +849,19 @@ static ssize_t cifs_write(struct file *file, const char *write_data, | |||
849 | /* BB FIXME We can not sign across two buffers yet */ | 849 | /* BB FIXME We can not sign across two buffers yet */ |
850 | if((experimEnabled) && ((pTcon->ses->server->secMode & | 850 | if((experimEnabled) && ((pTcon->ses->server->secMode & |
851 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0)) { | 851 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0)) { |
852 | struct kvec iov[2]; | ||
853 | unsigned int len; | ||
854 | |||
855 | len = min(cifs_sb->wsize, | ||
856 | write_size - total_written); | ||
857 | /* iov[0] is reserved for smb header */ | ||
858 | iov[1].iov_base = (char *)write_data + | ||
859 | total_written; | ||
860 | iov[1].iov_len = len; | ||
852 | rc = CIFSSMBWrite2(xid, pTcon, | 861 | rc = CIFSSMBWrite2(xid, pTcon, |
853 | open_file->netfid, | 862 | open_file->netfid, len, |
854 | min_t(const int, cifs_sb->wsize, | ||
855 | write_size - total_written), | ||
856 | *poffset, &bytes_written, | 863 | *poffset, &bytes_written, |
857 | write_data + total_written, | 864 | iov, 1, long_op); |
858 | long_op); | ||
859 | } else | 865 | } else |
860 | /* BB FIXME fixup indentation of line below */ | 866 | /* BB FIXME fixup indentation of line below */ |
861 | #endif | 867 | #endif |
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); |