Signed-off-by: Pavel Shilovsky <[email protected]>
---
 fs/cifs/cifsglob.h |    1 +
 fs/cifs/cifssmb.c  |    7 +++++--
 fs/cifs/file.c     |   29 +++++++++++++++++++++++++++--
 fs/cifs/smb2ops.c  |    5 -----
 fs/cifs/smb2pdu.c  |   15 +++++++++++++--
 5 files changed, 46 insertions(+), 11 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 3e5ab4e..c76e5ec 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -968,6 +968,7 @@ struct cifs_readdata {
        struct kvec                     iov;
        unsigned int                    pagesz;
        unsigned int                    tailsz;
+       unsigned int                    credits;
        unsigned int                    nr_pages;
        struct page                     *pages[];
 };
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 75e9c87..58ced1f 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1575,7 +1575,7 @@ cifs_readv_callback(struct mid_q_entry *mid)
 int
 cifs_async_readv(struct cifs_readdata *rdata)
 {
-       int rc;
+       int rc, flags = 0;
        READ_REQ *smb = NULL;
        int wct;
        struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
@@ -1623,9 +1623,12 @@ cifs_async_readv(struct cifs_readdata *rdata)
        rdata->iov.iov_base = smb;
        rdata->iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
 
+       if (rdata->credits)
+               flags = CIFS_HAS_CREDITS;
+
        kref_get(&rdata->refcount);
        rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
-                            cifs_readv_callback, rdata, 0);
+                            cifs_readv_callback, rdata, flags);
 
        if (rc == 0)
                cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 99c7532..2aa4f6e 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -2669,9 +2669,11 @@ cifs_iovec_read(struct file *file, const struct iovec 
*iov,
        unsigned int npages;
        struct cifs_sb_info *cifs_sb;
        struct cifs_tcon *tcon;
+       struct TCP_Server_Info *server;
        struct cifsFileInfo *open_file;
        struct cifs_readdata *rdata, *tmp;
        struct list_head rdata_list;
+       unsigned int rsize, credits;
        pid_t pid;
 
        if (!nr_segs)
@@ -2685,8 +2687,9 @@ cifs_iovec_read(struct file *file, const struct iovec 
*iov,
        cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
        open_file = file->private_data;
        tcon = tlink_tcon(open_file->tlink);
+       server = tcon->ses->server;
 
-       if (!tcon->ses->server->ops->async_readv)
+       if (!server->ops->async_readv)
                return -ENOSYS;
 
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
@@ -2698,7 +2701,10 @@ cifs_iovec_read(struct file *file, const struct iovec 
*iov,
                cFYI(1, "attempting read on write only file instance");
 
        do {
-               cur_len = min_t(const size_t, len - total_read, cifs_sb->rsize);
+               rc = server->ops->wait_mtu_credits(server, cifs_sb->rsize,
+                                                  &rsize, &credits);
+
+               cur_len = min_t(const size_t, len - total_read, rsize);
                npages = DIV_ROUND_UP(cur_len, PAGE_SIZE);
 
                /* allocate a readdata struct */
@@ -2709,6 +2715,8 @@ cifs_iovec_read(struct file *file, const struct iovec 
*iov,
                        goto error;
                }
 
+               rdata->credits = credits;
+
                rc = cifs_read_allocate_pages(rdata, npages);
                if (rc)
                        goto error;
@@ -2726,6 +2734,8 @@ error:
                if (rc) {
                        kref_put(&rdata->refcount,
                                 cifs_uncached_readdata_release);
+                       add_credits(server, credits, 0);
+                       wake_up(&server->request_q);
                        break;
                }
 
@@ -3068,6 +3078,7 @@ static int cifs_readpages(struct file *file, struct 
address_space *mapping,
        struct cifsFileInfo *open_file = file->private_data;
        struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
        unsigned int rsize = cifs_sb->rsize;
+       struct TCP_Server_Info *server;
        pid_t pid;
 
        /*
@@ -3095,6 +3106,7 @@ static int cifs_readpages(struct file *file, struct 
address_space *mapping,
 
        rc = 0;
        INIT_LIST_HEAD(&tmplist);
+       server = tlink_tcon(open_file->tlink)->ses->server;
 
        cFYI(1, "%s: file=%p mapping=%p num_pages=%u", __func__, file,
                mapping, num_pages);
@@ -3118,6 +3130,12 @@ static int cifs_readpages(struct file *file, struct 
address_space *mapping,
                loff_t offset;
                struct page *page, *tpage;
                struct cifs_readdata *rdata;
+               unsigned credits;
+
+               rc = server->ops->wait_mtu_credits(server, rsize, &rsize,
+                                                  &credits);
+               if (rc)
+                       break;
 
                page = list_entry(page_list->prev, struct page, lru);
 
@@ -3133,6 +3151,8 @@ static int cifs_readpages(struct file *file, struct 
address_space *mapping,
                /* give up if we can't stick it in the cache */
                if (rc) {
                        __clear_page_locked(page);
+                       add_credits(server, credits, 0);
+                       wake_up(&server->request_q);
                        break;
                }
 
@@ -3140,6 +3160,7 @@ static int cifs_readpages(struct file *file, struct 
address_space *mapping,
                offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
                list_move_tail(&page->lru, &tmplist);
 
+
                /* now try and add more pages onto the request */
                expected_index = page->index + 1;
                list_for_each_entry_safe_reverse(page, tpage, page_list, lru) {
@@ -3173,9 +3194,13 @@ static int cifs_readpages(struct file *file, struct 
address_space *mapping,
                                page_cache_release(page);
                        }
                        rc = -ENOMEM;
+                       add_credits(server, credits, 0);
+                       wake_up(&server->request_q);
                        break;
                }
 
+               rdata->credits = credits;
+
                rdata->cfile = cifsFileInfo_get(open_file);
                rdata->mapping = mapping;
                rdata->offset = offset;
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 8b93f03..6692e84 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -235,11 +235,6 @@ smb2_negotiate_rsize(struct cifs_tcon *tcon, struct 
smb_vol *volume_info)
        /* start with specified rsize, or default */
        rsize = volume_info->rsize ? volume_info->rsize : CIFS_DEFAULT_IOSIZE;
        rsize = min_t(unsigned int, rsize, server->max_read);
-       /*
-        * limit write size to 2 ** 16, because we don't support multicredit
-        * requests now.
-        */
-       rsize = min_t(unsigned int, rsize, 2 << 15);
 
        return rsize;
 }
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 6fc41b8..86489d3 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1455,11 +1455,12 @@ smb2_readv_callback(struct mid_q_entry *mid)
 int
 smb2_async_readv(struct cifs_readdata *rdata)
 {
-       int rc;
+       int rc, flags = 0;
        struct smb2_hdr *buf;
        struct cifs_io_parms io_parms;
        struct smb_rqst rqst = { .rq_iov = &rdata->iov,
                                 .rq_nvec = 1 };
+       struct TCP_Server_Info *server;
 
        cFYI(1, "%s: offset=%llu bytes=%u", __func__,
                rdata->offset, rdata->bytes);
@@ -1474,14 +1475,24 @@ smb2_async_readv(struct cifs_readdata *rdata)
        if (rc)
                return rc;
 
+       server = io_parms.tcon->ses->server;
        buf = (struct smb2_hdr *)rdata->iov.iov_base;
        /* 4 for rfc1002 length field */
        rdata->iov.iov_len = get_rfc1002_length(rdata->iov.iov_base) + 4;
 
+       if (rdata->credits) {
+               buf->CreditCharge =
+                       cpu_to_le16(DIV_ROUND_UP(rdata->bytes, 2 << 15));
+               add_credits(server,
+                       rdata->credits - le16_to_cpu(buf->CreditCharge), 0);
+               wake_up(&server->request_q);
+               flags = CIFS_HAS_CREDITS;
+       }
+
        kref_get(&rdata->refcount);
        rc = cifs_call_async(io_parms.tcon->ses->server, &rqst,
                             cifs_readv_receive, smb2_readv_callback,
-                            rdata, 0);
+                            rdata, flags);
        if (rc)
                kref_put(&rdata->refcount, cifs_readdata_release);
 
-- 
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to