CIFS: Respect reconnect in MTU credits calculations
authorPavel Shilovsky <pshilov@microsoft.com>
Wed, 16 Jan 2019 19:12:41 +0000 (11:12 -0800)
committerSteve French <stfrench@microsoft.com>
Wed, 6 Mar 2019 00:10:01 +0000 (18:10 -0600)
Every time after a session reconnect we don't need to account for
credits obtained in previous sessions. Introduce new struct cifs_credits
which contains both credits value and reconnect instance of the
time those credits were taken. Modify a routine that add credits
back to handle the reconnect instance by assuming zero credits
if the reconnect happened after the credits were obtained and
before we decided to add them back due to some errors during sending.

This patch fixes the MTU credits cases. The subsequent patch
will handle non-MTU ones.

Signed-off-by: Pavel Shilovsky <pshilov@microsoft.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/connect.c
fs/cifs/file.c
fs/cifs/smb1ops.c
fs/cifs/smb2ops.c
fs/cifs/smb2pdu.c
fs/cifs/transport.c

index 0c796a27d1ebd826731301ce83c93521d14a141a..4293b1f13f0032c25c247799771a7f4e6f5e8c34 100644 (file)
@@ -216,6 +216,7 @@ struct cifs_io_parms;
 struct cifs_search_info;
 struct cifsInodeInfo;
 struct cifs_open_parms;
+struct cifs_credits;
 
 struct smb_version_operations {
        int (*send_cancel)(struct TCP_Server_Info *, struct smb_rqst *,
@@ -230,8 +231,9 @@ struct smb_version_operations {
        /* check response: verify signature, map error */
        int (*check_receive)(struct mid_q_entry *, struct TCP_Server_Info *,
                             bool);
-       void (*add_credits)(struct TCP_Server_Info *, const unsigned int,
-                           const int);
+       void (*add_credits)(struct TCP_Server_Info *server,
+                           const struct cifs_credits *credits,
+                           const int optype);
        void (*set_credits)(struct TCP_Server_Info *, const int);
        int * (*get_credits_field)(struct TCP_Server_Info *, const int);
        unsigned int (*get_credits)(struct mid_q_entry *);
@@ -454,7 +456,7 @@ struct smb_version_operations {
        unsigned int (*wp_retry_size)(struct inode *);
        /* get mtu credits */
        int (*wait_mtu_credits)(struct TCP_Server_Info *, unsigned int,
-                               unsigned int *, unsigned int *);
+                               unsigned int *, struct cifs_credits *);
        /* check if we need to issue closedir */
        bool (*dir_needs_close)(struct cifsFileInfo *);
        long (*fallocate)(struct file *, struct cifs_tcon *, int, loff_t,
@@ -713,6 +715,11 @@ struct TCP_Server_Info {
        int nr_targets;
 };
 
+struct cifs_credits {
+       unsigned int value;
+       unsigned int instance;
+};
+
 static inline unsigned int
 in_flight(struct TCP_Server_Info *server)
 {
@@ -737,15 +744,17 @@ static inline void
 add_credits(struct TCP_Server_Info *server, const unsigned int add,
            const int optype)
 {
-       server->ops->add_credits(server, add, optype);
+       struct cifs_credits credits = { .value = add, .instance = 0 };
+
+       server->ops->add_credits(server, &credits, optype);
 }
 
 static inline void
-add_credits_and_wake_if(struct TCP_Server_Info *server, const unsigned int add,
-                       const int optype)
+add_credits_and_wake_if(struct TCP_Server_Info *server,
+                       const struct cifs_credits *credits, const int optype)
 {
-       if (add) {
-               server->ops->add_credits(server, add, optype);
+       if (credits->value) {
+               server->ops->add_credits(server, credits, optype);
                wake_up(&server->request_q);
        }
 }
@@ -1253,7 +1262,7 @@ struct cifs_readdata {
        unsigned int                    pagesz;
        unsigned int                    page_offset;
        unsigned int                    tailsz;
-       unsigned int                    credits;
+       struct cifs_credits             credits;
        unsigned int                    nr_pages;
        struct page                     **pages;
 };
@@ -1279,7 +1288,7 @@ struct cifs_writedata {
        unsigned int                    pagesz;
        unsigned int                    page_offset;
        unsigned int                    tailsz;
-       unsigned int                    credits;
+       struct cifs_credits             credits;
        unsigned int                    nr_pages;
        struct page                     **pages;
 };
index 336c116995d7a509257a3cc938b23aaae8779b73..7a9a9fd12ea9a2d9eb5f499510e8c36523f2fe03 100644 (file)
@@ -115,7 +115,7 @@ extern int cifs_check_receive(struct mid_q_entry *mid,
                        struct TCP_Server_Info *server, bool log_error);
 extern int cifs_wait_mtu_credits(struct TCP_Server_Info *server,
                                 unsigned int size, unsigned int *num,
-                                unsigned int *credits);
+                                struct cifs_credits *credits);
 extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *,
                        struct kvec *, int /* nvec to send */,
                        int * /* type of buf returned */, const int flags,
index 46bee3b4eeed93ebb957292d9686abc8a3f1eaeb..b95db2b593cb078639ba71cfdcafe6c9d19c5a4b 100644 (file)
@@ -593,6 +593,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
                        msleep(3000);
                } else {
                        atomic_inc(&tcpSesReconnectCount);
+                       set_credits(server, 1);
                        spin_lock(&GlobalMid_Lock);
                        if (server->tcpStatus != CifsExiting)
                                server->tcpStatus = CifsNeedNegotiate;
@@ -4951,8 +4952,6 @@ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses)
        if (!server->ops->need_neg(server))
                return 0;
 
-       set_credits(server, 1);
-
        rc = server->ops->negotiate(xid, ses);
        if (rc == 0) {
                spin_lock(&GlobalMid_Lock);
index da1f05f4ac0cf66ca2d8651e190500e8ac2c01b9..61b4dc7cfb911bebc3c9bc05d1f9b4a9ed50bb64 100644 (file)
@@ -2143,11 +2143,13 @@ static int cifs_writepages(struct address_space *mapping,
        server = cifs_sb_master_tcon(cifs_sb)->ses->server;
 retry:
        while (!done && index <= end) {
-               unsigned int i, nr_pages, found_pages, wsize, credits;
+               unsigned int i, nr_pages, found_pages, wsize;
                pgoff_t next = 0, tofind, saved_index = index;
+               struct cifs_credits credits_on_stack;
+               struct cifs_credits *credits = &credits_on_stack;
 
                rc = server->ops->wait_mtu_credits(server, cifs_sb->wsize,
-                                                  &wsize, &credits);
+                                                  &wsize, credits);
                if (rc != 0) {
                        done = true;
                        break;
@@ -2180,13 +2182,13 @@ retry:
                        continue;
                }
 
-               wdata->credits = credits;
+               wdata->credits = credits_on_stack;
 
                rc = wdata_send_pages(wdata, nr_pages, mapping, wbc);
 
                /* send failure -- clean up the mess */
                if (rc != 0) {
-                       add_credits_and_wake_if(server, wdata->credits, 0);
+                       add_credits_and_wake_if(server, &wdata->credits, 0);
                        for (i = 0; i < nr_pages; ++i) {
                                if (is_retryable_error(rc))
                                        redirty_page_for_writepage(wbc,
@@ -2567,7 +2569,8 @@ static int
 cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head *wdata_list,
        struct cifs_aio_ctx *ctx)
 {
-       unsigned int wsize, credits;
+       unsigned int wsize;
+       struct cifs_credits credits;
        int rc;
        struct TCP_Server_Info *server =
                tlink_tcon(wdata->cfile->tlink)->ses->server;
@@ -2577,18 +2580,19 @@ cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head *wdata_list,
         * Note: we are attempting to resend the whole wdata not in segments
         */
        do {
-               rc = server->ops->wait_mtu_credits(
-                       server, wdata->bytes, &wsize, &credits);
+               rc = server->ops->wait_mtu_credits(server, wdata->bytes, &wsize,
+                                                  &credits);
 
                if (rc)
                        goto out;
 
                if (wsize < wdata->bytes) {
-                       add_credits_and_wake_if(server, credits, 0);
+                       add_credits_and_wake_if(server, &credits, 0);
                        msleep(1000);
                }
        } while (wsize < wdata->bytes);
 
+       wdata->credits = credits;
        rc = -EAGAIN;
        while (rc == -EAGAIN) {
                rc = 0;
@@ -2604,7 +2608,7 @@ cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head *wdata_list,
                return 0;
        }
 
-       add_credits_and_wake_if(server, wdata->credits, 0);
+       add_credits_and_wake_if(server, &wdata->credits, 0);
 out:
        kref_put(&wdata->refcount, cifs_uncached_writedata_release);
 
@@ -2627,6 +2631,7 @@ cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from,
        struct TCP_Server_Info *server;
        struct page **pagevec;
        size_t start;
+       unsigned int xid;
 
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
                pid = open_file->pid;
@@ -2634,12 +2639,15 @@ cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from,
                pid = current->tgid;
 
        server = tlink_tcon(open_file->tlink)->ses->server;
+       xid = get_xid();
 
        do {
-               unsigned int wsize, credits;
+               unsigned int wsize;
+               struct cifs_credits credits_on_stack;
+               struct cifs_credits *credits = &credits_on_stack;
 
                rc = server->ops->wait_mtu_credits(server, cifs_sb->wsize,
-                                                  &wsize, &credits);
+                                                  &wsize, credits);
                if (rc)
                        break;
 
@@ -2731,7 +2739,7 @@ cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from,
                wdata->pid = pid;
                wdata->bytes = cur_len;
                wdata->pagesz = PAGE_SIZE;
-               wdata->credits = credits;
+               wdata->credits = credits_on_stack;
                wdata->ctx = ctx;
                kref_get(&ctx->refcount);
 
@@ -2740,7 +2748,7 @@ cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from,
                        rc = server->ops->async_writev(wdata,
                                        cifs_uncached_writedata_release);
                if (rc) {
-                       add_credits_and_wake_if(server, wdata->credits, 0);
+                       add_credits_and_wake_if(server, &wdata->credits, 0);
                        kref_put(&wdata->refcount,
                                 cifs_uncached_writedata_release);
                        if (rc == -EAGAIN) {
@@ -2756,6 +2764,7 @@ cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from,
                len -= cur_len;
        } while (len > 0);
 
+       free_xid(xid);
        return rc;
 }
 
@@ -3260,7 +3269,8 @@ static int cifs_resend_rdata(struct cifs_readdata *rdata,
                        struct list_head *rdata_list,
                        struct cifs_aio_ctx *ctx)
 {
-       unsigned int rsize, credits;
+       unsigned int rsize;
+       struct cifs_credits credits;
        int rc;
        struct TCP_Server_Info *server =
                tlink_tcon(rdata->cfile->tlink)->ses->server;
@@ -3277,11 +3287,12 @@ static int cifs_resend_rdata(struct cifs_readdata *rdata,
                        goto out;
 
                if (rsize < rdata->bytes) {
-                       add_credits_and_wake_if(server, credits, 0);
+                       add_credits_and_wake_if(server, &credits, 0);
                        msleep(1000);
                }
        } while (rsize < rdata->bytes);
 
+       rdata->credits = credits;
        rc = -EAGAIN;
        while (rc == -EAGAIN) {
                rc = 0;
@@ -3297,7 +3308,7 @@ static int cifs_resend_rdata(struct cifs_readdata *rdata,
                return 0;
        }
 
-       add_credits_and_wake_if(server, rdata->credits, 0);
+       add_credits_and_wake_if(server, &rdata->credits, 0);
 out:
        kref_put(&rdata->refcount,
                cifs_uncached_readdata_release);
@@ -3311,7 +3322,9 @@ cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file,
                     struct cifs_aio_ctx *ctx)
 {
        struct cifs_readdata *rdata;
-       unsigned int npages, rsize, credits;
+       unsigned int npages, rsize;
+       struct cifs_credits credits_on_stack;
+       struct cifs_credits *credits = &credits_on_stack;
        size_t cur_len;
        int rc;
        pid_t pid;
@@ -3332,7 +3345,7 @@ cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file,
 
        do {
                rc = server->ops->wait_mtu_credits(server, cifs_sb->rsize,
-                                                  &rsize, &credits);
+                                                  &rsize, credits);
                if (rc)
                        break;
 
@@ -3406,7 +3419,7 @@ cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file,
                rdata->pagesz = PAGE_SIZE;
                rdata->read_into_pages = cifs_uncached_read_into_pages;
                rdata->copy_into_pages = cifs_uncached_copy_into_pages;
-               rdata->credits = credits;
+               rdata->credits = credits_on_stack;
                rdata->ctx = ctx;
                kref_get(&ctx->refcount);
 
@@ -3414,7 +3427,7 @@ cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file,
                    !(rc = cifs_reopen_file(rdata->cfile, true)))
                        rc = server->ops->async_readv(rdata);
                if (rc) {
-                       add_credits_and_wake_if(server, rdata->credits, 0);
+                       add_credits_and_wake_if(server, &rdata->credits, 0);
                        kref_put(&rdata->refcount,
                                cifs_uncached_readdata_release);
                        if (rc == -EAGAIN) {
@@ -4093,10 +4106,11 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                loff_t offset;
                struct page *page, *tpage;
                struct cifs_readdata *rdata;
-               unsigned credits;
+               struct cifs_credits credits_on_stack;
+               struct cifs_credits *credits = &credits_on_stack;
 
                rc = server->ops->wait_mtu_credits(server, cifs_sb->rsize,
-                                                  &rsize, &credits);
+                                                  &rsize, credits);
                if (rc)
                        break;
 
@@ -4142,7 +4156,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                rdata->tailsz = PAGE_SIZE;
                rdata->read_into_pages = cifs_readpages_read_into_pages;
                rdata->copy_into_pages = cifs_readpages_copy_into_pages;
-               rdata->credits = credits;
+               rdata->credits = credits_on_stack;
 
                list_for_each_entry_safe(page, tpage, &tmplist, lru) {
                        list_del(&page->lru);
@@ -4153,7 +4167,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                    !(rc = cifs_reopen_file(rdata->cfile, true)))
                        rc = server->ops->async_readv(rdata);
                if (rc) {
-                       add_credits_and_wake_if(server, rdata->credits, 0);
+                       add_credits_and_wake_if(server, &rdata->credits, 0);
                        for (i = 0; i < rdata->nr_pages; i++) {
                                page = rdata->pages[i];
                                lru_cache_add_file(page);
index 32a6c020478f542723a1b7aaa35eb8f9b2d966f4..6f92d649f6fb68a92ab9abde9bd0f5123036974f 100644 (file)
@@ -117,11 +117,11 @@ cifs_find_mid(struct TCP_Server_Info *server, char *buffer)
 }
 
 static void
-cifs_add_credits(struct TCP_Server_Info *server, const unsigned int add,
-                const int optype)
+cifs_add_credits(struct TCP_Server_Info *server,
+                const struct cifs_credits *credits, const int optype)
 {
        spin_lock(&server->req_lock);
-       server->credits += add;
+       server->credits += credits->value;
        server->in_flight--;
        spin_unlock(&server->req_lock);
        wake_up(&server->request_q);
index 7291d8289511b91f25fda40abe4d7c038ca99780..6f1a5f504c024bb2033e22f82c325374eb655c99 100644 (file)
@@ -67,10 +67,13 @@ change_conf(struct TCP_Server_Info *server)
 }
 
 static void
-smb2_add_credits(struct TCP_Server_Info *server, const unsigned int add,
-                const int optype)
+smb2_add_credits(struct TCP_Server_Info *server,
+                const struct cifs_credits *credits, const int optype)
 {
        int *val, rc = -1;
+       unsigned int add = credits->value;
+       unsigned int instance = credits->instance;
+       bool reconnect_detected = false;
 
        spin_lock(&server->req_lock);
        val = server->ops->get_credits_field(server, optype);
@@ -79,8 +82,11 @@ smb2_add_credits(struct TCP_Server_Info *server, const unsigned int add,
        if (((optype & CIFS_OP_MASK) == CIFS_NEG_OP) && (*val != 0))
                trace_smb3_reconnect_with_invalid_credits(server->CurrentMid,
                        server->hostname, *val);
+       if ((instance == 0) || (instance == server->reconnect_instance))
+               *val += add;
+       else
+               reconnect_detected = true;
 
-       *val += add;
        if (*val > 65000) {
                *val = 65000; /* Don't get near 64K credits, avoid srv bugs */
                printk_once(KERN_WARNING "server overflowed SMB3 credits\n");
@@ -102,6 +108,10 @@ smb2_add_credits(struct TCP_Server_Info *server, const unsigned int add,
        spin_unlock(&server->req_lock);
        wake_up(&server->request_q);
 
+       if (reconnect_detected)
+               cifs_dbg(FYI, "trying to put %d credits from the old server instance %d\n",
+                        add, instance);
+
        if (server->tcpStatus == CifsNeedReconnect
            || server->tcpStatus == CifsExiting)
                return;
@@ -164,7 +174,7 @@ smb2_get_credits(struct mid_q_entry *mid)
 
 static int
 smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size,
-                     unsigned int *num, unsigned int *credits)
+                     unsigned int *num, struct cifs_credits *credits)
 {
        int rc = 0;
        unsigned int scredits;
@@ -190,7 +200,8 @@ smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size,
                        /* can deadlock with reopen */
                        if (scredits <= 8) {
                                *num = SMB2_MAX_BUFFER_SIZE;
-                               *credits = 0;
+                               credits->value = 0;
+                               credits->instance = 0;
                                break;
                        }
 
@@ -199,8 +210,10 @@ smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size,
                        *num = min_t(unsigned int, size,
                                     scredits * SMB2_MAX_BUFFER_SIZE);
 
-                       *credits = DIV_ROUND_UP(*num, SMB2_MAX_BUFFER_SIZE);
-                       server->credits -= *credits;
+                       credits->value =
+                               DIV_ROUND_UP(*num, SMB2_MAX_BUFFER_SIZE);
+                       credits->instance = server->reconnect_instance;
+                       server->credits -= credits->value;
                        server->in_flight++;
                        break;
                }
index 77f2c723befa6f005b7338fba74cb7759bd38493..04581f06f29f33ffb38f1026244a6623259e86c3 100644 (file)
@@ -3294,9 +3294,9 @@ smb2_async_readv(struct cifs_readdata *rdata)
        rc = smb2_new_read_req(
                (void **) &buf, &total_len, &io_parms, rdata, 0, 0);
        if (rc) {
-               if (rc == -EAGAIN && rdata->credits) {
+               if (rc == -EAGAIN && rdata->credits.value) {
                        /* credits was reset by reconnect */
-                       rdata->credits = 0;
+                       rdata->credits.value = 0;
                        /* reduce in_flight value since we won't send the req */
                        spin_lock(&server->req_lock);
                        server->in_flight--;
@@ -3313,17 +3313,26 @@ smb2_async_readv(struct cifs_readdata *rdata)
 
        shdr = (struct smb2_sync_hdr *)buf;
 
-       if (rdata->credits) {
+       if (rdata->credits.value > 0) {
                shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(rdata->bytes,
                                                SMB2_MAX_BUFFER_SIZE));
                shdr->CreditRequest =
                        cpu_to_le16(le16_to_cpu(shdr->CreditCharge) + 1);
                spin_lock(&server->req_lock);
-               server->credits += rdata->credits -
+               if (server->reconnect_instance == rdata->credits.instance)
+                       server->credits += rdata->credits.value -
                                                le16_to_cpu(shdr->CreditCharge);
+               else {
+                       spin_unlock(&server->req_lock);
+                       cifs_dbg(VFS, "trying to return %u credits to old session\n",
+                                rdata->credits.value
+                                - le16_to_cpu(shdr->CreditCharge));
+                       rc = -EAGAIN;
+                       goto async_readv_out;
+               }
                spin_unlock(&server->req_lock);
                wake_up(&server->request_q);
-               rdata->credits = le16_to_cpu(shdr->CreditCharge);
+               rdata->credits.value = le16_to_cpu(shdr->CreditCharge);
                flags |= CIFS_HAS_CREDITS;
        }
 
@@ -3340,6 +3349,7 @@ smb2_async_readv(struct cifs_readdata *rdata)
                                    io_parms.offset, io_parms.length, rc);
        }
 
+async_readv_out:
        cifs_small_buf_release(buf);
        return rc;
 }
@@ -3508,9 +3518,9 @@ smb2_async_writev(struct cifs_writedata *wdata,
 
        rc = smb2_plain_req_init(SMB2_WRITE, tcon, (void **) &req, &total_len);
        if (rc) {
-               if (rc == -EAGAIN && wdata->credits) {
+               if (rc == -EAGAIN && wdata->credits.value) {
                        /* credits was reset by reconnect */
-                       wdata->credits = 0;
+                       wdata->credits.value = 0;
                        /* reduce in_flight value since we won't send the req */
                        spin_lock(&server->req_lock);
                        server->in_flight--;
@@ -3603,17 +3613,26 @@ smb2_async_writev(struct cifs_writedata *wdata,
        req->Length = cpu_to_le32(wdata->bytes);
 #endif
 
-       if (wdata->credits) {
+       if (wdata->credits.value > 0) {
                shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(wdata->bytes,
                                                    SMB2_MAX_BUFFER_SIZE));
                shdr->CreditRequest =
                        cpu_to_le16(le16_to_cpu(shdr->CreditCharge) + 1);
                spin_lock(&server->req_lock);
-               server->credits += wdata->credits -
+               if (server->reconnect_instance == wdata->credits.instance)
+                       server->credits += wdata->credits.value -
                                                le16_to_cpu(shdr->CreditCharge);
+               else {
+                       spin_unlock(&server->req_lock);
+                       cifs_dbg(VFS, "trying to return %d credits to old session\n",
+                                wdata->credits.value
+                                - le16_to_cpu(shdr->CreditCharge));
+                       rc = -EAGAIN;
+                       goto async_writev_out;
+               }
                spin_unlock(&server->req_lock);
                wake_up(&server->request_q);
-               wdata->credits = le16_to_cpu(shdr->CreditCharge);
+               wdata->credits.value = le16_to_cpu(shdr->CreditCharge);
                flags |= CIFS_HAS_CREDITS;
        }
 
index 9544eb99b5a2f9e11da4b4bea4e1cdc2b519dd65..099a1c91472027eac16607e3f40e1a6088399094 100644 (file)
@@ -512,10 +512,11 @@ wait_for_free_request(struct TCP_Server_Info *server, const int timeout,
 
 int
 cifs_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size,
-                     unsigned int *num, unsigned int *credits)
+                     unsigned int *num, struct cifs_credits *credits)
 {
        *num = size;
-       *credits = 0;
+       credits->value = 0;
+       credits->instance = server->reconnect_instance;
        return 0;
 }
 
@@ -606,7 +607,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
 {
        int rc, timeout, optype;
        struct mid_q_entry *mid;
-       unsigned int credits = 0;
+       struct cifs_credits credits = { .value = 0, .instance = 0 };
 
        timeout = flags & CIFS_TIMEOUT_MASK;
        optype = flags & CIFS_OP_MASK;
@@ -615,14 +616,14 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
                rc = wait_for_free_request(server, timeout, optype);
                if (rc)
                        return rc;
-               credits = 1;
+               credits.value = 1;
        }
 
        mutex_lock(&server->srv_mutex);
        mid = server->ops->setup_async_request(server, rqst);
        if (IS_ERR(mid)) {
                mutex_unlock(&server->srv_mutex);
-               add_credits_and_wake_if(server, credits, optype);
+               add_credits_and_wake_if(server, &credits, optype);
                return PTR_ERR(mid);
        }
 
@@ -657,7 +658,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
        if (rc == 0)
                return 0;
 
-       add_credits_and_wake_if(server, credits, optype);
+       add_credits_and_wake_if(server, &credits, optype);
        return rc;
 }