diff mbox

[v2] cifs: Send a logoff request before removing a smb session

Message ID 1381590363-4725-1-git-send-email-shirishpargaonkar@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Shirish Pargaonkar Oct. 12, 2013, 3:06 p.m. UTC
From: Shirish Pargaonkar <shirishpargaonkar@gmail.com>

Send a smb session logoff request before removing smb session off of the list.
On a signed smb session, remvoing a session off of the list before sending
a logoff request results in server returning an error for lack of
smb signature.

Never seen an error during smb logoff, so as per MS-SMB2 3.2.5.1,
not sure how an error during logoff should be retried. So for now,
if a server returns an error to a logoff request, log the error and
remove the session off of the list.


Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
---
 fs/cifs/connect.c       | 25 ++++++++++++++++++++-----
 fs/cifs/smb2transport.c | 10 ++++++++--
 fs/cifs/transport.c     | 11 +++++++++--
 3 files changed, 37 insertions(+), 9 deletions(-)

Comments

Jeff Layton Oct. 16, 2013, 11:48 a.m. UTC | #1
On Sat, 12 Oct 2013 10:06:03 -0500
shirishpargaonkar@gmail.com wrote:

> From: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
> 
> Send a smb session logoff request before removing smb session off of the list.
> On a signed smb session, remvoing a session off of the list before sending
> a logoff request results in server returning an error for lack of
> smb signature.
> 
> Never seen an error during smb logoff, so as per MS-SMB2 3.2.5.1,
> not sure how an error during logoff should be retried. So for now,
> if a server returns an error to a logoff request, log the error and
> remove the session off of the list.
> 
> 
> Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
> ---
>  fs/cifs/connect.c       | 25 ++++++++++++++++++++-----
>  fs/cifs/smb2transport.c | 10 ++++++++--
>  fs/cifs/transport.c     | 11 +++++++++--
>  3 files changed, 37 insertions(+), 9 deletions(-)
> 
> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
> index a279ffc..62a5514 100644
> --- a/fs/cifs/connect.c
> +++ b/fs/cifs/connect.c
> @@ -2242,6 +2242,8 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol)
>  
>  	spin_lock(&cifs_tcp_ses_lock);
>  	list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
> +		if (ses->status == CifsExiting)
> +			continue;
>  		if (!match_session(ses, vol))
>  			continue;
>  		++ses->ses_count;
> @@ -2255,24 +2257,37 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol)
>  static void
>  cifs_put_smb_ses(struct cifs_ses *ses)
>  {
> -	unsigned int xid;
> +	unsigned int rc, xid;
>  	struct TCP_Server_Info *server = ses->server;
>  
>  	cifs_dbg(FYI, "%s: ses_count=%d\n", __func__, ses->ses_count);
> +
>  	spin_lock(&cifs_tcp_ses_lock);
> +	if (ses->status == CifsExiting) {
> +		spin_unlock(&cifs_tcp_ses_lock);
> +		return;
> +	}
>  	if (--ses->ses_count > 0) {
>  		spin_unlock(&cifs_tcp_ses_lock);
>  		return;
>  	}
> -
> -	list_del_init(&ses->smb_ses_list);
> +	if (ses->status == CifsGood)
> +		ses->status = CifsExiting;
>  	spin_unlock(&cifs_tcp_ses_lock);
>  
> -	if (ses->status == CifsGood && server->ops->logoff) {
> +	if (ses->status == CifsExiting && server->ops->logoff) {
>  		xid = get_xid();
> -		server->ops->logoff(xid, ses);
> +		rc = server->ops->logoff(xid, ses);
> +		if (rc)
> +			cifs_dbg(VFS, "%s: Session Logoff failure rc=%d\n",
> +				__func__, rc);
>  		_free_xid(xid);
>  	}
> +
> +	spin_lock(&cifs_tcp_ses_lock);
> +	list_del_init(&ses->smb_ses_list);
> +	spin_unlock(&cifs_tcp_ses_lock);
> +
>  	sesInfoFree(ses);
>  	cifs_put_tcp_session(server);
>  }
> diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c
> index 340abca..ee1963b 100644
> --- a/fs/cifs/smb2transport.c
> +++ b/fs/cifs/smb2transport.c
> @@ -516,13 +516,19 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct smb2_hdr *buf,
>  		return -EAGAIN;
>  	}
>  
> -	if (ses->status != CifsGood) {
> -		/* check if SMB2 session is bad because we are setting it up */
> +	if (ses->status == CifsNew) {
>  		if ((buf->Command != SMB2_SESSION_SETUP) &&
>  		    (buf->Command != SMB2_NEGOTIATE))
>  			return -EAGAIN;
>  		/* else ok - we are setting up session */
>  	}
> +
> +	if (ses->status == CifsExiting) {
> +		if (buf->Command != SMB2_LOGOFF)
> +			return -EAGAIN;
> +		/* else ok - we are shutting down the session */
> +	}
> +
>  	*mid = smb2_mid_entry_alloc(buf, ses->server);
>  	if (*mid == NULL)
>  		return -ENOMEM;
> diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
> index 6fdcb1b..fc6e652 100644
> --- a/fs/cifs/transport.c
> +++ b/fs/cifs/transport.c
> @@ -426,13 +426,20 @@ static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
>  		return -EAGAIN;
>  	}
>  
> -	if (ses->status != CifsGood) {
> -		/* check if SMB session is bad because we are setting it up */
> +	if (ses->status == CifsNew) {
>  		if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
>  			(in_buf->Command != SMB_COM_NEGOTIATE))
>  			return -EAGAIN;
>  		/* else ok - we are setting up session */
>  	}
> +
> +	if (ses->status == CifsExiting) {
> +		/* check if SMB session is bad because we are setting it up */
> +		if (in_buf->Command != SMB_COM_LOGOFF_ANDX)
> +			return -EAGAIN;
> +		/* else ok - we are shutting down session */
> +	}
> +
>  	*ppmidQ = AllocMidQEntry(in_buf, ses->server);
>  	if (*ppmidQ == NULL)
>  		return -ENOMEM;

Looks good...

Reviewed-by: Jeff Layton <jlayton@redhat.com>
--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Steve French Oct. 28, 2013, 2:37 p.m. UTC | #2
merged into cifs-2.6.git for-next

On Sat, Oct 12, 2013 at 10:06 AM,  <shirishpargaonkar@gmail.com> wrote:
> From: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
>
> Send a smb session logoff request before removing smb session off of the list.
> On a signed smb session, remvoing a session off of the list before sending
> a logoff request results in server returning an error for lack of
> smb signature.
>
> Never seen an error during smb logoff, so as per MS-SMB2 3.2.5.1,
> not sure how an error during logoff should be retried. So for now,
> if a server returns an error to a logoff request, log the error and
> remove the session off of the list.
>
>
> Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
> ---
>  fs/cifs/connect.c       | 25 ++++++++++++++++++++-----
>  fs/cifs/smb2transport.c | 10 ++++++++--
>  fs/cifs/transport.c     | 11 +++++++++--
>  3 files changed, 37 insertions(+), 9 deletions(-)
>
> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
> index a279ffc..62a5514 100644
> --- a/fs/cifs/connect.c
> +++ b/fs/cifs/connect.c
> @@ -2242,6 +2242,8 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol)
>
>         spin_lock(&cifs_tcp_ses_lock);
>         list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
> +               if (ses->status == CifsExiting)
> +                       continue;
>                 if (!match_session(ses, vol))
>                         continue;
>                 ++ses->ses_count;
> @@ -2255,24 +2257,37 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol)
>  static void
>  cifs_put_smb_ses(struct cifs_ses *ses)
>  {
> -       unsigned int xid;
> +       unsigned int rc, xid;
>         struct TCP_Server_Info *server = ses->server;
>
>         cifs_dbg(FYI, "%s: ses_count=%d\n", __func__, ses->ses_count);
> +
>         spin_lock(&cifs_tcp_ses_lock);
> +       if (ses->status == CifsExiting) {
> +               spin_unlock(&cifs_tcp_ses_lock);
> +               return;
> +       }
>         if (--ses->ses_count > 0) {
>                 spin_unlock(&cifs_tcp_ses_lock);
>                 return;
>         }
> -
> -       list_del_init(&ses->smb_ses_list);
> +       if (ses->status == CifsGood)
> +               ses->status = CifsExiting;
>         spin_unlock(&cifs_tcp_ses_lock);
>
> -       if (ses->status == CifsGood && server->ops->logoff) {
> +       if (ses->status == CifsExiting && server->ops->logoff) {
>                 xid = get_xid();
> -               server->ops->logoff(xid, ses);
> +               rc = server->ops->logoff(xid, ses);
> +               if (rc)
> +                       cifs_dbg(VFS, "%s: Session Logoff failure rc=%d\n",
> +                               __func__, rc);
>                 _free_xid(xid);
>         }
> +
> +       spin_lock(&cifs_tcp_ses_lock);
> +       list_del_init(&ses->smb_ses_list);
> +       spin_unlock(&cifs_tcp_ses_lock);
> +
>         sesInfoFree(ses);
>         cifs_put_tcp_session(server);
>  }
> diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c
> index 340abca..ee1963b 100644
> --- a/fs/cifs/smb2transport.c
> +++ b/fs/cifs/smb2transport.c
> @@ -516,13 +516,19 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct smb2_hdr *buf,
>                 return -EAGAIN;
>         }
>
> -       if (ses->status != CifsGood) {
> -               /* check if SMB2 session is bad because we are setting it up */
> +       if (ses->status == CifsNew) {
>                 if ((buf->Command != SMB2_SESSION_SETUP) &&
>                     (buf->Command != SMB2_NEGOTIATE))
>                         return -EAGAIN;
>                 /* else ok - we are setting up session */
>         }
> +
> +       if (ses->status == CifsExiting) {
> +               if (buf->Command != SMB2_LOGOFF)
> +                       return -EAGAIN;
> +               /* else ok - we are shutting down the session */
> +       }
> +
>         *mid = smb2_mid_entry_alloc(buf, ses->server);
>         if (*mid == NULL)
>                 return -ENOMEM;
> diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
> index 6fdcb1b..fc6e652 100644
> --- a/fs/cifs/transport.c
> +++ b/fs/cifs/transport.c
> @@ -426,13 +426,20 @@ static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
>                 return -EAGAIN;
>         }
>
> -       if (ses->status != CifsGood) {
> -               /* check if SMB session is bad because we are setting it up */
> +       if (ses->status == CifsNew) {
>                 if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
>                         (in_buf->Command != SMB_COM_NEGOTIATE))
>                         return -EAGAIN;
>                 /* else ok - we are setting up session */
>         }
> +
> +       if (ses->status == CifsExiting) {
> +               /* check if SMB session is bad because we are setting it up */
> +               if (in_buf->Command != SMB_COM_LOGOFF_ANDX)
> +                       return -EAGAIN;
> +               /* else ok - we are shutting down session */
> +       }
> +
>         *ppmidQ = AllocMidQEntry(in_buf, ses->server);
>         if (*ppmidQ == NULL)
>                 return -ENOMEM;
> --
> 1.8.1.2
>
diff mbox

Patch

diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index a279ffc..62a5514 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -2242,6 +2242,8 @@  cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol)
 
 	spin_lock(&cifs_tcp_ses_lock);
 	list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
+		if (ses->status == CifsExiting)
+			continue;
 		if (!match_session(ses, vol))
 			continue;
 		++ses->ses_count;
@@ -2255,24 +2257,37 @@  cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol)
 static void
 cifs_put_smb_ses(struct cifs_ses *ses)
 {
-	unsigned int xid;
+	unsigned int rc, xid;
 	struct TCP_Server_Info *server = ses->server;
 
 	cifs_dbg(FYI, "%s: ses_count=%d\n", __func__, ses->ses_count);
+
 	spin_lock(&cifs_tcp_ses_lock);
+	if (ses->status == CifsExiting) {
+		spin_unlock(&cifs_tcp_ses_lock);
+		return;
+	}
 	if (--ses->ses_count > 0) {
 		spin_unlock(&cifs_tcp_ses_lock);
 		return;
 	}
-
-	list_del_init(&ses->smb_ses_list);
+	if (ses->status == CifsGood)
+		ses->status = CifsExiting;
 	spin_unlock(&cifs_tcp_ses_lock);
 
-	if (ses->status == CifsGood && server->ops->logoff) {
+	if (ses->status == CifsExiting && server->ops->logoff) {
 		xid = get_xid();
-		server->ops->logoff(xid, ses);
+		rc = server->ops->logoff(xid, ses);
+		if (rc)
+			cifs_dbg(VFS, "%s: Session Logoff failure rc=%d\n",
+				__func__, rc);
 		_free_xid(xid);
 	}
+
+	spin_lock(&cifs_tcp_ses_lock);
+	list_del_init(&ses->smb_ses_list);
+	spin_unlock(&cifs_tcp_ses_lock);
+
 	sesInfoFree(ses);
 	cifs_put_tcp_session(server);
 }
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c
index 340abca..ee1963b 100644
--- a/fs/cifs/smb2transport.c
+++ b/fs/cifs/smb2transport.c
@@ -516,13 +516,19 @@  smb2_get_mid_entry(struct cifs_ses *ses, struct smb2_hdr *buf,
 		return -EAGAIN;
 	}
 
-	if (ses->status != CifsGood) {
-		/* check if SMB2 session is bad because we are setting it up */
+	if (ses->status == CifsNew) {
 		if ((buf->Command != SMB2_SESSION_SETUP) &&
 		    (buf->Command != SMB2_NEGOTIATE))
 			return -EAGAIN;
 		/* else ok - we are setting up session */
 	}
+
+	if (ses->status == CifsExiting) {
+		if (buf->Command != SMB2_LOGOFF)
+			return -EAGAIN;
+		/* else ok - we are shutting down the session */
+	}
+
 	*mid = smb2_mid_entry_alloc(buf, ses->server);
 	if (*mid == NULL)
 		return -ENOMEM;
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 6fdcb1b..fc6e652 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -426,13 +426,20 @@  static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
 		return -EAGAIN;
 	}
 
-	if (ses->status != CifsGood) {
-		/* check if SMB session is bad because we are setting it up */
+	if (ses->status == CifsNew) {
 		if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
 			(in_buf->Command != SMB_COM_NEGOTIATE))
 			return -EAGAIN;
 		/* else ok - we are setting up session */
 	}
+
+	if (ses->status == CifsExiting) {
+		/* check if SMB session is bad because we are setting it up */
+		if (in_buf->Command != SMB_COM_LOGOFF_ANDX)
+			return -EAGAIN;
+		/* else ok - we are shutting down session */
+	}
+
 	*ppmidQ = AllocMidQEntry(in_buf, ses->server);
 	if (*ppmidQ == NULL)
 		return -ENOMEM;