ASoC: rt5651: add alc5651 ASRC switch for HDMIIn
[firefly-linux-kernel-4.4.55.git] / fs / cifs / smb2pdu.c
index 0dbbdf5e4aeeb2fc56e7a9d4df235c18c188430e..2fa754c5fd6299aecedf7969b23c31d6f33e6e80 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;
@@ -1822,6 +1822,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)
 {
@@ -1834,32 +1882,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;