@@ -996,10 +996,8 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server)
996996		 */ 
997997	}
998998
999- #ifdef  CONFIG_CIFS_DFS_UPCALL 
1000999	kfree (server -> origin_fullpath );
10011000	kfree (server -> leaf_fullpath );
1002- #endif 
10031001	kfree (server );
10041002
10051003	length  =  atomic_dec_return (& tcpSesAllocCount );
@@ -1387,23 +1385,8 @@ match_security(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
13871385	return  true;
13881386}
13891387
1390- static  bool  dfs_src_pathname_equal (const  char  * s1 , const  char  * s2 )
1391- {
1392- 	if  (strlen (s1 ) !=  strlen (s2 ))
1393- 		return  false;
1394- 	for  (; * s1 ; s1 ++ , s2 ++ ) {
1395- 		if  (* s1  ==  '/'  ||  * s1  ==  '\\' ) {
1396- 			if  (* s2  !=  '/'  &&  * s2  !=  '\\' )
1397- 				return  false;
1398- 		} else  if  (tolower (* s1 ) !=  tolower (* s2 ))
1399- 			return  false;
1400- 	}
1401- 	return  true;
1402- }
1403- 
14041388/* this function must be called with srv_lock held */ 
1405- static  int  match_server (struct  TCP_Server_Info  * server , struct  smb3_fs_context  * ctx ,
1406- 			bool  dfs_super_cmp )
1389+ static  int  match_server (struct  TCP_Server_Info  * server , struct  smb3_fs_context  * ctx )
14071390{
14081391	struct  sockaddr  * addr  =  (struct  sockaddr  * )& ctx -> dstaddr ;
14091392
@@ -1434,27 +1417,41 @@ static int match_server(struct TCP_Server_Info *server, struct smb3_fs_context *
14341417			       (struct  sockaddr  * )& server -> srcaddr ))
14351418		return  0 ;
14361419	/* 
1437- 	 * When matching DFS superblocks, we only check for original source pathname as the 
1438- 	 * currently connected target might be different than the one parsed earlier in i.e. 
1439- 	 * mount.cifs(8). 
1420+ 	 * - Match for an DFS tcon (@server->origin_fullpath). 
1421+ 	 * - Match for an DFS root server connection (@server->leaf_fullpath). 
1422+ 	 * - If none of the above and @ctx->leaf_fullpath is set, then 
1423+ 	 *   it is a new DFS connection. 
1424+ 	 * - If 'nodfs' mount option was passed, then match only connections 
1425+ 	 *   that have no DFS referrals set 
1426+ 	 *   (e.g. can't failover to other targets). 
14401427	 */ 
1441- 	if  (dfs_super_cmp ) {
1442- 		if  (!ctx -> source  ||  !server -> origin_fullpath  || 
1443- 		    !dfs_src_pathname_equal (server -> origin_fullpath , ctx -> source ))
1444- 			return  0 ;
1445- 	} else  {
1446- 		/* Skip addr, hostname and port matching for DFS connections */ 
1447- 		if  (server -> leaf_fullpath ) {
1428+ 	if  (!ctx -> nodfs ) {
1429+ 		if  (ctx -> source  &&  server -> origin_fullpath ) {
1430+ 			if  (!dfs_src_pathname_equal (ctx -> source ,
1431+ 						    server -> origin_fullpath ))
1432+ 				return  0 ;
1433+ 		} else  if  (server -> leaf_fullpath ) {
14481434			if  (!ctx -> leaf_fullpath  || 
1449- 			    strcasecmp (server -> leaf_fullpath , ctx -> leaf_fullpath ))
1435+ 			    strcasecmp (server -> leaf_fullpath ,
1436+ 				       ctx -> leaf_fullpath ))
14501437				return  0 ;
1451- 		} else  if  (strcasecmp (server -> hostname , ctx -> server_hostname ) || 
1452- 			   !match_server_address (server , addr ) || 
1453- 			   !match_port (server , addr )) {
1438+ 		} else  if  (ctx -> leaf_fullpath ) {
14541439			return  0 ;
14551440		}
1441+ 	} else  if  (server -> origin_fullpath  ||  server -> leaf_fullpath ) {
1442+ 		return  0 ;
14561443	}
14571444
1445+ 	/* 
1446+ 	 * Match for a regular connection (address/hostname/port) which has no 
1447+ 	 * DFS referrals set. 
1448+ 	 */ 
1449+ 	if  (!server -> origin_fullpath  &&  !server -> leaf_fullpath  && 
1450+ 	    (strcasecmp (server -> hostname , ctx -> server_hostname ) || 
1451+ 	     !match_server_address (server , addr ) || 
1452+ 	     !match_port (server , addr )))
1453+ 		return  0 ;
1454+ 
14581455	if  (!match_security (server , ctx ))
14591456		return  0 ;
14601457
@@ -1485,7 +1482,7 @@ cifs_find_tcp_session(struct smb3_fs_context *ctx)
14851482		 * Skip ses channels since they're only handled in lower layers 
14861483		 * (e.g. cifs_send_recv). 
14871484		 */ 
1488- 		if  (CIFS_SERVER_IS_CHAN (server ) ||  !match_server (server , ctx , false )) {
1485+ 		if  (CIFS_SERVER_IS_CHAN (server ) ||  !match_server (server , ctx )) {
14891486			spin_unlock (& server -> srv_lock );
14901487			continue ;
14911488		}
@@ -1869,7 +1866,7 @@ cifs_free_ipc(struct cifs_ses *ses)
18691866static  struct  cifs_ses  * 
18701867cifs_find_smb_ses (struct  TCP_Server_Info  * server , struct  smb3_fs_context  * ctx )
18711868{
1872- 	struct  cifs_ses  * ses ;
1869+ 	struct  cifs_ses  * ses ,  * ret   =   NULL ;
18731870
18741871	spin_lock (& cifs_tcp_ses_lock );
18751872	list_for_each_entry (ses , & server -> smb_ses_list , smb_ses_list ) {
@@ -1879,23 +1876,22 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
18791876			continue ;
18801877		}
18811878		spin_lock (& ses -> chan_lock );
1882- 		if  (! match_session (ses , ctx )) {
1879+ 		if  (match_session (ses , ctx )) {
18831880			spin_unlock (& ses -> chan_lock );
18841881			spin_unlock (& ses -> ses_lock );
1885- 			continue ;
1882+ 			ret  =  ses ;
1883+ 			break ;
18861884		}
18871885		spin_unlock (& ses -> chan_lock );
18881886		spin_unlock (& ses -> ses_lock );
1889- 
1890- 		++ ses -> ses_count ;
1891- 		spin_unlock (& cifs_tcp_ses_lock );
1892- 		return  ses ;
18931887	}
1888+ 	if  (ret )
1889+ 		cifs_smb_ses_inc_refcount (ret );
18941890	spin_unlock (& cifs_tcp_ses_lock );
1895- 	return  NULL ;
1891+ 	return  ret ;
18961892}
18971893
1898- void  cifs_put_smb_ses (struct  cifs_ses  * ses )
1894+ void  __cifs_put_smb_ses (struct  cifs_ses  * ses )
18991895{
19001896	unsigned int   rc , xid ;
19011897	unsigned int   chan_count ;
@@ -2250,6 +2246,8 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
22502246	 */ 
22512247	spin_lock (& cifs_tcp_ses_lock );
22522248	ses -> dfs_root_ses  =  ctx -> dfs_root_ses ;
2249+ 	if  (ses -> dfs_root_ses )
2250+ 		ses -> dfs_root_ses -> ses_count ++ ;
22532251	list_add (& ses -> smb_ses_list , & server -> smb_ses_list );
22542252	spin_unlock (& cifs_tcp_ses_lock );
22552253
@@ -2266,12 +2264,15 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
22662264}
22672265
22682266/* this function must be called with tc_lock held */ 
2269- static  int  match_tcon (struct  cifs_tcon  * tcon , struct  smb3_fs_context  * ctx ,  bool   dfs_super_cmp )
2267+ static  int  match_tcon (struct  cifs_tcon  * tcon , struct  smb3_fs_context  * ctx )
22702268{
2269+ 	struct  TCP_Server_Info  * server  =  tcon -> ses -> server ;
2270+ 
22712271	if  (tcon -> status  ==  TID_EXITING )
22722272		return  0 ;
2273- 	/* Skip UNC validation when matching DFS superblocks */ 
2274- 	if  (!dfs_super_cmp  &&  strncmp (tcon -> tree_name , ctx -> UNC , MAX_TREE_SIZE ))
2273+ 	/* Skip UNC validation when matching DFS connections or superblocks */ 
2274+ 	if  (!server -> origin_fullpath  &&  !server -> leaf_fullpath  && 
2275+ 	    strncmp (tcon -> tree_name , ctx -> UNC , MAX_TREE_SIZE ))
22752276		return  0 ;
22762277	if  (tcon -> seal  !=  ctx -> seal )
22772278		return  0 ;
@@ -2294,7 +2295,7 @@ cifs_find_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx)
22942295	spin_lock (& cifs_tcp_ses_lock );
22952296	list_for_each_entry (tcon , & ses -> tcon_list , tcon_list ) {
22962297		spin_lock (& tcon -> tc_lock );
2297- 		if  (!match_tcon (tcon , ctx , false )) {
2298+ 		if  (!match_tcon (tcon , ctx )) {
22982299			spin_unlock (& tcon -> tc_lock );
22992300			continue ;
23002301		}
@@ -2670,16 +2671,22 @@ compare_mount_options(struct super_block *sb, struct cifs_mnt_data *mnt_data)
26702671	return  1 ;
26712672}
26722673
2673- static  int 
2674- match_prepath (struct  super_block  * sb , struct  cifs_mnt_data  * mnt_data )
2674+ static  int  match_prepath (struct  super_block  * sb ,
2675+ 			 struct  TCP_Server_Info  * server ,
2676+ 			 struct  cifs_mnt_data  * mnt_data )
26752677{
2678+ 	struct  smb3_fs_context  * ctx  =  mnt_data -> ctx ;
26762679	struct  cifs_sb_info  * old  =  CIFS_SB (sb );
26772680	struct  cifs_sb_info  * new  =  mnt_data -> cifs_sb ;
26782681	bool  old_set  =  (old -> mnt_cifs_flags  &  CIFS_MOUNT_USE_PREFIX_PATH ) && 
26792682		old -> prepath ;
26802683	bool  new_set  =  (new -> mnt_cifs_flags  &  CIFS_MOUNT_USE_PREFIX_PATH ) && 
26812684		new -> prepath ;
26822685
2686+ 	if  (server -> origin_fullpath  && 
2687+ 	    dfs_src_pathname_equal (server -> origin_fullpath , ctx -> source ))
2688+ 		return  1 ;
2689+ 
26832690	if  (old_set  &&  new_set  &&  !strcmp (new -> prepath , old -> prepath ))
26842691		return  1 ;
26852692	else  if  (!old_set  &&  !new_set )
@@ -2698,7 +2705,6 @@ cifs_match_super(struct super_block *sb, void *data)
26982705	struct  cifs_ses  * ses ;
26992706	struct  cifs_tcon  * tcon ;
27002707	struct  tcon_link  * tlink ;
2701- 	bool  dfs_super_cmp ;
27022708	int  rc  =  0 ;
27032709
27042710	spin_lock (& cifs_tcp_ses_lock );
@@ -2713,18 +2719,16 @@ cifs_match_super(struct super_block *sb, void *data)
27132719	ses  =  tcon -> ses ;
27142720	tcp_srv  =  ses -> server ;
27152721
2716- 	dfs_super_cmp  =  IS_ENABLED (CONFIG_CIFS_DFS_UPCALL ) &&  tcp_srv -> origin_fullpath ;
2717- 
27182722	ctx  =  mnt_data -> ctx ;
27192723
27202724	spin_lock (& tcp_srv -> srv_lock );
27212725	spin_lock (& ses -> ses_lock );
27222726	spin_lock (& ses -> chan_lock );
27232727	spin_lock (& tcon -> tc_lock );
2724- 	if  (!match_server (tcp_srv , ctx ,  dfs_super_cmp ) || 
2728+ 	if  (!match_server (tcp_srv , ctx ) || 
27252729	    !match_session (ses , ctx ) || 
2726- 	    !match_tcon (tcon , ctx ,  dfs_super_cmp ) || 
2727- 	    !match_prepath (sb , mnt_data )) {
2730+ 	    !match_tcon (tcon , ctx ) || 
2731+ 	    !match_prepath (sb , tcp_srv ,  mnt_data )) {
27282732		rc  =  0 ;
27292733		goto out ;
27302734	}
@@ -3469,8 +3473,6 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
34693473
34703474error :
34713475	dfs_put_root_smb_sessions (& mnt_ctx .dfs_ses_list );
3472- 	kfree (mnt_ctx .origin_fullpath );
3473- 	kfree (mnt_ctx .leaf_fullpath );
34743476	cifs_mount_put_conns (& mnt_ctx );
34753477	return  rc ;
34763478}
0 commit comments