[PATCH] cifs: stop trying to use virtual circuits

Jeff Layton jlayton at redhat.com
Mon Sep 16 19:49:04 CEST 2013


On Mon, 16 Sep 2013 11:23:45 -0400
Jeff Layton <jlayton at redhat.com> wrote:

> Currently, we try to ensure that we use vcnum of 0 on the first
> established session on a connection and then try to use a different
> vcnum on each session after that.
> 
> This is a little odd, since there's no real reason to use a different
> vcnum for each SMB session. I can only assume there was some confusion
> between SMB sessions and VCs. That's somewhat understandable since they
> both get created during SESSION_SETUP, but the documentation indicates
> that they are really orthogonal. The comment on max_vcs in particular
> looks quite misguided. An SMB session is already uniquely identified
> by the SMB UID value -- there's no need to again uniquely ID with a
> VC.
> 
> Furthermore, a vcnum of 0 is a cue to the server that it should release
> any resources that were previously held by the client. This sounds like
> a good thing, until you consider that:
> 
> a) it totally ignores the fact that other programs on the box (e.g.
> smbclient) might have connections established to the server. Using a
> vcnum of 0 causes them to get kicked off.
> 
> b) it causes problems with NAT. If several clients are connected to the
> same server via the same NAT'ed address, whenever one connects to the
> server it kicks off all the others, which then reconnect and kick off
> the first one...ad nauseum.
> 
> I don't see any reason to ignore the advice in "Implementing CIFS" which
> has a comprehensive treatment of virtual circuits. In there, it states
> "...and contrary to the specs the client should always use a VcNumber of
> one, never zero."
> 
> Have the client just use a hardcoded vcnum of 1, and stop abusing the
> special behavior of vcnum 0.
> 


Forgot to mention too that I believe this patch will fix:

    https://bugzilla.samba.org/show_bug.cgi?id=10113


> Reported-by: Sauron99 at gmx.de <sauron99 at gmx.de>
> Signed-off-by: Jeff Layton <jlayton at redhat.com>
> ---
>  fs/cifs/cifsglob.h |  4 ---
>  fs/cifs/cifssmb.c  |  1 -
>  fs/cifs/sess.c     | 84 +-----------------------------------------------------
>  3 files changed, 1 insertion(+), 88 deletions(-)
> 
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index cfa14c8..9c72be6 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -547,9 +547,6 @@ struct TCP_Server_Info {
>  	unsigned int max_rw;	/* maxRw specifies the maximum */
>  	/* message size the server can send or receive for */
>  	/* SMB_COM_WRITE_RAW or SMB_COM_READ_RAW. */
> -	unsigned int max_vcs;	/* maximum number of smb sessions, at least
> -				   those that can be specified uniquely with
> -				   vcnumbers */
>  	unsigned int capabilities; /* selective disabling of caps by smb sess */
>  	int timeAdj;  /* Adjust for difference in server time zone in sec */
>  	__u64 CurrentMid;         /* multiplex id - rotating counter */
> @@ -715,7 +712,6 @@ struct cifs_ses {
>  	enum statusEnum status;
>  	unsigned overrideSecFlg;  /* if non-zero override global sec flags */
>  	__u16 ipc_tid;		/* special tid for connection to IPC share */
> -	__u16 vcnum;
>  	char *serverOS;		/* name of operating system underlying server */
>  	char *serverNOS;	/* name of network operating system of server */
>  	char *serverDomain;	/* security realm of server */
> diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
> index a3d74fe..4baf359 100644
> --- a/fs/cifs/cifssmb.c
> +++ b/fs/cifs/cifssmb.c
> @@ -463,7 +463,6 @@ decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
>  			       cifs_max_pending);
>  	set_credits(server, server->maxReq);
>  	server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
> -	server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
>  	/* even though we do not use raw we might as well set this
>  	accurately, in case we ever find a need for it */
>  	if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
> diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
> index 5f99b7f..352358d 100644
> --- a/fs/cifs/sess.c
> +++ b/fs/cifs/sess.c
> @@ -32,88 +32,6 @@
>  #include <linux/slab.h>
>  #include "cifs_spnego.h"
>  
> -/*
> - * Checks if this is the first smb session to be reconnected after
> - * the socket has been reestablished (so we know whether to use vc 0).
> - * Called while holding the cifs_tcp_ses_lock, so do not block
> - */
> -static bool is_first_ses_reconnect(struct cifs_ses *ses)
> -{
> -	struct list_head *tmp;
> -	struct cifs_ses *tmp_ses;
> -
> -	list_for_each(tmp, &ses->server->smb_ses_list) {
> -		tmp_ses = list_entry(tmp, struct cifs_ses,
> -				     smb_ses_list);
> -		if (tmp_ses->need_reconnect == false)
> -			return false;
> -	}
> -	/* could not find a session that was already connected,
> -	   this must be the first one we are reconnecting */
> -	return true;
> -}
> -
> -/*
> - *	vc number 0 is treated specially by some servers, and should be the
> - *      first one we request.  After that we can use vcnumbers up to maxvcs,
> - *	one for each smb session (some Windows versions set maxvcs incorrectly
> - *	so maxvc=1 can be ignored).  If we have too many vcs, we can reuse
> - *	any vc but zero (some servers reset the connection on vcnum zero)
> - *
> - */
> -static __le16 get_next_vcnum(struct cifs_ses *ses)
> -{
> -	__u16 vcnum = 0;
> -	struct list_head *tmp;
> -	struct cifs_ses *tmp_ses;
> -	__u16 max_vcs = ses->server->max_vcs;
> -	__u16 i;
> -	int free_vc_found = 0;
> -
> -	/* Quoting the MS-SMB specification: "Windows-based SMB servers set this
> -	field to one but do not enforce this limit, which allows an SMB client
> -	to establish more virtual circuits than allowed by this value ... but
> -	other server implementations can enforce this limit." */
> -	if (max_vcs < 2)
> -		max_vcs = 0xFFFF;
> -
> -	spin_lock(&cifs_tcp_ses_lock);
> -	if ((ses->need_reconnect) && is_first_ses_reconnect(ses))
> -			goto get_vc_num_exit;  /* vcnum will be zero */
> -	for (i = ses->server->srv_count - 1; i < max_vcs; i++) {
> -		if (i == 0) /* this is the only connection, use vc 0 */
> -			break;
> -
> -		free_vc_found = 1;
> -
> -		list_for_each(tmp, &ses->server->smb_ses_list) {
> -			tmp_ses = list_entry(tmp, struct cifs_ses,
> -					     smb_ses_list);
> -			if (tmp_ses->vcnum == i) {
> -				free_vc_found = 0;
> -				break; /* found duplicate, try next vcnum */
> -			}
> -		}
> -		if (free_vc_found)
> -			break; /* we found a vcnumber that will work - use it */
> -	}
> -
> -	if (i == 0)
> -		vcnum = 0; /* for most common case, ie if one smb session, use
> -			      vc zero.  Also for case when no free vcnum, zero
> -			      is safest to send (some clients only send zero) */
> -	else if (free_vc_found == 0)
> -		vcnum = 1;  /* we can not reuse vc=0 safely, since some servers
> -				reset all uids on that, but 1 is ok. */
> -	else
> -		vcnum = i;
> -	ses->vcnum = vcnum;
> -get_vc_num_exit:
> -	spin_unlock(&cifs_tcp_ses_lock);
> -
> -	return cpu_to_le16(vcnum);
> -}
> -
>  static __u32 cifs_ssetup_hdr(struct cifs_ses *ses, SESSION_SETUP_ANDX *pSMB)
>  {
>  	__u32 capabilities = 0;
> @@ -128,7 +46,7 @@ static __u32 cifs_ssetup_hdr(struct cifs_ses *ses, SESSION_SETUP_ANDX *pSMB)
>  					CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4,
>  					USHRT_MAX));
>  	pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
> -	pSMB->req.VcNumber = get_next_vcnum(ses);
> +	pSMB->req.VcNumber = __constant_cpu_to_le16(1);
>  
>  	/* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */
>  

-- 
Jeff Layton <jlayton at redhat.com>


More information about the samba-technical mailing list