diff options
Diffstat (limited to 'fs/smb/client/connect.c')
| -rw-r--r-- | fs/smb/client/connect.c | 93 | 
1 files changed, 53 insertions, 40 deletions
| diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index 28bc33496623..5eec8957f2a9 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -97,7 +97,7 @@ static int reconn_set_ipaddr_from_hostname(struct TCP_Server_Info *server)  	return rc;  } -static void smb2_query_server_interfaces(struct work_struct *work) +void smb2_query_server_interfaces(struct work_struct *work)  {  	int rc;  	int xid; @@ -124,6 +124,14 @@ static void smb2_query_server_interfaces(struct work_struct *work)  			   (SMB_INTERFACE_POLL_INTERVAL * HZ));  } +#define set_need_reco(server) \ +do { \ +	spin_lock(&server->srv_lock); \ +	if (server->tcpStatus != CifsExiting) \ +		server->tcpStatus = CifsNeedReconnect; \ +	spin_unlock(&server->srv_lock); \ +} while (0) +  /*   * Update the tcpStatus for the server.   * This is used to signal the cifsd thread to call cifs_reconnect @@ -137,39 +145,45 @@ void  cifs_signal_cifsd_for_reconnect(struct TCP_Server_Info *server,  				bool all_channels)  { -	struct TCP_Server_Info *pserver; +	struct TCP_Server_Info *nserver;  	struct cifs_ses *ses; +	LIST_HEAD(reco);  	int i; -	/* If server is a channel, select the primary channel */ -	pserver = SERVER_IS_CHAN(server) ? server->primary_server : server; -  	/* if we need to signal just this channel */  	if (!all_channels) { -		spin_lock(&server->srv_lock); -		if (server->tcpStatus != CifsExiting) -			server->tcpStatus = CifsNeedReconnect; -		spin_unlock(&server->srv_lock); +		set_need_reco(server);  		return;  	} -	spin_lock(&cifs_tcp_ses_lock); -	list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) { -		if (cifs_ses_exiting(ses)) -			continue; -		spin_lock(&ses->chan_lock); -		for (i = 0; i < ses->chan_count; i++) { -			if (!ses->chans[i].server) +	if (SERVER_IS_CHAN(server)) +		server = server->primary_server; +	scoped_guard(spinlock, &cifs_tcp_ses_lock) { +		set_need_reco(server); +		list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { +			spin_lock(&ses->ses_lock); +			if (ses->ses_status == SES_EXITING) { +				spin_unlock(&ses->ses_lock);  				continue; - -			spin_lock(&ses->chans[i].server->srv_lock); -			if (ses->chans[i].server->tcpStatus != CifsExiting) -				ses->chans[i].server->tcpStatus = CifsNeedReconnect; -			spin_unlock(&ses->chans[i].server->srv_lock); +			} +			spin_lock(&ses->chan_lock); +			for (i = 1; i < ses->chan_count; i++) { +				nserver = ses->chans[i].server; +				if (!nserver) +					continue; +				nserver->srv_count++; +				list_add(&nserver->rlist, &reco); +			} +			spin_unlock(&ses->chan_lock); +			spin_unlock(&ses->ses_lock);  		} -		spin_unlock(&ses->chan_lock);  	} -	spin_unlock(&cifs_tcp_ses_lock); + +	list_for_each_entry_safe(server, nserver, &reco, rlist) { +		list_del_init(&server->rlist); +		set_need_reco(server); +		cifs_put_tcp_session(server, 0); +	}  }  /* @@ -665,12 +679,12 @@ server_unresponsive(struct TCP_Server_Info *server)  	/*  	 * If we're in the process of mounting a share or reconnecting a session  	 * and the server abruptly shut down (e.g. socket wasn't closed, packet -	 * had been ACK'ed but no SMB response), don't wait longer than 20s to -	 * negotiate protocol. +	 * had been ACK'ed but no SMB response), don't wait longer than 20s from +	 * when negotiate actually started.  	 */  	spin_lock(&server->srv_lock);  	if (server->tcpStatus == CifsInNegotiate && -	    time_after(jiffies, server->lstrp + 20 * HZ)) { +	    time_after(jiffies, server->neg_start + 20 * HZ)) {  		spin_unlock(&server->srv_lock);  		cifs_reconnect(server, false);  		return true; @@ -2866,20 +2880,14 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx)  	tcon->max_cached_dirs = ctx->max_cached_dirs;  	tcon->nodelete = ctx->nodelete;  	tcon->local_lease = ctx->local_lease; -	INIT_LIST_HEAD(&tcon->pending_opens);  	tcon->status = TID_GOOD; -	INIT_DELAYED_WORK(&tcon->query_interfaces, -			  smb2_query_server_interfaces);  	if (ses->server->dialect >= SMB30_PROT_ID &&  	    (ses->server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL)) {  		/* schedule query interfaces poll */  		queue_delayed_work(cifsiod_wq, &tcon->query_interfaces,  				   (SMB_INTERFACE_POLL_INTERVAL * HZ));  	} -#ifdef CONFIG_CIFS_DFS_UPCALL -	INIT_DELAYED_WORK(&tcon->dfs_cache_work, dfs_cache_refresh); -#endif  	spin_lock(&cifs_tcp_ses_lock);  	list_add(&tcon->tcon_list, &ses->tcon_list);  	spin_unlock(&cifs_tcp_ses_lock); @@ -3354,18 +3362,15 @@ generic_ip_connect(struct TCP_Server_Info *server)  		struct net *net = cifs_net_ns(server);  		struct sock *sk; -		rc = __sock_create(net, sfamily, SOCK_STREAM, -				   IPPROTO_TCP, &server->ssocket, 1); +		rc = sock_create_kern(net, sfamily, SOCK_STREAM, +				      IPPROTO_TCP, &server->ssocket);  		if (rc < 0) {  			cifs_server_dbg(VFS, "Error %d creating socket\n", rc);  			return rc;  		}  		sk = server->ssocket->sk; -		__netns_tracker_free(net, &sk->ns_tracker, false); -		sk->sk_net_refcnt = 1; -		get_net_track(net, &sk->ns_tracker, GFP_KERNEL); -		sock_inuse_add(net, 1); +		sk_net_refcnt_upgrade(sk);  		/* BB other socket options to set KEEPALIVE, NODELAY? */  		cifs_dbg(FYI, "Socket created\n"); @@ -3718,9 +3723,15 @@ int cifs_mount_get_tcon(struct cifs_mount_ctx *mnt_ctx)  		goto out;  	} -	/* if new SMB3.11 POSIX extensions are supported do not remap / and \ */ -	if (tcon->posix_extensions) +	/* +	 * if new SMB3.11 POSIX extensions are supported, do not change anything in the +	 * path (i.e., do not remap / and \ and do not map any special characters) +	 */ +	if (tcon->posix_extensions) {  		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS; +		cifs_sb->mnt_cifs_flags &= ~(CIFS_MOUNT_MAP_SFM_CHR | +					     CIFS_MOUNT_MAP_SPECIAL_CHR); +	}  #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY  	/* tell server which Unix caps we support */ @@ -4193,7 +4204,9 @@ retry:  		return 0;  	} +	server->lstrp = jiffies;  	server->tcpStatus = CifsInNegotiate; +	server->neg_start = jiffies;  	spin_unlock(&server->srv_lock);  	rc = server->ops->negotiate(xid, ses, server); | 
