cifs: do not send tree disconnect to ipc shares
[linux-2.6-microblaze.git] / fs / cifs / connect.c
index eec8a20..ecac8ca 100644 (file)
@@ -62,9 +62,7 @@
 #include "dfs_cache.h"
 #endif
 #include "fs_context.h"
-#ifdef CONFIG_CIFS_SWN_UPCALL
 #include "cifs_swn.h"
-#endif
 
 extern mempool_t *cifs_req_poolp;
 extern bool disable_legacy_dialects;
@@ -87,7 +85,6 @@ static void cifs_prune_tlinks(struct work_struct *work);
  *
  * This should be called with server->srv_mutex held.
  */
-#ifdef CONFIG_CIFS_DFS_UPCALL
 static int reconn_set_ipaddr_from_hostname(struct TCP_Server_Info *server)
 {
        int rc;
@@ -124,6 +121,7 @@ static int reconn_set_ipaddr_from_hostname(struct TCP_Server_Info *server)
        return !rc ? -1 : 0;
 }
 
+#ifdef CONFIG_CIFS_DFS_UPCALL
 /* These functions must be called with server->srv_mutex held */
 static void reconn_set_next_dfs_target(struct TCP_Server_Info *server,
                                       struct cifs_sb_info *cifs_sb,
@@ -314,25 +312,34 @@ cifs_reconnect(struct TCP_Server_Info *server)
 
                mutex_lock(&server->srv_mutex);
 
-#ifdef CONFIG_CIFS_SWN_UPCALL
-               if (server->use_swn_dstaddr) {
-                       server->dstaddr = server->swn_dstaddr;
-               } else {
-#endif
 
+               if (!cifs_swn_set_server_dstaddr(server)) {
 #ifdef CONFIG_CIFS_DFS_UPCALL
+               if (cifs_sb && cifs_sb->origin_fullpath)
                        /*
                         * Set up next DFS target server (if any) for reconnect. If DFS
                         * feature is disabled, then we will retry last server we
                         * connected to before.
                         */
                        reconn_set_next_dfs_target(server, cifs_sb, &tgt_list, &tgt_it);
+               else {
 #endif
+                       /*
+                        * Resolve the hostname again to make sure that IP address is up-to-date.
+                        */
+                       rc = reconn_set_ipaddr_from_hostname(server);
+                       if (rc) {
+                               cifs_dbg(FYI, "%s: failed to resolve hostname: %d\n",
+                                               __func__, rc);
+                       }
 
-#ifdef CONFIG_CIFS_SWN_UPCALL
+#ifdef CONFIG_CIFS_DFS_UPCALL
                }
 #endif
 
+
+               }
+
                if (cifs_rdma_enabled(server))
                        rc = smbd_reconnect(server);
                else
@@ -348,9 +355,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
                        if (server->tcpStatus != CifsExiting)
                                server->tcpStatus = CifsNeedNegotiate;
                        spin_unlock(&GlobalMid_Lock);
-#ifdef CONFIG_CIFS_SWN_UPCALL
-                       server->use_swn_dstaddr = false;
-#endif
+                       cifs_swn_reset_server_dstaddr(server);
                        mutex_unlock(&server->srv_mutex);
                }
        } while (server->tcpStatus == CifsNeedReconnect);
@@ -387,16 +392,6 @@ cifs_echo_request(struct work_struct *work)
        int rc;
        struct TCP_Server_Info *server = container_of(work,
                                        struct TCP_Server_Info, echo.work);
-       unsigned long echo_interval;
-
-       /*
-        * If we need to renegotiate, set echo interval to zero to
-        * immediately call echo service where we can renegotiate.
-        */
-       if (server->tcpStatus == CifsNeedNegotiate)
-               echo_interval = 0;
-       else
-               echo_interval = server->echo_interval;
 
        /*
         * We cannot send an echo if it is disabled.
@@ -407,7 +402,7 @@ cifs_echo_request(struct work_struct *work)
            server->tcpStatus == CifsExiting ||
            server->tcpStatus == CifsNew ||
            (server->ops->can_echo && !server->ops->can_echo(server)) ||
-           time_before(jiffies, server->lstrp + echo_interval - HZ))
+           time_before(jiffies, server->lstrp + server->echo_interval - HZ))
                goto requeue_echo;
 
        rc = server->ops->echo ? server->ops->echo(server) : -ENOSYS;
@@ -415,10 +410,8 @@ cifs_echo_request(struct work_struct *work)
                cifs_dbg(FYI, "Unable to send echo request to server: %s\n",
                         server->hostname);
 
-#ifdef CONFIG_CIFS_SWN_UPCALL
        /* Check witness registrations */
        cifs_swn_check();
-#endif
 
 requeue_echo:
        queue_delayed_work(cifsiod_wq, &server->echo, server->echo_interval);
@@ -473,6 +466,7 @@ server_unresponsive(struct TCP_Server_Info *server)
         */
        if ((server->tcpStatus == CifsGood ||
            server->tcpStatus == CifsNeedNegotiate) &&
+           (!server->ops->can_echo || server->ops->can_echo(server)) &&
            time_after(jiffies, server->lstrp + 3 * server->echo_interval)) {
                cifs_server_dbg(VFS, "has not responded in %lu seconds. Reconnecting...\n",
                         (3 * server->echo_interval) / HZ);
@@ -1563,29 +1557,25 @@ out:
 /**
  * cifs_free_ipc - helper to release the session IPC tcon
  *
- * Needs to be called everytime a session is destroyed
+ * Needs to be called everytime a session is destroyed.
+ *
+ * On session close, the IPC is closed and the server must release all tcons of the session.
+ * No need to send a tree disconnect here.
+ *
+ * Besides, it will make the server to not close durable and resilient files on session close, as
+ * specified in MS-SMB2 3.3.5.6 Receiving an SMB2 LOGOFF Request.
  */
 static int
 cifs_free_ipc(struct cifs_ses *ses)
 {
-       int rc = 0, xid;
        struct cifs_tcon *tcon = ses->tcon_ipc;
 
        if (tcon == NULL)
                return 0;
 
-       if (ses->server->ops->tree_disconnect) {
-               xid = get_xid();
-               rc = ses->server->ops->tree_disconnect(xid, tcon);
-               free_xid(xid);
-       }
-
-       if (rc)
-               cifs_dbg(FYI, "failed to disconnect IPC tcon (rc=%d)\n", rc);
-
        tconInfoFree(tcon);
        ses->tcon_ipc = NULL;
-       return rc;
+       return 0;
 }
 
 static struct cifs_ses *
@@ -1775,9 +1765,7 @@ cifs_set_cifscreds(struct smb3_fs_context *ctx, struct cifs_ses *ses)
         * for the request.
         */
        if (is_domain && ses->domainName) {
-               ctx->domainname = kstrndup(ses->domainName,
-                                          strlen(ses->domainName),
-                                          GFP_KERNEL);
+               ctx->domainname = kstrdup(ses->domainName, GFP_KERNEL);
                if (!ctx->domainname) {
                        cifs_dbg(FYI, "Unable to allocate %zd bytes for domain\n",
                                 len);
@@ -1994,7 +1982,6 @@ cifs_put_tcon(struct cifs_tcon *tcon)
                return;
        }
 
-#ifdef CONFIG_CIFS_SWN_UPCALL
        if (tcon->use_witness) {
                int rc;
 
@@ -2004,7 +1991,6 @@ cifs_put_tcon(struct cifs_tcon *tcon)
                                        __func__, rc);
                }
        }
-#endif
 
        list_del_init(&tcon->tcon_list);
        spin_unlock(&cifs_tcp_ses_lock);
@@ -2166,9 +2152,9 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx)
                }
                tcon->use_resilient = true;
        }
-#ifdef CONFIG_CIFS_SWN_UPCALL
+
        tcon->use_witness = false;
-       if (ctx->witness) {
+       if (IS_ENABLED(CONFIG_CIFS_SWN_UPCALL) && ctx->witness) {
                if (ses->server->vals->protocol_id >= SMB30_PROT_ID) {
                        if (tcon->capabilities & SMB2_SHARE_CAP_CLUSTER) {
                                /*
@@ -2194,7 +2180,6 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx)
                        goto out_fail;
                }
        }
-#endif
 
        /* If the user really knows what they are doing they can override */
        if (tcon->share_flags & SMB2_SHAREFLAG_NO_CACHING) {
@@ -3160,17 +3145,29 @@ out:
 int
 cifs_setup_volume_info(struct smb3_fs_context *ctx, const char *mntopts, const char *devname)
 {
-       int rc = 0;
+       int rc;
 
-       smb3_parse_devname(devname, ctx);
+       if (devname) {
+               cifs_dbg(FYI, "%s: devname=%s\n", __func__, devname);
+               rc = smb3_parse_devname(devname, ctx);
+               if (rc) {
+                       cifs_dbg(VFS, "%s: failed to parse %s: %d\n", __func__, devname, rc);
+                       return rc;
+               }
+       }
 
        if (mntopts) {
                char *ip;
 
-               cifs_dbg(FYI, "%s: mntopts=%s\n", __func__, mntopts);
                rc = smb3_parse_opt(mntopts, "ip", &ip);
-               if (!rc && !cifs_convert_address((struct sockaddr *)&ctx->dstaddr, ip,
-                                                strlen(ip))) {
+               if (rc) {
+                       cifs_dbg(VFS, "%s: failed to parse ip options: %d\n", __func__, rc);
+                       return rc;
+               }
+
+               rc = cifs_convert_address((struct sockaddr *)&ctx->dstaddr, ip, strlen(ip));
+               kfree(ip);
+               if (!rc) {
                        cifs_dbg(VFS, "%s: failed to convert ip address\n", __func__);
                        return -EINVAL;
                }
@@ -3190,7 +3187,7 @@ cifs_setup_volume_info(struct smb3_fs_context *ctx, const char *mntopts, const c
                return -EINVAL;
        }
 
-       return rc;
+       return 0;
 }
 
 static int
@@ -3411,8 +3408,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
                        goto error;
        }
        /* Save mount options */
-       mntdata = kstrndup(cifs_sb->ctx->mount_options,
-                          strlen(cifs_sb->ctx->mount_options), GFP_KERNEL);
+       mntdata = kstrdup(cifs_sb->ctx->mount_options, GFP_KERNEL);
        if (!mntdata) {
                rc = -ENOMEM;
                goto error;
@@ -3485,7 +3481,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
         * links, the prefix path is included in both and may be changed during reconnect.  See
         * cifs_tree_connect().
         */
-       cifs_sb->origin_fullpath = kstrndup(full_path, strlen(full_path), GFP_KERNEL);
+       cifs_sb->origin_fullpath = kstrdup(full_path, GFP_KERNEL);
        if (!cifs_sb->origin_fullpath) {
                rc = -ENOMEM;
                goto error;
@@ -3862,9 +3858,7 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid)
        ctx->sectype = master_tcon->ses->sectype;
        ctx->sign = master_tcon->ses->sign;
        ctx->seal = master_tcon->seal;
-#ifdef CONFIG_CIFS_SWN_UPCALL
        ctx->witness = master_tcon->use_witness;
-#endif
 
        rc = cifs_set_vol_auth(ctx, master_tcon->ses);
        if (rc) {