ASoC: rockchip: add support for rk3228 spdif
[firefly-linux-kernel-4.4.55.git] / fs / cifs / smb2pdu.c
index 749cc3e5b9330a9748b2ce35e3465ef5b04f46d4..6cb2603f8a5c3685159eef3c549e6d558613d61d 100644 (file)
@@ -278,7 +278,7 @@ out:
        case SMB2_CHANGE_NOTIFY:
        case SMB2_QUERY_INFO:
        case SMB2_SET_INFO:
-               return -EAGAIN;
+               rc = -EAGAIN;
        }
        unload_nls(nls_codepage);
        return rc;
@@ -607,6 +607,7 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
        char *security_blob = NULL;
        unsigned char *ntlmssp_blob = NULL;
        bool use_spnego = false; /* else use raw ntlmssp */
+       u64 previous_session = ses->Suid;
 
        cifs_dbg(FYI, "Session Setup\n");
 
@@ -644,6 +645,10 @@ ssetup_ntlmssp_authenticate:
                return rc;
 
        req->hdr.SessionId = 0; /* First session, not a reauthenticate */
+
+       /* if reconnect, we need to send previous sess id, otherwise it is 0 */
+       req->PreviousSessionId = previous_session;
+
        req->Flags = 0; /* MBZ */
        /* to enable echos and oplocks */
        req->hdr.CreditRequest = cpu_to_le16(3);
@@ -927,9 +932,6 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
        else
                return -EIO;
 
-       if (tcon && tcon->bad_network_name)
-               return -ENOENT;
-
        if ((tcon && tcon->seal) &&
            ((ses->server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION) == 0)) {
                cifs_dbg(VFS, "encryption requested but no server support");
@@ -947,6 +949,10 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
                return -EINVAL;
        }
 
+       /* SMB2 TREE_CONNECT request must be called with TreeId == 0 */
+       if (tcon)
+               tcon->tid = 0;
+
        rc = small_smb2_init(SMB2_TREE_CONNECT, tcon, (void **) &req);
        if (rc) {
                kfree(unc_path);
@@ -1027,8 +1033,6 @@ tcon_exit:
 tcon_error_exit:
        if (rsp->hdr.Status == STATUS_BAD_NETWORK_NAME) {
                cifs_dbg(VFS, "BAD_NETWORK_NAME: %s\n", tree);
-               if (tcon)
-                       tcon->bad_network_name = true;
        }
        goto tcon_exit;
 }
@@ -1181,7 +1185,7 @@ create_durable_v2_buf(struct cifs_fid *pfid)
 
        buf->dcontext.Timeout = 0; /* Should this be configurable by workload */
        buf->dcontext.Flags = cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT);
-       get_random_bytes(buf->dcontext.CreateGuid, 16);
+       generate_random_uuid(buf->dcontext.CreateGuid);
        memcpy(pfid->create_guid, buf->dcontext.CreateGuid, 16);
 
        /* SMB2_CREATE_DURABLE_HANDLE_REQUEST is "DH2Q" */
@@ -1817,6 +1821,54 @@ smb2_echo_callback(struct mid_q_entry *mid)
        add_credits(server, credits_received, CIFS_ECHO_OP);
 }
 
+void smb2_reconnect_server(struct work_struct *work)
+{
+       struct TCP_Server_Info *server = container_of(work,
+                                       struct TCP_Server_Info, reconnect.work);
+       struct cifs_ses *ses;
+       struct cifs_tcon *tcon, *tcon2;
+       struct list_head tmp_list;
+       int tcon_exist = false;
+
+       /* Prevent simultaneous reconnects that can corrupt tcon->rlist list */
+       mutex_lock(&server->reconnect_mutex);
+
+       INIT_LIST_HEAD(&tmp_list);
+       cifs_dbg(FYI, "Need negotiate, reconnecting tcons\n");
+
+       spin_lock(&cifs_tcp_ses_lock);
+       list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
+               list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
+                       if (tcon->need_reconnect) {
+                               tcon->tc_count++;
+                               list_add_tail(&tcon->rlist, &tmp_list);
+                               tcon_exist = true;
+                       }
+               }
+       }
+       /*
+        * Get the reference to server struct to be sure that the last call of
+        * cifs_put_tcon() in the loop below won't release the server pointer.
+        */
+       if (tcon_exist)
+               server->srv_count++;
+
+       spin_unlock(&cifs_tcp_ses_lock);
+
+       list_for_each_entry_safe(tcon, tcon2, &tmp_list, rlist) {
+               smb2_reconnect(SMB2_ECHO, tcon);
+               list_del_init(&tcon->rlist);
+               cifs_put_tcon(tcon);
+       }
+
+       cifs_dbg(FYI, "Reconnecting tcons finished\n");
+       mutex_unlock(&server->reconnect_mutex);
+
+       /* now we can safely release srv struct */
+       if (tcon_exist)
+               cifs_put_tcp_session(server, 1);
+}
+
 int
 SMB2_echo(struct TCP_Server_Info *server)
 {
@@ -1829,32 +1881,11 @@ SMB2_echo(struct TCP_Server_Info *server)
        cifs_dbg(FYI, "In echo request\n");
 
        if (server->tcpStatus == CifsNeedNegotiate) {
-               struct list_head *tmp, *tmp2;
-               struct cifs_ses *ses;
-               struct cifs_tcon *tcon;
-
-               cifs_dbg(FYI, "Need negotiate, reconnecting tcons\n");
-               spin_lock(&cifs_tcp_ses_lock);
-               list_for_each(tmp, &server->smb_ses_list) {
-                       ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
-                       list_for_each(tmp2, &ses->tcon_list) {
-                               tcon = list_entry(tmp2, struct cifs_tcon,
-                                                 tcon_list);
-                               /* add check for persistent handle reconnect */
-                               if (tcon && tcon->need_reconnect) {
-                                       spin_unlock(&cifs_tcp_ses_lock);
-                                       rc = smb2_reconnect(SMB2_ECHO, tcon);
-                                       spin_lock(&cifs_tcp_ses_lock);
-                               }
-                       }
-               }
-               spin_unlock(&cifs_tcp_ses_lock);
+               /* No need to send echo on newly established connections */
+               queue_delayed_work(cifsiod_wq, &server->reconnect, 0);
+               return rc;
        }
 
-       /* if no session, renegotiate failed above */
-       if (server->tcpStatus == CifsNeedNegotiate)
-               return -EIO;
-
        rc = small_smb2_init(SMB2_ECHO, NULL, (void **)&req);
        if (rc)
                return rc;