Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 24 Dec 2016 19:37:18 +0000 (11:37 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 24 Dec 2016 19:37:18 +0000 (11:37 -0800)
Pull cifs fixes from Steve French:
 "This ncludes various cifs/smb3 bug fixes, mostly for stable as well.

  In the next week I expect that Germano will have some reconnection
  fixes, and also I expect to have the remaining pieces of the snapshot
  enablement and SMB3 ACLs, but wanted to get this set of bug fixes in"

* 'for-next' of git://git.samba.org/sfrench/cifs-2.6:
  cifs_get_root shouldn't use path with tree name
  Fix default behaviour for empty domains and add domainauto option
  cifs: use %16phN for formatting md5 sum
  cifs: Fix smbencrypt() to stop pointing a scatterlist at the stack
  CIFS: Fix a possible double locking of mutex during reconnect
  CIFS: Fix a possible memory corruption during reconnect
  CIFS: Fix a possible memory corruption in push locks
  CIFS: Fix missing nls unload in smb2_reconnect()
  CIFS: Decrease verbosity of ioctl call
  SMB3: parsing for new snapshot timestamp mount parm

14 files changed:
fs/cifs/cifsencrypt.c
fs/cifs/cifsfs.c
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/connect.c
fs/cifs/dir.c
fs/cifs/file.c
fs/cifs/ioctl.c
fs/cifs/link.c
fs/cifs/smb2file.c
fs/cifs/smb2pdu.c
fs/cifs/smb2pdu.h
fs/cifs/smb2proto.h
fs/cifs/smbencrypt.c

index 5eb04129f93849c2727a517119bc484761160332..66bd7fa9b7a6f739f7f5fda0d0b6fe4c79192a47 100644 (file)
@@ -699,11 +699,15 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
 
        if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED) {
                if (!ses->domainName) {
-                       rc = find_domain_name(ses, nls_cp);
-                       if (rc) {
-                               cifs_dbg(VFS, "error %d finding domain name\n",
-                                        rc);
-                               goto setup_ntlmv2_rsp_ret;
+                       if (ses->domainAuto) {
+                               rc = find_domain_name(ses, nls_cp);
+                               if (rc) {
+                                       cifs_dbg(VFS, "error %d finding domain name\n",
+                                                rc);
+                                       goto setup_ntlmv2_rsp_ret;
+                               }
+                       } else {
+                               ses->domainName = kstrdup("", GFP_KERNEL);
                        }
                }
        } else {
index e6efb9a8859892df6ded9d58334815439828d2ec..70f4e65fced233613746e33422cf6efa4e9b0ea0 100644 (file)
@@ -615,7 +615,7 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb)
                return dget(sb->s_root);
 
        full_path = cifs_build_path_to_root(vol, cifs_sb,
-                                           cifs_sb_master_tcon(cifs_sb));
+                               cifs_sb_master_tcon(cifs_sb), 0);
        if (full_path == NULL)
                return ERR_PTR(-ENOMEM);
 
index 1f17f6bd7a601c56e40a6393c25eaee892e40a0f..7ea8a3393936c87976208677d816258eb3a94465 100644 (file)
@@ -514,6 +514,7 @@ struct smb_vol {
        bool persistent:1;
        bool nopersistent:1;
        bool resilient:1; /* noresilient not required since not fored for CA */
+       bool domainauto:1;
        unsigned int rsize;
        unsigned int wsize;
        bool sockopt_tcp_nodelay:1;
@@ -525,6 +526,7 @@ struct smb_vol {
        struct sockaddr_storage srcaddr; /* allow binding to a local IP */
        struct nls_table *local_nls;
        unsigned int echo_interval; /* echo interval in secs */
+       __u64 snapshot_time; /* needed for timewarp tokens */
        unsigned int max_credits; /* smb3 max_credits 10 < credits < 60000 */
 };
 
@@ -646,6 +648,8 @@ struct TCP_Server_Info {
        unsigned int    max_read;
        unsigned int    max_write;
        __u8            preauth_hash[512];
+       struct delayed_work reconnect; /* reconnect workqueue job */
+       struct mutex reconnect_mutex; /* prevent simultaneous reconnects */
 #endif /* CONFIG_CIFS_SMB2 */
        unsigned long echo_interval;
 };
@@ -827,6 +831,7 @@ struct cifs_ses {
        enum securityEnum sectype; /* what security flavor was specified? */
        bool sign;              /* is signing required? */
        bool need_reconnect:1; /* connection reset, uid now invalid */
+       bool domainAuto:1;
 #ifdef CONFIG_CIFS_SMB2
        __u16 session_flags;
        __u8 smb3signingkey[SMB3_SIGN_KEY_SIZE];
@@ -849,6 +854,7 @@ cap_unix(struct cifs_ses *ses)
 struct cifs_tcon {
        struct list_head tcon_list;
        int tc_count;
+       struct list_head rlist; /* reconnect list */
        struct list_head openFileList;
        spinlock_t open_file_lock; /* protects list above */
        struct cifs_ses *ses;   /* pointer to session associated with */
@@ -922,6 +928,7 @@ struct cifs_tcon {
        bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */
        bool broken_sparse_sup; /* if server or share does not support sparse */
        bool need_reconnect:1; /* connection reset, tid now invalid */
+       bool need_reopen_files:1; /* need to reopen tcon file handles */
        bool use_resilient:1; /* use resilient instead of durable handles */
        bool use_persistent:1; /* use persistent instead of durable handles */
 #ifdef CONFIG_CIFS_SMB2
@@ -932,6 +939,7 @@ struct cifs_tcon {
        __u32 maximal_access;
        __u32 vol_serial_number;
        __le64 vol_create_time;
+       __u64 snapshot_time; /* for timewarp tokens - timestamp of snapshot */
        __u32 ss_flags;         /* sector size flags */
        __u32 perf_sector_size; /* best sector size for perf */
        __u32 max_chunks;
index ced0e42ce460963104d89bb8b941b899ceb33dea..c7b3c841e6604d150e22d2ed40695c2cec3d3d99 100644 (file)
@@ -63,7 +63,8 @@ extern void exit_cifs_spnego(void);
 extern char *build_path_from_dentry(struct dentry *);
 extern char *cifs_build_path_to_root(struct smb_vol *vol,
                                     struct cifs_sb_info *cifs_sb,
-                                    struct cifs_tcon *tcon);
+                                    struct cifs_tcon *tcon,
+                                    int add_treename);
 extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
 extern char *cifs_compose_mount_options(const char *sb_mountdata,
                const char *fullpath, const struct dfs_info3_param *ref,
@@ -206,6 +207,9 @@ extern void cifs_add_pending_open_locked(struct cifs_fid *fid,
                                         struct tcon_link *tlink,
                                         struct cifs_pending_open *open);
 extern void cifs_del_pending_open(struct cifs_pending_open *open);
+extern void cifs_put_tcp_session(struct TCP_Server_Info *server,
+                                int from_reconnect);
+extern void cifs_put_tcon(struct cifs_tcon *tcon);
 
 #if IS_ENABLED(CONFIG_CIFS_DFS_UPCALL)
 extern void cifs_dfs_release_automount_timer(void);
index f7563c88c917d2174f2259b35191992752217247..b822bf364c2bcdbb8e428fc5027dc50415978285 100644 (file)
@@ -53,6 +53,9 @@
 #include "nterr.h"
 #include "rfc1002pdu.h"
 #include "fscache.h"
+#ifdef CONFIG_CIFS_SMB2
+#include "smb2proto.h"
+#endif
 
 #define CIFS_PORT 445
 #define RFC1001_PORT 139
@@ -89,6 +92,7 @@ enum {
        Opt_multiuser, Opt_sloppy, Opt_nosharesock,
        Opt_persistent, Opt_nopersistent,
        Opt_resilient, Opt_noresilient,
+       Opt_domainauto,
 
        /* Mount options which take numeric value */
        Opt_backupuid, Opt_backupgid, Opt_uid,
@@ -96,6 +100,7 @@ enum {
        Opt_dirmode, Opt_port,
        Opt_rsize, Opt_wsize, Opt_actimeo,
        Opt_echo_interval, Opt_max_credits,
+       Opt_snapshot,
 
        /* Mount options which take string value */
        Opt_user, Opt_pass, Opt_ip,
@@ -177,6 +182,7 @@ static const match_table_t cifs_mount_option_tokens = {
        { Opt_nopersistent, "nopersistenthandles"},
        { Opt_resilient, "resilienthandles"},
        { Opt_noresilient, "noresilienthandles"},
+       { Opt_domainauto, "domainauto"},
 
        { Opt_backupuid, "backupuid=%s" },
        { Opt_backupgid, "backupgid=%s" },
@@ -192,6 +198,7 @@ static const match_table_t cifs_mount_option_tokens = {
        { Opt_actimeo, "actimeo=%s" },
        { Opt_echo_interval, "echo_interval=%s" },
        { Opt_max_credits, "max_credits=%s" },
+       { Opt_snapshot, "snapshot=%s" },
 
        { Opt_blank_user, "user=" },
        { Opt_blank_user, "username=" },
@@ -1500,6 +1507,9 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                case Opt_noresilient:
                        vol->resilient = false; /* already the default */
                        break;
+               case Opt_domainauto:
+                       vol->domainauto = true;
+                       break;
 
                /* Numeric Values */
                case Opt_backupuid:
@@ -1602,6 +1612,14 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                        }
                        vol->echo_interval = option;
                        break;
+               case Opt_snapshot:
+                       if (get_option_ul(args, &option)) {
+                               cifs_dbg(VFS, "%s: Invalid snapshot time\n",
+                                        __func__);
+                               goto cifs_parse_mount_err;
+                       }
+                       vol->snapshot_time = option;
+                       break;
                case Opt_max_credits:
                        if (get_option_ul(args, &option) || (option < 20) ||
                            (option > 60000)) {
@@ -2101,8 +2119,8 @@ cifs_find_tcp_session(struct smb_vol *vol)
        return NULL;
 }
 
-static void
-cifs_put_tcp_session(struct TCP_Server_Info *server)
+void
+cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
 {
        struct task_struct *task;
 
@@ -2119,6 +2137,19 @@ cifs_put_tcp_session(struct TCP_Server_Info *server)
 
        cancel_delayed_work_sync(&server->echo);
 
+#ifdef CONFIG_CIFS_SMB2
+       if (from_reconnect)
+               /*
+                * Avoid deadlock here: reconnect work calls
+                * cifs_put_tcp_session() at its end. Need to be sure
+                * that reconnect work does nothing with server pointer after
+                * that step.
+                */
+               cancel_delayed_work(&server->reconnect);
+       else
+               cancel_delayed_work_sync(&server->reconnect);
+#endif
+
        spin_lock(&GlobalMid_Lock);
        server->tcpStatus = CifsExiting;
        spin_unlock(&GlobalMid_Lock);
@@ -2183,6 +2214,10 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
        INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
        INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
        INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request);
+#ifdef CONFIG_CIFS_SMB2
+       INIT_DELAYED_WORK(&tcp_ses->reconnect, smb2_reconnect_server);
+       mutex_init(&tcp_ses->reconnect_mutex);
+#endif
        memcpy(&tcp_ses->srcaddr, &volume_info->srcaddr,
               sizeof(tcp_ses->srcaddr));
        memcpy(&tcp_ses->dstaddr, &volume_info->dstaddr,
@@ -2341,7 +2376,7 @@ cifs_put_smb_ses(struct cifs_ses *ses)
        spin_unlock(&cifs_tcp_ses_lock);
 
        sesInfoFree(ses);
-       cifs_put_tcp_session(server);
+       cifs_put_tcp_session(server, 0);
 }
 
 #ifdef CONFIG_KEYS
@@ -2515,7 +2550,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
                mutex_unlock(&ses->session_mutex);
 
                /* existing SMB ses has a server reference already */
-               cifs_put_tcp_session(server);
+               cifs_put_tcp_session(server, 0);
                free_xid(xid);
                return ses;
        }
@@ -2549,6 +2584,8 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
                if (!ses->domainName)
                        goto get_ses_fail;
        }
+       if (volume_info->domainauto)
+               ses->domainAuto = volume_info->domainauto;
        ses->cred_uid = volume_info->cred_uid;
        ses->linux_uid = volume_info->linux_uid;
 
@@ -2587,7 +2624,7 @@ static int match_tcon(struct cifs_tcon *tcon, const char *unc)
 }
 
 static struct cifs_tcon *
-cifs_find_tcon(struct cifs_ses *ses, const char *unc)
+cifs_find_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
 {
        struct list_head *tmp;
        struct cifs_tcon *tcon;
@@ -2595,8 +2632,14 @@ cifs_find_tcon(struct cifs_ses *ses, const char *unc)
        spin_lock(&cifs_tcp_ses_lock);
        list_for_each(tmp, &ses->tcon_list) {
                tcon = list_entry(tmp, struct cifs_tcon, tcon_list);
-               if (!match_tcon(tcon, unc))
+               if (!match_tcon(tcon, volume_info->UNC))
                        continue;
+
+#ifdef CONFIG_CIFS_SMB2
+               if (tcon->snapshot_time != volume_info->snapshot_time)
+                       continue;
+#endif /* CONFIG_CIFS_SMB2 */
+
                ++tcon->tc_count;
                spin_unlock(&cifs_tcp_ses_lock);
                return tcon;
@@ -2605,7 +2648,7 @@ cifs_find_tcon(struct cifs_ses *ses, const char *unc)
        return NULL;
 }
 
-static void
+void
 cifs_put_tcon(struct cifs_tcon *tcon)
 {
        unsigned int xid;
@@ -2637,7 +2680,7 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
        int rc, xid;
        struct cifs_tcon *tcon;
 
-       tcon = cifs_find_tcon(ses, volume_info->UNC);
+       tcon = cifs_find_tcon(ses, volume_info);
        if (tcon) {
                cifs_dbg(FYI, "Found match on UNC path\n");
                /* existing tcon already has a reference */
@@ -2658,6 +2701,22 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
                goto out_fail;
        }
 
+       if (volume_info->snapshot_time) {
+#ifdef CONFIG_CIFS_SMB2
+               if (ses->server->vals->protocol_id == 0) {
+                       cifs_dbg(VFS,
+                            "Use SMB2 or later for snapshot mount option\n");
+                       rc = -EOPNOTSUPP;
+                       goto out_fail;
+               } else
+                       tcon->snapshot_time = volume_info->snapshot_time;
+#else
+               cifs_dbg(VFS, "Snapshot mount option requires SMB2 support\n");
+               rc = -EOPNOTSUPP;
+               goto out_fail;
+#endif /* CONFIG_CIFS_SMB2 */
+       }
+
        tcon->ses = ses;
        if (volume_info->password) {
                tcon->password = kstrdup(volume_info->password, GFP_KERNEL);
@@ -3707,7 +3766,8 @@ remote_path_check:
                /*
                 * cifs_build_path_to_root works only when we have a valid tcon
                 */
-               full_path = cifs_build_path_to_root(volume_info, cifs_sb, tcon);
+               full_path = cifs_build_path_to_root(volume_info, cifs_sb, tcon,
+                                       tcon->Flags & SMB_SHARE_IS_IN_DFS);
                if (full_path == NULL) {
                        rc = -ENOMEM;
                        goto mount_fail_check;
@@ -3793,7 +3853,7 @@ mount_fail_check:
                else if (ses)
                        cifs_put_smb_ses(ses);
                else
-                       cifs_put_tcp_session(server);
+                       cifs_put_tcp_session(server, 0);
                bdi_destroy(&cifs_sb->bdi);
        }
 
@@ -4104,7 +4164,7 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid)
        ses = cifs_get_smb_ses(master_tcon->ses->server, vol_info);
        if (IS_ERR(ses)) {
                tcon = (struct cifs_tcon *)ses;
-               cifs_put_tcp_session(master_tcon->ses->server);
+               cifs_put_tcp_session(master_tcon->ses->server, 0);
                goto out;
        }
 
index 789ff1df2d8d5d1b6b923ee1f60428278a9d0319..2c227a99f369f08e8941652eb87dd685a6f66b61 100644 (file)
@@ -47,7 +47,7 @@ renew_parental_timestamps(struct dentry *direntry)
 
 char *
 cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
-                       struct cifs_tcon *tcon)
+                       struct cifs_tcon *tcon, int add_treename)
 {
        int pplen = vol->prepath ? strlen(vol->prepath) + 1 : 0;
        int dfsplen;
@@ -59,7 +59,7 @@ cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
                return full_path;
        }
 
-       if (tcon->Flags & SMB_SHARE_IS_IN_DFS)
+       if (add_treename)
                dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1);
        else
                dfsplen = 0;
index 7f5f6176c6f15caff307e078320122141c119ab9..18a1e1d6671fc0825b2f265280a96e065e6c6aae 100644 (file)
@@ -777,6 +777,11 @@ cifs_reopen_persistent_handles(struct cifs_tcon *tcon)
        struct list_head *tmp1;
        struct list_head tmp_list;
 
+       if (!tcon->use_persistent || !tcon->need_reopen_files)
+               return;
+
+       tcon->need_reopen_files = false;
+
        cifs_dbg(FYI, "Reopen persistent handles");
        INIT_LIST_HEAD(&tmp_list);
 
@@ -793,7 +798,8 @@ cifs_reopen_persistent_handles(struct cifs_tcon *tcon)
 
        list_for_each_safe(tmp, tmp1, &tmp_list) {
                open_file = list_entry(tmp, struct cifsFileInfo, rlist);
-               cifs_reopen_file(open_file, false /* do not flush */);
+               if (cifs_reopen_file(open_file, false /* do not flush */))
+                       tcon->need_reopen_files = true;
                list_del_init(&open_file->rlist);
                cifsFileInfo_put(open_file);
        }
index 9f51b81119f2b204361f25d86dcfd350a8917700..001528781b6b0f80552c33f3d8e93fb9cfc27b86 100644 (file)
@@ -189,7 +189,7 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
        xid = get_xid();
 
        cifs_sb = CIFS_SB(inode->i_sb);
-       cifs_dbg(VFS, "cifs ioctl 0x%x\n", command);
+       cifs_dbg(FYI, "cifs ioctl 0x%x\n", command);
        switch (command) {
                case FS_IOC_GETFLAGS:
                        if (pSMBFile == NULL)
index d031af8d3d4da8b1d57cdb79236529e416d850e3..c4d996f78e1c9a7d63bef0964d7ad127124d3167 100644 (file)
        (CIFS_MF_SYMLINK_LINK_OFFSET + CIFS_MF_SYMLINK_LINK_MAXLEN)
 
 #define CIFS_MF_SYMLINK_LEN_FORMAT "XSym\n%04u\n"
-#define CIFS_MF_SYMLINK_MD5_FORMAT \
-       "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n"
-#define CIFS_MF_SYMLINK_MD5_ARGS(md5_hash) \
-       md5_hash[0],  md5_hash[1],  md5_hash[2],  md5_hash[3], \
-       md5_hash[4],  md5_hash[5],  md5_hash[6],  md5_hash[7], \
-       md5_hash[8],  md5_hash[9],  md5_hash[10], md5_hash[11],\
-       md5_hash[12], md5_hash[13], md5_hash[14], md5_hash[15]
+#define CIFS_MF_SYMLINK_MD5_FORMAT "%16phN\n"
+#define CIFS_MF_SYMLINK_MD5_ARGS(md5_hash) md5_hash
 
 static int
 symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash)
index f9e766f464beec408b628146c4e0d4e04010e0f2..b2aff0c6f22c528eb628a25247bad85b1d096a3c 100644 (file)
@@ -260,7 +260,7 @@ smb2_push_mandatory_locks(struct cifsFileInfo *cfile)
         * and check it for zero before using.
         */
        max_buf = tlink_tcon(cfile->tlink)->ses->server->maxBuf;
-       if (!max_buf) {
+       if (max_buf < sizeof(struct smb2_lock_element)) {
                free_xid(xid);
                return -EINVAL;
        }
index 5ca5ea4668a1482ef9643cd525ded6ebbaa7e326..87457227812c393fe1ee9e09bacd9f1c65d93f9e 100644 (file)
@@ -250,16 +250,19 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
        }
 
        cifs_mark_open_files_invalid(tcon);
+       if (tcon->use_persistent)
+               tcon->need_reopen_files = true;
 
        rc = SMB2_tcon(0, tcon->ses, tcon->treeName, tcon, nls_codepage);
        mutex_unlock(&tcon->ses->session_mutex);
 
-       if (tcon->use_persistent)
-               cifs_reopen_persistent_handles(tcon);
-
        cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
        if (rc)
                goto out;
+
+       if (smb2_command != SMB2_INTERNAL_CMD)
+               queue_delayed_work(cifsiod_wq, &server->reconnect, 0);
+
        atomic_inc(&tconInfoReconnectCount);
 out:
        /*
@@ -280,7 +283,7 @@ out:
        case SMB2_CHANGE_NOTIFY:
        case SMB2_QUERY_INFO:
        case SMB2_SET_INFO:
-               return -EAGAIN;
+               rc = -EAGAIN;
        }
        unload_nls(nls_codepage);
        return rc;
@@ -1972,6 +1975,55 @@ 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->need_reopen_files) {
+                               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) {
+               if (!smb2_reconnect(SMB2_INTERNAL_CMD, tcon))
+                       cifs_reopen_persistent_handles(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 +2036,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;
index fd3709e8de33eddee8c66cca29cb6653921b020e..dc0d141f33e25730ea0242d2f946034e321cb1a4 100644 (file)
@@ -80,6 +80,8 @@
 #define SMB2_SET_INFO          cpu_to_le16(SMB2_SET_INFO_HE)
 #define SMB2_OPLOCK_BREAK      cpu_to_le16(SMB2_OPLOCK_BREAK_HE)
 
+#define SMB2_INTERNAL_CMD      cpu_to_le16(0xFFFF)
+
 #define NUMBER_OF_SMB2_COMMANDS        0x0013
 
 /* BB FIXME - analyze following length BB */
index eb2cde2f64ba7c818c5ea0db10dd8cb192d94c67..f2d511a6971b88c0019526bcd5b3938383f4f106 100644 (file)
@@ -96,6 +96,7 @@ extern int smb2_open_file(const unsigned int xid,
 extern int smb2_unlock_range(struct cifsFileInfo *cfile,
                             struct file_lock *flock, const unsigned int xid);
 extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile);
+extern void smb2_reconnect_server(struct work_struct *work);
 
 /*
  * SMB2 Worker functions - most of protocol specific implementation details
index 699b7868108f658a3262943c7763b13d59767a89..c12bffefa3c9b59b2290ecdb243ae308b08e7224 100644 (file)
@@ -23,7 +23,7 @@
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-#include <crypto/skcipher.h>
+#include <linux/crypto.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/fs.h>
@@ -69,46 +69,22 @@ str_to_key(unsigned char *str, unsigned char *key)
 static int
 smbhash(unsigned char *out, const unsigned char *in, unsigned char *key)
 {
-       int rc;
        unsigned char key2[8];
-       struct crypto_skcipher *tfm_des;
-       struct scatterlist sgin, sgout;
-       struct skcipher_request *req;
+       struct crypto_cipher *tfm_des;
 
        str_to_key(key, key2);
 
-       tfm_des = crypto_alloc_skcipher("ecb(des)", 0, CRYPTO_ALG_ASYNC);
+       tfm_des = crypto_alloc_cipher("des", 0, 0);
        if (IS_ERR(tfm_des)) {
-               rc = PTR_ERR(tfm_des);
-               cifs_dbg(VFS, "could not allocate des crypto API\n");
-               goto smbhash_err;
-       }
-
-       req = skcipher_request_alloc(tfm_des, GFP_KERNEL);
-       if (!req) {
-               rc = -ENOMEM;
                cifs_dbg(VFS, "could not allocate des crypto API\n");
-               goto smbhash_free_skcipher;
+               return PTR_ERR(tfm_des);
        }
 
-       crypto_skcipher_setkey(tfm_des, key2, 8);
-
-       sg_init_one(&sgin, in, 8);
-       sg_init_one(&sgout, out, 8);
+       crypto_cipher_setkey(tfm_des, key2, 8);
+       crypto_cipher_encrypt_one(tfm_des, out, in);
+       crypto_free_cipher(tfm_des);
 
-       skcipher_request_set_callback(req, 0, NULL, NULL);
-       skcipher_request_set_crypt(req, &sgin, &sgout, 8, NULL);
-
-       rc = crypto_skcipher_encrypt(req);
-       if (rc)
-               cifs_dbg(VFS, "could not encrypt crypt key rc: %d\n", rc);
-
-       skcipher_request_free(req);
-
-smbhash_free_skcipher:
-       crypto_free_skcipher(tfm_des);
-smbhash_err:
-       return rc;
+       return 0;
 }
 
 static int