* [PATCH v2 00/11] Prepare transport code for future SMB2 usage
@ 2012-03-16 15:09 Pavel Shilovsky
[not found] ` <1331910574-998-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
0 siblings, 1 reply; 43+ messages in thread
From: Pavel Shilovsky @ 2012-03-16 15:09 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
The goal of this patchset is to reorganize existing CIFS code 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. Also fix the long-term bug by using negotiated MaxMpxCount
value rather than hardcoded cifs_max_pending.
Pavel Shilovsky (11):
CIFS: Respect negotiated MaxMpxCount
CIFS: Simplify inFlight logic
CIFS: Introduce credit-based flow control
CIFS: Make wait_for_free_request killable
CIFS: Prepare credits code for a slot reservation
CIFS: Delete echo_retries module parm
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 | 13 +--
fs/cifs/cifsglob.h | 79 ++++++++++---
fs/cifs/cifsproto.h | 14 ++-
fs/cifs/cifssmb.c | 106 +++++++++++-------
fs/cifs/connect.c | 118 +++++++++-----------
fs/cifs/dir.c | 6 +-
fs/cifs/file.c | 4 +-
fs/cifs/misc.c | 116 ++++++++++++--------
fs/cifs/netmisc.c | 3 +-
fs/cifs/transport.c | 297 ++++++++++++++++++++++++++++---------------------
13 files changed, 457 insertions(+), 337 deletions(-)
^ permalink raw reply [flat|nested] 43+ messages in thread
* [PATCH v2 01/11] CIFS: Respect negotiated MaxMpxCount
[not found] ` <1331910574-998-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
@ 2012-03-16 15:09 ` Pavel Shilovsky
[not found] ` <1331910574-998-2-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-03-16 15:09 ` [PATCH v2 02/11] CIFS: Simplify inFlight logic Pavel Shilovsky
` (9 subsequent siblings)
10 siblings, 1 reply; 43+ messages in thread
From: Pavel Shilovsky @ 2012-03-16 15:09 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Some servers sets this value less than 50 that was hardcoded and
we lost the connection if when we exceed this limit. Fix this by
respecting this value - not sending more than the server allows.
Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
fs/cifs/cifsfs.c | 8 ++++----
fs/cifs/cifsglob.h | 10 +++-------
fs/cifs/cifssmb.c | 9 +++++++--
fs/cifs/connect.c | 11 ++++-------
fs/cifs/dir.c | 6 ++++--
fs/cifs/file.c | 4 ++--
fs/cifs/transport.c | 4 ++--
7 files changed, 26 insertions(+), 26 deletions(-)
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index b1fd382..6ee1cb4 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -76,7 +76,7 @@ MODULE_PARM_DESC(cifs_min_small, "Small network buffers in pool. Default: 30 "
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");
+ "Default: 32767 Range: 2 to 32767.");
unsigned short echo_retries = 5;
module_param(echo_retries, ushort, 0644);
MODULE_PARM_DESC(echo_retries, "Number of echo attempts before giving up and "
@@ -1116,9 +1116,9 @@ init_cifs(void)
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");
+ } else if (cifs_max_pending > CIFS_MAX_REQ) {
+ cifs_max_pending = CIFS_MAX_REQ;
+ cFYI(1, "cifs_max_pending set to max of %u", CIFS_MAX_REQ);
}
rc = cifs_fscache_register();
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 76e7d8b..d47d20a 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -55,14 +55,9 @@
/*
* 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.
+ * on one socket concurrently.
*/
-#define CIFS_MAX_REQ 50
+#define CIFS_MAX_REQ 32767
#define RFC1001_NAME_LEN 15
#define RFC1001_NAME_LEN_WITH_NULL (RFC1001_NAME_LEN + 1)
@@ -263,6 +258,7 @@ struct TCP_Server_Info {
bool session_estab; /* mark when very first sess is established */
u16 dialect; /* dialect index that server chose */
enum securityEnum secType;
+ bool oplocks:1; /* enable oplocks */
unsigned int maxReq; /* Clients should submit no more */
/* than maxReq distinct unanswered SMBs to the server when using */
/* multiplexed reads or writes */
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 8b7794c..cd66b76 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -458,7 +458,10 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
goto neg_err_exit;
}
server->sec_mode = (__u8)le16_to_cpu(rsp->SecurityMode);
- server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
+ server->maxReq = min_t(unsigned int,
+ le16_to_cpu(rsp->MaxMpxCount),
+ cifs_max_pending);
+ server->oplocks = server->maxReq > 1 ? enable_oplocks : false;
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
@@ -564,7 +567,9 @@ 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);
+ server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
+ cifs_max_pending);
+ server->oplocks = server->maxReq > 1 ? enable_oplocks : false;
/* probably no need to store and check maxvcs */
server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 602f77c..03f71fb 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -642,14 +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(&GlobalMid_Lock);
- if (atomic_read(&server->inFlight) >= cifs_max_pending)
- atomic_set(&server->inFlight, cifs_max_pending - 1);
+ if (atomic_read(&server->inFlight) >= server->maxReq)
+ atomic_set(&server->inFlight, server->maxReq - 1);
/*
* We do not want to set the max_pending too low or we could end up
* with the counter going negative.
@@ -1910,6 +1906,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;
atomic_set(&tcp_ses->inFlight, 0);
+ tcp_ses->maxReq = 1; /* enough to send negotiate request */
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/dir.c b/fs/cifs/dir.c
index bc7e244..d172c8e 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;
@@ -518,6 +518,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
}
pTcon = tlink_tcon(tlink);
+ oplock = pTcon->ses->server->oplocks ? REQ_OPLOCK : 0;
+
/*
* Don't allow the separator character in a path component.
* The VFS will not allow "/", but "\" is allowed by posix.
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 5e64748..4aa6080 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/transport.c b/fs/cifs/transport.c
index 0cc9584..99a27cf 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -265,12 +265,12 @@ static int wait_for_free_request(struct TCP_Server_Info *server,
spin_lock(&GlobalMid_Lock);
while (1) {
- if (atomic_read(&server->inFlight) >= cifs_max_pending) {
+ if (atomic_read(&server->inFlight) >= server->maxReq) {
spin_unlock(&GlobalMid_Lock);
cifs_num_waiters_inc(server);
wait_event(server->request_q,
atomic_read(&server->inFlight)
- < cifs_max_pending);
+ < server->maxReq);
cifs_num_waiters_dec(server);
spin_lock(&GlobalMid_Lock);
} else {
--
1.7.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v2 02/11] CIFS: Simplify inFlight logic
[not found] ` <1331910574-998-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-03-16 15:09 ` [PATCH v2 01/11] CIFS: Respect negotiated MaxMpxCount Pavel Shilovsky
@ 2012-03-16 15:09 ` Pavel Shilovsky
[not found] ` <1331910574-998-3-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-03-16 15:09 ` [PATCH v2 03/11] CIFS: Introduce credit-based flow control Pavel Shilovsky
` (8 subsequent siblings)
10 siblings, 1 reply; 43+ messages in thread
From: Pavel Shilovsky @ 2012-03-16 15:09 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 d47d20a..fb78bc9 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -250,7 +250,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];
@@ -303,6 +304,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 cd66b76..d7cbcfa 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -721,7 +721,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);
}
@@ -1674,7 +1674,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);
}
@@ -2115,7 +2115,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 03f71fb..a7627f2 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -643,14 +643,14 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server)
wake_up_all(&server->response_q);
/* Check if we have blocked requests that need to free. */
- spin_lock(&GlobalMid_Lock);
- if (atomic_read(&server->inFlight) >= server->maxReq)
- atomic_set(&server->inFlight, server->maxReq - 1);
+ spin_lock(&server->req_lock);
+ if (server->in_flight >= server->maxReq)
+ server->in_flight = server->maxReq - 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
@@ -1905,7 +1905,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;
tcp_ses->maxReq = 1; /* enough to send negotiate request */
init_waitqueue_head(&tcp_ses->response_q);
init_waitqueue_head(&tcp_ses->request_q);
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 99a27cf..e2673aa 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) >= server->maxReq) {
- spin_unlock(&GlobalMid_Lock);
+ if (server->in_flight >= server->maxReq) {
+ spin_unlock(&server->req_lock);
cifs_num_waiters_inc(server);
wait_event(server->request_q,
- atomic_read(&server->inFlight)
- < server->maxReq);
+ in_flight(server) < server->maxReq);
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] 43+ messages in thread
* [PATCH v2 03/11] CIFS: Introduce credit-based flow control
[not found] ` <1331910574-998-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-03-16 15:09 ` [PATCH v2 01/11] CIFS: Respect negotiated MaxMpxCount Pavel Shilovsky
2012-03-16 15:09 ` [PATCH v2 02/11] CIFS: Simplify inFlight logic Pavel Shilovsky
@ 2012-03-16 15:09 ` Pavel Shilovsky
[not found] ` <1331910574-998-4-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-03-16 15:09 ` [PATCH v2 04/11] CIFS: Make wait_for_free_request killable Pavel Shilovsky
` (7 subsequent siblings)
10 siblings, 1 reply; 43+ messages in thread
From: Pavel Shilovsky @ 2012-03-16 15:09 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 | 11 +++++++----
fs/cifs/cifsproto.h | 3 +++
fs/cifs/cifssmb.c | 10 +++++-----
fs/cifs/connect.c | 14 ++++++--------
fs/cifs/misc.c | 18 ++++++++++++++++++
fs/cifs/transport.c | 36 ++++++++++++++++++++----------------
6 files changed, 59 insertions(+), 33 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index fb78bc9..d55de96 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -250,8 +250,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];
@@ -314,12 +315,14 @@ in_flight(struct TCP_Server_Info *server)
return num;
}
-static inline void
-dec_in_flight(struct TCP_Server_Info *server)
+static inline bool
+has_credits(struct TCP_Server_Info *server)
{
+ int num;
spin_lock(&server->req_lock);
- server->in_flight--;
+ num = server->credits;
spin_unlock(&server->req_lock);
+ return num > 0;
}
/*
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 6f4e243..47a769e 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -88,6 +88,9 @@ extern int SendReceiveBlockingLock(const unsigned int xid,
struct smb_hdr *in_buf ,
struct smb_hdr *out_buf,
int *bytes_returned);
+extern void cifs_add_credits(struct TCP_Server_Info *server,
+ const unsigned int add);
+extern void cifs_set_credits(struct TCP_Server_Info *server, const int val);
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 *);
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index d7cbcfa..08c84a1 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -461,7 +461,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
server->maxReq = min_t(unsigned int,
le16_to_cpu(rsp->MaxMpxCount),
cifs_max_pending);
- server->oplocks = server->maxReq > 1 ? enable_oplocks : false;
+ cifs_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
@@ -569,7 +569,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
little endian */
server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
cifs_max_pending);
- server->oplocks = server->maxReq > 1 ? enable_oplocks : false;
+ cifs_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);
@@ -721,7 +721,7 @@ cifs_echo_callback(struct mid_q_entry *mid)
struct TCP_Server_Info *server = mid->callback_data;
DeleteMidQEntry(mid);
- dec_in_flight(server);
+ cifs_add_credits(server, 1);
wake_up(&server->request_q);
}
@@ -1674,7 +1674,7 @@ cifs_readv_callback(struct mid_q_entry *mid)
queue_work(system_nrt_wq, &rdata->work);
DeleteMidQEntry(mid);
- dec_in_flight(server);
+ cifs_add_credits(server, 1);
wake_up(&server->request_q);
}
@@ -2115,7 +2115,7 @@ cifs_writev_callback(struct mid_q_entry *mid)
queue_work(system_nrt_wq, &wdata->work);
DeleteMidQEntry(mid);
- dec_in_flight(tcon->ses->server);
+ cifs_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 a7627f2..f3a0c49 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -642,14 +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. */
+ /* check if we have blocked requests that need to free */
spin_lock(&server->req_lock);
- if (server->in_flight >= server->maxReq)
- server->in_flight = server->maxReq - 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
@@ -1906,7 +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->maxReq = 1; /* enough to send negotiate request */
+ tcp_ses->credits = 1;
init_waitqueue_head(&tcp_ses->response_q);
init_waitqueue_head(&tcp_ses->request_q);
INIT_LIST_HEAD(&tcp_ses->pending_mid_q);
@@ -3756,9 +3752,11 @@ int cifs_negotiate_protocol(unsigned int xid, struct cifs_ses *ses)
if (server->maxBuf != 0)
return 0;
+ cifs_set_credits(server, 1);
rc = CIFSSMBNegotiate(xid, ses);
if (rc == -EAGAIN) {
/* retry only once on 1st time connection */
+ cifs_set_credits(server, 1);
rc = CIFSSMBNegotiate(xid, ses);
if (rc == -EAGAIN)
rc = -EHOSTDOWN;
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 703ef5c..5dc936b 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -690,3 +690,21 @@ backup_cred(struct cifs_sb_info *cifs_sb)
return false;
}
+
+void
+cifs_add_credits(struct TCP_Server_Info *server, const unsigned int add)
+{
+ spin_lock(&server->req_lock);
+ server->credits += add;
+ server->in_flight--;
+ spin_unlock(&server->req_lock);
+}
+
+void
+cifs_set_credits(struct TCP_Server_Info *server, const int val)
+{
+ spin_lock(&server->req_lock);
+ server->credits = val;
+ server->oplocks = val > 1 ? enable_oplocks : false;
+ spin_unlock(&server->req_lock);
+}
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index e2673aa..e8a4fd3 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 >= server->maxReq) {
+ if (server->credits <= 0) {
spin_unlock(&server->req_lock);
cifs_num_waiters_inc(server);
- wait_event(server->request_q,
- in_flight(server) < server->maxReq);
+ wait_event(server->request_q, has_credits(server));
cifs_num_waiters_dec(server);
spin_lock(&server->req_lock);
} else {
@@ -280,12 +280,16 @@ wait_for_free_request(struct TCP_Server_Info *server, const int long_op)
return -ENOENT;
}
- /* can not count locking commands against total
- as they are allowed to block on server */
+ /*
+ * 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)
+ if (long_op != CIFS_BLOCKING_OP) {
+ server->credits--;
server->in_flight++;
+ }
spin_unlock(&server->req_lock);
break;
}
@@ -360,7 +364,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);
+ cifs_add_credits(server, 1);
wake_up(&server->request_q);
return -ENOMEM;
}
@@ -393,7 +397,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
return rc;
out_err:
delete_mid(mid);
- dec_in_flight(server);
+ cifs_add_credits(server, 1);
wake_up(&server->request_q);
return rc;
}
@@ -565,7 +569,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);
+ cifs_add_credits(ses->server, 1);
wake_up(&ses->server->request_q);
return rc;
}
@@ -602,7 +606,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);
+ cifs_add_credits(ses->server, 1);
wake_up(&ses->server->request_q);
return rc;
}
@@ -613,7 +617,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);
+ cifs_add_credits(ses->server, 1);
wake_up(&ses->server->request_q);
return rc;
}
@@ -638,7 +642,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
midQ->resp_buf = NULL;
out:
delete_mid(midQ);
- dec_in_flight(ses->server);
+ cifs_add_credits(ses->server, 1);
wake_up(&ses->server->request_q);
return rc;
@@ -689,7 +693,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);
+ cifs_add_credits(ses->server, 1);
wake_up(&ses->server->request_q);
return rc;
}
@@ -722,7 +726,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);
+ cifs_add_credits(ses->server, 1);
wake_up(&ses->server->request_q);
return rc;
}
@@ -731,7 +735,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);
+ cifs_add_credits(ses->server, 1);
wake_up(&ses->server->request_q);
return rc;
}
@@ -748,7 +752,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);
+ cifs_add_credits(ses->server, 1);
wake_up(&ses->server->request_q);
return rc;
--
1.7.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v2 04/11] CIFS: Make wait_for_free_request killable
[not found] ` <1331910574-998-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (2 preceding siblings ...)
2012-03-16 15:09 ` [PATCH v2 03/11] CIFS: Introduce credit-based flow control Pavel Shilovsky
@ 2012-03-16 15:09 ` Pavel Shilovsky
[not found] ` <1331910574-998-5-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-03-16 15:09 ` [PATCH v2 05/11] CIFS: Prepare credits code for a slot reservation Pavel Shilovsky
` (6 subsequent siblings)
10 siblings, 1 reply; 43+ messages in thread
From: Pavel Shilovsky @ 2012-03-16 15:09 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
to let us kill the proccess if it hangs waiting for a credit when
the session is 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 e8a4fd3..11787cc 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, has_credits(server));
+ rc = wait_event_killable(server->request_q,
+ has_credits(server));
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] 43+ messages in thread
* [PATCH v2 05/11] CIFS: Prepare credits code for a slot reservation
[not found] ` <1331910574-998-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (3 preceding siblings ...)
2012-03-16 15:09 ` [PATCH v2 04/11] CIFS: Make wait_for_free_request killable Pavel Shilovsky
@ 2012-03-16 15:09 ` Pavel Shilovsky
[not found] ` <1331910574-998-6-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-03-16 15:09 ` [PATCH v2 06/11] CIFS: Delete echo_retries module parm Pavel Shilovsky
` (5 subsequent siblings)
10 siblings, 1 reply; 43+ messages in thread
From: Pavel Shilovsky @ 2012-03-16 15:09 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
that is essential for CIFS/SMB/SMB2 oplock breaks and SMB2 echos.
Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
fs/cifs/cifsglob.h | 14 ++++++++++++--
fs/cifs/transport.c | 22 ++++++++++++++--------
2 files changed, 26 insertions(+), 10 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index d55de96..2309a67 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -315,12 +315,22 @@ in_flight(struct TCP_Server_Info *server)
return num;
}
+static inline int*
+get_credits_field(struct TCP_Server_Info *server)
+{
+ /*
+ * This will change to switch statement when we reserve slots for echos
+ * and oplock breaks.
+ */
+ return &server->credits;
+}
+
static inline bool
-has_credits(struct TCP_Server_Info *server)
+has_credits(struct TCP_Server_Info *server, int *credits)
{
int num;
spin_lock(&server->req_lock);
- num = server->credits;
+ num = *credits;
spin_unlock(&server->req_lock);
return num > 0;
}
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 11787cc..20dc7ba 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -255,26 +255,26 @@ 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, const int optype,
+ int *credits)
{
int rc;
spin_lock(&server->req_lock);
-
- if (long_op == CIFS_ASYNC_OP) {
+ if (optype == CIFS_ASYNC_OP) {
/* oplock breaks must not be held up */
server->in_flight++;
- server->credits--;
+ *credits -= 1;
spin_unlock(&server->req_lock);
return 0;
}
while (1) {
- if (server->credits <= 0) {
+ if (*credits <= 0) {
spin_unlock(&server->req_lock);
cifs_num_waiters_inc(server);
rc = wait_event_killable(server->request_q,
- has_credits(server));
+ has_credits(server, credits));
cifs_num_waiters_dec(server);
if (rc)
return rc;
@@ -291,8 +291,8 @@ wait_for_free_request(struct TCP_Server_Info *server, const int long_op)
*/
/* update # of requests on the wire to server */
- if (long_op != CIFS_BLOCKING_OP) {
- server->credits--;
+ if (optype != CIFS_BLOCKING_OP) {
+ *credits -= 1;
server->in_flight++;
}
spin_unlock(&server->req_lock);
@@ -302,6 +302,12 @@ wait_for_free_request(struct TCP_Server_Info *server, const int long_op)
return 0;
}
+static int
+wait_for_free_request(struct TCP_Server_Info *server, const int optype)
+{
+ return wait_for_free_credits(server, optype, get_credits_field(server));
+}
+
static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
struct mid_q_entry **ppmidQ)
{
--
1.7.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v2 06/11] CIFS: Delete echo_retries module parm
[not found] ` <1331910574-998-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (4 preceding siblings ...)
2012-03-16 15:09 ` [PATCH v2 05/11] CIFS: Prepare credits code for a slot reservation Pavel Shilovsky
@ 2012-03-16 15:09 ` Pavel Shilovsky
[not found] ` <1331910574-998-7-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-03-16 15:09 ` [PATCH v2 07/11] CIFS: Separate protocol-specific code from transport routines Pavel Shilovsky
` (4 subsequent siblings)
10 siblings, 1 reply; 43+ messages in thread
From: Pavel Shilovsky @ 2012-03-16 15:09 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 during two echo intervals -
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 6ee1cb4..f266161 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: 32767 Range: 2 to 32767.");
-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 2309a67..339ebe3 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -1038,9 +1038,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 f3a0c49..4156351 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 + 2 * SMB_ECHO_INTERVAL)) {
cERROR(1, "Server %s has not responded in %d seconds. "
"Reconnecting...", server->hostname,
- (echo_retries * SMB_ECHO_INTERVAL / HZ));
+ (2 * SMB_ECHO_INTERVAL) / HZ);
cifs_reconnect(server);
wake_up(&server->response_q);
return true;
--
1.7.1
^ permalink raw reply related [flat|nested] 43+ messages in thread
* [PATCH v2 07/11] CIFS: Separate protocol-specific code from transport routines
[not found] ` <1331910574-998-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (5 preceding siblings ...)
2012-03-16 15:09 ` [PATCH v2 06/11] CIFS: Delete echo_retries module parm Pavel Shilovsky
@ 2012-03-16 15:09 ` Pavel Shilovsky
[not found] ` <1331910574-998-8-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-03-16 15:09 ` [PATCH v2 08/11] CIFS: Separate protocol-specific code from demultiplex code Pavel Shilovsky
` (3 subsequent siblings)
10 siblings, 1 reply; 43+ messages in thread
From: Pavel Shilovsky @ 2012-03-16 15:09 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 339ebe3..c3c7d7c 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -230,6 +230,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 47a769e..2d506e3 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 08c84a1..d3b8089 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -696,7 +696,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);
@@ -793,7 +793,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);
@@ -2423,8 +2423,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);
@@ -2591,7 +2590,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) {
@@ -2620,7 +2619,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);
@@ -4628,7 +4627,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);
@@ -5649,7 +5648,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);
}
@@ -5718,7 +5717,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);
@@ -5777,7 +5776,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);
@@ -6009,7 +6008,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 5dc936b..1578617 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 20dc7ba..7f63c44 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;
}
@@ -349,6 +348,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
@@ -361,34 +387,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, ignore_pend ? CIFS_ASYNC_OP : 0);
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);
cifs_add_credits(server, 1);
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;
@@ -424,14 +434,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);
@@ -514,7 +524,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));
@@ -534,6 +544,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 */,
@@ -542,54 +570,52 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
int rc = 0;
int long_op;
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;
*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, long_op);
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 */
cifs_add_credits(ses->server, 1);
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);
@@ -600,23 +626,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);
cifs_add_credits(ses->server, 1);
wake_up(&ses->server->request_q);
return rc;
@@ -624,7 +650,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) {
@@ -639,8 +665,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] 43+ messages in thread
* [PATCH v2 08/11] CIFS: Separate protocol-specific code from demultiplex code
[not found] ` <1331910574-998-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (6 preceding siblings ...)
2012-03-16 15:09 ` [PATCH v2 07/11] CIFS: Separate protocol-specific code from transport routines Pavel Shilovsky
@ 2012-03-16 15:09 ` Pavel Shilovsky
[not found] ` <1331910574-998-9-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-03-16 15:09 ` [PATCH v2 09/11] CIFS: Separate protocol-specific code from cifs_readv_receive code Pavel Shilovsky
` (2 subsequent siblings)
10 siblings, 1 reply; 43+ messages in thread
From: Pavel Shilovsky @ 2012-03-16 15:09 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 c3c7d7c..34a897e 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -730,7 +730,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 2d506e3..15c9b59 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -91,9 +91,8 @@ extern int SendReceiveBlockingLock(const unsigned int xid,
extern void cifs_add_credits(struct TCP_Server_Info *server,
const unsigned int add);
extern void cifs_set_credits(struct TCP_Server_Info *server, const int val);
-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 4156351..76cffc9 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 1578617..88459d0 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 7f63c44..d4c01b9 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -785,7 +785,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:
@@ -953,7 +953,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] 43+ messages in thread
* [PATCH v2 09/11] CIFS: Separate protocol-specific code from cifs_readv_receive code
[not found] ` <1331910574-998-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (7 preceding siblings ...)
2012-03-16 15:09 ` [PATCH v2 08/11] CIFS: Separate protocol-specific code from demultiplex code Pavel Shilovsky
@ 2012-03-16 15:09 ` Pavel Shilovsky
[not found] ` <1331910574-998-10-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-03-16 15:09 ` [PATCH v2 10/11] CIFS: Expand CurrentMid field Pavel Shilovsky
2012-03-16 15:09 ` [PATCH v2 11/11] CIFS: Change mid_q_entry structure fields Pavel Shilovsky
10 siblings, 1 reply; 43+ messages in thread
From: Pavel Shilovsky @ 2012-03-16 15:09 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 34a897e..a403398 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -341,6 +341,18 @@ has_credits(struct TCP_Server_Info *server, int *credits)
return num > 0;
}
+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 15c9b59..db38a40 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -106,7 +106,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 d3b8089..765f804 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1415,8 +1415,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;
@@ -1425,7 +1424,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;
@@ -1436,14 +1435,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;
@@ -1456,10 +1476,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);
@@ -1468,7 +1487,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);
@@ -1476,14 +1495,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
@@ -1507,7 +1526,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)
@@ -1516,15 +1535,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);
@@ -1603,11 +1621,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 76cffc9..3d46493 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] 43+ messages in thread
* [PATCH v2 10/11] CIFS: Expand CurrentMid field
[not found] ` <1331910574-998-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (8 preceding siblings ...)
2012-03-16 15:09 ` [PATCH v2 09/11] CIFS: Separate protocol-specific code from cifs_readv_receive code Pavel Shilovsky
@ 2012-03-16 15:09 ` Pavel Shilovsky
[not found] ` <1331910574-998-11-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-03-16 15:09 ` [PATCH v2 11/11] CIFS: Change mid_q_entry structure fields Pavel Shilovsky
10 siblings, 1 reply; 43+ messages in thread
From: Pavel Shilovsky @ 2012-03-16 15:09 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 a403398..b213458 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -282,7 +282,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 db38a40..8958721 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -115,7 +115,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 88459d0..0b743b7 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] 43+ messages in thread
* [PATCH v2 11/11] CIFS: Change mid_q_entry structure fields
[not found] ` <1331910574-998-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
` (9 preceding siblings ...)
2012-03-16 15:09 ` [PATCH v2 10/11] CIFS: Expand CurrentMid field Pavel Shilovsky
@ 2012-03-16 15:09 ` Pavel Shilovsky
[not found] ` <1331910574-998-12-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
10 siblings, 1 reply; 43+ messages in thread
From: Pavel Shilovsky @ 2012-03-16 15:09 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 b213458..d5ccd46 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -731,8 +731,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
@@ -743,9 +743,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 765f804..2dbf7db 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1468,7 +1468,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);
/*
@@ -1666,10 +1666,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 &
@@ -2088,7 +2088,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
@@ -2099,7 +2099,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 3d46493..3bd4e77 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 0b743b7..5313d37 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 d4c01b9..751404f 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,
@@ -341,7 +341,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;
@@ -404,7 +404,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);
@@ -454,11 +454,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;
@@ -473,8 +473,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);
@@ -617,7 +617,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);
@@ -639,7 +639,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);
@@ -659,7 +659,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;
@@ -668,7 +668,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;
@@ -742,7 +742,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));
@@ -760,7 +760,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);
@@ -779,7 +779,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;
@@ -879,7 +879,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);
@@ -893,13 +893,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))) {
@@ -929,7 +929,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);
@@ -947,7 +947,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
return rc;
/* 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] 43+ messages in thread
* Re: [PATCH v2 03/11] CIFS: Introduce credit-based flow control
[not found] ` <1331910574-998-4-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
@ 2012-03-17 10:32 ` Jeff Layton
[not found] ` <20120317063258.77618c0e-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
0 siblings, 1 reply; 43+ messages in thread
From: Jeff Layton @ 2012-03-17 10:32 UTC (permalink / raw)
To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA
On Fri, 16 Mar 2012 18:09:26 +0300
Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> 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.
>
The existing code essentially "hardcodes" a value of 50 instead of
using maxReq. While I think that's wrong, if you change that behavior
in the first patch, it's going to make tracking down any regressions
from this very difficult.
I think it might be better to have this series introduce no behavioral
changes at all, and simply reorganize the code around a credit-based
model. Once that's complete and working, then do a patch that makes the
code respect maxReq.
I know that that's more work, but we do need to be careful when we're
tinkering with the low-level plumbing like this...
> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
> ---
> fs/cifs/cifsglob.h | 11 +++++++----
> fs/cifs/cifsproto.h | 3 +++
> fs/cifs/cifssmb.c | 10 +++++-----
> fs/cifs/connect.c | 14 ++++++--------
> fs/cifs/misc.c | 18 ++++++++++++++++++
> fs/cifs/transport.c | 36 ++++++++++++++++++++----------------
> 6 files changed, 59 insertions(+), 33 deletions(-)
>
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index fb78bc9..d55de96 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -250,8 +250,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];
> @@ -314,12 +315,14 @@ in_flight(struct TCP_Server_Info *server)
> return num;
> }
>
> -static inline void
> -dec_in_flight(struct TCP_Server_Info *server)
> +static inline bool
> +has_credits(struct TCP_Server_Info *server)
> {
> + int num;
> spin_lock(&server->req_lock);
> - server->in_flight--;
> + num = server->credits;
> spin_unlock(&server->req_lock);
> + return num > 0;
> }
>
> /*
> diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
> index 6f4e243..47a769e 100644
> --- a/fs/cifs/cifsproto.h
> +++ b/fs/cifs/cifsproto.h
> @@ -88,6 +88,9 @@ extern int SendReceiveBlockingLock(const unsigned int xid,
> struct smb_hdr *in_buf ,
> struct smb_hdr *out_buf,
> int *bytes_returned);
> +extern void cifs_add_credits(struct TCP_Server_Info *server,
> + const unsigned int add);
> +extern void cifs_set_credits(struct TCP_Server_Info *server, const int val);
> 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 *);
> diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
> index d7cbcfa..08c84a1 100644
> --- a/fs/cifs/cifssmb.c
> +++ b/fs/cifs/cifssmb.c
> @@ -461,7 +461,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
> server->maxReq = min_t(unsigned int,
> le16_to_cpu(rsp->MaxMpxCount),
> cifs_max_pending);
> - server->oplocks = server->maxReq > 1 ? enable_oplocks : false;
> + cifs_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
> @@ -569,7 +569,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
> little endian */
> server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
> cifs_max_pending);
> - server->oplocks = server->maxReq > 1 ? enable_oplocks : false;
> + cifs_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);
> @@ -721,7 +721,7 @@ cifs_echo_callback(struct mid_q_entry *mid)
> struct TCP_Server_Info *server = mid->callback_data;
>
> DeleteMidQEntry(mid);
> - dec_in_flight(server);
> + cifs_add_credits(server, 1);
> wake_up(&server->request_q);
^^^^^^^^^
The above wake_up always follows the call to cifs_add_credits. Should
you go ahead and move it inside of cifs_add_credits?
> }
>
> @@ -1674,7 +1674,7 @@ cifs_readv_callback(struct mid_q_entry *mid)
>
> queue_work(system_nrt_wq, &rdata->work);
> DeleteMidQEntry(mid);
> - dec_in_flight(server);
> + cifs_add_credits(server, 1);
> wake_up(&server->request_q);
> }
>
> @@ -2115,7 +2115,7 @@ cifs_writev_callback(struct mid_q_entry *mid)
>
> queue_work(system_nrt_wq, &wdata->work);
> DeleteMidQEntry(mid);
> - dec_in_flight(tcon->ses->server);
> + cifs_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 a7627f2..f3a0c49 100644
> --- a/fs/cifs/connect.c
> +++ b/fs/cifs/connect.c
> @@ -642,14 +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. */
> + /* check if we have blocked requests that need to free */
> spin_lock(&server->req_lock);
> - if (server->in_flight >= server->maxReq)
> - server->in_flight = server->maxReq - 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
> @@ -1906,7 +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->maxReq = 1; /* enough to send negotiate request */
> + tcp_ses->credits = 1;
> init_waitqueue_head(&tcp_ses->response_q);
> init_waitqueue_head(&tcp_ses->request_q);
> INIT_LIST_HEAD(&tcp_ses->pending_mid_q);
> @@ -3756,9 +3752,11 @@ int cifs_negotiate_protocol(unsigned int xid, struct cifs_ses *ses)
> if (server->maxBuf != 0)
> return 0;
>
> + cifs_set_credits(server, 1);
> rc = CIFSSMBNegotiate(xid, ses);
> if (rc == -EAGAIN) {
> /* retry only once on 1st time connection */
> + cifs_set_credits(server, 1);
> rc = CIFSSMBNegotiate(xid, ses);
> if (rc == -EAGAIN)
> rc = -EHOSTDOWN;
> diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
> index 703ef5c..5dc936b 100644
> --- a/fs/cifs/misc.c
> +++ b/fs/cifs/misc.c
> @@ -690,3 +690,21 @@ backup_cred(struct cifs_sb_info *cifs_sb)
>
> return false;
> }
> +
> +void
> +cifs_add_credits(struct TCP_Server_Info *server, const unsigned int add)
> +{
> + spin_lock(&server->req_lock);
> + server->credits += add;
> + server->in_flight--;
> + spin_unlock(&server->req_lock);
> +}
> +
> +void
> +cifs_set_credits(struct TCP_Server_Info *server, const int val)
> +{
> + spin_lock(&server->req_lock);
> + server->credits = val;
> + server->oplocks = val > 1 ? enable_oplocks : false;
> + spin_unlock(&server->req_lock);
> +}
> diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
> index e2673aa..e8a4fd3 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 >= server->maxReq) {
> + if (server->credits <= 0) {
> spin_unlock(&server->req_lock);
> cifs_num_waiters_inc(server);
> - wait_event(server->request_q,
> - in_flight(server) < server->maxReq);
> + wait_event(server->request_q, has_credits(server));
> cifs_num_waiters_dec(server);
> spin_lock(&server->req_lock);
> } else {
> @@ -280,12 +280,16 @@ wait_for_free_request(struct TCP_Server_Info *server, const int long_op)
> return -ENOENT;
> }
>
> - /* can not count locking commands against total
> - as they are allowed to block on server */
> + /*
> + * 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)
> + if (long_op != CIFS_BLOCKING_OP) {
> + server->credits--;
> server->in_flight++;
> + }
> spin_unlock(&server->req_lock);
> break;
> }
> @@ -360,7 +364,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);
> + cifs_add_credits(server, 1);
> wake_up(&server->request_q);
> return -ENOMEM;
> }
> @@ -393,7 +397,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
> return rc;
> out_err:
> delete_mid(mid);
> - dec_in_flight(server);
> + cifs_add_credits(server, 1);
> wake_up(&server->request_q);
> return rc;
> }
> @@ -565,7 +569,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);
> + cifs_add_credits(ses->server, 1);
> wake_up(&ses->server->request_q);
> return rc;
> }
> @@ -602,7 +606,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);
> + cifs_add_credits(ses->server, 1);
> wake_up(&ses->server->request_q);
> return rc;
> }
> @@ -613,7 +617,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);
> + cifs_add_credits(ses->server, 1);
> wake_up(&ses->server->request_q);
> return rc;
> }
> @@ -638,7 +642,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
> midQ->resp_buf = NULL;
> out:
> delete_mid(midQ);
> - dec_in_flight(ses->server);
> + cifs_add_credits(ses->server, 1);
> wake_up(&ses->server->request_q);
>
> return rc;
> @@ -689,7 +693,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);
> + cifs_add_credits(ses->server, 1);
> wake_up(&ses->server->request_q);
> return rc;
> }
> @@ -722,7 +726,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);
> + cifs_add_credits(ses->server, 1);
> wake_up(&ses->server->request_q);
> return rc;
> }
> @@ -731,7 +735,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);
> + cifs_add_credits(ses->server, 1);
> wake_up(&ses->server->request_q);
> return rc;
> }
> @@ -748,7 +752,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);
> + cifs_add_credits(ses->server, 1);
> wake_up(&ses->server->request_q);
>
> return rc;
--
Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH v2 02/11] CIFS: Simplify inFlight logic
[not found] ` <1331910574-998-3-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
@ 2012-03-17 11:07 ` Jeff Layton
0 siblings, 0 replies; 43+ messages in thread
From: Jeff Layton @ 2012-03-17 11:07 UTC (permalink / raw)
To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA
On Fri, 16 Mar 2012 18:09:25 +0300
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 d47d20a..fb78bc9 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -250,7 +250,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];
> @@ -303,6 +304,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 cd66b76..d7cbcfa 100644
> --- a/fs/cifs/cifssmb.c
> +++ b/fs/cifs/cifssmb.c
> @@ -721,7 +721,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);
> }
>
> @@ -1674,7 +1674,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);
> }
>
> @@ -2115,7 +2115,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 03f71fb..a7627f2 100644
> --- a/fs/cifs/connect.c
> +++ b/fs/cifs/connect.c
> @@ -643,14 +643,14 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server)
> wake_up_all(&server->response_q);
>
> /* Check if we have blocked requests that need to free. */
> - spin_lock(&GlobalMid_Lock);
> - if (atomic_read(&server->inFlight) >= server->maxReq)
> - atomic_set(&server->inFlight, server->maxReq - 1);
> + spin_lock(&server->req_lock);
> + if (server->in_flight >= server->maxReq)
> + server->in_flight = server->maxReq - 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
> @@ -1905,7 +1905,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;
> tcp_ses->maxReq = 1; /* enough to send negotiate request */
> init_waitqueue_head(&tcp_ses->response_q);
> init_waitqueue_head(&tcp_ses->request_q);
> diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
> index 99a27cf..e2673aa 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) >= server->maxReq) {
> - spin_unlock(&GlobalMid_Lock);
> + if (server->in_flight >= server->maxReq) {
> + spin_unlock(&server->req_lock);
> cifs_num_waiters_inc(server);
> wait_event(server->request_q,
> - atomic_read(&server->inFlight)
> - < server->maxReq);
> + in_flight(server) < server->maxReq);
> 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;
Looks reasonable. It might be a little slower with the extra locking,
but it shouldn't make much difference as this is not a terribly hot
codepath. This also makes the locking very clear.
Reviewed-by: Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH v2 01/11] CIFS: Respect negotiated MaxMpxCount
[not found] ` <1331910574-998-2-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
@ 2012-03-17 11:12 ` Jeff Layton
[not found] ` <20120317071201.7f28683b-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
0 siblings, 1 reply; 43+ messages in thread
From: Jeff Layton @ 2012-03-17 11:12 UTC (permalink / raw)
To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA
On Fri, 16 Mar 2012 18:09:24 +0300
Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> Some servers sets this value less than 50 that was hardcoded and
> we lost the connection if when we exceed this limit. Fix this by
> respecting this value - not sending more than the server allows.
>
> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
> ---
> fs/cifs/cifsfs.c | 8 ++++----
> fs/cifs/cifsglob.h | 10 +++-------
> fs/cifs/cifssmb.c | 9 +++++++--
> fs/cifs/connect.c | 11 ++++-------
> fs/cifs/dir.c | 6 ++++--
> fs/cifs/file.c | 4 ++--
> fs/cifs/transport.c | 4 ++--
> 7 files changed, 26 insertions(+), 26 deletions(-)
>
> diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
> index b1fd382..6ee1cb4 100644
> --- a/fs/cifs/cifsfs.c
> +++ b/fs/cifs/cifsfs.c
> @@ -76,7 +76,7 @@ MODULE_PARM_DESC(cifs_min_small, "Small network buffers in pool. Default: 30 "
> 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");
> + "Default: 32767 Range: 2 to 32767.");
> unsigned short echo_retries = 5;
> module_param(echo_retries, ushort, 0644);
> MODULE_PARM_DESC(echo_retries, "Number of echo attempts before giving up and "
> @@ -1116,9 +1116,9 @@ init_cifs(void)
> 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");
> + } else if (cifs_max_pending > CIFS_MAX_REQ) {
> + cifs_max_pending = CIFS_MAX_REQ;
> + cFYI(1, "cifs_max_pending set to max of %u", CIFS_MAX_REQ);
> }
>
> rc = cifs_fscache_register();
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index 76e7d8b..d47d20a 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -55,14 +55,9 @@
>
> /*
> * 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.
> + * on one socket concurrently.
> */
> -#define CIFS_MAX_REQ 50
> +#define CIFS_MAX_REQ 32767
>
> #define RFC1001_NAME_LEN 15
> #define RFC1001_NAME_LEN_WITH_NULL (RFC1001_NAME_LEN + 1)
> @@ -263,6 +258,7 @@ struct TCP_Server_Info {
> bool session_estab; /* mark when very first sess is established */
> u16 dialect; /* dialect index that server chose */
> enum securityEnum secType;
> + bool oplocks:1; /* enable oplocks */
> unsigned int maxReq; /* Clients should submit no more */
> /* than maxReq distinct unanswered SMBs to the server when using */
> /* multiplexed reads or writes */
> diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
> index 8b7794c..cd66b76 100644
> --- a/fs/cifs/cifssmb.c
> +++ b/fs/cifs/cifssmb.c
> @@ -458,7 +458,10 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
> goto neg_err_exit;
> }
> server->sec_mode = (__u8)le16_to_cpu(rsp->SecurityMode);
> - server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
> + server->maxReq = min_t(unsigned int,
> + le16_to_cpu(rsp->MaxMpxCount),
> + cifs_max_pending);
> + server->oplocks = server->maxReq > 1 ? enable_oplocks : false;
> 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
> @@ -564,7 +567,9 @@ 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);
> + server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
> + cifs_max_pending);
> + server->oplocks = server->maxReq > 1 ? enable_oplocks : false;
> /* probably no need to store and check maxvcs */
> server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
> server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
> index 602f77c..03f71fb 100644
> --- a/fs/cifs/connect.c
> +++ b/fs/cifs/connect.c
> @@ -642,14 +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(&GlobalMid_Lock);
> - if (atomic_read(&server->inFlight) >= cifs_max_pending)
> - atomic_set(&server->inFlight, cifs_max_pending - 1);
> + if (atomic_read(&server->inFlight) >= server->maxReq)
> + atomic_set(&server->inFlight, server->maxReq - 1);
> /*
> * We do not want to set the max_pending too low or we could end up
> * with the counter going negative.
> @@ -1910,6 +1906,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;
> atomic_set(&tcp_ses->inFlight, 0);
> + tcp_ses->maxReq = 1; /* enough to send negotiate request */
> 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/dir.c b/fs/cifs/dir.c
> index bc7e244..d172c8e 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;
> @@ -518,6 +518,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
> }
> pTcon = tlink_tcon(tlink);
>
> + oplock = pTcon->ses->server->oplocks ? REQ_OPLOCK : 0;
> +
> /*
> * Don't allow the separator character in a path component.
> * The VFS will not allow "/", but "\" is allowed by posix.
> diff --git a/fs/cifs/file.c b/fs/cifs/file.c
> index 5e64748..4aa6080 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/transport.c b/fs/cifs/transport.c
> index 0cc9584..99a27cf 100644
> --- a/fs/cifs/transport.c
> +++ b/fs/cifs/transport.c
> @@ -265,12 +265,12 @@ static int wait_for_free_request(struct TCP_Server_Info *server,
>
> spin_lock(&GlobalMid_Lock);
> while (1) {
> - if (atomic_read(&server->inFlight) >= cifs_max_pending) {
> + if (atomic_read(&server->inFlight) >= server->maxReq) {
> spin_unlock(&GlobalMid_Lock);
> cifs_num_waiters_inc(server);
> wait_event(server->request_q,
> atomic_read(&server->inFlight)
> - < cifs_max_pending);
> + < server->maxReq);
> cifs_num_waiters_dec(server);
> spin_lock(&GlobalMid_Lock);
> } else {
Sorry, I probably should have made my earlier comment against this
email. If there are regressions from this series, they are likely going
to be quite difficult to track down. We need to ensure that we do this
in a way that makes that possible.
Introducing a behavior change like this at the beginning of the series
is probably a mistake. You'll have no reasonable way to bisect down
regressions, so you won't know if a problem is due to the change to a
credit-based model or due to changing the client to respect the maxmpx.
Instead of doing this, we should instead reorganize the code around a
credit based model first, while attempting to mimic the existing
behavior as closely as possible. Once that framework is in place, then
change the behavior and start respecting the maxmpx.
If you do that, then someone can reasonably bisect between those two
changes and we can determine the source of a regression.
--
Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH v2 04/11] CIFS: Make wait_for_free_request killable
[not found] ` <1331910574-998-5-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
@ 2012-03-17 11:13 ` Jeff Layton
0 siblings, 0 replies; 43+ messages in thread
From: Jeff Layton @ 2012-03-17 11:13 UTC (permalink / raw)
To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA
On Fri, 16 Mar 2012 18:09:27 +0300
Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> to let us kill the proccess if it hangs waiting for a credit when
> the session is 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 e8a4fd3..11787cc 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, has_credits(server));
> + rc = wait_event_killable(server->request_q,
> + has_credits(server));
> cifs_num_waiters_dec(server);
> + if (rc)
> + return rc;
> spin_lock(&server->req_lock);
> } else {
> if (server->tcpStatus == CifsExiting) {
Reviewed-by: Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH v2 01/11] CIFS: Respect negotiated MaxMpxCount
[not found] ` <20120317071201.7f28683b-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
@ 2012-03-17 14:53 ` Pavel Shilovsky
[not found] ` <CAKywueTDsGhcHiGM_uX6V0dnY3m_W4kD2qcb+JWRq=UVnBnvPw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
0 siblings, 1 reply; 43+ messages in thread
From: Pavel Shilovsky @ 2012-03-17 14:53 UTC (permalink / raw)
To: Jeff Layton, Steve French; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA
17 марта 2012 г. 15:12 пользователь Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> написал:
> On Fri, 16 Mar 2012 18:09:24 +0300
> Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
>
>> Some servers sets this value less than 50 that was hardcoded and
>> we lost the connection if when we exceed this limit. Fix this by
>> respecting this value - not sending more than the server allows.
>>
>> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
>> ---
>> fs/cifs/cifsfs.c | 8 ++++----
>> fs/cifs/cifsglob.h | 10 +++-------
>> fs/cifs/cifssmb.c | 9 +++++++--
>> fs/cifs/connect.c | 11 ++++-------
>> fs/cifs/dir.c | 6 ++++--
>> fs/cifs/file.c | 4 ++--
>> fs/cifs/transport.c | 4 ++--
>> 7 files changed, 26 insertions(+), 26 deletions(-)
>>
>> diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
>> index b1fd382..6ee1cb4 100644
>> --- a/fs/cifs/cifsfs.c
>> +++ b/fs/cifs/cifsfs.c
>> @@ -76,7 +76,7 @@ MODULE_PARM_DESC(cifs_min_small, "Small network buffers in pool. Default: 30 "
>> 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");
>> + "Default: 32767 Range: 2 to 32767.");
>> unsigned short echo_retries = 5;
>> module_param(echo_retries, ushort, 0644);
>> MODULE_PARM_DESC(echo_retries, "Number of echo attempts before giving up and "
>> @@ -1116,9 +1116,9 @@ init_cifs(void)
>> 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");
>> + } else if (cifs_max_pending > CIFS_MAX_REQ) {
>> + cifs_max_pending = CIFS_MAX_REQ;
>> + cFYI(1, "cifs_max_pending set to max of %u", CIFS_MAX_REQ);
>> }
>>
>> rc = cifs_fscache_register();
>> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
>> index 76e7d8b..d47d20a 100644
>> --- a/fs/cifs/cifsglob.h
>> +++ b/fs/cifs/cifsglob.h
>> @@ -55,14 +55,9 @@
>>
>> /*
>> * 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.
>> + * on one socket concurrently.
>> */
>> -#define CIFS_MAX_REQ 50
>> +#define CIFS_MAX_REQ 32767
>>
>> #define RFC1001_NAME_LEN 15
>> #define RFC1001_NAME_LEN_WITH_NULL (RFC1001_NAME_LEN + 1)
>> @@ -263,6 +258,7 @@ struct TCP_Server_Info {
>> bool session_estab; /* mark when very first sess is established */
>> u16 dialect; /* dialect index that server chose */
>> enum securityEnum secType;
>> + bool oplocks:1; /* enable oplocks */
>> unsigned int maxReq; /* Clients should submit no more */
>> /* than maxReq distinct unanswered SMBs to the server when using */
>> /* multiplexed reads or writes */
>> diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
>> index 8b7794c..cd66b76 100644
>> --- a/fs/cifs/cifssmb.c
>> +++ b/fs/cifs/cifssmb.c
>> @@ -458,7 +458,10 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
>> goto neg_err_exit;
>> }
>> server->sec_mode = (__u8)le16_to_cpu(rsp->SecurityMode);
>> - server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
>> + server->maxReq = min_t(unsigned int,
>> + le16_to_cpu(rsp->MaxMpxCount),
>> + cifs_max_pending);
>> + server->oplocks = server->maxReq > 1 ? enable_oplocks : false;
>> 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
>> @@ -564,7 +567,9 @@ 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);
>> + server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
>> + cifs_max_pending);
>> + server->oplocks = server->maxReq > 1 ? enable_oplocks : false;
>> /* probably no need to store and check maxvcs */
>> server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
>> server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
>> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
>> index 602f77c..03f71fb 100644
>> --- a/fs/cifs/connect.c
>> +++ b/fs/cifs/connect.c
>> @@ -642,14 +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(&GlobalMid_Lock);
>> - if (atomic_read(&server->inFlight) >= cifs_max_pending)
>> - atomic_set(&server->inFlight, cifs_max_pending - 1);
>> + if (atomic_read(&server->inFlight) >= server->maxReq)
>> + atomic_set(&server->inFlight, server->maxReq - 1);
>> /*
>> * We do not want to set the max_pending too low or we could end up
>> * with the counter going negative.
>> @@ -1910,6 +1906,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;
>> atomic_set(&tcp_ses->inFlight, 0);
>> + tcp_ses->maxReq = 1; /* enough to send negotiate request */
>> 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/dir.c b/fs/cifs/dir.c
>> index bc7e244..d172c8e 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;
>> @@ -518,6 +518,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
>> }
>> pTcon = tlink_tcon(tlink);
>>
>> + oplock = pTcon->ses->server->oplocks ? REQ_OPLOCK : 0;
>> +
>> /*
>> * Don't allow the separator character in a path component.
>> * The VFS will not allow "/", but "\" is allowed by posix.
>> diff --git a/fs/cifs/file.c b/fs/cifs/file.c
>> index 5e64748..4aa6080 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/transport.c b/fs/cifs/transport.c
>> index 0cc9584..99a27cf 100644
>> --- a/fs/cifs/transport.c
>> +++ b/fs/cifs/transport.c
>> @@ -265,12 +265,12 @@ static int wait_for_free_request(struct TCP_Server_Info *server,
>>
>> spin_lock(&GlobalMid_Lock);
>> while (1) {
>> - if (atomic_read(&server->inFlight) >= cifs_max_pending) {
>> + if (atomic_read(&server->inFlight) >= server->maxReq) {
>> spin_unlock(&GlobalMid_Lock);
>> cifs_num_waiters_inc(server);
>> wait_event(server->request_q,
>> atomic_read(&server->inFlight)
>> - < cifs_max_pending);
>> + < server->maxReq);
>> cifs_num_waiters_dec(server);
>> spin_lock(&GlobalMid_Lock);
>> } else {
>
> Sorry, I probably should have made my earlier comment against this
> email. If there are regressions from this series, they are likely going
> to be quite difficult to track down. We need to ensure that we do this
> in a way that makes that possible.
>
> Introducing a behavior change like this at the beginning of the series
> is probably a mistake. You'll have no reasonable way to bisect down
> regressions, so you won't know if a problem is due to the change to a
> credit-based model or due to changing the client to respect the maxmpx.
>
> Instead of doing this, we should instead reorganize the code around a
> credit based model first, while attempting to mimic the existing
> behavior as closely as possible. Once that framework is in place, then
> change the behavior and start respecting the maxmpx.
>
> If you do that, then someone can reasonably bisect between those two
> changes and we can determine the source of a regression.
> --
> Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
This was done to push this patch to 3.3 and stable tree as well.
That's why it is in the start of series.
If we decide not to push it for now, I agree that this patch should be
in the modified version (according to changes from other patches) at
the end of the series.
Steve, your thoughts?
--
Best regards,
Pavel Shilovsky.
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH v2 03/11] CIFS: Introduce credit-based flow control
[not found] ` <20120317063258.77618c0e-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
@ 2012-03-17 14:56 ` Pavel Shilovsky
0 siblings, 0 replies; 43+ messages in thread
From: Pavel Shilovsky @ 2012-03-17 14:56 UTC (permalink / raw)
To: Jeff Layton; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA
17 марта 2012 г. 14:32 пользователь Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> написал:
> On Fri, 16 Mar 2012 18:09:26 +0300
> Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
>
>> 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.
>>
>
> The existing code essentially "hardcodes" a value of 50 instead of
> using maxReq. While I think that's wrong, if you change that behavior
> in the first patch, it's going to make tracking down any regressions
> from this very difficult.
>
> I think it might be better to have this series introduce no behavioral
> changes at all, and simply reorganize the code around a credit-based
> model. Once that's complete and working, then do a patch that makes the
> code respect maxReq.
>
> I know that that's more work, but we do need to be careful when we're
> tinkering with the low-level plumbing like this...
>
>> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
>> ---
>> fs/cifs/cifsglob.h | 11 +++++++----
>> fs/cifs/cifsproto.h | 3 +++
>> fs/cifs/cifssmb.c | 10 +++++-----
>> fs/cifs/connect.c | 14 ++++++--------
>> fs/cifs/misc.c | 18 ++++++++++++++++++
>> fs/cifs/transport.c | 36 ++++++++++++++++++++----------------
>> 6 files changed, 59 insertions(+), 33 deletions(-)
>>
>> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
>> index fb78bc9..d55de96 100644
>> --- a/fs/cifs/cifsglob.h
>> +++ b/fs/cifs/cifsglob.h
>> @@ -250,8 +250,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];
>> @@ -314,12 +315,14 @@ in_flight(struct TCP_Server_Info *server)
>> return num;
>> }
>>
>> -static inline void
>> -dec_in_flight(struct TCP_Server_Info *server)
>> +static inline bool
>> +has_credits(struct TCP_Server_Info *server)
>> {
>> + int num;
>> spin_lock(&server->req_lock);
>> - server->in_flight--;
>> + num = server->credits;
>> spin_unlock(&server->req_lock);
>> + return num > 0;
>> }
>>
>> /*
>> diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
>> index 6f4e243..47a769e 100644
>> --- a/fs/cifs/cifsproto.h
>> +++ b/fs/cifs/cifsproto.h
>> @@ -88,6 +88,9 @@ extern int SendReceiveBlockingLock(const unsigned int xid,
>> struct smb_hdr *in_buf ,
>> struct smb_hdr *out_buf,
>> int *bytes_returned);
>> +extern void cifs_add_credits(struct TCP_Server_Info *server,
>> + const unsigned int add);
>> +extern void cifs_set_credits(struct TCP_Server_Info *server, const int val);
>> 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 *);
>> diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
>> index d7cbcfa..08c84a1 100644
>> --- a/fs/cifs/cifssmb.c
>> +++ b/fs/cifs/cifssmb.c
>> @@ -461,7 +461,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
>> server->maxReq = min_t(unsigned int,
>> le16_to_cpu(rsp->MaxMpxCount),
>> cifs_max_pending);
>> - server->oplocks = server->maxReq > 1 ? enable_oplocks : false;
>> + cifs_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
>> @@ -569,7 +569,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
>> little endian */
>> server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
>> cifs_max_pending);
>> - server->oplocks = server->maxReq > 1 ? enable_oplocks : false;
>> + cifs_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);
>> @@ -721,7 +721,7 @@ cifs_echo_callback(struct mid_q_entry *mid)
>> struct TCP_Server_Info *server = mid->callback_data;
>>
>> DeleteMidQEntry(mid);
>> - dec_in_flight(server);
>> + cifs_add_credits(server, 1);
>> wake_up(&server->request_q);
> ^^^^^^^^^
>
> The above wake_up always follows the call to cifs_add_credits. Should
> you go ahead and move it inside of cifs_add_credits?
That makes sense - will fix it when we decide what to do with the first patch.
>
>
>> }
>>
>> @@ -1674,7 +1674,7 @@ cifs_readv_callback(struct mid_q_entry *mid)
>>
>> queue_work(system_nrt_wq, &rdata->work);
>> DeleteMidQEntry(mid);
>> - dec_in_flight(server);
>> + cifs_add_credits(server, 1);
>> wake_up(&server->request_q);
>> }
>>
>> @@ -2115,7 +2115,7 @@ cifs_writev_callback(struct mid_q_entry *mid)
>>
>> queue_work(system_nrt_wq, &wdata->work);
>> DeleteMidQEntry(mid);
>> - dec_in_flight(tcon->ses->server);
>> + cifs_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 a7627f2..f3a0c49 100644
>> --- a/fs/cifs/connect.c
>> +++ b/fs/cifs/connect.c
>> @@ -642,14 +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. */
>> + /* check if we have blocked requests that need to free */
>> spin_lock(&server->req_lock);
>> - if (server->in_flight >= server->maxReq)
>> - server->in_flight = server->maxReq - 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
>> @@ -1906,7 +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->maxReq = 1; /* enough to send negotiate request */
>> + tcp_ses->credits = 1;
>> init_waitqueue_head(&tcp_ses->response_q);
>> init_waitqueue_head(&tcp_ses->request_q);
>> INIT_LIST_HEAD(&tcp_ses->pending_mid_q);
>> @@ -3756,9 +3752,11 @@ int cifs_negotiate_protocol(unsigned int xid, struct cifs_ses *ses)
>> if (server->maxBuf != 0)
>> return 0;
>>
>> + cifs_set_credits(server, 1);
>> rc = CIFSSMBNegotiate(xid, ses);
>> if (rc == -EAGAIN) {
>> /* retry only once on 1st time connection */
>> + cifs_set_credits(server, 1);
>> rc = CIFSSMBNegotiate(xid, ses);
>> if (rc == -EAGAIN)
>> rc = -EHOSTDOWN;
>> diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
>> index 703ef5c..5dc936b 100644
>> --- a/fs/cifs/misc.c
>> +++ b/fs/cifs/misc.c
>> @@ -690,3 +690,21 @@ backup_cred(struct cifs_sb_info *cifs_sb)
>>
>> return false;
>> }
>> +
>> +void
>> +cifs_add_credits(struct TCP_Server_Info *server, const unsigned int add)
>> +{
>> + spin_lock(&server->req_lock);
>> + server->credits += add;
>> + server->in_flight--;
>> + spin_unlock(&server->req_lock);
>> +}
>> +
>> +void
>> +cifs_set_credits(struct TCP_Server_Info *server, const int val)
>> +{
>> + spin_lock(&server->req_lock);
>> + server->credits = val;
>> + server->oplocks = val > 1 ? enable_oplocks : false;
>> + spin_unlock(&server->req_lock);
>> +}
>> diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
>> index e2673aa..e8a4fd3 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 >= server->maxReq) {
>> + if (server->credits <= 0) {
>> spin_unlock(&server->req_lock);
>> cifs_num_waiters_inc(server);
>> - wait_event(server->request_q,
>> - in_flight(server) < server->maxReq);
>> + wait_event(server->request_q, has_credits(server));
>> cifs_num_waiters_dec(server);
>> spin_lock(&server->req_lock);
>> } else {
>> @@ -280,12 +280,16 @@ wait_for_free_request(struct TCP_Server_Info *server, const int long_op)
>> return -ENOENT;
>> }
>>
>> - /* can not count locking commands against total
>> - as they are allowed to block on server */
>> + /*
>> + * 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)
>> + if (long_op != CIFS_BLOCKING_OP) {
>> + server->credits--;
>> server->in_flight++;
>> + }
>> spin_unlock(&server->req_lock);
>> break;
>> }
>> @@ -360,7 +364,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);
>> + cifs_add_credits(server, 1);
>> wake_up(&server->request_q);
>> return -ENOMEM;
>> }
>> @@ -393,7 +397,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
>> return rc;
>> out_err:
>> delete_mid(mid);
>> - dec_in_flight(server);
>> + cifs_add_credits(server, 1);
>> wake_up(&server->request_q);
>> return rc;
>> }
>> @@ -565,7 +569,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);
>> + cifs_add_credits(ses->server, 1);
>> wake_up(&ses->server->request_q);
>> return rc;
>> }
>> @@ -602,7 +606,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);
>> + cifs_add_credits(ses->server, 1);
>> wake_up(&ses->server->request_q);
>> return rc;
>> }
>> @@ -613,7 +617,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);
>> + cifs_add_credits(ses->server, 1);
>> wake_up(&ses->server->request_q);
>> return rc;
>> }
>> @@ -638,7 +642,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
>> midQ->resp_buf = NULL;
>> out:
>> delete_mid(midQ);
>> - dec_in_flight(ses->server);
>> + cifs_add_credits(ses->server, 1);
>> wake_up(&ses->server->request_q);
>>
>> return rc;
>> @@ -689,7 +693,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);
>> + cifs_add_credits(ses->server, 1);
>> wake_up(&ses->server->request_q);
>> return rc;
>> }
>> @@ -722,7 +726,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);
>> + cifs_add_credits(ses->server, 1);
>> wake_up(&ses->server->request_q);
>> return rc;
>> }
>> @@ -731,7 +735,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);
>> + cifs_add_credits(ses->server, 1);
>> wake_up(&ses->server->request_q);
>> return rc;
>> }
>> @@ -748,7 +752,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);
>> + cifs_add_credits(ses->server, 1);
>> wake_up(&ses->server->request_q);
>>
>> return rc;
>
> --
> Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
--
Best regards,
Pavel Shilovsky.
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH v2 01/11] CIFS: Respect negotiated MaxMpxCount
[not found] ` <CAKywueTDsGhcHiGM_uX6V0dnY3m_W4kD2qcb+JWRq=UVnBnvPw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2012-03-17 15:20 ` Steve French
[not found] ` <CAH2r5msMKiEyS2-ak2+tQoRFommSHRcCNwp-J+XtgovmSae7-A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
0 siblings, 1 reply; 43+ messages in thread
From: Steve French @ 2012-03-17 15:20 UTC (permalink / raw)
To: Pavel Shilovsky; +Cc: Jeff Layton, linux-cifs-u79uwXL29TY76Z2rM5mHXA
On Sat, Mar 17, 2012 at 9:53 AM, Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> 17 марта 2012 г. 15:12 пользователь Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> написал:
>> On Fri, 16 Mar 2012 18:09:24 +0300
>> Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
>>
>>> Some servers sets this value less than 50 that was hardcoded and
>>> we lost the connection if when we exceed this limit. Fix this by
>>> respecting this value - not sending more than the server allows.
>>>
>>> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
>>> ---
>>> fs/cifs/cifsfs.c | 8 ++++----
>>> fs/cifs/cifsglob.h | 10 +++-------
>>> fs/cifs/cifssmb.c | 9 +++++++--
>>> fs/cifs/connect.c | 11 ++++-------
>>> fs/cifs/dir.c | 6 ++++--
>>> fs/cifs/file.c | 4 ++--
>>> fs/cifs/transport.c | 4 ++--
>>
>> Introducing a behavior change like this at the beginning of the series
>> is probably a mistake. You'll have no reasonable way to bisect down
>> regressions, so you won't know if a problem is due to the change to a
>> credit-based model or due to changing the client to respect the maxmpx.
>>
>> Instead of doing this, we should instead reorganize the code around a
>> credit based model first, while attempting to mimic the existing
>> behavior as closely as possible. Once that framework is in place, then
>> change the behavior and start respecting the maxmpx.
>>
>> If you do that, then someone can reasonably bisect between those two
>> changes and we can determine the source of a regression.
>> --
>> Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
>
> This was done to push this patch to 3.3 and stable tree as well.
> That's why it is in the start of series.
>
> If we decide not to push it for now, I agree that this patch should be
> in the modified version (according to changes from other patches) at
> the end of the series.
>
> Steve, your thoughts?
>
> --
> Best regards,
> Pavel Shilovsky.
We want to fix the reported (cifs) problem first with a simple patch
(that would be suitable for stable too).
The most important reported problems are mounts to servers
running some versions of Windows Vista and some versions of Windows 7
which set maxmpx below 50 and more importantly have maxworkitems
(in the windows registry on the server) set at too small a value to handle
the 20 or 30 async reads or writes which are now often in flight to them.
The fix we need first is to honor the maxmpx that the server sets (and
probably remove cifs_max_pending which is obsolete as
a global module parm or simply do the minimum of cifs_max_pending
and maxmpx as the earlier patch did). If desired (to workaround buggy
servers) in a second patch we could add a mount parm if we think there are
servers such as windows 7 for which we will need to set the
negotiated value lower (due to their maxworkitems registry
problem), or Samba for which maxmpx could be ignored
(and as JRA and others indicated - we could send
a thousand requests in parallel).
--
Thanks,
Steve
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH v2 06/11] CIFS: Delete echo_retries module parm
[not found] ` <1331910574-998-7-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
@ 2012-03-18 10:30 ` Jeff Layton
0 siblings, 0 replies; 43+ messages in thread
From: Jeff Layton @ 2012-03-18 10:30 UTC (permalink / raw)
To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA
On Fri, 16 Mar 2012 18:09:29 +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 during two echo intervals -
> 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 6ee1cb4..f266161 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: 32767 Range: 2 to 32767.");
> -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 2309a67..339ebe3 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -1038,9 +1038,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 f3a0c49..4156351 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 + 2 * SMB_ECHO_INTERVAL)) {
Since you're replacing a variable with a hardcoded value like this, it's
probably a good idea to add a comment that explains why we're using 2 *
SMB_ECHO_INTERVAL here. Otherwise we'll forget in a year or two...
> cERROR(1, "Server %s has not responded in %d seconds. "
> "Reconnecting...", server->hostname,
> - (echo_retries * SMB_ECHO_INTERVAL / HZ));
> + (2 * SMB_ECHO_INTERVAL) / HZ);
> cifs_reconnect(server);
> wake_up(&server->response_q);
> return true;
If you're targeting part of this series for stable, then it seems like
this patch ought to be earlier in it (#2 or #3 or so). Looks fine to me
though other than the nit about the comment.
Reviewed-by: Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH v2 01/11] CIFS: Respect negotiated MaxMpxCount
[not found] ` <CAH2r5msMKiEyS2-ak2+tQoRFommSHRcCNwp-J+XtgovmSae7-A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2012-03-18 10:33 ` Jeff Layton
2012-03-18 10:50 ` Jeff Layton
1 sibling, 0 replies; 43+ messages in thread
From: Jeff Layton @ 2012-03-18 10:33 UTC (permalink / raw)
To: Steve French; +Cc: Pavel Shilovsky, linux-cifs-u79uwXL29TY76Z2rM5mHXA
On Sat, 17 Mar 2012 10:20:59 -0500
Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> On Sat, Mar 17, 2012 at 9:53 AM, Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> > 17 марта 2012 г. 15:12 пользователь Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> написал:
> >> On Fri, 16 Mar 2012 18:09:24 +0300
> >> Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> >>
> >>> Some servers sets this value less than 50 that was hardcoded and
> >>> we lost the connection if when we exceed this limit. Fix this by
> >>> respecting this value - not sending more than the server allows.
> >>>
> >>> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
> >>> ---
> >>> fs/cifs/cifsfs.c | 8 ++++----
> >>> fs/cifs/cifsglob.h | 10 +++-------
> >>> fs/cifs/cifssmb.c | 9 +++++++--
> >>> fs/cifs/connect.c | 11 ++++-------
> >>> fs/cifs/dir.c | 6 ++++--
> >>> fs/cifs/file.c | 4 ++--
> >>> fs/cifs/transport.c | 4 ++--
> >>
> >> Introducing a behavior change like this at the beginning of the series
> >> is probably a mistake. You'll have no reasonable way to bisect down
> >> regressions, so you won't know if a problem is due to the change to a
> >> credit-based model or due to changing the client to respect the maxmpx.
> >>
> >> Instead of doing this, we should instead reorganize the code around a
> >> credit based model first, while attempting to mimic the existing
> >> behavior as closely as possible. Once that framework is in place, then
> >> change the behavior and start respecting the maxmpx.
> >>
> >> If you do that, then someone can reasonably bisect between those two
> >> changes and we can determine the source of a regression.
> >> --
> >> Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
> >
> > This was done to push this patch to 3.3 and stable tree as well.
> > That's why it is in the start of series.
> >
> > If we decide not to push it for now, I agree that this patch should be
> > in the modified version (according to changes from other patches) at
> > the end of the series.
> >
> > Steve, your thoughts?
> >
> > --
> > Best regards,
> > Pavel Shilovsky.
>
> We want to fix the reported (cifs) problem first with a simple patch
> (that would be suitable for stable too).
>
> The most important reported problems are mounts to servers
> running some versions of Windows Vista and some versions of Windows 7
> which set maxmpx below 50 and more importantly have maxworkitems
> (in the windows registry on the server) set at too small a value to handle
> the 20 or 30 async reads or writes which are now often in flight to them.
>
> The fix we need first is to honor the maxmpx that the server sets (and
> probably remove cifs_max_pending which is obsolete as
> a global module parm or simply do the minimum of cifs_max_pending
> and maxmpx as the earlier patch did). If desired (to workaround buggy
> servers) in a second patch we could add a mount parm if we think there are
> servers such as windows 7 for which we will need to set the
> negotiated value lower (due to their maxworkitems registry
> problem), or Samba for which maxmpx could be ignored
> (and as JRA and others indicated - we could send
> a thousand requests in parallel).
>
Ok, that sounds like a reasonable approach.
If you want to do that though would it make more sense to do a patch or
series that just fixes the problem with smb1 without introducing
credits? That series could be targeted for stable and you could then do
another series on top of it that converts to a credit based model and
adds in the smb2 code.
The spec is so ambiguous here that we can be reasonably sure that
*something* will break. We ought to try to proceed in such a way that
we can deal with those problems quickly and efficiently as they arise.
The thing we don't want to do is conflate the credit based changes with
the change to respect maxmpx too much since that'll make it tough to
know what caused a particular problem...
--
Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH v2 01/11] CIFS: Respect negotiated MaxMpxCount
[not found] ` <CAH2r5msMKiEyS2-ak2+tQoRFommSHRcCNwp-J+XtgovmSae7-A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-03-18 10:33 ` Jeff Layton
@ 2012-03-18 10:50 ` Jeff Layton
[not found] ` <20120318065059.62592afb-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
1 sibling, 1 reply; 43+ messages in thread
From: Jeff Layton @ 2012-03-18 10:50 UTC (permalink / raw)
To: Steve French; +Cc: Pavel Shilovsky, linux-cifs-u79uwXL29TY76Z2rM5mHXA
On Sat, 17 Mar 2012 10:20:59 -0500
Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> On Sat, Mar 17, 2012 at 9:53 AM, Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> > 17 марта 2012 г. 15:12 пользователь Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> написал:
> >> On Fri, 16 Mar 2012 18:09:24 +0300
> >> Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> >>
> >>> Some servers sets this value less than 50 that was hardcoded and
> >>> we lost the connection if when we exceed this limit. Fix this by
> >>> respecting this value - not sending more than the server allows.
> >>>
> >>> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
> >>> ---
> >>> fs/cifs/cifsfs.c | 8 ++++----
> >>> fs/cifs/cifsglob.h | 10 +++-------
> >>> fs/cifs/cifssmb.c | 9 +++++++--
> >>> fs/cifs/connect.c | 11 ++++-------
> >>> fs/cifs/dir.c | 6 ++++--
> >>> fs/cifs/file.c | 4 ++--
> >>> fs/cifs/transport.c | 4 ++--
> >>
> >> Introducing a behavior change like this at the beginning of the series
> >> is probably a mistake. You'll have no reasonable way to bisect down
> >> regressions, so you won't know if a problem is due to the change to a
> >> credit-based model or due to changing the client to respect the maxmpx.
> >>
> >> Instead of doing this, we should instead reorganize the code around a
> >> credit based model first, while attempting to mimic the existing
> >> behavior as closely as possible. Once that framework is in place, then
> >> change the behavior and start respecting the maxmpx.
> >>
> >> If you do that, then someone can reasonably bisect between those two
> >> changes and we can determine the source of a regression.
> >> --
> >> Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
> >
> > This was done to push this patch to 3.3 and stable tree as well.
> > That's why it is in the start of series.
> >
> > If we decide not to push it for now, I agree that this patch should be
> > in the modified version (according to changes from other patches) at
> > the end of the series.
> >
> > Steve, your thoughts?
> >
> > --
> > Best regards,
> > Pavel Shilovsky.
>
> We want to fix the reported (cifs) problem first with a simple patch
> (that would be suitable for stable too).
>
> The most important reported problems are mounts to servers
> running some versions of Windows Vista and some versions of Windows 7
> which set maxmpx below 50 and more importantly have maxworkitems
> (in the windows registry on the server) set at too small a value to handle
> the 20 or 30 async reads or writes which are now often in flight to them.
>
> The fix we need first is to honor the maxmpx that the server sets (and
> probably remove cifs_max_pending which is obsolete as
> a global module parm or simply do the minimum of cifs_max_pending
> and maxmpx as the earlier patch did).
> If desired (to workaround buggy
> servers) in a second patch we could add a mount parm if we think there are
> servers such as windows 7 for which we will need to set the
> negotiated value lower (due to their maxworkitems registry
> problem), or Samba for which maxmpx could be ignored
> (and as JRA and others indicated - we could send
> a thousand requests in parallel).
>
By the way...
What's the plan for blocking locks and echoes here? Do you plan to make
them just ignore the maxmpx limit?
Another important case to consider is the (apparently common) case
where maxmpx is 1. We don't really want to make things worse against
such servers...
--
Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH v2 01/11] CIFS: Respect negotiated MaxMpxCount
[not found] ` <20120318065059.62592afb-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
@ 2012-03-18 18:23 ` Pavel Shilovsky
[not found] ` <CAKywueSrGVvwqHbTK3sNLsHDx3vR6U0Ca712ZXKNTnjnOgPGDA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
0 siblings, 1 reply; 43+ messages in thread
From: Pavel Shilovsky @ 2012-03-18 18:23 UTC (permalink / raw)
To: Jeff Layton; +Cc: Steve French, linux-cifs-u79uwXL29TY76Z2rM5mHXA
18 марта 2012 г. 14:50 пользователь Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> написал:
> On Sat, 17 Mar 2012 10:20:59 -0500
> Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
>
>> On Sat, Mar 17, 2012 at 9:53 AM, Pavel Shilovsky <piastry@etersoft.ru> wrote:
>> > 17 марта 2012 г. 15:12 пользователь Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> написал:
>> >> On Fri, 16 Mar 2012 18:09:24 +0300
>> >> Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
>> >>
>> >>> Some servers sets this value less than 50 that was hardcoded and
>> >>> we lost the connection if when we exceed this limit. Fix this by
>> >>> respecting this value - not sending more than the server allows.
>> >>>
>> >>> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
>> >>> ---
>> >>> fs/cifs/cifsfs.c | 8 ++++----
>> >>> fs/cifs/cifsglob.h | 10 +++-------
>> >>> fs/cifs/cifssmb.c | 9 +++++++--
>> >>> fs/cifs/connect.c | 11 ++++-------
>> >>> fs/cifs/dir.c | 6 ++++--
>> >>> fs/cifs/file.c | 4 ++--
>> >>> fs/cifs/transport.c | 4 ++--
>> >>
>> >> Introducing a behavior change like this at the beginning of the series
>> >> is probably a mistake. You'll have no reasonable way to bisect down
>> >> regressions, so you won't know if a problem is due to the change to a
>> >> credit-based model or due to changing the client to respect the maxmpx.
>> >>
>> >> Instead of doing this, we should instead reorganize the code around a
>> >> credit based model first, while attempting to mimic the existing
>> >> behavior as closely as possible. Once that framework is in place, then
>> >> change the behavior and start respecting the maxmpx.
>> >>
>> >> If you do that, then someone can reasonably bisect between those two
>> >> changes and we can determine the source of a regression.
>> >> --
>> >> Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
>> >
>> > This was done to push this patch to 3.3 and stable tree as well.
>> > That's why it is in the start of series.
>> >
>> > If we decide not to push it for now, I agree that this patch should be
>> > in the modified version (according to changes from other patches) at
>> > the end of the series.
>> >
>> > Steve, your thoughts?
>> >
>> > --
>> > Best regards,
>> > Pavel Shilovsky.
>>
>> We want to fix the reported (cifs) problem first with a simple patch
>> (that would be suitable for stable too).
>>
>> The most important reported problems are mounts to servers
>> running some versions of Windows Vista and some versions of Windows 7
>> which set maxmpx below 50 and more importantly have maxworkitems
>> (in the windows registry on the server) set at too small a value to handle
>> the 20 or 30 async reads or writes which are now often in flight to them.
>>
>> The fix we need first is to honor the maxmpx that the server sets (and
>> probably remove cifs_max_pending which is obsolete as
>> a global module parm or simply do the minimum of cifs_max_pending
>> and maxmpx as the earlier patch did).
>> If desired (to workaround buggy
>> servers) in a second patch we could add a mount parm if we think there are
>> servers such as windows 7 for which we will need to set the
>> negotiated value lower (due to their maxworkitems registry
>> problem), or Samba for which maxmpx could be ignored
>> (and as JRA and others indicated - we could send
>> a thousand requests in parallel).
>>
>
> By the way...
>
> What's the plan for blocking locks and echoes here? Do you plan to make
> them just ignore the maxmpx limit?
I think we shouldn't play with them for stable. We still don't know
what exactly we should do with them - really risky to make experiments
on stable kernels.
So, as we are sure that exceeding negotiated maxmpx value with any
request except blocking lock and echo is wrong, I suggest to fix this
- it is what this patch (#1) does. When we get more information about
blocking locks and echos we can fix this too.
>
> Another important case to consider is the (apparently common) case
> where maxmpx is 1. We don't really want to make things worse against
> such servers...
>
If server negotiates maxmpx=1 then we simply disable oplocks for now
(that the patch does) - don't think it makes things worse for those
servers.
--
Best regards,
Pavel Shilovsky.
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH v2 01/11] CIFS: Respect negotiated MaxMpxCount
[not found] ` <CAKywueSrGVvwqHbTK3sNLsHDx3vR6U0Ca712ZXKNTnjnOgPGDA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2012-03-19 15:04 ` Jeff Layton
[not found] ` <20120319110437.635ea546-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
0 siblings, 1 reply; 43+ messages in thread
From: Jeff Layton @ 2012-03-19 15:04 UTC (permalink / raw)
To: Pavel Shilovsky; +Cc: Steve French, linux-cifs-u79uwXL29TY76Z2rM5mHXA
On Sun, 18 Mar 2012 22:23:47 +0400
Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> 18 марта 2012 г. 14:50 пользователь Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> написал:
> > On Sat, 17 Mar 2012 10:20:59 -0500
> > Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> >
> >> On Sat, Mar 17, 2012 at 9:53 AM, Pavel Shilovsky <piastry@etersoft.ru> wrote:
> >> > 17 марта 2012 г. 15:12 пользователь Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> написал:
> >> >> On Fri, 16 Mar 2012 18:09:24 +0300
> >> >> Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> >> >>
> >> >>> Some servers sets this value less than 50 that was hardcoded and
> >> >>> we lost the connection if when we exceed this limit. Fix this by
> >> >>> respecting this value - not sending more than the server allows.
> >> >>>
> >> >>> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
> >> >>> ---
> >> >>> fs/cifs/cifsfs.c | 8 ++++----
> >> >>> fs/cifs/cifsglob.h | 10 +++-------
> >> >>> fs/cifs/cifssmb.c | 9 +++++++--
> >> >>> fs/cifs/connect.c | 11 ++++-------
> >> >>> fs/cifs/dir.c | 6 ++++--
> >> >>> fs/cifs/file.c | 4 ++--
> >> >>> fs/cifs/transport.c | 4 ++--
> >> >>
> >> >> Introducing a behavior change like this at the beginning of the series
> >> >> is probably a mistake. You'll have no reasonable way to bisect down
> >> >> regressions, so you won't know if a problem is due to the change to a
> >> >> credit-based model or due to changing the client to respect the maxmpx.
> >> >>
> >> >> Instead of doing this, we should instead reorganize the code around a
> >> >> credit based model first, while attempting to mimic the existing
> >> >> behavior as closely as possible. Once that framework is in place, then
> >> >> change the behavior and start respecting the maxmpx.
> >> >>
> >> >> If you do that, then someone can reasonably bisect between those two
> >> >> changes and we can determine the source of a regression.
> >> >> --
> >> >> Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
> >> >
> >> > This was done to push this patch to 3.3 and stable tree as well.
> >> > That's why it is in the start of series.
> >> >
> >> > If we decide not to push it for now, I agree that this patch should be
> >> > in the modified version (according to changes from other patches) at
> >> > the end of the series.
> >> >
> >> > Steve, your thoughts?
> >> >
> >> > --
> >> > Best regards,
> >> > Pavel Shilovsky.
> >>
> >> We want to fix the reported (cifs) problem first with a simple patch
> >> (that would be suitable for stable too).
> >>
> >> The most important reported problems are mounts to servers
> >> running some versions of Windows Vista and some versions of Windows 7
> >> which set maxmpx below 50 and more importantly have maxworkitems
> >> (in the windows registry on the server) set at too small a value to handle
> >> the 20 or 30 async reads or writes which are now often in flight to them.
> >>
> >> The fix we need first is to honor the maxmpx that the server sets (and
> >> probably remove cifs_max_pending which is obsolete as
> >> a global module parm or simply do the minimum of cifs_max_pending
> >> and maxmpx as the earlier patch did).
> >> If desired (to workaround buggy
> >> servers) in a second patch we could add a mount parm if we think there are
> >> servers such as windows 7 for which we will need to set the
> >> negotiated value lower (due to their maxworkitems registry
> >> problem), or Samba for which maxmpx could be ignored
> >> (and as JRA and others indicated - we could send
> >> a thousand requests in parallel).
> >>
> >
> > By the way...
> >
> > What's the plan for blocking locks and echoes here? Do you plan to make
> > them just ignore the maxmpx limit?
>
> I think we shouldn't play with them for stable. We still don't know
> what exactly we should do with them - really risky to make experiments
> on stable kernels.
>
Then I'm confused, since you said this in your earlier email:
> This was done to push this patch to 3.3 and stable tree as well.
> That's why it is in the start of series.
>
If you're not worrying about stable (and I agree that it's premature to
do that here), then you should focus on converting everything to use
the new credit-based scheme first and only then introduce the behavior
change of respecting maxmpx.
> So, as we are sure that exceeding negotiated maxmpx value with any
> request except blocking lock and echo is wrong, I suggest to fix this
> - it is what this patch (#1) does. When we get more information about
> blocking locks and echos we can fix this too.
>
Well, according to what MS wrote back to Steve when he asked, exceeding
the maxmpx is wrong _period_, regardless of the call. Echoes are fairly
easy to deal with, but blocking locks are another matter entirely. I
believe we need a fundamental rethink there.
I think we need to change blocking lock calls to respect the maxmpx,
use a small timeout (3-5s or so) and call it in a loop. That would
allow other calls to "slip in", though it will suck for lock
"fairness".
That's a separate problem though. For the initial pass here, I think we
should just continue to ignore the limit for blocking locks.
--
Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH v2 01/11] CIFS: Respect negotiated MaxMpxCount
[not found] ` <20120319110437.635ea546-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
@ 2012-03-19 19:04 ` Pavel Shilovsky
[not found] ` <CAKywueR2mWNKxNDhhj_0i0TfiPz3nmvVBXbxGMZ+Lrbgts3cDQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
0 siblings, 1 reply; 43+ messages in thread
From: Pavel Shilovsky @ 2012-03-19 19:04 UTC (permalink / raw)
To: Jeff Layton; +Cc: Steve French, linux-cifs-u79uwXL29TY76Z2rM5mHXA
19 марта 2012 г. 19:04 пользователь Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> написал:
> On Sun, 18 Mar 2012 22:23:47 +0400
> Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
>
>> 18 марта 2012 г. 14:50 пользователь Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> написал:
>> > On Sat, 17 Mar 2012 10:20:59 -0500
>> > Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
>> >
>> >> On Sat, Mar 17, 2012 at 9:53 AM, Pavel Shilovsky <piastry@etersoft.ru> wrote:
>> >> > 17 марта 2012 г. 15:12 пользователь Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> написал:
>> >> >> On Fri, 16 Mar 2012 18:09:24 +0300
>> >> >> Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
>> >> >>
>> >> >>> Some servers sets this value less than 50 that was hardcoded and
>> >> >>> we lost the connection if when we exceed this limit. Fix this by
>> >> >>> respecting this value - not sending more than the server allows.
>> >> >>>
>> >> >>> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
>> >> >>> ---
>> >> >>> fs/cifs/cifsfs.c | 8 ++++----
>> >> >>> fs/cifs/cifsglob.h | 10 +++-------
>> >> >>> fs/cifs/cifssmb.c | 9 +++++++--
>> >> >>> fs/cifs/connect.c | 11 ++++-------
>> >> >>> fs/cifs/dir.c | 6 ++++--
>> >> >>> fs/cifs/file.c | 4 ++--
>> >> >>> fs/cifs/transport.c | 4 ++--
>> >> >>
>> >> >> Introducing a behavior change like this at the beginning of the series
>> >> >> is probably a mistake. You'll have no reasonable way to bisect down
>> >> >> regressions, so you won't know if a problem is due to the change to a
>> >> >> credit-based model or due to changing the client to respect the maxmpx.
>> >> >>
>> >> >> Instead of doing this, we should instead reorganize the code around a
>> >> >> credit based model first, while attempting to mimic the existing
>> >> >> behavior as closely as possible. Once that framework is in place, then
>> >> >> change the behavior and start respecting the maxmpx.
>> >> >>
>> >> >> If you do that, then someone can reasonably bisect between those two
>> >> >> changes and we can determine the source of a regression.
>> >> >> --
>> >> >> Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
>> >> >
>> >> > This was done to push this patch to 3.3 and stable tree as well.
>> >> > That's why it is in the start of series.
>> >> >
>> >> > If we decide not to push it for now, I agree that this patch should be
>> >> > in the modified version (according to changes from other patches) at
>> >> > the end of the series.
>> >> >
>> >> > Steve, your thoughts?
>> >> >
>> >> > --
>> >> > Best regards,
>> >> > Pavel Shilovsky.
>> >>
>> >> We want to fix the reported (cifs) problem first with a simple patch
>> >> (that would be suitable for stable too).
>> >>
>> >> The most important reported problems are mounts to servers
>> >> running some versions of Windows Vista and some versions of Windows 7
>> >> which set maxmpx below 50 and more importantly have maxworkitems
>> >> (in the windows registry on the server) set at too small a value to handle
>> >> the 20 or 30 async reads or writes which are now often in flight to them.
>> >>
>> >> The fix we need first is to honor the maxmpx that the server sets (and
>> >> probably remove cifs_max_pending which is obsolete as
>> >> a global module parm or simply do the minimum of cifs_max_pending
>> >> and maxmpx as the earlier patch did).
>> >> If desired (to workaround buggy
>> >> servers) in a second patch we could add a mount parm if we think there are
>> >> servers such as windows 7 for which we will need to set the
>> >> negotiated value lower (due to their maxworkitems registry
>> >> problem), or Samba for which maxmpx could be ignored
>> >> (and as JRA and others indicated - we could send
>> >> a thousand requests in parallel).
>> >>
>> >
>> > By the way...
>> >
>> > What's the plan for blocking locks and echoes here? Do you plan to make
>> > them just ignore the maxmpx limit?
>>
>> I think we shouldn't play with them for stable. We still don't know
>> what exactly we should do with them - really risky to make experiments
>> on stable kernels.
>>
>
> Then I'm confused, since you said this in your earlier email:
>
>> This was done to push this patch to 3.3 and stable tree as well.
>> That's why it is in the start of series.
>>
>
> If you're not worrying about stable (and I agree that it's premature to
> do that here), then you should focus on converting everything to use
> the new credit-based scheme first and only then introduce the behavior
> change of respecting maxmpx.
>
>> So, as we are sure that exceeding negotiated maxmpx value with any
>> request except blocking lock and echo is wrong, I suggest to fix this
>> - it is what this patch (#1) does. When we get more information about
>> blocking locks and echos we can fix this too.
>>
>
> Well, according to what MS wrote back to Steve when he asked, exceeding
> the maxmpx is wrong _period_, regardless of the call. Echoes are fairly
> easy to deal with, but blocking locks are another matter entirely. I
> believe we need a fundamental rethink there.
I meant that playing with things like blocking locks and echos is too
risky for stable. But if we can fix the existing stable problem (not
respecting MaxMpxCount value by other commands) with a strait-forward
patch like this - we should do it.
>
> I think we need to change blocking lock calls to respect the maxmpx,
> use a small timeout (3-5s or so) and call it in a loop. That would
> allow other calls to "slip in", though it will suck for lock
> "fairness".
>
> That's a separate problem though. For the initial pass here, I think we
> should just continue to ignore the limit for blocking locks.
Yes, I agree this is another separate problem.
--
Best regards,
Pavel Shilovsky.
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH v2 05/11] CIFS: Prepare credits code for a slot reservation
[not found] ` <1331910574-998-6-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
@ 2012-03-19 19:27 ` Jeff Layton
[not found] ` <20120319152702.3eee1608-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
0 siblings, 1 reply; 43+ messages in thread
From: Jeff Layton @ 2012-03-19 19:27 UTC (permalink / raw)
To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA
On Fri, 16 Mar 2012 18:09:28 +0300
Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> that is essential for CIFS/SMB/SMB2 oplock breaks and SMB2 echos.
>
> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
> ---
> fs/cifs/cifsglob.h | 14 ++++++++++++--
> fs/cifs/transport.c | 22 ++++++++++++++--------
> 2 files changed, 26 insertions(+), 10 deletions(-)
>
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index d55de96..2309a67 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -315,12 +315,22 @@ in_flight(struct TCP_Server_Info *server)
> return num;
> }
>
> +static inline int*
> +get_credits_field(struct TCP_Server_Info *server)
> +{
> + /*
> + * This will change to switch statement when we reserve slots for echos
> + * and oplock breaks.
> + */
> + return &server->credits;
> +}
> +
> static inline bool
> -has_credits(struct TCP_Server_Info *server)
> +has_credits(struct TCP_Server_Info *server, int *credits)
Why are you passing "credits" by reference here? Might as well pass by
value...
> {
> int num;
> spin_lock(&server->req_lock);
> - num = server->credits;
> + num = *credits;
> spin_unlock(&server->req_lock);
> return num > 0;
> }
> diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
> index 11787cc..20dc7ba 100644
> --- a/fs/cifs/transport.c
> +++ b/fs/cifs/transport.c
> @@ -255,26 +255,26 @@ 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, const int optype,
> + int *credits)
> {
> int rc;
>
> spin_lock(&server->req_lock);
> -
> - if (long_op == CIFS_ASYNC_OP) {
> + if (optype == CIFS_ASYNC_OP) {
> /* oplock breaks must not be held up */
> server->in_flight++;
> - server->credits--;
> + *credits -= 1;
> spin_unlock(&server->req_lock);
> return 0;
> }
>
> while (1) {
> - if (server->credits <= 0) {
> + if (*credits <= 0) {
> spin_unlock(&server->req_lock);
> cifs_num_waiters_inc(server);
> rc = wait_event_killable(server->request_q,
> - has_credits(server));
> + has_credits(server, credits));
> cifs_num_waiters_dec(server);
> if (rc)
> return rc;
> @@ -291,8 +291,8 @@ wait_for_free_request(struct TCP_Server_Info *server, const int long_op)
> */
>
> /* update # of requests on the wire to server */
> - if (long_op != CIFS_BLOCKING_OP) {
> - server->credits--;
> + if (optype != CIFS_BLOCKING_OP) {
> + *credits -= 1;
> server->in_flight++;
> }
> spin_unlock(&server->req_lock);
> @@ -302,6 +302,12 @@ wait_for_free_request(struct TCP_Server_Info *server, const int long_op)
> return 0;
> }
>
> +static int
> +wait_for_free_request(struct TCP_Server_Info *server, const int optype)
> +{
> + return wait_for_free_credits(server, optype, get_credits_field(server));
> +}
> +
> static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
> struct mid_q_entry **ppmidQ)
> {
Other than that nit, this looks fine...
Reviewed-by: Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH v2 07/11] CIFS: Separate protocol-specific code from transport routines
[not found] ` <1331910574-998-8-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
@ 2012-03-19 19:31 ` Jeff Layton
0 siblings, 0 replies; 43+ messages in thread
From: Jeff Layton @ 2012-03-19 19:31 UTC (permalink / raw)
To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA
On Fri, 16 Mar 2012 18:09:30 +0300
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 339ebe3..c3c7d7c 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -230,6 +230,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 47a769e..2d506e3 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 08c84a1..d3b8089 100644
> --- a/fs/cifs/cifssmb.c
> +++ b/fs/cifs/cifssmb.c
> @@ -696,7 +696,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);
>
> @@ -793,7 +793,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);
>
> @@ -2423,8 +2423,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);
> @@ -2591,7 +2590,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) {
> @@ -2620,7 +2619,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);
> @@ -4628,7 +4627,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);
>
> @@ -5649,7 +5648,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);
> }
> @@ -5718,7 +5717,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);
>
> @@ -5777,7 +5776,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);
>
> @@ -6009,7 +6008,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 5dc936b..1578617 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 20dc7ba..7f63c44 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;
> }
> @@ -349,6 +348,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
> @@ -361,34 +387,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, ignore_pend ? CIFS_ASYNC_OP : 0);
> 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);
> cifs_add_credits(server, 1);
> 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;
> @@ -424,14 +434,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);
> @@ -514,7 +524,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));
>
> @@ -534,6 +544,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 */,
> @@ -542,54 +570,52 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
> int rc = 0;
> int long_op;
> 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;
>
> *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, long_op);
> 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 */
> cifs_add_credits(ses->server, 1);
> 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);
> @@ -600,23 +626,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);
> cifs_add_credits(ses->server, 1);
> wake_up(&ses->server->request_q);
> return rc;
> @@ -624,7 +650,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) {
> @@ -639,8 +665,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
Nice cleanup.
Reviewed-by: Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH v2 01/11] CIFS: Respect negotiated MaxMpxCount
[not found] ` <CAKywueR2mWNKxNDhhj_0i0TfiPz3nmvVBXbxGMZ+Lrbgts3cDQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2012-03-19 19:32 ` Steve French
[not found] ` <CAH2r5mvhTYPxvDRFCpQ0ULmDn2TNQ80ODbnvTmgFurptYukR1Q-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
0 siblings, 1 reply; 43+ messages in thread
From: Steve French @ 2012-03-19 19:32 UTC (permalink / raw)
To: Pavel Shilovsky; +Cc: Jeff Layton, linux-cifs-u79uwXL29TY76Z2rM5mHXA
On Mon, Mar 19, 2012 at 2:04 PM, Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> 19 марта 2012 г. 19:04 пользователь Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> написал:
>> On Sun, 18 Mar 2012 22:23:47 +0400
>> Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
>>
>>> 18 марта 2012 г. 14:50 пользователь Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> написал:
>>> > On Sat, 17 Mar 2012 10:20:59 -0500
>>> > Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
>>> >
>>> >> On Sat, Mar 17, 2012 at 9:53 AM, Pavel Shilovsky <piastry@etersoft.ru> wrote:
>>> >> > 17 марта 2012 г. 15:12 пользователь Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> написал:
>>> >> >> On Fri, 16 Mar 2012 18:09:24 +0300
>>> >> >> Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
>>> >> >>
>>> >> >>> Some servers sets this value less than 50 that was hardcoded and
>>> >> >>> we lost the connection if when we exceed this limit. Fix this by
>>> >> >>> respecting this value - not sending more than the server allows.
>>> >> >>>
>>> >> >>> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
>>> >> >>> ---
>>> >> >>> fs/cifs/cifsfs.c | 8 ++++----
>>> >> >>> fs/cifs/cifsglob.h | 10 +++-------
>>> >> >>> fs/cifs/cifssmb.c | 9 +++++++--
>>> >> >>> fs/cifs/connect.c | 11 ++++-------
>>> >> >>> fs/cifs/dir.c | 6 ++++--
>>> >> >>> fs/cifs/file.c | 4 ++--
>>> >> >>> fs/cifs/transport.c | 4 ++--
>>> >> >>
>>> >> >> Introducing a behavior change like this at the beginning of the series
>>> >> >> is probably a mistake. You'll have no reasonable way to bisect down
>>> >> >> regressions, so you won't know if a problem is due to the change to a
>>> >> >> credit-based model or due to changing the client to respect the maxmpx.
>>> >> >>
>>> >> >> Instead of doing this, we should instead reorganize the code around a
>>> >> >> credit based model first, while attempting to mimic the existing
>>> >> >> behavior as closely as possible. Once that framework is in place, then
>>> >> >> change the behavior and start respecting the maxmpx.
>>> >> >>
>>> >> >> If you do that, then someone can reasonably bisect between those two
>>> >> >> changes and we can determine the source of a regression.
>>> >> >> --
>>> >> >> Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
>>> >> >
>>> >> > This was done to push this patch to 3.3 and stable tree as well.
>>> >> > That's why it is in the start of series.
>>> >> >
>>> >> > If we decide not to push it for now, I agree that this patch should be
>>> >> > in the modified version (according to changes from other patches) at
>>> >> > the end of the series.
>>> >> >
>>> >> > Steve, your thoughts?
>>> >> >
>>> >> > --
>>> >> > Best regards,
>>> >> > Pavel Shilovsky.
>>> >>
>>> >> We want to fix the reported (cifs) problem first with a simple patch
>>> >> (that would be suitable for stable too).
>>> >>
>>> >> The most important reported problems are mounts to servers
>>> >> running some versions of Windows Vista and some versions of Windows 7
>>> >> which set maxmpx below 50 and more importantly have maxworkitems
>>> >> (in the windows registry on the server) set at too small a value to handle
>>> >> the 20 or 30 async reads or writes which are now often in flight to them.
>>> >>
>>> >> The fix we need first is to honor the maxmpx that the server sets (and
>>> >> probably remove cifs_max_pending which is obsolete as
>>> >> a global module parm or simply do the minimum of cifs_max_pending
>>> >> and maxmpx as the earlier patch did).
>>> >> If desired (to workaround buggy
>>> >> servers) in a second patch we could add a mount parm if we think there are
>>> >> servers such as windows 7 for which we will need to set the
>>> >> negotiated value lower (due to their maxworkitems registry
>>> >> problem), or Samba for which maxmpx could be ignored
>>> >> (and as JRA and others indicated - we could send
>>> >> a thousand requests in parallel).
>>> >>
>>> >
>>> > By the way...
>>> >
>>> > What's the plan for blocking locks and echoes here? Do you plan to make
>>> > them just ignore the maxmpx limit?
>>>
>>> I think we shouldn't play with them for stable. We still don't know
>>> what exactly we should do with them - really risky to make experiments
>>> on stable kernels.
>>>
>>
>> Then I'm confused, since you said this in your earlier email:
>>
>>> This was done to push this patch to 3.3 and stable tree as well.
>>> That's why it is in the start of series.
>>>
>>
>> If you're not worrying about stable (and I agree that it's premature to
>> do that here), then you should focus on converting everything to use
>> the new credit-based scheme first and only then introduce the behavior
>> change of respecting maxmpx.
>>
>>> So, as we are sure that exceeding negotiated maxmpx value with any
>>> request except blocking lock and echo is wrong, I suggest to fix this
>>> - it is what this patch (#1) does. When we get more information about
>>> blocking locks and echos we can fix this too.
>>>
>>
>> Well, according to what MS wrote back to Steve when he asked, exceeding
>> the maxmpx is wrong _period_, regardless of the call. Echoes are fairly
>> easy to deal with, but blocking locks are another matter entirely. I
>> believe we need a fundamental rethink there.
>
> I meant that playing with things like blocking locks and echos is too
> risky for stable. But if we can fix the existing stable problem (not
> respecting MaxMpxCount value by other commands) with a strait-forward
> patch like this - we should do it.
yes. agreed
--
Thanks,
Steve
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH v2 01/11] CIFS: Respect negotiated MaxMpxCount
[not found] ` <CAH2r5mvhTYPxvDRFCpQ0ULmDn2TNQ80ODbnvTmgFurptYukR1Q-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2012-03-19 19:39 ` Jeff Layton
0 siblings, 0 replies; 43+ messages in thread
From: Jeff Layton @ 2012-03-19 19:39 UTC (permalink / raw)
To: Steve French; +Cc: Pavel Shilovsky, linux-cifs-u79uwXL29TY76Z2rM5mHXA
On Mon, 19 Mar 2012 14:32:17 -0500
Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> On Mon, Mar 19, 2012 at 2:04 PM, Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> > 19 марта 2012 г. 19:04 пользователь Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> написал:
> >> On Sun, 18 Mar 2012 22:23:47 +0400
> >> Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> >>
> >>> 18 марта 2012 г. 14:50 пользователь Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> написал:
> >>> > On Sat, 17 Mar 2012 10:20:59 -0500
> >>> > Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> >>> >
> >>> >> On Sat, Mar 17, 2012 at 9:53 AM, Pavel Shilovsky <piastry@etersoft.ru> wrote:
> >>> >> > 17 марта 2012 г. 15:12 пользователь Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> написал:
> >>> >> >> On Fri, 16 Mar 2012 18:09:24 +0300
> >>> >> >> Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> >>> >> >>
> >>> >> >>> Some servers sets this value less than 50 that was hardcoded and
> >>> >> >>> we lost the connection if when we exceed this limit. Fix this by
> >>> >> >>> respecting this value - not sending more than the server allows.
> >>> >> >>>
> >>> >> >>> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
> >>> >> >>> ---
> >>> >> >>> fs/cifs/cifsfs.c | 8 ++++----
> >>> >> >>> fs/cifs/cifsglob.h | 10 +++-------
> >>> >> >>> fs/cifs/cifssmb.c | 9 +++++++--
> >>> >> >>> fs/cifs/connect.c | 11 ++++-------
> >>> >> >>> fs/cifs/dir.c | 6 ++++--
> >>> >> >>> fs/cifs/file.c | 4 ++--
> >>> >> >>> fs/cifs/transport.c | 4 ++--
> >>> >> >>
> >>> >> >> Introducing a behavior change like this at the beginning of the series
> >>> >> >> is probably a mistake. You'll have no reasonable way to bisect down
> >>> >> >> regressions, so you won't know if a problem is due to the change to a
> >>> >> >> credit-based model or due to changing the client to respect the maxmpx.
> >>> >> >>
> >>> >> >> Instead of doing this, we should instead reorganize the code around a
> >>> >> >> credit based model first, while attempting to mimic the existing
> >>> >> >> behavior as closely as possible. Once that framework is in place, then
> >>> >> >> change the behavior and start respecting the maxmpx.
> >>> >> >>
> >>> >> >> If you do that, then someone can reasonably bisect between those two
> >>> >> >> changes and we can determine the source of a regression.
> >>> >> >> --
> >>> >> >> Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
> >>> >> >
> >>> >> > This was done to push this patch to 3.3 and stable tree as well.
> >>> >> > That's why it is in the start of series.
> >>> >> >
> >>> >> > If we decide not to push it for now, I agree that this patch should be
> >>> >> > in the modified version (according to changes from other patches) at
> >>> >> > the end of the series.
> >>> >> >
> >>> >> > Steve, your thoughts?
> >>> >> >
> >>> >> > --
> >>> >> > Best regards,
> >>> >> > Pavel Shilovsky.
> >>> >>
> >>> >> We want to fix the reported (cifs) problem first with a simple patch
> >>> >> (that would be suitable for stable too).
> >>> >>
> >>> >> The most important reported problems are mounts to servers
> >>> >> running some versions of Windows Vista and some versions of Windows 7
> >>> >> which set maxmpx below 50 and more importantly have maxworkitems
> >>> >> (in the windows registry on the server) set at too small a value to handle
> >>> >> the 20 or 30 async reads or writes which are now often in flight to them.
> >>> >>
> >>> >> The fix we need first is to honor the maxmpx that the server sets (and
> >>> >> probably remove cifs_max_pending which is obsolete as
> >>> >> a global module parm or simply do the minimum of cifs_max_pending
> >>> >> and maxmpx as the earlier patch did).
> >>> >> If desired (to workaround buggy
> >>> >> servers) in a second patch we could add a mount parm if we think there are
> >>> >> servers such as windows 7 for which we will need to set the
> >>> >> negotiated value lower (due to their maxworkitems registry
> >>> >> problem), or Samba for which maxmpx could be ignored
> >>> >> (and as JRA and others indicated - we could send
> >>> >> a thousand requests in parallel).
> >>> >>
> >>> >
> >>> > By the way...
> >>> >
> >>> > What's the plan for blocking locks and echoes here? Do you plan to make
> >>> > them just ignore the maxmpx limit?
> >>>
> >>> I think we shouldn't play with them for stable. We still don't know
> >>> what exactly we should do with them - really risky to make experiments
> >>> on stable kernels.
> >>>
> >>
> >> Then I'm confused, since you said this in your earlier email:
> >>
> >>> This was done to push this patch to 3.3 and stable tree as well.
> >>> That's why it is in the start of series.
> >>>
> >>
> >> If you're not worrying about stable (and I agree that it's premature to
> >> do that here), then you should focus on converting everything to use
> >> the new credit-based scheme first and only then introduce the behavior
> >> change of respecting maxmpx.
> >>
> >>> So, as we are sure that exceeding negotiated maxmpx value with any
> >>> request except blocking lock and echo is wrong, I suggest to fix this
> >>> - it is what this patch (#1) does. When we get more information about
> >>> blocking locks and echos we can fix this too.
> >>>
> >>
> >> Well, according to what MS wrote back to Steve when he asked, exceeding
> >> the maxmpx is wrong _period_, regardless of the call. Echoes are fairly
> >> easy to deal with, but blocking locks are another matter entirely. I
> >> believe we need a fundamental rethink there.
> >
> > I meant that playing with things like blocking locks and echos is too
> > risky for stable. But if we can fix the existing stable problem (not
> > respecting MaxMpxCount value by other commands) with a strait-forward
> > patch like this - we should do it.
>
> yes. agreed
>
>
Fair enough. Given that the existing code just ignores this, that's
probably a reasonable first step.
One question though -- has anyone actually done any testing against
servers with a maxmpx of 1 with this patch? It would be good to have
some idea of how this behaves in the pessimal case...
--
Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH v2 08/11] CIFS: Separate protocol-specific code from demultiplex code
[not found] ` <1331910574-998-9-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
@ 2012-03-19 19:41 ` Jeff Layton
[not found] ` <20120319154150.03713caf-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
0 siblings, 1 reply; 43+ messages in thread
From: Jeff Layton @ 2012-03-19 19:41 UTC (permalink / raw)
To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA
On Fri, 16 Mar 2012 18:09:31 +0300
Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> 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 c3c7d7c..34a897e 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -730,7 +730,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 2d506e3..15c9b59 100644
> --- a/fs/cifs/cifsproto.h
> +++ b/fs/cifs/cifsproto.h
> @@ -91,9 +91,8 @@ extern int SendReceiveBlockingLock(const unsigned int xid,
> extern void cifs_add_credits(struct TCP_Server_Info *server,
> const unsigned int add);
> extern void cifs_set_credits(struct TCP_Server_Info *server, const int val);
> -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 4156351..76cffc9 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);
> +}
> +
I guess that eventually things like this will have a smb2 variant, and
you'll bundle them all up into a set of "transport ops" or something?
> +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 1578617..88459d0 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 7f63c44..d4c01b9 100644
> --- a/fs/cifs/transport.c
> +++ b/fs/cifs/transport.c
> @@ -785,7 +785,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:
> @@ -953,7 +953,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:
Either way, it looks reasonable...
Reviewed-by: Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH v2 09/11] CIFS: Separate protocol-specific code from cifs_readv_receive code
[not found] ` <1331910574-998-10-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
@ 2012-03-19 20:17 ` Jeff Layton
[not found] ` <20120319161728.1f8cec40-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
0 siblings, 1 reply; 43+ messages in thread
From: Jeff Layton @ 2012-03-19 20:17 UTC (permalink / raw)
To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA
On Fri, 16 Mar 2012 18:09:32 +0300
Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> 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 34a897e..a403398 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -341,6 +341,18 @@ has_credits(struct TCP_Server_Info *server, int *credits)
> return num > 0;
> }
>
> +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 15c9b59..db38a40 100644
> --- a/fs/cifs/cifsproto.h
> +++ b/fs/cifs/cifsproto.h
> @@ -106,7 +106,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 d3b8089..765f804 100644
> --- a/fs/cifs/cifssmb.c
> +++ b/fs/cifs/cifssmb.c
> @@ -1415,8 +1415,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;
>
> @@ -1425,7 +1424,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;
> @@ -1436,14 +1435,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;
> @@ -1456,10 +1476,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);
> @@ -1468,7 +1487,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);
> @@ -1476,14 +1495,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
> @@ -1507,7 +1526,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)
> @@ -1516,15 +1535,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);
> @@ -1603,11 +1621,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 76cffc9..3d46493 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;
You're changing the prototype of the above function, but are not
changing both of the callers. If you expect to pass different pointer
types in there in the future, then it might be best to call it a void
pointer instead of a char?
--
Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH v2 10/11] CIFS: Expand CurrentMid field
[not found] ` <1331910574-998-11-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
@ 2012-03-19 20:24 ` Jeff Layton
[not found] ` <20120319162410.42b95f13-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
0 siblings, 1 reply; 43+ messages in thread
From: Jeff Layton @ 2012-03-19 20:24 UTC (permalink / raw)
To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA
On Fri, 16 Mar 2012 18:09:33 +0300
Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> 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 a403398..b213458 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -282,7 +282,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 */
It occurs to me that a simpler way to do this might be to turn this
into a union with a u16 and u64 field. This works just as well though...
> 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 db38a40..8958721 100644
> --- a/fs/cifs/cifsproto.h
> +++ b/fs/cifs/cifsproto.h
> @@ -115,7 +115,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 88459d0..0b743b7 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;
Not directly related to this patch, but should we move all of these mid
operations under the req_lock instead of the GlobalMid_Lock? The global
spinlock is a bottleneck and all of the structures involved should be
per-server anyway.
Anyway, I think this looks ok
Reviewed-by: Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH v2 11/11] CIFS: Change mid_q_entry structure fields
[not found] ` <1331910574-998-12-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
@ 2012-03-19 20:28 ` Jeff Layton
0 siblings, 0 replies; 43+ messages in thread
From: Jeff Layton @ 2012-03-19 20:28 UTC (permalink / raw)
To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA
On Fri, 16 Mar 2012 18:09:34 +0300
Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> 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 b213458..d5ccd46 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -731,8 +731,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
> @@ -743,9 +743,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 765f804..2dbf7db 100644
> --- a/fs/cifs/cifssmb.c
> +++ b/fs/cifs/cifssmb.c
> @@ -1468,7 +1468,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);
>
> /*
> @@ -1666,10 +1666,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 &
> @@ -2088,7 +2088,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
> @@ -2099,7 +2099,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 3d46493..3bd4e77 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 0b743b7..5313d37 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 d4c01b9..751404f 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,
> @@ -341,7 +341,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;
>
> @@ -404,7 +404,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);
> @@ -454,11 +454,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;
> @@ -473,8 +473,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);
> @@ -617,7 +617,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);
> @@ -639,7 +639,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);
> @@ -659,7 +659,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;
> @@ -668,7 +668,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;
> @@ -742,7 +742,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));
> @@ -760,7 +760,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);
> @@ -779,7 +779,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;
> @@ -879,7 +879,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);
> @@ -893,13 +893,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))) {
>
> @@ -929,7 +929,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);
> @@ -947,7 +947,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
> return rc;
>
> /* 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;
Reviewed-by: Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH v2 10/11] CIFS: Expand CurrentMid field
[not found] ` <20120319162410.42b95f13-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
@ 2012-03-19 20:48 ` Steve French
[not found] ` <CAH2r5mujZook3O2Ojvu+vjx5Y5uYuormbtbDW69iOLEf1XVQgg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
0 siblings, 1 reply; 43+ messages in thread
From: Steve French @ 2012-03-19 20:48 UTC (permalink / raw)
To: Jeff Layton; +Cc: Pavel Shilovsky, linux-cifs-u79uwXL29TY76Z2rM5mHXA
On Mon, Mar 19, 2012 at 3:24 PM, Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> wrote:
> On Fri, 16 Mar 2012 18:09:33 +0300
> Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
>
>> 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 a403398..b213458 100644
>> --- a/fs/cifs/cifsglob.h
>> +++ b/fs/cifs/cifsglob.h
>> @@ -282,7 +282,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 */
>
> It occurs to me that a simpler way to do this might be to turn this
> into a union with a u16 and u64 field. This works just as well though...
>
>> 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 db38a40..8958721 100644
>> --- a/fs/cifs/cifsproto.h
>> +++ b/fs/cifs/cifsproto.h
>> @@ -115,7 +115,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 88459d0..0b743b7 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;
>
> Not directly related to this patch, but should we move all of these mid
> operations under the req_lock instead of the GlobalMid_Lock? The global
> spinlock is a bottleneck and all of the structures involved should be
> per-server anyway.
>
> Anyway, I think this looks ok
>
> Reviewed-by: Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
The idea of a union for these two key fields is worth thinking about
more - any more opinions from others on this?
--
Thanks,
Steve
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH v2 05/11] CIFS: Prepare credits code for a slot reservation
[not found] ` <20120319152702.3eee1608-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
@ 2012-03-20 7:03 ` Pavel Shilovsky
0 siblings, 0 replies; 43+ messages in thread
From: Pavel Shilovsky @ 2012-03-20 7:03 UTC (permalink / raw)
To: Jeff Layton; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA
19 марта 2012 г. 23:27 пользователь Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> написал:
> On Fri, 16 Mar 2012 18:09:28 +0300
> Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
>
>> that is essential for CIFS/SMB/SMB2 oplock breaks and SMB2 echos.
>>
>> Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
>> ---
>> fs/cifs/cifsglob.h | 14 ++++++++++++--
>> fs/cifs/transport.c | 22 ++++++++++++++--------
>> 2 files changed, 26 insertions(+), 10 deletions(-)
>>
>> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
>> index d55de96..2309a67 100644
>> --- a/fs/cifs/cifsglob.h
>> +++ b/fs/cifs/cifsglob.h
>> @@ -315,12 +315,22 @@ in_flight(struct TCP_Server_Info *server)
>> return num;
>> }
>>
>> +static inline int*
>> +get_credits_field(struct TCP_Server_Info *server)
>> +{
>> + /*
>> + * This will change to switch statement when we reserve slots for echos
>> + * and oplock breaks.
>> + */
>> + return &server->credits;
>> +}
>> +
>> static inline bool
>> -has_credits(struct TCP_Server_Info *server)
>> +has_credits(struct TCP_Server_Info *server, int *credits)
>
> Why are you passing "credits" by reference here? Might as well pass by
> value...
This was done because we need to be sure that we are doing credits
pointer dereferencing under server->req_lock - no one is changing it
at that time. We wake up by the signal, lock req_lock and then
dereference credits pointer (that may refer to reserved credits slot
in the future).
>
>> {
>> int num;
>> spin_lock(&server->req_lock);
>> - num = server->credits;
>> + num = *credits;
>> spin_unlock(&server->req_lock);
>> return num > 0;
>> }
>> diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
>> index 11787cc..20dc7ba 100644
>> --- a/fs/cifs/transport.c
>> +++ b/fs/cifs/transport.c
>> @@ -255,26 +255,26 @@ 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, const int optype,
>> + int *credits)
>> {
>> int rc;
>>
>> spin_lock(&server->req_lock);
>> -
>> - if (long_op == CIFS_ASYNC_OP) {
>> + if (optype == CIFS_ASYNC_OP) {
>> /* oplock breaks must not be held up */
>> server->in_flight++;
>> - server->credits--;
>> + *credits -= 1;
>> spin_unlock(&server->req_lock);
>> return 0;
>> }
>>
>> while (1) {
>> - if (server->credits <= 0) {
>> + if (*credits <= 0) {
>> spin_unlock(&server->req_lock);
>> cifs_num_waiters_inc(server);
>> rc = wait_event_killable(server->request_q,
>> - has_credits(server));
>> + has_credits(server, credits));
>> cifs_num_waiters_dec(server);
>> if (rc)
>> return rc;
>> @@ -291,8 +291,8 @@ wait_for_free_request(struct TCP_Server_Info *server, const int long_op)
>> */
>>
>> /* update # of requests on the wire to server */
>> - if (long_op != CIFS_BLOCKING_OP) {
>> - server->credits--;
>> + if (optype != CIFS_BLOCKING_OP) {
>> + *credits -= 1;
>> server->in_flight++;
>> }
>> spin_unlock(&server->req_lock);
>> @@ -302,6 +302,12 @@ wait_for_free_request(struct TCP_Server_Info *server, const int long_op)
>> return 0;
>> }
>>
>> +static int
>> +wait_for_free_request(struct TCP_Server_Info *server, const int optype)
>> +{
>> + return wait_for_free_credits(server, optype, get_credits_field(server));
>> +}
>> +
>> static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
>> struct mid_q_entry **ppmidQ)
>> {
>
>
> Other than that nit, this looks fine...
>
> Reviewed-by: Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
> --
> 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
--
Best regards,
Pavel Shilovsky.
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH v2 08/11] CIFS: Separate protocol-specific code from demultiplex code
[not found] ` <20120319154150.03713caf-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
@ 2012-03-20 7:29 ` Pavel Shilovsky
[not found] ` <CAKywueTxicF658ys1yBzC_95qw0v8R+6pxuhZ_zc+aRKyRLFdw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
0 siblings, 1 reply; 43+ messages in thread
From: Pavel Shilovsky @ 2012-03-20 7:29 UTC (permalink / raw)
To: Jeff Layton; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA
19 марта 2012 г. 23:41 пользователь Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> написал:
> On Fri, 16 Mar 2012 18:09:31 +0300
> Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
>
>> 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 c3c7d7c..34a897e 100644
>> --- a/fs/cifs/cifsglob.h
>> +++ b/fs/cifs/cifsglob.h
>> @@ -730,7 +730,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 2d506e3..15c9b59 100644
>> --- a/fs/cifs/cifsproto.h
>> +++ b/fs/cifs/cifsproto.h
>> @@ -91,9 +91,8 @@ extern int SendReceiveBlockingLock(const unsigned int xid,
>> extern void cifs_add_credits(struct TCP_Server_Info *server,
>> const unsigned int add);
>> extern void cifs_set_credits(struct TCP_Server_Info *server, const int val);
>> -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 4156351..76cffc9 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);
>> +}
>> +
>
> I guess that eventually things like this will have a smb2 variant, and
> you'll bundle them all up into a set of "transport ops" or something?
Now I modify these functions for SMB2 code to this variant:
static inline size_t
header_size(server)
{
#ifdef CONFIG_CIFS_SMB2
if (server->is_smb2)
return sizeof(struct smb2_hdr);
#endif
return sizeof(struct smb_hdr);
}
But having smth like:
struct TCP_Server_Info {
...
struct cifs_transport_ops *t_ops;
...
}
and then using server->t_ops->header_size() looks better.
I also have an idea to have such ops structures for cifsFileInfo and
cifsInodeInfo pointers. I think this let us make the code cleaner.
(Now I use ifdefs and callbacks to share the code between cifs and
smb2). Thoughts?
>
>> +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 1578617..88459d0 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 7f63c44..d4c01b9 100644
>> --- a/fs/cifs/transport.c
>> +++ b/fs/cifs/transport.c
>> @@ -785,7 +785,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:
>> @@ -953,7 +953,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:
>
> Either way, it looks reasonable...
>
> Reviewed-by: Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
> --
> 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
--
Best regards,
Pavel Shilovsky.
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH v2 09/11] CIFS: Separate protocol-specific code from cifs_readv_receive code
[not found] ` <20120319161728.1f8cec40-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
@ 2012-03-20 7:33 ` Pavel Shilovsky
[not found] ` <CAKywueSvsb+BP7ktb0QEgL3WmrO8j42bicvd-WjWNro6qGRc7w-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
0 siblings, 1 reply; 43+ messages in thread
From: Pavel Shilovsky @ 2012-03-20 7:33 UTC (permalink / raw)
To: Jeff Layton; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA
20 марта 2012 г. 0:17 пользователь Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> написал:
> On Fri, 16 Mar 2012 18:09:32 +0300
> Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
>
>> 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 34a897e..a403398 100644
>> --- a/fs/cifs/cifsglob.h
>> +++ b/fs/cifs/cifsglob.h
>> @@ -341,6 +341,18 @@ has_credits(struct TCP_Server_Info *server, int *credits)
>> return num > 0;
>> }
>>
>> +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 15c9b59..db38a40 100644
>> --- a/fs/cifs/cifsproto.h
>> +++ b/fs/cifs/cifsproto.h
>> @@ -106,7 +106,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 d3b8089..765f804 100644
>> --- a/fs/cifs/cifssmb.c
>> +++ b/fs/cifs/cifssmb.c
>> @@ -1415,8 +1415,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;
>>
>> @@ -1425,7 +1424,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;
>> @@ -1436,14 +1435,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;
>> @@ -1456,10 +1476,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);
>> @@ -1468,7 +1487,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);
>> @@ -1476,14 +1495,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
>> @@ -1507,7 +1526,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)
>> @@ -1516,15 +1535,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);
>> @@ -1603,11 +1621,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 76cffc9..3d46493 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;
>
> You're changing the prototype of the above function, but are not
> changing both of the callers. If you expect to pass different pointer
> types in there in the future, then it might be best to call it a void
> pointer instead of a char?
The first caller is cifs_readv_receive and it passes char pointer -
ok. The second caller is cifs_check_receive - passes void pointer - ok
too.
--
Best regards,
Pavel Shilovsky.
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH v2 10/11] CIFS: Expand CurrentMid field
[not found] ` <CAH2r5mujZook3O2Ojvu+vjx5Y5uYuormbtbDW69iOLEf1XVQgg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2012-03-20 7:37 ` Pavel Shilovsky
[not found] ` <CAKywueTpa6Hmz7oQ=8S1ViRU9ky7wqhKN+f=eaWrJY1457X86w-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
0 siblings, 1 reply; 43+ messages in thread
From: Pavel Shilovsky @ 2012-03-20 7:37 UTC (permalink / raw)
To: Steve French; +Cc: Jeff Layton, linux-cifs-u79uwXL29TY76Z2rM5mHXA
20 марта 2012 г. 0:48 пользователь Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> написал:
> On Mon, Mar 19, 2012 at 3:24 PM, Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> wrote:
>> On Fri, 16 Mar 2012 18:09:33 +0300
>> Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
>>
>>> 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 a403398..b213458 100644
>>> --- a/fs/cifs/cifsglob.h
>>> +++ b/fs/cifs/cifsglob.h
>>> @@ -282,7 +282,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 */
>>
>> It occurs to me that a simpler way to do this might be to turn this
>> into a union with a u16 and u64 field. This works just as well though...
>>
>>> 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 db38a40..8958721 100644
>>> --- a/fs/cifs/cifsproto.h
>>> +++ b/fs/cifs/cifsproto.h
>>> @@ -115,7 +115,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 88459d0..0b743b7 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;
>>
>> Not directly related to this patch, but should we move all of these mid
>> operations under the req_lock instead of the GlobalMid_Lock? The global
>> spinlock is a bottleneck and all of the structures involved should be
>> per-server anyway.
>>
>> Anyway, I think this looks ok
>>
>> Reviewed-by: Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
>
> The idea of a union for these two key fields is worth thinking about
> more - any more opinions from others on this?
>
I think our main goal is to make to code is cleaner as possible. If we
change this to a union we can't use the same codepath for both
protocols - more protocol specific code - harder to understand, fix
bugs, etc.
--
Best regards,
Pavel Shilovsky.
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH v2 08/11] CIFS: Separate protocol-specific code from demultiplex code
[not found] ` <CAKywueTxicF658ys1yBzC_95qw0v8R+6pxuhZ_zc+aRKyRLFdw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2012-03-20 10:22 ` Jeff Layton
0 siblings, 0 replies; 43+ messages in thread
From: Jeff Layton @ 2012-03-20 10:22 UTC (permalink / raw)
To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA
On Tue, 20 Mar 2012 11:29:45 +0400
Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> 19 марта 2012 г. 23:41 пользователь Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> написал:
> > On Fri, 16 Mar 2012 18:09:31 +0300
> > Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> >
> >> 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 c3c7d7c..34a897e 100644
> >> --- a/fs/cifs/cifsglob.h
> >> +++ b/fs/cifs/cifsglob.h
> >> @@ -730,7 +730,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 2d506e3..15c9b59 100644
> >> --- a/fs/cifs/cifsproto.h
> >> +++ b/fs/cifs/cifsproto.h
> >> @@ -91,9 +91,8 @@ extern int SendReceiveBlockingLock(const unsigned int xid,
> >> extern void cifs_add_credits(struct TCP_Server_Info *server,
> >> const unsigned int add);
> >> extern void cifs_set_credits(struct TCP_Server_Info *server, const int val);
> >> -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 4156351..76cffc9 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);
> >> +}
> >> +
> >
> > I guess that eventually things like this will have a smb2 variant, and
> > you'll bundle them all up into a set of "transport ops" or something?
>
> Now I modify these functions for SMB2 code to this variant:
>
> static inline size_t
> header_size(server)
> {
> #ifdef CONFIG_CIFS_SMB2
> if (server->is_smb2)
> return sizeof(struct smb2_hdr);
> #endif
> return sizeof(struct smb_hdr);
> }
>
> But having smth like:
>
> struct TCP_Server_Info {
> ...
> struct cifs_transport_ops *t_ops;
> ...
> }
>
> and then using server->t_ops->header_size() looks better.
>
> I also have an idea to have such ops structures for cifsFileInfo and
> cifsInodeInfo pointers. I think this let us make the code cleaner.
> (Now I use ifdefs and callbacks to share the code between cifs and
> smb2). Thoughts?
>
Yes, that would be much cleaner and more efficient too. Just set the
transport ops when the connection is negotiated and then call the
appropriate one in the appropriate situation.
That also makes it easier to deal with protocol changes in the future.
If you need a different operation for 2.0 vs. 2.2 then you can just
create different ops there and call the right one.
If you look at the NFS client code, then you'll see that that's how it
handles the different protocols too -- see struct nfs_rpc_ops. That
model has worked well over the years. We ought to do something similar
here.
--
Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH v2 09/11] CIFS: Separate protocol-specific code from cifs_readv_receive code
[not found] ` <CAKywueSvsb+BP7ktb0QEgL3WmrO8j42bicvd-WjWNro6qGRc7w-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2012-03-20 10:24 ` Jeff Layton
[not found] ` <20120320062414.554a033c-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
0 siblings, 1 reply; 43+ messages in thread
From: Jeff Layton @ 2012-03-20 10:24 UTC (permalink / raw)
To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA
On Tue, 20 Mar 2012 11:33:42 +0400
Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> 20 марта 2012 г. 0:17 пользователь Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> написал:
> > On Fri, 16 Mar 2012 18:09:32 +0300
> > Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> >
> >> 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 34a897e..a403398 100644
> >> --- a/fs/cifs/cifsglob.h
> >> +++ b/fs/cifs/cifsglob.h
> >> @@ -341,6 +341,18 @@ has_credits(struct TCP_Server_Info *server, int *credits)
> >> return num > 0;
> >> }
> >>
> >> +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 15c9b59..db38a40 100644
> >> --- a/fs/cifs/cifsproto.h
> >> +++ b/fs/cifs/cifsproto.h
> >> @@ -106,7 +106,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 d3b8089..765f804 100644
> >> --- a/fs/cifs/cifssmb.c
> >> +++ b/fs/cifs/cifssmb.c
> >> @@ -1415,8 +1415,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;
> >>
> >> @@ -1425,7 +1424,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;
> >> @@ -1436,14 +1435,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;
> >> @@ -1456,10 +1476,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);
> >> @@ -1468,7 +1487,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);
> >> @@ -1476,14 +1495,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
> >> @@ -1507,7 +1526,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)
> >> @@ -1516,15 +1535,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);
> >> @@ -1603,11 +1621,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 76cffc9..3d46493 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;
> >
> > You're changing the prototype of the above function, but are not
> > changing both of the callers. If you expect to pass different pointer
> > types in there in the future, then it might be best to call it a void
> > pointer instead of a char?
>
> The first caller is cifs_readv_receive and it passes char pointer -
> ok. The second caller is cifs_check_receive - passes void pointer - ok
> too.
>
In my tree, cifs_check_receive does this:
return map_smb_to_linux_error(mid->resp_buf, log_error);
...and mid->resp_buf is:
struct smb_hdr *resp_buf; /* pointer to received SMB header */
...not a void pointer.
--
Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH v2 10/11] CIFS: Expand CurrentMid field
[not found] ` <CAKywueTpa6Hmz7oQ=8S1ViRU9ky7wqhKN+f=eaWrJY1457X86w-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2012-03-20 10:28 ` Jeff Layton
[not found] ` <20120320062843.1cd218ed-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
0 siblings, 1 reply; 43+ messages in thread
From: Jeff Layton @ 2012-03-20 10:28 UTC (permalink / raw)
To: Pavel Shilovsky; +Cc: Steve French, linux-cifs-u79uwXL29TY76Z2rM5mHXA
On Tue, 20 Mar 2012 11:37:27 +0400
Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> 20 марта 2012 г. 0:48 пользователь Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> написал:
> > On Mon, Mar 19, 2012 at 3:24 PM, Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> wrote:
> >> On Fri, 16 Mar 2012 18:09:33 +0300
> >> Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
> >>
> >>> 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 a403398..b213458 100644
> >>> --- a/fs/cifs/cifsglob.h
> >>> +++ b/fs/cifs/cifsglob.h
> >>> @@ -282,7 +282,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 */
> >>
> >> It occurs to me that a simpler way to do this might be to turn this
> >> into a union with a u16 and u64 field. This works just as well though...
> >>
> >>> 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 db38a40..8958721 100644
> >>> --- a/fs/cifs/cifsproto.h
> >>> +++ b/fs/cifs/cifsproto.h
> >>> @@ -115,7 +115,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 88459d0..0b743b7 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;
> >>
> >> Not directly related to this patch, but should we move all of these mid
> >> operations under the req_lock instead of the GlobalMid_Lock? The global
> >> spinlock is a bottleneck and all of the structures involved should be
> >> per-server anyway.
> >>
> >> Anyway, I think this looks ok
> >>
> >> Reviewed-by: Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
> >
> > The idea of a union for these two key fields is worth thinking about
> > more - any more opinions from others on this?
> >
>
> I think our main goal is to make to code is cleaner as possible. If we
> change this to a union we can't use the same codepath for both
> protocols - more protocol specific code - harder to understand, fix
> bugs, etc.
>
>
You're going to need some bit of separate code in order to deal with
the differences in field width in things like the MID. The question is
how to abstract that code out. It's probably cleaner to do so with an
ops struct of some sort rather than sprinkling "if (server->is_smb2)"
all over the code.
Once you design the code around that sort of idea, then using a union
may be cleaner, but you'll have to make that judgment as you proceed...
--
Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH v2 09/11] CIFS: Separate protocol-specific code from cifs_readv_receive code
[not found] ` <20120320062414.554a033c-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
@ 2012-03-20 10:54 ` Pavel Shilovsky
0 siblings, 0 replies; 43+ messages in thread
From: Pavel Shilovsky @ 2012-03-20 10:54 UTC (permalink / raw)
To: Jeff Layton; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA
20 марта 2012 г. 14:24 пользователь Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> написал:
> On Tue, 20 Mar 2012 11:33:42 +0400
> Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
>
>> 20 марта 2012 г. 0:17 пользователь Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> написал:
>> > On Fri, 16 Mar 2012 18:09:32 +0300
>> > Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
>> >
>> >> 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 34a897e..a403398 100644
>> >> --- a/fs/cifs/cifsglob.h
>> >> +++ b/fs/cifs/cifsglob.h
>> >> @@ -341,6 +341,18 @@ has_credits(struct TCP_Server_Info *server, int *credits)
>> >> return num > 0;
>> >> }
>> >>
>> >> +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 15c9b59..db38a40 100644
>> >> --- a/fs/cifs/cifsproto.h
>> >> +++ b/fs/cifs/cifsproto.h
>> >> @@ -106,7 +106,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 d3b8089..765f804 100644
>> >> --- a/fs/cifs/cifssmb.c
>> >> +++ b/fs/cifs/cifssmb.c
>> >> @@ -1415,8 +1415,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;
>> >>
>> >> @@ -1425,7 +1424,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;
>> >> @@ -1436,14 +1435,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;
>> >> @@ -1456,10 +1476,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);
>> >> @@ -1468,7 +1487,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);
>> >> @@ -1476,14 +1495,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
>> >> @@ -1507,7 +1526,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)
>> >> @@ -1516,15 +1535,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);
>> >> @@ -1603,11 +1621,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 76cffc9..3d46493 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;
>> >
>> > You're changing the prototype of the above function, but are not
>> > changing both of the callers. If you expect to pass different pointer
>> > types in there in the future, then it might be best to call it a void
>> > pointer instead of a char?
>>
>> The first caller is cifs_readv_receive and it passes char pointer -
>> ok. The second caller is cifs_check_receive - passes void pointer - ok
>> too.
>>
>
> In my tree, cifs_check_receive does this:
>
> return map_smb_to_linux_error(mid->resp_buf, log_error);
>
> ...and mid->resp_buf is:
>
> struct smb_hdr *resp_buf; /* pointer to received SMB header */
>
> ...not a void pointer.
>
Oh - yes, thanks - will respin it soon.
--
Best regards,
Pavel Shilovsky.
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH v2 10/11] CIFS: Expand CurrentMid field
[not found] ` <20120320062843.1cd218ed-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
@ 2012-03-20 22:21 ` Steve French
0 siblings, 0 replies; 43+ messages in thread
From: Steve French @ 2012-03-20 22:21 UTC (permalink / raw)
To: Jeff Layton; +Cc: Pavel Shilovsky, linux-cifs-u79uwXL29TY76Z2rM5mHXA
On Tue, Mar 20, 2012 at 5:28 AM, Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> wrote:
> On Tue, 20 Mar 2012 11:37:27 +0400
> Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
>
>> 20 марта 2012 г. 0:48 пользователь Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> написал:
>> > On Mon, Mar 19, 2012 at 3:24 PM, Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> wrote:
>> >> On Fri, 16 Mar 2012 18:09:33 +0300
>> >> Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org> wrote:
>> >>
>> >>> 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 a403398..b213458 100644
>> >>> --- a/fs/cifs/cifsglob.h
>> >>> +++ b/fs/cifs/cifsglob.h
>> >>> @@ -282,7 +282,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 */
>> >>
>> >> It occurs to me that a simpler way to do this might be to turn this
>> >> into a union with a u16 and u64 field. This works just as well though...
>> >>
>> >>> 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 db38a40..8958721 100644
>> >>> --- a/fs/cifs/cifsproto.h
>> >>> +++ b/fs/cifs/cifsproto.h
>> >>> @@ -115,7 +115,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 88459d0..0b743b7 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;
>> >>
>> >> Not directly related to this patch, but should we move all of these mid
>> >> operations under the req_lock instead of the GlobalMid_Lock? The global
>> >> spinlock is a bottleneck and all of the structures involved should be
>> >> per-server anyway.
>> >>
>> >> Anyway, I think this looks ok
>> >>
>> >> Reviewed-by: Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
>> >
>> > The idea of a union for these two key fields is worth thinking about
>> > more - any more opinions from others on this?
>> >
>>
>> I think our main goal is to make to code is cleaner as possible. If we
>> change this to a union we can't use the same codepath for both
>> protocols - more protocol specific code - harder to understand, fix
>> bugs, etc.
>>
>>
>
> You're going to need some bit of separate code in order to deal with
> the differences in field width in things like the MID. The question is
> how to abstract that code out. It's probably cleaner to do so with an
> ops struct of some sort rather than sprinkling "if (server->is_smb2)"
> all over the code.
>
> Once you design the code around that sort of idea, then using a union
> may be cleaner, but you'll have to make that judgment as you proceed...
Yes - probably right that this will change a few times as we figure
out what is cleaner.
--
Thanks,
Steve
^ permalink raw reply [flat|nested] 43+ messages in thread
end of thread, other threads:[~2012-03-20 22:21 UTC | newest]
Thread overview: 43+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-03-16 15:09 [PATCH v2 00/11] Prepare transport code for future SMB2 usage Pavel Shilovsky
[not found] ` <1331910574-998-1-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-03-16 15:09 ` [PATCH v2 01/11] CIFS: Respect negotiated MaxMpxCount Pavel Shilovsky
[not found] ` <1331910574-998-2-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-03-17 11:12 ` Jeff Layton
[not found] ` <20120317071201.7f28683b-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
2012-03-17 14:53 ` Pavel Shilovsky
[not found] ` <CAKywueTDsGhcHiGM_uX6V0dnY3m_W4kD2qcb+JWRq=UVnBnvPw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-03-17 15:20 ` Steve French
[not found] ` <CAH2r5msMKiEyS2-ak2+tQoRFommSHRcCNwp-J+XtgovmSae7-A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-03-18 10:33 ` Jeff Layton
2012-03-18 10:50 ` Jeff Layton
[not found] ` <20120318065059.62592afb-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
2012-03-18 18:23 ` Pavel Shilovsky
[not found] ` <CAKywueSrGVvwqHbTK3sNLsHDx3vR6U0Ca712ZXKNTnjnOgPGDA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-03-19 15:04 ` Jeff Layton
[not found] ` <20120319110437.635ea546-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
2012-03-19 19:04 ` Pavel Shilovsky
[not found] ` <CAKywueR2mWNKxNDhhj_0i0TfiPz3nmvVBXbxGMZ+Lrbgts3cDQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-03-19 19:32 ` Steve French
[not found] ` <CAH2r5mvhTYPxvDRFCpQ0ULmDn2TNQ80ODbnvTmgFurptYukR1Q-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-03-19 19:39 ` Jeff Layton
2012-03-16 15:09 ` [PATCH v2 02/11] CIFS: Simplify inFlight logic Pavel Shilovsky
[not found] ` <1331910574-998-3-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-03-17 11:07 ` Jeff Layton
2012-03-16 15:09 ` [PATCH v2 03/11] CIFS: Introduce credit-based flow control Pavel Shilovsky
[not found] ` <1331910574-998-4-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-03-17 10:32 ` Jeff Layton
[not found] ` <20120317063258.77618c0e-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
2012-03-17 14:56 ` Pavel Shilovsky
2012-03-16 15:09 ` [PATCH v2 04/11] CIFS: Make wait_for_free_request killable Pavel Shilovsky
[not found] ` <1331910574-998-5-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-03-17 11:13 ` Jeff Layton
2012-03-16 15:09 ` [PATCH v2 05/11] CIFS: Prepare credits code for a slot reservation Pavel Shilovsky
[not found] ` <1331910574-998-6-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-03-19 19:27 ` Jeff Layton
[not found] ` <20120319152702.3eee1608-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2012-03-20 7:03 ` Pavel Shilovsky
2012-03-16 15:09 ` [PATCH v2 06/11] CIFS: Delete echo_retries module parm Pavel Shilovsky
[not found] ` <1331910574-998-7-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-03-18 10:30 ` Jeff Layton
2012-03-16 15:09 ` [PATCH v2 07/11] CIFS: Separate protocol-specific code from transport routines Pavel Shilovsky
[not found] ` <1331910574-998-8-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-03-19 19:31 ` Jeff Layton
2012-03-16 15:09 ` [PATCH v2 08/11] CIFS: Separate protocol-specific code from demultiplex code Pavel Shilovsky
[not found] ` <1331910574-998-9-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-03-19 19:41 ` Jeff Layton
[not found] ` <20120319154150.03713caf-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2012-03-20 7:29 ` Pavel Shilovsky
[not found] ` <CAKywueTxicF658ys1yBzC_95qw0v8R+6pxuhZ_zc+aRKyRLFdw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-03-20 10:22 ` Jeff Layton
2012-03-16 15:09 ` [PATCH v2 09/11] CIFS: Separate protocol-specific code from cifs_readv_receive code Pavel Shilovsky
[not found] ` <1331910574-998-10-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-03-19 20:17 ` Jeff Layton
[not found] ` <20120319161728.1f8cec40-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2012-03-20 7:33 ` Pavel Shilovsky
[not found] ` <CAKywueSvsb+BP7ktb0QEgL3WmrO8j42bicvd-WjWNro6qGRc7w-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-03-20 10:24 ` Jeff Layton
[not found] ` <20120320062414.554a033c-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
2012-03-20 10:54 ` Pavel Shilovsky
2012-03-16 15:09 ` [PATCH v2 10/11] CIFS: Expand CurrentMid field Pavel Shilovsky
[not found] ` <1331910574-998-11-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-03-19 20:24 ` Jeff Layton
[not found] ` <20120319162410.42b95f13-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2012-03-19 20:48 ` Steve French
[not found] ` <CAH2r5mujZook3O2Ojvu+vjx5Y5uYuormbtbDW69iOLEf1XVQgg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-03-20 7:37 ` Pavel Shilovsky
[not found] ` <CAKywueTpa6Hmz7oQ=8S1ViRU9ky7wqhKN+f=eaWrJY1457X86w-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-03-20 10:28 ` Jeff Layton
[not found] ` <20120320062843.1cd218ed-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
2012-03-20 22:21 ` Steve French
2012-03-16 15:09 ` [PATCH v2 11/11] CIFS: Change mid_q_entry structure fields Pavel Shilovsky
[not found] ` <1331910574-998-12-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2012-03-19 20:28 ` Jeff Layton
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.