diff options
Diffstat (limited to 'fs/cifs/cifssmb.c')
-rw-r--r-- | fs/cifs/cifssmb.c | 317 |
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 */ | ||
106 | static int | 105 | static int |
107 | small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | 106 | cifs_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 | |||
208 | out: | ||
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 */ | ||
229 | static int | ||
230 | small_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, |