aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/cifssmb.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs/cifssmb.c')
-rw-r--r--fs/cifs/cifssmb.c317
1 files changed, 128 insertions, 189 deletions
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 1866bc2927d4..941441d3e386 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -94,116 +94,145 @@ static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
94 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) { 94 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
95 open_file = list_entry(tmp, struct cifsFileInfo, tlist); 95 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
96 open_file->invalidHandle = true; 96 open_file->invalidHandle = true;
97 open_file->oplock_break_cancelled = true;
97 } 98 }
98 write_unlock(&GlobalSMBSeslock); 99 write_unlock(&GlobalSMBSeslock);
99 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted 100 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
100 to this tcon */ 101 to this tcon */
101} 102}
102 103
103/* Allocate and return pointer to an SMB request buffer, and set basic 104/* reconnect the socket, tcon, and smb session if needed */
104 SMB information in the SMB header. If the return code is zero, this
105 function must have filled in request_buf pointer */
106static int 105static int
107small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, 106cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command)
108 void **request_buf)
109{ 107{
110 int rc = 0; 108 int rc = 0;
109 struct cifsSesInfo *ses;
110 struct TCP_Server_Info *server;
111 struct nls_table *nls_codepage;
111 112
112 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so 113 /*
113 check for tcp and smb session status done differently 114 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
114 for those three - in the calling routine */ 115 * tcp and smb session status done differently for those three - in the
115 if (tcon) { 116 * calling routine
116 if (tcon->tidStatus == CifsExiting) { 117 */
117 /* only tree disconnect, open, and write, 118 if (!tcon)
118 (and ulogoff which does not have tcon) 119 return 0;
119 are allowed as we start force umount */ 120
120 if ((smb_command != SMB_COM_WRITE_ANDX) && 121 ses = tcon->ses;
121 (smb_command != SMB_COM_OPEN_ANDX) && 122 server = ses->server;
122 (smb_command != SMB_COM_TREE_DISCONNECT)) { 123
123 cFYI(1, ("can not send cmd %d while umounting", 124 /*
124 smb_command)); 125 * only tree disconnect, open, and write, (and ulogoff which does not
125 return -ENODEV; 126 * have tcon) are allowed as we start force umount
126 } 127 */
128 if (tcon->tidStatus == CifsExiting) {
129 if (smb_command != SMB_COM_WRITE_ANDX &&
130 smb_command != SMB_COM_OPEN_ANDX &&
131 smb_command != SMB_COM_TREE_DISCONNECT) {
132 cFYI(1, ("can not send cmd %d while umounting",
133 smb_command));
134 return -ENODEV;
127 } 135 }
128 if ((tcon->ses) && (tcon->ses->status != CifsExiting) && 136 }
129 (tcon->ses->server)) {
130 struct nls_table *nls_codepage;
131 /* Give Demultiplex thread up to 10 seconds to
132 reconnect, should be greater than cifs socket
133 timeout which is 7 seconds */
134 while (tcon->ses->server->tcpStatus ==
135 CifsNeedReconnect) {
136 wait_event_interruptible_timeout(tcon->ses->server->response_q,
137 (tcon->ses->server->tcpStatus ==
138 CifsGood), 10 * HZ);
139 if (tcon->ses->server->tcpStatus ==
140 CifsNeedReconnect) {
141 /* on "soft" mounts we wait once */
142 if (!tcon->retry ||
143 (tcon->ses->status == CifsExiting)) {
144 cFYI(1, ("gave up waiting on "
145 "reconnect in smb_init"));
146 return -EHOSTDOWN;
147 } /* else "hard" mount - keep retrying
148 until process is killed or server
149 comes back on-line */
150 } else /* TCP session is reestablished now */
151 break;
152 }
153 137
154 nls_codepage = load_nls_default(); 138 if (ses->status == CifsExiting)
155 /* need to prevent multiple threads trying to 139 return -EIO;
156 simultaneously reconnect the same SMB session */
157 down(&tcon->ses->sesSem);
158 if (tcon->ses->need_reconnect)
159 rc = cifs_setup_session(0, tcon->ses,
160 nls_codepage);
161 if (!rc && (tcon->need_reconnect)) {
162 mark_open_files_invalid(tcon);
163 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
164 tcon, nls_codepage);
165 up(&tcon->ses->sesSem);
166 /* BB FIXME add code to check if wsize needs
167 update due to negotiated smb buffer size
168 shrinking */
169 if (rc == 0) {
170 atomic_inc(&tconInfoReconnectCount);
171 /* tell server Unix caps we support */
172 if (tcon->ses->capabilities & CAP_UNIX)
173 reset_cifs_unix_caps(
174 0 /* no xid */,
175 tcon,
176 NULL /* we do not know sb */,
177 NULL /* no vol info */);
178 }
179 140
180 cFYI(1, ("reconnect tcon rc = %d", rc)); 141 /*
181 /* Removed call to reopen open files here. 142 * Give demultiplex thread up to 10 seconds to reconnect, should be
182 It is safer (and faster) to reopen files 143 * greater than cifs socket timeout which is 7 seconds
183 one at a time as needed in read and write */ 144 */
184 145 while (server->tcpStatus == CifsNeedReconnect) {
185 /* Check if handle based operation so we 146 wait_event_interruptible_timeout(server->response_q,
186 know whether we can continue or not without 147 (server->tcpStatus == CifsGood), 10 * HZ);
187 returning to caller to reset file handle */
188 switch (smb_command) {
189 case SMB_COM_READ_ANDX:
190 case SMB_COM_WRITE_ANDX:
191 case SMB_COM_CLOSE:
192 case SMB_COM_FIND_CLOSE2:
193 case SMB_COM_LOCKING_ANDX: {
194 unload_nls(nls_codepage);
195 return -EAGAIN;
196 }
197 }
198 } else {
199 up(&tcon->ses->sesSem);
200 }
201 unload_nls(nls_codepage);
202 148
203 } else { 149 /* is TCP session is reestablished now ?*/
204 return -EIO; 150 if (server->tcpStatus != CifsNeedReconnect)
151 break;
152
153 /*
154 * on "soft" mounts we wait once. Hard mounts keep
155 * retrying until process is killed or server comes
156 * back on-line
157 */
158 if (!tcon->retry || ses->status == CifsExiting) {
159 cFYI(1, ("gave up waiting on reconnect in smb_init"));
160 return -EHOSTDOWN;
205 } 161 }
206 } 162 }
163
164 if (!ses->need_reconnect && !tcon->need_reconnect)
165 return 0;
166
167 nls_codepage = load_nls_default();
168
169 /*
170 * need to prevent multiple threads trying to simultaneously
171 * reconnect the same SMB session
172 */
173 down(&ses->sesSem);
174 if (ses->need_reconnect)
175 rc = cifs_setup_session(0, ses, nls_codepage);
176
177 /* do we need to reconnect tcon? */
178 if (rc || !tcon->need_reconnect) {
179 up(&ses->sesSem);
180 goto out;
181 }
182
183 mark_open_files_invalid(tcon);
184 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
185 up(&ses->sesSem);
186 cFYI(1, ("reconnect tcon rc = %d", rc));
187
188 if (rc)
189 goto out;
190
191 /*
192 * FIXME: check if wsize needs updated due to negotiated smb buffer
193 * size shrinking
194 */
195 atomic_inc(&tconInfoReconnectCount);
196
197 /* tell server Unix caps we support */
198 if (ses->capabilities & CAP_UNIX)
199 reset_cifs_unix_caps(0, tcon, NULL, NULL);
200
201 /*
202 * Removed call to reopen open files here. It is safer (and faster) to
203 * reopen files one at a time as needed in read and write.
204 *
205 * FIXME: what about file locks? don't we need to reclaim them ASAP?
206 */
207
208out:
209 /*
210 * Check if handle based operation so we know whether we can continue
211 * or not without returning to caller to reset file handle
212 */
213 switch (smb_command) {
214 case SMB_COM_READ_ANDX:
215 case SMB_COM_WRITE_ANDX:
216 case SMB_COM_CLOSE:
217 case SMB_COM_FIND_CLOSE2:
218 case SMB_COM_LOCKING_ANDX:
219 rc = -EAGAIN;
220 }
221
222 unload_nls(nls_codepage);
223 return rc;
224}
225
226/* Allocate and return pointer to an SMB request buffer, and set basic
227 SMB information in the SMB header. If the return code is zero, this
228 function must have filled in request_buf pointer */
229static int
230small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
231 void **request_buf)
232{
233 int rc = 0;
234
235 rc = cifs_reconnect_tcon(tcon, smb_command);
207 if (rc) 236 if (rc)
208 return rc; 237 return rc;
209 238
@@ -256,101 +285,7 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
256{ 285{
257 int rc = 0; 286 int rc = 0;
258 287
259 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so 288 rc = cifs_reconnect_tcon(tcon, smb_command);
260 check for tcp and smb session status done differently
261 for those three - in the calling routine */
262 if (tcon) {
263 if (tcon->tidStatus == CifsExiting) {
264 /* only tree disconnect, open, and write,
265 (and ulogoff which does not have tcon)
266 are allowed as we start force umount */
267 if ((smb_command != SMB_COM_WRITE_ANDX) &&
268 (smb_command != SMB_COM_OPEN_ANDX) &&
269 (smb_command != SMB_COM_TREE_DISCONNECT)) {
270 cFYI(1, ("can not send cmd %d while umounting",
271 smb_command));
272 return -ENODEV;
273 }
274 }
275
276 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
277 (tcon->ses->server)) {
278 struct nls_table *nls_codepage;
279 /* Give Demultiplex thread up to 10 seconds to
280 reconnect, should be greater than cifs socket
281 timeout which is 7 seconds */
282 while (tcon->ses->server->tcpStatus ==
283 CifsNeedReconnect) {
284 wait_event_interruptible_timeout(tcon->ses->server->response_q,
285 (tcon->ses->server->tcpStatus ==
286 CifsGood), 10 * HZ);
287 if (tcon->ses->server->tcpStatus ==
288 CifsNeedReconnect) {
289 /* on "soft" mounts we wait once */
290 if (!tcon->retry ||
291 (tcon->ses->status == CifsExiting)) {
292 cFYI(1, ("gave up waiting on "
293 "reconnect in smb_init"));
294 return -EHOSTDOWN;
295 } /* else "hard" mount - keep retrying
296 until process is killed or server
297 comes on-line */
298 } else /* TCP session is reestablished now */
299 break;
300 }
301 nls_codepage = load_nls_default();
302 /* need to prevent multiple threads trying to
303 simultaneously reconnect the same SMB session */
304 down(&tcon->ses->sesSem);
305 if (tcon->ses->need_reconnect)
306 rc = cifs_setup_session(0, tcon->ses,
307 nls_codepage);
308 if (!rc && (tcon->need_reconnect)) {
309 mark_open_files_invalid(tcon);
310 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
311 tcon, nls_codepage);
312 up(&tcon->ses->sesSem);
313 /* BB FIXME add code to check if wsize needs
314 update due to negotiated smb buffer size
315 shrinking */
316 if (rc == 0) {
317 atomic_inc(&tconInfoReconnectCount);
318 /* tell server Unix caps we support */
319 if (tcon->ses->capabilities & CAP_UNIX)
320 reset_cifs_unix_caps(
321 0 /* no xid */,
322 tcon,
323 NULL /* do not know sb */,
324 NULL /* no vol info */);
325 }
326
327 cFYI(1, ("reconnect tcon rc = %d", rc));
328 /* Removed call to reopen open files here.
329 It is safer (and faster) to reopen files
330 one at a time as needed in read and write */
331
332 /* Check if handle based operation so we
333 know whether we can continue or not without
334 returning to caller to reset file handle */
335 switch (smb_command) {
336 case SMB_COM_READ_ANDX:
337 case SMB_COM_WRITE_ANDX:
338 case SMB_COM_CLOSE:
339 case SMB_COM_FIND_CLOSE2:
340 case SMB_COM_LOCKING_ANDX: {
341 unload_nls(nls_codepage);
342 return -EAGAIN;
343 }
344 }
345 } else {
346 up(&tcon->ses->sesSem);
347 }
348 unload_nls(nls_codepage);
349
350 } else {
351 return -EIO;
352 }
353 }
354 if (rc) 289 if (rc)
355 return rc; 290 return rc;
356 291
@@ -3961,6 +3896,10 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
3961 if (is_unicode) { 3896 if (is_unicode) {
3962 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2, 3897 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
3963 GFP_KERNEL); 3898 GFP_KERNEL);
3899 if (tmp == NULL) {
3900 rc = -ENOMEM;
3901 goto parse_DFS_referrals_exit;
3902 }
3964 cifsConvertToUCS((__le16 *) tmp, searchName, 3903 cifsConvertToUCS((__le16 *) tmp, searchName,
3965 PATH_MAX, nls_codepage, remap); 3904 PATH_MAX, nls_codepage, remap);
3966 node->path_consumed = cifs_ucs2_bytes(tmp, 3905 node->path_consumed = cifs_ucs2_bytes(tmp,