diff options
author | Pavel Shilovsky <piastry@etersoft.ru> | 2011-12-27 07:23:34 -0500 |
---|---|---|
committer | Pavel Shilovsky <pshilovsky@samba.org> | 2012-07-24 13:54:59 -0400 |
commit | aa24d1e9692411e605084938ced6b160f92df454 (patch) | |
tree | 399446513c2437af67ca8ed065ba16f272715bb4 /fs/cifs/smb2pdu.c | |
parent | faaf946a7d5b79194358437150f34ab4c66bfe21 (diff) |
CIFS: Process reconnects for SMB2 shares
Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru>
Signed-off-by: Steve French <smfrench@gmail.com>
Diffstat (limited to 'fs/cifs/smb2pdu.c')
-rw-r--r-- | fs/cifs/smb2pdu.c | 127 |
1 files changed, 126 insertions, 1 deletions
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 1bf037ec5a9d..48c04b2832e2 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c | |||
@@ -127,7 +127,132 @@ static int | |||
127 | smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) | 127 | smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) |
128 | { | 128 | { |
129 | int rc = 0; | 129 | int rc = 0; |
130 | /* BB add missing code here */ | 130 | struct nls_table *nls_codepage; |
131 | struct cifs_ses *ses; | ||
132 | struct TCP_Server_Info *server; | ||
133 | |||
134 | /* | ||
135 | * SMB2s NegProt, SessSetup, Logoff do not have tcon yet so | ||
136 | * check for tcp and smb session status done differently | ||
137 | * for those three - in the calling routine. | ||
138 | */ | ||
139 | if (tcon == NULL) | ||
140 | return rc; | ||
141 | |||
142 | if (smb2_command == SMB2_TREE_CONNECT) | ||
143 | return rc; | ||
144 | |||
145 | if (tcon->tidStatus == CifsExiting) { | ||
146 | /* | ||
147 | * only tree disconnect, open, and write, | ||
148 | * (and ulogoff which does not have tcon) | ||
149 | * are allowed as we start force umount. | ||
150 | */ | ||
151 | if ((smb2_command != SMB2_WRITE) && | ||
152 | (smb2_command != SMB2_CREATE) && | ||
153 | (smb2_command != SMB2_TREE_DISCONNECT)) { | ||
154 | cFYI(1, "can not send cmd %d while umounting", | ||
155 | smb2_command); | ||
156 | return -ENODEV; | ||
157 | } | ||
158 | } | ||
159 | if ((!tcon->ses) || (tcon->ses->status == CifsExiting) || | ||
160 | (!tcon->ses->server)) | ||
161 | return -EIO; | ||
162 | |||
163 | ses = tcon->ses; | ||
164 | server = ses->server; | ||
165 | |||
166 | /* | ||
167 | * Give demultiplex thread up to 10 seconds to reconnect, should be | ||
168 | * greater than cifs socket timeout which is 7 seconds | ||
169 | */ | ||
170 | while (server->tcpStatus == CifsNeedReconnect) { | ||
171 | /* | ||
172 | * Return to caller for TREE_DISCONNECT and LOGOFF and CLOSE | ||
173 | * here since they are implicitly done when session drops. | ||
174 | */ | ||
175 | switch (smb2_command) { | ||
176 | /* | ||
177 | * BB Should we keep oplock break and add flush to exceptions? | ||
178 | */ | ||
179 | case SMB2_TREE_DISCONNECT: | ||
180 | case SMB2_CANCEL: | ||
181 | case SMB2_CLOSE: | ||
182 | case SMB2_OPLOCK_BREAK: | ||
183 | return -EAGAIN; | ||
184 | } | ||
185 | |||
186 | wait_event_interruptible_timeout(server->response_q, | ||
187 | (server->tcpStatus != CifsNeedReconnect), 10 * HZ); | ||
188 | |||
189 | /* are we still trying to reconnect? */ | ||
190 | if (server->tcpStatus != CifsNeedReconnect) | ||
191 | break; | ||
192 | |||
193 | /* | ||
194 | * on "soft" mounts we wait once. Hard mounts keep | ||
195 | * retrying until process is killed or server comes | ||
196 | * back on-line | ||
197 | */ | ||
198 | if (!tcon->retry) { | ||
199 | cFYI(1, "gave up waiting on reconnect in smb_init"); | ||
200 | return -EHOSTDOWN; | ||
201 | } | ||
202 | } | ||
203 | |||
204 | if (!tcon->ses->need_reconnect && !tcon->need_reconnect) | ||
205 | return rc; | ||
206 | |||
207 | nls_codepage = load_nls_default(); | ||
208 | |||
209 | /* | ||
210 | * need to prevent multiple threads trying to simultaneously reconnect | ||
211 | * the same SMB session | ||
212 | */ | ||
213 | mutex_lock(&tcon->ses->session_mutex); | ||
214 | rc = cifs_negotiate_protocol(0, tcon->ses); | ||
215 | if (!rc && tcon->ses->need_reconnect) | ||
216 | rc = cifs_setup_session(0, tcon->ses, nls_codepage); | ||
217 | |||
218 | if (rc || !tcon->need_reconnect) { | ||
219 | mutex_unlock(&tcon->ses->session_mutex); | ||
220 | goto out; | ||
221 | } | ||
222 | |||
223 | cifs_mark_open_files_invalid(tcon); | ||
224 | rc = SMB2_tcon(0, tcon->ses, tcon->treeName, tcon, nls_codepage); | ||
225 | mutex_unlock(&tcon->ses->session_mutex); | ||
226 | cFYI(1, "reconnect tcon rc = %d", rc); | ||
227 | if (rc) | ||
228 | goto out; | ||
229 | atomic_inc(&tconInfoReconnectCount); | ||
230 | /* | ||
231 | * BB FIXME add code to check if wsize needs update due to negotiated | ||
232 | * smb buffer size shrinking. | ||
233 | */ | ||
234 | out: | ||
235 | /* | ||
236 | * Check if handle based operation so we know whether we can continue | ||
237 | * or not without returning to caller to reset file handle. | ||
238 | */ | ||
239 | /* | ||
240 | * BB Is flush done by server on drop of tcp session? Should we special | ||
241 | * case it and skip above? | ||
242 | */ | ||
243 | switch (smb2_command) { | ||
244 | case SMB2_FLUSH: | ||
245 | case SMB2_READ: | ||
246 | case SMB2_WRITE: | ||
247 | case SMB2_LOCK: | ||
248 | case SMB2_IOCTL: | ||
249 | case SMB2_QUERY_DIRECTORY: | ||
250 | case SMB2_CHANGE_NOTIFY: | ||
251 | case SMB2_QUERY_INFO: | ||
252 | case SMB2_SET_INFO: | ||
253 | return -EAGAIN; | ||
254 | } | ||
255 | unload_nls(nls_codepage); | ||
131 | return rc; | 256 | return rc; |
132 | } | 257 | } |
133 | 258 | ||