[linux-cifs-client] use non-zero vcnumbers patch
Jeff Layton
jlayton at redhat.com
Wed Feb 4 01:49:23 GMT 2009
On Fri, 30 Jan 2009 19:50:08 -0600
Steve French <smfrench at gmail.com> wrote:
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index 94c1ca0..e004f6d 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -164,9 +164,12 @@ struct TCP_Server_Info {
> /* multiplexed reads or writes */
> unsigned int maxBuf; /* maxBuf specifies the maximum */
> /* message size the server can send or receive for non-raw SMBs */
> - unsigned int maxRw; /* maxRw specifies the maximum */
> + 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 */
> char sessid[4]; /* unique token id for this session */
> /* (returned on Negotiate */
> int capabilities; /* allow selective disabling of caps by smb sess */
> @@ -210,6 +213,7 @@ struct cifsSesInfo {
> unsigned overrideSecFlg; /* if non-zero override global sec flags */
> __u16 ipc_tid; /* special tid for connection to IPC share */
> __u16 flags;
> + __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 552642a..b0f4e56 100644
> --- a/fs/cifs/cifssmb.c
> +++ b/fs/cifs/cifssmb.c
> @@ -528,14 +528,15 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
> server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
> server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
> (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
> + server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
> GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
> /* 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) {
> - server->maxRw = 0xFF00;
> + server->max_rw = 0xFF00;
> server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
> } else {
> - server->maxRw = 0;/* we do not need to use raw anyway */
> + server->max_rw = 0;/* we do not need to use raw anyway */
> server->capabilities = CAP_MPX_MODE;
> }
> tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
> @@ -638,7 +639,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
> /* probably no need to store and check maxvcs */
> server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
> (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
> - server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
> + server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
> cFYI(DBG2, ("Max buf = %d", ses->server->maxBuf));
> GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
> server->capabilities = le32_to_cpu(pSMBr->Capabilities);
> diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
> index 5f22de7..fdbfdca 100644
> --- a/fs/cifs/sess.c
> +++ b/fs/cifs/sess.c
> @@ -34,15 +34,62 @@
> extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
> unsigned char *p24);
>
> +static __le16 get_next_vcnum(struct cifsSesInfo *ses)
> +{
> + __u16 vcnum = 0;
> + struct list_head *tmp;
> + struct cifsSesInfo *tmp_ses;
> + __u16 max_vcs = ses->server->max_vcs;
> + __u16 i;
> + int free_vc_found = 0;
> +
> + if (max_vcs < 2)
> + max_vcs = 0xFFFF;
> +
A comment about the above situation seems warranted since it's basically
a workaround for buggy servers.
> + write_lock(&cifs_tcp_ses_lock);
> + 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 cifsSesInfo,
> + 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 (free_vc_found == 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
> + vcnum = i;
> + ses->vcnum = vcnum;
> + write_unlock(&cifs_tcp_ses_lock);
> +
> + return le16_to_cpu(vcnum);
> +}
> +
> static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
> {
> __u32 capabilities = 0;
>
> /* init fields common to all four types of SessSetup */
> - /* note that header is initialized to zero in header_assemble */
> + /* Note that offsets for first seven fields in req struct are same */
> + /* in CIFS Specs so does not matter which of 3 forms of struct */
> + /* that we use in next few lines */
> + /* Note that header is initialized to zero in header_assemble */
> pSMB->req.AndXCommand = 0xFF;
> pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
> pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
> + pSMB->req.VcNumber = get_next_vcnum(ses);
>
> /* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */
>
> @@ -71,7 +118,6 @@ static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
> if (ses->capabilities & CAP_UNIX)
> capabilities |= CAP_UNIX;
>
> - /* BB check whether to init vcnum BB */
> return capabilities;
> }
>
So what happens at reconnect? Shouldn't we "reset" all the vcnums?
Shouldn't the first session setup on the reconnected socket use vcnum
0? I seem to recall reading that vcnum of 0 has some significance for
the server...
Other than that, the patch looks reasonable to me.
--
Jeff Layton <jlayton at redhat.com>
More information about the linux-cifs-client
mailing list