diff options
Diffstat (limited to 'fs/cifs')
-rw-r--r-- | fs/cifs/cifsproto.h | 6 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 57 | ||||
-rw-r--r-- | fs/cifs/file.c | 21 | ||||
-rw-r--r-- | fs/cifs/transport.c | 223 |
4 files changed, 231 insertions, 76 deletions
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index ea239dea571e..b43ac9230eab 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -47,6 +47,10 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, | |||
47 | struct smb_hdr * /* input */ , | 47 | struct smb_hdr * /* input */ , |
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 *, | ||
51 | struct smb_hdr * /* input */ , int hdr_len, | ||
52 | const char * /* SMB data to send */ , int data_len, | ||
53 | int * /* bytes returned */ , const int long_op); | ||
50 | extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); | 54 | extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); |
51 | extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); | 55 | extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); |
52 | extern int is_valid_oplock_break(struct smb_hdr *smb); | 56 | extern int is_valid_oplock_break(struct smb_hdr *smb); |
@@ -222,7 +226,7 @@ extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
222 | extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | 226 | extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, |
223 | const int netfid, const unsigned int count, | 227 | const int netfid, const unsigned int count, |
224 | const __u64 offset, unsigned int *nbytes, | 228 | const __u64 offset, unsigned int *nbytes, |
225 | const char __user *buf,const int long_op); | 229 | const char *buf,const int long_op); |
226 | extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, | 230 | extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, |
227 | const unsigned char *searchName, __u64 * inode_number, | 231 | const unsigned char *searchName, __u64 * inode_number, |
228 | const struct nls_table *nls_codepage, | 232 | const struct nls_table *nls_codepage, |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 3c628bf667a5..b4f7b9859e3b 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -951,56 +951,69 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
951 | } | 951 | } |
952 | 952 | ||
953 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 953 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
954 | int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | 954 | int |
955 | CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | ||
955 | const int netfid, const unsigned int count, | 956 | const int netfid, const unsigned int count, |
956 | const __u64 offset, unsigned int *nbytes, const char __user *buf, | 957 | const __u64 offset, unsigned int *nbytes, const char *buf, |
957 | const int long_op) | 958 | const int long_op) |
958 | { | 959 | { |
959 | int rc = -EACCES; | 960 | int rc = -EACCES; |
960 | WRITE_REQ *pSMB = NULL; | 961 | WRITE_REQ *pSMB = NULL; |
961 | WRITE_RSP *pSMBr = NULL; | 962 | int bytes_returned; |
962 | /*int bytes_returned;*/ | 963 | int smb_hdr_len; |
963 | unsigned bytes_sent; | 964 | __u32 bytes_sent; |
964 | __u16 byte_count; | 965 | __u16 byte_count; |
965 | 966 | ||
967 | cERROR(1,("write2 at %lld %d bytes",offset,count)); /* BB removeme BB */ | ||
966 | rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB); | 968 | rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB); |
967 | |||
968 | if (rc) | 969 | if (rc) |
969 | return rc; | 970 | return rc; |
970 | |||
971 | pSMBr = (WRITE_RSP *)pSMB; /* BB removeme BB */ | ||
972 | |||
973 | /* tcon and ses pointer are checked in smb_init */ | 971 | /* tcon and ses pointer are checked in smb_init */ |
974 | if (tcon->ses->server == NULL) | 972 | if (tcon->ses->server == NULL) |
975 | return -ECONNABORTED; | 973 | return -ECONNABORTED; |
976 | 974 | ||
977 | pSMB->AndXCommand = 0xFF; /* none */ | 975 | pSMB->AndXCommand = 0xFF; /* none */ |
978 | pSMB->Fid = netfid; | 976 | pSMB->Fid = netfid; |
979 | pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); | 977 | pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); |
980 | pSMB->OffsetHigh = cpu_to_le32(offset >> 32); | 978 | pSMB->OffsetHigh = cpu_to_le32(offset >> 32); |
981 | pSMB->Reserved = 0xFFFFFFFF; | 979 | pSMB->Reserved = 0xFFFFFFFF; |
982 | pSMB->WriteMode = 0; | 980 | pSMB->WriteMode = 0; |
983 | pSMB->Remaining = 0; | 981 | pSMB->Remaining = 0; |
984 | bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & ~0xFF; | 982 | |
983 | /* Can increase buffer size if buffer is big enough in some cases - ie | ||
984 | can send more if LARGE_WRITE_X capability returned by the server and if | ||
985 | our buffer is big enough or if we convert to iovecs on socket writes | ||
986 | and eliminate the copy to the CIFS buffer */ | ||
987 | if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) { | ||
988 | bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count); | ||
989 | } else { | ||
990 | bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) | ||
991 | & ~0xFF; | ||
992 | } | ||
993 | |||
985 | if (bytes_sent > count) | 994 | if (bytes_sent > count) |
986 | bytes_sent = count; | 995 | bytes_sent = count; |
987 | pSMB->DataLengthHigh = 0; | ||
988 | pSMB->DataOffset = | 996 | pSMB->DataOffset = |
989 | cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4); | 997 | cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4); |
990 | 998 | ||
991 | byte_count = bytes_sent + 1 /* pad */ ; | 999 | byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */ |
992 | pSMB->DataLengthLow = cpu_to_le16(bytes_sent); | 1000 | pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF); |
993 | pSMB->DataLengthHigh = 0; | 1001 | pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16); |
994 | pSMB->hdr.smb_buf_length += byte_count; | 1002 | smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */ |
1003 | pSMB->hdr.smb_buf_length += bytes_sent+1; | ||
995 | pSMB->ByteCount = cpu_to_le16(byte_count); | 1004 | pSMB->ByteCount = cpu_to_le16(byte_count); |
996 | 1005 | ||
997 | /* rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1006 | rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB, smb_hdr_len, |
998 | (struct smb_hdr *) pSMBr, buf, buflen, &bytes_returned, long_op); */ /* BB fixme BB */ | 1007 | buf, bytes_sent, &bytes_returned, long_op); |
999 | if (rc) { | 1008 | if (rc) { |
1000 | cFYI(1, ("Send error in write2 (large write) = %d", rc)); | 1009 | cFYI(1, ("Send error in write = %d", rc)); |
1001 | *nbytes = 0; | 1010 | *nbytes = 0; |
1002 | } else | 1011 | } else { |
1003 | *nbytes = le16_to_cpu(pSMBr->Count); | 1012 | WRITE_RSP * pSMBr = (WRITE_RSP *)pSMB; |
1013 | *nbytes = le16_to_cpu(pSMBr->CountHigh); | ||
1014 | *nbytes = (*nbytes) << 16; | ||
1015 | *nbytes += le16_to_cpu(pSMBr->Count); | ||
1016 | } | ||
1004 | 1017 | ||
1005 | cifs_small_buf_release(pSMB); | 1018 | cifs_small_buf_release(pSMB); |
1006 | 1019 | ||
@@ -1009,6 +1022,8 @@ int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | |||
1009 | 1022 | ||
1010 | return rc; | 1023 | return rc; |
1011 | } | 1024 | } |
1025 | |||
1026 | |||
1012 | #endif /* CIFS_EXPERIMENTAL */ | 1027 | #endif /* CIFS_EXPERIMENTAL */ |
1013 | 1028 | ||
1014 | int | 1029 | int |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index dde2d251fc3d..ca74c1151be9 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -791,9 +791,8 @@ static ssize_t cifs_write(struct file *file, const char *write_data, | |||
791 | 791 | ||
792 | pTcon = cifs_sb->tcon; | 792 | pTcon = cifs_sb->tcon; |
793 | 793 | ||
794 | /* cFYI(1, | 794 | cFYI(1,(" write %d bytes to offset %lld of %s", write_size, |
795 | (" write %d bytes to offset %lld of %s", write_size, | 795 | *poffset, file->f_dentry->d_name.name)); /* BB removeme BB */ |
796 | *poffset, file->f_dentry->d_name.name)); */ | ||
797 | 796 | ||
798 | if (file->private_data == NULL) | 797 | if (file->private_data == NULL) |
799 | return -EBADF; | 798 | return -EBADF; |
@@ -846,7 +845,21 @@ static ssize_t cifs_write(struct file *file, const char *write_data, | |||
846 | if (rc != 0) | 845 | if (rc != 0) |
847 | break; | 846 | break; |
848 | } | 847 | } |
849 | 848 | #ifdef CIFS_EXPERIMENTAL | |
849 | /* BB FIXME We can not sign across two buffers yet */ | ||
850 | cERROR(1,("checking signing")); /* BB removeme BB */ | ||
851 | if(pTcon->ses->server->secMode & | ||
852 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED) == 0) | ||
853 | rc = CIFSSMBWrite2(xid, pTcon, | ||
854 | open_file->netfid, | ||
855 | min_t(const int, cifs_sb->wsize, | ||
856 | write_size - total_written), | ||
857 | *poffset, &bytes_written, | ||
858 | write_data + total_written, | ||
859 | long_op); | ||
860 | } else | ||
861 | /* BB FIXME fixup indentation of line below */ | ||
862 | #endif | ||
850 | rc = CIFSSMBWrite(xid, pTcon, | 863 | rc = CIFSSMBWrite(xid, pTcon, |
851 | open_file->netfid, | 864 | open_file->netfid, |
852 | min_t(const int, cifs_sb->wsize, | 865 | min_t(const int, cifs_sb->wsize, |
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 0046c219833d..04f4af07fdd4 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -49,7 +49,8 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) | |||
49 | return NULL; | 49 | return NULL; |
50 | } | 50 | } |
51 | 51 | ||
52 | temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,SLAB_KERNEL | SLAB_NOFS); | 52 | temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp, |
53 | SLAB_KERNEL | SLAB_NOFS); | ||
53 | if (temp == NULL) | 54 | if (temp == NULL) |
54 | return temp; | 55 | return temp; |
55 | else { | 56 | else { |
@@ -179,27 +180,24 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, | |||
179 | return rc; | 180 | return rc; |
180 | } | 181 | } |
181 | 182 | ||
182 | #ifdef CIFS_EXPERIMENTAL | 183 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
183 | /* BB finish off this function, adding support for writing set of pages as iovec */ | 184 | static int |
184 | /* and also adding support for operations that need to parse the response smb */ | 185 | smb_send2(struct socket *ssocket, struct smb_hdr *smb_buffer, |
185 | 186 | unsigned int smb_hdr_length, const char * data, unsigned int datalen, | |
186 | int | 187 | struct sockaddr *sin) |
187 | smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer, | ||
188 | unsigned int smb_buf_length, struct kvec * write_vector | ||
189 | /* page list */, struct sockaddr *sin) | ||
190 | { | 188 | { |
191 | int rc = 0; | 189 | int rc = 0; |
192 | int i = 0; | 190 | int i = 0; |
193 | struct msghdr smb_msg; | 191 | struct msghdr smb_msg; |
194 | number_of_pages += 1; /* account for SMB header */ | 192 | struct kvec iov[2]; |
195 | struct kvec * piov = kmalloc(number_of_pages * sizeof(struct kvec)); | 193 | unsigned len = smb_hdr_length + 4; |
196 | unsigned len = smb_buf_length + 4; | 194 | |
197 | |||
198 | if(ssocket == NULL) | 195 | if(ssocket == NULL) |
199 | return -ENOTSOCK; /* BB eventually add reconnect code here */ | 196 | return -ENOTSOCK; /* BB eventually add reconnect code here */ |
200 | iov.iov_base = smb_buffer; | 197 | iov[0].iov_base = smb_buffer; |
201 | iov.iov_len = len; | 198 | iov[0].iov_len = len; |
202 | 199 | iov[1].iov_base = data; | |
200 | iov[2].iov_len = datalen; | ||
203 | smb_msg.msg_name = sin; | 201 | smb_msg.msg_name = sin; |
204 | smb_msg.msg_namelen = sizeof (struct sockaddr); | 202 | smb_msg.msg_namelen = sizeof (struct sockaddr); |
205 | smb_msg.msg_control = NULL; | 203 | smb_msg.msg_control = NULL; |
@@ -212,12 +210,11 @@ smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer, | |||
212 | Flags2 is converted in SendReceive */ | 210 | Flags2 is converted in SendReceive */ |
213 | 211 | ||
214 | smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); | 212 | smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); |
215 | cFYI(1, ("Sending smb of length %d ", smb_buf_length)); | 213 | cFYI(1, ("Sending smb of length %d ", len + datalen)); |
216 | dump_smb(smb_buffer, len); | 214 | dump_smb(smb_buffer, len); |
217 | 215 | ||
218 | while (len > 0) { | 216 | while (len + datalen > 0) { |
219 | rc = kernel_sendmsg(ssocket, &smb_msg, &iov, number_of_pages, | 217 | rc = kernel_sendmsg(ssocket, &smb_msg, iov, 2, len); |
220 | len); | ||
221 | if ((rc == -ENOSPC) || (rc == -EAGAIN)) { | 218 | if ((rc == -ENOSPC) || (rc == -EAGAIN)) { |
222 | i++; | 219 | i++; |
223 | if(i > 60) { | 220 | if(i > 60) { |
@@ -232,9 +229,22 @@ smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer, | |||
232 | } | 229 | } |
233 | if (rc < 0) | 230 | if (rc < 0) |
234 | break; | 231 | break; |
235 | iov.iov_base += rc; | 232 | if(iov[0].iov_len > 0) { |
236 | iov.iov_len -= rc; | 233 | if(rc >= len) { |
237 | len -= rc; | 234 | iov[0].iov_len = 0; |
235 | rc -= len; | ||
236 | } else { /* some of hdr was not sent */ | ||
237 | len -= rc; | ||
238 | iov[0].iov_len -= rc; | ||
239 | iov[0].iov_base += rc; | ||
240 | continue; | ||
241 | } | ||
242 | } | ||
243 | if((iov[0].iov_len == 0) && (rc > 0)){ | ||
244 | iov[1].iov_base += rc; | ||
245 | iov[1].iov_len -= rc; | ||
246 | datalen -= rc; | ||
247 | } | ||
238 | } | 248 | } |
239 | 249 | ||
240 | if (rc < 0) { | 250 | if (rc < 0) { |
@@ -246,14 +256,15 @@ smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer, | |||
246 | return rc; | 256 | return rc; |
247 | } | 257 | } |
248 | 258 | ||
249 | |||
250 | int | 259 | int |
251 | CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, | 260 | SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, |
252 | struct smb_hdr *in_buf, struct kvec * write_vector /* page list */, int *pbytes_returned, const int long_op) | 261 | struct smb_hdr *in_buf, int hdrlen, const char * data, |
262 | int datalen, int *pbytes_returned, const int long_op) | ||
253 | { | 263 | { |
254 | int rc = 0; | 264 | int rc = 0; |
255 | unsigned long timeout = 15 * HZ; | 265 | unsigned int receive_len; |
256 | struct mid_q_entry *midQ = NULL; | 266 | unsigned long timeout; |
267 | struct mid_q_entry *midQ; | ||
257 | 268 | ||
258 | if (ses == NULL) { | 269 | if (ses == NULL) { |
259 | cERROR(1,("Null smb session")); | 270 | cERROR(1,("Null smb session")); |
@@ -263,14 +274,8 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, | |||
263 | cERROR(1,("Null tcp session")); | 274 | cERROR(1,("Null tcp session")); |
264 | return -EIO; | 275 | return -EIO; |
265 | } | 276 | } |
266 | if(pbytes_returned == NULL) | ||
267 | return -EIO; | ||
268 | else | ||
269 | *pbytes_returned = 0; | ||
270 | 277 | ||
271 | 278 | if(ses->server->tcpStatus == CifsExiting) | |
272 | |||
273 | if(ses->server->tcpStatus == CIFS_EXITING) | ||
274 | return -ENOENT; | 279 | return -ENOENT; |
275 | 280 | ||
276 | /* Ensure that we do not send more than 50 overlapping requests | 281 | /* Ensure that we do not send more than 50 overlapping requests |
@@ -282,7 +287,8 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, | |||
282 | } else { | 287 | } else { |
283 | spin_lock(&GlobalMid_Lock); | 288 | spin_lock(&GlobalMid_Lock); |
284 | while(1) { | 289 | while(1) { |
285 | if(atomic_read(&ses->server->inFlight) >= cifs_max_pending){ | 290 | if(atomic_read(&ses->server->inFlight) >= |
291 | cifs_max_pending){ | ||
286 | spin_unlock(&GlobalMid_Lock); | 292 | spin_unlock(&GlobalMid_Lock); |
287 | wait_event(ses->server->request_q, | 293 | wait_event(ses->server->request_q, |
288 | atomic_read(&ses->server->inFlight) | 294 | atomic_read(&ses->server->inFlight) |
@@ -314,17 +320,17 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, | |||
314 | 320 | ||
315 | if (ses->server->tcpStatus == CifsExiting) { | 321 | if (ses->server->tcpStatus == CifsExiting) { |
316 | rc = -ENOENT; | 322 | rc = -ENOENT; |
317 | goto cifs_out_label; | 323 | goto out_unlock2; |
318 | } else if (ses->server->tcpStatus == CifsNeedReconnect) { | 324 | } else if (ses->server->tcpStatus == CifsNeedReconnect) { |
319 | cFYI(1,("tcp session dead - return to caller to retry")); | 325 | cFYI(1,("tcp session dead - return to caller to retry")); |
320 | rc = -EAGAIN; | 326 | rc = -EAGAIN; |
321 | goto cifs_out_label; | 327 | goto out_unlock2; |
322 | } else if (ses->status != CifsGood) { | 328 | } else if (ses->status != CifsGood) { |
323 | /* check if SMB session is bad because we are setting it up */ | 329 | /* check if SMB session is bad because we are setting it up */ |
324 | if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && | 330 | if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && |
325 | (in_buf->Command != SMB_COM_NEGOTIATE)) { | 331 | (in_buf->Command != SMB_COM_NEGOTIATE)) { |
326 | rc = -EAGAIN; | 332 | rc = -EAGAIN; |
327 | goto cifs_out_label; | 333 | goto out_unlock2; |
328 | } /* else ok - we are setting up session */ | 334 | } /* else ok - we are setting up session */ |
329 | } | 335 | } |
330 | midQ = AllocMidQEntry(in_buf, ses); | 336 | midQ = AllocMidQEntry(in_buf, ses); |
@@ -352,13 +358,12 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, | |||
352 | return -EIO; | 358 | return -EIO; |
353 | } | 359 | } |
354 | 360 | ||
355 | /* BB can we sign efficiently in this path? */ | 361 | /* BB FIXME */ |
356 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); | 362 | /* rc = cifs_sign_smb2(in_buf, data, ses->server, &midQ->sequence_number); */ |
357 | 363 | ||
358 | midQ->midState = MID_REQUEST_SUBMITTED; | 364 | midQ->midState = MID_REQUEST_SUBMITTED; |
359 | /* rc = smb_sendv(ses->server->ssocket, in_buf, in_buf->smb_buf_length, | 365 | rc = smb_send2(ses->server->ssocket, in_buf, hdrlen, data, datalen, |
360 | piovec, | 366 | (struct sockaddr *) &(ses->server->addr.sockAddr)); |
361 | (struct sockaddr *) &(ses->server->addr.sockAddr));*/ | ||
362 | if(rc < 0) { | 367 | if(rc < 0) { |
363 | DeleteMidQEntry(midQ); | 368 | DeleteMidQEntry(midQ); |
364 | up(&ses->server->tcpSem); | 369 | up(&ses->server->tcpSem); |
@@ -370,19 +375,137 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, | |||
370 | return rc; | 375 | return rc; |
371 | } else | 376 | } else |
372 | up(&ses->server->tcpSem); | 377 | up(&ses->server->tcpSem); |
373 | cifs_out_label: | 378 | if (long_op == -1) |
374 | if(midQ) | 379 | goto cifs_no_response_exit2; |
375 | DeleteMidQEntry(midQ); | 380 | else if (long_op == 2) /* writes past end of file can take loong time */ |
376 | 381 | timeout = 300 * HZ; | |
382 | else if (long_op == 1) | ||
383 | timeout = 45 * HZ; /* should be greater than | ||
384 | servers oplock break timeout (about 43 seconds) */ | ||
385 | else if (long_op > 2) { | ||
386 | timeout = MAX_SCHEDULE_TIMEOUT; | ||
387 | } else | ||
388 | timeout = 15 * HZ; | ||
389 | /* wait for 15 seconds or until woken up due to response arriving or | ||
390 | due to last connection to this server being unmounted */ | ||
391 | if (signal_pending(current)) { | ||
392 | /* if signal pending do not hold up user for full smb timeout | ||
393 | but we still give response a change to complete */ | ||
394 | timeout = 2 * HZ; | ||
395 | } | ||
396 | |||
397 | /* No user interrupts in wait - wreaks havoc with performance */ | ||
398 | if(timeout != MAX_SCHEDULE_TIMEOUT) { | ||
399 | timeout += jiffies; | ||
400 | wait_event(ses->server->response_q, | ||
401 | (!(midQ->midState & MID_REQUEST_SUBMITTED)) || | ||
402 | time_after(jiffies, timeout) || | ||
403 | ((ses->server->tcpStatus != CifsGood) && | ||
404 | (ses->server->tcpStatus != CifsNew))); | ||
405 | } else { | ||
406 | wait_event(ses->server->response_q, | ||
407 | (!(midQ->midState & MID_REQUEST_SUBMITTED)) || | ||
408 | ((ses->server->tcpStatus != CifsGood) && | ||
409 | (ses->server->tcpStatus != CifsNew))); | ||
410 | } | ||
411 | |||
412 | spin_lock(&GlobalMid_Lock); | ||
413 | if (midQ->resp_buf) { | ||
414 | spin_unlock(&GlobalMid_Lock); | ||
415 | receive_len = be32_to_cpu(*(__be32 *)midQ->resp_buf); | ||
416 | } else { | ||
417 | cERROR(1,("No response buffer")); | ||
418 | if(midQ->midState == MID_REQUEST_SUBMITTED) { | ||
419 | if(ses->server->tcpStatus == CifsExiting) | ||
420 | rc = -EHOSTDOWN; | ||
421 | else { | ||
422 | ses->server->tcpStatus = CifsNeedReconnect; | ||
423 | midQ->midState = MID_RETRY_NEEDED; | ||
424 | } | ||
425 | } | ||
426 | |||
427 | if (rc != -EHOSTDOWN) { | ||
428 | if(midQ->midState == MID_RETRY_NEEDED) { | ||
429 | rc = -EAGAIN; | ||
430 | cFYI(1,("marking request for retry")); | ||
431 | } else { | ||
432 | rc = -EIO; | ||
433 | } | ||
434 | } | ||
435 | spin_unlock(&GlobalMid_Lock); | ||
436 | DeleteMidQEntry(midQ); | ||
437 | /* If not lock req, update # of requests on wire to server */ | ||
438 | if(long_op < 3) { | ||
439 | atomic_dec(&ses->server->inFlight); | ||
440 | wake_up(&ses->server->request_q); | ||
441 | } | ||
442 | return rc; | ||
443 | } | ||
444 | |||
445 | if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { | ||
446 | cERROR(1, ("Frame too large received. Length: %d Xid: %d", | ||
447 | receive_len, xid)); | ||
448 | rc = -EIO; | ||
449 | } else { /* rcvd frame is ok */ | ||
450 | |||
451 | if (midQ->resp_buf && | ||
452 | (midQ->midState == MID_RESPONSE_RECEIVED)) { | ||
453 | in_buf->smb_buf_length = receive_len; | ||
454 | /* BB verify that length would not overrun small buf */ | ||
455 | memcpy((char *)in_buf + 4, | ||
456 | (char *)midQ->resp_buf + 4, | ||
457 | receive_len); | ||
458 | |||
459 | dump_smb(in_buf, 80); | ||
460 | /* convert the length into a more usable form */ | ||
461 | if((receive_len > 24) && | ||
462 | (ses->server->secMode & (SECMODE_SIGN_REQUIRED | | ||
463 | SECMODE_SIGN_ENABLED))) { | ||
464 | rc = cifs_verify_signature(in_buf, | ||
465 | ses->server->mac_signing_key, | ||
466 | midQ->sequence_number+1); | ||
467 | if(rc) { | ||
468 | cERROR(1,("Unexpected SMB signature")); | ||
469 | /* BB FIXME add code to kill session */ | ||
470 | } | ||
471 | } | ||
472 | |||
473 | *pbytes_returned = in_buf->smb_buf_length; | ||
474 | |||
475 | /* BB special case reconnect tid and uid here? */ | ||
476 | rc = map_smb_to_linux_error(in_buf); | ||
477 | |||
478 | /* convert ByteCount if necessary */ | ||
479 | if (receive_len >= | ||
480 | sizeof (struct smb_hdr) - | ||
481 | 4 /* do not count RFC1001 header */ + | ||
482 | (2 * in_buf->WordCount) + 2 /* bcc */ ) | ||
483 | BCC(in_buf) = le16_to_cpu(BCC(in_buf)); | ||
484 | } else { | ||
485 | rc = -EIO; | ||
486 | cFYI(1,("Bad MID state? ")); | ||
487 | } | ||
488 | } | ||
489 | cifs_no_response_exit2: | ||
490 | DeleteMidQEntry(midQ); | ||
491 | |||
377 | if(long_op < 3) { | 492 | if(long_op < 3) { |
378 | atomic_dec(&ses->server->inFlight); | 493 | atomic_dec(&ses->server->inFlight); |
379 | wake_up(&ses->server->request_q); | 494 | wake_up(&ses->server->request_q); |
380 | } | 495 | } |
381 | 496 | ||
382 | return rc; | 497 | return rc; |
383 | } | ||
384 | 498 | ||
499 | out_unlock2: | ||
500 | up(&ses->server->tcpSem); | ||
501 | /* If not lock req, update # of requests on wire to server */ | ||
502 | if(long_op < 3) { | ||
503 | atomic_dec(&ses->server->inFlight); | ||
504 | wake_up(&ses->server->request_q); | ||
505 | } | ||
385 | 506 | ||
507 | return rc; | ||
508 | } | ||
386 | #endif /* CIFS_EXPERIMENTAL */ | 509 | #endif /* CIFS_EXPERIMENTAL */ |
387 | 510 | ||
388 | int | 511 | int |