All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/11] Improve transport code for future SMB2 usage
@ 2012-02-22  7:32 Pavel Shilovsky
       [not found] ` <1329895984-9251-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
  0 siblings, 1 reply; 51+ messages in thread
From: Pavel Shilovsky @ 2012-02-22  7:32 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

This is the second version of the patchset. The main change from the first one
is the patch that add the code to respect MaxMpxCount value got from
negotiate response.

The goal of this patchset is to reorganize existing transport infrustructure
to make it easily expandable when SMB2 specific code come into the tree.

This let us avoid a code dublication and reduce the whole number of changes
coming with SMB2 code.

Pavel Shilovsky (11):
  CIFS: Simplify inFlight logic
  CIFS: Introduce credit-based flow control
  CIFS: Count blocking lock command
  CIFS: Delete echo_retries module parm
  CIFS: Make wait_for_free_request interruptible
  CIFS: Respect MaxMpxCount field
  CIFS: Separate protocol-specific code from transport routines
  CIFS: Separate protocol-specific code from demultiplex code
  CIFS: Separate protocol-specific code from cifs_readv_receive code
  CIFS: Expand CurrentMid field
  CIFS: Change mid_q_entry structure fields

 fs/cifs/README       |    6 +-
 fs/cifs/cifs_debug.c |   28 ++--
 fs/cifs/cifs_debug.h |    4 +-
 fs/cifs/cifsfs.c     |   17 ---
 fs/cifs/cifsglob.h   |   98 ++++++++++++----
 fs/cifs/cifsproto.h  |   18 ++-
 fs/cifs/cifssmb.c    |  107 ++++++++++-------
 fs/cifs/connect.c    |  122 +++++++++-----------
 fs/cifs/dir.c        |    5 +-
 fs/cifs/file.c       |    4 +-
 fs/cifs/misc.c       |  147 ++++++++++++++++-------
 fs/cifs/netmisc.c    |    3 +-
 fs/cifs/transport.c  |  324 ++++++++++++++++++++++++++++----------------------
 13 files changed, 515 insertions(+), 368 deletions(-)

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH 01/11] CIFS: Simplify inFlight logic
       [not found] ` <1329895984-9251-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
@ 2012-02-22  7:32   ` Pavel Shilovsky
       [not found]     ` <1329895984-9251-2-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
  2012-02-22  7:32   ` [PATCH 02/11] CIFS: Introduce credit-based flow control Pavel Shilovsky
                     ` (9 subsequent siblings)
  10 siblings, 1 reply; 51+ messages in thread
From: Pavel Shilovsky @ 2012-02-22  7:32 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

by making it as unsigned integer and surround access with req_lock
from server structure.

Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
 fs/cifs/cifs_debug.c |    3 +--
 fs/cifs/cifsglob.h   |   21 ++++++++++++++++++++-
 fs/cifs/cifssmb.c    |    6 +++---
 fs/cifs/connect.c    |   10 +++++-----
 fs/cifs/transport.c  |   45 +++++++++++++++++++++++----------------------
 5 files changed, 52 insertions(+), 33 deletions(-)

diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
index 24b3dfc..573b899 100644
--- a/fs/cifs/cifs_debug.c
+++ b/fs/cifs/cifs_debug.c
@@ -171,8 +171,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
 			seq_printf(m, "TCP status: %d\n\tLocal Users To "
 				   "Server: %d SecMode: 0x%x Req On Wire: %d",
 				   server->tcpStatus, server->srv_count,
-				   server->sec_mode,
-				   atomic_read(&server->inFlight));
+				   server->sec_mode, in_flight(server));
 
 #ifdef CONFIG_CIFS_STATS2
 			seq_printf(m, " In Send: %d In MaxReq Wait: %d",
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 76e7d8b..44cfc9a 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -255,7 +255,8 @@ struct TCP_Server_Info {
 	bool noblocksnd;		/* use blocking sendmsg */
 	bool noautotune;		/* do not autotune send buf sizes */
 	bool tcp_nodelay;
-	atomic_t inFlight;  /* number of requests on the wire to server */
+	unsigned int in_flight;  /* number of requests on the wire to server */
+	spinlock_t req_lock; /* protect the value above */
 	struct mutex srv_mutex;
 	struct task_struct *tsk;
 	char server_GUID[16];
@@ -307,6 +308,24 @@ struct TCP_Server_Info {
 #endif
 };
 
+static inline unsigned int
+in_flight(struct TCP_Server_Info *server)
+{
+	unsigned int num;
+	spin_lock(&server->req_lock);
+	num = server->in_flight;
+	spin_unlock(&server->req_lock);
+	return num;
+}
+
+static inline void
+dec_in_flight(struct TCP_Server_Info *server)
+{
+	spin_lock(&server->req_lock);
+	server->in_flight--;
+	spin_unlock(&server->req_lock);
+}
+
 /*
  * Macros to allow the TCP_Server_Info->net field and related code to drop out
  * when CONFIG_NET_NS isn't set.
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 8b7794c..0b50551 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -716,7 +716,7 @@ cifs_echo_callback(struct mid_q_entry *mid)
 	struct TCP_Server_Info *server = mid->callback_data;
 
 	DeleteMidQEntry(mid);
-	atomic_dec(&server->inFlight);
+	dec_in_flight(server);
 	wake_up(&server->request_q);
 }
 
@@ -1669,7 +1669,7 @@ cifs_readv_callback(struct mid_q_entry *mid)
 
 	queue_work(system_nrt_wq, &rdata->work);
 	DeleteMidQEntry(mid);
-	atomic_dec(&server->inFlight);
+	dec_in_flight(server);
 	wake_up(&server->request_q);
 }
 
@@ -2110,7 +2110,7 @@ cifs_writev_callback(struct mid_q_entry *mid)
 
 	queue_work(system_nrt_wq, &wdata->work);
 	DeleteMidQEntry(mid);
-	atomic_dec(&tcon->ses->server->inFlight);
+	dec_in_flight(tcon->ses->server);
 	wake_up(&tcon->ses->server->request_q);
 }
 
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 602f77c..12286d0 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -647,14 +647,14 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server)
 	 * cifs_max_pending is normally 50, but can be set at module install
 	 * time to as little as two.
 	 */
-	spin_lock(&GlobalMid_Lock);
-	if (atomic_read(&server->inFlight) >= cifs_max_pending)
-		atomic_set(&server->inFlight, cifs_max_pending - 1);
+	spin_lock(&server->req_lock);
+	if (server->in_flight >= cifs_max_pending)
+		server->in_flight = cifs_max_pending - 1;
 	/*
 	 * We do not want to set the max_pending too low or we could end up
 	 * with the counter going negative.
 	 */
-	spin_unlock(&GlobalMid_Lock);
+	spin_unlock(&server->req_lock);
 	/*
 	 * Although there should not be any requests blocked on this queue it
 	 * can not hurt to be paranoid and try to wake up requests that may
@@ -1909,7 +1909,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
 	tcp_ses->noblocksnd = volume_info->noblocksnd;
 	tcp_ses->noautotune = volume_info->noautotune;
 	tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay;
-	atomic_set(&tcp_ses->inFlight, 0);
+	tcp_ses->in_flight = 0;
 	init_waitqueue_head(&tcp_ses->response_q);
 	init_waitqueue_head(&tcp_ses->request_q);
 	INIT_LIST_HEAD(&tcp_ses->pending_mid_q);
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 0cc9584..fc1904f 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -254,28 +254,29 @@ smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
 	return smb_sendv(server, &iov, 1);
 }
 
-static int wait_for_free_request(struct TCP_Server_Info *server,
-				 const int long_op)
+static int
+wait_for_free_request(struct TCP_Server_Info *server, const int long_op)
 {
+	spin_lock(&server->req_lock);
+
 	if (long_op == CIFS_ASYNC_OP) {
 		/* oplock breaks must not be held up */
-		atomic_inc(&server->inFlight);
+		server->in_flight++;
+		spin_unlock(&server->req_lock);
 		return 0;
 	}
 
-	spin_lock(&GlobalMid_Lock);
 	while (1) {
-		if (atomic_read(&server->inFlight) >= cifs_max_pending) {
-			spin_unlock(&GlobalMid_Lock);
+		if (server->in_flight >= cifs_max_pending) {
+			spin_unlock(&server->req_lock);
 			cifs_num_waiters_inc(server);
 			wait_event(server->request_q,
-				   atomic_read(&server->inFlight)
-				     < cifs_max_pending);
+				   in_flight(server) < cifs_max_pending);
 			cifs_num_waiters_dec(server);
-			spin_lock(&GlobalMid_Lock);
+			spin_lock(&server->req_lock);
 		} else {
 			if (server->tcpStatus == CifsExiting) {
-				spin_unlock(&GlobalMid_Lock);
+				spin_unlock(&server->req_lock);
 				return -ENOENT;
 			}
 
@@ -284,8 +285,8 @@ static int wait_for_free_request(struct TCP_Server_Info *server,
 
 			/* update # of requests on the wire to server */
 			if (long_op != CIFS_BLOCKING_OP)
-				atomic_inc(&server->inFlight);
-			spin_unlock(&GlobalMid_Lock);
+				server->in_flight++;
+			spin_unlock(&server->req_lock);
 			break;
 		}
 	}
@@ -359,7 +360,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
 	mid = AllocMidQEntry(hdr, server);
 	if (mid == NULL) {
 		mutex_unlock(&server->srv_mutex);
-		atomic_dec(&server->inFlight);
+		dec_in_flight(server);
 		wake_up(&server->request_q);
 		return -ENOMEM;
 	}
@@ -392,7 +393,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
 	return rc;
 out_err:
 	delete_mid(mid);
-	atomic_dec(&server->inFlight);
+	dec_in_flight(server);
 	wake_up(&server->request_q);
 	return rc;
 }
@@ -564,7 +565,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 		mutex_unlock(&ses->server->srv_mutex);
 		cifs_small_buf_release(in_buf);
 		/* Update # of requests on wire to server */
-		atomic_dec(&ses->server->inFlight);
+		dec_in_flight(ses->server);
 		wake_up(&ses->server->request_q);
 		return rc;
 	}
@@ -601,7 +602,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 			midQ->callback = DeleteMidQEntry;
 			spin_unlock(&GlobalMid_Lock);
 			cifs_small_buf_release(in_buf);
-			atomic_dec(&ses->server->inFlight);
+			dec_in_flight(ses->server);
 			wake_up(&ses->server->request_q);
 			return rc;
 		}
@@ -612,7 +613,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 
 	rc = cifs_sync_mid_result(midQ, ses->server);
 	if (rc != 0) {
-		atomic_dec(&ses->server->inFlight);
+		dec_in_flight(ses->server);
 		wake_up(&ses->server->request_q);
 		return rc;
 	}
@@ -637,7 +638,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 		midQ->resp_buf = NULL;
 out:
 	delete_mid(midQ);
-	atomic_dec(&ses->server->inFlight);
+	dec_in_flight(ses->server);
 	wake_up(&ses->server->request_q);
 
 	return rc;
@@ -688,7 +689,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 	if (rc) {
 		mutex_unlock(&ses->server->srv_mutex);
 		/* Update # of requests on wire to server */
-		atomic_dec(&ses->server->inFlight);
+		dec_in_flight(ses->server);
 		wake_up(&ses->server->request_q);
 		return rc;
 	}
@@ -721,7 +722,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 			/* no longer considered to be "in-flight" */
 			midQ->callback = DeleteMidQEntry;
 			spin_unlock(&GlobalMid_Lock);
-			atomic_dec(&ses->server->inFlight);
+			dec_in_flight(ses->server);
 			wake_up(&ses->server->request_q);
 			return rc;
 		}
@@ -730,7 +731,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 
 	rc = cifs_sync_mid_result(midQ, ses->server);
 	if (rc != 0) {
-		atomic_dec(&ses->server->inFlight);
+		dec_in_flight(ses->server);
 		wake_up(&ses->server->request_q);
 		return rc;
 	}
@@ -747,7 +748,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 	rc = cifs_check_receive(midQ, ses->server, 0);
 out:
 	delete_mid(midQ);
-	atomic_dec(&ses->server->inFlight);
+	dec_in_flight(ses->server);
 	wake_up(&ses->server->request_q);
 
 	return rc;
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 02/11] CIFS: Introduce credit-based flow control
       [not found] ` <1329895984-9251-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
  2012-02-22  7:32   ` [PATCH 01/11] CIFS: Simplify inFlight logic Pavel Shilovsky
@ 2012-02-22  7:32   ` Pavel Shilovsky
  2012-02-22  7:32   ` [PATCH 03/11] CIFS: Count blocking lock command Pavel Shilovsky
                     ` (8 subsequent siblings)
  10 siblings, 0 replies; 51+ messages in thread
From: Pavel Shilovsky @ 2012-02-22  7:32 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

and send no more than credits value requests at once. For SMB/CIFS
it's trivial: increment this value by receiving any message and
decrement by sending one.

Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
 fs/cifs/cifsglob.h  |   24 ++++++++++++++++++++++--
 fs/cifs/cifssmb.c   |    6 +++---
 fs/cifs/connect.c   |   17 ++++++-----------
 fs/cifs/transport.c |   30 ++++++++++++++++--------------
 4 files changed, 47 insertions(+), 30 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 44cfc9a..600d61c 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -255,8 +255,9 @@ struct TCP_Server_Info {
 	bool noblocksnd;		/* use blocking sendmsg */
 	bool noautotune;		/* do not autotune send buf sizes */
 	bool tcp_nodelay;
+	int credits;  /* send no more requests at once */
 	unsigned int in_flight;  /* number of requests on the wire to server */
-	spinlock_t req_lock; /* protect the value above */
+	spinlock_t req_lock;  /* protect the two values above */
 	struct mutex srv_mutex;
 	struct task_struct *tsk;
 	char server_GUID[16];
@@ -318,14 +319,33 @@ in_flight(struct TCP_Server_Info *server)
 	return num;
 }
 
+static inline int
+get_credits(struct TCP_Server_Info *server)
+{
+	int num;
+	spin_lock(&server->req_lock);
+	num = server->credits;
+	spin_unlock(&server->req_lock);
+	return num;
+}
+
 static inline void
-dec_in_flight(struct TCP_Server_Info *server)
+add_credits(struct TCP_Server_Info *server, unsigned int add)
 {
 	spin_lock(&server->req_lock);
+	server->credits += add;
 	server->in_flight--;
 	spin_unlock(&server->req_lock);
 }
 
+static inline void
+set_credits(struct TCP_Server_Info *server, int val)
+{
+	spin_lock(&server->req_lock);
+	server->credits = val;
+	spin_unlock(&server->req_lock);
+}
+
 /*
  * Macros to allow the TCP_Server_Info->net field and related code to drop out
  * when CONFIG_NET_NS isn't set.
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 0b50551..c255c25 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -716,7 +716,7 @@ cifs_echo_callback(struct mid_q_entry *mid)
 	struct TCP_Server_Info *server = mid->callback_data;
 
 	DeleteMidQEntry(mid);
-	dec_in_flight(server);
+	add_credits(server, 1);
 	wake_up(&server->request_q);
 }
 
@@ -1669,7 +1669,7 @@ cifs_readv_callback(struct mid_q_entry *mid)
 
 	queue_work(system_nrt_wq, &rdata->work);
 	DeleteMidQEntry(mid);
-	dec_in_flight(server);
+	add_credits(server, 1);
 	wake_up(&server->request_q);
 }
 
@@ -2110,7 +2110,7 @@ cifs_writev_callback(struct mid_q_entry *mid)
 
 	queue_work(system_nrt_wq, &wdata->work);
 	DeleteMidQEntry(mid);
-	dec_in_flight(tcon->ses->server);
+	add_credits(tcon->ses->server, 1);
 	wake_up(&tcon->ses->server->request_q);
 }
 
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 12286d0..673813f 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -642,18 +642,10 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server)
 	spin_unlock(&GlobalMid_Lock);
 	wake_up_all(&server->response_q);
 
-	/*
-	 * Check if we have blocked requests that need to free. Note that
-	 * cifs_max_pending is normally 50, but can be set at module install
-	 * time to as little as two.
-	 */
+	/* check if we have blocked requests that need to free */
 	spin_lock(&server->req_lock);
-	if (server->in_flight >= cifs_max_pending)
-		server->in_flight = cifs_max_pending - 1;
-	/*
-	 * We do not want to set the max_pending too low or we could end up
-	 * with the counter going negative.
-	 */
+	if (server->credits <= 0)
+		server->credits = 1;
 	spin_unlock(&server->req_lock);
 	/*
 	 * Although there should not be any requests blocked on this queue it
@@ -1910,6 +1902,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
 	tcp_ses->noautotune = volume_info->noautotune;
 	tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay;
 	tcp_ses->in_flight = 0;
+	tcp_ses->credits = cifs_max_pending;
 	init_waitqueue_head(&tcp_ses->response_q);
 	init_waitqueue_head(&tcp_ses->request_q);
 	INIT_LIST_HEAD(&tcp_ses->pending_mid_q);
@@ -3759,9 +3752,11 @@ int cifs_negotiate_protocol(unsigned int xid, struct cifs_ses *ses)
 	if (server->maxBuf != 0)
 		return 0;
 
+	set_credits(server, cifs_max_pending);
 	rc = CIFSSMBNegotiate(xid, ses);
 	if (rc == -EAGAIN) {
 		/* retry only once on 1st time connection */
+		set_credits(server, cifs_max_pending);
 		rc = CIFSSMBNegotiate(xid, ses);
 		if (rc == -EAGAIN)
 			rc = -EHOSTDOWN;
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index fc1904f..44ac0aa 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -262,16 +262,16 @@ wait_for_free_request(struct TCP_Server_Info *server, const int long_op)
 	if (long_op == CIFS_ASYNC_OP) {
 		/* oplock breaks must not be held up */
 		server->in_flight++;
+		server->credits--;
 		spin_unlock(&server->req_lock);
 		return 0;
 	}
 
 	while (1) {
-		if (server->in_flight >= cifs_max_pending) {
+		if (server->credits <= 0) {
 			spin_unlock(&server->req_lock);
 			cifs_num_waiters_inc(server);
-			wait_event(server->request_q,
-				   in_flight(server) < cifs_max_pending);
+			wait_event(server->request_q, get_credits(server) > 0);
 			cifs_num_waiters_dec(server);
 			spin_lock(&server->req_lock);
 		} else {
@@ -284,8 +284,10 @@ wait_for_free_request(struct TCP_Server_Info *server, const int long_op)
 			   as they are allowed to block on server */
 
 			/* update # of requests on the wire to server */
-			if (long_op != CIFS_BLOCKING_OP)
+			if (long_op != CIFS_BLOCKING_OP) {
+				server->credits--;
 				server->in_flight++;
+			}
 			spin_unlock(&server->req_lock);
 			break;
 		}
@@ -360,7 +362,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
 	mid = AllocMidQEntry(hdr, server);
 	if (mid == NULL) {
 		mutex_unlock(&server->srv_mutex);
-		dec_in_flight(server);
+		add_credits(server, 1);
 		wake_up(&server->request_q);
 		return -ENOMEM;
 	}
@@ -393,7 +395,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
 	return rc;
 out_err:
 	delete_mid(mid);
-	dec_in_flight(server);
+	add_credits(server, 1);
 	wake_up(&server->request_q);
 	return rc;
 }
@@ -565,7 +567,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 		mutex_unlock(&ses->server->srv_mutex);
 		cifs_small_buf_release(in_buf);
 		/* Update # of requests on wire to server */
-		dec_in_flight(ses->server);
+		add_credits(ses->server, 1);
 		wake_up(&ses->server->request_q);
 		return rc;
 	}
@@ -602,7 +604,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 			midQ->callback = DeleteMidQEntry;
 			spin_unlock(&GlobalMid_Lock);
 			cifs_small_buf_release(in_buf);
-			dec_in_flight(ses->server);
+			add_credits(ses->server, 1);
 			wake_up(&ses->server->request_q);
 			return rc;
 		}
@@ -613,7 +615,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 
 	rc = cifs_sync_mid_result(midQ, ses->server);
 	if (rc != 0) {
-		dec_in_flight(ses->server);
+		add_credits(ses->server, 1);
 		wake_up(&ses->server->request_q);
 		return rc;
 	}
@@ -638,7 +640,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 		midQ->resp_buf = NULL;
 out:
 	delete_mid(midQ);
-	dec_in_flight(ses->server);
+	add_credits(ses->server, 1);
 	wake_up(&ses->server->request_q);
 
 	return rc;
@@ -689,7 +691,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 	if (rc) {
 		mutex_unlock(&ses->server->srv_mutex);
 		/* Update # of requests on wire to server */
-		dec_in_flight(ses->server);
+		add_credits(ses->server, 1);
 		wake_up(&ses->server->request_q);
 		return rc;
 	}
@@ -722,7 +724,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 			/* no longer considered to be "in-flight" */
 			midQ->callback = DeleteMidQEntry;
 			spin_unlock(&GlobalMid_Lock);
-			dec_in_flight(ses->server);
+			add_credits(ses->server, 1);
 			wake_up(&ses->server->request_q);
 			return rc;
 		}
@@ -731,7 +733,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 
 	rc = cifs_sync_mid_result(midQ, ses->server);
 	if (rc != 0) {
-		dec_in_flight(ses->server);
+		add_credits(ses->server, 1);
 		wake_up(&ses->server->request_q);
 		return rc;
 	}
@@ -748,7 +750,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 	rc = cifs_check_receive(midQ, ses->server, 0);
 out:
 	delete_mid(midQ);
-	dec_in_flight(ses->server);
+	add_credits(ses->server, 1);
 	wake_up(&ses->server->request_q);
 
 	return rc;
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 03/11] CIFS: Count blocking lock command
       [not found] ` <1329895984-9251-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
  2012-02-22  7:32   ` [PATCH 01/11] CIFS: Simplify inFlight logic Pavel Shilovsky
  2012-02-22  7:32   ` [PATCH 02/11] CIFS: Introduce credit-based flow control Pavel Shilovsky
@ 2012-02-22  7:32   ` Pavel Shilovsky
       [not found]     ` <1329895984-9251-4-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
  2012-02-22  7:32   ` [PATCH 04/11] CIFS: Delete echo_retries module parm Pavel Shilovsky
                     ` (7 subsequent siblings)
  10 siblings, 1 reply; 51+ messages in thread
From: Pavel Shilovsky @ 2012-02-22  7:32 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

to make sure we don't exceed the number of credits we have in this case.

Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
 fs/cifs/transport.c |   32 +++++++++++++++++++++-----------
 1 files changed, 21 insertions(+), 11 deletions(-)

diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 44ac0aa..fa93720 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -279,15 +279,8 @@ wait_for_free_request(struct TCP_Server_Info *server, const int long_op)
 				spin_unlock(&server->req_lock);
 				return -ENOENT;
 			}
-
-			/* can not count locking commands against total
-			   as they are allowed to block on server */
-
-			/* update # of requests on the wire to server */
-			if (long_op != CIFS_BLOCKING_OP) {
-				server->credits--;
-				server->in_flight++;
-			}
+			server->credits--;
+			server->in_flight++;
 			spin_unlock(&server->req_lock);
 			break;
 		}
@@ -816,7 +809,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 		return -EIO;
 	}
 
-	rc = wait_for_free_request(ses->server, CIFS_BLOCKING_OP);
+	rc = wait_for_free_request(ses->server, 0);
 	if (rc)
 		return rc;
 
@@ -829,6 +822,8 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 	rc = allocate_mid(ses, in_buf, &midQ);
 	if (rc) {
 		mutex_unlock(&ses->server->srv_mutex);
+		add_credits(ses->server, 1);
+		wake_up(&ses->server->request_q);
 		return rc;
 	}
 
@@ -836,6 +831,8 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 	if (rc) {
 		delete_mid(midQ);
 		mutex_unlock(&ses->server->srv_mutex);
+		add_credits(ses->server, 1);
+		wake_up(&ses->server->request_q);
 		return rc;
 	}
 
@@ -848,6 +845,8 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 
 	if (rc < 0) {
 		delete_mid(midQ);
+		add_credits(ses->server, 1);
+		wake_up(&ses->server->request_q);
 		return rc;
 	}
 
@@ -869,6 +868,8 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 			rc = send_nt_cancel(ses->server, in_buf, midQ);
 			if (rc) {
 				delete_mid(midQ);
+				add_credits(ses->server, 1);
+				wake_up(&ses->server->request_q);
 				return rc;
 			}
 		} else {
@@ -881,6 +882,8 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 			   already been removed. Don't exit in this case. */
 			if (rc && rc != -ENOLCK) {
 				delete_mid(midQ);
+				add_credits(ses->server, 1);
+				wake_up(&ses->server->request_q);
 				return rc;
 			}
 		}
@@ -893,6 +896,8 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 				/* no longer considered to be "in-flight" */
 				midQ->callback = DeleteMidQEntry;
 				spin_unlock(&GlobalMid_Lock);
+				add_credits(ses->server, 1);
+				wake_up(&ses->server->request_q);
 				return rc;
 			}
 			spin_unlock(&GlobalMid_Lock);
@@ -903,8 +908,11 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 	}
 
 	rc = cifs_sync_mid_result(midQ, ses->server);
-	if (rc != 0)
+	if (rc != 0) {
+		add_credits(ses->server, 1);
+		wake_up(&ses->server->request_q);
 		return rc;
+	}
 
 	/* rcvd frame is ok */
 	if (out_buf == NULL || midQ->midState != MID_RESPONSE_RECEIVED) {
@@ -918,6 +926,8 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 	rc = cifs_check_receive(midQ, ses->server, 0);
 out:
 	delete_mid(midQ);
+	add_credits(ses->server, 1);
+	wake_up(&ses->server->request_q);
 	if (rstart && rc == -EACCES)
 		return -ERESTARTSYS;
 	return rc;
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 04/11] CIFS: Delete echo_retries module parm
       [not found] ` <1329895984-9251-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
                     ` (2 preceding siblings ...)
  2012-02-22  7:32   ` [PATCH 03/11] CIFS: Count blocking lock command Pavel Shilovsky
@ 2012-02-22  7:32   ` Pavel Shilovsky
       [not found]     ` <1329895984-9251-5-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
  2012-02-22  7:32   ` [PATCH 05/11] CIFS: Make wait_for_free_request interruptible Pavel Shilovsky
                     ` (6 subsequent siblings)
  10 siblings, 1 reply; 51+ messages in thread
From: Pavel Shilovsky @ 2012-02-22  7:32 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

It's the essential step before respecting MaxMpxCount value during
negotiating because we will keep only one extra slot for sending
echo requests. If there is no response for echo message - reconnect
the tcp session.

Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
 fs/cifs/README     |    6 +-----
 fs/cifs/cifsfs.c   |    5 -----
 fs/cifs/cifsglob.h |    3 ---
 fs/cifs/connect.c  |    7 +++----
 4 files changed, 4 insertions(+), 17 deletions(-)

diff --git a/fs/cifs/README b/fs/cifs/README
index 895da1d..b7d782b 100644
--- a/fs/cifs/README
+++ b/fs/cifs/README
@@ -753,10 +753,6 @@ module loading or during the runtime by using the interface
 
 i.e. echo "value" > /sys/module/cifs/parameters/<param>
 
-1. echo_retries - The number of echo attempts before giving up and
-		  reconnecting to the server. The default is 5. The value 0
-		  means never reconnect.
-
-2. enable_oplocks - Enable or disable oplocks. Oplocks are enabled by default.
+1. enable_oplocks - Enable or disable oplocks. Oplocks are enabled by default.
 		    [Y/y/1]. To disable use any of [N/n/0].
 
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index b1fd382..e1ce1ca 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -77,11 +77,6 @@ unsigned int cifs_max_pending = CIFS_MAX_REQ;
 module_param(cifs_max_pending, int, 0444);
 MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server. "
 				   "Default: 50 Range: 2 to 256");
-unsigned short echo_retries = 5;
-module_param(echo_retries, ushort, 0644);
-MODULE_PARM_DESC(echo_retries, "Number of echo attempts before giving up and "
-			       "reconnecting server. Default: 5. 0 means "
-			       "never reconnect.");
 module_param(enable_oplocks, bool, 0644);
 MODULE_PARM_DESC(enable_oplocks, "Enable or disable oplocks (bool). Default:"
 				 "y/Y/1");
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 600d61c..674792e 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -1049,9 +1049,6 @@ GLOBAL_EXTERN unsigned int cifs_min_rcv;    /* min size of big ntwrk buf pool */
 GLOBAL_EXTERN unsigned int cifs_min_small;  /* min size of small buf pool */
 GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/
 
-/* reconnect after this many failed echo attempts */
-GLOBAL_EXTERN unsigned short echo_retries;
-
 #ifdef CONFIG_CIFS_ACL
 GLOBAL_EXTERN struct rb_root uidtree;
 GLOBAL_EXTERN struct rb_root gidtree;
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 673813f..86d7a40 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -373,12 +373,11 @@ allocate_buffers(struct TCP_Server_Info *server)
 static bool
 server_unresponsive(struct TCP_Server_Info *server)
 {
-	if (echo_retries > 0 && server->tcpStatus == CifsGood &&
-	    time_after(jiffies, server->lstrp +
-				(echo_retries * SMB_ECHO_INTERVAL))) {
+	if (server->tcpStatus == CifsGood &&
+	    time_after(jiffies, server->lstrp + SMB_ECHO_INTERVAL)) {
 		cERROR(1, "Server %s has not responded in %d seconds. "
 			  "Reconnecting...", server->hostname,
-			  (echo_retries * SMB_ECHO_INTERVAL / HZ));
+			  SMB_ECHO_INTERVAL / HZ);
 		cifs_reconnect(server);
 		wake_up(&server->response_q);
 		return true;
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 05/11] CIFS: Make wait_for_free_request interruptible
       [not found] ` <1329895984-9251-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
                     ` (3 preceding siblings ...)
  2012-02-22  7:32   ` [PATCH 04/11] CIFS: Delete echo_retries module parm Pavel Shilovsky
@ 2012-02-22  7:32   ` Pavel Shilovsky
       [not found]     ` <1329895984-9251-6-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
  2012-02-22  7:32   ` [PATCH 06/11] CIFS: Respect MaxMpxCount field Pavel Shilovsky
                     ` (5 subsequent siblings)
  10 siblings, 1 reply; 51+ messages in thread
From: Pavel Shilovsky @ 2012-02-22  7:32 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

to let us interrupt the proccess if the session went down and echo
is disabled.

Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
 fs/cifs/transport.c |    7 ++++++-
 1 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index fa93720..938d20b 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -257,6 +257,8 @@ smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
 static int
 wait_for_free_request(struct TCP_Server_Info *server, const int long_op)
 {
+	int rc;
+
 	spin_lock(&server->req_lock);
 
 	if (long_op == CIFS_ASYNC_OP) {
@@ -271,8 +273,11 @@ wait_for_free_request(struct TCP_Server_Info *server, const int long_op)
 		if (server->credits <= 0) {
 			spin_unlock(&server->req_lock);
 			cifs_num_waiters_inc(server);
-			wait_event(server->request_q, get_credits(server) > 0);
+			rc = wait_event_interruptible(server->request_q,
+						      get_credits(server) > 0);
 			cifs_num_waiters_dec(server);
+			if (rc)
+				return rc;
 			spin_lock(&server->req_lock);
 		} else {
 			if (server->tcpStatus == CifsExiting) {
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 06/11] CIFS: Respect MaxMpxCount field
       [not found] ` <1329895984-9251-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
                     ` (4 preceding siblings ...)
  2012-02-22  7:32   ` [PATCH 05/11] CIFS: Make wait_for_free_request interruptible Pavel Shilovsky
@ 2012-02-22  7:32   ` Pavel Shilovsky
       [not found]     ` <1329895984-9251-7-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
  2012-02-22  7:33   ` [PATCH 07/11] CIFS: Separate protocol-specific code from transport routines Pavel Shilovsky
                     ` (4 subsequent siblings)
  10 siblings, 1 reply; 51+ messages in thread
From: Pavel Shilovsky @ 2012-02-22  7:32 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

by setting the number of available credits to it except 2 that goes
to extra echo and oplock slots. If MaxMpxCount is 2 - disable oplocks,
if 1 - disable oplocks and echos.

Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
 fs/cifs/cifsfs.c    |   12 --------
 fs/cifs/cifsglob.h  |   60 ++++++++++++++++++--------------------
 fs/cifs/cifsproto.h |    7 ++++-
 fs/cifs/cifssmb.c   |   16 ++++++----
 fs/cifs/connect.c   |   10 +++---
 fs/cifs/dir.c       |    5 ++-
 fs/cifs/file.c      |    4 +-
 fs/cifs/misc.c      |   49 +++++++++++++++++++++++++++++++
 fs/cifs/transport.c |   79 +++++++++++++++++++++++++--------------------------
 9 files changed, 142 insertions(+), 100 deletions(-)

diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index e1ce1ca..a9b483b 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -73,10 +73,6 @@ unsigned int cifs_min_small = 30;
 module_param(cifs_min_small, int, 0);
 MODULE_PARM_DESC(cifs_min_small, "Small network buffers in pool. Default: 30 "
 				 "Range: 2 to 256");
-unsigned int cifs_max_pending = CIFS_MAX_REQ;
-module_param(cifs_max_pending, int, 0444);
-MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server. "
-				   "Default: 50 Range: 2 to 256");
 module_param(enable_oplocks, bool, 0644);
 MODULE_PARM_DESC(enable_oplocks, "Enable or disable oplocks (bool). Default:"
 				 "y/Y/1");
@@ -1108,14 +1104,6 @@ init_cifs(void)
 	spin_lock_init(&cifs_file_list_lock);
 	spin_lock_init(&GlobalMid_Lock);
 
-	if (cifs_max_pending < 2) {
-		cifs_max_pending = 2;
-		cFYI(1, "cifs_max_pending set to min of 2");
-	} else if (cifs_max_pending > 256) {
-		cifs_max_pending = 256;
-		cFYI(1, "cifs_max_pending set to max of 256");
-	}
-
 	rc = cifs_fscache_register();
 	if (rc)
 		goto out_clean_proc;
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 674792e..4b13be5 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -53,17 +53,6 @@
  */
 #define CIFS_MAX_ACTIMEO (1 << 30)
 
-/*
- * MAX_REQ is the maximum number of requests that WE will send
- * on one socket concurrently. It also matches the most common
- * value of max multiplex returned by servers.  We may
- * eventually want to use the negotiated value (in case
- * future servers can handle more) when we are more confident that
- * we will not have problems oveloading the socket with pending
- * write data.
- */
-#define CIFS_MAX_REQ 50
-
 #define RFC1001_NAME_LEN 15
 #define RFC1001_NAME_LEN_WITH_NULL (RFC1001_NAME_LEN + 1)
 
@@ -255,7 +244,11 @@ struct TCP_Server_Info {
 	bool noblocksnd;		/* use blocking sendmsg */
 	bool noautotune;		/* do not autotune send buf sizes */
 	bool tcp_nodelay;
-	int credits;  /* send no more requests at once */
+	bool oplocks:1; /* server supports async oplock breaks */
+	bool echos:1; /* server supports async echos */
+	unsigned int echo_credits; /* reserve for echos */
+	unsigned int oplock_credits; /* reserve for oplock breaks */
+	unsigned int credits;  /* send no more requests at once */
 	unsigned int in_flight;  /* number of requests on the wire to server */
 	spinlock_t req_lock;  /* protect the two values above */
 	struct mutex srv_mutex;
@@ -309,6 +302,12 @@ struct TCP_Server_Info {
 #endif
 };
 
+/*
+ * The minimal value to set before negotiating and don't issue extra messaging
+ * in cifs_change_conf.
+ */
+#define CIFS_CREDITS_DEFAULT 3
+
 static inline unsigned int
 in_flight(struct TCP_Server_Info *server)
 {
@@ -319,31 +318,31 @@ in_flight(struct TCP_Server_Info *server)
 	return num;
 }
 
-static inline int
-get_credits(struct TCP_Server_Info *server)
-{
-	int num;
-	spin_lock(&server->req_lock);
-	num = server->credits;
-	spin_unlock(&server->req_lock);
-	return num;
-}
+#define   CIFS_OBREAK_OP    0x080    /* oplock break request */
+#define   CIFS_ECHO_OP     0x0100    /* echo request */
+#define   CIFS_REQ_MASK    0x0180    /* mask request type */
 
-static inline void
-add_credits(struct TCP_Server_Info *server, unsigned int add)
+static inline unsigned int*
+get_credits_field(struct TCP_Server_Info *server, const int optype)
 {
-	spin_lock(&server->req_lock);
-	server->credits += add;
-	server->in_flight--;
-	spin_unlock(&server->req_lock);
+	switch (optype) {
+	case CIFS_ECHO_OP:
+		return &server->echo_credits;
+	case CIFS_OBREAK_OP:
+		return &server->oplock_credits;
+	default:
+		return &server->credits;
+	}
 }
 
-static inline void
-set_credits(struct TCP_Server_Info *server, int val)
+static inline bool
+has_free_credits(struct TCP_Server_Info *server, unsigned int *val)
 {
+	bool res;
 	spin_lock(&server->req_lock);
-	server->credits = val;
+	res = *val > 0;
 	spin_unlock(&server->req_lock);
+	return res;
 }
 
 /*
@@ -1047,7 +1046,6 @@ GLOBAL_EXTERN unsigned int linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/
 GLOBAL_EXTERN unsigned int CIFSMaxBufSize;  /* max size not including hdr */
 GLOBAL_EXTERN unsigned int cifs_min_rcv;    /* min size of big ntwrk buf pool */
 GLOBAL_EXTERN unsigned int cifs_min_small;  /* min size of small buf pool */
-GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/
 
 #ifdef CONFIG_CIFS_ACL
 GLOBAL_EXTERN struct rb_root uidtree;
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 6f4e243..75163a6 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -71,7 +71,7 @@ extern void DeleteMidQEntry(struct mid_q_entry *midEntry);
 extern int cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
 			   unsigned int nvec, mid_receive_t *receive,
 			   mid_callback_t *callback, void *cbdata,
-			   bool ignore_pend);
+			   int optype);
 extern int SendReceive(const unsigned int /* xid */ , struct cifs_ses *,
 			struct smb_hdr * /* input */ ,
 			struct smb_hdr * /* out */ ,
@@ -169,6 +169,11 @@ extern struct smb_vol *cifs_get_volume_info(char *mount_data,
 extern int cifs_mount(struct cifs_sb_info *, struct smb_vol *);
 extern void cifs_umount(struct cifs_sb_info *);
 extern void cifs_dfs_release_automount_timer(void);
+extern int cifs_reconnect(struct TCP_Server_Info *server);
+extern void cifs_change_conf(struct TCP_Server_Info *server);
+extern void add_credits(struct TCP_Server_Info *server, unsigned int add,
+			const int optype);
+extern void set_credits(struct TCP_Server_Info *server, unsigned int val);
 void cifs_proc_init(void);
 void cifs_proc_clean(void);
 
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index c255c25..985dcce 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -459,6 +459,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
 		}
 		server->sec_mode = (__u8)le16_to_cpu(rsp->SecurityMode);
 		server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
+		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
@@ -565,6 +566,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
 	/* one byte, so no need to convert this or EncryptionKeyLen from
 	   little endian */
 	server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
+	set_credits(server, server->maxReq);
 	/* probably no need to store and check maxvcs */
 	server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
 	server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
@@ -716,7 +718,7 @@ cifs_echo_callback(struct mid_q_entry *mid)
 	struct TCP_Server_Info *server = mid->callback_data;
 
 	DeleteMidQEntry(mid);
-	add_credits(server, 1);
+	add_credits(server, 1, CIFS_ECHO_OP);
 	wake_up(&server->request_q);
 }
 
@@ -744,7 +746,7 @@ CIFSSMBEcho(struct TCP_Server_Info *server)
 	iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
 
 	rc = cifs_call_async(server, &iov, 1, NULL, cifs_echo_callback,
-			     server, true);
+			     server, CIFS_ECHO_OP);
 	if (rc)
 		cFYI(1, "Echo request failed: %d", rc);
 
@@ -1669,7 +1671,7 @@ cifs_readv_callback(struct mid_q_entry *mid)
 
 	queue_work(system_nrt_wq, &rdata->work);
 	DeleteMidQEntry(mid);
-	add_credits(server, 1);
+	add_credits(server, 1, 0);
 	wake_up(&server->request_q);
 }
 
@@ -1725,7 +1727,7 @@ cifs_async_readv(struct cifs_readdata *rdata)
 
 	rc = cifs_call_async(tcon->ses->server, rdata->iov, 1,
 			     cifs_readv_receive, cifs_readv_callback,
-			     rdata, false);
+			     rdata, 0);
 
 	if (rc == 0)
 		cifs_stats_inc(&tcon->num_reads);
@@ -2110,7 +2112,7 @@ cifs_writev_callback(struct mid_q_entry *mid)
 
 	queue_work(system_nrt_wq, &wdata->work);
 	DeleteMidQEntry(mid);
-	add_credits(tcon->ses->server, 1);
+	add_credits(tcon->ses->server, 1, 0);
 	wake_up(&tcon->ses->server->request_q);
 }
 
@@ -2194,7 +2196,7 @@ cifs_async_writev(struct cifs_writedata *wdata)
 
 	kref_get(&wdata->refcount);
 	rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1,
-			     NULL, cifs_writev_callback, wdata, false);
+			     NULL, cifs_writev_callback, wdata, 0);
 
 	if (rc == 0)
 		cifs_stats_inc(&tcon->num_writes);
@@ -2382,7 +2384,7 @@ CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
 		return rc;
 
 	if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
-		timeout = CIFS_ASYNC_OP; /* no response expected */
+		timeout = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
 		pSMB->Timeout = 0;
 	} else if (waitFlag) {
 		timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 86d7a40..aa97dab 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -78,7 +78,7 @@ static int cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data,
  * reconnect tcp session
  * wake up waiters on reconnection? - (not needed currently)
  */
-static int
+int
 cifs_reconnect(struct TCP_Server_Info *server)
 {
 	int rc = 0;
@@ -324,7 +324,7 @@ cifs_echo_request(struct work_struct *work)
 	 * done, which is indicated by maxBuf != 0. Also, no need to ping if
 	 * we got a response recently
 	 */
-	if (server->maxBuf == 0 ||
+	if (!server->echos || server->maxBuf == 0 ||
 	    time_before(jiffies, server->lstrp + SMB_ECHO_INTERVAL - HZ))
 		goto requeue_echo;
 
@@ -1901,7 +1901,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
 	tcp_ses->noautotune = volume_info->noautotune;
 	tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay;
 	tcp_ses->in_flight = 0;
-	tcp_ses->credits = cifs_max_pending;
+	tcp_ses->credits = CIFS_CREDITS_DEFAULT;
 	init_waitqueue_head(&tcp_ses->response_q);
 	init_waitqueue_head(&tcp_ses->request_q);
 	INIT_LIST_HEAD(&tcp_ses->pending_mid_q);
@@ -3751,11 +3751,11 @@ int cifs_negotiate_protocol(unsigned int xid, struct cifs_ses *ses)
 	if (server->maxBuf != 0)
 		return 0;
 
-	set_credits(server, cifs_max_pending);
+	set_credits(server, CIFS_CREDITS_DEFAULT);
 	rc = CIFSSMBNegotiate(xid, ses);
 	if (rc == -EAGAIN) {
 		/* retry only once on 1st time connection */
-		set_credits(server, cifs_max_pending);
+		set_credits(server, CIFS_CREDITS_DEFAULT);
 		rc = CIFSSMBNegotiate(xid, ses);
 		if (rc == -EAGAIN)
 			rc = -EHOSTDOWN;
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 63a196b..e183e38 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -171,7 +171,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
 	}
 	tcon = tlink_tcon(tlink);
 
-	if (enable_oplocks)
+	if (tcon->ses->server->oplocks)
 		oplock = REQ_OPLOCK;
 
 	if (nd)
@@ -492,7 +492,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
 {
 	int xid;
 	int rc = 0; /* to get around spurious gcc warning, set to zero here */
-	__u32 oplock = enable_oplocks ? REQ_OPLOCK : 0;
+	__u32 oplock;
 	__u16 fileHandle = 0;
 	bool posix_open = false;
 	struct cifs_sb_info *cifs_sb;
@@ -517,6 +517,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
 		return (struct dentry *)tlink;
 	}
 	pTcon = tlink_tcon(tlink);
+	oplock = pTcon->ses->server->oplocks ? REQ_OPLOCK : 0;
 
 	/*
 	 * Don't allow the separator character in a path component.
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 4dd9283..b5e38b1 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -380,7 +380,7 @@ int cifs_open(struct inode *inode, struct file *file)
 	cFYI(1, "inode = 0x%p file flags are 0x%x for %s",
 		 inode, file->f_flags, full_path);
 
-	if (enable_oplocks)
+	if (tcon->ses->server->oplocks)
 		oplock = REQ_OPLOCK;
 	else
 		oplock = 0;
@@ -505,7 +505,7 @@ static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
 	cFYI(1, "inode = 0x%p file flags 0x%x for %s",
 		 inode, pCifsFile->f_flags, full_path);
 
-	if (enable_oplocks)
+	if (tcon->ses->server->oplocks)
 		oplock = REQ_OPLOCK;
 	else
 		oplock = 0;
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 703ef5c..e14dc8f 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -690,3 +690,52 @@ backup_cred(struct cifs_sb_info *cifs_sb)
 
 	return false;
 }
+
+void
+cifs_change_conf(struct TCP_Server_Info *server)
+{
+	server->oplock_credits = server->echo_credits = 0;
+	switch (server->credits) {
+	case 0:
+		cifs_reconnect(server);
+		return;
+	case 1:
+		server->echos = false;
+		server->oplocks = false;
+		cERROR(1, "disabling echos and oplocks");
+		break;
+	case 2:
+		server->echos = true;
+		server->oplocks = false;
+		server->echo_credits = 1;
+		cFYI(1, "disabling oplocks");
+		break;
+	default:
+		server->echos = true;
+		server->oplocks = true;
+		server->echo_credits = 1;
+		server->oplock_credits = 1;
+	}
+	server->credits -= server->echo_credits + server->oplock_credits;
+}
+
+void
+add_credits(struct TCP_Server_Info *server, const unsigned int add,
+	    const int optype)
+{
+	unsigned int *val;
+	spin_lock(&server->req_lock);
+	val = get_credits_field(server, optype);
+	*val += add;
+	server->in_flight--;
+	spin_unlock(&server->req_lock);
+}
+
+void
+set_credits(struct TCP_Server_Info *server, const unsigned int val)
+{
+	spin_lock(&server->req_lock);
+	server->credits = val;
+	cifs_change_conf(server);
+	spin_unlock(&server->req_lock);
+}
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 938d20b..91f009d 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -255,44 +255,41 @@ smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
 }
 
 static int
-wait_for_free_request(struct TCP_Server_Info *server, const int long_op)
+wait_for_free_credits(struct TCP_Server_Info *server, unsigned int *num)
 {
 	int rc;
 
-	spin_lock(&server->req_lock);
-
-	if (long_op == CIFS_ASYNC_OP) {
-		/* oplock breaks must not be held up */
-		server->in_flight++;
-		server->credits--;
-		spin_unlock(&server->req_lock);
-		return 0;
-	}
-
 	while (1) {
-		if (server->credits <= 0) {
+		if (*num == 0) {
 			spin_unlock(&server->req_lock);
 			cifs_num_waiters_inc(server);
 			rc = wait_event_interruptible(server->request_q,
-						      get_credits(server) > 0);
+						has_free_credits(server, num));
 			cifs_num_waiters_dec(server);
 			if (rc)
 				return rc;
 			spin_lock(&server->req_lock);
 		} else {
-			if (server->tcpStatus == CifsExiting) {
-				spin_unlock(&server->req_lock);
+			if (server->tcpStatus == CifsExiting)
 				return -ENOENT;
-			}
-			server->credits--;
+			*num -= 1;
 			server->in_flight++;
-			spin_unlock(&server->req_lock);
 			break;
 		}
 	}
 	return 0;
 }
 
+static int
+wait_for_free_request(struct TCP_Server_Info *server, const int optype)
+{
+	int rc;
+	spin_lock(&server->req_lock);
+	rc = wait_for_free_credits(server, get_credits_field(server, optype));
+	spin_unlock(&server->req_lock);
+	return rc;
+}
+
 static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
 			struct mid_q_entry **ppmidQ)
 {
@@ -342,13 +339,13 @@ wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
 int
 cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
 		unsigned int nvec, mid_receive_t *receive,
-		mid_callback_t *callback, void *cbdata, bool ignore_pend)
+		mid_callback_t *callback, void *cbdata, int optype)
 {
 	int rc;
 	struct mid_q_entry *mid;
 	struct smb_hdr *hdr = (struct smb_hdr *)iov[0].iov_base;
 
-	rc = wait_for_free_request(server, ignore_pend ? CIFS_ASYNC_OP : 0);
+	rc = wait_for_free_request(server, optype);
 	if (rc)
 		return rc;
 
@@ -360,7 +357,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
 	mid = AllocMidQEntry(hdr, server);
 	if (mid == NULL) {
 		mutex_unlock(&server->srv_mutex);
-		add_credits(server, 1);
+		add_credits(server, 1, optype);
 		wake_up(&server->request_q);
 		return -ENOMEM;
 	}
@@ -393,7 +390,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
 	return rc;
 out_err:
 	delete_mid(mid);
-	add_credits(server, 1);
+	add_credits(server, 1, optype);
 	wake_up(&server->request_q);
 	return rc;
 }
@@ -526,10 +523,12 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 {
 	int rc = 0;
 	int long_op;
+	int optype;
 	struct mid_q_entry *midQ;
 	struct smb_hdr *in_buf = iov[0].iov_base;
 
 	long_op = flags & CIFS_TIMEOUT_MASK;
+	optype = flags & CIFS_REQ_MASK;
 
 	*pRespBufType = CIFS_NO_BUFFER;  /* no response buf yet */
 
@@ -548,7 +547,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 	   to the same server. We may make this configurable later or
 	   use ses->maxReq */
 
-	rc = wait_for_free_request(ses->server, long_op);
+	rc = wait_for_free_request(ses->server, optype);
 	if (rc) {
 		cifs_small_buf_release(in_buf);
 		return rc;
@@ -565,7 +564,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 		mutex_unlock(&ses->server->srv_mutex);
 		cifs_small_buf_release(in_buf);
 		/* Update # of requests on wire to server */
-		add_credits(ses->server, 1);
+		add_credits(ses->server, 1, optype);
 		wake_up(&ses->server->request_q);
 		return rc;
 	}
@@ -602,7 +601,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 			midQ->callback = DeleteMidQEntry;
 			spin_unlock(&GlobalMid_Lock);
 			cifs_small_buf_release(in_buf);
-			add_credits(ses->server, 1);
+			add_credits(ses->server, 1, optype);
 			wake_up(&ses->server->request_q);
 			return rc;
 		}
@@ -613,7 +612,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 
 	rc = cifs_sync_mid_result(midQ, ses->server);
 	if (rc != 0) {
-		add_credits(ses->server, 1);
+		add_credits(ses->server, 1, optype);
 		wake_up(&ses->server->request_q);
 		return rc;
 	}
@@ -638,7 +637,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 		midQ->resp_buf = NULL;
 out:
 	delete_mid(midQ);
-	add_credits(ses->server, 1);
+	add_credits(ses->server, 1, optype);
 	wake_up(&ses->server->request_q);
 
 	return rc;
@@ -675,7 +674,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 		return -EIO;
 	}
 
-	rc = wait_for_free_request(ses->server, long_op);
+	rc = wait_for_free_request(ses->server, 0);
 	if (rc)
 		return rc;
 
@@ -689,7 +688,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 	if (rc) {
 		mutex_unlock(&ses->server->srv_mutex);
 		/* Update # of requests on wire to server */
-		add_credits(ses->server, 1);
+		add_credits(ses->server, 1, 0);
 		wake_up(&ses->server->request_q);
 		return rc;
 	}
@@ -722,7 +721,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 			/* no longer considered to be "in-flight" */
 			midQ->callback = DeleteMidQEntry;
 			spin_unlock(&GlobalMid_Lock);
-			add_credits(ses->server, 1);
+			add_credits(ses->server, 1, 0);
 			wake_up(&ses->server->request_q);
 			return rc;
 		}
@@ -731,7 +730,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 
 	rc = cifs_sync_mid_result(midQ, ses->server);
 	if (rc != 0) {
-		add_credits(ses->server, 1);
+		add_credits(ses->server, 1, 0);
 		wake_up(&ses->server->request_q);
 		return rc;
 	}
@@ -748,7 +747,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 	rc = cifs_check_receive(midQ, ses->server, 0);
 out:
 	delete_mid(midQ);
-	add_credits(ses->server, 1);
+	add_credits(ses->server, 1, 0);
 	wake_up(&ses->server->request_q);
 
 	return rc;
@@ -827,7 +826,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 	rc = allocate_mid(ses, in_buf, &midQ);
 	if (rc) {
 		mutex_unlock(&ses->server->srv_mutex);
-		add_credits(ses->server, 1);
+		add_credits(ses->server, 1, 0);
 		wake_up(&ses->server->request_q);
 		return rc;
 	}
@@ -836,7 +835,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 	if (rc) {
 		delete_mid(midQ);
 		mutex_unlock(&ses->server->srv_mutex);
-		add_credits(ses->server, 1);
+		add_credits(ses->server, 1, 0);
 		wake_up(&ses->server->request_q);
 		return rc;
 	}
@@ -850,7 +849,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 
 	if (rc < 0) {
 		delete_mid(midQ);
-		add_credits(ses->server, 1);
+		add_credits(ses->server, 1, 0);
 		wake_up(&ses->server->request_q);
 		return rc;
 	}
@@ -873,7 +872,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 			rc = send_nt_cancel(ses->server, in_buf, midQ);
 			if (rc) {
 				delete_mid(midQ);
-				add_credits(ses->server, 1);
+				add_credits(ses->server, 1, 0);
 				wake_up(&ses->server->request_q);
 				return rc;
 			}
@@ -887,7 +886,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 			   already been removed. Don't exit in this case. */
 			if (rc && rc != -ENOLCK) {
 				delete_mid(midQ);
-				add_credits(ses->server, 1);
+				add_credits(ses->server, 1, 0);
 				wake_up(&ses->server->request_q);
 				return rc;
 			}
@@ -901,7 +900,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 				/* no longer considered to be "in-flight" */
 				midQ->callback = DeleteMidQEntry;
 				spin_unlock(&GlobalMid_Lock);
-				add_credits(ses->server, 1);
+				add_credits(ses->server, 1, 0);
 				wake_up(&ses->server->request_q);
 				return rc;
 			}
@@ -914,7 +913,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 
 	rc = cifs_sync_mid_result(midQ, ses->server);
 	if (rc != 0) {
-		add_credits(ses->server, 1);
+		add_credits(ses->server, 1, 0);
 		wake_up(&ses->server->request_q);
 		return rc;
 	}
@@ -931,7 +930,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 	rc = cifs_check_receive(midQ, ses->server, 0);
 out:
 	delete_mid(midQ);
-	add_credits(ses->server, 1);
+	add_credits(ses->server, 1, 0);
 	wake_up(&ses->server->request_q);
 	if (rstart && rc == -EACCES)
 		return -ERESTARTSYS;
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 07/11] CIFS: Separate protocol-specific code from transport routines
       [not found] ` <1329895984-9251-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
                     ` (5 preceding siblings ...)
  2012-02-22  7:32   ` [PATCH 06/11] CIFS: Respect MaxMpxCount field Pavel Shilovsky
@ 2012-02-22  7:33   ` Pavel Shilovsky
       [not found]     ` <1329895984-9251-8-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
  2012-02-22  7:33   ` [PATCH 08/11] CIFS: Separate protocol-specific code from demultiplex code Pavel Shilovsky
                     ` (3 subsequent siblings)
  10 siblings, 1 reply; 51+ messages in thread
From: Pavel Shilovsky @ 2012-02-22  7:33 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

that lets us use this functions for SMB2.

Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
 fs/cifs/cifs_debug.h |    2 +-
 fs/cifs/cifsglob.h   |    6 ++
 fs/cifs/cifsproto.h  |    2 +-
 fs/cifs/cifssmb.c    |   21 +++---
 fs/cifs/misc.c       |    5 +-
 fs/cifs/transport.c  |  171 +++++++++++++++++++++++++++++---------------------
 6 files changed, 119 insertions(+), 88 deletions(-)

diff --git a/fs/cifs/cifs_debug.h b/fs/cifs/cifs_debug.h
index 8942b28..0a234c1 100644
--- a/fs/cifs/cifs_debug.h
+++ b/fs/cifs/cifs_debug.h
@@ -32,7 +32,7 @@ void cifs_dump_mids(struct TCP_Server_Info *);
 #define DBG2 0
 #endif
 extern int traceSMB;		/* flag which enables the function below */
-void dump_smb(struct smb_hdr *, int);
+void dump_smb(void *, int);
 #define CIFS_INFO	0x01
 #define CIFS_RC		0x02
 #define CIFS_TIMER	0x04
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 4b13be5..e56baca 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -224,6 +224,12 @@ struct cifs_mnt_data {
 	int flags;
 };
 
+static inline unsigned int
+get_rfc1002_length(void *buf)
+{
+	return be32_to_cpu(*((__be32 *)buf));
+}
+
 struct TCP_Server_Info {
 	struct list_head tcp_ses_list;
 	struct list_head smb_ses_list;
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 75163a6..6ba8d1c 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -77,7 +77,7 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifs_ses *,
 			struct smb_hdr * /* out */ ,
 			int * /* bytes returned */ , const int long_op);
 extern int SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
-			struct smb_hdr *in_buf, int flags);
+			    char *in_buf, int flags);
 extern int cifs_check_receive(struct mid_q_entry *mid,
 			struct TCP_Server_Info *server, bool log_error);
 extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 985dcce..5ba869f 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -693,7 +693,7 @@ CIFSSMBTDis(const int xid, struct cifs_tcon *tcon)
 	if (rc)
 		return rc;
 
-	rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
+	rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
 	if (rc)
 		cFYI(1, "Tree disconnect failed %d", rc);
 
@@ -790,7 +790,7 @@ CIFSSMBLogoff(const int xid, struct cifs_ses *ses)
 	pSMB->hdr.Uid = ses->Suid;
 
 	pSMB->AndXCommand = 0xFF;
-	rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
+	rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
 session_already_dead:
 	mutex_unlock(&ses->session_mutex);
 
@@ -2420,8 +2420,7 @@ CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
 			(struct smb_hdr *) pSMB, &bytes_returned);
 		cifs_small_buf_release(pSMB);
 	} else {
-		rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
-				      timeout);
+		rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, timeout);
 		/* SMB buffer freed by function above */
 	}
 	cifs_stats_inc(&tcon->num_locks);
@@ -2588,7 +2587,7 @@ CIFSSMBClose(const int xid, struct cifs_tcon *tcon, int smb_file_id)
 	pSMB->FileID = (__u16) smb_file_id;
 	pSMB->LastWriteTime = 0xFFFFFFFF;
 	pSMB->ByteCount = 0;
-	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
 	cifs_stats_inc(&tcon->num_closes);
 	if (rc) {
 		if (rc != -EINTR) {
@@ -2617,7 +2616,7 @@ CIFSSMBFlush(const int xid, struct cifs_tcon *tcon, int smb_file_id)
 
 	pSMB->FileID = (__u16) smb_file_id;
 	pSMB->ByteCount = 0;
-	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
 	cifs_stats_inc(&tcon->num_flushes);
 	if (rc)
 		cERROR(1, "Send error in Flush = %d", rc);
@@ -4625,7 +4624,7 @@ CIFSFindClose(const int xid, struct cifs_tcon *tcon,
 
 	pSMB->FileID = searchHandle;
 	pSMB->ByteCount = 0;
-	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
 	if (rc)
 		cERROR(1, "Send error in FindClose = %d", rc);
 
@@ -5646,7 +5645,7 @@ CIFSSMBSetFileSize(const int xid, struct cifs_tcon *tcon, __u64 size,
 	pSMB->Reserved4 = 0;
 	inc_rfc1001_len(pSMB, byte_count);
 	pSMB->ByteCount = cpu_to_le16(byte_count);
-	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
 	if (rc) {
 		cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
 	}
@@ -5715,7 +5714,7 @@ CIFSSMBSetFileInfo(const int xid, struct cifs_tcon *tcon,
 	inc_rfc1001_len(pSMB, byte_count);
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 	memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
-	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
 	if (rc)
 		cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
 
@@ -5774,7 +5773,7 @@ CIFSSMBSetFileDisposition(const int xid, struct cifs_tcon *tcon,
 	inc_rfc1001_len(pSMB, byte_count);
 	pSMB->ByteCount = cpu_to_le16(byte_count);
 	*data_offset = delete_file ? 1 : 0;
-	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
 	if (rc)
 		cFYI(1, "Send error in SetFileDisposition = %d", rc);
 
@@ -6006,7 +6005,7 @@ CIFSSMBUnixSetFileInfo(const int xid, struct cifs_tcon *tcon,
 
 	cifs_fill_unix_set_info(data_offset, args);
 
-	rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
 	if (rc)
 		cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
 
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index e14dc8f..8e7516f 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -604,16 +604,15 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
 }
 
 void
-dump_smb(struct smb_hdr *smb_buf, int smb_buf_length)
+dump_smb(void *buf, int smb_buf_length)
 {
 	int i, j;
 	char debug_line[17];
-	unsigned char *buffer;
+	unsigned char *buffer = buf;
 
 	if (traceSMB == 0)
 		return;
 
-	buffer = (unsigned char *) smb_buf;
 	for (i = 0, j = 0; i < smb_buf_length; i++, j++) {
 		if (i % 8 == 0) {
 			/* have reached the beginning of line */
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 91f009d..0d2707e 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -126,11 +126,11 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
 	int rc = 0;
 	int i = 0;
 	struct msghdr smb_msg;
-	struct smb_hdr *smb_buffer = iov[0].iov_base;
+	__be32 *buf_len = (__be32 *)(iov[0].iov_base);
 	unsigned int len = iov[0].iov_len;
 	unsigned int total_len;
 	int first_vec = 0;
-	unsigned int smb_buf_length = be32_to_cpu(smb_buffer->smb_buf_length);
+	unsigned int smb_buf_length = get_rfc1002_length(iov[0].iov_base);
 	struct socket *ssocket = server->ssocket;
 
 	if (ssocket == NULL)
@@ -150,7 +150,7 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
 		total_len += iov[i].iov_len;
 
 	cFYI(1, "Sending smb:  total_len %d", total_len);
-	dump_smb(smb_buffer, len);
+	dump_smb(iov[0].iov_base, len);
 
 	i = 0;
 	while (total_len) {
@@ -158,24 +158,24 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
 				    n_vec - first_vec, total_len);
 		if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
 			i++;
-			/* if blocking send we try 3 times, since each can block
-			   for 5 seconds. For nonblocking  we have to try more
-			   but wait increasing amounts of time allowing time for
-			   socket to clear.  The overall time we wait in either
-			   case to send on the socket is about 15 seconds.
-			   Similarly we wait for 15 seconds for
-			   a response from the server in SendReceive[2]
-			   for the server to send a response back for
-			   most types of requests (except SMB Write
-			   past end of file which can be slow, and
-			   blocking lock operations). NFS waits slightly longer
-			   than CIFS, but this can make it take longer for
-			   nonresponsive servers to be detected and 15 seconds
-			   is more than enough time for modern networks to
-			   send a packet.  In most cases if we fail to send
-			   after the retries we will kill the socket and
-			   reconnect which may clear the network problem.
-			*/
+			/*
+			 * If blocking send we try 3 times, since each can block
+			 * for 5 seconds. For nonblocking  we have to try more
+			 * but wait increasing amounts of time allowing time for
+			 * socket to clear.  The overall time we wait in either
+			 * case to send on the socket is about 15 seconds.
+			 * Similarly we wait for 15 seconds for a response from
+			 * the server in SendReceive[2] for the server to send
+			 * a response back for most types of requests (except
+			 * SMB Write past end of file which can be slow, and
+			 * blocking lock operations). NFS waits slightly longer
+			 * than CIFS, but this can make it take longer for
+			 * nonresponsive servers to be detected and 15 seconds
+			 * is more than enough time for modern networks to
+			 * send a packet.  In most cases if we fail to send
+			 * after the retries we will kill the socket and
+			 * reconnect which may clear the network problem.
+			 */
 			if ((i >= 14) || (!server->noblocksnd && (i > 2))) {
 				cERROR(1, "sends on sock %p stuck for 15 seconds",
 				    ssocket);
@@ -235,9 +235,8 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
 	else
 		rc = 0;
 
-	/* Don't want to modify the buffer as a
-	   side effect of this call. */
-	smb_buffer->smb_buf_length = cpu_to_be32(smb_buf_length);
+	/* Don't want to modify the buffer as a side effect of this call. */
+	*buf_len = cpu_to_be32(smb_buf_length);
 
 	return rc;
 }
@@ -331,6 +330,33 @@ wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
 	return 0;
 }
 
+static int
+cifs_setup_async_request(struct TCP_Server_Info *server, struct kvec *iov,
+			 unsigned int nvec, struct mid_q_entry **ret_mid)
+{
+	int rc;
+	struct smb_hdr *hdr = (struct smb_hdr *)iov[0].iov_base;
+	struct mid_q_entry *mid;
+
+	/* enable signing if server requires it */
+	if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+		hdr->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+
+	mid = AllocMidQEntry(hdr, server);
+	if (mid == NULL)
+		return -ENOMEM;
+
+	/* put it on the pending_mid_q */
+	spin_lock(&GlobalMid_Lock);
+	list_add_tail(&mid->qhead, &server->pending_mid_q);
+	spin_unlock(&GlobalMid_Lock);
+
+	rc = cifs_sign_smb2(iov, nvec, server, &mid->sequence_number);
+	if (rc)
+		delete_mid(mid);
+	*ret_mid = mid;
+	return rc;
+}
 
 /*
  * Send a SMB request and set the callback function in the mid to handle
@@ -343,34 +369,18 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
 {
 	int rc;
 	struct mid_q_entry *mid;
-	struct smb_hdr *hdr = (struct smb_hdr *)iov[0].iov_base;
 
 	rc = wait_for_free_request(server, optype);
 	if (rc)
 		return rc;
 
-	/* enable signing if server requires it */
-	if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
-		hdr->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
-
 	mutex_lock(&server->srv_mutex);
-	mid = AllocMidQEntry(hdr, server);
-	if (mid == NULL) {
+	rc = cifs_setup_async_request(server, iov, nvec, &mid);
+	if (rc) {
 		mutex_unlock(&server->srv_mutex);
 		add_credits(server, 1, optype);
 		wake_up(&server->request_q);
-		return -ENOMEM;
-	}
-
-	/* put it on the pending_mid_q */
-	spin_lock(&GlobalMid_Lock);
-	list_add_tail(&mid->qhead, &server->pending_mid_q);
-	spin_unlock(&GlobalMid_Lock);
-
-	rc = cifs_sign_smb2(iov, nvec, server, &mid->sequence_number);
-	if (rc) {
-		mutex_unlock(&server->srv_mutex);
-		goto out_err;
+		return rc;
 	}
 
 	mid->receive = receive;
@@ -406,14 +416,14 @@ out_err:
  */
 int
 SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
-		struct smb_hdr *in_buf, int flags)
+		 char *in_buf, int flags)
 {
 	int rc;
 	struct kvec iov[1];
 	int resp_buf_type;
 
-	iov[0].iov_base = (char *)in_buf;
-	iov[0].iov_len = be32_to_cpu(in_buf->smb_buf_length) + 4;
+	iov[0].iov_base = in_buf;
+	iov[0].iov_len = get_rfc1002_length(in_buf) + 4;
 	flags |= CIFS_NO_RESP;
 	rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags);
 	cFYI(DBG2, "SendRcvNoRsp flags %d rc %d", flags, rc);
@@ -496,7 +506,7 @@ int
 cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
 		   bool log_error)
 {
-	unsigned int len = be32_to_cpu(mid->resp_buf->smb_buf_length) + 4;
+	unsigned int len = get_rfc1002_length(mid->resp_buf) + 4;
 
 	dump_smb(mid->resp_buf, min_t(u32, 92, len));
 
@@ -516,6 +526,24 @@ cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
 	return map_smb_to_linux_error(mid->resp_buf, log_error);
 }
 
+static int
+cifs_setup_request(struct cifs_ses *ses, struct kvec *iov,
+		   unsigned int nvec, struct mid_q_entry **ret_mid)
+{
+	int rc;
+	struct smb_hdr *hdr = (struct smb_hdr *)iov[0].iov_base;
+	struct mid_q_entry *mid;
+
+	rc = allocate_mid(ses, hdr, &mid);
+	if (rc)
+		return rc;
+	rc = cifs_sign_smb2(iov, nvec, ses->server, &mid->sequence_number);
+	if (rc)
+		delete_mid(mid);
+	*ret_mid = mid;
+	return rc;
+}
+
 int
 SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 	     struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
@@ -525,7 +553,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 	int long_op;
 	int optype;
 	struct mid_q_entry *midQ;
-	struct smb_hdr *in_buf = iov[0].iov_base;
+	char *buf = iov[0].iov_base;
 
 	long_op = flags & CIFS_TIMEOUT_MASK;
 	optype = flags & CIFS_REQ_MASK;
@@ -533,47 +561,45 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 	*pRespBufType = CIFS_NO_BUFFER;  /* no response buf yet */
 
 	if ((ses == NULL) || (ses->server == NULL)) {
-		cifs_small_buf_release(in_buf);
+		cifs_small_buf_release(buf);
 		cERROR(1, "Null session");
 		return -EIO;
 	}
 
 	if (ses->server->tcpStatus == CifsExiting) {
-		cifs_small_buf_release(in_buf);
+		cifs_small_buf_release(buf);
 		return -ENOENT;
 	}
 
-	/* Ensure that we do not send more than 50 overlapping requests
-	   to the same server. We may make this configurable later or
-	   use ses->maxReq */
+	/*
+	 * Ensure that we do not send more than 50 overlapping requests
+	 * to the same server. We may make this configurable later or
+	 * use ses->maxReq.
+	 */
 
 	rc = wait_for_free_request(ses->server, optype);
 	if (rc) {
-		cifs_small_buf_release(in_buf);
+		cifs_small_buf_release(buf);
 		return rc;
 	}
 
-	/* make sure that we sign in the same order that we send on this socket
-	   and avoid races inside tcp sendmsg code that could cause corruption
-	   of smb data */
+	/*
+	 * Make sure that we sign in the same order that we send on this socket
+	 * and avoid races inside tcp sendmsg code that could cause corruption
+	 * of smb data.
+	 */
 
 	mutex_lock(&ses->server->srv_mutex);
 
-	rc = allocate_mid(ses, in_buf, &midQ);
+	rc = cifs_setup_request(ses, iov, n_vec, &midQ);
 	if (rc) {
 		mutex_unlock(&ses->server->srv_mutex);
-		cifs_small_buf_release(in_buf);
+		cifs_small_buf_release(buf);
 		/* Update # of requests on wire to server */
 		add_credits(ses->server, 1, optype);
 		wake_up(&ses->server->request_q);
 		return rc;
 	}
-	rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
-	if (rc) {
-		mutex_unlock(&ses->server->srv_mutex);
-		cifs_small_buf_release(in_buf);
-		goto out;
-	}
 
 	midQ->midState = MID_REQUEST_SUBMITTED;
 	cifs_in_send_inc(ses->server);
@@ -584,23 +610,23 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 	mutex_unlock(&ses->server->srv_mutex);
 
 	if (rc < 0) {
-		cifs_small_buf_release(in_buf);
+		cifs_small_buf_release(buf);
 		goto out;
 	}
 
 	if (long_op == CIFS_ASYNC_OP) {
-		cifs_small_buf_release(in_buf);
+		cifs_small_buf_release(buf);
 		goto out;
 	}
 
 	rc = wait_for_response(ses->server, midQ);
 	if (rc != 0) {
-		send_nt_cancel(ses->server, in_buf, midQ);
+		send_nt_cancel(ses->server, (struct smb_hdr *)buf, midQ);
 		spin_lock(&GlobalMid_Lock);
 		if (midQ->midState == MID_REQUEST_SUBMITTED) {
 			midQ->callback = DeleteMidQEntry;
 			spin_unlock(&GlobalMid_Lock);
-			cifs_small_buf_release(in_buf);
+			cifs_small_buf_release(buf);
 			add_credits(ses->server, 1, optype);
 			wake_up(&ses->server->request_q);
 			return rc;
@@ -608,7 +634,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 		spin_unlock(&GlobalMid_Lock);
 	}
 
-	cifs_small_buf_release(in_buf);
+	cifs_small_buf_release(buf);
 
 	rc = cifs_sync_mid_result(midQ, ses->server);
 	if (rc != 0) {
@@ -623,8 +649,9 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 		goto out;
 	}
 
-	iov[0].iov_base = (char *)midQ->resp_buf;
-	iov[0].iov_len = be32_to_cpu(midQ->resp_buf->smb_buf_length) + 4;
+	buf = (char *)midQ->resp_buf;
+	iov[0].iov_base = buf;
+	iov[0].iov_len = get_rfc1002_length(buf) + 4;
 	if (midQ->largeBuf)
 		*pRespBufType = CIFS_LARGE_BUFFER;
 	else
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 08/11] CIFS: Separate protocol-specific code from demultiplex code
       [not found] ` <1329895984-9251-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
                     ` (6 preceding siblings ...)
  2012-02-22  7:33   ` [PATCH 07/11] CIFS: Separate protocol-specific code from transport routines Pavel Shilovsky
@ 2012-02-22  7:33   ` Pavel Shilovsky
  2012-02-22  7:33   ` [PATCH 09/11] CIFS: Separate protocol-specific code from cifs_readv_receive code Pavel Shilovsky
                     ` (2 subsequent siblings)
  10 siblings, 0 replies; 51+ messages in thread
From: Pavel Shilovsky @ 2012-02-22  7:33 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
 fs/cifs/cifs_debug.c |    5 ++-
 fs/cifs/cifs_debug.h |    2 +-
 fs/cifs/cifsglob.h   |    2 +-
 fs/cifs/cifsproto.h  |    5 +--
 fs/cifs/connect.c    |   78 +++++++++++++++++++++++++++-----------------------
 fs/cifs/misc.c       |    7 +++-
 fs/cifs/transport.c  |    4 +-
 7 files changed, 56 insertions(+), 47 deletions(-)

diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
index 573b899..bcd0db7 100644
--- a/fs/cifs/cifs_debug.c
+++ b/fs/cifs/cifs_debug.c
@@ -58,15 +58,16 @@ cifs_dump_mem(char *label, void *data, int length)
 }
 
 #ifdef CONFIG_CIFS_DEBUG2
-void cifs_dump_detail(struct smb_hdr *smb)
+void cifs_dump_detail(void *buf)
 {
+	struct smb_hdr *smb = (struct smb_hdr *)buf;
+
 	cERROR(1, "Cmd: %d Err: 0x%x Flags: 0x%x Flgs2: 0x%x Mid: %d Pid: %d",
 		  smb->Command, smb->Status.CifsError,
 		  smb->Flags, smb->Flags2, smb->Mid, smb->Pid);
 	cERROR(1, "smb buf %p len %d", smb, smbCalcSize(smb));
 }
 
-
 void cifs_dump_mids(struct TCP_Server_Info *server)
 {
 	struct list_head *tmp;
diff --git a/fs/cifs/cifs_debug.h b/fs/cifs/cifs_debug.h
index 0a234c1..566e0ae 100644
--- a/fs/cifs/cifs_debug.h
+++ b/fs/cifs/cifs_debug.h
@@ -26,7 +26,7 @@
 void cifs_dump_mem(char *label, void *data, int length);
 #ifdef CONFIG_CIFS_DEBUG2
 #define DBG2 2
-void cifs_dump_detail(struct smb_hdr *);
+void cifs_dump_detail(void *);
 void cifs_dump_mids(struct TCP_Server_Info *);
 #else
 #define DBG2 0
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index e56baca..e95b8b1 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -740,7 +740,7 @@ struct mid_q_entry {
 	mid_receive_t *receive; /* call receive callback */
 	mid_callback_t *callback; /* call completion callback */
 	void *callback_data;	  /* general purpose pointer for callback */
-	struct smb_hdr *resp_buf;	/* pointer to received SMB header */
+	void *resp_buf;		/* pointer to received SMB header */
 	int midState;	/* wish this were enum but can not pass to wait_event */
 	__u8 command;	/* smb command code */
 	bool largeBuf:1;	/* if valid response, is pointer to large buf */
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 6ba8d1c..97a400c 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -88,9 +88,8 @@ extern int SendReceiveBlockingLock(const unsigned int xid,
 			struct smb_hdr *in_buf ,
 			struct smb_hdr *out_buf,
 			int *bytes_returned);
-extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length);
-extern bool is_valid_oplock_break(struct smb_hdr *smb,
-				  struct TCP_Server_Info *);
+extern int checkSMB(char *buf, unsigned int length);
+extern bool is_valid_oplock_break(char *, struct TCP_Server_Info *);
 extern bool backup_cred(struct cifs_sb_info *);
 extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof);
 extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index aa97dab..efb0a44 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -183,8 +183,9 @@ cifs_reconnect(struct TCP_Server_Info *server)
 		-EINVAL = invalid transact2
 
  */
-static int check2ndT2(struct smb_hdr *pSMB)
+static int check2ndT2(char *buf)
 {
+	struct smb_hdr *pSMB = (struct smb_hdr *)buf;
 	struct smb_t2_rsp *pSMBt;
 	int remaining;
 	__u16 total_data_size, data_in_this_rsp;
@@ -224,10 +225,10 @@ static int check2ndT2(struct smb_hdr *pSMB)
 	return remaining;
 }
 
-static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
+static int coalesce_t2(char *second_buf, struct smb_hdr *target_hdr)
 {
-	struct smb_t2_rsp *pSMBs = (struct smb_t2_rsp *)psecond;
-	struct smb_t2_rsp *pSMBt  = (struct smb_t2_rsp *)pTargetSMB;
+	struct smb_t2_rsp *pSMBs = (struct smb_t2_rsp *)second_buf;
+	struct smb_t2_rsp *pSMBt  = (struct smb_t2_rsp *)target_hdr;
 	char *data_area_of_tgt;
 	char *data_area_of_src;
 	int remaining;
@@ -280,23 +281,23 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
 	put_unaligned_le16(total_in_tgt, &pSMBt->t2_rsp.DataCount);
 
 	/* fix up the BCC */
-	byte_count = get_bcc(pTargetSMB);
+	byte_count = get_bcc(target_hdr);
 	byte_count += total_in_src;
 	/* is the result too big for the field? */
 	if (byte_count > USHRT_MAX) {
 		cFYI(1, "coalesced BCC too large (%u)", byte_count);
 		return -EPROTO;
 	}
-	put_bcc(byte_count, pTargetSMB);
+	put_bcc(byte_count, target_hdr);
 
-	byte_count = be32_to_cpu(pTargetSMB->smb_buf_length);
+	byte_count = be32_to_cpu(target_hdr->smb_buf_length);
 	byte_count += total_in_src;
 	/* don't allow buffer to overflow */
 	if (byte_count > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
 		cFYI(1, "coalesced BCC exceeds buffer size (%u)", byte_count);
 		return -ENOBUFS;
 	}
-	pTargetSMB->smb_buf_length = cpu_to_be32(byte_count);
+	target_hdr->smb_buf_length = cpu_to_be32(byte_count);
 
 	/* copy second buffer into end of first buffer */
 	memcpy(data_area_of_tgt, data_area_of_src, total_in_src);
@@ -337,6 +338,18 @@ requeue_echo:
 	queue_delayed_work(system_nrt_wq, &server->echo, SMB_ECHO_INTERVAL);
 }
 
+static inline size_t
+header_size(void)
+{
+	return sizeof(struct smb_hdr);
+}
+
+static inline size_t
+max_header_size(void)
+{
+	return MAX_CIFS_HDR_SIZE;
+}
+
 static bool
 allocate_buffers(struct TCP_Server_Info *server)
 {
@@ -350,7 +363,7 @@ allocate_buffers(struct TCP_Server_Info *server)
 		}
 	} else if (server->large_buf) {
 		/* we are reusing a dirty large buf, clear its start */
-		memset(server->bigbuf, 0, sizeof(struct smb_hdr));
+		memset(server->bigbuf, 0, header_size());
 	}
 
 	if (!server->smallbuf) {
@@ -364,7 +377,7 @@ allocate_buffers(struct TCP_Server_Info *server)
 		/* beginning of smb buffer is cleared in our buf_get */
 	} else {
 		/* if existing small buf clear beginning */
-		memset(server->smallbuf, 0, sizeof(struct smb_hdr));
+		memset(server->smallbuf, 0, header_size());
 	}
 
 	return true;
@@ -555,8 +568,9 @@ is_smb_response(struct TCP_Server_Info *server, unsigned char type)
 }
 
 static struct mid_q_entry *
-find_mid(struct TCP_Server_Info *server, struct smb_hdr *buf)
+find_mid(struct TCP_Server_Info *server, char *buffer)
 {
+	struct smb_hdr *buf = (struct smb_hdr *)buffer;
 	struct mid_q_entry *mid;
 
 	spin_lock(&GlobalMid_Lock);
@@ -589,7 +603,7 @@ dequeue_mid(struct mid_q_entry *mid, bool malformed)
 
 static void
 handle_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server,
-	   struct smb_hdr *buf, int malformed)
+	   char *buf, int malformed)
 {
 	if (malformed == 0 && check2ndT2(buf) > 0) {
 		mid->multiRsp = true;
@@ -720,11 +734,10 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 {
 	int length;
 	char *buf = server->smallbuf;
-	struct smb_hdr *smb_buffer = (struct smb_hdr *)buf;
-	unsigned int pdu_length = be32_to_cpu(smb_buffer->smb_buf_length);
+	unsigned int pdu_length = get_rfc1002_length(buf);
 
 	/* make sure this will fit in a large buffer */
-	if (pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
+	if (pdu_length > CIFSMaxBufSize + max_header_size() - 4) {
 		cERROR(1, "SMB response too long (%u bytes)",
 			pdu_length);
 		cifs_reconnect(server);
@@ -735,20 +748,18 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 	/* switch to large buffer if too big for a small one */
 	if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
 		server->large_buf = true;
-		memcpy(server->bigbuf, server->smallbuf, server->total_read);
+		memcpy(server->bigbuf, buf, server->total_read);
 		buf = server->bigbuf;
-		smb_buffer = (struct smb_hdr *)buf;
 	}
 
 	/* now read the rest */
-	length = cifs_read_from_socket(server,
-			  buf + sizeof(struct smb_hdr) - 1,
-			  pdu_length - sizeof(struct smb_hdr) + 1 + 4);
+	length = cifs_read_from_socket(server, buf + header_size() - 1,
+				       pdu_length - header_size() + 1 + 4);
 	if (length < 0)
 		return length;
 	server->total_read += length;
 
-	dump_smb(smb_buffer, server->total_read);
+	dump_smb(buf, server->total_read);
 
 	/*
 	 * We know that we received enough to get to the MID as we
@@ -759,7 +770,7 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 	 * 48 bytes is enough to display the header and a little bit
 	 * into the payload for debugging purposes.
 	 */
-	length = checkSMB(smb_buffer, smb_buffer->Mid, server->total_read);
+	length = checkSMB(buf, server->total_read);
 	if (length != 0)
 		cifs_dump_mem("Bad SMB: ", buf,
 			min_t(unsigned int, server->total_read, 48));
@@ -767,7 +778,7 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 	if (!mid)
 		return length;
 
-	handle_mid(mid, server, smb_buffer, length);
+	handle_mid(mid, server, buf, length);
 	return 0;
 }
 
@@ -778,7 +789,6 @@ cifs_demultiplex_thread(void *p)
 	struct TCP_Server_Info *server = p;
 	unsigned int pdu_length;
 	char *buf = NULL;
-	struct smb_hdr *smb_buffer = NULL;
 	struct task_struct *task_to_wake = NULL;
 	struct mid_q_entry *mid_entry;
 
@@ -799,7 +809,6 @@ cifs_demultiplex_thread(void *p)
 			continue;
 
 		server->large_buf = false;
-		smb_buffer = (struct smb_hdr *)server->smallbuf;
 		buf = server->smallbuf;
 		pdu_length = 4; /* enough to get RFC1001 header */
 
@@ -812,14 +821,14 @@ cifs_demultiplex_thread(void *p)
 		 * The right amount was read from socket - 4 bytes,
 		 * so we can now interpret the length field.
 		 */
-		pdu_length = be32_to_cpu(smb_buffer->smb_buf_length);
+		pdu_length = get_rfc1002_length(buf);
 
 		cFYI(1, "RFC1002 header 0x%x", pdu_length);
 		if (!is_smb_response(server, buf[0]))
 			continue;
 
 		/* make sure we have enough to get to the MID */
-		if (pdu_length < sizeof(struct smb_hdr) - 1 - 4) {
+		if (pdu_length < header_size() - 1 - 4) {
 			cERROR(1, "SMB response too short (%u bytes)",
 				pdu_length);
 			cifs_reconnect(server);
@@ -829,12 +838,12 @@ cifs_demultiplex_thread(void *p)
 
 		/* read down to the MID */
 		length = cifs_read_from_socket(server, buf + 4,
-					sizeof(struct smb_hdr) - 1 - 4);
+					       header_size() - 1 - 4);
 		if (length < 0)
 			continue;
 		server->total_read += length;
 
-		mid_entry = find_mid(server, smb_buffer);
+		mid_entry = find_mid(server, buf);
 
 		if (!mid_entry || !mid_entry->receive)
 			length = standard_receive3(server, mid_entry);
@@ -844,22 +853,19 @@ cifs_demultiplex_thread(void *p)
 		if (length < 0)
 			continue;
 
-		if (server->large_buf) {
+		if (server->large_buf)
 			buf = server->bigbuf;
-			smb_buffer = (struct smb_hdr *)buf;
-		}
 
 		server->lstrp = jiffies;
 		if (mid_entry != NULL) {
 			if (!mid_entry->multiRsp || mid_entry->multiEnd)
 				mid_entry->callback(mid_entry);
-		} else if (!is_valid_oplock_break(smb_buffer, server)) {
+		} else if (!is_valid_oplock_break(buf, server)) {
 			cERROR(1, "No task to wake, unknown frame received! "
 				   "NumMids %d", atomic_read(&midCount));
-			cifs_dump_mem("Received Data is: ", buf,
-				      sizeof(struct smb_hdr));
+			cifs_dump_mem("Received Data is: ", buf, header_size());
 #ifdef CONFIG_CIFS_DEBUG2
-			cifs_dump_detail(smb_buffer);
+			cifs_dump_detail(buf);
 			cifs_dump_mids(server);
 #endif /* CIFS_DEBUG2 */
 
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 8e7516f..83e1e7e 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -420,8 +420,10 @@ check_smb_hdr(struct smb_hdr *smb, __u16 mid)
 }
 
 int
-checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int total_read)
+checkSMB(char *buf, unsigned int total_read)
 {
+	struct smb_hdr *smb = (struct smb_hdr *)buf;
+	__u16 mid = smb->Mid;
 	__u32 rfclen = be32_to_cpu(smb->smb_buf_length);
 	__u32 clc_len;  /* calculated length */
 	cFYI(0, "checkSMB Length: 0x%x, smb_buf_length: 0x%x",
@@ -502,8 +504,9 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int total_read)
 }
 
 bool
-is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
+is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
 {
+	struct smb_hdr *buf = (struct smb_hdr *)buffer;
 	struct smb_com_lock_req *pSMB = (struct smb_com_lock_req *)buf;
 	struct list_head *tmp, *tmp1, *tmp2;
 	struct cifs_ses *ses;
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 0d2707e..70d6e9f 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -769,7 +769,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 		goto out;
 	}
 
-	*pbytes_returned = be32_to_cpu(midQ->resp_buf->smb_buf_length);
+	*pbytes_returned = get_rfc1002_length(midQ->resp_buf);
 	memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
 	rc = cifs_check_receive(midQ, ses->server, 0);
 out:
@@ -952,7 +952,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 		goto out;
 	}
 
-	*pbytes_returned = be32_to_cpu(midQ->resp_buf->smb_buf_length);
+	*pbytes_returned = get_rfc1002_length(midQ->resp_buf);
 	memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
 	rc = cifs_check_receive(midQ, ses->server, 0);
 out:
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 09/11] CIFS: Separate protocol-specific code from cifs_readv_receive code
       [not found] ` <1329895984-9251-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
                     ` (7 preceding siblings ...)
  2012-02-22  7:33   ` [PATCH 08/11] CIFS: Separate protocol-specific code from demultiplex code Pavel Shilovsky
@ 2012-02-22  7:33   ` Pavel Shilovsky
  2012-02-22  7:33   ` [PATCH 10/11] CIFS: Expand CurrentMid field Pavel Shilovsky
  2012-02-22  7:33   ` [PATCH 11/11] CIFS: Change mid_q_entry structure fields Pavel Shilovsky
  10 siblings, 0 replies; 51+ messages in thread
From: Pavel Shilovsky @ 2012-02-22  7:33 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
 fs/cifs/cifsglob.h  |   12 ++++++++++
 fs/cifs/cifsproto.h |    2 +-
 fs/cifs/cifssmb.c   |   58 +++++++++++++++++++++++++++++++++-----------------
 fs/cifs/connect.c   |   12 ----------
 fs/cifs/netmisc.c   |    3 +-
 5 files changed, 53 insertions(+), 34 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index e95b8b1..c9128f4 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -351,6 +351,18 @@ has_free_credits(struct TCP_Server_Info *server, unsigned int *val)
 	return res;
 }
 
+static inline size_t
+header_size(void)
+{
+	return sizeof(struct smb_hdr);
+}
+
+static inline size_t
+max_header_size(void)
+{
+	return MAX_CIFS_HDR_SIZE;
+}
+
 /*
  * Macros to allow the TCP_Server_Info->net field and related code to drop out
  * when CONFIG_NET_NS isn't set.
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 97a400c..68c8f02 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -103,7 +103,7 @@ extern int cifs_convert_address(struct sockaddr *dst, const char *src, int len);
 extern int cifs_set_port(struct sockaddr *addr, const unsigned short int port);
 extern int cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len,
 				const unsigned short int port);
-extern int map_smb_to_linux_error(struct smb_hdr *smb, bool logErr);
+extern int map_smb_to_linux_error(char *buf, bool logErr);
 extern void header_assemble(struct smb_hdr *, char /* command */ ,
 			    const struct cifs_tcon *, int /* length of
 			    fixed section (word count) in two byte units */);
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 5ba869f..767091e 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1412,8 +1412,7 @@ cifs_readdata_free(struct cifs_readdata *rdata)
 static int
 cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 {
-	READ_RSP *rsp = (READ_RSP *)server->smallbuf;
-	unsigned int rfclen = be32_to_cpu(rsp->hdr.smb_buf_length);
+	unsigned int rfclen = get_rfc1002_length(server->smallbuf);
 	int remaining = rfclen + 4 - server->total_read;
 	struct cifs_readdata *rdata = mid->callback_data;
 
@@ -1422,7 +1421,7 @@ cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 
 		length = cifs_read_from_socket(server, server->bigbuf,
 				min_t(unsigned int, remaining,
-					CIFSMaxBufSize + MAX_CIFS_HDR_SIZE));
+					CIFSMaxBufSize + max_header_size()));
 		if (length < 0)
 			return length;
 		server->total_read += length;
@@ -1433,14 +1432,35 @@ cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 	return 0;
 }
 
+static inline size_t
+read_rsp_size(void)
+{
+	return sizeof(READ_RSP);
+}
+
+static inline unsigned int
+read_data_offset(char *buf)
+{
+	READ_RSP *rsp = (READ_RSP *)buf;
+	return le16_to_cpu(rsp->DataOffset);
+}
+
+static inline unsigned int
+read_data_length(char *buf)
+{
+	READ_RSP *rsp = (READ_RSP *)buf;
+	return (le16_to_cpu(rsp->DataLengthHigh) << 16) +
+	       le16_to_cpu(rsp->DataLength);
+}
+
 static int
 cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 {
 	int length, len;
 	unsigned int data_offset, remaining, data_len;
 	struct cifs_readdata *rdata = mid->callback_data;
-	READ_RSP *rsp = (READ_RSP *)server->smallbuf;
-	unsigned int rfclen = be32_to_cpu(rsp->hdr.smb_buf_length) + 4;
+	char *buf = server->smallbuf;
+	unsigned int buflen = get_rfc1002_length(buf) + 4;
 	u64 eof;
 	pgoff_t eof_index;
 	struct page *page, *tpage;
@@ -1453,10 +1473,9 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 	 * can if there's not enough data. At this point, we've read down to
 	 * the Mid.
 	 */
-	len = min_t(unsigned int, rfclen, sizeof(*rsp)) -
-			sizeof(struct smb_hdr) + 1;
+	len = min_t(unsigned int, buflen, read_rsp_size()) - header_size() + 1;
 
-	rdata->iov[0].iov_base = server->smallbuf + sizeof(struct smb_hdr) - 1;
+	rdata->iov[0].iov_base = buf + header_size() - 1;
 	rdata->iov[0].iov_len = len;
 
 	length = cifs_readv_from_socket(server, rdata->iov, 1, len);
@@ -1465,7 +1484,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 	server->total_read += length;
 
 	/* Was the SMB read successful? */
-	rdata->result = map_smb_to_linux_error(&rsp->hdr, false);
+	rdata->result = map_smb_to_linux_error(buf, false);
 	if (rdata->result != 0) {
 		cFYI(1, "%s: server returned error %d", __func__,
 			rdata->result);
@@ -1473,14 +1492,14 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 	}
 
 	/* Is there enough to get to the rest of the READ_RSP header? */
-	if (server->total_read < sizeof(READ_RSP)) {
+	if (server->total_read < read_rsp_size()) {
 		cFYI(1, "%s: server returned short header. got=%u expected=%zu",
-			__func__, server->total_read, sizeof(READ_RSP));
+			__func__, server->total_read, read_rsp_size());
 		rdata->result = -EIO;
 		return cifs_readv_discard(server, mid);
 	}
 
-	data_offset = le16_to_cpu(rsp->DataOffset) + 4;
+	data_offset = read_data_offset(buf) + 4;
 	if (data_offset < server->total_read) {
 		/*
 		 * win2k8 sometimes sends an offset of 0 when the read
@@ -1504,7 +1523,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 	len = data_offset - server->total_read;
 	if (len > 0) {
 		/* read any junk before data into the rest of smallbuf */
-		rdata->iov[0].iov_base = server->smallbuf + server->total_read;
+		rdata->iov[0].iov_base = buf + server->total_read;
 		rdata->iov[0].iov_len = len;
 		length = cifs_readv_from_socket(server, rdata->iov, 1, len);
 		if (length < 0)
@@ -1513,15 +1532,14 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 	}
 
 	/* set up first iov for signature check */
-	rdata->iov[0].iov_base = server->smallbuf;
+	rdata->iov[0].iov_base = buf;
 	rdata->iov[0].iov_len = server->total_read;
 	cFYI(1, "0: iov_base=%p iov_len=%zu",
 		rdata->iov[0].iov_base, rdata->iov[0].iov_len);
 
 	/* how much data is in the response? */
-	data_len = le16_to_cpu(rsp->DataLengthHigh) << 16;
-	data_len += le16_to_cpu(rsp->DataLength);
-	if (data_offset + data_len > rfclen) {
+	data_len = read_data_length(buf);
+	if (data_offset + data_len > buflen) {
 		/* data_len is corrupt -- discard frame */
 		rdata->result = -EIO;
 		return cifs_readv_discard(server, mid);
@@ -1600,11 +1618,11 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 
 	rdata->bytes = length;
 
-	cFYI(1, "total_read=%u rfclen=%u remaining=%u", server->total_read,
-		rfclen, remaining);
+	cFYI(1, "total_read=%u buflen=%u remaining=%u", server->total_read,
+		buflen, remaining);
 
 	/* discard anything left over */
-	if (server->total_read < rfclen)
+	if (server->total_read < buflen)
 		return cifs_readv_discard(server, mid);
 
 	dequeue_mid(mid, false);
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index efb0a44..cf70d86 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -338,18 +338,6 @@ requeue_echo:
 	queue_delayed_work(system_nrt_wq, &server->echo, SMB_ECHO_INTERVAL);
 }
 
-static inline size_t
-header_size(void)
-{
-	return sizeof(struct smb_hdr);
-}
-
-static inline size_t
-max_header_size(void)
-{
-	return MAX_CIFS_HDR_SIZE;
-}
-
 static bool
 allocate_buffers(struct TCP_Server_Info *server)
 {
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
index 73e47e8..dd23a32 100644
--- a/fs/cifs/netmisc.c
+++ b/fs/cifs/netmisc.c
@@ -836,8 +836,9 @@ ntstatus_to_dos(__u32 ntstatus, __u8 *eclass, __u16 *ecode)
 }
 
 int
-map_smb_to_linux_error(struct smb_hdr *smb, bool logErr)
+map_smb_to_linux_error(char *buf, bool logErr)
 {
+	struct smb_hdr *smb = (struct smb_hdr *)buf;
 	unsigned int i;
 	int rc = -EIO;	/* if transport error smb error may not be set */
 	__u8 smberrclass;
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 10/11] CIFS: Expand CurrentMid field
       [not found] ` <1329895984-9251-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
                     ` (8 preceding siblings ...)
  2012-02-22  7:33   ` [PATCH 09/11] CIFS: Separate protocol-specific code from cifs_readv_receive code Pavel Shilovsky
@ 2012-02-22  7:33   ` Pavel Shilovsky
  2012-02-22  7:33   ` [PATCH 11/11] CIFS: Change mid_q_entry structure fields Pavel Shilovsky
  10 siblings, 0 replies; 51+ messages in thread
From: Pavel Shilovsky @ 2012-02-22  7:33 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

While in CIFS/SMB we have 16 bit mid, in SMB2 it is 64 bit.
Convert the existing field to 64 bit and mask off higher bits
for CIFS/SMB.

Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
 fs/cifs/cifsglob.h  |    2 +-
 fs/cifs/cifsproto.h |    2 +-
 fs/cifs/misc.c      |   84 ++++++++++++++++++++++++++++-----------------------
 3 files changed, 48 insertions(+), 40 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index c9128f4..7e3761e 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -279,7 +279,7 @@ struct TCP_Server_Info {
 				   vcnumbers */
 	int capabilities; /* allow selective disabling of caps by smb sess */
 	int timeAdj;  /* Adjust for difference in server time zone in sec */
-	__u16 CurrentMid;         /* multiplex id - rotating counter */
+	__u64 CurrentMid;         /* multiplex id - rotating counter */
 	char cryptkey[CIFS_CRYPTO_KEY_SIZE]; /* used by ntlm, ntlmv2 etc */
 	/* 16th byte of RFC1001 workstation name is always null */
 	char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 68c8f02..99dde5e 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -112,7 +112,7 @@ extern int small_smb_init_no_tc(const int smb_cmd, const int wct,
 				void **request_buf);
 extern int CIFS_SessSetup(unsigned int xid, struct cifs_ses *ses,
 			     const struct nls_table *nls_cp);
-extern __u16 GetNextMid(struct TCP_Server_Info *server);
+extern __u64 GetNextMid(struct TCP_Server_Info *server);
 extern struct timespec cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601);
 extern u64 cifs_UnixTimeToNT(struct timespec);
 extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time,
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 83e1e7e..e91f983 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -213,54 +213,61 @@ cifs_small_buf_release(void *buf_to_free)
 }
 
 /*
-	Find a free multiplex id (SMB mid). Otherwise there could be
-	mid collisions which might cause problems, demultiplexing the
-	wrong response to this request. Multiplex ids could collide if
-	one of a series requests takes much longer than the others, or
-	if a very large number of long lived requests (byte range
-	locks or FindNotify requests) are pending.  No more than
-	64K-1 requests can be outstanding at one time.  If no
-	mids are available, return zero.  A future optimization
-	could make the combination of mids and uid the key we use
-	to demultiplex on (rather than mid alone).
-	In addition to the above check, the cifs demultiplex
-	code already used the command code as a secondary
-	check of the frame and if signing is negotiated the
-	response would be discarded if the mid were the same
-	but the signature was wrong.  Since the mid is not put in the
-	pending queue until later (when it is about to be dispatched)
-	we do have to limit the number of outstanding requests
-	to somewhat less than 64K-1 although it is hard to imagine
-	so many threads being in the vfs at one time.
-*/
-__u16 GetNextMid(struct TCP_Server_Info *server)
+ * Find a free multiplex id (SMB mid). Otherwise there could be
+ * mid collisions which might cause problems, demultiplexing the
+ * wrong response to this request. Multiplex ids could collide if
+ * one of a series requests takes much longer than the others, or
+ * if a very large number of long lived requests (byte range
+ * locks or FindNotify requests) are pending. No more than
+ * 64K-1 requests can be outstanding at one time. If no
+ * mids are available, return zero. A future optimization
+ * could make the combination of mids and uid the key we use
+ * to demultiplex on (rather than mid alone).
+ * In addition to the above check, the cifs demultiplex
+ * code already used the command code as a secondary
+ * check of the frame and if signing is negotiated the
+ * response would be discarded if the mid were the same
+ * but the signature was wrong. Since the mid is not put in the
+ * pending queue until later (when it is about to be dispatched)
+ * we do have to limit the number of outstanding requests
+ * to somewhat less than 64K-1 although it is hard to imagine
+ * so many threads being in the vfs at one time.
+ */
+__u64 GetNextMid(struct TCP_Server_Info *server)
 {
-	__u16 mid = 0;
-	__u16 last_mid;
+	__u64 mid = 0;
+	__u16 last_mid, cur_mid;
 	bool collision;
 
 	spin_lock(&GlobalMid_Lock);
-	last_mid = server->CurrentMid; /* we do not want to loop forever */
-	server->CurrentMid++;
-	/* This nested loop looks more expensive than it is.
-	In practice the list of pending requests is short,
-	fewer than 50, and the mids are likely to be unique
-	on the first pass through the loop unless some request
-	takes longer than the 64 thousand requests before it
-	(and it would also have to have been a request that
-	 did not time out) */
-	while (server->CurrentMid != last_mid) {
+
+	/* mid is 16 bit only for CIFS/SMB */
+	cur_mid = (__u16)((server->CurrentMid) & 0xffff);
+	/* we do not want to loop forever */
+	last_mid = cur_mid;
+	cur_mid++;
+
+	/*
+	 * This nested loop looks more expensive than it is.
+	 * In practice the list of pending requests is short,
+	 * fewer than 50, and the mids are likely to be unique
+	 * on the first pass through the loop unless some request
+	 * takes longer than the 64 thousand requests before it
+	 * (and it would also have to have been a request that
+	 * did not time out).
+	 */
+	while (cur_mid != last_mid) {
 		struct mid_q_entry *mid_entry;
 		unsigned int num_mids;
 
 		collision = false;
-		if (server->CurrentMid == 0)
-			server->CurrentMid++;
+		if (cur_mid == 0)
+			cur_mid++;
 
 		num_mids = 0;
 		list_for_each_entry(mid_entry, &server->pending_mid_q, qhead) {
 			++num_mids;
-			if (mid_entry->mid == server->CurrentMid &&
+			if (mid_entry->mid == cur_mid &&
 			    mid_entry->midState == MID_REQUEST_SUBMITTED) {
 				/* This mid is in use, try a different one */
 				collision = true;
@@ -282,10 +289,11 @@ __u16 GetNextMid(struct TCP_Server_Info *server)
 			server->tcpStatus = CifsNeedReconnect;
 
 		if (!collision) {
-			mid = server->CurrentMid;
+			mid = (__u64)cur_mid;
+			server->CurrentMid = mid;
 			break;
 		}
-		server->CurrentMid++;
+		cur_mid++;
 	}
 	spin_unlock(&GlobalMid_Lock);
 	return mid;
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH 11/11] CIFS: Change mid_q_entry structure fields
       [not found] ` <1329895984-9251-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
                     ` (9 preceding siblings ...)
  2012-02-22  7:33   ` [PATCH 10/11] CIFS: Expand CurrentMid field Pavel Shilovsky
@ 2012-02-22  7:33   ` Pavel Shilovsky
  10 siblings, 0 replies; 51+ messages in thread
From: Pavel Shilovsky @ 2012-02-22  7:33 UTC (permalink / raw)
  To: linux-cifs-u79uwXL29TY76Z2rM5mHXA

to be protocol-unspecific and big enough to keep both CIFS
and SMB2 values.

Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
 fs/cifs/cifs_debug.c |   20 +++++++++---------
 fs/cifs/cifsglob.h   |   10 ++++----
 fs/cifs/cifssmb.c    |   12 +++++-----
 fs/cifs/connect.c    |   22 ++++++++++----------
 fs/cifs/misc.c       |    2 +-
 fs/cifs/transport.c  |   52 +++++++++++++++++++++++++-------------------------
 6 files changed, 59 insertions(+), 59 deletions(-)

diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
index bcd0db7..81be263 100644
--- a/fs/cifs/cifs_debug.c
+++ b/fs/cifs/cifs_debug.c
@@ -80,15 +80,15 @@ void cifs_dump_mids(struct TCP_Server_Info *server)
 	spin_lock(&GlobalMid_Lock);
 	list_for_each(tmp, &server->pending_mid_q) {
 		mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
-		cERROR(1, "State: %d Cmd: %d Pid: %d Cbdata: %p Mid %d",
-			mid_entry->midState,
-			(int)mid_entry->command,
+		cERROR(1, "State: %d Cmd: %d Pid: %d Cbdata: %p Mid %llu",
+			mid_entry->mid_state,
+			le16_to_cpu(mid_entry->command),
 			mid_entry->pid,
 			mid_entry->callback_data,
 			mid_entry->mid);
 #ifdef CONFIG_CIFS_STATS2
 		cERROR(1, "IsLarge: %d buf: %p time rcv: %ld now: %ld",
-			mid_entry->largeBuf,
+			mid_entry->large_buf,
 			mid_entry->resp_buf,
 			mid_entry->when_received,
 			jiffies);
@@ -218,12 +218,12 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
 				mid_entry = list_entry(tmp3, struct mid_q_entry,
 					qhead);
 				seq_printf(m, "\tState: %d com: %d pid:"
-						" %d cbdata: %p mid %d\n",
-						mid_entry->midState,
-						(int)mid_entry->command,
-						mid_entry->pid,
-						mid_entry->callback_data,
-						mid_entry->mid);
+					      " %d cbdata: %p mid %llu\n",
+					      mid_entry->mid_state,
+					      le16_to_cpu(mid_entry->command),
+					      mid_entry->pid,
+					      mid_entry->callback_data,
+					      mid_entry->mid);
 			}
 			spin_unlock(&GlobalMid_Lock);
 		}
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 7e3761e..3f09ffb 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -741,8 +741,8 @@ typedef void (mid_callback_t)(struct mid_q_entry *mid);
 /* one of these for every pending CIFS request to the server */
 struct mid_q_entry {
 	struct list_head qhead;	/* mids waiting on reply from this server */
-	__u16 mid;		/* multiplex id */
-	__u16 pid;		/* process id */
+	__u64 mid;		/* multiplex id */
+	__u32 pid;		/* process id */
 	__u32 sequence_number;  /* for CIFS signing */
 	unsigned long when_alloc;  /* when mid was created */
 #ifdef CONFIG_CIFS_STATS2
@@ -753,9 +753,9 @@ struct mid_q_entry {
 	mid_callback_t *callback; /* call completion callback */
 	void *callback_data;	  /* general purpose pointer for callback */
 	void *resp_buf;		/* pointer to received SMB header */
-	int midState;	/* wish this were enum but can not pass to wait_event */
-	__u8 command;	/* smb command code */
-	bool largeBuf:1;	/* if valid response, is pointer to large buf */
+	int mid_state;	/* wish this were enum but can not pass to wait_event */
+	__le16 command;		/* smb command code */
+	bool large_buf:1;	/* if valid response, is pointer to large buf */
 	bool multiRsp:1;	/* multiple trans2 responses for one request  */
 	bool multiEnd:1;	/* both received */
 };
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 767091e..f2a5e91 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1465,7 +1465,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 	pgoff_t eof_index;
 	struct page *page, *tpage;
 
-	cFYI(1, "%s: mid=%u offset=%llu bytes=%u", __func__,
+	cFYI(1, "%s: mid=%llu offset=%llu bytes=%u", __func__,
 		mid->mid, rdata->offset, rdata->bytes);
 
 	/*
@@ -1663,10 +1663,10 @@ cifs_readv_callback(struct mid_q_entry *mid)
 	struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
 	struct TCP_Server_Info *server = tcon->ses->server;
 
-	cFYI(1, "%s: mid=%u state=%d result=%d bytes=%u", __func__,
-		mid->mid, mid->midState, rdata->result, rdata->bytes);
+	cFYI(1, "%s: mid=%llu state=%d result=%d bytes=%u", __func__,
+		mid->mid, mid->mid_state, rdata->result, rdata->bytes);
 
-	switch (mid->midState) {
+	switch (mid->mid_state) {
 	case MID_RESPONSE_RECEIVED:
 		/* result already set, check signature */
 		if (server->sec_mode &
@@ -2085,7 +2085,7 @@ cifs_writedata_alloc(unsigned int nr_pages)
 }
 
 /*
- * Check the midState and signature on received buffer (if any), and queue the
+ * Check the mid_state and signature on received buffer (if any), and queue the
  * workqueue completion task.
  */
 static void
@@ -2096,7 +2096,7 @@ cifs_writev_callback(struct mid_q_entry *mid)
 	unsigned int written;
 	WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
 
-	switch (mid->midState) {
+	switch (mid->mid_state) {
 	case MID_RESPONSE_RECEIVED:
 		wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
 		if (wdata->result != 0)
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index cf70d86..a305df5 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -143,8 +143,8 @@ cifs_reconnect(struct TCP_Server_Info *server)
 	spin_lock(&GlobalMid_Lock);
 	list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
 		mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
-		if (mid_entry->midState == MID_REQUEST_SUBMITTED)
-			mid_entry->midState = MID_RETRY_NEEDED;
+		if (mid_entry->mid_state == MID_REQUEST_SUBMITTED)
+			mid_entry->mid_state = MID_RETRY_NEEDED;
 		list_move(&mid_entry->qhead, &retry_list);
 	}
 	spin_unlock(&GlobalMid_Lock);
@@ -564,8 +564,8 @@ find_mid(struct TCP_Server_Info *server, char *buffer)
 	spin_lock(&GlobalMid_Lock);
 	list_for_each_entry(mid, &server->pending_mid_q, qhead) {
 		if (mid->mid == buf->Mid &&
-		    mid->midState == MID_REQUEST_SUBMITTED &&
-		    mid->command == buf->Command) {
+		    mid->mid_state == MID_REQUEST_SUBMITTED &&
+		    le16_to_cpu(mid->command) == buf->Command) {
 			spin_unlock(&GlobalMid_Lock);
 			return mid;
 		}
@@ -582,9 +582,9 @@ dequeue_mid(struct mid_q_entry *mid, bool malformed)
 #endif
 	spin_lock(&GlobalMid_Lock);
 	if (!malformed)
-		mid->midState = MID_RESPONSE_RECEIVED;
+		mid->mid_state = MID_RESPONSE_RECEIVED;
 	else
-		mid->midState = MID_RESPONSE_MALFORMED;
+		mid->mid_state = MID_RESPONSE_MALFORMED;
 	list_del_init(&mid->qhead);
 	spin_unlock(&GlobalMid_Lock);
 }
@@ -611,13 +611,13 @@ handle_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server,
 		} else {
 			/* Have first buffer */
 			mid->resp_buf = buf;
-			mid->largeBuf = true;
+			mid->large_buf = true;
 			server->bigbuf = NULL;
 		}
 		return;
 	}
 	mid->resp_buf = buf;
-	mid->largeBuf = server->large_buf;
+	mid->large_buf = server->large_buf;
 	/* Was previous buf put in mpx struct for multi-rsp? */
 	if (!mid->multiRsp) {
 		/* smb buffer will be freed by user thread */
@@ -673,8 +673,8 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server)
 		spin_lock(&GlobalMid_Lock);
 		list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
 			mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
-			cFYI(1, "Clearing mid 0x%x", mid_entry->mid);
-			mid_entry->midState = MID_SHUTDOWN;
+			cFYI(1, "Clearing mid 0x%llx", mid_entry->mid);
+			mid_entry->mid_state = MID_SHUTDOWN;
 			list_move(&mid_entry->qhead, &dispose_list);
 		}
 		spin_unlock(&GlobalMid_Lock);
@@ -682,7 +682,7 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server)
 		/* now walk dispose list and issue callbacks */
 		list_for_each_safe(tmp, tmp2, &dispose_list) {
 			mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
-			cFYI(1, "Callback mid 0x%x", mid_entry->mid);
+			cFYI(1, "Callback mid 0x%llx", mid_entry->mid);
 			list_del_init(&mid_entry->qhead);
 			mid_entry->callback(mid_entry);
 		}
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index e91f983..f8bdb5e 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -268,7 +268,7 @@ __u64 GetNextMid(struct TCP_Server_Info *server)
 		list_for_each_entry(mid_entry, &server->pending_mid_q, qhead) {
 			++num_mids;
 			if (mid_entry->mid == cur_mid &&
-			    mid_entry->midState == MID_REQUEST_SUBMITTED) {
+			    mid_entry->mid_state == MID_REQUEST_SUBMITTED) {
 				/* This mid is in use, try a different one */
 				collision = true;
 				break;
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 70d6e9f..993ec18 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -60,8 +60,8 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
 		memset(temp, 0, sizeof(struct mid_q_entry));
 		temp->mid = smb_buffer->Mid;	/* always LE */
 		temp->pid = current->pid;
-		temp->command = smb_buffer->Command;
-		cFYI(1, "For smb_command %d", temp->command);
+		temp->command = cpu_to_le16(smb_buffer->Command);
+		cFYI(1, "For smb_command %d", smb_buffer->Command);
 	/*	do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */
 		/* when mid allocated can be before when sent */
 		temp->when_alloc = jiffies;
@@ -75,7 +75,7 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
 	}
 
 	atomic_inc(&midCount);
-	temp->midState = MID_REQUEST_ALLOCATED;
+	temp->mid_state = MID_REQUEST_ALLOCATED;
 	return temp;
 }
 
@@ -85,9 +85,9 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
 #ifdef CONFIG_CIFS_STATS2
 	unsigned long now;
 #endif
-	midEntry->midState = MID_FREE;
+	midEntry->mid_state = MID_FREE;
 	atomic_dec(&midCount);
-	if (midEntry->largeBuf)
+	if (midEntry->large_buf)
 		cifs_buf_release(midEntry->resp_buf);
 	else
 		cifs_small_buf_release(midEntry->resp_buf);
@@ -97,8 +97,8 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
 	   something is wrong, unless it is quite a slow link or server */
 	if ((now - midEntry->when_alloc) > HZ) {
 		if ((cifsFYI & CIFS_TIMER) &&
-		   (midEntry->command != SMB_COM_LOCKING_ANDX)) {
-			printk(KERN_DEBUG " CIFS slow rsp: cmd %d mid %d",
+		    (midEntry->command != cpu_to_le16(SMB_COM_LOCKING_ANDX))) {
+			printk(KERN_DEBUG " CIFS slow rsp: cmd %d mid %llu",
 			       midEntry->command, midEntry->mid);
 			printk(" A: 0x%lx S: 0x%lx R: 0x%lx\n",
 			       now - midEntry->when_alloc,
@@ -323,7 +323,7 @@ wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
 	int error;
 
 	error = wait_event_freezekillable(server->response_q,
-				    midQ->midState != MID_REQUEST_SUBMITTED);
+				    midQ->mid_state != MID_REQUEST_SUBMITTED);
 	if (error < 0)
 		return -ERESTARTSYS;
 
@@ -386,7 +386,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
 	mid->receive = receive;
 	mid->callback = callback;
 	mid->callback_data = cbdata;
-	mid->midState = MID_REQUEST_SUBMITTED;
+	mid->mid_state = MID_REQUEST_SUBMITTED;
 
 	cifs_in_send_inc(server);
 	rc = smb_sendv(server, iov, nvec);
@@ -436,11 +436,11 @@ cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
 {
 	int rc = 0;
 
-	cFYI(1, "%s: cmd=%d mid=%d state=%d", __func__, mid->command,
-		mid->mid, mid->midState);
+	cFYI(1, "%s: cmd=%d mid=%llu state=%d", __func__,
+	     le16_to_cpu(mid->command), mid->mid, mid->mid_state);
 
 	spin_lock(&GlobalMid_Lock);
-	switch (mid->midState) {
+	switch (mid->mid_state) {
 	case MID_RESPONSE_RECEIVED:
 		spin_unlock(&GlobalMid_Lock);
 		return rc;
@@ -455,8 +455,8 @@ cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
 		break;
 	default:
 		list_del_init(&mid->qhead);
-		cERROR(1, "%s: invalid mid state mid=%d state=%d", __func__,
-			mid->mid, mid->midState);
+		cERROR(1, "%s: invalid mid state mid=%llu state=%d", __func__,
+		       mid->mid, mid->mid_state);
 		rc = -EIO;
 	}
 	spin_unlock(&GlobalMid_Lock);
@@ -601,7 +601,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 		return rc;
 	}
 
-	midQ->midState = MID_REQUEST_SUBMITTED;
+	midQ->mid_state = MID_REQUEST_SUBMITTED;
 	cifs_in_send_inc(ses->server);
 	rc = smb_sendv(ses->server, iov, n_vec);
 	cifs_in_send_dec(ses->server);
@@ -623,7 +623,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 	if (rc != 0) {
 		send_nt_cancel(ses->server, (struct smb_hdr *)buf, midQ);
 		spin_lock(&GlobalMid_Lock);
-		if (midQ->midState == MID_REQUEST_SUBMITTED) {
+		if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
 			midQ->callback = DeleteMidQEntry;
 			spin_unlock(&GlobalMid_Lock);
 			cifs_small_buf_release(buf);
@@ -643,7 +643,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 		return rc;
 	}
 
-	if (!midQ->resp_buf || midQ->midState != MID_RESPONSE_RECEIVED) {
+	if (!midQ->resp_buf || midQ->mid_state != MID_RESPONSE_RECEIVED) {
 		rc = -EIO;
 		cFYI(1, "Bad MID state?");
 		goto out;
@@ -652,7 +652,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 	buf = (char *)midQ->resp_buf;
 	iov[0].iov_base = buf;
 	iov[0].iov_len = get_rfc1002_length(buf) + 4;
-	if (midQ->largeBuf)
+	if (midQ->large_buf)
 		*pRespBufType = CIFS_LARGE_BUFFER;
 	else
 		*pRespBufType = CIFS_SMALL_BUFFER;
@@ -726,7 +726,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 		goto out;
 	}
 
-	midQ->midState = MID_REQUEST_SUBMITTED;
+	midQ->mid_state = MID_REQUEST_SUBMITTED;
 
 	cifs_in_send_inc(ses->server);
 	rc = smb_send(ses->server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
@@ -744,7 +744,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 	if (rc != 0) {
 		send_nt_cancel(ses->server, in_buf, midQ);
 		spin_lock(&GlobalMid_Lock);
-		if (midQ->midState == MID_REQUEST_SUBMITTED) {
+		if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
 			/* no longer considered to be "in-flight" */
 			midQ->callback = DeleteMidQEntry;
 			spin_unlock(&GlobalMid_Lock);
@@ -763,7 +763,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 	}
 
 	if (!midQ->resp_buf || !out_buf ||
-	    midQ->midState != MID_RESPONSE_RECEIVED) {
+	    midQ->mid_state != MID_RESPONSE_RECEIVED) {
 		rc = -EIO;
 		cERROR(1, "Bad MID state?");
 		goto out;
@@ -867,7 +867,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 		return rc;
 	}
 
-	midQ->midState = MID_REQUEST_SUBMITTED;
+	midQ->mid_state = MID_REQUEST_SUBMITTED;
 	cifs_in_send_inc(ses->server);
 	rc = smb_send(ses->server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
 	cifs_in_send_dec(ses->server);
@@ -883,13 +883,13 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 
 	/* Wait for a reply - allow signals to interrupt. */
 	rc = wait_event_interruptible(ses->server->response_q,
-		(!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
+		(!(midQ->mid_state == MID_REQUEST_SUBMITTED)) ||
 		((ses->server->tcpStatus != CifsGood) &&
 		 (ses->server->tcpStatus != CifsNew)));
 
 	/* Were we interrupted by a signal ? */
 	if ((rc == -ERESTARTSYS) &&
-		(midQ->midState == MID_REQUEST_SUBMITTED) &&
+		(midQ->mid_state == MID_REQUEST_SUBMITTED) &&
 		((ses->server->tcpStatus == CifsGood) ||
 		 (ses->server->tcpStatus == CifsNew))) {
 
@@ -923,7 +923,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 		if (rc) {
 			send_nt_cancel(ses->server, in_buf, midQ);
 			spin_lock(&GlobalMid_Lock);
-			if (midQ->midState == MID_REQUEST_SUBMITTED) {
+			if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
 				/* no longer considered to be "in-flight" */
 				midQ->callback = DeleteMidQEntry;
 				spin_unlock(&GlobalMid_Lock);
@@ -946,7 +946,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 	}
 
 	/* rcvd frame is ok */
-	if (out_buf == NULL || midQ->midState != MID_RESPONSE_RECEIVED) {
+	if (out_buf == NULL || midQ->mid_state != MID_RESPONSE_RECEIVED) {
 		rc = -EIO;
 		cERROR(1, "Bad MID state?");
 		goto out;
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* Re: [PATCH 04/11] CIFS: Delete echo_retries module parm
       [not found]     ` <1329895984-9251-5-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
@ 2012-02-22 16:23       ` Jeff Layton
       [not found]         ` <20120222112323.3d1afe4b-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
  2012-02-27 23:39       ` Steve French
  1 sibling, 1 reply; 51+ messages in thread
From: Jeff Layton @ 2012-02-22 16:23 UTC (permalink / raw)
  To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

On Wed, 22 Feb 2012 10:32:57 +0300
Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:

> It's the essential step before respecting MaxMpxCount value during
> negotiating because we will keep only one extra slot for sending
> echo requests. If there is no response for echo message - reconnect
> the tcp session.
> 
> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
> ---
>  fs/cifs/README     |    6 +-----
>  fs/cifs/cifsfs.c   |    5 -----
>  fs/cifs/cifsglob.h |    3 ---
>  fs/cifs/connect.c  |    7 +++----
>  4 files changed, 4 insertions(+), 17 deletions(-)
> 
> diff --git a/fs/cifs/README b/fs/cifs/README
> index 895da1d..b7d782b 100644
> --- a/fs/cifs/README
> +++ b/fs/cifs/README
> @@ -753,10 +753,6 @@ module loading or during the runtime by using the interface
>  
>  i.e. echo "value" > /sys/module/cifs/parameters/<param>
>  
> -1. echo_retries - The number of echo attempts before giving up and
> -		  reconnecting to the server. The default is 5. The value 0
> -		  means never reconnect.
> -
> -2. enable_oplocks - Enable or disable oplocks. Oplocks are enabled by default.
> +1. enable_oplocks - Enable or disable oplocks. Oplocks are enabled by default.
>  		    [Y/y/1]. To disable use any of [N/n/0].
>  
> diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
> index b1fd382..e1ce1ca 100644
> --- a/fs/cifs/cifsfs.c
> +++ b/fs/cifs/cifsfs.c
> @@ -77,11 +77,6 @@ unsigned int cifs_max_pending = CIFS_MAX_REQ;
>  module_param(cifs_max_pending, int, 0444);
>  MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server. "
>  				   "Default: 50 Range: 2 to 256");
> -unsigned short echo_retries = 5;
> -module_param(echo_retries, ushort, 0644);
> -MODULE_PARM_DESC(echo_retries, "Number of echo attempts before giving up and "
> -			       "reconnecting server. Default: 5. 0 means "
> -			       "never reconnect.");
>  module_param(enable_oplocks, bool, 0644);
>  MODULE_PARM_DESC(enable_oplocks, "Enable or disable oplocks (bool). Default:"
>  				 "y/Y/1");
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index 600d61c..674792e 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -1049,9 +1049,6 @@ GLOBAL_EXTERN unsigned int cifs_min_rcv;    /* min size of big ntwrk buf pool */
>  GLOBAL_EXTERN unsigned int cifs_min_small;  /* min size of small buf pool */
>  GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/
>  
> -/* reconnect after this many failed echo attempts */
> -GLOBAL_EXTERN unsigned short echo_retries;
> -
>  #ifdef CONFIG_CIFS_ACL
>  GLOBAL_EXTERN struct rb_root uidtree;
>  GLOBAL_EXTERN struct rb_root gidtree;
> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
> index 673813f..86d7a40 100644
> --- a/fs/cifs/connect.c
> +++ b/fs/cifs/connect.c
> @@ -373,12 +373,11 @@ allocate_buffers(struct TCP_Server_Info *server)
>  static bool
>  server_unresponsive(struct TCP_Server_Info *server)
>  {
> -	if (echo_retries > 0 && server->tcpStatus == CifsGood &&
> -	    time_after(jiffies, server->lstrp +
> -				(echo_retries * SMB_ECHO_INTERVAL))) {
> +	if (server->tcpStatus == CifsGood &&
> +	    time_after(jiffies, server->lstrp + SMB_ECHO_INTERVAL)) {
>  		cERROR(1, "Server %s has not responded in %d seconds. "
>  			  "Reconnecting...", server->hostname,
> -			  (echo_retries * SMB_ECHO_INTERVAL / HZ));
> +			  SMB_ECHO_INTERVAL / HZ);

This will be a problem since we skip sending an echo when the client
has gotten a response recently (within the last echo interval).

Consider:

1s	client sends a normal smb request
2s	client gets a response
30s	echo workqueue job pops, and decides we got a response
	recently and don't need to send another
...
65s	kernel_recvmsg times out, and we see that we haven't gotten
	a response in >60s

...I think you'll probably want to only reconnect when we haven't
gotten a response in 2 echo intervals? Or maybe there's a better way?

>  		cifs_reconnect(server);
>  		wake_up(&server->response_q);
>  		return true;


-- 
Jeff Layton <jlayton-vpEMnDpepFuMZCB2o+C8xQ@public.gmane.org>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 05/11] CIFS: Make wait_for_free_request interruptible
       [not found]     ` <1329895984-9251-6-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
@ 2012-02-22 19:15       ` Jeff Layton
       [not found]         ` <20120222141534.5512c3bf-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
  0 siblings, 1 reply; 51+ messages in thread
From: Jeff Layton @ 2012-02-22 19:15 UTC (permalink / raw)
  To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

On Wed, 22 Feb 2012 10:32:58 +0300
Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:

> to let us interrupt the proccess if the session went down and echo
> is disabled.
> 
> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
> ---
>  fs/cifs/transport.c |    7 ++++++-
>  1 files changed, 6 insertions(+), 1 deletions(-)
> 
> diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
> index fa93720..938d20b 100644
> --- a/fs/cifs/transport.c
> +++ b/fs/cifs/transport.c
> @@ -257,6 +257,8 @@ smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
>  static int
>  wait_for_free_request(struct TCP_Server_Info *server, const int long_op)
>  {
> +	int rc;
> +
>  	spin_lock(&server->req_lock);
>  
>  	if (long_op == CIFS_ASYNC_OP) {
> @@ -271,8 +273,11 @@ wait_for_free_request(struct TCP_Server_Info *server, const int long_op)
>  		if (server->credits <= 0) {
>  			spin_unlock(&server->req_lock);
>  			cifs_num_waiters_inc(server);
> -			wait_event(server->request_q, get_credits(server) > 0);
> +			rc = wait_event_interruptible(server->request_q,
> +						      get_credits(server) > 0);
>  			cifs_num_waiters_dec(server);
> +			if (rc)
> +				return rc;
>  			spin_lock(&server->req_lock);
>  		} else {
>  			if (server->tcpStatus == CifsExiting) {

In general, I think making this interruptible is a good idea. The
problem here though is that you're going to end up interrupting this on
any signal. That includes stuff like SIGCHLD -- you don't necessarily
want to interrupt this because the process forked off a child earlier
and then that child exited...

It's probably simpler to just make this a TASK_KILLABLE sleep for that
reason, rather than trying to handle different signals differently.

-- 
Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 04/11] CIFS: Delete echo_retries module parm
       [not found]         ` <20120222112323.3d1afe4b-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
@ 2012-02-23  6:16           ` Pavel Shilovsky
  0 siblings, 0 replies; 51+ messages in thread
From: Pavel Shilovsky @ 2012-02-23  6:16 UTC (permalink / raw)
  To: Jeff Layton; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

2012/2/22 Jeff Layton <jlayton-vpEMnDpepFuMZCB2o+C8xQ@public.gmane.org>:
> On Wed, 22 Feb 2012 10:32:57 +0300
> Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
>
>> It's the essential step before respecting MaxMpxCount value during
>> negotiating because we will keep only one extra slot for sending
>> echo requests. If there is no response for echo message - reconnect
>> the tcp session.
>>
>> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
>> ---
>>  fs/cifs/README     |    6 +-----
>>  fs/cifs/cifsfs.c   |    5 -----
>>  fs/cifs/cifsglob.h |    3 ---
>>  fs/cifs/connect.c  |    7 +++----
>>  4 files changed, 4 insertions(+), 17 deletions(-)
>>
>> diff --git a/fs/cifs/README b/fs/cifs/README
>> index 895da1d..b7d782b 100644
>> --- a/fs/cifs/README
>> +++ b/fs/cifs/README
>> @@ -753,10 +753,6 @@ module loading or during the runtime by using the interface
>>
>>  i.e. echo "value" > /sys/module/cifs/parameters/<param>
>>
>> -1. echo_retries - The number of echo attempts before giving up and
>> -               reconnecting to the server. The default is 5. The value 0
>> -               means never reconnect.
>> -
>> -2. enable_oplocks - Enable or disable oplocks. Oplocks are enabled by default.
>> +1. enable_oplocks - Enable or disable oplocks. Oplocks are enabled by default.
>>                   [Y/y/1]. To disable use any of [N/n/0].
>>
>> diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
>> index b1fd382..e1ce1ca 100644
>> --- a/fs/cifs/cifsfs.c
>> +++ b/fs/cifs/cifsfs.c
>> @@ -77,11 +77,6 @@ unsigned int cifs_max_pending = CIFS_MAX_REQ;
>>  module_param(cifs_max_pending, int, 0444);
>>  MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server. "
>>                                  "Default: 50 Range: 2 to 256");
>> -unsigned short echo_retries = 5;
>> -module_param(echo_retries, ushort, 0644);
>> -MODULE_PARM_DESC(echo_retries, "Number of echo attempts before giving up and "
>> -                            "reconnecting server. Default: 5. 0 means "
>> -                            "never reconnect.");
>>  module_param(enable_oplocks, bool, 0644);
>>  MODULE_PARM_DESC(enable_oplocks, "Enable or disable oplocks (bool). Default:"
>>                                "y/Y/1");
>> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
>> index 600d61c..674792e 100644
>> --- a/fs/cifs/cifsglob.h
>> +++ b/fs/cifs/cifsglob.h
>> @@ -1049,9 +1049,6 @@ GLOBAL_EXTERN unsigned int cifs_min_rcv;    /* min size of big ntwrk buf pool */
>>  GLOBAL_EXTERN unsigned int cifs_min_small;  /* min size of small buf pool */
>>  GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/
>>
>> -/* reconnect after this many failed echo attempts */
>> -GLOBAL_EXTERN unsigned short echo_retries;
>> -
>>  #ifdef CONFIG_CIFS_ACL
>>  GLOBAL_EXTERN struct rb_root uidtree;
>>  GLOBAL_EXTERN struct rb_root gidtree;
>> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
>> index 673813f..86d7a40 100644
>> --- a/fs/cifs/connect.c
>> +++ b/fs/cifs/connect.c
>> @@ -373,12 +373,11 @@ allocate_buffers(struct TCP_Server_Info *server)
>>  static bool
>>  server_unresponsive(struct TCP_Server_Info *server)
>>  {
>> -     if (echo_retries > 0 && server->tcpStatus == CifsGood &&
>> -         time_after(jiffies, server->lstrp +
>> -                             (echo_retries * SMB_ECHO_INTERVAL))) {
>> +     if (server->tcpStatus == CifsGood &&
>> +         time_after(jiffies, server->lstrp + SMB_ECHO_INTERVAL)) {
>>               cERROR(1, "Server %s has not responded in %d seconds. "
>>                         "Reconnecting...", server->hostname,
>> -                       (echo_retries * SMB_ECHO_INTERVAL / HZ));
>> +                       SMB_ECHO_INTERVAL / HZ);
>
> This will be a problem since we skip sending an echo when the client
> has gotten a response recently (within the last echo interval).
>
> Consider:
>
> 1s      client sends a normal smb request
> 2s      client gets a response
> 30s     echo workqueue job pops, and decides we got a response
>        recently and don't need to send another
> ...
> 65s     kernel_recvmsg times out, and we see that we haven't gotten
>        a response in >60s
>
> ...I think you'll probably want to only reconnect when we haven't
> gotten a response in 2 echo intervals? Or maybe there's a better way?
>

Seems like 2 intervals is good for now. We can change this later, if
we find a better way.

-- 
Best regards,
Pavel Shilovsky.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 05/11] CIFS: Make wait_for_free_request interruptible
       [not found]         ` <20120222141534.5512c3bf-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
@ 2012-02-23  6:18           ` Pavel Shilovsky
       [not found]             ` <CAKywueR7tggS99buChze5WHFY2=daoHUkO41F+WTNfqRT64Syw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 51+ messages in thread
From: Pavel Shilovsky @ 2012-02-23  6:18 UTC (permalink / raw)
  To: Jeff Layton; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

2012/2/22 Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>:
> On Wed, 22 Feb 2012 10:32:58 +0300
> Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
>
>> to let us interrupt the proccess if the session went down and echo
>> is disabled.
>>
>> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
>> ---
>>  fs/cifs/transport.c |    7 ++++++-
>>  1 files changed, 6 insertions(+), 1 deletions(-)
>>
>> diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
>> index fa93720..938d20b 100644
>> --- a/fs/cifs/transport.c
>> +++ b/fs/cifs/transport.c
>> @@ -257,6 +257,8 @@ smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
>>  static int
>>  wait_for_free_request(struct TCP_Server_Info *server, const int long_op)
>>  {
>> +     int rc;
>> +
>>       spin_lock(&server->req_lock);
>>
>>       if (long_op == CIFS_ASYNC_OP) {
>> @@ -271,8 +273,11 @@ wait_for_free_request(struct TCP_Server_Info *server, const int long_op)
>>               if (server->credits <= 0) {
>>                       spin_unlock(&server->req_lock);
>>                       cifs_num_waiters_inc(server);
>> -                     wait_event(server->request_q, get_credits(server) > 0);
>> +                     rc = wait_event_interruptible(server->request_q,
>> +                                                   get_credits(server) > 0);
>>                       cifs_num_waiters_dec(server);
>> +                     if (rc)
>> +                             return rc;
>>                       spin_lock(&server->req_lock);
>>               } else {
>>                       if (server->tcpStatus == CifsExiting) {
>
> In general, I think making this interruptible is a good idea. The
> problem here though is that you're going to end up interrupting this on
> any signal. That includes stuff like SIGCHLD -- you don't necessarily
> want to interrupt this because the process forked off a child earlier
> and then that child exited...
>
> It's probably simpler to just make this a TASK_KILLABLE sleep for that
> reason, rather than trying to handle different signals differently.
>

Ok, good points - will change it.

-- 
Best regards,
Pavel Shilovsky.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 01/11] CIFS: Simplify inFlight logic
       [not found]     ` <1329895984-9251-2-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
@ 2012-02-27 22:53       ` Steve French
       [not found]         ` <CAH2r5msNLEF9qVvKsTVTUnPyUjk+7iYVJTxZgd_uuXLAE0iyRg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 51+ messages in thread
From: Steve French @ 2012-02-27 22:53 UTC (permalink / raw)
  To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

I got a chance to look through this patch set in more detail on the way
to the SMB2.2 test event.  I liked many of the patches, but this one
seems to complicate, rather than simplify by adding a spinlock
to what used to be an atomic_inc.  There is also a possibility that this
spinlock will become hot.  I don't mind moving the atomic_inc inside the
new dec_in_flight macro though to make it easier in the future.

On Wed, Feb 22, 2012 at 1:32 AM, Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> by making it as unsigned integer and surround access with req_lock
> from server structure.
>
> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
> ---
>  fs/cifs/cifs_debug.c |    3 +--
>  fs/cifs/cifsglob.h   |   21 ++++++++++++++++++++-
>  fs/cifs/cifssmb.c    |    6 +++---
>  fs/cifs/connect.c    |   10 +++++-----
>  fs/cifs/transport.c  |   45 +++++++++++++++++++++++----------------------
>  5 files changed, 52 insertions(+), 33 deletions(-)
>
> diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
> index 24b3dfc..573b899 100644
> --- a/fs/cifs/cifs_debug.c
> +++ b/fs/cifs/cifs_debug.c
> @@ -171,8 +171,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
>                        seq_printf(m, "TCP status: %d\n\tLocal Users To "
>                                   "Server: %d SecMode: 0x%x Req On Wire: %d",
>                                   server->tcpStatus, server->srv_count,
> -                                  server->sec_mode,
> -                                  atomic_read(&server->inFlight));
> +                                  server->sec_mode, in_flight(server));
>
>  #ifdef CONFIG_CIFS_STATS2
>                        seq_printf(m, " In Send: %d In MaxReq Wait: %d",
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index 76e7d8b..44cfc9a 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -255,7 +255,8 @@ struct TCP_Server_Info {
>        bool noblocksnd;                /* use blocking sendmsg */
>        bool noautotune;                /* do not autotune send buf sizes */
>        bool tcp_nodelay;
> -       atomic_t inFlight;  /* number of requests on the wire to server */
> +       unsigned int in_flight;  /* number of requests on the wire to server */
> +       spinlock_t req_lock; /* protect the value above */
>        struct mutex srv_mutex;
>        struct task_struct *tsk;
>        char server_GUID[16];
> @@ -307,6 +308,24 @@ struct TCP_Server_Info {
>  #endif
>  };
>
> +static inline unsigned int
> +in_flight(struct TCP_Server_Info *server)
> +{
> +       unsigned int num;
> +       spin_lock(&server->req_lock);
> +       num = server->in_flight;
> +       spin_unlock(&server->req_lock);
> +       return num;
> +}
> +
> +static inline void
> +dec_in_flight(struct TCP_Server_Info *server)
> +{
> +       spin_lock(&server->req_lock);
> +       server->in_flight--;
> +       spin_unlock(&server->req_lock);
> +}
> +
>  /*
>  * Macros to allow the TCP_Server_Info->net field and related code to drop out
>  * when CONFIG_NET_NS isn't set.
> diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
> index 8b7794c..0b50551 100644
> --- a/fs/cifs/cifssmb.c
> +++ b/fs/cifs/cifssmb.c
> @@ -716,7 +716,7 @@ cifs_echo_callback(struct mid_q_entry *mid)
>        struct TCP_Server_Info *server = mid->callback_data;
>
>        DeleteMidQEntry(mid);
> -       atomic_dec(&server->inFlight);
> +       dec_in_flight(server);
>        wake_up(&server->request_q);
>  }
>
> @@ -1669,7 +1669,7 @@ cifs_readv_callback(struct mid_q_entry *mid)
>
>        queue_work(system_nrt_wq, &rdata->work);
>        DeleteMidQEntry(mid);
> -       atomic_dec(&server->inFlight);
> +       dec_in_flight(server);
>        wake_up(&server->request_q);
>  }
>
> @@ -2110,7 +2110,7 @@ cifs_writev_callback(struct mid_q_entry *mid)
>
>        queue_work(system_nrt_wq, &wdata->work);
>        DeleteMidQEntry(mid);
> -       atomic_dec(&tcon->ses->server->inFlight);
> +       dec_in_flight(tcon->ses->server);
>        wake_up(&tcon->ses->server->request_q);
>  }
>
> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
> index 602f77c..12286d0 100644
> --- a/fs/cifs/connect.c
> +++ b/fs/cifs/connect.c
> @@ -647,14 +647,14 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server)
>         * cifs_max_pending is normally 50, but can be set at module install
>         * time to as little as two.
>         */
> -       spin_lock(&GlobalMid_Lock);
> -       if (atomic_read(&server->inFlight) >= cifs_max_pending)
> -               atomic_set(&server->inFlight, cifs_max_pending - 1);
> +       spin_lock(&server->req_lock);
> +       if (server->in_flight >= cifs_max_pending)
> +               server->in_flight = cifs_max_pending - 1;
>        /*
>         * We do not want to set the max_pending too low or we could end up
>         * with the counter going negative.
>         */
> -       spin_unlock(&GlobalMid_Lock);
> +       spin_unlock(&server->req_lock);
>        /*
>         * Although there should not be any requests blocked on this queue it
>         * can not hurt to be paranoid and try to wake up requests that may
> @@ -1909,7 +1909,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
>        tcp_ses->noblocksnd = volume_info->noblocksnd;
>        tcp_ses->noautotune = volume_info->noautotune;
>        tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay;
> -       atomic_set(&tcp_ses->inFlight, 0);
> +       tcp_ses->in_flight = 0;
>        init_waitqueue_head(&tcp_ses->response_q);
>        init_waitqueue_head(&tcp_ses->request_q);
>        INIT_LIST_HEAD(&tcp_ses->pending_mid_q);
> diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
> index 0cc9584..fc1904f 100644
> --- a/fs/cifs/transport.c
> +++ b/fs/cifs/transport.c
> @@ -254,28 +254,29 @@ smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
>        return smb_sendv(server, &iov, 1);
>  }
>
> -static int wait_for_free_request(struct TCP_Server_Info *server,
> -                                const int long_op)
> +static int
> +wait_for_free_request(struct TCP_Server_Info *server, const int long_op)
>  {
> +       spin_lock(&server->req_lock);
> +
>        if (long_op == CIFS_ASYNC_OP) {
>                /* oplock breaks must not be held up */
> -               atomic_inc(&server->inFlight);
> +               server->in_flight++;
> +               spin_unlock(&server->req_lock);
>                return 0;
>        }
>
> -       spin_lock(&GlobalMid_Lock);
>        while (1) {
> -               if (atomic_read(&server->inFlight) >= cifs_max_pending) {
> -                       spin_unlock(&GlobalMid_Lock);
> +               if (server->in_flight >= cifs_max_pending) {
> +                       spin_unlock(&server->req_lock);
>                        cifs_num_waiters_inc(server);
>                        wait_event(server->request_q,
> -                                  atomic_read(&server->inFlight)
> -                                    < cifs_max_pending);
> +                                  in_flight(server) < cifs_max_pending);
>                        cifs_num_waiters_dec(server);
> -                       spin_lock(&GlobalMid_Lock);
> +                       spin_lock(&server->req_lock);
>                } else {
>                        if (server->tcpStatus == CifsExiting) {
> -                               spin_unlock(&GlobalMid_Lock);
> +                               spin_unlock(&server->req_lock);
>                                return -ENOENT;
>                        }
>
> @@ -284,8 +285,8 @@ static int wait_for_free_request(struct TCP_Server_Info *server,
>
>                        /* update # of requests on the wire to server */
>                        if (long_op != CIFS_BLOCKING_OP)
> -                               atomic_inc(&server->inFlight);
> -                       spin_unlock(&GlobalMid_Lock);
> +                               server->in_flight++;
> +                       spin_unlock(&server->req_lock);
>                        break;
>                }
>        }
> @@ -359,7 +360,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
>        mid = AllocMidQEntry(hdr, server);
>        if (mid == NULL) {
>                mutex_unlock(&server->srv_mutex);
> -               atomic_dec(&server->inFlight);
> +               dec_in_flight(server);
>                wake_up(&server->request_q);
>                return -ENOMEM;
>        }
> @@ -392,7 +393,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
>        return rc;
>  out_err:
>        delete_mid(mid);
> -       atomic_dec(&server->inFlight);
> +       dec_in_flight(server);
>        wake_up(&server->request_q);
>        return rc;
>  }
> @@ -564,7 +565,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
>                mutex_unlock(&ses->server->srv_mutex);
>                cifs_small_buf_release(in_buf);
>                /* Update # of requests on wire to server */
> -               atomic_dec(&ses->server->inFlight);
> +               dec_in_flight(ses->server);
>                wake_up(&ses->server->request_q);
>                return rc;
>        }
> @@ -601,7 +602,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
>                        midQ->callback = DeleteMidQEntry;
>                        spin_unlock(&GlobalMid_Lock);
>                        cifs_small_buf_release(in_buf);
> -                       atomic_dec(&ses->server->inFlight);
> +                       dec_in_flight(ses->server);
>                        wake_up(&ses->server->request_q);
>                        return rc;
>                }
> @@ -612,7 +613,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
>
>        rc = cifs_sync_mid_result(midQ, ses->server);
>        if (rc != 0) {
> -               atomic_dec(&ses->server->inFlight);
> +               dec_in_flight(ses->server);
>                wake_up(&ses->server->request_q);
>                return rc;
>        }
> @@ -637,7 +638,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
>                midQ->resp_buf = NULL;
>  out:
>        delete_mid(midQ);
> -       atomic_dec(&ses->server->inFlight);
> +       dec_in_flight(ses->server);
>        wake_up(&ses->server->request_q);
>
>        return rc;
> @@ -688,7 +689,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
>        if (rc) {
>                mutex_unlock(&ses->server->srv_mutex);
>                /* Update # of requests on wire to server */
> -               atomic_dec(&ses->server->inFlight);
> +               dec_in_flight(ses->server);
>                wake_up(&ses->server->request_q);
>                return rc;
>        }
> @@ -721,7 +722,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
>                        /* no longer considered to be "in-flight" */
>                        midQ->callback = DeleteMidQEntry;
>                        spin_unlock(&GlobalMid_Lock);
> -                       atomic_dec(&ses->server->inFlight);
> +                       dec_in_flight(ses->server);
>                        wake_up(&ses->server->request_q);
>                        return rc;
>                }
> @@ -730,7 +731,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
>
>        rc = cifs_sync_mid_result(midQ, ses->server);
>        if (rc != 0) {
> -               atomic_dec(&ses->server->inFlight);
> +               dec_in_flight(ses->server);
>                wake_up(&ses->server->request_q);
>                return rc;
>        }
> @@ -747,7 +748,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
>        rc = cifs_check_receive(midQ, ses->server, 0);
>  out:
>        delete_mid(midQ);
> -       atomic_dec(&ses->server->inFlight);
> +       dec_in_flight(ses->server);
>        wake_up(&ses->server->request_q);
>
>        return rc;
> --
> 1.7.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html



-- 
Thanks,

Steve

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 03/11] CIFS: Count blocking lock command
       [not found]     ` <1329895984-9251-4-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
@ 2012-02-27 23:23       ` Steve French
       [not found]         ` <CAH2r5mujUbTEe0xtk_sfM1xokCk7FnX=6JKO539ut88Z+RS7wA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 51+ messages in thread
From: Steve French @ 2012-02-27 23:23 UTC (permalink / raw)
  To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

I don't think we can do this for the cifs case - 49 blocking locks and
we would deadlock our system (a pending write could block forever) -
for smb2.2 it makes more sense.  I don't think it actually causes a
problem to exceed 50 blocks locks - but if we want to count blocking
locks we will have to limit the maximum number of blocking locks to 2
or 3 less than maxmpx and not allow blocking locks if maxmpx is lower
than 3.

On Wed, Feb 22, 2012 at 1:32 AM, Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> to make sure we don't exceed the number of credits we have in this case.
>
> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
> ---
>  fs/cifs/transport.c |   32 +++++++++++++++++++++-----------
>  1 files changed, 21 insertions(+), 11 deletions(-)
>
> diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
> index 44ac0aa..fa93720 100644
> --- a/fs/cifs/transport.c
> +++ b/fs/cifs/transport.c
> @@ -279,15 +279,8 @@ wait_for_free_request(struct TCP_Server_Info *server, const int long_op)
>                                spin_unlock(&server->req_lock);
>                                return -ENOENT;
>                        }
> -
> -                       /* can not count locking commands against total
> -                          as they are allowed to block on server */
> -
> -                       /* update # of requests on the wire to server */
> -                       if (long_op != CIFS_BLOCKING_OP) {
> -                               server->credits--;
> -                               server->in_flight++;
> -                       }
> +                       server->credits--;
> +                       server->in_flight++;
>                        spin_unlock(&server->req_lock);
>                        break;
>                }
> @@ -816,7 +809,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
>                return -EIO;
>        }
>
> -       rc = wait_for_free_request(ses->server, CIFS_BLOCKING_OP);
> +       rc = wait_for_free_request(ses->server, 0);
>        if (rc)
>                return rc;
>
> @@ -829,6 +822,8 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
>        rc = allocate_mid(ses, in_buf, &midQ);
>        if (rc) {
>                mutex_unlock(&ses->server->srv_mutex);
> +               add_credits(ses->server, 1);
> +               wake_up(&ses->server->request_q);
>                return rc;
>        }
>
> @@ -836,6 +831,8 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
>        if (rc) {
>                delete_mid(midQ);
>                mutex_unlock(&ses->server->srv_mutex);
> +               add_credits(ses->server, 1);
> +               wake_up(&ses->server->request_q);
>                return rc;
>        }
>
> @@ -848,6 +845,8 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
>
>        if (rc < 0) {
>                delete_mid(midQ);
> +               add_credits(ses->server, 1);
> +               wake_up(&ses->server->request_q);
>                return rc;
>        }
>
> @@ -869,6 +868,8 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
>                        rc = send_nt_cancel(ses->server, in_buf, midQ);
>                        if (rc) {
>                                delete_mid(midQ);
> +                               add_credits(ses->server, 1);
> +                               wake_up(&ses->server->request_q);
>                                return rc;
>                        }
>                } else {
> @@ -881,6 +882,8 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
>                           already been removed. Don't exit in this case. */
>                        if (rc && rc != -ENOLCK) {
>                                delete_mid(midQ);
> +                               add_credits(ses->server, 1);
> +                               wake_up(&ses->server->request_q);
>                                return rc;
>                        }
>                }
> @@ -893,6 +896,8 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
>                                /* no longer considered to be "in-flight" */
>                                midQ->callback = DeleteMidQEntry;
>                                spin_unlock(&GlobalMid_Lock);
> +                               add_credits(ses->server, 1);
> +                               wake_up(&ses->server->request_q);
>                                return rc;
>                        }
>                        spin_unlock(&GlobalMid_Lock);
> @@ -903,8 +908,11 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
>        }
>
>        rc = cifs_sync_mid_result(midQ, ses->server);
> -       if (rc != 0)
> +       if (rc != 0) {
> +               add_credits(ses->server, 1);
> +               wake_up(&ses->server->request_q);
>                return rc;
> +       }
>
>        /* rcvd frame is ok */
>        if (out_buf == NULL || midQ->midState != MID_RESPONSE_RECEIVED) {
> @@ -918,6 +926,8 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
>        rc = cifs_check_receive(midQ, ses->server, 0);
>  out:
>        delete_mid(midQ);
> +       add_credits(ses->server, 1);
> +       wake_up(&ses->server->request_q);
>        if (rstart && rc == -EACCES)
>                return -ERESTARTSYS;
>        return rc;
> --
> 1.7.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html



-- 
Thanks,

Steve

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 04/11] CIFS: Delete echo_retries module parm
       [not found]     ` <1329895984-9251-5-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
  2012-02-22 16:23       ` Jeff Layton
@ 2012-02-27 23:39       ` Steve French
  1 sibling, 0 replies; 51+ messages in thread
From: Steve French @ 2012-02-27 23:39 UTC (permalink / raw)
  To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Having interesting conversations here about maxmpx, echo, blocking locks etc.

To Samba apparently we should not be limiting these requests in flight
- they can go far beyond 50 with no problem (although for non-SMB2
case we should be checking for a few other things - like that opens
don't exceed 64K on cifs).

For blocking locks the story (according to Chris H.) is interesting,
but we can allow up to maxmpx (actually maxmpx minus one or two, for
oplock, and one other non-blocking command presumably) per pid-mid
pair (ie mids per process).   So we should be able to allow 48 (or 8,
ie two less than maxmpx, depending on server) simultaneous pending
blocking locks per process (per process/per connection) not per
connection.

On Wed, Feb 22, 2012 at 1:32 AM, Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> It's the essential step before respecting MaxMpxCount value during
> negotiating because we will keep only one extra slot for sending
> echo requests. If there is no response for echo message - reconnect
> the tcp session.
>
> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
> ---
>  fs/cifs/README     |    6 +-----
>  fs/cifs/cifsfs.c   |    5 -----
>  fs/cifs/cifsglob.h |    3 ---
>  fs/cifs/connect.c  |    7 +++----
>  4 files changed, 4 insertions(+), 17 deletions(-)
>
> diff --git a/fs/cifs/README b/fs/cifs/README
> index 895da1d..b7d782b 100644
> --- a/fs/cifs/README
> +++ b/fs/cifs/README
> @@ -753,10 +753,6 @@ module loading or during the runtime by using the interface
>
>  i.e. echo "value" > /sys/module/cifs/parameters/<param>
>
> -1. echo_retries - The number of echo attempts before giving up and
> -                 reconnecting to the server. The default is 5. The value 0
> -                 means never reconnect.
> -
> -2. enable_oplocks - Enable or disable oplocks. Oplocks are enabled by default.
> +1. enable_oplocks - Enable or disable oplocks. Oplocks are enabled by default.
>                    [Y/y/1]. To disable use any of [N/n/0].
>
> diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
> index b1fd382..e1ce1ca 100644
> --- a/fs/cifs/cifsfs.c
> +++ b/fs/cifs/cifsfs.c
> @@ -77,11 +77,6 @@ unsigned int cifs_max_pending = CIFS_MAX_REQ;
>  module_param(cifs_max_pending, int, 0444);
>  MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server. "
>                                   "Default: 50 Range: 2 to 256");
> -unsigned short echo_retries = 5;
> -module_param(echo_retries, ushort, 0644);
> -MODULE_PARM_DESC(echo_retries, "Number of echo attempts before giving up and "
> -                              "reconnecting server. Default: 5. 0 means "
> -                              "never reconnect.");
>  module_param(enable_oplocks, bool, 0644);
>  MODULE_PARM_DESC(enable_oplocks, "Enable or disable oplocks (bool). Default:"
>                                 "y/Y/1");
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index 600d61c..674792e 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -1049,9 +1049,6 @@ GLOBAL_EXTERN unsigned int cifs_min_rcv;    /* min size of big ntwrk buf pool */
>  GLOBAL_EXTERN unsigned int cifs_min_small;  /* min size of small buf pool */
>  GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/
>
> -/* reconnect after this many failed echo attempts */
> -GLOBAL_EXTERN unsigned short echo_retries;
> -
>  #ifdef CONFIG_CIFS_ACL
>  GLOBAL_EXTERN struct rb_root uidtree;
>  GLOBAL_EXTERN struct rb_root gidtree;
> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
> index 673813f..86d7a40 100644
> --- a/fs/cifs/connect.c
> +++ b/fs/cifs/connect.c
> @@ -373,12 +373,11 @@ allocate_buffers(struct TCP_Server_Info *server)
>  static bool
>  server_unresponsive(struct TCP_Server_Info *server)
>  {
> -       if (echo_retries > 0 && server->tcpStatus == CifsGood &&
> -           time_after(jiffies, server->lstrp +
> -                               (echo_retries * SMB_ECHO_INTERVAL))) {
> +       if (server->tcpStatus == CifsGood &&
> +           time_after(jiffies, server->lstrp + SMB_ECHO_INTERVAL)) {
>                cERROR(1, "Server %s has not responded in %d seconds. "
>                          "Reconnecting...", server->hostname,
> -                         (echo_retries * SMB_ECHO_INTERVAL / HZ));
> +                         SMB_ECHO_INTERVAL / HZ);
>                cifs_reconnect(server);
>                wake_up(&server->response_q);
>                return true;
> --
> 1.7.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html



-- 
Thanks,

Steve

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 05/11] CIFS: Make wait_for_free_request interruptible
       [not found]             ` <CAKywueR7tggS99buChze5WHFY2=daoHUkO41F+WTNfqRT64Syw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2012-02-27 23:54               ` Steve French
  0 siblings, 0 replies; 51+ messages in thread
From: Steve French @ 2012-02-27 23:54 UTC (permalink / raw)
  To: Pavel Shilovsky; +Cc: Jeff Layton, linux-cifs-u79uwXL29TY76Z2rM5mHXA

Jeff's point makes sense.  With the suggested fix, seems like reasonable idea.

On Thu, Feb 23, 2012 at 12:18 AM, Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> 2012/2/22 Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>:
>> On Wed, 22 Feb 2012 10:32:58 +0300
>> Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
>>
>>> to let us interrupt the proccess if the session went down and echo
>>> is disabled.
>>>
>>> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
>>> ---
>>>  fs/cifs/transport.c |    7 ++++++-
>>>  1 files changed, 6 insertions(+), 1 deletions(-)
>>>
>>> diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
>>> index fa93720..938d20b 100644
>>> --- a/fs/cifs/transport.c
>>> +++ b/fs/cifs/transport.c
>>> @@ -257,6 +257,8 @@ smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
>>>  static int
>>>  wait_for_free_request(struct TCP_Server_Info *server, const int long_op)
>>>  {
>>> +     int rc;
>>> +
>>>       spin_lock(&server->req_lock);
>>>
>>>       if (long_op == CIFS_ASYNC_OP) {
>>> @@ -271,8 +273,11 @@ wait_for_free_request(struct TCP_Server_Info *server, const int long_op)
>>>               if (server->credits <= 0) {
>>>                       spin_unlock(&server->req_lock);
>>>                       cifs_num_waiters_inc(server);
>>> -                     wait_event(server->request_q, get_credits(server) > 0);
>>> +                     rc = wait_event_interruptible(server->request_q,
>>> +                                                   get_credits(server) > 0);
>>>                       cifs_num_waiters_dec(server);
>>> +                     if (rc)
>>> +                             return rc;
>>>                       spin_lock(&server->req_lock);
>>>               } else {
>>>                       if (server->tcpStatus == CifsExiting) {
>>
>> In general, I think making this interruptible is a good idea. The
>> problem here though is that you're going to end up interrupting this on
>> any signal. That includes stuff like SIGCHLD -- you don't necessarily
>> want to interrupt this because the process forked off a child earlier
>> and then that child exited...
>>
>> It's probably simpler to just make this a TASK_KILLABLE sleep for that
>> reason, rather than trying to handle different signals differently.
>>
>
> Ok, good points - will change it.
>
> --
> Best regards,
> Pavel Shilovsky.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html



-- 
Thanks,

Steve

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 06/11] CIFS: Respect MaxMpxCount field
       [not found]     ` <1329895984-9251-7-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
@ 2012-02-28  0:01       ` Steve French
       [not found]         ` <CAH2r5mvVToaHozN3=YgCCCWFFnjE9AP5xX_BF2JdxDj_JvKsbQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 51+ messages in thread
From: Steve French @ 2012-02-28  0:01 UTC (permalink / raw)
  To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

This is going to be more complicated than it seems.

Apparently (according to Chris), Windows will often allow mapmpx simultaneous
requests per process for various handle based requests.   In addition according
to JRA, Samba server does not care if you go beyond maxmpx (and there is
a big performance advantage of that).   On the other hand - if the server
sets maxmpx to less than 10, these kind of changes probably make sense
(those servers are probably broken otherwise), but for normal servers
this will end up restricting more than windows (for more than than the
maxmpx per pid).   Generally, for servers like Samba that support
simultaneous requests reasonably we have to be careful about killing
performance especially now that with Jeff's async reads and writes
we will frequently get up to 50 (and should probably make it easier
to have more than 50 to servers like Samba).

Quoting JRA and Volker - "You should be able to queue
thousands of simultaneous requests from one client to Samba"
(as long as the client doesn't time out.  The server keeps
responding to the earlier requests, so with our client timeout
code weshould be fine).

On Wed, Feb 22, 2012 at 1:32 AM, Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> by setting the number of available credits to it except 2 that goes
> to extra echo and oplock slots. If MaxMpxCount is 2 - disable oplocks,
> if 1 - disable oplocks and echos.
>
> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
> ---
>  fs/cifs/cifsfs.c    |   12 --------
>  fs/cifs/cifsglob.h  |   60 ++++++++++++++++++--------------------
>  fs/cifs/cifsproto.h |    7 ++++-
>  fs/cifs/cifssmb.c   |   16 ++++++----
>  fs/cifs/connect.c   |   10 +++---
>  fs/cifs/dir.c       |    5 ++-
>  fs/cifs/file.c      |    4 +-
>  fs/cifs/misc.c      |   49 +++++++++++++++++++++++++++++++
>  fs/cifs/transport.c |   79 +++++++++++++++++++++++++--------------------------
>  9 files changed, 142 insertions(+), 100 deletions(-)
>
> diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
> index e1ce1ca..a9b483b 100644
> --- a/fs/cifs/cifsfs.c
> +++ b/fs/cifs/cifsfs.c
> @@ -73,10 +73,6 @@ unsigned int cifs_min_small = 30;
>  module_param(cifs_min_small, int, 0);
>  MODULE_PARM_DESC(cifs_min_small, "Small network buffers in pool. Default: 30 "
>                                 "Range: 2 to 256");
> -unsigned int cifs_max_pending = CIFS_MAX_REQ;
> -module_param(cifs_max_pending, int, 0444);
> -MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server. "
> -                                  "Default: 50 Range: 2 to 256");
>  module_param(enable_oplocks, bool, 0644);
>  MODULE_PARM_DESC(enable_oplocks, "Enable or disable oplocks (bool). Default:"
>                                 "y/Y/1");
> @@ -1108,14 +1104,6 @@ init_cifs(void)
>        spin_lock_init(&cifs_file_list_lock);
>        spin_lock_init(&GlobalMid_Lock);
>
> -       if (cifs_max_pending < 2) {
> -               cifs_max_pending = 2;
> -               cFYI(1, "cifs_max_pending set to min of 2");
> -       } else if (cifs_max_pending > 256) {
> -               cifs_max_pending = 256;
> -               cFYI(1, "cifs_max_pending set to max of 256");
> -       }
> -
>        rc = cifs_fscache_register();
>        if (rc)
>                goto out_clean_proc;
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index 674792e..4b13be5 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -53,17 +53,6 @@
>  */
>  #define CIFS_MAX_ACTIMEO (1 << 30)
>
> -/*
> - * MAX_REQ is the maximum number of requests that WE will send
> - * on one socket concurrently. It also matches the most common
> - * value of max multiplex returned by servers.  We may
> - * eventually want to use the negotiated value (in case
> - * future servers can handle more) when we are more confident that
> - * we will not have problems oveloading the socket with pending
> - * write data.
> - */
> -#define CIFS_MAX_REQ 50
> -
>  #define RFC1001_NAME_LEN 15
>  #define RFC1001_NAME_LEN_WITH_NULL (RFC1001_NAME_LEN + 1)
>
> @@ -255,7 +244,11 @@ struct TCP_Server_Info {
>        bool noblocksnd;                /* use blocking sendmsg */
>        bool noautotune;                /* do not autotune send buf sizes */
>        bool tcp_nodelay;
> -       int credits;  /* send no more requests at once */
> +       bool oplocks:1; /* server supports async oplock breaks */
> +       bool echos:1; /* server supports async echos */
> +       unsigned int echo_credits; /* reserve for echos */
> +       unsigned int oplock_credits; /* reserve for oplock breaks */
> +       unsigned int credits;  /* send no more requests at once */
>        unsigned int in_flight;  /* number of requests on the wire to server */
>        spinlock_t req_lock;  /* protect the two values above */
>        struct mutex srv_mutex;
> @@ -309,6 +302,12 @@ struct TCP_Server_Info {
>  #endif
>  };
>
> +/*
> + * The minimal value to set before negotiating and don't issue extra messaging
> + * in cifs_change_conf.
> + */
> +#define CIFS_CREDITS_DEFAULT 3
> +
>  static inline unsigned int
>  in_flight(struct TCP_Server_Info *server)
>  {
> @@ -319,31 +318,31 @@ in_flight(struct TCP_Server_Info *server)
>        return num;
>  }
>
> -static inline int
> -get_credits(struct TCP_Server_Info *server)
> -{
> -       int num;
> -       spin_lock(&server->req_lock);
> -       num = server->credits;
> -       spin_unlock(&server->req_lock);
> -       return num;
> -}
> +#define   CIFS_OBREAK_OP    0x080    /* oplock break request */
> +#define   CIFS_ECHO_OP     0x0100    /* echo request */
> +#define   CIFS_REQ_MASK    0x0180    /* mask request type */
>
> -static inline void
> -add_credits(struct TCP_Server_Info *server, unsigned int add)
> +static inline unsigned int*
> +get_credits_field(struct TCP_Server_Info *server, const int optype)
>  {
> -       spin_lock(&server->req_lock);
> -       server->credits += add;
> -       server->in_flight--;
> -       spin_unlock(&server->req_lock);
> +       switch (optype) {
> +       case CIFS_ECHO_OP:
> +               return &server->echo_credits;
> +       case CIFS_OBREAK_OP:
> +               return &server->oplock_credits;
> +       default:
> +               return &server->credits;
> +       }
>  }
>
> -static inline void
> -set_credits(struct TCP_Server_Info *server, int val)
> +static inline bool
> +has_free_credits(struct TCP_Server_Info *server, unsigned int *val)
>  {
> +       bool res;
>        spin_lock(&server->req_lock);
> -       server->credits = val;
> +       res = *val > 0;
>        spin_unlock(&server->req_lock);
> +       return res;
>  }
>
>  /*
> @@ -1047,7 +1046,6 @@ GLOBAL_EXTERN unsigned int linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/
>  GLOBAL_EXTERN unsigned int CIFSMaxBufSize;  /* max size not including hdr */
>  GLOBAL_EXTERN unsigned int cifs_min_rcv;    /* min size of big ntwrk buf pool */
>  GLOBAL_EXTERN unsigned int cifs_min_small;  /* min size of small buf pool */
> -GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/
>
>  #ifdef CONFIG_CIFS_ACL
>  GLOBAL_EXTERN struct rb_root uidtree;
> diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
> index 6f4e243..75163a6 100644
> --- a/fs/cifs/cifsproto.h
> +++ b/fs/cifs/cifsproto.h
> @@ -71,7 +71,7 @@ extern void DeleteMidQEntry(struct mid_q_entry *midEntry);
>  extern int cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
>                           unsigned int nvec, mid_receive_t *receive,
>                           mid_callback_t *callback, void *cbdata,
> -                          bool ignore_pend);
> +                          int optype);
>  extern int SendReceive(const unsigned int /* xid */ , struct cifs_ses *,
>                        struct smb_hdr * /* input */ ,
>                        struct smb_hdr * /* out */ ,
> @@ -169,6 +169,11 @@ extern struct smb_vol *cifs_get_volume_info(char *mount_data,
>  extern int cifs_mount(struct cifs_sb_info *, struct smb_vol *);
>  extern void cifs_umount(struct cifs_sb_info *);
>  extern void cifs_dfs_release_automount_timer(void);
> +extern int cifs_reconnect(struct TCP_Server_Info *server);
> +extern void cifs_change_conf(struct TCP_Server_Info *server);
> +extern void add_credits(struct TCP_Server_Info *server, unsigned int add,
> +                       const int optype);
> +extern void set_credits(struct TCP_Server_Info *server, unsigned int val);
>  void cifs_proc_init(void);
>  void cifs_proc_clean(void);
>
> diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
> index c255c25..985dcce 100644
> --- a/fs/cifs/cifssmb.c
> +++ b/fs/cifs/cifssmb.c
> @@ -459,6 +459,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
>                }
>                server->sec_mode = (__u8)le16_to_cpu(rsp->SecurityMode);
>                server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
> +               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
> @@ -565,6 +566,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
>        /* one byte, so no need to convert this or EncryptionKeyLen from
>           little endian */
>        server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
> +       set_credits(server, server->maxReq);
>        /* probably no need to store and check maxvcs */
>        server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
>        server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
> @@ -716,7 +718,7 @@ cifs_echo_callback(struct mid_q_entry *mid)
>        struct TCP_Server_Info *server = mid->callback_data;
>
>        DeleteMidQEntry(mid);
> -       add_credits(server, 1);
> +       add_credits(server, 1, CIFS_ECHO_OP);
>        wake_up(&server->request_q);
>  }
>
> @@ -744,7 +746,7 @@ CIFSSMBEcho(struct TCP_Server_Info *server)
>        iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
>
>        rc = cifs_call_async(server, &iov, 1, NULL, cifs_echo_callback,
> -                            server, true);
> +                            server, CIFS_ECHO_OP);
>        if (rc)
>                cFYI(1, "Echo request failed: %d", rc);
>
> @@ -1669,7 +1671,7 @@ cifs_readv_callback(struct mid_q_entry *mid)
>
>        queue_work(system_nrt_wq, &rdata->work);
>        DeleteMidQEntry(mid);
> -       add_credits(server, 1);
> +       add_credits(server, 1, 0);
>        wake_up(&server->request_q);
>  }
>
> @@ -1725,7 +1727,7 @@ cifs_async_readv(struct cifs_readdata *rdata)
>
>        rc = cifs_call_async(tcon->ses->server, rdata->iov, 1,
>                             cifs_readv_receive, cifs_readv_callback,
> -                            rdata, false);
> +                            rdata, 0);
>
>        if (rc == 0)
>                cifs_stats_inc(&tcon->num_reads);
> @@ -2110,7 +2112,7 @@ cifs_writev_callback(struct mid_q_entry *mid)
>
>        queue_work(system_nrt_wq, &wdata->work);
>        DeleteMidQEntry(mid);
> -       add_credits(tcon->ses->server, 1);
> +       add_credits(tcon->ses->server, 1, 0);
>        wake_up(&tcon->ses->server->request_q);
>  }
>
> @@ -2194,7 +2196,7 @@ cifs_async_writev(struct cifs_writedata *wdata)
>
>        kref_get(&wdata->refcount);
>        rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1,
> -                            NULL, cifs_writev_callback, wdata, false);
> +                            NULL, cifs_writev_callback, wdata, 0);
>
>        if (rc == 0)
>                cifs_stats_inc(&tcon->num_writes);
> @@ -2382,7 +2384,7 @@ CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
>                return rc;
>
>        if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
> -               timeout = CIFS_ASYNC_OP; /* no response expected */
> +               timeout = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
>                pSMB->Timeout = 0;
>        } else if (waitFlag) {
>                timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
> index 86d7a40..aa97dab 100644
> --- a/fs/cifs/connect.c
> +++ b/fs/cifs/connect.c
> @@ -78,7 +78,7 @@ static int cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data,
>  * reconnect tcp session
>  * wake up waiters on reconnection? - (not needed currently)
>  */
> -static int
> +int
>  cifs_reconnect(struct TCP_Server_Info *server)
>  {
>        int rc = 0;
> @@ -324,7 +324,7 @@ cifs_echo_request(struct work_struct *work)
>         * done, which is indicated by maxBuf != 0. Also, no need to ping if
>         * we got a response recently
>         */
> -       if (server->maxBuf == 0 ||
> +       if (!server->echos || server->maxBuf == 0 ||
>            time_before(jiffies, server->lstrp + SMB_ECHO_INTERVAL - HZ))
>                goto requeue_echo;
>
> @@ -1901,7 +1901,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
>        tcp_ses->noautotune = volume_info->noautotune;
>        tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay;
>        tcp_ses->in_flight = 0;
> -       tcp_ses->credits = cifs_max_pending;
> +       tcp_ses->credits = CIFS_CREDITS_DEFAULT;
>        init_waitqueue_head(&tcp_ses->response_q);
>        init_waitqueue_head(&tcp_ses->request_q);
>        INIT_LIST_HEAD(&tcp_ses->pending_mid_q);
> @@ -3751,11 +3751,11 @@ int cifs_negotiate_protocol(unsigned int xid, struct cifs_ses *ses)
>        if (server->maxBuf != 0)
>                return 0;
>
> -       set_credits(server, cifs_max_pending);
> +       set_credits(server, CIFS_CREDITS_DEFAULT);
>        rc = CIFSSMBNegotiate(xid, ses);
>        if (rc == -EAGAIN) {
>                /* retry only once on 1st time connection */
> -               set_credits(server, cifs_max_pending);
> +               set_credits(server, CIFS_CREDITS_DEFAULT);
>                rc = CIFSSMBNegotiate(xid, ses);
>                if (rc == -EAGAIN)
>                        rc = -EHOSTDOWN;
> diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
> index 63a196b..e183e38 100644
> --- a/fs/cifs/dir.c
> +++ b/fs/cifs/dir.c
> @@ -171,7 +171,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
>        }
>        tcon = tlink_tcon(tlink);
>
> -       if (enable_oplocks)
> +       if (tcon->ses->server->oplocks)
>                oplock = REQ_OPLOCK;
>
>        if (nd)
> @@ -492,7 +492,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
>  {
>        int xid;
>        int rc = 0; /* to get around spurious gcc warning, set to zero here */
> -       __u32 oplock = enable_oplocks ? REQ_OPLOCK : 0;
> +       __u32 oplock;
>        __u16 fileHandle = 0;
>        bool posix_open = false;
>        struct cifs_sb_info *cifs_sb;
> @@ -517,6 +517,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
>                return (struct dentry *)tlink;
>        }
>        pTcon = tlink_tcon(tlink);
> +       oplock = pTcon->ses->server->oplocks ? REQ_OPLOCK : 0;
>
>        /*
>         * Don't allow the separator character in a path component.
> diff --git a/fs/cifs/file.c b/fs/cifs/file.c
> index 4dd9283..b5e38b1 100644
> --- a/fs/cifs/file.c
> +++ b/fs/cifs/file.c
> @@ -380,7 +380,7 @@ int cifs_open(struct inode *inode, struct file *file)
>        cFYI(1, "inode = 0x%p file flags are 0x%x for %s",
>                 inode, file->f_flags, full_path);
>
> -       if (enable_oplocks)
> +       if (tcon->ses->server->oplocks)
>                oplock = REQ_OPLOCK;
>        else
>                oplock = 0;
> @@ -505,7 +505,7 @@ static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
>        cFYI(1, "inode = 0x%p file flags 0x%x for %s",
>                 inode, pCifsFile->f_flags, full_path);
>
> -       if (enable_oplocks)
> +       if (tcon->ses->server->oplocks)
>                oplock = REQ_OPLOCK;
>        else
>                oplock = 0;
> diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
> index 703ef5c..e14dc8f 100644
> --- a/fs/cifs/misc.c
> +++ b/fs/cifs/misc.c
> @@ -690,3 +690,52 @@ backup_cred(struct cifs_sb_info *cifs_sb)
>
>        return false;
>  }
> +
> +void
> +cifs_change_conf(struct TCP_Server_Info *server)
> +{
> +       server->oplock_credits = server->echo_credits = 0;
> +       switch (server->credits) {
> +       case 0:
> +               cifs_reconnect(server);
> +               return;
> +       case 1:
> +               server->echos = false;
> +               server->oplocks = false;
> +               cERROR(1, "disabling echos and oplocks");
> +               break;
> +       case 2:
> +               server->echos = true;
> +               server->oplocks = false;
> +               server->echo_credits = 1;
> +               cFYI(1, "disabling oplocks");
> +               break;
> +       default:
> +               server->echos = true;
> +               server->oplocks = true;
> +               server->echo_credits = 1;
> +               server->oplock_credits = 1;
> +       }
> +       server->credits -= server->echo_credits + server->oplock_credits;
> +}
> +
> +void
> +add_credits(struct TCP_Server_Info *server, const unsigned int add,
> +           const int optype)
> +{
> +       unsigned int *val;
> +       spin_lock(&server->req_lock);
> +       val = get_credits_field(server, optype);
> +       *val += add;
> +       server->in_flight--;
> +       spin_unlock(&server->req_lock);
> +}
> +
> +void
> +set_credits(struct TCP_Server_Info *server, const unsigned int val)
> +{
> +       spin_lock(&server->req_lock);
> +       server->credits = val;
> +       cifs_change_conf(server);
> +       spin_unlock(&server->req_lock);
> +}
> diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
> index 938d20b..91f009d 100644
> --- a/fs/cifs/transport.c
> +++ b/fs/cifs/transport.c
> @@ -255,44 +255,41 @@ smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
>  }
>
>  static int
> -wait_for_free_request(struct TCP_Server_Info *server, const int long_op)
> +wait_for_free_credits(struct TCP_Server_Info *server, unsigned int *num)
>  {
>        int rc;
>
> -       spin_lock(&server->req_lock);
> -
> -       if (long_op == CIFS_ASYNC_OP) {
> -               /* oplock breaks must not be held up */
> -               server->in_flight++;
> -               server->credits--;
> -               spin_unlock(&server->req_lock);
> -               return 0;
> -       }
> -
>        while (1) {
> -               if (server->credits <= 0) {
> +               if (*num == 0) {
>                        spin_unlock(&server->req_lock);
>                        cifs_num_waiters_inc(server);
>                        rc = wait_event_interruptible(server->request_q,
> -                                                     get_credits(server) > 0);
> +                                               has_free_credits(server, num));
>                        cifs_num_waiters_dec(server);
>                        if (rc)
>                                return rc;
>                        spin_lock(&server->req_lock);
>                } else {
> -                       if (server->tcpStatus == CifsExiting) {
> -                               spin_unlock(&server->req_lock);
> +                       if (server->tcpStatus == CifsExiting)
>                                return -ENOENT;
> -                       }
> -                       server->credits--;
> +                       *num -= 1;
>                        server->in_flight++;
> -                       spin_unlock(&server->req_lock);
>                        break;
>                }
>        }
>        return 0;
>  }
>
> +static int
> +wait_for_free_request(struct TCP_Server_Info *server, const int optype)
> +{
> +       int rc;
> +       spin_lock(&server->req_lock);
> +       rc = wait_for_free_credits(server, get_credits_field(server, optype));
> +       spin_unlock(&server->req_lock);
> +       return rc;
> +}
> +
>  static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
>                        struct mid_q_entry **ppmidQ)
>  {
> @@ -342,13 +339,13 @@ wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
>  int
>  cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
>                unsigned int nvec, mid_receive_t *receive,
> -               mid_callback_t *callback, void *cbdata, bool ignore_pend)
> +               mid_callback_t *callback, void *cbdata, int optype)
>  {
>        int rc;
>        struct mid_q_entry *mid;
>        struct smb_hdr *hdr = (struct smb_hdr *)iov[0].iov_base;
>
> -       rc = wait_for_free_request(server, ignore_pend ? CIFS_ASYNC_OP : 0);
> +       rc = wait_for_free_request(server, optype);
>        if (rc)
>                return rc;
>
> @@ -360,7 +357,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
>        mid = AllocMidQEntry(hdr, server);
>        if (mid == NULL) {
>                mutex_unlock(&server->srv_mutex);
> -               add_credits(server, 1);
> +               add_credits(server, 1, optype);
>                wake_up(&server->request_q);
>                return -ENOMEM;
>        }
> @@ -393,7 +390,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
>        return rc;
>  out_err:
>        delete_mid(mid);
> -       add_credits(server, 1);
> +       add_credits(server, 1, optype);
>        wake_up(&server->request_q);
>        return rc;
>  }
> @@ -526,10 +523,12 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
>  {
>        int rc = 0;
>        int long_op;
> +       int optype;
>        struct mid_q_entry *midQ;
>        struct smb_hdr *in_buf = iov[0].iov_base;
>
>        long_op = flags & CIFS_TIMEOUT_MASK;
> +       optype = flags & CIFS_REQ_MASK;
>
>        *pRespBufType = CIFS_NO_BUFFER;  /* no response buf yet */
>
> @@ -548,7 +547,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
>           to the same server. We may make this configurable later or
>           use ses->maxReq */
>
> -       rc = wait_for_free_request(ses->server, long_op);
> +       rc = wait_for_free_request(ses->server, optype);
>        if (rc) {
>                cifs_small_buf_release(in_buf);
>                return rc;
> @@ -565,7 +564,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
>                mutex_unlock(&ses->server->srv_mutex);
>                cifs_small_buf_release(in_buf);
>                /* Update # of requests on wire to server */
> -               add_credits(ses->server, 1);
> +               add_credits(ses->server, 1, optype);
>                wake_up(&ses->server->request_q);
>                return rc;
>        }
> @@ -602,7 +601,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
>                        midQ->callback = DeleteMidQEntry;
>                        spin_unlock(&GlobalMid_Lock);
>                        cifs_small_buf_release(in_buf);
> -                       add_credits(ses->server, 1);
> +                       add_credits(ses->server, 1, optype);
>                        wake_up(&ses->server->request_q);
>                        return rc;
>                }
> @@ -613,7 +612,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
>
>        rc = cifs_sync_mid_result(midQ, ses->server);
>        if (rc != 0) {
> -               add_credits(ses->server, 1);
> +               add_credits(ses->server, 1, optype);
>                wake_up(&ses->server->request_q);
>                return rc;
>        }
> @@ -638,7 +637,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
>                midQ->resp_buf = NULL;
>  out:
>        delete_mid(midQ);
> -       add_credits(ses->server, 1);
> +       add_credits(ses->server, 1, optype);
>        wake_up(&ses->server->request_q);
>
>        return rc;
> @@ -675,7 +674,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
>                return -EIO;
>        }
>
> -       rc = wait_for_free_request(ses->server, long_op);
> +       rc = wait_for_free_request(ses->server, 0);
>        if (rc)
>                return rc;
>
> @@ -689,7 +688,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
>        if (rc) {
>                mutex_unlock(&ses->server->srv_mutex);
>                /* Update # of requests on wire to server */
> -               add_credits(ses->server, 1);
> +               add_credits(ses->server, 1, 0);
>                wake_up(&ses->server->request_q);
>                return rc;
>        }
> @@ -722,7 +721,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
>                        /* no longer considered to be "in-flight" */
>                        midQ->callback = DeleteMidQEntry;
>                        spin_unlock(&GlobalMid_Lock);
> -                       add_credits(ses->server, 1);
> +                       add_credits(ses->server, 1, 0);
>                        wake_up(&ses->server->request_q);
>                        return rc;
>                }
> @@ -731,7 +730,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
>
>        rc = cifs_sync_mid_result(midQ, ses->server);
>        if (rc != 0) {
> -               add_credits(ses->server, 1);
> +               add_credits(ses->server, 1, 0);
>                wake_up(&ses->server->request_q);
>                return rc;
>        }
> @@ -748,7 +747,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
>        rc = cifs_check_receive(midQ, ses->server, 0);
>  out:
>        delete_mid(midQ);
> -       add_credits(ses->server, 1);
> +       add_credits(ses->server, 1, 0);
>        wake_up(&ses->server->request_q);
>
>        return rc;
> @@ -827,7 +826,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
>        rc = allocate_mid(ses, in_buf, &midQ);
>        if (rc) {
>                mutex_unlock(&ses->server->srv_mutex);
> -               add_credits(ses->server, 1);
> +               add_credits(ses->server, 1, 0);
>                wake_up(&ses->server->request_q);
>                return rc;
>        }
> @@ -836,7 +835,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
>        if (rc) {
>                delete_mid(midQ);
>                mutex_unlock(&ses->server->srv_mutex);
> -               add_credits(ses->server, 1);
> +               add_credits(ses->server, 1, 0);
>                wake_up(&ses->server->request_q);
>                return rc;
>        }
> @@ -850,7 +849,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
>
>        if (rc < 0) {
>                delete_mid(midQ);
> -               add_credits(ses->server, 1);
> +               add_credits(ses->server, 1, 0);
>                wake_up(&ses->server->request_q);
>                return rc;
>        }
> @@ -873,7 +872,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
>                        rc = send_nt_cancel(ses->server, in_buf, midQ);
>                        if (rc) {
>                                delete_mid(midQ);
> -                               add_credits(ses->server, 1);
> +                               add_credits(ses->server, 1, 0);
>                                wake_up(&ses->server->request_q);
>                                return rc;
>                        }
> @@ -887,7 +886,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
>                           already been removed. Don't exit in this case. */
>                        if (rc && rc != -ENOLCK) {
>                                delete_mid(midQ);
> -                               add_credits(ses->server, 1);
> +                               add_credits(ses->server, 1, 0);
>                                wake_up(&ses->server->request_q);
>                                return rc;
>                        }
> @@ -901,7 +900,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
>                                /* no longer considered to be "in-flight" */
>                                midQ->callback = DeleteMidQEntry;
>                                spin_unlock(&GlobalMid_Lock);
> -                               add_credits(ses->server, 1);
> +                               add_credits(ses->server, 1, 0);
>                                wake_up(&ses->server->request_q);
>                                return rc;
>                        }
> @@ -914,7 +913,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
>
>        rc = cifs_sync_mid_result(midQ, ses->server);
>        if (rc != 0) {
> -               add_credits(ses->server, 1);
> +               add_credits(ses->server, 1, 0);
>                wake_up(&ses->server->request_q);
>                return rc;
>        }
> @@ -931,7 +930,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
>        rc = cifs_check_receive(midQ, ses->server, 0);
>  out:
>        delete_mid(midQ);
> -       add_credits(ses->server, 1);
> +       add_credits(ses->server, 1, 0);
>        wake_up(&ses->server->request_q);
>        if (rstart && rc == -EACCES)
>                return -ERESTARTSYS;
> --
> 1.7.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html



-- 
Thanks,

Steve

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 07/11] CIFS: Separate protocol-specific code from transport routines
       [not found]     ` <1329895984-9251-8-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
@ 2012-02-28  0:03       ` Steve French
  0 siblings, 0 replies; 51+ messages in thread
From: Steve French @ 2012-02-28  0:03 UTC (permalink / raw)
  To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

Looks reasonable to me.

On Wed, Feb 22, 2012 at 1:33 AM, Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> that lets us use this functions for SMB2.
>
> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
> ---
>  fs/cifs/cifs_debug.h |    2 +-
>  fs/cifs/cifsglob.h   |    6 ++
>  fs/cifs/cifsproto.h  |    2 +-
>  fs/cifs/cifssmb.c    |   21 +++---
>  fs/cifs/misc.c       |    5 +-
>  fs/cifs/transport.c  |  171 +++++++++++++++++++++++++++++---------------------
>  6 files changed, 119 insertions(+), 88 deletions(-)
>
> diff --git a/fs/cifs/cifs_debug.h b/fs/cifs/cifs_debug.h
> index 8942b28..0a234c1 100644
> --- a/fs/cifs/cifs_debug.h
> +++ b/fs/cifs/cifs_debug.h
> @@ -32,7 +32,7 @@ void cifs_dump_mids(struct TCP_Server_Info *);
>  #define DBG2 0
>  #endif
>  extern int traceSMB;           /* flag which enables the function below */
> -void dump_smb(struct smb_hdr *, int);
> +void dump_smb(void *, int);
>  #define CIFS_INFO      0x01
>  #define CIFS_RC                0x02
>  #define CIFS_TIMER     0x04
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index 4b13be5..e56baca 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -224,6 +224,12 @@ struct cifs_mnt_data {
>        int flags;
>  };
>
> +static inline unsigned int
> +get_rfc1002_length(void *buf)
> +{
> +       return be32_to_cpu(*((__be32 *)buf));
> +}
> +
>  struct TCP_Server_Info {
>        struct list_head tcp_ses_list;
>        struct list_head smb_ses_list;
> diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
> index 75163a6..6ba8d1c 100644
> --- a/fs/cifs/cifsproto.h
> +++ b/fs/cifs/cifsproto.h
> @@ -77,7 +77,7 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifs_ses *,
>                        struct smb_hdr * /* out */ ,
>                        int * /* bytes returned */ , const int long_op);
>  extern int SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
> -                       struct smb_hdr *in_buf, int flags);
> +                           char *in_buf, int flags);
>  extern int cifs_check_receive(struct mid_q_entry *mid,
>                        struct TCP_Server_Info *server, bool log_error);
>  extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *,
> diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
> index 985dcce..5ba869f 100644
> --- a/fs/cifs/cifssmb.c
> +++ b/fs/cifs/cifssmb.c
> @@ -693,7 +693,7 @@ CIFSSMBTDis(const int xid, struct cifs_tcon *tcon)
>        if (rc)
>                return rc;
>
> -       rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
> +       rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
>        if (rc)
>                cFYI(1, "Tree disconnect failed %d", rc);
>
> @@ -790,7 +790,7 @@ CIFSSMBLogoff(const int xid, struct cifs_ses *ses)
>        pSMB->hdr.Uid = ses->Suid;
>
>        pSMB->AndXCommand = 0xFF;
> -       rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
> +       rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
>  session_already_dead:
>        mutex_unlock(&ses->session_mutex);
>
> @@ -2420,8 +2420,7 @@ CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
>                        (struct smb_hdr *) pSMB, &bytes_returned);
>                cifs_small_buf_release(pSMB);
>        } else {
> -               rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
> -                                     timeout);
> +               rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, timeout);
>                /* SMB buffer freed by function above */
>        }
>        cifs_stats_inc(&tcon->num_locks);
> @@ -2588,7 +2587,7 @@ CIFSSMBClose(const int xid, struct cifs_tcon *tcon, int smb_file_id)
>        pSMB->FileID = (__u16) smb_file_id;
>        pSMB->LastWriteTime = 0xFFFFFFFF;
>        pSMB->ByteCount = 0;
> -       rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
> +       rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
>        cifs_stats_inc(&tcon->num_closes);
>        if (rc) {
>                if (rc != -EINTR) {
> @@ -2617,7 +2616,7 @@ CIFSSMBFlush(const int xid, struct cifs_tcon *tcon, int smb_file_id)
>
>        pSMB->FileID = (__u16) smb_file_id;
>        pSMB->ByteCount = 0;
> -       rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
> +       rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
>        cifs_stats_inc(&tcon->num_flushes);
>        if (rc)
>                cERROR(1, "Send error in Flush = %d", rc);
> @@ -4625,7 +4624,7 @@ CIFSFindClose(const int xid, struct cifs_tcon *tcon,
>
>        pSMB->FileID = searchHandle;
>        pSMB->ByteCount = 0;
> -       rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
> +       rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
>        if (rc)
>                cERROR(1, "Send error in FindClose = %d", rc);
>
> @@ -5646,7 +5645,7 @@ CIFSSMBSetFileSize(const int xid, struct cifs_tcon *tcon, __u64 size,
>        pSMB->Reserved4 = 0;
>        inc_rfc1001_len(pSMB, byte_count);
>        pSMB->ByteCount = cpu_to_le16(byte_count);
> -       rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
> +       rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
>        if (rc) {
>                cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
>        }
> @@ -5715,7 +5714,7 @@ CIFSSMBSetFileInfo(const int xid, struct cifs_tcon *tcon,
>        inc_rfc1001_len(pSMB, byte_count);
>        pSMB->ByteCount = cpu_to_le16(byte_count);
>        memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
> -       rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
> +       rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
>        if (rc)
>                cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
>
> @@ -5774,7 +5773,7 @@ CIFSSMBSetFileDisposition(const int xid, struct cifs_tcon *tcon,
>        inc_rfc1001_len(pSMB, byte_count);
>        pSMB->ByteCount = cpu_to_le16(byte_count);
>        *data_offset = delete_file ? 1 : 0;
> -       rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
> +       rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
>        if (rc)
>                cFYI(1, "Send error in SetFileDisposition = %d", rc);
>
> @@ -6006,7 +6005,7 @@ CIFSSMBUnixSetFileInfo(const int xid, struct cifs_tcon *tcon,
>
>        cifs_fill_unix_set_info(data_offset, args);
>
> -       rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
> +       rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
>        if (rc)
>                cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
>
> diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
> index e14dc8f..8e7516f 100644
> --- a/fs/cifs/misc.c
> +++ b/fs/cifs/misc.c
> @@ -604,16 +604,15 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
>  }
>
>  void
> -dump_smb(struct smb_hdr *smb_buf, int smb_buf_length)
> +dump_smb(void *buf, int smb_buf_length)
>  {
>        int i, j;
>        char debug_line[17];
> -       unsigned char *buffer;
> +       unsigned char *buffer = buf;
>
>        if (traceSMB == 0)
>                return;
>
> -       buffer = (unsigned char *) smb_buf;
>        for (i = 0, j = 0; i < smb_buf_length; i++, j++) {
>                if (i % 8 == 0) {
>                        /* have reached the beginning of line */
> diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
> index 91f009d..0d2707e 100644
> --- a/fs/cifs/transport.c
> +++ b/fs/cifs/transport.c
> @@ -126,11 +126,11 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
>        int rc = 0;
>        int i = 0;
>        struct msghdr smb_msg;
> -       struct smb_hdr *smb_buffer = iov[0].iov_base;
> +       __be32 *buf_len = (__be32 *)(iov[0].iov_base);
>        unsigned int len = iov[0].iov_len;
>        unsigned int total_len;
>        int first_vec = 0;
> -       unsigned int smb_buf_length = be32_to_cpu(smb_buffer->smb_buf_length);
> +       unsigned int smb_buf_length = get_rfc1002_length(iov[0].iov_base);
>        struct socket *ssocket = server->ssocket;
>
>        if (ssocket == NULL)
> @@ -150,7 +150,7 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
>                total_len += iov[i].iov_len;
>
>        cFYI(1, "Sending smb:  total_len %d", total_len);
> -       dump_smb(smb_buffer, len);
> +       dump_smb(iov[0].iov_base, len);
>
>        i = 0;
>        while (total_len) {
> @@ -158,24 +158,24 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
>                                    n_vec - first_vec, total_len);
>                if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
>                        i++;
> -                       /* if blocking send we try 3 times, since each can block
> -                          for 5 seconds. For nonblocking  we have to try more
> -                          but wait increasing amounts of time allowing time for
> -                          socket to clear.  The overall time we wait in either
> -                          case to send on the socket is about 15 seconds.
> -                          Similarly we wait for 15 seconds for
> -                          a response from the server in SendReceive[2]
> -                          for the server to send a response back for
> -                          most types of requests (except SMB Write
> -                          past end of file which can be slow, and
> -                          blocking lock operations). NFS waits slightly longer
> -                          than CIFS, but this can make it take longer for
> -                          nonresponsive servers to be detected and 15 seconds
> -                          is more than enough time for modern networks to
> -                          send a packet.  In most cases if we fail to send
> -                          after the retries we will kill the socket and
> -                          reconnect which may clear the network problem.
> -                       */
> +                       /*
> +                        * If blocking send we try 3 times, since each can block
> +                        * for 5 seconds. For nonblocking  we have to try more
> +                        * but wait increasing amounts of time allowing time for
> +                        * socket to clear.  The overall time we wait in either
> +                        * case to send on the socket is about 15 seconds.
> +                        * Similarly we wait for 15 seconds for a response from
> +                        * the server in SendReceive[2] for the server to send
> +                        * a response back for most types of requests (except
> +                        * SMB Write past end of file which can be slow, and
> +                        * blocking lock operations). NFS waits slightly longer
> +                        * than CIFS, but this can make it take longer for
> +                        * nonresponsive servers to be detected and 15 seconds
> +                        * is more than enough time for modern networks to
> +                        * send a packet.  In most cases if we fail to send
> +                        * after the retries we will kill the socket and
> +                        * reconnect which may clear the network problem.
> +                        */
>                        if ((i >= 14) || (!server->noblocksnd && (i > 2))) {
>                                cERROR(1, "sends on sock %p stuck for 15 seconds",
>                                    ssocket);
> @@ -235,9 +235,8 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
>        else
>                rc = 0;
>
> -       /* Don't want to modify the buffer as a
> -          side effect of this call. */
> -       smb_buffer->smb_buf_length = cpu_to_be32(smb_buf_length);
> +       /* Don't want to modify the buffer as a side effect of this call. */
> +       *buf_len = cpu_to_be32(smb_buf_length);
>
>        return rc;
>  }
> @@ -331,6 +330,33 @@ wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
>        return 0;
>  }
>
> +static int
> +cifs_setup_async_request(struct TCP_Server_Info *server, struct kvec *iov,
> +                        unsigned int nvec, struct mid_q_entry **ret_mid)
> +{
> +       int rc;
> +       struct smb_hdr *hdr = (struct smb_hdr *)iov[0].iov_base;
> +       struct mid_q_entry *mid;
> +
> +       /* enable signing if server requires it */
> +       if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
> +               hdr->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
> +
> +       mid = AllocMidQEntry(hdr, server);
> +       if (mid == NULL)
> +               return -ENOMEM;
> +
> +       /* put it on the pending_mid_q */
> +       spin_lock(&GlobalMid_Lock);
> +       list_add_tail(&mid->qhead, &server->pending_mid_q);
> +       spin_unlock(&GlobalMid_Lock);
> +
> +       rc = cifs_sign_smb2(iov, nvec, server, &mid->sequence_number);
> +       if (rc)
> +               delete_mid(mid);
> +       *ret_mid = mid;
> +       return rc;
> +}
>
>  /*
>  * Send a SMB request and set the callback function in the mid to handle
> @@ -343,34 +369,18 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
>  {
>        int rc;
>        struct mid_q_entry *mid;
> -       struct smb_hdr *hdr = (struct smb_hdr *)iov[0].iov_base;
>
>        rc = wait_for_free_request(server, optype);
>        if (rc)
>                return rc;
>
> -       /* enable signing if server requires it */
> -       if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
> -               hdr->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
> -
>        mutex_lock(&server->srv_mutex);
> -       mid = AllocMidQEntry(hdr, server);
> -       if (mid == NULL) {
> +       rc = cifs_setup_async_request(server, iov, nvec, &mid);
> +       if (rc) {
>                mutex_unlock(&server->srv_mutex);
>                add_credits(server, 1, optype);
>                wake_up(&server->request_q);
> -               return -ENOMEM;
> -       }
> -
> -       /* put it on the pending_mid_q */
> -       spin_lock(&GlobalMid_Lock);
> -       list_add_tail(&mid->qhead, &server->pending_mid_q);
> -       spin_unlock(&GlobalMid_Lock);
> -
> -       rc = cifs_sign_smb2(iov, nvec, server, &mid->sequence_number);
> -       if (rc) {
> -               mutex_unlock(&server->srv_mutex);
> -               goto out_err;
> +               return rc;
>        }
>
>        mid->receive = receive;
> @@ -406,14 +416,14 @@ out_err:
>  */
>  int
>  SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
> -               struct smb_hdr *in_buf, int flags)
> +                char *in_buf, int flags)
>  {
>        int rc;
>        struct kvec iov[1];
>        int resp_buf_type;
>
> -       iov[0].iov_base = (char *)in_buf;
> -       iov[0].iov_len = be32_to_cpu(in_buf->smb_buf_length) + 4;
> +       iov[0].iov_base = in_buf;
> +       iov[0].iov_len = get_rfc1002_length(in_buf) + 4;
>        flags |= CIFS_NO_RESP;
>        rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags);
>        cFYI(DBG2, "SendRcvNoRsp flags %d rc %d", flags, rc);
> @@ -496,7 +506,7 @@ int
>  cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
>                   bool log_error)
>  {
> -       unsigned int len = be32_to_cpu(mid->resp_buf->smb_buf_length) + 4;
> +       unsigned int len = get_rfc1002_length(mid->resp_buf) + 4;
>
>        dump_smb(mid->resp_buf, min_t(u32, 92, len));
>
> @@ -516,6 +526,24 @@ cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
>        return map_smb_to_linux_error(mid->resp_buf, log_error);
>  }
>
> +static int
> +cifs_setup_request(struct cifs_ses *ses, struct kvec *iov,
> +                  unsigned int nvec, struct mid_q_entry **ret_mid)
> +{
> +       int rc;
> +       struct smb_hdr *hdr = (struct smb_hdr *)iov[0].iov_base;
> +       struct mid_q_entry *mid;
> +
> +       rc = allocate_mid(ses, hdr, &mid);
> +       if (rc)
> +               return rc;
> +       rc = cifs_sign_smb2(iov, nvec, ses->server, &mid->sequence_number);
> +       if (rc)
> +               delete_mid(mid);
> +       *ret_mid = mid;
> +       return rc;
> +}
> +
>  int
>  SendReceive2(const unsigned int xid, struct cifs_ses *ses,
>             struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
> @@ -525,7 +553,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
>        int long_op;
>        int optype;
>        struct mid_q_entry *midQ;
> -       struct smb_hdr *in_buf = iov[0].iov_base;
> +       char *buf = iov[0].iov_base;
>
>        long_op = flags & CIFS_TIMEOUT_MASK;
>        optype = flags & CIFS_REQ_MASK;
> @@ -533,47 +561,45 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
>        *pRespBufType = CIFS_NO_BUFFER;  /* no response buf yet */
>
>        if ((ses == NULL) || (ses->server == NULL)) {
> -               cifs_small_buf_release(in_buf);
> +               cifs_small_buf_release(buf);
>                cERROR(1, "Null session");
>                return -EIO;
>        }
>
>        if (ses->server->tcpStatus == CifsExiting) {
> -               cifs_small_buf_release(in_buf);
> +               cifs_small_buf_release(buf);
>                return -ENOENT;
>        }
>
> -       /* Ensure that we do not send more than 50 overlapping requests
> -          to the same server. We may make this configurable later or
> -          use ses->maxReq */
> +       /*
> +        * Ensure that we do not send more than 50 overlapping requests
> +        * to the same server. We may make this configurable later or
> +        * use ses->maxReq.
> +        */
>
>        rc = wait_for_free_request(ses->server, optype);
>        if (rc) {
> -               cifs_small_buf_release(in_buf);
> +               cifs_small_buf_release(buf);
>                return rc;
>        }
>
> -       /* make sure that we sign in the same order that we send on this socket
> -          and avoid races inside tcp sendmsg code that could cause corruption
> -          of smb data */
> +       /*
> +        * Make sure that we sign in the same order that we send on this socket
> +        * and avoid races inside tcp sendmsg code that could cause corruption
> +        * of smb data.
> +        */
>
>        mutex_lock(&ses->server->srv_mutex);
>
> -       rc = allocate_mid(ses, in_buf, &midQ);
> +       rc = cifs_setup_request(ses, iov, n_vec, &midQ);
>        if (rc) {
>                mutex_unlock(&ses->server->srv_mutex);
> -               cifs_small_buf_release(in_buf);
> +               cifs_small_buf_release(buf);
>                /* Update # of requests on wire to server */
>                add_credits(ses->server, 1, optype);
>                wake_up(&ses->server->request_q);
>                return rc;
>        }
> -       rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
> -       if (rc) {
> -               mutex_unlock(&ses->server->srv_mutex);
> -               cifs_small_buf_release(in_buf);
> -               goto out;
> -       }
>
>        midQ->midState = MID_REQUEST_SUBMITTED;
>        cifs_in_send_inc(ses->server);
> @@ -584,23 +610,23 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
>        mutex_unlock(&ses->server->srv_mutex);
>
>        if (rc < 0) {
> -               cifs_small_buf_release(in_buf);
> +               cifs_small_buf_release(buf);
>                goto out;
>        }
>
>        if (long_op == CIFS_ASYNC_OP) {
> -               cifs_small_buf_release(in_buf);
> +               cifs_small_buf_release(buf);
>                goto out;
>        }
>
>        rc = wait_for_response(ses->server, midQ);
>        if (rc != 0) {
> -               send_nt_cancel(ses->server, in_buf, midQ);
> +               send_nt_cancel(ses->server, (struct smb_hdr *)buf, midQ);
>                spin_lock(&GlobalMid_Lock);
>                if (midQ->midState == MID_REQUEST_SUBMITTED) {
>                        midQ->callback = DeleteMidQEntry;
>                        spin_unlock(&GlobalMid_Lock);
> -                       cifs_small_buf_release(in_buf);
> +                       cifs_small_buf_release(buf);
>                        add_credits(ses->server, 1, optype);
>                        wake_up(&ses->server->request_q);
>                        return rc;
> @@ -608,7 +634,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
>                spin_unlock(&GlobalMid_Lock);
>        }
>
> -       cifs_small_buf_release(in_buf);
> +       cifs_small_buf_release(buf);
>
>        rc = cifs_sync_mid_result(midQ, ses->server);
>        if (rc != 0) {
> @@ -623,8 +649,9 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
>                goto out;
>        }
>
> -       iov[0].iov_base = (char *)midQ->resp_buf;
> -       iov[0].iov_len = be32_to_cpu(midQ->resp_buf->smb_buf_length) + 4;
> +       buf = (char *)midQ->resp_buf;
> +       iov[0].iov_base = buf;
> +       iov[0].iov_len = get_rfc1002_length(buf) + 4;
>        if (midQ->largeBuf)
>                *pRespBufType = CIFS_LARGE_BUFFER;
>        else
> --
> 1.7.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html



-- 
Thanks,

Steve

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 01/11] CIFS: Simplify inFlight logic
       [not found]         ` <CAH2r5msNLEF9qVvKsTVTUnPyUjk+7iYVJTxZgd_uuXLAE0iyRg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2012-02-28  9:38           ` Pavel Shilovsky
       [not found]             ` <CAKywueQNFbwDqwr7adWsUZmaYX28tz3kYnL1=4itBHAFV1aeaA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  2012-03-03  9:33           ` Pavel Shilovsky
  1 sibling, 1 reply; 51+ messages in thread
From: Pavel Shilovsky @ 2012-02-28  9:38 UTC (permalink / raw)
  To: Steve French, Jeff Layton; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

2012/2/28 Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>:
> I got a chance to look through this patch set in more detail on the way
> to the SMB2.2 test event.  I liked many of the patches, but this one
> seems to complicate, rather than simplify by adding a spinlock
> to what used to be an atomic_inc.  There is also a possibility that this
> spinlock will become hot.  I don't mind moving the atomic_inc inside the
> new dec_in_flight macro though to make it easier in the future.
>

The idea was to simplify the usage of inFlight value. Now it is
protected by both spin_lock and atomic mechanism in one case and with
only atomic in another -  I think it's rather complicated. The patch
gets rid of one of the protection mechanism (atomic) and use only
spin_lock - this spin_lock is used further for protecting oplock and
echo specific variables as well.

-- 
Best regards,
Pavel Shilovsky.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 03/11] CIFS: Count blocking lock command
       [not found]         ` <CAH2r5mujUbTEe0xtk_sfM1xokCk7FnX=6JKO539ut88Z+RS7wA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2012-02-28  9:40           ` Pavel Shilovsky
  0 siblings, 0 replies; 51+ messages in thread
From: Pavel Shilovsky @ 2012-02-28  9:40 UTC (permalink / raw)
  To: Steve French; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

2012/2/28 Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>:
> I don't think we can do this for the cifs case - 49 blocking locks and
> we would deadlock our system (a pending write could block forever) -
> for smb2.2 it makes more sense.  I don't think it actually causes a
> problem to exceed 50 blocks locks - but if we want to count blocking
> locks we will have to limit the maximum number of blocking locks to 2
> or 3 less than maxmpx and not allow blocking locks if maxmpx is lower
> than 3.
>

Seems reasonable. We can easy add such a check to now exceed maxmpx - 3 value.

-- 
Best regards,
Pavel Shilovsky.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 01/11] CIFS: Simplify inFlight logic
       [not found]             ` <CAKywueQNFbwDqwr7adWsUZmaYX28tz3kYnL1=4itBHAFV1aeaA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2012-02-28 11:31               ` Jeff Layton
       [not found]                 ` <20120228063120.76265cd9-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
  0 siblings, 1 reply; 51+ messages in thread
From: Jeff Layton @ 2012-02-28 11:31 UTC (permalink / raw)
  To: Pavel Shilovsky, Steve French; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

On Tue, 28 Feb 2012 13:38:46 +0400
Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:

> 2012/2/28 Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>:
> > I got a chance to look through this patch set in more detail on the way
> > to the SMB2.2 test event.  I liked many of the patches, but this one
> > seems to complicate, rather than simplify by adding a spinlock
> > to what used to be an atomic_inc.  There is also a possibility that this
> > spinlock will become hot.  I don't mind moving the atomic_inc inside the
> > new dec_in_flight macro though to make it easier in the future.
> >
> 
> The idea was to simplify the usage of inFlight value. Now it is
> protected by both spin_lock and atomic mechanism in one case and with
> only atomic in another -  I think it's rather complicated. The patch
> gets rid of one of the protection mechanism (atomic) and use only
> spin_lock - this spin_lock is used further for protecting oplock and
> echo specific variables as well.
> 

The problem here is that the locking around this variable is unclear:

If you need a spinlock to access/change it, then why use an atomic? If
an atomic is sufficient then why use the spinlock at all?

I don't much care what scheme you end up using for this, but if you
really need a belt-and-suspenders approach (atomic + spinlock), then
the reasoning for it needs to be clearly documented. We mere mortals
must understand how it's supposed to work so we don't break it later.
-- 
Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 01/11] CIFS: Simplify inFlight logic
       [not found]                 ` <20120228063120.76265cd9-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
@ 2012-02-28 11:39                   ` Pavel Shilovsky
  0 siblings, 0 replies; 51+ messages in thread
From: Pavel Shilovsky @ 2012-02-28 11:39 UTC (permalink / raw)
  To: Jeff Layton; +Cc: Steve French, linux-cifs-u79uwXL29TY76Z2rM5mHXA

2012/2/28 Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>:
> On Tue, 28 Feb 2012 13:38:46 +0400
> Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
>
>> 2012/2/28 Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>:
>> > I got a chance to look through this patch set in more detail on the way
>> > to the SMB2.2 test event.  I liked many of the patches, but this one
>> > seems to complicate, rather than simplify by adding a spinlock
>> > to what used to be an atomic_inc.  There is also a possibility that this
>> > spinlock will become hot.  I don't mind moving the atomic_inc inside the
>> > new dec_in_flight macro though to make it easier in the future.
>> >
>>
>> The idea was to simplify the usage of inFlight value. Now it is
>> protected by both spin_lock and atomic mechanism in one case and with
>> only atomic in another -  I think it's rather complicated. The patch
>> gets rid of one of the protection mechanism (atomic) and use only
>> spin_lock - this spin_lock is used further for protecting oplock and
>> echo specific variables as well.
>>
>
> The problem here is that the locking around this variable is unclear:
>
> If you need a spinlock to access/change it, then why use an atomic? If
> an atomic is sufficient then why use the spinlock at all?
>
> I don't much care what scheme you end up using for this, but if you
> really need a belt-and-suspenders approach (atomic + spinlock), then
> the reasoning for it needs to be clearly documented. We mere mortals
> must understand how it's supposed to work so we don't break it later.

I don't know how the existing approach comes the tree but I guess that
it needs to be atomic to easily decrement and read this variable and
needs to be surrounded by spinlocks in wait_for_free_request to make
sure we are not incrementing the value that is already >=
cifs_max_pending.

The whole scheme is rather complicated of course - so, the goal of
this patch is to make it more understandable and simple (only one
protection mechanism - spin_lock).

-- 
Best regards,
Pavel Shilovsky.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 06/11] CIFS: Respect MaxMpxCount field
       [not found]         ` <CAH2r5mvVToaHozN3=YgCCCWFFnjE9AP5xX_BF2JdxDj_JvKsbQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2012-02-28 16:43           ` Jeff Layton
       [not found]             ` <20120228114341.1629ed85-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
  2012-03-03  8:35           ` Pavel Shilovsky
  1 sibling, 1 reply; 51+ messages in thread
From: Jeff Layton @ 2012-02-28 16:43 UTC (permalink / raw)
  To: Steve French; +Cc: Pavel Shilovsky, linux-cifs-u79uwXL29TY76Z2rM5mHXA

On Mon, 27 Feb 2012 18:01:04 -0600
Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:

> This is going to be more complicated than it seems.
> 
> Apparently (according to Chris), Windows will often allow mapmpx simultaneous
> requests per process for various handle based requests.   In addition according
> to JRA, Samba server does not care if you go beyond maxmpx (and there is
> a big performance advantage of that).   On the other hand - if the server
> sets maxmpx to less than 10, these kind of changes probably make sense
> (those servers are probably broken otherwise), but for normal servers
> this will end up restricting more than windows (for more than than the
> maxmpx per pid).   Generally, for servers like Samba that support
> simultaneous requests reasonably we have to be careful about killing
> performance especially now that with Jeff's async reads and writes
> we will frequently get up to 50 (and should probably make it easier
> to have more than 50 to servers like Samba).
> 
> Quoting JRA and Volker - "You should be able to queue
> thousands of simultaneous requests from one client to Samba"
> (as long as the client doesn't time out.  The server keeps
> responding to the earlier requests, so with our client timeout
> code weshould be fine).
> 

The problem here though is that we have to code for the lowest common
denominator. While many servers handle exceeding the maxmpx gracefully,
a lot don't. The only safe course here is to respect the MaxMpx by
default since we can't reliably predict what the effect will be if we
exceed it.

That said, if you want to add some sort of knob (mount option?) later
that allows the client to override the server-provided maxmpx, then I'd
be ok with that.

-- 
Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 06/11] CIFS: Respect MaxMpxCount field
       [not found]             ` <20120228114341.1629ed85-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
@ 2012-02-28 17:42               ` Steve French
       [not found]                 ` <CAH2r5mvFyw8Cn8nXN9ZBZogBGVr5L5T9aX7Zs8DOiZgDUqGp1Q-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 51+ messages in thread
From: Steve French @ 2012-02-28 17:42 UTC (permalink / raw)
  To: Jeff Layton; +Cc: Pavel Shilovsky, linux-cifs-u79uwXL29TY76Z2rM5mHXA

I think the best way to handle this is to do the special casing
(limiting retries, turning off byte range blocking locks, turning off
oplock) for the servers which do limit maxmpx to small values.   For
maxmpx=50 or higher (or if you wish to narrow this, distinguish
servers like Samba more narrowly by check for the unix extensions that
is fine) which shouldn't be stricter than windows (whose client will
exceed 50 simultaneous requests for various cases Chris described).
There is a significant chance of deadlock if we don't allow writes
through due to counting blocking byte range locks against maxmpx too
strictly.   We do have to fix the case of maxmpx = 1 or 2 (disable
oplock and possibly echo) and enforce maxmpx for those which set it
lower than 50 - but the byte range lock issue has never come up, and
fixing it the way pavel describes would be stricter than windows and
risk deadlock by chewing up slots.

Another issue is that we are significantly underutilizes Samba by
setting maxmpx so low, but if we expect to move to SMB2 soon, it may
not matter.

On Tue, Feb 28, 2012 at 10:43 AM, Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:
> On Mon, 27 Feb 2012 18:01:04 -0600
> Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
>
>> This is going to be more complicated than it seems.
>>
>> Apparently (according to Chris), Windows will often allow mapmpx simultaneous
>> requests per process for various handle based requests.   In addition according
>> to JRA, Samba server does not care if you go beyond maxmpx (and there is
>> a big performance advantage of that).   On the other hand - if the server
>> sets maxmpx to less than 10, these kind of changes probably make sense
>> (those servers are probably broken otherwise), but for normal servers
>> this will end up restricting more than windows (for more than than the
>> maxmpx per pid).   Generally, for servers like Samba that support
>> simultaneous requests reasonably we have to be careful about killing
>> performance especially now that with Jeff's async reads and writes
>> we will frequently get up to 50 (and should probably make it easier
>> to have more than 50 to servers like Samba).
>>
>> Quoting JRA and Volker - "You should be able to queue
>> thousands of simultaneous requests from one client to Samba"
>> (as long as the client doesn't time out.  The server keeps
>> responding to the earlier requests, so with our client timeout
>> code weshould be fine).
>>
>
> The problem here though is that we have to code for the lowest common
> denominator. While many servers handle exceeding the maxmpx gracefully,
> a lot don't. The only safe course here is to respect the MaxMpx by
> default since we can't reliably predict what the effect will be if we
> exceed it.
>
> That said, if you want to add some sort of knob (mount option?) later
> that allows the client to override the server-provided maxmpx, then I'd
> be ok with that.
>
> --
> Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>



-- 
Thanks,

Steve

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 06/11] CIFS: Respect MaxMpxCount field
       [not found]                 ` <CAH2r5mvFyw8Cn8nXN9ZBZogBGVr5L5T9aX7Zs8DOiZgDUqGp1Q-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2012-02-28 19:47                   ` Jeff Layton
       [not found]                     ` <20120228144736.18124fc3-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
  0 siblings, 1 reply; 51+ messages in thread
From: Jeff Layton @ 2012-02-28 19:47 UTC (permalink / raw)
  To: Steve French; +Cc: Pavel Shilovsky, linux-cifs-u79uwXL29TY76Z2rM5mHXA

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On Tue, 28 Feb 2012 11:42:49 -0600
Steve French <smfrench@gmail.com> wrote:

> I think the best way to handle this is to do the special casing
> (limiting retries, turning off byte range blocking locks, turning off
> oplock) for the servers which do limit maxmpx to small values.   For
> maxmpx=50 or higher (or if you wish to narrow this, distinguish
> servers like Samba more narrowly by check for the unix extensions that
> is fine) which shouldn't be stricter than windows (whose client will
> exceed 50 simultaneous requests for various cases Chris described).
> There is a significant chance of deadlock if we don't allow writes
> through due to counting blocking byte range locks against maxmpx too
> strictly.   We do have to fix the case of maxmpx = 1 or 2 (disable
> oplock and possibly echo) and enforce maxmpx for those which set it
> lower than 50 - but the byte range lock issue has never come up, and
> fixing it the way pavel describes would be stricter than windows and
> risk deadlock by chewing up slots.
> 
> Another issue is that we are significantly underutilizes Samba by
> setting maxmpx so low, but if we expect to move to SMB2 soon, it may
> not matter.
> 

I'm having a hard time understanding what you're proposing above. It
sounds like you're saying that when the server sends maxmpx >= 50 that
you think we should effectively treat that as unlimited?

Can you lay out the "rules" (and the exceptions thereof) that you're
proposing here?

- -- 
Jeff Layton <jlayton@samba.org>
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.18 (GNU/Linux)

iQIcBAEBAgAGBQJPTS9YAAoJEAAOaEEZVoIVduYQANVGfFMVX0Z2TKKcPXN5NsUX
aGssTTToK2JK6kSbKFmSxQHCmD4nSPHc3W5qpsk4VQ0F5KC6tuNMowcWHJaZ/f2f
Qo2TiH7jgRneWOv2y7dxZ66Gs+1mPPIVREhHq0EJzVH/WPcUq+VRkwl3O8k+WQOh
QVZYoj5Aap/sKzwjdX5LcS4jUEuqXVZG/np216grKr1zKpgo4fAXk22sFrpivKyP
XUyyP6SU5EAg2EbA7lbEGGmmfQz7HRiWZ+Vnwd9gdbA1up6vtaSF4ms5aiE6y+XN
c+kaGvgP6EWnNblavEEOJd9+dksHQ5fXRo6t3rGvFmdkAGZlk6kCse6N6zaKnpCi
XEeoIhq/FDAlUNmU7/B4IoXkHqrf7LgXQvycuP3iUFK5N61FfO+NQvtOuHhhbhH8
c4JoiVheQKJh3DJww6DkrLmmjKhwf1byrsYLyCs0Xm/YyK//tlKeN3zF0hS3j8f8
f17P1QyeE1E+FWd+QEThTKuR5vMNcCA4yBFctC7gidi98vPY2L6+xNTqUWZkUTdr
pBSiKahXms8oNyvf1ijqoy99wRLIOL0fXLUIBF/NXDw0Gy4YmJvR5PKewoXQYu+R
JEITC1MPiizA7YKgx37OmkERGpVl97r9QS2FvpSUhBfsgoXOKWR4cs+7KPGZQBBF
Ao/y7L/DAVGFoYbMuTZF
=jJfp
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 06/11] CIFS: Respect MaxMpxCount field
       [not found]                     ` <20120228144736.18124fc3-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
@ 2012-02-28 20:03                       ` Steve French
       [not found]                         ` <CAH2r5mvJE+ACNVuv+HEQMuwvaMTzfOb7Msk4U1ZVnZ046AEi1Q-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 51+ messages in thread
From: Steve French @ 2012-02-28 20:03 UTC (permalink / raw)
  To: Jeff Layton; +Cc: Pavel Shilovsky, linux-cifs-u79uwXL29TY76Z2rM5mHXA

Attempt to summarize after discussions with jra and Chris:

- don't make default case to Samba worse performance than it already is
- don't "fix" by adding restrictions on echo retries and blocking
locks when it is not broken (windows allows these, and counts blocking
locks against the pid not against the session).   For servers which
allow few mpx, perhaps those for 10 or fewer - if you think they are
buggy, I don't mind treating echo and blocking locks differently than
we do now - but echo and blocking locks don't need to be restricted
the way Pavel suggested to windows and samba and any normal server
(and there is some risk in restricting them that way).   We could
probably limit the number of blocking locks (out of resource error,
returning ENOLOCK) when there are 50 (e.g.) on a process (or 10 if the
server supports maxmpx of 10, and zero if maxmpx is less than 3 or
less than 10).
- for other smb requests (the ones we enforce today) enforce the limit
the server returns (rather than 50 always)

On Tue, Feb 28, 2012 at 1:47 PM, Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> On Tue, 28 Feb 2012 11:42:49 -0600
> Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
>
>> I think the best way to handle this is to do the special casing
>> (limiting retries, turning off byte range blocking locks, turning off
>> oplock) for the servers which do limit maxmpx to small values.   For
>> maxmpx=50 or higher (or if you wish to narrow this, distinguish
>> servers like Samba more narrowly by check for the unix extensions that
>> is fine) which shouldn't be stricter than windows (whose client will
>> exceed 50 simultaneous requests for various cases Chris described).
>> There is a significant chance of deadlock if we don't allow writes
>> through due to counting blocking byte range locks against maxmpx too
>> strictly.   We do have to fix the case of maxmpx = 1 or 2 (disable
>> oplock and possibly echo) and enforce maxmpx for those which set it
>> lower than 50 - but the byte range lock issue has never come up, and
>> fixing it the way pavel describes would be stricter than windows and
>> risk deadlock by chewing up slots.
>>
>> Another issue is that we are significantly underutilizes Samba by
>> setting maxmpx so low, but if we expect to move to SMB2 soon, it may
>> not matter.
>>
>
> I'm having a hard time understanding what you're proposing above. It
> sounds like you're saying that when the server sends maxmpx >= 50 that
> you think we should effectively treat that as unlimited?
>
> Can you lay out the "rules" (and the exceptions thereof) that you're
> proposing here?
>
> - --
> Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
> -----BEGIN PGP SIGNATURE-----
> Version: GnuPG v2.0.18 (GNU/Linux)
>
> iQIcBAEBAgAGBQJPTS9YAAoJEAAOaEEZVoIVduYQANVGfFMVX0Z2TKKcPXN5NsUX
> aGssTTToK2JK6kSbKFmSxQHCmD4nSPHc3W5qpsk4VQ0F5KC6tuNMowcWHJaZ/f2f
> Qo2TiH7jgRneWOv2y7dxZ66Gs+1mPPIVREhHq0EJzVH/WPcUq+VRkwl3O8k+WQOh
> QVZYoj5Aap/sKzwjdX5LcS4jUEuqXVZG/np216grKr1zKpgo4fAXk22sFrpivKyP
> XUyyP6SU5EAg2EbA7lbEGGmmfQz7HRiWZ+Vnwd9gdbA1up6vtaSF4ms5aiE6y+XN
> c+kaGvgP6EWnNblavEEOJd9+dksHQ5fXRo6t3rGvFmdkAGZlk6kCse6N6zaKnpCi
> XEeoIhq/FDAlUNmU7/B4IoXkHqrf7LgXQvycuP3iUFK5N61FfO+NQvtOuHhhbhH8
> c4JoiVheQKJh3DJww6DkrLmmjKhwf1byrsYLyCs0Xm/YyK//tlKeN3zF0hS3j8f8
> f17P1QyeE1E+FWd+QEThTKuR5vMNcCA4yBFctC7gidi98vPY2L6+xNTqUWZkUTdr
> pBSiKahXms8oNyvf1ijqoy99wRLIOL0fXLUIBF/NXDw0Gy4YmJvR5PKewoXQYu+R
> JEITC1MPiizA7YKgx37OmkERGpVl97r9QS2FvpSUhBfsgoXOKWR4cs+7KPGZQBBF
> Ao/y7L/DAVGFoYbMuTZF
> =jJfp
> -----END PGP SIGNATURE-----



-- 
Thanks,

Steve

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 06/11] CIFS: Respect MaxMpxCount field
       [not found]                         ` <CAH2r5mvJE+ACNVuv+HEQMuwvaMTzfOb7Msk4U1ZVnZ046AEi1Q-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2012-02-28 20:53                           ` Pavel Shilovsky
       [not found]                             ` <CAKywueSxe_wZwudx3UK14C94o53zjghsTJJSah=CQSqy0uhZRQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 51+ messages in thread
From: Pavel Shilovsky @ 2012-02-28 20:53 UTC (permalink / raw)
  To: Steve French; +Cc: Jeff Layton, linux-cifs-u79uwXL29TY76Z2rM5mHXA

2012/2/29 Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>:
> Attempt to summarize after discussions with jra and Chris:
>
> - don't make default case to Samba worse performance than it already is
> - don't "fix" by adding restrictions on echo retries and blocking
> locks when it is not broken (windows allows these, and counts blocking
> locks against the pid not against the session).   For servers which
> allow few mpx, perhaps those for 10 or fewer - if you think they are
> buggy, I don't mind treating echo and blocking locks differently than
> we do now - but echo and blocking locks don't need to be restricted
> the way Pavel suggested to windows and samba and any normal server
> (and there is some risk in restricting them that way).   We could
> probably limit the number of blocking locks (out of resource error,
> returning ENOLOCK) when there are 50 (e.g.) on a process (or 10 if the
> server supports maxmpx of 10, and zero if maxmpx is less than 3 or
> less than 10).
> - for other smb requests (the ones we enforce today) enforce the limit
> the server returns (rather than 50 always)
>

But for SMB2 we need to count both echos and blocking locks. It even
more compicated because the number of credits is dynamic: we need to
increment/decrement the maximum number of parallel blocking locks to
make sure we don't exceed available credits.

-- 
Best regards,
Pavel Shilovsky.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 06/11] CIFS: Respect MaxMpxCount field
       [not found]                             ` <CAKywueSxe_wZwudx3UK14C94o53zjghsTJJSah=CQSqy0uhZRQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2012-02-28 21:18                               ` Steve French
       [not found]                                 ` <CAH2r5mvFiwpVwcBgfuXvEGC1_8snLMAsp4fRVEDMqTWXDJdu9w-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 51+ messages in thread
From: Steve French @ 2012-02-28 21:18 UTC (permalink / raw)
  To: Pavel Shilovsky; +Cc: Jeff Layton, linux-cifs-u79uwXL29TY76Z2rM5mHXA

On Tue, Feb 28, 2012 at 2:53 PM, Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> 2012/2/29 Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>:
>> Attempt to summarize after discussions with jra and Chris:
>>
>> - don't make default case to Samba worse performance than it already is
>> - don't "fix" by adding restrictions on echo retries and blocking
>> locks when it is not broken (windows allows these, and counts blocking
>> locks against the pid not against the session).   For servers which
>> allow few mpx, perhaps those for 10 or fewer - if you think they are
>> buggy, I don't mind treating echo and blocking locks differently than
>> we do now - but echo and blocking locks don't need to be restricted
>> the way Pavel suggested to windows and samba and any normal server
>> (and there is some risk in restricting them that way).   We could
>> probably limit the number of blocking locks (out of resource error,
>> returning ENOLOCK) when there are 50 (e.g.) on a process (or 10 if the
>> server supports maxmpx of 10, and zero if maxmpx is less than 3 or
>> less than 10).
>> - for other smb requests (the ones we enforce today) enforce the limit
>> the server returns (rather than 50 always)
>>
>
> But for SMB2 we need to count both echos and blocking locks. It even
> more compicated because the number of credits is dynamic: we need to
> increment/decrement the maximum number of parallel blocking locks to
> make sure we don't exceed available credits.

Yes - for smb2 the number of available requests (credits) can change
on ANY smb2 response.  It is not related to how cifs requests are
processed.

Also note that for cifs for Windows, apparently the smb echo is
handled at a lower level (before checking mpx) - (and also Samba
server does not enforce either).

-- 
Thanks,

Steve

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 06/11] CIFS: Respect MaxMpxCount field
       [not found]                                 ` <CAH2r5mvFiwpVwcBgfuXvEGC1_8snLMAsp4fRVEDMqTWXDJdu9w-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2012-03-01 18:37                                   ` Jeff Layton
       [not found]                                     ` <20120301133747.5fc891b5-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
  0 siblings, 1 reply; 51+ messages in thread
From: Jeff Layton @ 2012-03-01 18:37 UTC (permalink / raw)
  To: Steve French
  Cc: Pavel Shilovsky, linux-cifs-u79uwXL29TY76Z2rM5mHXA,
	jra-eUNUBHrolfbYtjvyW6yDsg, crh-eUNUBHrolfbYtjvyW6yDsg

On Tue, 28 Feb 2012 15:18:02 -0600
Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:

> On Tue, Feb 28, 2012 at 2:53 PM, Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> > 2012/2/29 Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>:
> >> Attempt to summarize after discussions with jra and Chris:
> >>
> >> - don't make default case to Samba worse performance than it already is
> >> - don't "fix" by adding restrictions on echo retries and blocking
> >> locks when it is not broken (windows allows these, and counts blocking
> >> locks against the pid not against the session).   For servers which
> >> allow few mpx, perhaps those for 10 or fewer - if you think they are
> >> buggy, I don't mind treating echo and blocking locks differently than
> >> we do now - but echo and blocking locks don't need to be restricted
> >> the way Pavel suggested to windows and samba and any normal server
> >> (and there is some risk in restricting them that way).   We could
> >> probably limit the number of blocking locks (out of resource error,
> >> returning ENOLOCK) when there are 50 (e.g.) on a process (or 10 if the
> >> server supports maxmpx of 10, and zero if maxmpx is less than 3 or
> >> less than 10).
> >> - for other smb requests (the ones we enforce today) enforce the limit
> >> the server returns (rather than 50 always)
> >>
> >
> > But for SMB2 we need to count both echos and blocking locks. It even
> > more compicated because the number of credits is dynamic: we need to
> > increment/decrement the maximum number of parallel blocking locks to
> > make sure we don't exceed available credits.
> 
> Yes - for smb2 the number of available requests (credits) can change
> on ANY smb2 response.  It is not related to how cifs requests are
> processed.
> 
> Also note that for cifs for Windows, apparently the smb echo is
> handled at a lower level (before checking mpx) - (and also Samba
> server does not enforce either).
> 

(cc'ing Chris and Jeremy to make sure I understand)

The description above is a good start but doesn't quite outline the
clear concise "rules" for this that I was looking for.

So if I understand what Steve wrote above, he's basically saying that
we should enforce the maxmpx for everything but blocking locks and
echoes? Is that correct? If so then I think that's wrong and won't fix
any of the problems that people have reported with the existing code.

It's all well and good that *some* servers allow you to exceed the
maxmpx in *some* cases, but we can't code to that assumption. We know
well that many servers do not handle exceeding the maxmpx gracefully at
all. As always we have to code to the lowest common denominator by
default, and then optionally allow people to exceed that if they choose
to do so.

I think this is a case where we need a good description in a human
language (preferably english) of how this should work (aka a
specification), and then write code to match that description (aka code
to the spec).

Anything else is going to send us down the rabbit hole where we are
today with cifs.ko -- a bunch of ad-hoc, broken code that no one really
understands.

While we may not like it, a hard cap on the number of outstanding
requests is required by the protocol docs that Chris helped write.

Allow me to quote from MS-CIFS:

MaxMpxCount (2 bytes): The maximum number of outstanding SMB operations
that the server supports. This value includes existing OpLocks, the
NT_TRANSACT_NOTIFY_CHANGE subcommand, and any other commands that are
pending on the server.

There's nothing in there that says anything about certain commands
being excepted from that value.
-- 
Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 06/11] CIFS: Respect MaxMpxCount field
       [not found]                                     ` <20120301133747.5fc891b5-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
@ 2012-03-01 18:48                                       ` Jeremy Allison
  2012-03-01 19:12                                         ` Jeff Layton
  2012-03-01 19:18                                         ` Christopher R. Hertel
  0 siblings, 2 replies; 51+ messages in thread
From: Jeremy Allison @ 2012-03-01 18:48 UTC (permalink / raw)
  To: Jeff Layton
  Cc: Steve French, Pavel Shilovsky, linux-cifs-u79uwXL29TY76Z2rM5mHXA,
	jra-eUNUBHrolfbYtjvyW6yDsg, crh-eUNUBHrolfbYtjvyW6yDsg

On Thu, Mar 01, 2012 at 01:37:47PM -0500, Jeff Layton wrote:
> 
> (cc'ing Chris and Jeremy to make sure I understand)
> 
> The description above is a good start but doesn't quite outline the
> clear concise "rules" for this that I was looking for.
> 
> So if I understand what Steve wrote above, he's basically saying that
> we should enforce the maxmpx for everything but blocking locks and
> echoes? Is that correct? If so then I think that's wrong and won't fix
> any of the problems that people have reported with the existing code.
> 
> It's all well and good that *some* servers allow you to exceed the
> maxmpx in *some* cases, but we can't code to that assumption. We know
> well that many servers do not handle exceeding the maxmpx gracefully at
> all. As always we have to code to the lowest common denominator by
> default, and then optionally allow people to exceed that if they choose
> to do so.
> 
> I think this is a case where we need a good description in a human
> language (preferably english) of how this should work (aka a
> specification), and then write code to match that description (aka code
> to the spec).
> 
> Anything else is going to send us down the rabbit hole where we are
> today with cifs.ko -- a bunch of ad-hoc, broken code that no one really
> understands.
> 
> While we may not like it, a hard cap on the number of outstanding
> requests is required by the protocol docs that Chris helped write.
> 
> Allow me to quote from MS-CIFS:
> 
> MaxMpxCount (2 bytes): The maximum number of outstanding SMB operations
> that the server supports. This value includes existing OpLocks, the
> NT_TRANSACT_NOTIFY_CHANGE subcommand, and any other commands that are
> pending on the server.
> 
> There's nothing in there that says anything about certain commands
> being excepted from that value.

The only way to know this for sure is to put in a request
to Microsoft doc-help to ask if SMBecho and blocking SMB
locks are exempted from the maxmpx count.

Jeremy.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 06/11] CIFS: Respect MaxMpxCount field
  2012-03-01 18:48                                       ` Jeremy Allison
@ 2012-03-01 19:12                                         ` Jeff Layton
  2012-03-01 19:18                                         ` Christopher R. Hertel
  1 sibling, 0 replies; 51+ messages in thread
From: Jeff Layton @ 2012-03-01 19:12 UTC (permalink / raw)
  To: Jeremy Allison
  Cc: Steve French, Pavel Shilovsky, linux-cifs-u79uwXL29TY76Z2rM5mHXA,
	crh-eUNUBHrolfbYtjvyW6yDsg

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On Thu, 1 Mar 2012 10:48:23 -0800
Jeremy Allison <jra@samba.org> wrote:

> On Thu, Mar 01, 2012 at 01:37:47PM -0500, Jeff Layton wrote:
> > 
> > (cc'ing Chris and Jeremy to make sure I understand)
> > 
> > The description above is a good start but doesn't quite outline the
> > clear concise "rules" for this that I was looking for.
> > 
> > So if I understand what Steve wrote above, he's basically saying that
> > we should enforce the maxmpx for everything but blocking locks and
> > echoes? Is that correct? If so then I think that's wrong and won't fix
> > any of the problems that people have reported with the existing code.
> > 
> > It's all well and good that *some* servers allow you to exceed the
> > maxmpx in *some* cases, but we can't code to that assumption. We know
> > well that many servers do not handle exceeding the maxmpx gracefully at
> > all. As always we have to code to the lowest common denominator by
> > default, and then optionally allow people to exceed that if they choose
> > to do so.
> > 
> > I think this is a case where we need a good description in a human
> > language (preferably english) of how this should work (aka a
> > specification), and then write code to match that description (aka code
> > to the spec).
> > 
> > Anything else is going to send us down the rabbit hole where we are
> > today with cifs.ko -- a bunch of ad-hoc, broken code that no one really
> > understands.
> > 
> > While we may not like it, a hard cap on the number of outstanding
> > requests is required by the protocol docs that Chris helped write.
> > 
> > Allow me to quote from MS-CIFS:
> > 
> > MaxMpxCount (2 bytes): The maximum number of outstanding SMB operations
> > that the server supports. This value includes existing OpLocks, the
> > NT_TRANSACT_NOTIFY_CHANGE subcommand, and any other commands that are
> > pending on the server.
> > 
> > There's nothing in there that says anything about certain commands
> > being excepted from that value.
> 
> The only way to know this for sure is to put in a request
> to Microsoft doc-help to ask if SMBecho and blocking SMB
> locks are exempted from the maxmpx count.
> 

That will probably tell us what Windows does, but the problems are not
necessarily with Windows servers. There are a lot of crappy CIFS
servers in the field and Microsoft can't tell us how they behave in
this regard.

Still, it won't hurt to ask, so I'll do so...I just don't think their
answer will have much bearing on what we'll eventually have to
implement.


- -- 
Jeff Layton <jlayton@samba.org>
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.18 (GNU/Linux)

iQIcBAEBAgAGBQJPT8owAAoJEAAOaEEZVoIVkVAQAK7Z9a+krmXnUQmbfjYr+jEd
bvpXp2FWpiJxzhnv4EQPoMHlWUjYc2mCLeOvo/42pcYzDzx0Gko4F9hfJJTB7Rj6
RqueGzJpvjpuw+HNo3t0YUXU+/OU2E+OBCEnuQ5a7K2sJGI4BUmXLfXKeCaWL8Bz
5H/CdbUkzFM6TH9QTe7vbwkHRgTBqMPd7Ugy1crWWO0thJpkRF9MkJCCdaXIxkgP
LiN10E5D5wkfTdb0SWAhYvc8FvEkS8wKEQcM+BN45PqaWiW2gMZpS4cgQdcWzH1I
Dlz2zJlMZlV5f71DQVHCDvlY44TfN/LjlnA1+wW6h/QhJomJQhZKzTk2aqThiF4h
iNCOPvlDuBab0ZAynGj7VA4KZ0DNY/CVrqH20OHW9ROkLCjcqCHgvx5eEGXPkWcm
HhY88eWpmrj7nxZ+zqipKwlJas8Zu7NYixGWEPQ3j+dxebhxLKfqBDQBgpXpoZFH
WhEp5L33RF4NUkKy0ToihXjxp8HLEFhfOAgTzbKJS4GtPDfyckXqw3yL967gZEV3
LJEBjI5+kjUOEIHt+/uhSQDVM/uT+sFMQpBbtGguK0k4WIIbFgT3cvG/SnCUIdXB
O9jEZTZ7DtZY6rG35Kq05usclWFz9Fi2u/FVTqZxJcM8ufuY5c5vApL9SPgzN7zr
qGPm7BM6MP2x+kVL3fHs
=clwm
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 06/11] CIFS: Respect MaxMpxCount field
  2012-03-01 18:48                                       ` Jeremy Allison
  2012-03-01 19:12                                         ` Jeff Layton
@ 2012-03-01 19:18                                         ` Christopher R. Hertel
       [not found]                                           ` <4F4FCB69.6060705-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
  1 sibling, 1 reply; 51+ messages in thread
From: Christopher R. Hertel @ 2012-03-01 19:18 UTC (permalink / raw)
  To: Jeremy Allison
  Cc: Jeff Layton, Steve French, Pavel Shilovsky,
	linux-cifs-u79uwXL29TY76Z2rM5mHXA

On 03/01/2012 10:48 AM, Jeremy Allison wrote:
> On Thu, Mar 01, 2012 at 01:37:47PM -0500, Jeff Layton wrote:
>>
>> (cc'ing Chris and Jeremy to make sure I understand)
>>
>> The description above is a good start but doesn't quite outline the
>> clear concise "rules" for this that I was looking for.
>>
>> So if I understand what Steve wrote above, he's basically saying that
>> we should enforce the maxmpx for everything but blocking locks and
>> echoes? Is that correct? If so then I think that's wrong and won't fix
>> any of the problems that people have reported with the existing code.
>>
>> It's all well and good that *some* servers allow you to exceed the
>> maxmpx in *some* cases, but we can't code to that assumption. We know
>> well that many servers do not handle exceeding the maxmpx gracefully at
>> all. As always we have to code to the lowest common denominator by
>> default, and then optionally allow people to exceed that if they choose
>> to do so.
>>
>> I think this is a case where we need a good description in a human
>> language (preferably english) of how this should work (aka a
>> specification), and then write code to match that description (aka code
>> to the spec).
>>
>> Anything else is going to send us down the rabbit hole where we are
>> today with cifs.ko -- a bunch of ad-hoc, broken code that no one really
>> understands.
>>
>> While we may not like it, a hard cap on the number of outstanding
>> requests is required by the protocol docs that Chris helped write.
>>
>> Allow me to quote from MS-CIFS:
>>
>> MaxMpxCount (2 bytes): The maximum number of outstanding SMB operations
>> that the server supports. This value includes existing OpLocks, the
>> NT_TRANSACT_NOTIFY_CHANGE subcommand, and any other commands that are
>> pending on the server.
>>
>> There's nothing in there that says anything about certain commands
>> being excepted from that value.
>
> The only way to know this for sure is to put in a request
> to Microsoft doc-help to ask if SMBecho and blocking SMB
> locks are exempted from the maxmpx count.

I recall, from the code, that the SMBecho is handled "out of band".  I can't 
speak to the blocking locks.

Internally, the system keeps a per-connection table keyed on [PID,MID].  The 
MaxMpxCount indicates the fixed size of this table.  Outstanding commands, 
including things like ChangeNotify and OpLocks (which are handled as if they 
were incomplete commands, pending on the server) are kept in this table.

The doc talks about needing to disable OpLocks if the MaxMpxCount is less 
than 2.  That's because clients can break their own OpLocks.  If a client 
has an OpLock on a file, and then opens the file again (the same or 
different process...it doesn't matter) there won't be enough slots in the 
[PID,MID] table to allow the open to occur.  The client's second Open 
request will not be able to be queued (it becomes a pending command since it 
cannot be answered until the OpLock break either times out or completes) 
because the pending command table is full.

Okay, so...  The question is this:  When are commands added to the server's 
pending queue (the table indexed on [PID,MID].

The answer is scattered across section 3 of the [MS-CIFS] doc.  If the 
command needs to be added to the pending queue, it'll say so in the doc.  It 
should all be under section 3.3.5.

Look for information about the PendingRequestTable, starting at section 
3.3.5.2.1.

Chris -)-----

--
"Implementing CIFS - the Common Internet FileSystem" ISBN: 013047116X
Samba Team -- http://www.samba.org/     -)-----   Christopher R. Hertel
jCIFS Team -- http://jcifs.samba.org/   -)-----   ubiqx development, uninq.
ubiqx Team -- http://www.ubiqx.org/     -)-----   crh-jFlgvBokg3lg9hUCZPvPmw@public.gmane.org
OnLineBook -- http://ubiqx.org/cifs/    -)-----   crh-zuGDro9SezXYtjvyW6yDsg@public.gmane.org

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 06/11] CIFS: Respect MaxMpxCount field
       [not found]                                           ` <4F4FCB69.6060705-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
@ 2012-03-02 15:45                                             ` Jeff Layton
  0 siblings, 0 replies; 51+ messages in thread
From: Jeff Layton @ 2012-03-02 15:45 UTC (permalink / raw)
  To: Christopher R. Hertel
  Cc: Jeremy Allison, Steve French, Pavel Shilovsky,
	linux-cifs-u79uwXL29TY76Z2rM5mHXA

On Thu, 01 Mar 2012 11:18:01 -0800
"Christopher R. Hertel" <crh-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:

> On 03/01/2012 10:48 AM, Jeremy Allison wrote:
> > On Thu, Mar 01, 2012 at 01:37:47PM -0500, Jeff Layton wrote:
> >>
> >> (cc'ing Chris and Jeremy to make sure I understand)
> >>
> >> The description above is a good start but doesn't quite outline the
> >> clear concise "rules" for this that I was looking for.
> >>
> >> So if I understand what Steve wrote above, he's basically saying that
> >> we should enforce the maxmpx for everything but blocking locks and
> >> echoes? Is that correct? If so then I think that's wrong and won't fix
> >> any of the problems that people have reported with the existing code.
> >>
> >> It's all well and good that *some* servers allow you to exceed the
> >> maxmpx in *some* cases, but we can't code to that assumption. We know
> >> well that many servers do not handle exceeding the maxmpx gracefully at
> >> all. As always we have to code to the lowest common denominator by
> >> default, and then optionally allow people to exceed that if they choose
> >> to do so.
> >>
> >> I think this is a case where we need a good description in a human
> >> language (preferably english) of how this should work (aka a
> >> specification), and then write code to match that description (aka code
> >> to the spec).
> >>
> >> Anything else is going to send us down the rabbit hole where we are
> >> today with cifs.ko -- a bunch of ad-hoc, broken code that no one really
> >> understands.
> >>
> >> While we may not like it, a hard cap on the number of outstanding
> >> requests is required by the protocol docs that Chris helped write.
> >>
> >> Allow me to quote from MS-CIFS:
> >>
> >> MaxMpxCount (2 bytes): The maximum number of outstanding SMB operations
> >> that the server supports. This value includes existing OpLocks, the
> >> NT_TRANSACT_NOTIFY_CHANGE subcommand, and any other commands that are
> >> pending on the server.
> >>
> >> There's nothing in there that says anything about certain commands
> >> being excepted from that value.
> >
> > The only way to know this for sure is to put in a request
> > to Microsoft doc-help to ask if SMBecho and blocking SMB
> > locks are exempted from the maxmpx count.
> 
> I recall, from the code, that the SMBecho is handled "out of band".  I can't 
> speak to the blocking locks.
> 
> Internally, the system keeps a per-connection table keyed on [PID,MID].  The 
> MaxMpxCount indicates the fixed size of this table.  Outstanding commands, 
> including things like ChangeNotify and OpLocks (which are handled as if they 
> were incomplete commands, pending on the server) are kept in this table.
> 
> The doc talks about needing to disable OpLocks if the MaxMpxCount is less 
> than 2.  That's because clients can break their own OpLocks.  If a client 
> has an OpLock on a file, and then opens the file again (the same or 
> different process...it doesn't matter) there won't be enough slots in the 
> [PID,MID] table to allow the open to occur.  The client's second Open 
> request will not be able to be queued (it becomes a pending command since it 
> cannot be answered until the OpLock break either times out or completes) 
> because the pending command table is full.
> 
> Okay, so...  The question is this:  When are commands added to the server's 
> pending queue (the table indexed on [PID,MID].
> 
> The answer is scattered across section 3 of the [MS-CIFS] doc.  If the 
> command needs to be added to the pending queue, it'll say so in the doc.  It 
> should all be under section 3.3.5.
> 
> Look for information about the PendingRequestTable, starting at section 
> 3.3.5.2.1.
> 
> Chris -)-----
> 

Thanks -- that description of windows server behavior is interesting,
but it doesn't really help us much in this case. The question is more:
"Do windows _clients_ ever exceed the server's maxmpx and if so, under
what conditions?"

I'm not really worried about working against windows servers. It's the
3rd party server implementations that concern me. Because of that, I'm
less concerned with windows server behavior, but windows client
behavior is of interest here.

Presumably, most server vendors test their implementations with windows
clients, so we should be reasonably safe if we follow the same "rules"
that the windows redirector does.

-- 
Jeff Layton <jlayton-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 06/11] CIFS: Respect MaxMpxCount field
       [not found]         ` <CAH2r5mvVToaHozN3=YgCCCWFFnjE9AP5xX_BF2JdxDj_JvKsbQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  2012-02-28 16:43           ` Jeff Layton
@ 2012-03-03  8:35           ` Pavel Shilovsky
       [not found]             ` <CAKywueRwzdak2LfpfVkiX2ue0A-0a15J9kO8kgUYseRPXM8Tfw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  1 sibling, 1 reply; 51+ messages in thread
From: Pavel Shilovsky @ 2012-03-03  8:35 UTC (permalink / raw)
  To: Steve French, Jeff Layton; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

2012/2/28 Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>:
> This is going to be more complicated than it seems.
>
> Apparently (according to Chris), Windows will often allow mapmpx simultaneous
> requests per process for various handle based requests.   In addition according
> to JRA, Samba server does not care if you go beyond maxmpx (and there is
> a big performance advantage of that).   On the other hand - if the server
> sets maxmpx to less than 10, these kind of changes probably make sense
> (those servers are probably broken otherwise), but for normal servers
> this will end up restricting more than windows (for more than than the
> maxmpx per pid).   Generally, for servers like Samba that support
> simultaneous requests reasonably we have to be careful about killing
> performance especially now that with Jeff's async reads and writes
> we will frequently get up to 50 (and should probably make it easier
> to have more than 50 to servers like Samba).
>
> Quoting JRA and Volker - "You should be able to queue
> thousands of simultaneous requests from one client to Samba"
> (as long as the client doesn't time out.  The server keeps
> responding to the earlier requests, so with our client timeout
> code weshould be fine).
>

If Samba supports more than 50 requests on fly why it doens't set
MaxMpx count value appropriately (higher that 50). If some servers
respect this value, some - not, why this value needs anyway? I really
think that if it exists in the spec we must follow it's logic -
support all servers that follow the CIFS/SMB spec.

From another hand, we won't kill the nowdays performance if we
substract only 1 slot for echos and 1 slot for oplocks from maxmpx
value (we have 48 for Samba anyway). But it helps us to make the code
more common and easily shareble between existing cifs code and new
smb2 one (for smb2 we should reserve these 2 slots too).

I really think we shouldn't fix all the problems with one patch. This
patch doesn't make things worse but better: it solves the problem with
3rd party servers and doesn't make the performance worse (there is no
much difference between 48 and 50 simultaneous requests for io
operations).

While we can change the behavior for some special cases (Samba,
Windows) later to make them faster, etc, I think we shouldn't stop on
the current patch - it fixes the existing bug and it is the essential
step we should do before SMB2 comes to the tree.

-- 
Best regards,
Pavel Shilovsky.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 01/11] CIFS: Simplify inFlight logic
       [not found]         ` <CAH2r5msNLEF9qVvKsTVTUnPyUjk+7iYVJTxZgd_uuXLAE0iyRg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  2012-02-28  9:38           ` Pavel Shilovsky
@ 2012-03-03  9:33           ` Pavel Shilovsky
  1 sibling, 0 replies; 51+ messages in thread
From: Pavel Shilovsky @ 2012-03-03  9:33 UTC (permalink / raw)
  To: Steve French; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA

2012/2/28 Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>:
> I got a chance to look through this patch set in more detail on the way
> to the SMB2.2 test event.  I liked many of the patches, but this one
> seems to complicate, rather than simplify by adding a spinlock
> to what used to be an atomic_inc.  There is also a possibility that this
> spinlock will become hot.  I don't mind moving the atomic_inc inside the
> new dec_in_flight macro though to make it easier in the future.
>

I tested the performance with and without this patch with dbench 3.
The variant with the patch is slightly worse (~1%). So, seems no
problem with this approach because we need to spinlock echo/oplock
specific variables anyway further.

-- 
Best regards,
Pavel Shilovsky.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 06/11] CIFS: Respect MaxMpxCount field
       [not found]             ` <CAKywueRwzdak2LfpfVkiX2ue0A-0a15J9kO8kgUYseRPXM8Tfw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2012-03-03 12:09               ` Jeff Layton
       [not found]                 ` <20120303070921.5ce2bb10-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
  0 siblings, 1 reply; 51+ messages in thread
From: Jeff Layton @ 2012-03-03 12:09 UTC (permalink / raw)
  To: Pavel Shilovsky; +Cc: Steve French, linux-cifs-u79uwXL29TY76Z2rM5mHXA

On Sat, 3 Mar 2012 12:35:50 +0400
Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:

> 2012/2/28 Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>:
> > This is going to be more complicated than it seems.
> >
> > Apparently (according to Chris), Windows will often allow mapmpx simultaneous
> > requests per process for various handle based requests.   In addition according
> > to JRA, Samba server does not care if you go beyond maxmpx (and there is
> > a big performance advantage of that).   On the other hand - if the server
> > sets maxmpx to less than 10, these kind of changes probably make sense
> > (those servers are probably broken otherwise), but for normal servers
> > this will end up restricting more than windows (for more than than the
> > maxmpx per pid).   Generally, for servers like Samba that support
> > simultaneous requests reasonably we have to be careful about killing
> > performance especially now that with Jeff's async reads and writes
> > we will frequently get up to 50 (and should probably make it easier
> > to have more than 50 to servers like Samba).
> >
> > Quoting JRA and Volker - "You should be able to queue
> > thousands of simultaneous requests from one client to Samba"
> > (as long as the client doesn't time out.  The server keeps
> > responding to the earlier requests, so with our client timeout
> > code weshould be fine).
> >
> 
> If Samba supports more than 50 requests on fly why it doens't set
> MaxMpx count value appropriately (higher that 50). If some servers
> respect this value, some - not, why this value needs anyway? I really
> think that if it exists in the spec we must follow it's logic -
> support all servers that follow the CIFS/SMB spec.
> 

Yeah, that seems crazy to me too. Why not simply have samba advertise a
more realistic value of MaxMpx if it's able to support one?

> From another hand, we won't kill the nowdays performance if we
> substract only 1 slot for echos and 1 slot for oplocks from maxmpx
> value (we have 48 for Samba anyway). But it helps us to make the code
> more common and easily shareble between existing cifs code and new
> smb2 one (for smb2 we should reserve these 2 slots too).
> 
> I really think we shouldn't fix all the problems with one patch. This
> patch doesn't make things worse but better: it solves the problem with
> 3rd party servers and doesn't make the performance worse (there is no
> much difference between 48 and 50 simultaneous requests for io
> operations).
> 
> While we can change the behavior for some special cases (Samba,
> Windows) later to make them faster, etc, I think we shouldn't stop on
> the current patch - it fixes the existing bug and it is the essential
> step we should do before SMB2 comes to the tree.
> 

I agree wholeheartedly. Let's code to the spec we have first and only
afterward worry about adding hacks for servers that deviate from it.

FWIW, I feel that it is absolutely essential that we clean this code up
and get it right before we can merge any further SMB2 code as it's
fundamental.

Now that said, I think Steve's objection is more related to blocking
locks than oplock breaks or echoes. The existing code does this in
wait_for_free_request:

	/* update # of requests on the wire to server */
	if (long_op != CIFS_BLOCKING_OP)
		atomic_inc(&server->inFlight);

...so blocking locks are not currently counted against "inFlight". The
big question is whether windows clients do something similar here.

If they do then we can probably reasonably assume that most servers
are designed to deal with that fact. If not, then we'll need to come up
with some way to deal with pessimal cases like this:

Suppose I have a MaxMpx of 50, and a task on the client locks a file.
Then, 50 more threads go to lock the same file with blocking lock
calls. At that point all of the slots are presumably consumed. How do
we ensure that the thread holding the lock can issue an unlock call so
we can make progress?

Also, suppose we have maxmpx == 1. Can we even do blocking locks at
all? A single blocking lock will consume our only slot...

One thing we could consider is to stop using blocking locks at all. Or,
use the Timeout field with a reasonable value of a few seconds and just
loop to emulate blocking. It would suck for lock "fairness", but we
could be reasonably sure that we won't end up sucking up the entire
maxmpx for long periods of time that way.

-- 
Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 06/11] CIFS: Respect MaxMpxCount field
       [not found]                 ` <20120303070921.5ce2bb10-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
@ 2012-03-04  3:14                   ` Steve French
       [not found]                     ` <CAH2r5mvGjzS73bhgG54Yzcqui9qxfv7e3yrxWZX+weSUQB4cHA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 51+ messages in thread
From: Steve French @ 2012-03-04  3:14 UTC (permalink / raw)
  To: Jeff Layton; +Cc: Pavel Shilovsky, linux-cifs-u79uwXL29TY76Z2rM5mHXA

Echo is fairly minor - we rarely send them when mpxcount is "full",
and when we do, usually send only one unless the server is broken.
For the case where server has an mpxcount fewer than 4, I can see the
logic of turning off (e.g. turn off oplock, blocking lock and echo if
mpxcount 1, blocking lock and echo if only 2, disable echo if mpxcount
is only 3) similar to the way you described, but sending an echo on a
dead session with a "full" mpx count can't hurt so I don't feel as
strongly about echo as I do about making sure that we disable oplock
and blocking locks if mpxcount is 1.

Making sure that we don't send too many blocking locks should be easy
because there is a posix rc that we can use if we have too many
pending (so for example we can limit to something like 25, and not
hurt Jeff's async read/write perf much).

On the issue of why Samba didn't up maxmpx, I expect it is simply that
until Jeff fixed async read/write, it was rare for a client to send 50
requests in parallel.

On the SMB2 credits vs. CIFS maxmpx topic ...  more than once at the
MS Plugfest I heard pushback on treating SMB2 credits and CIFS maxmpx
similarly - they are totally unrelated.  SMB2 credits are pretty
straightforward - we get them back on every request so they are
constantly changing, but the rules are easier to understand (and are
well documented, where the CIFS maxmpx behavior is only partially
documented).

On Sat, Mar 3, 2012 at 6:09 AM, Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> wrote:
> On Sat, 3 Mar 2012 12:35:50 +0400
> Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
>
>> 2012/2/28 Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>:
>> > This is going to be more complicated than it seems.
>> >
>> > Apparently (according to Chris), Windows will often allow mapmpx simultaneous
>> > requests per process for various handle based requests.   In addition according
>> > to JRA, Samba server does not care if you go beyond maxmpx (and there is
>> > a big performance advantage of that).   On the other hand - if the server
>> > sets maxmpx to less than 10, these kind of changes probably make sense
>> > (those servers are probably broken otherwise), but for normal servers
>> > this will end up restricting more than windows (for more than than the
>> > maxmpx per pid).   Generally, for servers like Samba that support
>> > simultaneous requests reasonably we have to be careful about killing
>> > performance especially now that with Jeff's async reads and writes
>> > we will frequently get up to 50 (and should probably make it easier
>> > to have more than 50 to servers like Samba).
>> >
>> > Quoting JRA and Volker - "You should be able to queue
>> > thousands of simultaneous requests from one client to Samba"
>> > (as long as the client doesn't time out.  The server keeps
>> > responding to the earlier requests, so with our client timeout
>> > code weshould be fine).
>> >
>>
>> If Samba supports more than 50 requests on fly why it doens't set
>> MaxMpx count value appropriately (higher that 50). If some servers
>> respect this value, some - not, why this value needs anyway? I really
>> think that if it exists in the spec we must follow it's logic -
>> support all servers that follow the CIFS/SMB spec.
>>
>
> Yeah, that seems crazy to me too. Why not simply have samba advertise a
> more realistic value of MaxMpx if it's able to support one?
>
>> From another hand, we won't kill the nowdays performance if we
>> substract only 1 slot for echos and 1 slot for oplocks from maxmpx
>> value (we have 48 for Samba anyway). But it helps us to make the code
>> more common and easily shareble between existing cifs code and new
>> smb2 one (for smb2 we should reserve these 2 slots too).
>>
>> I really think we shouldn't fix all the problems with one patch. This
>> patch doesn't make things worse but better: it solves the problem with
>> 3rd party servers and doesn't make the performance worse (there is no
>> much difference between 48 and 50 simultaneous requests for io
>> operations).
>>
>> While we can change the behavior for some special cases (Samba,
>> Windows) later to make them faster, etc, I think we shouldn't stop on
>> the current patch - it fixes the existing bug and it is the essential
>> step we should do before SMB2 comes to the tree.
>>
>
> I agree wholeheartedly. Let's code to the spec we have first and only
> afterward worry about adding hacks for servers that deviate from it.
>
> FWIW, I feel that it is absolutely essential that we clean this code up
> and get it right before we can merge any further SMB2 code as it's
> fundamental.
>
> Now that said, I think Steve's objection is more related to blocking
> locks than oplock breaks or echoes. The existing code does this in
> wait_for_free_request:
>
>        /* update # of requests on the wire to server */
>        if (long_op != CIFS_BLOCKING_OP)
>                atomic_inc(&server->inFlight);
>
> ...so blocking locks are not currently counted against "inFlight". The
> big question is whether windows clients do something similar here.
>
> If they do then we can probably reasonably assume that most servers
> are designed to deal with that fact. If not, then we'll need to come up
> with some way to deal with pessimal cases like this:
>
> Suppose I have a MaxMpx of 50, and a task on the client locks a file.
> Then, 50 more threads go to lock the same file with blocking lock
> calls. At that point all of the slots are presumably consumed. How do
> we ensure that the thread holding the lock can issue an unlock call so
> we can make progress?
>
> Also, suppose we have maxmpx == 1. Can we even do blocking locks at
> all? A single blocking lock will consume our only slot...
>
> One thing we could consider is to stop using blocking locks at all. Or,
> use the Timeout field with a reasonable value of a few seconds and just
> loop to emulate blocking. It would suck for lock "fairness", but we
> could be reasonably sure that we won't end up sucking up the entire
> maxmpx for long periods of time that way.
>
> --
> Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>



-- 
Thanks,

Steve

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 06/11] CIFS: Respect MaxMpxCount field
       [not found]                     ` <CAH2r5mvGjzS73bhgG54Yzcqui9qxfv7e3yrxWZX+weSUQB4cHA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2012-03-04 11:30                       ` Jeff Layton
  2012-03-09 12:39                       ` Jeff Layton
  1 sibling, 0 replies; 51+ messages in thread
From: Jeff Layton @ 2012-03-04 11:30 UTC (permalink / raw)
  To: Steve French; +Cc: Pavel Shilovsky, linux-cifs-u79uwXL29TY76Z2rM5mHXA

On Sat, 3 Mar 2012 21:14:19 -0600
Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:

> Echo is fairly minor - we rarely send them when mpxcount is "full",
> and when we do, usually send only one unless the server is broken.
> For the case where server has an mpxcount fewer than 4, I can see the
> logic of turning off (e.g. turn off oplock, blocking lock and echo if
> mpxcount 1, blocking lock and echo if only 2, disable echo if mpxcount
> is only 3) similar to the way you described, but sending an echo on a
> dead session with a "full" mpx count can't hurt so I don't feel as
> strongly about echo as I do about making sure that we disable oplock
> and blocking locks if mpxcount is 1.
> 
> Making sure that we don't send too many blocking locks should be easy
> because there is a posix rc that we can use if we have too many
> pending (so for example we can limit to something like 25, and not
> hurt Jeff's async read/write perf much).
> 

Another possibility is to use a smaller timeout for blocking locks in a
loop. Do something like this (simplified pseudocode):

do {
	rc = [blocking lock call with timeout of 10s];
} while (rc == -ETIMEDOUT)

Lock "fairness" would possibly suffer, but you could be reasonably
certain that you wouldn't deadlock the client for an undue period of
time. Eventually your other calls would get in between the lock
attempts.

> On the issue of why Samba didn't up maxmpx, I expect it is simply that
> until Jeff fixed async read/write, it was rare for a client to send 50
> requests in parallel.
> 

I'm fairly certain that windows sends reads/writes in parallel. Does
their client have a hard cap of 50 or so as well?

> On the SMB2 credits vs. CIFS maxmpx topic ...  more than once at the
> MS Plugfest I heard pushback on treating SMB2 credits and CIFS maxmpx
> similarly - they are totally unrelated.  SMB2 credits are pretty
> straightforward - we get them back on every request so they are
> constantly changing, but the rules are easier to understand (and are
> well documented, where the CIFS maxmpx behavior is only partially
> documented).
> 

That may be, particularly if we have to treat certain types of calls as
"special". Still, whether the rules for SMB1 are documented or not, we
have to settle on a set of them in order to fix cifs.ko. Building a
framework that can accommodate both sets of rules is better than
cut-and-paste. We just may need to abstract out a bit more than we
thought originally.

-- 
Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 06/11] CIFS: Respect MaxMpxCount field
       [not found]                     ` <CAH2r5mvGjzS73bhgG54Yzcqui9qxfv7e3yrxWZX+weSUQB4cHA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  2012-03-04 11:30                       ` Jeff Layton
@ 2012-03-09 12:39                       ` Jeff Layton
       [not found]                         ` <20120309073930.3a79fa10-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
  1 sibling, 1 reply; 51+ messages in thread
From: Jeff Layton @ 2012-03-09 12:39 UTC (permalink / raw)
  To: Steve French
  Cc: Pavel Shilovsky, linux-cifs-u79uwXL29TY76Z2rM5mHXA,
	crh-eUNUBHrolfbYtjvyW6yDsg, jra-eUNUBHrolfbYtjvyW6yDsg

On Sat, 3 Mar 2012 21:14:19 -0600
Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:

> 
> On the issue of why Samba didn't up maxmpx, I expect it is simply that
> until Jeff fixed async read/write, it was rare for a client to send 50
> requests in parallel.
> 

Are windows clients hard capped at 50 outstanding calls or so?

> On the SMB2 credits vs. CIFS maxmpx topic ...  more than once at the
> MS Plugfest I heard pushback on treating SMB2 credits and CIFS maxmpx
> similarly - they are totally unrelated.  SMB2 credits are pretty
> straightforward - we get them back on every request so they are
> constantly changing, but the rules are easier to understand (and are
> well documented, where the CIFS maxmpx behavior is only partially
> documented).
> 

I can understand their POV, and that may be correct. I think we ought
to step back though and consider the fundamental problem that we're
trying to solve. When we want to send a call on the wire, we need to
know:

"Is this particular call allowed to go out onto the wire at this time
or does it need to wait for another event to occur?"

Earlier, I suggested: "Let's treat SMB1 maxmpx handling as a trivial
case of SMB2 credits." If that's not possible for some reason then we
ought to consider something like this:

"Let's build this out the transport layer so that it can accomodate
both sets of protocols by allowing us to plug in different rules
depending on the protocol."

Now that we're looking more closely at this, I think you're correct
that SMB1 maxmpx limits and SMB2 credits follow different "rules". But
I also think that it's best to engineer this in such a way that we can
"plug in" the correct ruleset for answering the above question based on
the protocol version in use.

The trick is to do this in such a way that we only "plug in" what needs
to be different. If treating SMB1 maxmpx limits as a trivial case of
SMB2 credits is too difficult, then I would take that as a sign that we
just need to expand how much of that decision making needs to be
protocol specific.

-- 
Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 06/11] CIFS: Respect MaxMpxCount field
       [not found]                         ` <20120309073930.3a79fa10-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
@ 2012-03-09 16:45                           ` Steve French
       [not found]                             ` <CAH2r5mvzgnTcyhL-Rip9yHUEMsLOCFhfAoNdRyVqhNFin_A6mw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 51+ messages in thread
From: Steve French @ 2012-03-09 16:45 UTC (permalink / raw)
  To: Jeff Layton
  Cc: Pavel Shilovsky, linux-cifs-u79uwXL29TY76Z2rM5mHXA,
	crh-eUNUBHrolfbYtjvyW6yDsg, jra-eUNUBHrolfbYtjvyW6yDsg

On Fri, Mar 9, 2012 at 6:39 AM, Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> wrote:
> On Sat, 3 Mar 2012 21:14:19 -0600
> Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
>
>>
>> On the issue of why Samba didn't up maxmpx, I expect it is simply that
>> until Jeff fixed async read/write, it was rare for a client to send 50
>> requests in parallel.
>>
>
> Are windows clients hard capped at 50 outstanding calls or so?

No.   Windows can definitely go beyond 50.  And clients apparently do
sometimes go
beyond 50 )(even if server negotiates 50) as the following Microsoft
TechNote implies:

"Because the limit on outstanding requests is negotiated between the
client and and server and is enforced by the client, this value might
not be the actual maximum used. Increasing this value might improve
server performance, but it requires more receive buffers (also known
as work items ) on the server.  Note:  For Windows NT 4.0 Service Pack
3 and later, the valid values for this entry range from 1 to 65,535
requests, with a default value of 50 requests. Windows 2000 limits the
maximum value of this entry to 125 requests to assure that Windows 95
and Windows 98 clients can connect to the server."

Apparently IIS and Windows Terminal Server (as a client to NAS boxes)
need more than 50 - see this quote from NetApp server manual.

"cifs.max_mpx
This option controls how many simultaneous operations the filer
reports that it can process. An
"operation" is each I/O the client believes is pending on the filer
including outstanding change notify
operations. Clients such as Windows Terminal Server or IIS may require
that this number be increased
to avoid errors and performance delays."


Note that on the WIndows server side note that there is MaxMpxCt which
controls it
and a second parm maxworkitems which helps avoid hangs (as we found
out in testing).



>> On the SMB2 credits vs. CIFS maxmpx topic ...  more than once at the
>> MS Plugfest I heard pushback on treating SMB2 credits and CIFS maxmpx
>> similarly - they are totally unrelated.  SMB2 credits are pretty
>> straightforward - we get them back on every request so they are
>> constantly changing, but the rules are easier to understand (and are
>> well documented, where the CIFS maxmpx behavior is only partially
>> documented).
>>
>
> I can understand their POV, and that may be correct. I think we ought
> to step back though and consider the fundamental problem that we're
> trying to solve. When we want to send a call on the wire, we need to
> know:
>
> "Is this particular call allowed to go out onto the wire at this time
> or does it need to wait for another event to occur?"
>
> Earlier, I suggested: "Let's treat SMB1 maxmpx handling as a trivial
> case of SMB2 credits." If that's not possible for some reason then we
> ought to consider something like this:
>
> "Let's build this out the transport layer so that it can accomodate
> both sets of protocols by allowing us to plug in different rules
> depending on the protocol."
>
> Now that we're looking more closely at this, I think you're correct
> that SMB1 maxmpx limits and SMB2 credits follow different "rules". But
> I also think that it's best to engineer this in such a way that we can
> "plug in" the correct ruleset for answering the above question based on
> the protocol version in use.
>
> The trick is to do this in such a way that we only "plug in" what needs
> to be different. If treating SMB1 maxmpx limits as a trivial case of
> SMB2 credits is too difficult, then I would take that as a sign that we
> just need to expand how much of that decision making needs to be
> protocol specific.
>
> --
> Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>



-- 
Thanks,

Steve

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 06/11] CIFS: Respect MaxMpxCount field
       [not found]                             ` <CAH2r5mvzgnTcyhL-Rip9yHUEMsLOCFhfAoNdRyVqhNFin_A6mw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2012-03-09 19:04                               ` Christopher R. Hertel
       [not found]                                 ` <4F5A543D.2040808-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
  0 siblings, 1 reply; 51+ messages in thread
From: Christopher R. Hertel @ 2012-03-09 19:04 UTC (permalink / raw)
  To: Steve French
  Cc: Jeff Layton, Pavel Shilovsky, linux-cifs-u79uwXL29TY76Z2rM5mHXA,
	jra-eUNUBHrolfbYtjvyW6yDsg

On 03/09/2012 10:45 AM, Steve French wrote:
> On Fri, Mar 9, 2012 at 6:39 AM, Jeff Layton<jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>  wrote:
>> On Sat, 3 Mar 2012 21:14:19 -0600
>> Steve French<smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>  wrote:
>>
>>>
>>> On the issue of why Samba didn't up maxmpx, I expect it is simply that
>>> until Jeff fixed async read/write, it was rare for a client to send 50
>>> requests in parallel.
>>>
>>
>> Are windows clients hard capped at 50 outstanding calls or so?
>
> No.   Windows can definitely go beyond 50.  And clients apparently do
> sometimes go
> beyond 50 )(even if server negotiates 50) as the following Microsoft
> TechNote implies:
>
> "Because the limit on outstanding requests is negotiated between the
> client and and server and is enforced by the client, this value might
> not be the actual maximum used. Increasing this value might improve
> server performance, but it requires more receive buffers (also known
> as work items ) on the server.  Note:  For Windows NT 4.0 Service Pack
> 3 and later, the valid values for this entry range from 1 to 65,535
> requests, with a default value of 50 requests. Windows 2000 limits the
> maximum value of this entry to 125 requests to assure that Windows 95
> and Windows 98 clients can connect to the server."

My memory is fuzzy, but I did research this when my team and I were writing 
the SMB/CIFS documentation.  What I recall is that Windows servers have a 
fixed pool of Receive Buffers (used to receive incoming messages).  When a 
message comes in, a Receive Buffer is allocated and the message is copied 
into the Receive Buffer.  The Receive Buffer is then placed into the pending 
message table for the connection.  (A connection is a single transport link 
between client and server.  There may be several SMB Sessions per connection.)

I do not know what happens if the pending message table fills up.  I 
*believe* that the server will stop reading messages from the connection, 
but this should be verified by checking with Microsoft and by testing.  It 
will be difficult to get conclusive results, since the server will be 
working to answer the outstanding requests and remove them from the table at 
the same time.

In any case, the protocol specifications define MaxMpxCount as a hard limit. 
  The client is simply not supposed to overfill the server's outstanding 
request table.  Unpredictable things will happen, particularly when you 
start running against other servers (Samba, EMC, NetApp, etc.) all of which 
will have implemented this differently.

One more note on this:  The ability to modify the size of the table was not 
used heavily in the early days and I suspect, based upon test results that 
Steve shared with me in Redmond, that there may be some bugs exposed in some 
servers if you increase the size of the table.  One errant hard-coded value 
is all it takes.  Proceed with caution.

> Apparently IIS and Windows Terminal Server (as a client to NAS boxes)
> need more than 50 - see this quote from NetApp server manual.
>
> "cifs.max_mpx
> This option controls how many simultaneous operations the filer
> reports that it can process.  An "operation" is each I/O the
> client believes is pending on the filer including outstanding
> change notify operations.  Clients such as Windows Terminal
> Server or IIS may require that this number be increased
> to avoid errors and performance delays."

Windows Terminal Server and IIS will likely have a lot of processes and 
threads talking to the server over the same connection at the same time--a 
lot of parallelism.

> Note that on the WIndows server side note that there is MaxMpxCt which
> controls it and a second parm maxworkitems which helps avoid hangs (as
> we found out in testing).

Search for MaxWorkItems in this doc:
   http://msdn.microsoft.com/en-us/library/cc615012.aspx

The description of MaxWorkItems is poorly written (by my standards) but it 
seems to indicate that MaxWorkItems controls the overall server pool of 
receive buffers.  MaxMpxCt, in contrast, refers to individual connections.

>>> On the SMB2 credits vs. CIFS maxmpx topic ...  more than once at the
>>> MS Plugfest I heard pushback on treating SMB2 credits and CIFS maxmpx
>>> similarly - they are totally unrelated.  SMB2 credits are pretty
>>> straightforward - we get them back on every request so they are
>>> constantly changing, but the rules are easier to understand (and are
>>> well documented, where the CIFS maxmpx behavior is only partially
>>> documented).

If there is missing documentation on the MaxMpxCount negotiation or the use 
of the value, it should be reported as a bug.

Please prove me wrong if I'm wrong, but I believe that the expected wire 
behavior is well covered in [MS-CIFS], and that references are given to 
other documentation to provide the deeper "what Windows does" documentation. 
  I wrote most of that stuff, so show me what's missing.  I found it all 
when I looked.

>> I can understand their POV, and that may be correct. I think we ought
>> to step back though and consider the fundamental problem that we're
>> trying to solve. When we want to send a call on the wire, we need to
>> know:
>>
>> "Is this particular call allowed to go out onto the wire at this time
>> or does it need to wait for another event to occur?"
>>
>> Earlier, I suggested: "Let's treat SMB1 maxmpx handling as a trivial
>> case of SMB2 credits." If that's not possible for some reason then we
>> ought to consider something like this:
>>
>> "Let's build this out the transport layer so that it can accomodate
>> both sets of protocols by allowing us to plug in different rules
>> depending on the protocol."

Hmmm...

>> Now that we're looking more closely at this, I think you're correct
>> that SMB1 maxmpx limits and SMB2 credits follow different "rules". But
>> I also think that it's best to engineer this in such a way that we can
>> "plug in" the correct ruleset for answering the above question based on
>> the protocol version in use.
 >>
>> The trick is to do this in such a way that we only "plug in" what needs
>> to be different. If treating SMB1 maxmpx limits as a trivial case of
>> SMB2 credits is too difficult, then I would take that as a sign that we
>> just need to expand how much of that decision making needs to be
>> protocol specific.

The folks at Microsoft (who are, of course, well ahead in their SMB2.x 
implementations) are very surprised that we are trying to maintain a single 
codebase for both protocols.  (I heard the same thing from several Microsoft 
engineers during separate conversations.)

My concern with this approach is that there are enough differences between 
the two protocols that we will wind up with more plug-ins than common code. 
  It'll look like hair transplant surgery gone very, very wrong.  I prefer 
to turn this around and think about what code can be conveniently used by 
both protocol stacks.

Chris -)-----

-- 
"Implementing CIFS - the Common Internet FileSystem" ISBN: 013047116X
Samba Team -- http://www.samba.org/     -)-----   Christopher R. Hertel
jCIFS Team -- http://jcifs.samba.org/   -)-----   ubiqx development, uninq.
ubiqx Team -- http://www.ubiqx.org/     -)-----   crh-jFlgvBokg3lg9hUCZPvPmw@public.gmane.org
OnLineBook -- http://ubiqx.org/cifs/    -)-----   crh-zuGDro9SezXYtjvyW6yDsg@public.gmane.org

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 06/11] CIFS: Respect MaxMpxCount field
       [not found]                                 ` <4F5A543D.2040808-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
@ 2012-03-09 20:14                                   ` Jeremy Allison
  2012-03-09 20:16                                     ` Steve French
  2012-03-09 21:05                                     ` Christopher R. Hertel
  0 siblings, 2 replies; 51+ messages in thread
From: Jeremy Allison @ 2012-03-09 20:14 UTC (permalink / raw)
  To: Christopher R. Hertel
  Cc: Steve French, Jeff Layton, Pavel Shilovsky,
	linux-cifs-u79uwXL29TY76Z2rM5mHXA, jra-eUNUBHrolfbYtjvyW6yDsg

On Fri, Mar 09, 2012 at 01:04:29PM -0600, Christopher R. Hertel wrote:
> 
> The folks at Microsoft (who are, of course, well ahead in their
> SMB2.x implementations) are very surprised that we are trying to
> maintain a single codebase for both protocols.  (I heard the same
> thing from several Microsoft engineers during separate
> conversations.)

That's just a misunderstanding of how our codebase is
structured, that's all.

The SMB1 parser/protocol engine is completely different code from the SMB2
parser/protocol engine in Samba.

What is in common (as is also in common in Microsoft's codebase)
is the code that implements the underlying file system functionality.

They have a common NTFS (and now ReFS) codebase, we have a common
map POSIX to Windows semantics layer.

Jeremy.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 06/11] CIFS: Respect MaxMpxCount field
  2012-03-09 20:14                                   ` Jeremy Allison
@ 2012-03-09 20:16                                     ` Steve French
       [not found]                                       ` <CAH2r5mvMWOVrKXYJjcKYwUR+yaJpzYysDoc+TvPmfN+RDHAQ5g-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  2012-03-09 21:05                                     ` Christopher R. Hertel
  1 sibling, 1 reply; 51+ messages in thread
From: Steve French @ 2012-03-09 20:16 UTC (permalink / raw)
  To: Jeremy Allison
  Cc: Christopher R. Hertel, Jeff Layton, Pavel Shilovsky,
	linux-cifs-u79uwXL29TY76Z2rM5mHXA

On Fri, Mar 9, 2012 at 2:14 PM, Jeremy Allison <jra-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:
> On Fri, Mar 09, 2012 at 01:04:29PM -0600, Christopher R. Hertel wrote:
>>
>> The folks at Microsoft (who are, of course, well ahead in their
>> SMB2.x implementations) are very surprised that we are trying to
>> maintain a single codebase for both protocols.  (I heard the same
>> thing from several Microsoft engineers during separate
>> conversations.)
>
> That's just a misunderstanding of how our codebase is
> structured, that's all.
>
> The SMB1 parser/protocol engine is completely different code from the SMB2
> parser/protocol engine in Samba.
>
> What is in common (as is also in common in Microsoft's codebase)
> is the code that implements the underlying file system functionality.
>
> They have a common NTFS (and now ReFS) codebase, we have a common
> map POSIX to Windows semantics layer.

On the client side, as a compromise with those who wanted one module,
(ie in Pavel's tree) we keep the majority of the smb2 specific code in
distinct c files
which are not linked in by default to cifs.ko.   Sharing the same transport code
does have headaches though as the discussion above mentions with regard
to "credits" vs. "maxmpx" but it has turned out better than I originally
expected (ie the changes to common code)

-- 
Thanks,

Steve

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 06/11] CIFS: Respect MaxMpxCount field
  2012-03-09 20:14                                   ` Jeremy Allison
  2012-03-09 20:16                                     ` Steve French
@ 2012-03-09 21:05                                     ` Christopher R. Hertel
       [not found]                                       ` <4F5A70A3.906-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
  1 sibling, 1 reply; 51+ messages in thread
From: Christopher R. Hertel @ 2012-03-09 21:05 UTC (permalink / raw)
  To: Jeremy Allison
  Cc: Steve French, Jeff Layton, Pavel Shilovsky,
	linux-cifs-u79uwXL29TY76Z2rM5mHXA

On 03/09/2012 02:14 PM, Jeremy Allison wrote:
> On Fri, Mar 09, 2012 at 01:04:29PM -0600, Christopher R. Hertel wrote:
>>
>> The folks at Microsoft (who are, of course, well ahead in their
>> SMB2.x implementations) are very surprised that we are trying to
>> maintain a single codebase for both protocols.  (I heard the same
>> thing from several Microsoft engineers during separate
>> conversations.)
>
> That's just a misunderstanding of how our codebase is
> structured, that's all.
>
> The SMB1 parser/protocol engine is completely different code from the SMB2
> parser/protocol engine in Samba.

I was thinking of the CIFS client, which is what Jeff was talking about.

> What is in common (as is also in common in Microsoft's codebase)
> is the code that implements the underlying file system functionality.

Having seen the code, I'd say it's mixed.  There is actually a lot of work 
done in the server system to massage and validate the requests before 
converting them into NT system requests and passing them down.

I was surprised by that at first.  I expected it for the DOS and OS/2 calls. 
  Semantics for those needed to be converted to NT semantics, which made 
sense.  What surprised me was how much work was done on SMB_COM_NT_* commands.

Looking more closely, I found that some of the work done on NT-to-NT calls 
was done to ensure that the DOS and OS/2 state were kept up to date.  There 
was other work done, however.  It's not a simple pass-through.  In part 
because the SMB server has to defend the kernel from bogus calls and values.

The SMB2 server code does not need to worry about DOS and OS/2 semantics, 
but there are a number of new features and behaviors it does need to handle. 
  So, the SMB2 code processes requests differently.

> They have a common NTFS (and now ReFS) codebase, we have a common
> map POSIX to Windows semantics layer.

...and at that level I agree.  That layer can be a single layer accessed by 
both protocols.

Keep in mind, though, that SMB1 is dead and will never make use of things 
like durable, resilient, and persistent handles.  It will also never fully 
expose the semantics of ReFS.  Similarly, SMB2 will never need to worry 
about presenting DOS and OS/2 as SMB1 does.

So some of the semantics that file system mapping layer has to handle are 
going to be purely for one protocol or the other.  The biggest part of the 
overlap there will be NTFS semantics... which is, admittedly, the lions 
share of the market now and for some time to come.

Chris -)-----

-- 
"Implementing CIFS - the Common Internet FileSystem" ISBN: 013047116X
Samba Team -- http://www.samba.org/     -)-----   Christopher R. Hertel
jCIFS Team -- http://jcifs.samba.org/   -)-----   ubiqx development, uninq.
ubiqx Team -- http://www.ubiqx.org/     -)-----   crh-jFlgvBokg3lg9hUCZPvPmw@public.gmane.org
OnLineBook -- http://ubiqx.org/cifs/    -)-----   crh-zuGDro9SezXYtjvyW6yDsg@public.gmane.org

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 06/11] CIFS: Respect MaxMpxCount field
       [not found]                                       ` <CAH2r5mvMWOVrKXYJjcKYwUR+yaJpzYysDoc+TvPmfN+RDHAQ5g-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2012-03-09 21:07                                         ` Christopher R. Hertel
       [not found]                                           ` <4F5A712C.8030500-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
  0 siblings, 1 reply; 51+ messages in thread
From: Christopher R. Hertel @ 2012-03-09 21:07 UTC (permalink / raw)
  To: Steve French
  Cc: Jeremy Allison, Jeff Layton, Pavel Shilovsky,
	linux-cifs-u79uwXL29TY76Z2rM5mHXA

On 03/09/2012 02:16 PM, Steve French wrote:
> On Fri, Mar 9, 2012 at 2:14 PM, Jeremy Allison<jra-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>  wrote:
>> On Fri, Mar 09, 2012 at 01:04:29PM -0600, Christopher R. Hertel wrote:
>>>
>>> The folks at Microsoft (who are, of course, well ahead in their
>>> SMB2.x implementations) are very surprised that we are trying to
>>> maintain a single codebase for both protocols.  (I heard the same
>>> thing from several Microsoft engineers during separate
>>> conversations.)
>>
>> That's just a misunderstanding of how our codebase is
>> structured, that's all.
>>
>> The SMB1 parser/protocol engine is completely different code from the SMB2
>> parser/protocol engine in Samba.
>>
>> What is in common (as is also in common in Microsoft's codebase)
>> is the code that implements the underlying file system functionality.
>>
>> They have a common NTFS (and now ReFS) codebase, we have a common
>> map POSIX to Windows semantics layer.
>
> On the client side, as a compromise with those who wanted one module,
> (ie in Pavel's tree) we keep the majority of the smb2 specific code in
> distinct c files
> which are not linked in by default to cifs.ko.   Sharing the same transport code
> does have headaches though as the discussion above mentions with regard
> to "credits" vs. "maxmpx" but it has turned out better than I originally
> expected (ie the changes to common code)

No doubt.

...and we certainly want only one piece of code actually creating and 
managing connections to the server.

-- 
"Implementing CIFS - the Common Internet FileSystem" ISBN: 013047116X
Samba Team -- http://www.samba.org/     -)-----   Christopher R. Hertel
jCIFS Team -- http://jcifs.samba.org/   -)-----   ubiqx development, uninq.
ubiqx Team -- http://www.ubiqx.org/     -)-----   crh-jFlgvBokg3lg9hUCZPvPmw@public.gmane.org
OnLineBook -- http://ubiqx.org/cifs/    -)-----   crh-zuGDro9SezXYtjvyW6yDsg@public.gmane.org

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 06/11] CIFS: Respect MaxMpxCount field
       [not found]                                       ` <4F5A70A3.906-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
@ 2012-03-09 21:14                                         ` Jeremy Allison
  0 siblings, 0 replies; 51+ messages in thread
From: Jeremy Allison @ 2012-03-09 21:14 UTC (permalink / raw)
  To: Christopher R. Hertel
  Cc: Jeremy Allison, Steve French, Jeff Layton, Pavel Shilovsky,
	linux-cifs-u79uwXL29TY76Z2rM5mHXA

On Fri, Mar 09, 2012 at 03:05:39PM -0600, Christopher R. Hertel wrote:
> On 03/09/2012 02:14 PM, Jeremy Allison wrote:
> >On Fri, Mar 09, 2012 at 01:04:29PM -0600, Christopher R. Hertel wrote:
> >>
> >>The folks at Microsoft (who are, of course, well ahead in their
> >>SMB2.x implementations) are very surprised that we are trying to
> >>maintain a single codebase for both protocols.  (I heard the same
> >>thing from several Microsoft engineers during separate
> >>conversations.)
> >
> >That's just a misunderstanding of how our codebase is
> >structured, that's all.
> >
> >The SMB1 parser/protocol engine is completely different code from the SMB2
> >parser/protocol engine in Samba.
> 
> I was thinking of the CIFS client, which is what Jeff was talking about.

Then I am confused, sorry :-).

> Keep in mind, though, that SMB1 is dead and will never make use of
> things like durable, resilient, and persistent handles.  It will
> also never fully expose the semantics of ReFS.  Similarly, SMB2 will
> never need to worry about presenting DOS and OS/2 as SMB1 does.
> 
> So some of the semantics that file system mapping layer has to
> handle are going to be purely for one protocol or the other.  The
> biggest part of the overlap there will be NTFS semantics... which
> is, admittedly, the lions share of the market now and for some time
> to come.

So what we'll end up doing is migrating the layer to SMB2
semantics and then mapping the old SMB1 semantics into a
layer that goes on top (it's like one of those topological
tricks of turning a sphere inside out :-).

http://www.youtube.com/watch?v=BVVfs4zKrgk

We did it before when migrating from DOS semantics to
NT semantics.

Jeremy.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH 06/11] CIFS: Respect MaxMpxCount field
       [not found]                                           ` <4F5A712C.8030500-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
@ 2012-03-12 15:09                                             ` Jeff Layton
  0 siblings, 0 replies; 51+ messages in thread
From: Jeff Layton @ 2012-03-12 15:09 UTC (permalink / raw)
  To: Christopher R. Hertel
  Cc: Steve French, Jeremy Allison, Pavel Shilovsky,
	linux-cifs-u79uwXL29TY76Z2rM5mHXA

On Fri, 09 Mar 2012 15:07:56 -0600
"Christopher R. Hertel" <crh-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:

> On 03/09/2012 02:16 PM, Steve French wrote:
> > On Fri, Mar 9, 2012 at 2:14 PM, Jeremy Allison<jra-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>  wrote:
> >> On Fri, Mar 09, 2012 at 01:04:29PM -0600, Christopher R. Hertel wrote:
> >>>
> >>> The folks at Microsoft (who are, of course, well ahead in their
> >>> SMB2.x implementations) are very surprised that we are trying to
> >>> maintain a single codebase for both protocols.  (I heard the same
> >>> thing from several Microsoft engineers during separate
> >>> conversations.)
> >>
> >> That's just a misunderstanding of how our codebase is
> >> structured, that's all.
> >>
> >> The SMB1 parser/protocol engine is completely different code from the SMB2
> >> parser/protocol engine in Samba.
> >>
> >> What is in common (as is also in common in Microsoft's codebase)
> >> is the code that implements the underlying file system functionality.
> >>
> >> They have a common NTFS (and now ReFS) codebase, we have a common
> >> map POSIX to Windows semantics layer.
> >
> > On the client side, as a compromise with those who wanted one module,
> > (ie in Pavel's tree) we keep the majority of the smb2 specific code in
> > distinct c files
> > which are not linked in by default to cifs.ko.   Sharing the same transport code
> > does have headaches though as the discussion above mentions with regard
> > to "credits" vs. "maxmpx" but it has turned out better than I originally
> > expected (ie the changes to common code)
> 
> No doubt.
> 
> ...and we certainly want only one piece of code actually creating and 
> managing connections to the server.
> 

(sorry for the long delay in responses here, we just got a newborn baby
at home and I've been a little busy ;)

Yep. There are probably more pieces that will be shared, but we really
*do not* want to do what was done in the initial pass here. A basically
a wholesale copy and paste of fs/cifs into fs/smb2 with "s/cifs/smb2/g"
done over it. Steve tried that for a while and it was a mess -- bugs
would get fixed in fs/cifs but not fs/smb2 and vice versa.

We'll get far more benefit and less maintenance hassle over the long
haul by expanding the infrastructure to be able to handle both
protocols correctly.

Here's sort of what I would envision but we may need to alter it as we
find problems. I think we should model this similarly to how the NFS
code is layed out:

The transport layer should be unified. Basically we don't need an
entirely separate set of code handling sockets, etc. Also, the code
that handles NEGOTIATE ought to eventually be somewhat integrated as
well. We do want to be able to handle the smb1/2 protocol negotiation
a'la section 4.2 of MS-SMB2. That's not necessary initially, but is a
nice to have eventually.

By the same token we do not want a separate fs_type for smb2. We went
down that road with nfs vs nfs4 and it's still a headache today. We'll
be happier if we can keep that unified between the two protocols.

We'll probably want a unified superblock for the fs, though I would
envision that we may want a union or something inside the struct for
smb1 or smb2 specific parts.

inode and dentry operations can probably be the same for the most part,
but we may want smb1/2 specific ones in some cases. Below that, there
should be a set of protocol-level operations.

For instance, we might have a Linux VFS inode operation for doing an
open that we share between both protocols, but that calls out to a set
of protocol specific operations to do the actual call on the wire.
Where the protocols are widely divergent in behavior we may need
specific inode and dentry operations for each protocol as well.

Obviously as things move along we may need to abstract out more or
fewer pieces, but keeping code duplication to a minimum ought to be a
design goal.

-- 
Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>

^ permalink raw reply	[flat|nested] 51+ messages in thread

end of thread, other threads:[~2012-03-12 15:09 UTC | newest]

Thread overview: 51+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-02-22  7:32 [PATCH 0/11] Improve transport code for future SMB2 usage Pavel Shilovsky
     [not found] ` <1329895984-9251-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-02-22  7:32   ` [PATCH 01/11] CIFS: Simplify inFlight logic Pavel Shilovsky
     [not found]     ` <1329895984-9251-2-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-02-27 22:53       ` Steve French
     [not found]         ` <CAH2r5msNLEF9qVvKsTVTUnPyUjk+7iYVJTxZgd_uuXLAE0iyRg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-02-28  9:38           ` Pavel Shilovsky
     [not found]             ` <CAKywueQNFbwDqwr7adWsUZmaYX28tz3kYnL1=4itBHAFV1aeaA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-02-28 11:31               ` Jeff Layton
     [not found]                 ` <20120228063120.76265cd9-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
2012-02-28 11:39                   ` Pavel Shilovsky
2012-03-03  9:33           ` Pavel Shilovsky
2012-02-22  7:32   ` [PATCH 02/11] CIFS: Introduce credit-based flow control Pavel Shilovsky
2012-02-22  7:32   ` [PATCH 03/11] CIFS: Count blocking lock command Pavel Shilovsky
     [not found]     ` <1329895984-9251-4-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-02-27 23:23       ` Steve French
     [not found]         ` <CAH2r5mujUbTEe0xtk_sfM1xokCk7FnX=6JKO539ut88Z+RS7wA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-02-28  9:40           ` Pavel Shilovsky
2012-02-22  7:32   ` [PATCH 04/11] CIFS: Delete echo_retries module parm Pavel Shilovsky
     [not found]     ` <1329895984-9251-5-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-02-22 16:23       ` Jeff Layton
     [not found]         ` <20120222112323.3d1afe4b-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
2012-02-23  6:16           ` Pavel Shilovsky
2012-02-27 23:39       ` Steve French
2012-02-22  7:32   ` [PATCH 05/11] CIFS: Make wait_for_free_request interruptible Pavel Shilovsky
     [not found]     ` <1329895984-9251-6-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-02-22 19:15       ` Jeff Layton
     [not found]         ` <20120222141534.5512c3bf-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-02-23  6:18           ` Pavel Shilovsky
     [not found]             ` <CAKywueR7tggS99buChze5WHFY2=daoHUkO41F+WTNfqRT64Syw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-02-27 23:54               ` Steve French
2012-02-22  7:32   ` [PATCH 06/11] CIFS: Respect MaxMpxCount field Pavel Shilovsky
     [not found]     ` <1329895984-9251-7-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-02-28  0:01       ` Steve French
     [not found]         ` <CAH2r5mvVToaHozN3=YgCCCWFFnjE9AP5xX_BF2JdxDj_JvKsbQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-02-28 16:43           ` Jeff Layton
     [not found]             ` <20120228114341.1629ed85-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
2012-02-28 17:42               ` Steve French
     [not found]                 ` <CAH2r5mvFyw8Cn8nXN9ZBZogBGVr5L5T9aX7Zs8DOiZgDUqGp1Q-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-02-28 19:47                   ` Jeff Layton
     [not found]                     ` <20120228144736.18124fc3-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
2012-02-28 20:03                       ` Steve French
     [not found]                         ` <CAH2r5mvJE+ACNVuv+HEQMuwvaMTzfOb7Msk4U1ZVnZ046AEi1Q-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-02-28 20:53                           ` Pavel Shilovsky
     [not found]                             ` <CAKywueSxe_wZwudx3UK14C94o53zjghsTJJSah=CQSqy0uhZRQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-02-28 21:18                               ` Steve French
     [not found]                                 ` <CAH2r5mvFiwpVwcBgfuXvEGC1_8snLMAsp4fRVEDMqTWXDJdu9w-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-03-01 18:37                                   ` Jeff Layton
     [not found]                                     ` <20120301133747.5fc891b5-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-03-01 18:48                                       ` Jeremy Allison
2012-03-01 19:12                                         ` Jeff Layton
2012-03-01 19:18                                         ` Christopher R. Hertel
     [not found]                                           ` <4F4FCB69.6060705-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-03-02 15:45                                             ` Jeff Layton
2012-03-03  8:35           ` Pavel Shilovsky
     [not found]             ` <CAKywueRwzdak2LfpfVkiX2ue0A-0a15J9kO8kgUYseRPXM8Tfw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-03-03 12:09               ` Jeff Layton
     [not found]                 ` <20120303070921.5ce2bb10-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
2012-03-04  3:14                   ` Steve French
     [not found]                     ` <CAH2r5mvGjzS73bhgG54Yzcqui9qxfv7e3yrxWZX+weSUQB4cHA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-03-04 11:30                       ` Jeff Layton
2012-03-09 12:39                       ` Jeff Layton
     [not found]                         ` <20120309073930.3a79fa10-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2012-03-09 16:45                           ` Steve French
     [not found]                             ` <CAH2r5mvzgnTcyhL-Rip9yHUEMsLOCFhfAoNdRyVqhNFin_A6mw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-03-09 19:04                               ` Christopher R. Hertel
     [not found]                                 ` <4F5A543D.2040808-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-03-09 20:14                                   ` Jeremy Allison
2012-03-09 20:16                                     ` Steve French
     [not found]                                       ` <CAH2r5mvMWOVrKXYJjcKYwUR+yaJpzYysDoc+TvPmfN+RDHAQ5g-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-03-09 21:07                                         ` Christopher R. Hertel
     [not found]                                           ` <4F5A712C.8030500-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-03-12 15:09                                             ` Jeff Layton
2012-03-09 21:05                                     ` Christopher R. Hertel
     [not found]                                       ` <4F5A70A3.906-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-03-09 21:14                                         ` Jeremy Allison
2012-02-22  7:33   ` [PATCH 07/11] CIFS: Separate protocol-specific code from transport routines Pavel Shilovsky
     [not found]     ` <1329895984-9251-8-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-02-28  0:03       ` Steve French
2012-02-22  7:33   ` [PATCH 08/11] CIFS: Separate protocol-specific code from demultiplex code Pavel Shilovsky
2012-02-22  7:33   ` [PATCH 09/11] CIFS: Separate protocol-specific code from cifs_readv_receive code Pavel Shilovsky
2012-02-22  7:33   ` [PATCH 10/11] CIFS: Expand CurrentMid field Pavel Shilovsky
2012-02-22  7:33   ` [PATCH 11/11] CIFS: Change mid_q_entry structure fields Pavel Shilovsky

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.