aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-12-24 14:37:18 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2016-12-24 14:37:18 -0500
commit1dd5c6b15372c7c127c509afa9a816bad5feed3b (patch)
tree163e4e43d4e8f8fdfb70cc14379e01b5b09b40af
parent3a77fa854477a12fc543a69d00ff8a42adefc586 (diff)
parent374402a2a1dfbbee8ab1a5a32ec4887bf8c15d52 (diff)
Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6
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
-rw-r--r--fs/cifs/cifsencrypt.c14
-rw-r--r--fs/cifs/cifsfs.c2
-rw-r--r--fs/cifs/cifsglob.h8
-rw-r--r--fs/cifs/cifsproto.h6
-rw-r--r--fs/cifs/connect.c82
-rw-r--r--fs/cifs/dir.c4
-rw-r--r--fs/cifs/file.c8
-rw-r--r--fs/cifs/ioctl.c2
-rw-r--r--fs/cifs/link.c9
-rw-r--r--fs/cifs/smb2file.c2
-rw-r--r--fs/cifs/smb2pdu.c87
-rw-r--r--fs/cifs/smb2pdu.h2
-rw-r--r--fs/cifs/smb2proto.h1
-rw-r--r--fs/cifs/smbencrypt.c40
14 files changed, 177 insertions, 90 deletions
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index 5eb04129f938..66bd7fa9b7a6 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -699,11 +699,15 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
699 699
700 if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED) { 700 if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED) {
701 if (!ses->domainName) { 701 if (!ses->domainName) {
702 rc = find_domain_name(ses, nls_cp); 702 if (ses->domainAuto) {
703 if (rc) { 703 rc = find_domain_name(ses, nls_cp);
704 cifs_dbg(VFS, "error %d finding domain name\n", 704 if (rc) {
705 rc); 705 cifs_dbg(VFS, "error %d finding domain name\n",
706 goto setup_ntlmv2_rsp_ret; 706 rc);
707 goto setup_ntlmv2_rsp_ret;
708 }
709 } else {
710 ses->domainName = kstrdup("", GFP_KERNEL);
707 } 711 }
708 } 712 }
709 } else { 713 } else {
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index e6efb9a88598..70f4e65fced2 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -615,7 +615,7 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb)
615 return dget(sb->s_root); 615 return dget(sb->s_root);
616 616
617 full_path = cifs_build_path_to_root(vol, cifs_sb, 617 full_path = cifs_build_path_to_root(vol, cifs_sb,
618 cifs_sb_master_tcon(cifs_sb)); 618 cifs_sb_master_tcon(cifs_sb), 0);
619 if (full_path == NULL) 619 if (full_path == NULL)
620 return ERR_PTR(-ENOMEM); 620 return ERR_PTR(-ENOMEM);
621 621
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 1f17f6bd7a60..7ea8a3393936 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -514,6 +514,7 @@ struct smb_vol {
514 bool persistent:1; 514 bool persistent:1;
515 bool nopersistent:1; 515 bool nopersistent:1;
516 bool resilient:1; /* noresilient not required since not fored for CA */ 516 bool resilient:1; /* noresilient not required since not fored for CA */
517 bool domainauto:1;
517 unsigned int rsize; 518 unsigned int rsize;
518 unsigned int wsize; 519 unsigned int wsize;
519 bool sockopt_tcp_nodelay:1; 520 bool sockopt_tcp_nodelay:1;
@@ -525,6 +526,7 @@ struct smb_vol {
525 struct sockaddr_storage srcaddr; /* allow binding to a local IP */ 526 struct sockaddr_storage srcaddr; /* allow binding to a local IP */
526 struct nls_table *local_nls; 527 struct nls_table *local_nls;
527 unsigned int echo_interval; /* echo interval in secs */ 528 unsigned int echo_interval; /* echo interval in secs */
529 __u64 snapshot_time; /* needed for timewarp tokens */
528 unsigned int max_credits; /* smb3 max_credits 10 < credits < 60000 */ 530 unsigned int max_credits; /* smb3 max_credits 10 < credits < 60000 */
529}; 531};
530 532
@@ -646,6 +648,8 @@ struct TCP_Server_Info {
646 unsigned int max_read; 648 unsigned int max_read;
647 unsigned int max_write; 649 unsigned int max_write;
648 __u8 preauth_hash[512]; 650 __u8 preauth_hash[512];
651 struct delayed_work reconnect; /* reconnect workqueue job */
652 struct mutex reconnect_mutex; /* prevent simultaneous reconnects */
649#endif /* CONFIG_CIFS_SMB2 */ 653#endif /* CONFIG_CIFS_SMB2 */
650 unsigned long echo_interval; 654 unsigned long echo_interval;
651}; 655};
@@ -827,6 +831,7 @@ struct cifs_ses {
827 enum securityEnum sectype; /* what security flavor was specified? */ 831 enum securityEnum sectype; /* what security flavor was specified? */
828 bool sign; /* is signing required? */ 832 bool sign; /* is signing required? */
829 bool need_reconnect:1; /* connection reset, uid now invalid */ 833 bool need_reconnect:1; /* connection reset, uid now invalid */
834 bool domainAuto:1;
830#ifdef CONFIG_CIFS_SMB2 835#ifdef CONFIG_CIFS_SMB2
831 __u16 session_flags; 836 __u16 session_flags;
832 __u8 smb3signingkey[SMB3_SIGN_KEY_SIZE]; 837 __u8 smb3signingkey[SMB3_SIGN_KEY_SIZE];
@@ -849,6 +854,7 @@ cap_unix(struct cifs_ses *ses)
849struct cifs_tcon { 854struct cifs_tcon {
850 struct list_head tcon_list; 855 struct list_head tcon_list;
851 int tc_count; 856 int tc_count;
857 struct list_head rlist; /* reconnect list */
852 struct list_head openFileList; 858 struct list_head openFileList;
853 spinlock_t open_file_lock; /* protects list above */ 859 spinlock_t open_file_lock; /* protects list above */
854 struct cifs_ses *ses; /* pointer to session associated with */ 860 struct cifs_ses *ses; /* pointer to session associated with */
@@ -922,6 +928,7 @@ struct cifs_tcon {
922 bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */ 928 bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */
923 bool broken_sparse_sup; /* if server or share does not support sparse */ 929 bool broken_sparse_sup; /* if server or share does not support sparse */
924 bool need_reconnect:1; /* connection reset, tid now invalid */ 930 bool need_reconnect:1; /* connection reset, tid now invalid */
931 bool need_reopen_files:1; /* need to reopen tcon file handles */
925 bool use_resilient:1; /* use resilient instead of durable handles */ 932 bool use_resilient:1; /* use resilient instead of durable handles */
926 bool use_persistent:1; /* use persistent instead of durable handles */ 933 bool use_persistent:1; /* use persistent instead of durable handles */
927#ifdef CONFIG_CIFS_SMB2 934#ifdef CONFIG_CIFS_SMB2
@@ -932,6 +939,7 @@ struct cifs_tcon {
932 __u32 maximal_access; 939 __u32 maximal_access;
933 __u32 vol_serial_number; 940 __u32 vol_serial_number;
934 __le64 vol_create_time; 941 __le64 vol_create_time;
942 __u64 snapshot_time; /* for timewarp tokens - timestamp of snapshot */
935 __u32 ss_flags; /* sector size flags */ 943 __u32 ss_flags; /* sector size flags */
936 __u32 perf_sector_size; /* best sector size for perf */ 944 __u32 perf_sector_size; /* best sector size for perf */
937 __u32 max_chunks; 945 __u32 max_chunks;
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index ced0e42ce460..c7b3c841e660 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -63,7 +63,8 @@ extern void exit_cifs_spnego(void);
63extern char *build_path_from_dentry(struct dentry *); 63extern char *build_path_from_dentry(struct dentry *);
64extern char *cifs_build_path_to_root(struct smb_vol *vol, 64extern char *cifs_build_path_to_root(struct smb_vol *vol,
65 struct cifs_sb_info *cifs_sb, 65 struct cifs_sb_info *cifs_sb,
66 struct cifs_tcon *tcon); 66 struct cifs_tcon *tcon,
67 int add_treename);
67extern char *build_wildcard_path_from_dentry(struct dentry *direntry); 68extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
68extern char *cifs_compose_mount_options(const char *sb_mountdata, 69extern char *cifs_compose_mount_options(const char *sb_mountdata,
69 const char *fullpath, const struct dfs_info3_param *ref, 70 const char *fullpath, const struct dfs_info3_param *ref,
@@ -206,6 +207,9 @@ extern void cifs_add_pending_open_locked(struct cifs_fid *fid,
206 struct tcon_link *tlink, 207 struct tcon_link *tlink,
207 struct cifs_pending_open *open); 208 struct cifs_pending_open *open);
208extern void cifs_del_pending_open(struct cifs_pending_open *open); 209extern void cifs_del_pending_open(struct cifs_pending_open *open);
210extern void cifs_put_tcp_session(struct TCP_Server_Info *server,
211 int from_reconnect);
212extern void cifs_put_tcon(struct cifs_tcon *tcon);
209 213
210#if IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) 214#if IS_ENABLED(CONFIG_CIFS_DFS_UPCALL)
211extern void cifs_dfs_release_automount_timer(void); 215extern void cifs_dfs_release_automount_timer(void);
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index f7563c88c917..b822bf364c2b 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -53,6 +53,9 @@
53#include "nterr.h" 53#include "nterr.h"
54#include "rfc1002pdu.h" 54#include "rfc1002pdu.h"
55#include "fscache.h" 55#include "fscache.h"
56#ifdef CONFIG_CIFS_SMB2
57#include "smb2proto.h"
58#endif
56 59
57#define CIFS_PORT 445 60#define CIFS_PORT 445
58#define RFC1001_PORT 139 61#define RFC1001_PORT 139
@@ -89,6 +92,7 @@ enum {
89 Opt_multiuser, Opt_sloppy, Opt_nosharesock, 92 Opt_multiuser, Opt_sloppy, Opt_nosharesock,
90 Opt_persistent, Opt_nopersistent, 93 Opt_persistent, Opt_nopersistent,
91 Opt_resilient, Opt_noresilient, 94 Opt_resilient, Opt_noresilient,
95 Opt_domainauto,
92 96
93 /* Mount options which take numeric value */ 97 /* Mount options which take numeric value */
94 Opt_backupuid, Opt_backupgid, Opt_uid, 98 Opt_backupuid, Opt_backupgid, Opt_uid,
@@ -96,6 +100,7 @@ enum {
96 Opt_dirmode, Opt_port, 100 Opt_dirmode, Opt_port,
97 Opt_rsize, Opt_wsize, Opt_actimeo, 101 Opt_rsize, Opt_wsize, Opt_actimeo,
98 Opt_echo_interval, Opt_max_credits, 102 Opt_echo_interval, Opt_max_credits,
103 Opt_snapshot,
99 104
100 /* Mount options which take string value */ 105 /* Mount options which take string value */
101 Opt_user, Opt_pass, Opt_ip, 106 Opt_user, Opt_pass, Opt_ip,
@@ -177,6 +182,7 @@ static const match_table_t cifs_mount_option_tokens = {
177 { Opt_nopersistent, "nopersistenthandles"}, 182 { Opt_nopersistent, "nopersistenthandles"},
178 { Opt_resilient, "resilienthandles"}, 183 { Opt_resilient, "resilienthandles"},
179 { Opt_noresilient, "noresilienthandles"}, 184 { Opt_noresilient, "noresilienthandles"},
185 { Opt_domainauto, "domainauto"},
180 186
181 { Opt_backupuid, "backupuid=%s" }, 187 { Opt_backupuid, "backupuid=%s" },
182 { Opt_backupgid, "backupgid=%s" }, 188 { Opt_backupgid, "backupgid=%s" },
@@ -192,6 +198,7 @@ static const match_table_t cifs_mount_option_tokens = {
192 { Opt_actimeo, "actimeo=%s" }, 198 { Opt_actimeo, "actimeo=%s" },
193 { Opt_echo_interval, "echo_interval=%s" }, 199 { Opt_echo_interval, "echo_interval=%s" },
194 { Opt_max_credits, "max_credits=%s" }, 200 { Opt_max_credits, "max_credits=%s" },
201 { Opt_snapshot, "snapshot=%s" },
195 202
196 { Opt_blank_user, "user=" }, 203 { Opt_blank_user, "user=" },
197 { Opt_blank_user, "username=" }, 204 { Opt_blank_user, "username=" },
@@ -1500,6 +1507,9 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
1500 case Opt_noresilient: 1507 case Opt_noresilient:
1501 vol->resilient = false; /* already the default */ 1508 vol->resilient = false; /* already the default */
1502 break; 1509 break;
1510 case Opt_domainauto:
1511 vol->domainauto = true;
1512 break;
1503 1513
1504 /* Numeric Values */ 1514 /* Numeric Values */
1505 case Opt_backupuid: 1515 case Opt_backupuid:
@@ -1602,6 +1612,14 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
1602 } 1612 }
1603 vol->echo_interval = option; 1613 vol->echo_interval = option;
1604 break; 1614 break;
1615 case Opt_snapshot:
1616 if (get_option_ul(args, &option)) {
1617 cifs_dbg(VFS, "%s: Invalid snapshot time\n",
1618 __func__);
1619 goto cifs_parse_mount_err;
1620 }
1621 vol->snapshot_time = option;
1622 break;
1605 case Opt_max_credits: 1623 case Opt_max_credits:
1606 if (get_option_ul(args, &option) || (option < 20) || 1624 if (get_option_ul(args, &option) || (option < 20) ||
1607 (option > 60000)) { 1625 (option > 60000)) {
@@ -2101,8 +2119,8 @@ cifs_find_tcp_session(struct smb_vol *vol)
2101 return NULL; 2119 return NULL;
2102} 2120}
2103 2121
2104static void 2122void
2105cifs_put_tcp_session(struct TCP_Server_Info *server) 2123cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
2106{ 2124{
2107 struct task_struct *task; 2125 struct task_struct *task;
2108 2126
@@ -2119,6 +2137,19 @@ cifs_put_tcp_session(struct TCP_Server_Info *server)
2119 2137
2120 cancel_delayed_work_sync(&server->echo); 2138 cancel_delayed_work_sync(&server->echo);
2121 2139
2140#ifdef CONFIG_CIFS_SMB2
2141 if (from_reconnect)
2142 /*
2143 * Avoid deadlock here: reconnect work calls
2144 * cifs_put_tcp_session() at its end. Need to be sure
2145 * that reconnect work does nothing with server pointer after
2146 * that step.
2147 */
2148 cancel_delayed_work(&server->reconnect);
2149 else
2150 cancel_delayed_work_sync(&server->reconnect);
2151#endif
2152
2122 spin_lock(&GlobalMid_Lock); 2153 spin_lock(&GlobalMid_Lock);
2123 server->tcpStatus = CifsExiting; 2154 server->tcpStatus = CifsExiting;
2124 spin_unlock(&GlobalMid_Lock); 2155 spin_unlock(&GlobalMid_Lock);
@@ -2183,6 +2214,10 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
2183 INIT_LIST_HEAD(&tcp_ses->tcp_ses_list); 2214 INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
2184 INIT_LIST_HEAD(&tcp_ses->smb_ses_list); 2215 INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
2185 INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request); 2216 INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request);
2217#ifdef CONFIG_CIFS_SMB2
2218 INIT_DELAYED_WORK(&tcp_ses->reconnect, smb2_reconnect_server);
2219 mutex_init(&tcp_ses->reconnect_mutex);
2220#endif
2186 memcpy(&tcp_ses->srcaddr, &volume_info->srcaddr, 2221 memcpy(&tcp_ses->srcaddr, &volume_info->srcaddr,
2187 sizeof(tcp_ses->srcaddr)); 2222 sizeof(tcp_ses->srcaddr));
2188 memcpy(&tcp_ses->dstaddr, &volume_info->dstaddr, 2223 memcpy(&tcp_ses->dstaddr, &volume_info->dstaddr,
@@ -2341,7 +2376,7 @@ cifs_put_smb_ses(struct cifs_ses *ses)
2341 spin_unlock(&cifs_tcp_ses_lock); 2376 spin_unlock(&cifs_tcp_ses_lock);
2342 2377
2343 sesInfoFree(ses); 2378 sesInfoFree(ses);
2344 cifs_put_tcp_session(server); 2379 cifs_put_tcp_session(server, 0);
2345} 2380}
2346 2381
2347#ifdef CONFIG_KEYS 2382#ifdef CONFIG_KEYS
@@ -2515,7 +2550,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
2515 mutex_unlock(&ses->session_mutex); 2550 mutex_unlock(&ses->session_mutex);
2516 2551
2517 /* existing SMB ses has a server reference already */ 2552 /* existing SMB ses has a server reference already */
2518 cifs_put_tcp_session(server); 2553 cifs_put_tcp_session(server, 0);
2519 free_xid(xid); 2554 free_xid(xid);
2520 return ses; 2555 return ses;
2521 } 2556 }
@@ -2549,6 +2584,8 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
2549 if (!ses->domainName) 2584 if (!ses->domainName)
2550 goto get_ses_fail; 2585 goto get_ses_fail;
2551 } 2586 }
2587 if (volume_info->domainauto)
2588 ses->domainAuto = volume_info->domainauto;
2552 ses->cred_uid = volume_info->cred_uid; 2589 ses->cred_uid = volume_info->cred_uid;
2553 ses->linux_uid = volume_info->linux_uid; 2590 ses->linux_uid = volume_info->linux_uid;
2554 2591
@@ -2587,7 +2624,7 @@ static int match_tcon(struct cifs_tcon *tcon, const char *unc)
2587} 2624}
2588 2625
2589static struct cifs_tcon * 2626static struct cifs_tcon *
2590cifs_find_tcon(struct cifs_ses *ses, const char *unc) 2627cifs_find_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
2591{ 2628{
2592 struct list_head *tmp; 2629 struct list_head *tmp;
2593 struct cifs_tcon *tcon; 2630 struct cifs_tcon *tcon;
@@ -2595,8 +2632,14 @@ cifs_find_tcon(struct cifs_ses *ses, const char *unc)
2595 spin_lock(&cifs_tcp_ses_lock); 2632 spin_lock(&cifs_tcp_ses_lock);
2596 list_for_each(tmp, &ses->tcon_list) { 2633 list_for_each(tmp, &ses->tcon_list) {
2597 tcon = list_entry(tmp, struct cifs_tcon, tcon_list); 2634 tcon = list_entry(tmp, struct cifs_tcon, tcon_list);
2598 if (!match_tcon(tcon, unc)) 2635 if (!match_tcon(tcon, volume_info->UNC))
2599 continue; 2636 continue;
2637
2638#ifdef CONFIG_CIFS_SMB2
2639 if (tcon->snapshot_time != volume_info->snapshot_time)
2640 continue;
2641#endif /* CONFIG_CIFS_SMB2 */
2642
2600 ++tcon->tc_count; 2643 ++tcon->tc_count;
2601 spin_unlock(&cifs_tcp_ses_lock); 2644 spin_unlock(&cifs_tcp_ses_lock);
2602 return tcon; 2645 return tcon;
@@ -2605,7 +2648,7 @@ cifs_find_tcon(struct cifs_ses *ses, const char *unc)
2605 return NULL; 2648 return NULL;
2606} 2649}
2607 2650
2608static void 2651void
2609cifs_put_tcon(struct cifs_tcon *tcon) 2652cifs_put_tcon(struct cifs_tcon *tcon)
2610{ 2653{
2611 unsigned int xid; 2654 unsigned int xid;
@@ -2637,7 +2680,7 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
2637 int rc, xid; 2680 int rc, xid;
2638 struct cifs_tcon *tcon; 2681 struct cifs_tcon *tcon;
2639 2682
2640 tcon = cifs_find_tcon(ses, volume_info->UNC); 2683 tcon = cifs_find_tcon(ses, volume_info);
2641 if (tcon) { 2684 if (tcon) {
2642 cifs_dbg(FYI, "Found match on UNC path\n"); 2685 cifs_dbg(FYI, "Found match on UNC path\n");
2643 /* existing tcon already has a reference */ 2686 /* existing tcon already has a reference */
@@ -2658,6 +2701,22 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
2658 goto out_fail; 2701 goto out_fail;
2659 } 2702 }
2660 2703
2704 if (volume_info->snapshot_time) {
2705#ifdef CONFIG_CIFS_SMB2
2706 if (ses->server->vals->protocol_id == 0) {
2707 cifs_dbg(VFS,
2708 "Use SMB2 or later for snapshot mount option\n");
2709 rc = -EOPNOTSUPP;
2710 goto out_fail;
2711 } else
2712 tcon->snapshot_time = volume_info->snapshot_time;
2713#else
2714 cifs_dbg(VFS, "Snapshot mount option requires SMB2 support\n");
2715 rc = -EOPNOTSUPP;
2716 goto out_fail;
2717#endif /* CONFIG_CIFS_SMB2 */
2718 }
2719
2661 tcon->ses = ses; 2720 tcon->ses = ses;
2662 if (volume_info->password) { 2721 if (volume_info->password) {
2663 tcon->password = kstrdup(volume_info->password, GFP_KERNEL); 2722 tcon->password = kstrdup(volume_info->password, GFP_KERNEL);
@@ -3707,7 +3766,8 @@ remote_path_check:
3707 /* 3766 /*
3708 * cifs_build_path_to_root works only when we have a valid tcon 3767 * cifs_build_path_to_root works only when we have a valid tcon
3709 */ 3768 */
3710 full_path = cifs_build_path_to_root(volume_info, cifs_sb, tcon); 3769 full_path = cifs_build_path_to_root(volume_info, cifs_sb, tcon,
3770 tcon->Flags & SMB_SHARE_IS_IN_DFS);
3711 if (full_path == NULL) { 3771 if (full_path == NULL) {
3712 rc = -ENOMEM; 3772 rc = -ENOMEM;
3713 goto mount_fail_check; 3773 goto mount_fail_check;
@@ -3793,7 +3853,7 @@ mount_fail_check:
3793 else if (ses) 3853 else if (ses)
3794 cifs_put_smb_ses(ses); 3854 cifs_put_smb_ses(ses);
3795 else 3855 else
3796 cifs_put_tcp_session(server); 3856 cifs_put_tcp_session(server, 0);
3797 bdi_destroy(&cifs_sb->bdi); 3857 bdi_destroy(&cifs_sb->bdi);
3798 } 3858 }
3799 3859
@@ -4104,7 +4164,7 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid)
4104 ses = cifs_get_smb_ses(master_tcon->ses->server, vol_info); 4164 ses = cifs_get_smb_ses(master_tcon->ses->server, vol_info);
4105 if (IS_ERR(ses)) { 4165 if (IS_ERR(ses)) {
4106 tcon = (struct cifs_tcon *)ses; 4166 tcon = (struct cifs_tcon *)ses;
4107 cifs_put_tcp_session(master_tcon->ses->server); 4167 cifs_put_tcp_session(master_tcon->ses->server, 0);
4108 goto out; 4168 goto out;
4109 } 4169 }
4110 4170
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 789ff1df2d8d..2c227a99f369 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -47,7 +47,7 @@ renew_parental_timestamps(struct dentry *direntry)
47 47
48char * 48char *
49cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb, 49cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
50 struct cifs_tcon *tcon) 50 struct cifs_tcon *tcon, int add_treename)
51{ 51{
52 int pplen = vol->prepath ? strlen(vol->prepath) + 1 : 0; 52 int pplen = vol->prepath ? strlen(vol->prepath) + 1 : 0;
53 int dfsplen; 53 int dfsplen;
@@ -59,7 +59,7 @@ cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
59 return full_path; 59 return full_path;
60 } 60 }
61 61
62 if (tcon->Flags & SMB_SHARE_IS_IN_DFS) 62 if (add_treename)
63 dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1); 63 dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1);
64 else 64 else
65 dfsplen = 0; 65 dfsplen = 0;
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 7f5f6176c6f1..18a1e1d6671f 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -777,6 +777,11 @@ cifs_reopen_persistent_handles(struct cifs_tcon *tcon)
777 struct list_head *tmp1; 777 struct list_head *tmp1;
778 struct list_head tmp_list; 778 struct list_head tmp_list;
779 779
780 if (!tcon->use_persistent || !tcon->need_reopen_files)
781 return;
782
783 tcon->need_reopen_files = false;
784
780 cifs_dbg(FYI, "Reopen persistent handles"); 785 cifs_dbg(FYI, "Reopen persistent handles");
781 INIT_LIST_HEAD(&tmp_list); 786 INIT_LIST_HEAD(&tmp_list);
782 787
@@ -793,7 +798,8 @@ cifs_reopen_persistent_handles(struct cifs_tcon *tcon)
793 798
794 list_for_each_safe(tmp, tmp1, &tmp_list) { 799 list_for_each_safe(tmp, tmp1, &tmp_list) {
795 open_file = list_entry(tmp, struct cifsFileInfo, rlist); 800 open_file = list_entry(tmp, struct cifsFileInfo, rlist);
796 cifs_reopen_file(open_file, false /* do not flush */); 801 if (cifs_reopen_file(open_file, false /* do not flush */))
802 tcon->need_reopen_files = true;
797 list_del_init(&open_file->rlist); 803 list_del_init(&open_file->rlist);
798 cifsFileInfo_put(open_file); 804 cifsFileInfo_put(open_file);
799 } 805 }
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c
index 9f51b81119f2..001528781b6b 100644
--- a/fs/cifs/ioctl.c
+++ b/fs/cifs/ioctl.c
@@ -189,7 +189,7 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
189 xid = get_xid(); 189 xid = get_xid();
190 190
191 cifs_sb = CIFS_SB(inode->i_sb); 191 cifs_sb = CIFS_SB(inode->i_sb);
192 cifs_dbg(VFS, "cifs ioctl 0x%x\n", command); 192 cifs_dbg(FYI, "cifs ioctl 0x%x\n", command);
193 switch (command) { 193 switch (command) {
194 case FS_IOC_GETFLAGS: 194 case FS_IOC_GETFLAGS:
195 if (pSMBFile == NULL) 195 if (pSMBFile == NULL)
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index d031af8d3d4d..c4d996f78e1c 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -45,13 +45,8 @@
45 (CIFS_MF_SYMLINK_LINK_OFFSET + CIFS_MF_SYMLINK_LINK_MAXLEN) 45 (CIFS_MF_SYMLINK_LINK_OFFSET + CIFS_MF_SYMLINK_LINK_MAXLEN)
46 46
47#define CIFS_MF_SYMLINK_LEN_FORMAT "XSym\n%04u\n" 47#define CIFS_MF_SYMLINK_LEN_FORMAT "XSym\n%04u\n"
48#define CIFS_MF_SYMLINK_MD5_FORMAT \ 48#define CIFS_MF_SYMLINK_MD5_FORMAT "%16phN\n"
49 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n" 49#define CIFS_MF_SYMLINK_MD5_ARGS(md5_hash) md5_hash
50#define CIFS_MF_SYMLINK_MD5_ARGS(md5_hash) \
51 md5_hash[0], md5_hash[1], md5_hash[2], md5_hash[3], \
52 md5_hash[4], md5_hash[5], md5_hash[6], md5_hash[7], \
53 md5_hash[8], md5_hash[9], md5_hash[10], md5_hash[11],\
54 md5_hash[12], md5_hash[13], md5_hash[14], md5_hash[15]
55 50
56static int 51static int
57symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash) 52symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash)
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c
index f9e766f464be..b2aff0c6f22c 100644
--- a/fs/cifs/smb2file.c
+++ b/fs/cifs/smb2file.c
@@ -260,7 +260,7 @@ smb2_push_mandatory_locks(struct cifsFileInfo *cfile)
260 * and check it for zero before using. 260 * and check it for zero before using.
261 */ 261 */
262 max_buf = tlink_tcon(cfile->tlink)->ses->server->maxBuf; 262 max_buf = tlink_tcon(cfile->tlink)->ses->server->maxBuf;
263 if (!max_buf) { 263 if (max_buf < sizeof(struct smb2_lock_element)) {
264 free_xid(xid); 264 free_xid(xid);
265 return -EINVAL; 265 return -EINVAL;
266 } 266 }
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 5ca5ea4668a1..87457227812c 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -250,16 +250,19 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
250 } 250 }
251 251
252 cifs_mark_open_files_invalid(tcon); 252 cifs_mark_open_files_invalid(tcon);
253 if (tcon->use_persistent)
254 tcon->need_reopen_files = true;
253 255
254 rc = SMB2_tcon(0, tcon->ses, tcon->treeName, tcon, nls_codepage); 256 rc = SMB2_tcon(0, tcon->ses, tcon->treeName, tcon, nls_codepage);
255 mutex_unlock(&tcon->ses->session_mutex); 257 mutex_unlock(&tcon->ses->session_mutex);
256 258
257 if (tcon->use_persistent)
258 cifs_reopen_persistent_handles(tcon);
259
260 cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc); 259 cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
261 if (rc) 260 if (rc)
262 goto out; 261 goto out;
262
263 if (smb2_command != SMB2_INTERNAL_CMD)
264 queue_delayed_work(cifsiod_wq, &server->reconnect, 0);
265
263 atomic_inc(&tconInfoReconnectCount); 266 atomic_inc(&tconInfoReconnectCount);
264out: 267out:
265 /* 268 /*
@@ -280,7 +283,7 @@ out:
280 case SMB2_CHANGE_NOTIFY: 283 case SMB2_CHANGE_NOTIFY:
281 case SMB2_QUERY_INFO: 284 case SMB2_QUERY_INFO:
282 case SMB2_SET_INFO: 285 case SMB2_SET_INFO:
283 return -EAGAIN; 286 rc = -EAGAIN;
284 } 287 }
285 unload_nls(nls_codepage); 288 unload_nls(nls_codepage);
286 return rc; 289 return rc;
@@ -1972,6 +1975,55 @@ smb2_echo_callback(struct mid_q_entry *mid)
1972 add_credits(server, credits_received, CIFS_ECHO_OP); 1975 add_credits(server, credits_received, CIFS_ECHO_OP);
1973} 1976}
1974 1977
1978void smb2_reconnect_server(struct work_struct *work)
1979{
1980 struct TCP_Server_Info *server = container_of(work,
1981 struct TCP_Server_Info, reconnect.work);
1982 struct cifs_ses *ses;
1983 struct cifs_tcon *tcon, *tcon2;
1984 struct list_head tmp_list;
1985 int tcon_exist = false;
1986
1987 /* Prevent simultaneous reconnects that can corrupt tcon->rlist list */
1988 mutex_lock(&server->reconnect_mutex);
1989
1990 INIT_LIST_HEAD(&tmp_list);
1991 cifs_dbg(FYI, "Need negotiate, reconnecting tcons\n");
1992
1993 spin_lock(&cifs_tcp_ses_lock);
1994 list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
1995 list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
1996 if (tcon->need_reconnect || tcon->need_reopen_files) {
1997 tcon->tc_count++;
1998 list_add_tail(&tcon->rlist, &tmp_list);
1999 tcon_exist = true;
2000 }
2001 }
2002 }
2003 /*
2004 * Get the reference to server struct to be sure that the last call of
2005 * cifs_put_tcon() in the loop below won't release the server pointer.
2006 */
2007 if (tcon_exist)
2008 server->srv_count++;
2009
2010 spin_unlock(&cifs_tcp_ses_lock);
2011
2012 list_for_each_entry_safe(tcon, tcon2, &tmp_list, rlist) {
2013 if (!smb2_reconnect(SMB2_INTERNAL_CMD, tcon))
2014 cifs_reopen_persistent_handles(tcon);
2015 list_del_init(&tcon->rlist);
2016 cifs_put_tcon(tcon);
2017 }
2018
2019 cifs_dbg(FYI, "Reconnecting tcons finished\n");
2020 mutex_unlock(&server->reconnect_mutex);
2021
2022 /* now we can safely release srv struct */
2023 if (tcon_exist)
2024 cifs_put_tcp_session(server, 1);
2025}
2026
1975int 2027int
1976SMB2_echo(struct TCP_Server_Info *server) 2028SMB2_echo(struct TCP_Server_Info *server)
1977{ 2029{
@@ -1984,32 +2036,11 @@ SMB2_echo(struct TCP_Server_Info *server)
1984 cifs_dbg(FYI, "In echo request\n"); 2036 cifs_dbg(FYI, "In echo request\n");
1985 2037
1986 if (server->tcpStatus == CifsNeedNegotiate) { 2038 if (server->tcpStatus == CifsNeedNegotiate) {
1987 struct list_head *tmp, *tmp2; 2039 /* No need to send echo on newly established connections */
1988 struct cifs_ses *ses; 2040 queue_delayed_work(cifsiod_wq, &server->reconnect, 0);
1989 struct cifs_tcon *tcon; 2041 return rc;
1990
1991 cifs_dbg(FYI, "Need negotiate, reconnecting tcons\n");
1992 spin_lock(&cifs_tcp_ses_lock);
1993 list_for_each(tmp, &server->smb_ses_list) {
1994 ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
1995 list_for_each(tmp2, &ses->tcon_list) {
1996 tcon = list_entry(tmp2, struct cifs_tcon,
1997 tcon_list);
1998 /* add check for persistent handle reconnect */
1999 if (tcon && tcon->need_reconnect) {
2000 spin_unlock(&cifs_tcp_ses_lock);
2001 rc = smb2_reconnect(SMB2_ECHO, tcon);
2002 spin_lock(&cifs_tcp_ses_lock);
2003 }
2004 }
2005 }
2006 spin_unlock(&cifs_tcp_ses_lock);
2007 } 2042 }
2008 2043
2009 /* if no session, renegotiate failed above */
2010 if (server->tcpStatus == CifsNeedNegotiate)
2011 return -EIO;
2012
2013 rc = small_smb2_init(SMB2_ECHO, NULL, (void **)&req); 2044 rc = small_smb2_init(SMB2_ECHO, NULL, (void **)&req);
2014 if (rc) 2045 if (rc)
2015 return rc; 2046 return rc;
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index fd3709e8de33..dc0d141f33e2 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -80,6 +80,8 @@
80#define SMB2_SET_INFO cpu_to_le16(SMB2_SET_INFO_HE) 80#define SMB2_SET_INFO cpu_to_le16(SMB2_SET_INFO_HE)
81#define SMB2_OPLOCK_BREAK cpu_to_le16(SMB2_OPLOCK_BREAK_HE) 81#define SMB2_OPLOCK_BREAK cpu_to_le16(SMB2_OPLOCK_BREAK_HE)
82 82
83#define SMB2_INTERNAL_CMD cpu_to_le16(0xFFFF)
84
83#define NUMBER_OF_SMB2_COMMANDS 0x0013 85#define NUMBER_OF_SMB2_COMMANDS 0x0013
84 86
85/* BB FIXME - analyze following length BB */ 87/* BB FIXME - analyze following length BB */
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index eb2cde2f64ba..f2d511a6971b 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -96,6 +96,7 @@ extern int smb2_open_file(const unsigned int xid,
96extern int smb2_unlock_range(struct cifsFileInfo *cfile, 96extern int smb2_unlock_range(struct cifsFileInfo *cfile,
97 struct file_lock *flock, const unsigned int xid); 97 struct file_lock *flock, const unsigned int xid);
98extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile); 98extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile);
99extern void smb2_reconnect_server(struct work_struct *work);
99 100
100/* 101/*
101 * SMB2 Worker functions - most of protocol specific implementation details 102 * SMB2 Worker functions - most of protocol specific implementation details
diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c
index 699b7868108f..c12bffefa3c9 100644
--- a/fs/cifs/smbencrypt.c
+++ b/fs/cifs/smbencrypt.c
@@ -23,7 +23,7 @@
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24*/ 24*/
25 25
26#include <crypto/skcipher.h> 26#include <linux/crypto.h>
27#include <linux/module.h> 27#include <linux/module.h>
28#include <linux/slab.h> 28#include <linux/slab.h>
29#include <linux/fs.h> 29#include <linux/fs.h>
@@ -69,46 +69,22 @@ str_to_key(unsigned char *str, unsigned char *key)
69static int 69static int
70smbhash(unsigned char *out, const unsigned char *in, unsigned char *key) 70smbhash(unsigned char *out, const unsigned char *in, unsigned char *key)
71{ 71{
72 int rc;
73 unsigned char key2[8]; 72 unsigned char key2[8];
74 struct crypto_skcipher *tfm_des; 73 struct crypto_cipher *tfm_des;
75 struct scatterlist sgin, sgout;
76 struct skcipher_request *req;
77 74
78 str_to_key(key, key2); 75 str_to_key(key, key2);
79 76
80 tfm_des = crypto_alloc_skcipher("ecb(des)", 0, CRYPTO_ALG_ASYNC); 77 tfm_des = crypto_alloc_cipher("des", 0, 0);
81 if (IS_ERR(tfm_des)) { 78 if (IS_ERR(tfm_des)) {
82 rc = PTR_ERR(tfm_des);
83 cifs_dbg(VFS, "could not allocate des crypto API\n");
84 goto smbhash_err;
85 }
86
87 req = skcipher_request_alloc(tfm_des, GFP_KERNEL);
88 if (!req) {
89 rc = -ENOMEM;
90 cifs_dbg(VFS, "could not allocate des crypto API\n"); 79 cifs_dbg(VFS, "could not allocate des crypto API\n");
91 goto smbhash_free_skcipher; 80 return PTR_ERR(tfm_des);
92 } 81 }
93 82
94 crypto_skcipher_setkey(tfm_des, key2, 8); 83 crypto_cipher_setkey(tfm_des, key2, 8);
95 84 crypto_cipher_encrypt_one(tfm_des, out, in);
96 sg_init_one(&sgin, in, 8); 85 crypto_free_cipher(tfm_des);
97 sg_init_one(&sgout, out, 8);
98 86
99 skcipher_request_set_callback(req, 0, NULL, NULL); 87 return 0;
100 skcipher_request_set_crypt(req, &sgin, &sgout, 8, NULL);
101
102 rc = crypto_skcipher_encrypt(req);
103 if (rc)
104 cifs_dbg(VFS, "could not encrypt crypt key rc: %d\n", rc);
105
106 skcipher_request_free(req);
107
108smbhash_free_skcipher:
109 crypto_free_skcipher(tfm_des);
110smbhash_err:
111 return rc;
112} 88}
113 89
114static int 90static int