5353#include "nterr.h"
5454#include "rfc1002pdu.h"
5555#include "fscache.h"
56+ #ifdef CONFIG_CIFS_SMB2
57+ #include "smb2proto.h"
58+ #endif
5659
5760#define CIFS_PORT 445
5861#define RFC1001_PORT 139
@@ -89,13 +92,15 @@ enum {
8992 Opt_multiuser , Opt_sloppy , Opt_nosharesock ,
9093 Opt_persistent , Opt_nopersistent ,
9194 Opt_resilient , Opt_noresilient ,
95+ Opt_domainauto ,
9296
9397 /* Mount options which take numeric value */
9498 Opt_backupuid , Opt_backupgid , Opt_uid ,
9599 Opt_cruid , Opt_gid , Opt_file_mode ,
96100 Opt_dirmode , Opt_port ,
97101 Opt_rsize , Opt_wsize , Opt_actimeo ,
98102 Opt_echo_interval , Opt_max_credits ,
103+ Opt_snapshot ,
99104
100105 /* Mount options which take string value */
101106 Opt_user , Opt_pass , Opt_ip ,
@@ -177,6 +182,7 @@ static const match_table_t cifs_mount_option_tokens = {
177182 { Opt_nopersistent , "nopersistenthandles" },
178183 { Opt_resilient , "resilienthandles" },
179184 { Opt_noresilient , "noresilienthandles" },
185+ { Opt_domainauto , "domainauto" },
180186
181187 { Opt_backupuid , "backupuid=%s" },
182188 { Opt_backupgid , "backupgid=%s" },
@@ -192,6 +198,7 @@ static const match_table_t cifs_mount_option_tokens = {
192198 { Opt_actimeo , "actimeo=%s" },
193199 { Opt_echo_interval , "echo_interval=%s" },
194200 { Opt_max_credits , "max_credits=%s" },
201+ { Opt_snapshot , "snapshot=%s" },
195202
196203 { Opt_blank_user , "user=" },
197204 { Opt_blank_user , "username=" },
@@ -1500,6 +1507,9 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
15001507 case Opt_noresilient :
15011508 vol -> resilient = false; /* already the default */
15021509 break ;
1510+ case Opt_domainauto :
1511+ vol -> domainauto = true;
1512+ break ;
15031513
15041514 /* Numeric Values */
15051515 case Opt_backupuid :
@@ -1602,6 +1612,14 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
16021612 }
16031613 vol -> echo_interval = option ;
16041614 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 ;
16051623 case Opt_max_credits :
16061624 if (get_option_ul (args , & option ) || (option < 20 ) ||
16071625 (option > 60000 )) {
@@ -2101,8 +2119,8 @@ cifs_find_tcp_session(struct smb_vol *vol)
21012119 return NULL ;
21022120}
21032121
2104- static void
2105- cifs_put_tcp_session (struct TCP_Server_Info * server )
2122+ void
2123+ cifs_put_tcp_session (struct TCP_Server_Info * server , int from_reconnect )
21062124{
21072125 struct task_struct * task ;
21082126
@@ -2119,6 +2137,19 @@ cifs_put_tcp_session(struct TCP_Server_Info *server)
21192137
21202138 cancel_delayed_work_sync (& server -> echo );
21212139
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+
21222153 spin_lock (& GlobalMid_Lock );
21232154 server -> tcpStatus = CifsExiting ;
21242155 spin_unlock (& GlobalMid_Lock );
@@ -2183,6 +2214,10 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
21832214 INIT_LIST_HEAD (& tcp_ses -> tcp_ses_list );
21842215 INIT_LIST_HEAD (& tcp_ses -> smb_ses_list );
21852216 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
21862221 memcpy (& tcp_ses -> srcaddr , & volume_info -> srcaddr ,
21872222 sizeof (tcp_ses -> srcaddr ));
21882223 memcpy (& tcp_ses -> dstaddr , & volume_info -> dstaddr ,
@@ -2341,7 +2376,7 @@ cifs_put_smb_ses(struct cifs_ses *ses)
23412376 spin_unlock (& cifs_tcp_ses_lock );
23422377
23432378 sesInfoFree (ses );
2344- cifs_put_tcp_session (server );
2379+ cifs_put_tcp_session (server , 0 );
23452380}
23462381
23472382#ifdef CONFIG_KEYS
@@ -2515,7 +2550,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
25152550 mutex_unlock (& ses -> session_mutex );
25162551
25172552 /* existing SMB ses has a server reference already */
2518- cifs_put_tcp_session (server );
2553+ cifs_put_tcp_session (server , 0 );
25192554 free_xid (xid );
25202555 return ses ;
25212556 }
@@ -2549,6 +2584,8 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
25492584 if (!ses -> domainName )
25502585 goto get_ses_fail ;
25512586 }
2587+ if (volume_info -> domainauto )
2588+ ses -> domainAuto = volume_info -> domainauto ;
25522589 ses -> cred_uid = volume_info -> cred_uid ;
25532590 ses -> linux_uid = volume_info -> linux_uid ;
25542591
@@ -2587,16 +2624,22 @@ static int match_tcon(struct cifs_tcon *tcon, const char *unc)
25872624}
25882625
25892626static struct cifs_tcon *
2590- cifs_find_tcon (struct cifs_ses * ses , const char * unc )
2627+ cifs_find_tcon (struct cifs_ses * ses , struct smb_vol * volume_info )
25912628{
25922629 struct list_head * tmp ;
25932630 struct cifs_tcon * tcon ;
25942631
25952632 spin_lock (& cifs_tcp_ses_lock );
25962633 list_for_each (tmp , & ses -> tcon_list ) {
25972634 tcon = list_entry (tmp , struct cifs_tcon , tcon_list );
2598- if (!match_tcon (tcon , unc ))
2635+ if (!match_tcon (tcon , volume_info -> UNC ))
25992636 continue ;
2637+
2638+ #ifdef CONFIG_CIFS_SMB2
2639+ if (tcon -> snapshot_time != volume_info -> snapshot_time )
2640+ continue ;
2641+ #endif /* CONFIG_CIFS_SMB2 */
2642+
26002643 ++ tcon -> tc_count ;
26012644 spin_unlock (& cifs_tcp_ses_lock );
26022645 return tcon ;
@@ -2605,7 +2648,7 @@ cifs_find_tcon(struct cifs_ses *ses, const char *unc)
26052648 return NULL ;
26062649}
26072650
2608- static void
2651+ void
26092652cifs_put_tcon (struct cifs_tcon * tcon )
26102653{
26112654 unsigned int xid ;
@@ -2637,7 +2680,7 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
26372680 int rc , xid ;
26382681 struct cifs_tcon * tcon ;
26392682
2640- tcon = cifs_find_tcon (ses , volume_info -> UNC );
2683+ tcon = cifs_find_tcon (ses , volume_info );
26412684 if (tcon ) {
26422685 cifs_dbg (FYI , "Found match on UNC path\n" );
26432686 /* existing tcon already has a reference */
@@ -2658,6 +2701,22 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
26582701 goto out_fail ;
26592702 }
26602703
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+
26612720 tcon -> ses = ses ;
26622721 if (volume_info -> password ) {
26632722 tcon -> password = kstrdup (volume_info -> password , GFP_KERNEL );
@@ -3707,7 +3766,8 @@ cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info)
37073766 /*
37083767 * cifs_build_path_to_root works only when we have a valid tcon
37093768 */
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 );
37113771 if (full_path == NULL ) {
37123772 rc = - ENOMEM ;
37133773 goto mount_fail_check ;
@@ -3793,7 +3853,7 @@ cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info)
37933853 else if (ses )
37943854 cifs_put_smb_ses (ses );
37953855 else
3796- cifs_put_tcp_session (server );
3856+ cifs_put_tcp_session (server , 0 );
37973857 bdi_destroy (& cifs_sb -> bdi );
37983858 }
37993859
@@ -4104,7 +4164,7 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid)
41044164 ses = cifs_get_smb_ses (master_tcon -> ses -> server , vol_info );
41054165 if (IS_ERR (ses )) {
41064166 tcon = (struct cifs_tcon * )ses ;
4107- cifs_put_tcp_session (master_tcon -> ses -> server );
4167+ cifs_put_tcp_session (master_tcon -> ses -> server , 0 );
41084168 goto out ;
41094169 }
41104170
0 commit comments