|
@@ -1972,6 +1972,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)
|
|
|
{
|
|
@@ -1984,32 +2032,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;
|