|
@@ -127,7 +127,132 @@ static int
|
|
|
smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
|
|
|
{
|
|
|
int rc = 0;
|
|
|
- /* BB add missing code here */
|
|
|
+ struct nls_table *nls_codepage;
|
|
|
+ struct cifs_ses *ses;
|
|
|
+ struct TCP_Server_Info *server;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * SMB2s NegProt, SessSetup, Logoff do not have tcon yet so
|
|
|
+ * check for tcp and smb session status done differently
|
|
|
+ * for those three - in the calling routine.
|
|
|
+ */
|
|
|
+ if (tcon == NULL)
|
|
|
+ return rc;
|
|
|
+
|
|
|
+ if (smb2_command == SMB2_TREE_CONNECT)
|
|
|
+ return rc;
|
|
|
+
|
|
|
+ if (tcon->tidStatus == CifsExiting) {
|
|
|
+ /*
|
|
|
+ * only tree disconnect, open, and write,
|
|
|
+ * (and ulogoff which does not have tcon)
|
|
|
+ * are allowed as we start force umount.
|
|
|
+ */
|
|
|
+ if ((smb2_command != SMB2_WRITE) &&
|
|
|
+ (smb2_command != SMB2_CREATE) &&
|
|
|
+ (smb2_command != SMB2_TREE_DISCONNECT)) {
|
|
|
+ cFYI(1, "can not send cmd %d while umounting",
|
|
|
+ smb2_command);
|
|
|
+ return -ENODEV;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if ((!tcon->ses) || (tcon->ses->status == CifsExiting) ||
|
|
|
+ (!tcon->ses->server))
|
|
|
+ return -EIO;
|
|
|
+
|
|
|
+ ses = tcon->ses;
|
|
|
+ server = ses->server;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Give demultiplex thread up to 10 seconds to reconnect, should be
|
|
|
+ * greater than cifs socket timeout which is 7 seconds
|
|
|
+ */
|
|
|
+ while (server->tcpStatus == CifsNeedReconnect) {
|
|
|
+ /*
|
|
|
+ * Return to caller for TREE_DISCONNECT and LOGOFF and CLOSE
|
|
|
+ * here since they are implicitly done when session drops.
|
|
|
+ */
|
|
|
+ switch (smb2_command) {
|
|
|
+ /*
|
|
|
+ * BB Should we keep oplock break and add flush to exceptions?
|
|
|
+ */
|
|
|
+ case SMB2_TREE_DISCONNECT:
|
|
|
+ case SMB2_CANCEL:
|
|
|
+ case SMB2_CLOSE:
|
|
|
+ case SMB2_OPLOCK_BREAK:
|
|
|
+ return -EAGAIN;
|
|
|
+ }
|
|
|
+
|
|
|
+ wait_event_interruptible_timeout(server->response_q,
|
|
|
+ (server->tcpStatus != CifsNeedReconnect), 10 * HZ);
|
|
|
+
|
|
|
+ /* are we still trying to reconnect? */
|
|
|
+ if (server->tcpStatus != CifsNeedReconnect)
|
|
|
+ break;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * on "soft" mounts we wait once. Hard mounts keep
|
|
|
+ * retrying until process is killed or server comes
|
|
|
+ * back on-line
|
|
|
+ */
|
|
|
+ if (!tcon->retry) {
|
|
|
+ cFYI(1, "gave up waiting on reconnect in smb_init");
|
|
|
+ return -EHOSTDOWN;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!tcon->ses->need_reconnect && !tcon->need_reconnect)
|
|
|
+ return rc;
|
|
|
+
|
|
|
+ nls_codepage = load_nls_default();
|
|
|
+
|
|
|
+ /*
|
|
|
+ * need to prevent multiple threads trying to simultaneously reconnect
|
|
|
+ * the same SMB session
|
|
|
+ */
|
|
|
+ mutex_lock(&tcon->ses->session_mutex);
|
|
|
+ rc = cifs_negotiate_protocol(0, tcon->ses);
|
|
|
+ if (!rc && tcon->ses->need_reconnect)
|
|
|
+ rc = cifs_setup_session(0, tcon->ses, nls_codepage);
|
|
|
+
|
|
|
+ if (rc || !tcon->need_reconnect) {
|
|
|
+ mutex_unlock(&tcon->ses->session_mutex);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ cifs_mark_open_files_invalid(tcon);
|
|
|
+ rc = SMB2_tcon(0, tcon->ses, tcon->treeName, tcon, nls_codepage);
|
|
|
+ mutex_unlock(&tcon->ses->session_mutex);
|
|
|
+ cFYI(1, "reconnect tcon rc = %d", rc);
|
|
|
+ if (rc)
|
|
|
+ goto out;
|
|
|
+ atomic_inc(&tconInfoReconnectCount);
|
|
|
+ /*
|
|
|
+ * BB FIXME add code to check if wsize needs update due to negotiated
|
|
|
+ * smb buffer size shrinking.
|
|
|
+ */
|
|
|
+out:
|
|
|
+ /*
|
|
|
+ * Check if handle based operation so we know whether we can continue
|
|
|
+ * or not without returning to caller to reset file handle.
|
|
|
+ */
|
|
|
+ /*
|
|
|
+ * BB Is flush done by server on drop of tcp session? Should we special
|
|
|
+ * case it and skip above?
|
|
|
+ */
|
|
|
+ switch (smb2_command) {
|
|
|
+ case SMB2_FLUSH:
|
|
|
+ case SMB2_READ:
|
|
|
+ case SMB2_WRITE:
|
|
|
+ case SMB2_LOCK:
|
|
|
+ case SMB2_IOCTL:
|
|
|
+ case SMB2_QUERY_DIRECTORY:
|
|
|
+ case SMB2_CHANGE_NOTIFY:
|
|
|
+ case SMB2_QUERY_INFO:
|
|
|
+ case SMB2_SET_INFO:
|
|
|
+ return -EAGAIN;
|
|
|
+ }
|
|
|
+ unload_nls(nls_codepage);
|
|
|
return rc;
|
|
|
}
|
|
|
|