Blame view

fs/cifs/transport.c 26.9 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
  /*
   *   fs/cifs/transport.c
   *
79a58d1f6   Steve French   [CIFS] whitespace...
4
   *   Copyright (C) International Business Machines  Corp., 2002,2007
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
   *   Author(s): Steve French (sfrench@us.ibm.com)
14a441a2b   Steve French   [CIFS] spinlock p...
6
   *   Jeremy Allison (jra@samba.org) 2006.
79a58d1f6   Steve French   [CIFS] whitespace...
7
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
9
10
11
12
13
14
15
16
17
18
19
   *   This library is free software; you can redistribute it and/or modify
   *   it under the terms of the GNU Lesser General Public License as published
   *   by the Free Software Foundation; either version 2.1 of the License, or
   *   (at your option) any later version.
   *
   *   This library is distributed in the hope that it will be useful,
   *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
   *   the GNU Lesser General Public License for more details.
   *
   *   You should have received a copy of the GNU Lesser General Public License
   *   along with this library; if not, write to the Free Software
79a58d1f6   Steve French   [CIFS] whitespace...
20
   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
23
24
25
26
27
28
29
30
31
32
33
34
   */
  
  #include <linux/fs.h>
  #include <linux/list.h>
  #include <linux/wait.h>
  #include <linux/net.h>
  #include <linux/delay.h>
  #include <asm/uaccess.h>
  #include <asm/processor.h>
  #include <linux/mempool.h>
  #include "cifspdu.h"
  #include "cifsglob.h"
  #include "cifsproto.h"
  #include "cifs_debug.h"
50c2f7538   Steve French   [CIFS] whitespace...
35

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
  extern mempool_t *cifs_mid_poolp;
e18b890bb   Christoph Lameter   [PATCH] slab: rem...
37
  extern struct kmem_cache *cifs_oplock_cachep;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
39
  
  static struct mid_q_entry *
7ee1af765   Jeremy Allison   [CIFS]
40
  AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
43
44
  {
  	struct mid_q_entry *temp;
  
  	if (ses == NULL) {
275cde1a1   Steve French   [PATCH] cifs: cle...
45
  		cERROR(1, ("Null session passed in to AllocMidQEntry"));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
48
49
50
51
  		return NULL;
  	}
  	if (ses->server == NULL) {
  		cERROR(1, ("Null TCP session in AllocMidQEntry"));
  		return NULL;
  	}
50c2f7538   Steve French   [CIFS] whitespace...
52

d6e04ae64   Steve French   [CIFS] CIFS write...
53
  	temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,
e94b17660   Christoph Lameter   [PATCH] slab: rem...
54
  						    GFP_KERNEL | GFP_NOFS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
57
58
59
60
61
62
  	if (temp == NULL)
  		return temp;
  	else {
  		memset(temp, 0, sizeof (struct mid_q_entry));
  		temp->mid = smb_buffer->Mid;	/* always LE */
  		temp->pid = current->pid;
  		temp->command = smb_buffer->Command;
  		cFYI(1, ("For smb_command %d", temp->command));
1047abc15   Steve French   [CIFS] CIFS Stats...
63
64
65
  	/*	do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */
  		/* when mid allocated can be before when sent */
  		temp->when_alloc = jiffies;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
  		temp->ses = ses;
  		temp->tsk = current;
  	}
  
  	spin_lock(&GlobalMid_Lock);
  	list_add_tail(&temp->qhead, &ses->server->pending_mid_q);
  	atomic_inc(&midCount);
  	temp->midState = MID_REQUEST_ALLOCATED;
  	spin_unlock(&GlobalMid_Lock);
  	return temp;
  }
  
  static void
  DeleteMidQEntry(struct mid_q_entry *midEntry)
  {
1047abc15   Steve French   [CIFS] CIFS Stats...
81
82
83
  #ifdef CONFIG_CIFS_STATS2
  	unsigned long now;
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
85
86
87
88
  	spin_lock(&GlobalMid_Lock);
  	midEntry->midState = MID_FREE;
  	list_del(&midEntry->qhead);
  	atomic_dec(&midCount);
  	spin_unlock(&GlobalMid_Lock);
79a58d1f6   Steve French   [CIFS] whitespace...
89
  	if (midEntry->largeBuf)
b8643e1b5   Steve French   [PATCH] cifs: Do ...
90
91
92
  		cifs_buf_release(midEntry->resp_buf);
  	else
  		cifs_small_buf_release(midEntry->resp_buf);
1047abc15   Steve French   [CIFS] CIFS Stats...
93
94
95
96
  #ifdef CONFIG_CIFS_STATS2
  	now = jiffies;
  	/* commands taking longer than one second are indications that
  	   something is wrong, unless it is quite a slow link or server */
79a58d1f6   Steve French   [CIFS] whitespace...
97
98
  	if ((now - midEntry->when_alloc) > HZ) {
  		if ((cifsFYI & CIFS_TIMER) &&
1047abc15   Steve French   [CIFS] CIFS Stats...
99
100
101
102
103
104
105
106
107
108
109
  		   (midEntry->command != SMB_COM_LOCKING_ANDX)) {
  			printk(KERN_DEBUG " CIFS slow rsp: cmd %d mid %d",
  			       midEntry->command, midEntry->mid);
  			printk(" A: 0x%lx S: 0x%lx R: 0x%lx
  ",
  			       now - midEntry->when_alloc,
  			       now - midEntry->when_sent,
  			       now - midEntry->when_received);
  		}
  	}
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
111
112
113
  	mempool_free(midEntry, cifs_mid_poolp);
  }
  
  struct oplock_q_entry *
79a58d1f6   Steve French   [CIFS] whitespace...
114
  AllocOplockQEntry(struct inode *pinode, __u16 fid, struct cifsTconInfo *tcon)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
116
  {
  	struct oplock_q_entry *temp;
79a58d1f6   Steve French   [CIFS] whitespace...
117
  	if ((pinode == NULL) || (tcon == NULL)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
119
120
121
  		cERROR(1, ("Null parms passed to AllocOplockQEntry"));
  		return NULL;
  	}
  	temp = (struct oplock_q_entry *) kmem_cache_alloc(cifs_oplock_cachep,
e94b17660   Christoph Lameter   [PATCH] slab: rem...
122
  						       GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
124
125
126
127
128
129
130
131
132
133
134
135
  	if (temp == NULL)
  		return temp;
  	else {
  		temp->pinode = pinode;
  		temp->tcon = tcon;
  		temp->netfid = fid;
  		spin_lock(&GlobalMid_Lock);
  		list_add_tail(&temp->qhead, &GlobalOplock_Q);
  		spin_unlock(&GlobalMid_Lock);
  	}
  	return temp;
  
  }
79a58d1f6   Steve French   [CIFS] whitespace...
136
  void DeleteOplockQEntry(struct oplock_q_entry *oplockEntry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
  {
79a58d1f6   Steve French   [CIFS] whitespace...
138
  	spin_lock(&GlobalMid_Lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
      /* should we check if list empty first? */
  	list_del(&oplockEntry->qhead);
  	spin_unlock(&GlobalMid_Lock);
  	kmem_cache_free(cifs_oplock_cachep, oplockEntry);
  }
  
  int
  smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
  	 unsigned int smb_buf_length, struct sockaddr *sin)
  {
  	int rc = 0;
  	int i = 0;
  	struct msghdr smb_msg;
  	struct kvec iov;
  	unsigned len = smb_buf_length + 4;
79a58d1f6   Steve French   [CIFS] whitespace...
154
  	if (ssocket == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
156
157
158
159
160
161
162
163
164
165
  		return -ENOTSOCK; /* BB eventually add reconnect code here */
  	iov.iov_base = smb_buffer;
  	iov.iov_len = len;
  
  	smb_msg.msg_name = sin;
  	smb_msg.msg_namelen = sizeof (struct sockaddr);
  	smb_msg.msg_control = NULL;
  	smb_msg.msg_controllen = 0;
  	smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
  
  	/* smb header is converted in header_assemble. bcc and rest of SMB word
79a58d1f6   Steve French   [CIFS] whitespace...
166
167
  	   area, and byte area if necessary, is converted to littleendian in
  	   cifssmb.c and RFC1001 len is converted to bigendian in smb_send
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
169
170
  	   Flags2 is converted in SendReceive */
  
  	smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
3e84469d0   Steve French   [CIFS] Add writep...
171
  	cFYI(1, ("Sending smb of length %d", smb_buf_length));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172
173
174
175
176
177
  	dump_smb(smb_buffer, len);
  
  	while (len > 0) {
  		rc = kernel_sendmsg(ssocket, &smb_msg, &iov, 1, len);
  		if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
  			i++;
3e84469d0   Steve French   [CIFS] Add writep...
178
  		/* smaller timeout here than send2 since smaller size */
79a58d1f6   Steve French   [CIFS] whitespace...
179
180
181
  		/* Although it may not be required, this also is smaller
  		   oplock break time */
  			if (i > 12) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
  				cERROR(1,
68058e757   Steve French   [CIFS] Reduce CIF...
183
  				   ("sends on sock %p stuck for 7 seconds",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184
185
186
187
  				    ssocket));
  				rc = -EAGAIN;
  				break;
  			}
68058e757   Steve French   [CIFS] Reduce CIF...
188
  			msleep(1 << i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
190
  			continue;
  		}
79a58d1f6   Steve French   [CIFS] whitespace...
191
  		if (rc < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
  			break;
5e1253b50   Steve French   [CIFS] Correct ci...
193
194
  		else
  			i = 0; /* reset i after each successful send */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195
196
197
198
199
200
  		iov.iov_base += rc;
  		iov.iov_len -= rc;
  		len -= rc;
  	}
  
  	if (rc < 0) {
79a58d1f6   Steve French   [CIFS] whitespace...
201
  		cERROR(1, ("Error %d sending data on socket to server", rc));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
202
203
204
  	} else {
  		rc = 0;
  	}
7ee1af765   Jeremy Allison   [CIFS]
205
206
207
  	/* Don't want to modify the buffer as a
  	   side effect of this call. */
  	smb_buffer->smb_buf_length = smb_buf_length;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
209
  	return rc;
  }
d6e04ae64   Steve French   [CIFS] CIFS write...
210
  static int
3e84469d0   Steve French   [CIFS] Add writep...
211
212
  smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
  	  struct sockaddr *sin)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
214
215
216
  {
  	int rc = 0;
  	int i = 0;
  	struct msghdr smb_msg;
3e84469d0   Steve French   [CIFS] Add writep...
217
218
219
220
  	struct smb_hdr *smb_buffer = iov[0].iov_base;
  	unsigned int len = iov[0].iov_len;
  	unsigned int total_len;
  	int first_vec = 0;
7ee1af765   Jeremy Allison   [CIFS]
221
  	unsigned int smb_buf_length = smb_buffer->smb_buf_length;
50c2f7538   Steve French   [CIFS] whitespace...
222

79a58d1f6   Steve French   [CIFS] whitespace...
223
  	if (ssocket == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
224
  		return -ENOTSOCK; /* BB eventually add reconnect code here */
3e84469d0   Steve French   [CIFS] Add writep...
225

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
227
228
229
230
231
232
  	smb_msg.msg_name = sin;
  	smb_msg.msg_namelen = sizeof (struct sockaddr);
  	smb_msg.msg_control = NULL;
  	smb_msg.msg_controllen = 0;
  	smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
  
  	/* smb header is converted in header_assemble. bcc and rest of SMB word
79a58d1f6   Steve French   [CIFS] whitespace...
233
234
  	   area, and byte area if necessary, is converted to littleendian in
  	   cifssmb.c and RFC1001 len is converted to bigendian in smb_send
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
  	   Flags2 is converted in SendReceive */
3e84469d0   Steve French   [CIFS] Add writep...
236
237
238
239
  
  	total_len = 0;
  	for (i = 0; i < n_vec; i++)
  		total_len += iov[i].iov_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
  	smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
3e84469d0   Steve French   [CIFS] Add writep...
241
  	cFYI(1, ("Sending smb:  total_len %d", total_len));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
  	dump_smb(smb_buffer, len);
3e84469d0   Steve French   [CIFS] Add writep...
243
244
245
  	while (total_len) {
  		rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
  				    n_vec - first_vec, total_len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246
247
  		if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
  			i++;
79a58d1f6   Steve French   [CIFS] whitespace...
248
  			if (i >= 14) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
  				cERROR(1,
68058e757   Steve French   [CIFS] Reduce CIF...
250
  				   ("sends on sock %p stuck for 15 seconds",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
252
253
254
  				    ssocket));
  				rc = -EAGAIN;
  				break;
  			}
68058e757   Steve French   [CIFS] Reduce CIF...
255
  			msleep(1 << i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256
257
  			continue;
  		}
79a58d1f6   Steve French   [CIFS] whitespace...
258
  		if (rc < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259
  			break;
3e84469d0   Steve French   [CIFS] Add writep...
260
261
262
263
264
  
  		if (rc >= total_len) {
  			WARN_ON(rc > total_len);
  			break;
  		}
79a58d1f6   Steve French   [CIFS] whitespace...
265
  		if (rc == 0) {
3e84469d0   Steve French   [CIFS] Add writep...
266
267
  			/* should never happen, letting socket clear before
  			   retrying is our only obvious option here */
79a58d1f6   Steve French   [CIFS] whitespace...
268
  			cERROR(1, ("tcp sent no data"));
3e84469d0   Steve French   [CIFS] Add writep...
269
270
  			msleep(500);
  			continue;
d6e04ae64   Steve French   [CIFS] CIFS write...
271
  		}
3e84469d0   Steve French   [CIFS] Add writep...
272
  		total_len -= rc;
68058e757   Steve French   [CIFS] Reduce CIF...
273
  		/* the line below resets i */
3e84469d0   Steve French   [CIFS] Add writep...
274
275
276
277
278
279
280
281
282
283
284
285
  		for (i = first_vec; i < n_vec; i++) {
  			if (iov[i].iov_len) {
  				if (rc > iov[i].iov_len) {
  					rc -= iov[i].iov_len;
  					iov[i].iov_len = 0;
  				} else {
  					iov[i].iov_base += rc;
  					iov[i].iov_len -= rc;
  					first_vec = i;
  					break;
  				}
  			}
d6e04ae64   Steve French   [CIFS] CIFS write...
286
  		}
5e1253b50   Steve French   [CIFS] Correct ci...
287
  		i = 0; /* in case we get ENOSPC on the next send */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
289
290
  	}
  
  	if (rc < 0) {
79a58d1f6   Steve French   [CIFS] whitespace...
291
  		cERROR(1, ("Error %d sending data on socket to server", rc));
3e84469d0   Steve French   [CIFS] Add writep...
292
  	} else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
  		rc = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294

7ee1af765   Jeremy Allison   [CIFS]
295
296
297
  	/* Don't want to modify the buffer as a
  	   side effect of this call. */
  	smb_buffer->smb_buf_length = smb_buf_length;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298
299
  	return rc;
  }
7ee1af765   Jeremy Allison   [CIFS]
300
  static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
  {
79a58d1f6   Steve French   [CIFS] whitespace...
302
  	if (long_op == -1) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303
304
305
  		/* oplock breaks must not be held up */
  		atomic_inc(&ses->server->inFlight);
  	} else {
79a58d1f6   Steve French   [CIFS] whitespace...
306
307
308
  		spin_lock(&GlobalMid_Lock);
  		while (1) {
  			if (atomic_read(&ses->server->inFlight) >=
d6e04ae64   Steve French   [CIFS] CIFS write...
309
  					cifs_max_pending){
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
  				spin_unlock(&GlobalMid_Lock);
131afd0b7   Steve French   [CIFS] /proc/fs/c...
311
312
313
  #ifdef CONFIG_CIFS_STATS2
  				atomic_inc(&ses->server->num_waiters);
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
315
316
  				wait_event(ses->server->request_q,
  					atomic_read(&ses->server->inFlight)
  					 < cifs_max_pending);
131afd0b7   Steve French   [CIFS] /proc/fs/c...
317
318
319
  #ifdef CONFIG_CIFS_STATS2
  				atomic_dec(&ses->server->num_waiters);
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
320
321
  				spin_lock(&GlobalMid_Lock);
  			} else {
79a58d1f6   Steve French   [CIFS] whitespace...
322
  				if (ses->server->tcpStatus == CifsExiting) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323
324
325
  					spin_unlock(&GlobalMid_Lock);
  					return -ENOENT;
  				}
79a58d1f6   Steve French   [CIFS] whitespace...
326
327
  				/* can not count locking commands against total
  				   as they are allowed to block on server */
50c2f7538   Steve French   [CIFS] whitespace...
328

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329
  				/* update # of requests on the wire to server */
7ee1af765   Jeremy Allison   [CIFS]
330
  				if (long_op < 3)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331
  					atomic_inc(&ses->server->inFlight);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
333
334
335
336
  				spin_unlock(&GlobalMid_Lock);
  				break;
  			}
  		}
  	}
7ee1af765   Jeremy Allison   [CIFS]
337
338
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339

7ee1af765   Jeremy Allison   [CIFS]
340
341
342
  static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf,
  			struct mid_q_entry **ppmidQ)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343
  	if (ses->server->tcpStatus == CifsExiting) {
7ee1af765   Jeremy Allison   [CIFS]
344
  		return -ENOENT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
345
  	} else if (ses->server->tcpStatus == CifsNeedReconnect) {
79a58d1f6   Steve French   [CIFS] whitespace...
346
  		cFYI(1, ("tcp session dead - return to caller to retry"));
7ee1af765   Jeremy Allison   [CIFS]
347
  		return -EAGAIN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
348
349
  	} else if (ses->status != CifsGood) {
  		/* check if SMB session is bad because we are setting it up */
79a58d1f6   Steve French   [CIFS] whitespace...
350
  		if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
351
  			(in_buf->Command != SMB_COM_NEGOTIATE)) {
7ee1af765   Jeremy Allison   [CIFS]
352
  			return -EAGAIN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
354
  		} /* else ok - we are setting up session */
  	}
7ee1af765   Jeremy Allison   [CIFS]
355
356
357
358
359
360
  	*ppmidQ = AllocMidQEntry(in_buf, ses);
  	if (*ppmidQ == NULL) {
  		return -ENOMEM;
  	}
  	return 0;
  }
79a58d1f6   Steve French   [CIFS] whitespace...
361
  static int wait_for_response(struct cifsSesInfo *ses,
7ee1af765   Jeremy Allison   [CIFS]
362
363
364
365
366
367
368
369
370
  			struct mid_q_entry *midQ,
  			unsigned long timeout,
  			unsigned long time_to_wait)
  {
  	unsigned long curr_timeout;
  
  	for (;;) {
  		curr_timeout = timeout + jiffies;
  		wait_event(ses->server->response_q,
79a58d1f6   Steve French   [CIFS] whitespace...
371
372
  			(!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
  			time_after(jiffies, curr_timeout) ||
7ee1af765   Jeremy Allison   [CIFS]
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
  			((ses->server->tcpStatus != CifsGood) &&
  			 (ses->server->tcpStatus != CifsNew)));
  
  		if (time_after(jiffies, curr_timeout) &&
  			(midQ->midState == MID_REQUEST_SUBMITTED) &&
  			((ses->server->tcpStatus == CifsGood) ||
  			 (ses->server->tcpStatus == CifsNew))) {
  
  			unsigned long lrt;
  
  			/* We timed out. Is the server still
  			   sending replies ? */
  			spin_lock(&GlobalMid_Lock);
  			lrt = ses->server->lstrp;
  			spin_unlock(&GlobalMid_Lock);
  
  			/* Calculate time_to_wait past last receive time.
79a58d1f6   Steve French   [CIFS] whitespace...
390
  			 Although we prefer not to time out if the
7ee1af765   Jeremy Allison   [CIFS]
391
  			 server is still responding - we will time
79a58d1f6   Steve French   [CIFS] whitespace...
392
  			 out if the server takes more than 15 (or 45
7ee1af765   Jeremy Allison   [CIFS]
393
  			 or 180) seconds to respond to this request
79a58d1f6   Steve French   [CIFS] whitespace...
394
  			 and has not responded to any request from
7ee1af765   Jeremy Allison   [CIFS]
395
396
397
398
  			 other threads on the client within 10 seconds */
  			lrt += time_to_wait;
  			if (time_after(jiffies, lrt)) {
  				/* No replies for time_to_wait. */
79a58d1f6   Steve French   [CIFS] whitespace...
399
  				cERROR(1, ("server not responding"));
7ee1af765   Jeremy Allison   [CIFS]
400
401
402
403
404
405
406
407
408
  				return -1;
  			}
  		} else {
  			return 0;
  		}
  	}
  }
  
  int
79a58d1f6   Steve French   [CIFS] whitespace...
409
410
  SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
  	     struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
7ee1af765   Jeremy Allison   [CIFS]
411
412
413
414
415
416
417
  	     const int long_op)
  {
  	int rc = 0;
  	unsigned int receive_len;
  	unsigned long timeout;
  	struct mid_q_entry *midQ;
  	struct smb_hdr *in_buf = iov[0].iov_base;
50c2f7538   Steve French   [CIFS] whitespace...
418

7ee1af765   Jeremy Allison   [CIFS]
419
420
421
422
  	*pRespBufType = CIFS_NO_BUFFER;  /* no response buf yet */
  
  	if ((ses == NULL) || (ses->server == NULL)) {
  		cifs_small_buf_release(in_buf);
79a58d1f6   Steve French   [CIFS] whitespace...
423
  		cERROR(1, ("Null session"));
7ee1af765   Jeremy Allison   [CIFS]
424
425
  		return -EIO;
  	}
79a58d1f6   Steve French   [CIFS] whitespace...
426
  	if (ses->server->tcpStatus == CifsExiting) {
7ee1af765   Jeremy Allison   [CIFS]
427
428
429
  		cifs_small_buf_release(in_buf);
  		return -ENOENT;
  	}
79a58d1f6   Steve French   [CIFS] whitespace...
430
  	/* Ensure that we do not send more than 50 overlapping requests
7ee1af765   Jeremy Allison   [CIFS]
431
432
433
434
435
436
437
438
  	   to the same server. We may make this configurable later or
  	   use ses->maxReq */
  
  	rc = wait_for_free_request(ses, long_op);
  	if (rc) {
  		cifs_small_buf_release(in_buf);
  		return rc;
  	}
79a58d1f6   Steve French   [CIFS] whitespace...
439
  	/* make sure that we sign in the same order that we send on this socket
7ee1af765   Jeremy Allison   [CIFS]
440
441
  	   and avoid races inside tcp sendmsg code that could cause corruption
  	   of smb data */
79a58d1f6   Steve French   [CIFS] whitespace...
442
  	down(&ses->server->tcpSem);
7ee1af765   Jeremy Allison   [CIFS]
443
444
445
  
  	rc = allocate_mid(ses, in_buf, &midQ);
  	if (rc) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446
  		up(&ses->server->tcpSem);
4b8f930ff   Steve French   [CIFS] Free small...
447
  		cifs_small_buf_release(in_buf);
7ee1af765   Jeremy Allison   [CIFS]
448
  		/* Update # of requests on wire to server */
79a58d1f6   Steve French   [CIFS] whitespace...
449
  		atomic_dec(&ses->server->inFlight);
7ee1af765   Jeremy Allison   [CIFS]
450
451
  		wake_up(&ses->server->request_q);
  		return rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
452
  	}
79a58d1f6   Steve French   [CIFS] whitespace...
453
  	rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454
455
  
  	midQ->midState = MID_REQUEST_SUBMITTED;
131afd0b7   Steve French   [CIFS] /proc/fs/c...
456
457
458
  #ifdef CONFIG_CIFS_STATS2
  	atomic_inc(&ses->server->inSend);
  #endif
3e84469d0   Steve French   [CIFS] Add writep...
459
  	rc = smb_send2(ses->server->ssocket, iov, n_vec,
d6e04ae64   Steve French   [CIFS] CIFS write...
460
  		      (struct sockaddr *) &(ses->server->addr.sockAddr));
131afd0b7   Steve French   [CIFS] /proc/fs/c...
461
462
  #ifdef CONFIG_CIFS_STATS2
  	atomic_dec(&ses->server->inSend);
1047abc15   Steve French   [CIFS] CIFS Stats...
463
  	midQ->when_sent = jiffies;
131afd0b7   Steve French   [CIFS] /proc/fs/c...
464
  #endif
7ee1af765   Jeremy Allison   [CIFS]
465
466
467
  
  	up(&ses->server->tcpSem);
  	cifs_small_buf_release(in_buf);
79a58d1f6   Steve French   [CIFS] whitespace...
468
  	if (rc < 0)
7ee1af765   Jeremy Allison   [CIFS]
469
  		goto out;
4b8f930ff   Steve French   [CIFS] Free small...
470

d6e04ae64   Steve French   [CIFS] CIFS write...
471
  	if (long_op == -1)
7ee1af765   Jeremy Allison   [CIFS]
472
  		goto out;
d6e04ae64   Steve French   [CIFS] CIFS write...
473
  	else if (long_op == 2) /* writes past end of file can take loong time */
37c0eb467   Steve French   CIFS: implement c...
474
  		timeout = 180 * HZ;
d6e04ae64   Steve French   [CIFS] CIFS write...
475
  	else if (long_op == 1)
79a58d1f6   Steve French   [CIFS] whitespace...
476
  		timeout = 45 * HZ; /* should be greater than
d6e04ae64   Steve French   [CIFS] CIFS write...
477
  			servers oplock break timeout (about 43 seconds) */
7ee1af765   Jeremy Allison   [CIFS]
478
  	else
d6e04ae64   Steve French   [CIFS] CIFS write...
479
  		timeout = 15 * HZ;
7ee1af765   Jeremy Allison   [CIFS]
480

79a58d1f6   Steve French   [CIFS] whitespace...
481
  	/* wait for 15 seconds or until woken up due to response arriving or
d6e04ae64   Steve French   [CIFS] CIFS write...
482
483
484
  	   due to last connection to this server being unmounted */
  	if (signal_pending(current)) {
  		/* if signal pending do not hold up user for full smb timeout
8a236264f   Steve French   [CIFS] cifs_prepa...
485
  		but we still give response a chance to complete */
d6e04ae64   Steve French   [CIFS] CIFS write...
486
  		timeout = 2 * HZ;
79a58d1f6   Steve French   [CIFS] whitespace...
487
  	}
d6e04ae64   Steve French   [CIFS] CIFS write...
488
489
  
  	/* No user interrupts in wait - wreaks havoc with performance */
7ee1af765   Jeremy Allison   [CIFS]
490
  	wait_for_response(ses, midQ, timeout, 10 * HZ);
d6e04ae64   Steve French   [CIFS] CIFS write...
491
492
493
494
  
  	spin_lock(&GlobalMid_Lock);
  	if (midQ->resp_buf) {
  		spin_unlock(&GlobalMid_Lock);
70ca734a1   Steve French   [CIFS] Various mi...
495
  		receive_len = midQ->resp_buf->smb_buf_length;
d6e04ae64   Steve French   [CIFS] CIFS write...
496
  	} else {
79a58d1f6   Steve French   [CIFS] whitespace...
497
  		cERROR(1, ("No response to cmd %d mid %d",
37c0eb467   Steve French   CIFS: implement c...
498
  			midQ->command, midQ->mid));
79a58d1f6   Steve French   [CIFS] whitespace...
499
500
  		if (midQ->midState == MID_REQUEST_SUBMITTED) {
  			if (ses->server->tcpStatus == CifsExiting)
d6e04ae64   Steve French   [CIFS] CIFS write...
501
502
503
504
505
506
507
508
  				rc = -EHOSTDOWN;
  			else {
  				ses->server->tcpStatus = CifsNeedReconnect;
  				midQ->midState = MID_RETRY_NEEDED;
  			}
  		}
  
  		if (rc != -EHOSTDOWN) {
79a58d1f6   Steve French   [CIFS] whitespace...
509
  			if (midQ->midState == MID_RETRY_NEEDED) {
d6e04ae64   Steve French   [CIFS] CIFS write...
510
  				rc = -EAGAIN;
79a58d1f6   Steve French   [CIFS] whitespace...
511
  				cFYI(1, ("marking request for retry"));
d6e04ae64   Steve French   [CIFS] CIFS write...
512
513
514
515
516
517
  			} else {
  				rc = -EIO;
  			}
  		}
  		spin_unlock(&GlobalMid_Lock);
  		DeleteMidQEntry(midQ);
7ee1af765   Jeremy Allison   [CIFS]
518
  		/* Update # of requests on wire to server */
79a58d1f6   Steve French   [CIFS] whitespace...
519
  		atomic_dec(&ses->server->inFlight);
7ee1af765   Jeremy Allison   [CIFS]
520
  		wake_up(&ses->server->request_q);
d6e04ae64   Steve French   [CIFS] CIFS write...
521
522
  		return rc;
  	}
50c2f7538   Steve French   [CIFS] whitespace...
523

d6e04ae64   Steve French   [CIFS] CIFS write...
524
525
526
527
528
  	if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
  		cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
  			receive_len, xid));
  		rc = -EIO;
  	} else {		/* rcvd frame is ok */
79a58d1f6   Steve French   [CIFS] whitespace...
529
  		if (midQ->resp_buf &&
d6e04ae64   Steve French   [CIFS] CIFS write...
530
  			(midQ->midState == MID_RESPONSE_RECEIVED)) {
84afc29b1   Steve French   [CIFS] Readpages ...
531

ec637e3ff   Steve French   [CIFS] Avoid extr...
532
  			iov[0].iov_base = (char *)midQ->resp_buf;
79a58d1f6   Steve French   [CIFS] whitespace...
533
  			if (midQ->largeBuf)
ec637e3ff   Steve French   [CIFS] Avoid extr...
534
535
536
537
  				*pRespBufType = CIFS_LARGE_BUFFER;
  			else
  				*pRespBufType = CIFS_SMALL_BUFFER;
  			iov[0].iov_len = receive_len + 4;
d6e04ae64   Steve French   [CIFS] CIFS write...
538

ec637e3ff   Steve French   [CIFS] Avoid extr...
539
  			dump_smb(midQ->resp_buf, 80);
d6e04ae64   Steve French   [CIFS] CIFS write...
540
  			/* convert the length into a more usable form */
79a58d1f6   Steve French   [CIFS] whitespace...
541
  			if ((receive_len > 24) &&
d6e04ae64   Steve French   [CIFS] CIFS write...
542
543
  			   (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
  					SECMODE_SIGN_ENABLED))) {
ec637e3ff   Steve French   [CIFS] Avoid extr...
544
  				rc = cifs_verify_signature(midQ->resp_buf,
b609f06ac   Steve French   [CIFS] Fix packet...
545
  						&ses->server->mac_signing_key,
d6e04ae64   Steve French   [CIFS] CIFS write...
546
  						midQ->sequence_number+1);
79a58d1f6   Steve French   [CIFS] whitespace...
547
548
  				if (rc) {
  					cERROR(1, ("Unexpected SMB signature"));
d6e04ae64   Steve French   [CIFS] CIFS write...
549
550
551
  					/* BB FIXME add code to kill session */
  				}
  			}
d6e04ae64   Steve French   [CIFS] CIFS write...
552
  			/* BB special case reconnect tid and uid here? */
6ab16d249   Steve French   [CIFS] Fix umount...
553
  			/* BB special case Errbadpassword and pwdexpired here */
ec637e3ff   Steve French   [CIFS] Avoid extr...
554
  			rc = map_smb_to_linux_error(midQ->resp_buf);
d6e04ae64   Steve French   [CIFS] CIFS write...
555
556
557
558
559
  
  			/* convert ByteCount if necessary */
  			if (receive_len >=
  			    sizeof (struct smb_hdr) -
  			    4 /* do not count RFC1001 header */  +
ec637e3ff   Steve French   [CIFS] Avoid extr...
560
  			    (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
79a58d1f6   Steve French   [CIFS] whitespace...
561
  				BCC(midQ->resp_buf) =
ec637e3ff   Steve French   [CIFS] Avoid extr...
562
563
564
  					le16_to_cpu(BCC_LE(midQ->resp_buf));
  			midQ->resp_buf = NULL;  /* mark it so will not be freed
  						by DeleteMidQEntry */
d6e04ae64   Steve French   [CIFS] CIFS write...
565
566
  		} else {
  			rc = -EIO;
79a58d1f6   Steve French   [CIFS] whitespace...
567
  			cFYI(1, ("Bad MID state?"));
d6e04ae64   Steve French   [CIFS] CIFS write...
568
569
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570

7ee1af765   Jeremy Allison   [CIFS]
571
  out:
7ee1af765   Jeremy Allison   [CIFS]
572
  	DeleteMidQEntry(midQ);
79a58d1f6   Steve French   [CIFS] whitespace...
573
  	atomic_dec(&ses->server->inFlight);
7ee1af765   Jeremy Allison   [CIFS]
574
  	wake_up(&ses->server->request_q);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
575

d6e04ae64   Steve French   [CIFS] CIFS write...
576
577
  	return rc;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
578
579
580
581
582
583
584
585
586
587
588
589
  
  int
  SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
  	    struct smb_hdr *in_buf, struct smb_hdr *out_buf,
  	    int *pbytes_returned, const int long_op)
  {
  	int rc = 0;
  	unsigned int receive_len;
  	unsigned long timeout;
  	struct mid_q_entry *midQ;
  
  	if (ses == NULL) {
79a58d1f6   Steve French   [CIFS] whitespace...
590
  		cERROR(1, ("Null smb session"));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
591
592
  		return -EIO;
  	}
79a58d1f6   Steve French   [CIFS] whitespace...
593
594
  	if (ses->server == NULL) {
  		cERROR(1, ("Null tcp session"));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
595
596
  		return -EIO;
  	}
79a58d1f6   Steve French   [CIFS] whitespace...
597
  	if (ses->server->tcpStatus == CifsExiting)
31ca3bc3c   Steve French   [PATCH] cifs: Do ...
598
  		return -ENOENT;
79a58d1f6   Steve French   [CIFS] whitespace...
599
  	/* Ensure that we do not send more than 50 overlapping requests
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600
601
  	   to the same server. We may make this configurable later or
  	   use ses->maxReq */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602

7ee1af765   Jeremy Allison   [CIFS]
603
604
605
  	rc = wait_for_free_request(ses, long_op);
  	if (rc)
  		return rc;
79a58d1f6   Steve French   [CIFS] whitespace...
606
  	/* make sure that we sign in the same order that we send on this socket
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
607
608
  	   and avoid races inside tcp sendmsg code that could cause corruption
  	   of smb data */
79a58d1f6   Steve French   [CIFS] whitespace...
609
  	down(&ses->server->tcpSem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
610

7ee1af765   Jeremy Allison   [CIFS]
611
612
  	rc = allocate_mid(ses, in_buf, &midQ);
  	if (rc) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
613
  		up(&ses->server->tcpSem);
7ee1af765   Jeremy Allison   [CIFS]
614
  		/* Update # of requests on wire to server */
79a58d1f6   Steve French   [CIFS] whitespace...
615
  		atomic_dec(&ses->server->inFlight);
7ee1af765   Jeremy Allison   [CIFS]
616
617
  		wake_up(&ses->server->request_q);
  		return rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
618
619
620
  	}
  
  	if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
26a21b980   Steve French   [CIFS] Cleanup ex...
621
  		cERROR(1, ("Illegal length, greater than maximum frame, %d",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
622
623
  			in_buf->smb_buf_length));
  		DeleteMidQEntry(midQ);
7ee1af765   Jeremy Allison   [CIFS]
624
625
  		up(&ses->server->tcpSem);
  		/* Update # of requests on wire to server */
79a58d1f6   Steve French   [CIFS] whitespace...
626
  		atomic_dec(&ses->server->inFlight);
7ee1af765   Jeremy Allison   [CIFS]
627
  		wake_up(&ses->server->request_q);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
628
629
  		return -EIO;
  	}
ad009ac96   Steve French   [PATCH] cifs: Fix...
630
  	rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
631
632
  
  	midQ->midState = MID_REQUEST_SUBMITTED;
131afd0b7   Steve French   [CIFS] /proc/fs/c...
633
634
635
  #ifdef CONFIG_CIFS_STATS2
  	atomic_inc(&ses->server->inSend);
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636
637
  	rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
  		      (struct sockaddr *) &(ses->server->addr.sockAddr));
131afd0b7   Steve French   [CIFS] /proc/fs/c...
638
639
  #ifdef CONFIG_CIFS_STATS2
  	atomic_dec(&ses->server->inSend);
1047abc15   Steve French   [CIFS] CIFS Stats...
640
  	midQ->when_sent = jiffies;
131afd0b7   Steve French   [CIFS] /proc/fs/c...
641
  #endif
7ee1af765   Jeremy Allison   [CIFS]
642
  	up(&ses->server->tcpSem);
79a58d1f6   Steve French   [CIFS] whitespace...
643
  	if (rc < 0)
7ee1af765   Jeremy Allison   [CIFS]
644
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
645
  	if (long_op == -1)
7ee1af765   Jeremy Allison   [CIFS]
646
  		goto out;
275cde1a1   Steve French   [PATCH] cifs: cle...
647
  	else if (long_op == 2) /* writes past end of file can take loong time */
37c0eb467   Steve French   CIFS: implement c...
648
  		timeout = 180 * HZ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
649
  	else if (long_op == 1)
79a58d1f6   Steve French   [CIFS] whitespace...
650
  		timeout = 45 * HZ; /* should be greater than
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
651
  			servers oplock break timeout (about 43 seconds) */
7ee1af765   Jeremy Allison   [CIFS]
652
  	else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
653
  		timeout = 15 * HZ;
79a58d1f6   Steve French   [CIFS] whitespace...
654
  	/* wait for 15 seconds or until woken up due to response arriving or
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
655
656
657
  	   due to last connection to this server being unmounted */
  	if (signal_pending(current)) {
  		/* if signal pending do not hold up user for full smb timeout
8a236264f   Steve French   [CIFS] cifs_prepa...
658
  		but we still give response a chance to complete */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
659
  		timeout = 2 * HZ;
79a58d1f6   Steve French   [CIFS] whitespace...
660
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
661
662
  
  	/* No user interrupts in wait - wreaks havoc with performance */
7ee1af765   Jeremy Allison   [CIFS]
663
  	wait_for_response(ses, midQ, timeout, 10 * HZ);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
665
666
667
  
  	spin_lock(&GlobalMid_Lock);
  	if (midQ->resp_buf) {
  		spin_unlock(&GlobalMid_Lock);
70ca734a1   Steve French   [CIFS] Various mi...
668
  		receive_len = midQ->resp_buf->smb_buf_length;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
669
  	} else {
79a58d1f6   Steve French   [CIFS] whitespace...
670
  		cERROR(1, ("No response for cmd %d mid %d",
37c0eb467   Steve French   CIFS: implement c...
671
  			  midQ->command, midQ->mid));
79a58d1f6   Steve French   [CIFS] whitespace...
672
673
  		if (midQ->midState == MID_REQUEST_SUBMITTED) {
  			if (ses->server->tcpStatus == CifsExiting)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
674
675
676
677
678
679
680
681
  				rc = -EHOSTDOWN;
  			else {
  				ses->server->tcpStatus = CifsNeedReconnect;
  				midQ->midState = MID_RETRY_NEEDED;
  			}
  		}
  
  		if (rc != -EHOSTDOWN) {
79a58d1f6   Steve French   [CIFS] whitespace...
682
  			if (midQ->midState == MID_RETRY_NEEDED) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
683
  				rc = -EAGAIN;
79a58d1f6   Steve French   [CIFS] whitespace...
684
  				cFYI(1, ("marking request for retry"));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
685
686
687
688
689
690
  			} else {
  				rc = -EIO;
  			}
  		}
  		spin_unlock(&GlobalMid_Lock);
  		DeleteMidQEntry(midQ);
7ee1af765   Jeremy Allison   [CIFS]
691
  		/* Update # of requests on wire to server */
79a58d1f6   Steve French   [CIFS] whitespace...
692
  		atomic_dec(&ses->server->inFlight);
7ee1af765   Jeremy Allison   [CIFS]
693
  		wake_up(&ses->server->request_q);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
694
695
  		return rc;
  	}
50c2f7538   Steve French   [CIFS] whitespace...
696

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697
  	if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
ad009ac96   Steve French   [PATCH] cifs: Fix...
698
  		cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
699
700
701
702
703
704
705
706
707
708
709
710
711
  			receive_len, xid));
  		rc = -EIO;
  	} else {		/* rcvd frame is ok */
  
  		if (midQ->resp_buf && out_buf
  		    && (midQ->midState == MID_RESPONSE_RECEIVED)) {
  			out_buf->smb_buf_length = receive_len;
  			memcpy((char *)out_buf + 4,
  			       (char *)midQ->resp_buf + 4,
  			       receive_len);
  
  			dump_smb(out_buf, 92);
  			/* convert the length into a more usable form */
79a58d1f6   Steve French   [CIFS] whitespace...
712
  			if ((receive_len > 24) &&
ad009ac96   Steve French   [PATCH] cifs: Fix...
713
714
715
  			   (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
  					SECMODE_SIGN_ENABLED))) {
  				rc = cifs_verify_signature(out_buf,
b609f06ac   Steve French   [CIFS] Fix packet...
716
  						&ses->server->mac_signing_key,
ad009ac96   Steve French   [PATCH] cifs: Fix...
717
  						midQ->sequence_number+1);
79a58d1f6   Steve French   [CIFS] whitespace...
718
719
  				if (rc) {
  					cERROR(1, ("Unexpected SMB signature"));
275cde1a1   Steve French   [PATCH] cifs: cle...
720
  					/* BB FIXME add code to kill session */
ad009ac96   Steve French   [PATCH] cifs: Fix...
721
  				}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722
723
724
  			}
  
  			*pbytes_returned = out_buf->smb_buf_length;
ad009ac96   Steve French   [PATCH] cifs: Fix...
725
  			/* BB special case reconnect tid and uid here? */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
726
727
728
729
730
731
732
  			rc = map_smb_to_linux_error(out_buf);
  
  			/* convert ByteCount if necessary */
  			if (receive_len >=
  			    sizeof (struct smb_hdr) -
  			    4 /* do not count RFC1001 header */  +
  			    (2 * out_buf->WordCount) + 2 /* bcc */ )
0f2b27c43   Steve French   [CIFS] Fix sparse...
733
  				BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
734
735
  		} else {
  			rc = -EIO;
79a58d1f6   Steve French   [CIFS] whitespace...
736
  			cERROR(1, ("Bad MID state?"));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
737
738
  		}
  	}
7ee1af765   Jeremy Allison   [CIFS]
739
740
  
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
741
  	DeleteMidQEntry(midQ);
79a58d1f6   Steve French   [CIFS] whitespace...
742
  	atomic_dec(&ses->server->inFlight);
7ee1af765   Jeremy Allison   [CIFS]
743
  	wake_up(&ses->server->request_q);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
744

7ee1af765   Jeremy Allison   [CIFS]
745
746
  	return rc;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747

7ee1af765   Jeremy Allison   [CIFS]
748
749
750
751
752
753
754
755
756
757
758
759
  /* Send an NT_CANCEL SMB to cause the POSIX blocking lock to return. */
  
  static int
  send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf,
  		struct mid_q_entry *midQ)
  {
  	int rc = 0;
  	struct cifsSesInfo *ses = tcon->ses;
  	__u16 mid = in_buf->Mid;
  
  	header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0);
  	in_buf->Mid = mid;
79a58d1f6   Steve French   [CIFS] whitespace...
760
  	down(&ses->server->tcpSem);
7ee1af765   Jeremy Allison   [CIFS]
761
762
763
764
765
766
767
768
  	rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
  	if (rc) {
  		up(&ses->server->tcpSem);
  		return rc;
  	}
  	rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
  	      (struct sockaddr *) &(ses->server->addr.sockAddr));
  	up(&ses->server->tcpSem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
769
  	return rc;
7ee1af765   Jeremy Allison   [CIFS]
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
  }
  
  /* We send a LOCKINGX_CANCEL_LOCK to cause the Windows
     blocking lock to return. */
  
  static int
  send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon,
  			struct smb_hdr *in_buf,
  			struct smb_hdr *out_buf)
  {
  	int bytes_returned;
  	struct cifsSesInfo *ses = tcon->ses;
  	LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;
  
  	/* We just modify the current in_buf to change
  	   the type of lock from LOCKING_ANDX_SHARED_LOCK
  	   or LOCKING_ANDX_EXCLUSIVE_LOCK to
  	   LOCKING_ANDX_CANCEL_LOCK. */
  
  	pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES;
  	pSMB->Timeout = 0;
  	pSMB->hdr.Mid = GetNextMid(ses->server);
  
  	return SendReceive(xid, ses, in_buf, out_buf,
  			&bytes_returned, 0);
  }
  
  int
  SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
  	    struct smb_hdr *in_buf, struct smb_hdr *out_buf,
  	    int *pbytes_returned)
  {
  	int rc = 0;
  	int rstart = 0;
  	unsigned int receive_len;
  	struct mid_q_entry *midQ;
  	struct cifsSesInfo *ses;
  
  	if (tcon == NULL || tcon->ses == NULL) {
79a58d1f6   Steve French   [CIFS] whitespace...
809
  		cERROR(1, ("Null smb session"));
7ee1af765   Jeremy Allison   [CIFS]
810
811
812
  		return -EIO;
  	}
  	ses = tcon->ses;
79a58d1f6   Steve French   [CIFS] whitespace...
813
814
  	if (ses->server == NULL) {
  		cERROR(1, ("Null tcp session"));
7ee1af765   Jeremy Allison   [CIFS]
815
816
  		return -EIO;
  	}
79a58d1f6   Steve French   [CIFS] whitespace...
817
  	if (ses->server->tcpStatus == CifsExiting)
7ee1af765   Jeremy Allison   [CIFS]
818
  		return -ENOENT;
79a58d1f6   Steve French   [CIFS] whitespace...
819
  	/* Ensure that we do not send more than 50 overlapping requests
7ee1af765   Jeremy Allison   [CIFS]
820
821
822
823
824
825
  	   to the same server. We may make this configurable later or
  	   use ses->maxReq */
  
  	rc = wait_for_free_request(ses, 3);
  	if (rc)
  		return rc;
79a58d1f6   Steve French   [CIFS] whitespace...
826
  	/* make sure that we sign in the same order that we send on this socket
7ee1af765   Jeremy Allison   [CIFS]
827
828
  	   and avoid races inside tcp sendmsg code that could cause corruption
  	   of smb data */
79a58d1f6   Steve French   [CIFS] whitespace...
829
  	down(&ses->server->tcpSem);
7ee1af765   Jeremy Allison   [CIFS]
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
  
  	rc = allocate_mid(ses, in_buf, &midQ);
  	if (rc) {
  		up(&ses->server->tcpSem);
  		return rc;
  	}
  
  	if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
  		up(&ses->server->tcpSem);
  		cERROR(1, ("Illegal length, greater than maximum frame, %d",
  			in_buf->smb_buf_length));
  		DeleteMidQEntry(midQ);
  		return -EIO;
  	}
  
  	rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
846

7ee1af765   Jeremy Allison   [CIFS]
847
848
849
850
851
852
853
854
855
856
  	midQ->midState = MID_REQUEST_SUBMITTED;
  #ifdef CONFIG_CIFS_STATS2
  	atomic_inc(&ses->server->inSend);
  #endif
  	rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
  		      (struct sockaddr *) &(ses->server->addr.sockAddr));
  #ifdef CONFIG_CIFS_STATS2
  	atomic_dec(&ses->server->inSend);
  	midQ->when_sent = jiffies;
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
857
  	up(&ses->server->tcpSem);
7ee1af765   Jeremy Allison   [CIFS]
858

79a58d1f6   Steve French   [CIFS] whitespace...
859
  	if (rc < 0) {
7ee1af765   Jeremy Allison   [CIFS]
860
861
862
863
864
865
  		DeleteMidQEntry(midQ);
  		return rc;
  	}
  
  	/* Wait for a reply - allow signals to interrupt. */
  	rc = wait_event_interruptible(ses->server->response_q,
79a58d1f6   Steve French   [CIFS] whitespace...
866
  		(!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
7ee1af765   Jeremy Allison   [CIFS]
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
  		((ses->server->tcpStatus != CifsGood) &&
  		 (ses->server->tcpStatus != CifsNew)));
  
  	/* Were we interrupted by a signal ? */
  	if ((rc == -ERESTARTSYS) &&
  		(midQ->midState == MID_REQUEST_SUBMITTED) &&
  		((ses->server->tcpStatus == CifsGood) ||
  		 (ses->server->tcpStatus == CifsNew))) {
  
  		if (in_buf->Command == SMB_COM_TRANSACTION2) {
  			/* POSIX lock. We send a NT_CANCEL SMB to cause the
  			   blocking lock to return. */
  
  			rc = send_nt_cancel(tcon, in_buf, midQ);
  			if (rc) {
  				DeleteMidQEntry(midQ);
  				return rc;
  			}
  		} else {
  			/* Windows lock. We send a LOCKINGX_CANCEL_LOCK
  			   to cause the blocking lock to return. */
  
  			rc = send_lock_cancel(xid, tcon, in_buf, out_buf);
  
  			/* If we get -ENOLCK back the lock may have
  			   already been removed. Don't exit in this case. */
  			if (rc && rc != -ENOLCK) {
  				DeleteMidQEntry(midQ);
  				return rc;
  			}
  		}
  
  		/* Wait 5 seconds for the response. */
79a58d1f6   Steve French   [CIFS] whitespace...
900
  		if (wait_for_response(ses, midQ, 5 * HZ, 5 * HZ) == 0) {
7ee1af765   Jeremy Allison   [CIFS]
901
902
903
904
905
906
907
908
909
910
  			/* We got the response - restart system call. */
  			rstart = 1;
  		}
  	}
  
  	spin_lock(&GlobalMid_Lock);
  	if (midQ->resp_buf) {
  		spin_unlock(&GlobalMid_Lock);
  		receive_len = midQ->resp_buf->smb_buf_length;
  	} else {
79a58d1f6   Steve French   [CIFS] whitespace...
911
  		cERROR(1, ("No response for cmd %d mid %d",
7ee1af765   Jeremy Allison   [CIFS]
912
  			  midQ->command, midQ->mid));
79a58d1f6   Steve French   [CIFS] whitespace...
913
914
  		if (midQ->midState == MID_REQUEST_SUBMITTED) {
  			if (ses->server->tcpStatus == CifsExiting)
7ee1af765   Jeremy Allison   [CIFS]
915
916
917
918
919
920
921
922
  				rc = -EHOSTDOWN;
  			else {
  				ses->server->tcpStatus = CifsNeedReconnect;
  				midQ->midState = MID_RETRY_NEEDED;
  			}
  		}
  
  		if (rc != -EHOSTDOWN) {
79a58d1f6   Steve French   [CIFS] whitespace...
923
  			if (midQ->midState == MID_RETRY_NEEDED) {
7ee1af765   Jeremy Allison   [CIFS]
924
  				rc = -EAGAIN;
79a58d1f6   Steve French   [CIFS] whitespace...
925
  				cFYI(1, ("marking request for retry"));
7ee1af765   Jeremy Allison   [CIFS]
926
927
928
929
930
931
932
  			} else {
  				rc = -EIO;
  			}
  		}
  		spin_unlock(&GlobalMid_Lock);
  		DeleteMidQEntry(midQ);
  		return rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
933
  	}
50c2f7538   Steve French   [CIFS] whitespace...
934

7ee1af765   Jeremy Allison   [CIFS]
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
  	if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
  		cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
  			receive_len, xid));
  		rc = -EIO;
  	} else {		/* rcvd frame is ok */
  
  		if (midQ->resp_buf && out_buf
  		    && (midQ->midState == MID_RESPONSE_RECEIVED)) {
  			out_buf->smb_buf_length = receive_len;
  			memcpy((char *)out_buf + 4,
  			       (char *)midQ->resp_buf + 4,
  			       receive_len);
  
  			dump_smb(out_buf, 92);
  			/* convert the length into a more usable form */
79a58d1f6   Steve French   [CIFS] whitespace...
950
  			if ((receive_len > 24) &&
7ee1af765   Jeremy Allison   [CIFS]
951
952
953
  			   (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
  					SECMODE_SIGN_ENABLED))) {
  				rc = cifs_verify_signature(out_buf,
b609f06ac   Steve French   [CIFS] Fix packet...
954
  						&ses->server->mac_signing_key,
7ee1af765   Jeremy Allison   [CIFS]
955
  						midQ->sequence_number+1);
79a58d1f6   Steve French   [CIFS] whitespace...
956
957
  				if (rc) {
  					cERROR(1, ("Unexpected SMB signature"));
7ee1af765   Jeremy Allison   [CIFS]
958
959
960
961
962
963
964
965
  					/* BB FIXME add code to kill session */
  				}
  			}
  
  			*pbytes_returned = out_buf->smb_buf_length;
  
  			/* BB special case reconnect tid and uid here? */
  			rc = map_smb_to_linux_error(out_buf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
966

7ee1af765   Jeremy Allison   [CIFS]
967
968
969
970
971
972
973
974
  			/* convert ByteCount if necessary */
  			if (receive_len >=
  			    sizeof (struct smb_hdr) -
  			    4 /* do not count RFC1001 header */  +
  			    (2 * out_buf->WordCount) + 2 /* bcc */ )
  				BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
  		} else {
  			rc = -EIO;
79a58d1f6   Steve French   [CIFS] whitespace...
975
  			cERROR(1, ("Bad MID state?"));
7ee1af765   Jeremy Allison   [CIFS]
976
977
978
979
980
  		}
  	}
  	DeleteMidQEntry(midQ);
  	if (rstart && rc == -EACCES)
  		return -ERESTARTSYS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
981
982
  	return rc;
  }