]> git.itanic.dy.fi Git - linux-stable/commitdiff
CIFS: Respect negotiated MaxMpxCount
authorPavel Shilovsky <piastry@etersoft.ru>
Tue, 20 Mar 2012 09:55:09 +0000 (12:55 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 2 Apr 2012 17:32:07 +0000 (10:32 -0700)
commit 10b9b98e41ba248a899f6175ce96ee91431b6194 upstream.

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.

Reviewed-by: Jeff Layton <jlayton@samba.org>
Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru>
Signed-off-by: Steve French <smfrench@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/cifs/cifsfs.c
fs/cifs/cifsglob.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/dir.c
fs/cifs/file.c
fs/cifs/transport.c

index b1fd382d19529c798e1554b3a42ec16b36935554..6ee1cb45ca0d751a29b9e0c0a96f288c299cde33 100644 (file)
@@ -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();
index 76e7d8b6da171c6af1d8cb8466c9bfbc77d00dbf..d47d20aac6703c2a4562cf8bb40cf3da9db02165 100644 (file)
 
 /*
  * 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 */
index 8b7794c315919c5328a5bffbcb2aa5a9d7ad5b30..cd66b76e3282e7bfa8768c23a9ed211cacdeec40 100644 (file)
@@ -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);
index 602f77c304c90fc402c9ec221eff2b78be818081..03f71fb40a8a8a84e0cd31c00275ac1e2132f83f 100644 (file)
@@ -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);
index bc7e24420ac0bee0ac2cab03e96224d1edf4adc7..d172c8ed901786f9e72ee40a50cb6bc22a3be571 100644 (file)
@@ -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.
index 5e64748a29173d75ad976c0375f7152d5ae0171d..4aa6080e95bc58208211b859b9e901ec833bab5b 100644 (file)
@@ -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;
index 0cc9584f5889f051208a00bb346869d73f6ed1ba..99a27cfa6cd2cec5f43582ebb90d80ddae6fd962 100644 (file)
@@ -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 {