From patchwork Wed Jan 23 21:10:42 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pavel Shilovsky X-Patchwork-Id: 10777903 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 475656C2 for ; Wed, 23 Jan 2019 21:11:12 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 364C32D7AB for ; Wed, 23 Jan 2019 21:11:12 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 2ABC82D8B0; Wed, 23 Jan 2019 21:11:12 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CFAA02D7AB for ; Wed, 23 Jan 2019 21:11:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726993AbfAWVLK (ORCPT ); Wed, 23 Jan 2019 16:11:10 -0500 Received: from mail-pf1-f193.google.com ([209.85.210.193]:34224 "EHLO mail-pf1-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726345AbfAWVLK (ORCPT ); Wed, 23 Jan 2019 16:11:10 -0500 Received: by mail-pf1-f193.google.com with SMTP id h3so1815417pfg.1 for ; Wed, 23 Jan 2019 13:11:09 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references; bh=2vm9LJPxh0DUwQSZm7xpZNWq7qtMucWY9Snk00lu1WI=; b=rlRG2NN/tayinGGMWYJ67ibF3PKNld/iPAxhncQBhV+t9emcSdkcYEkg/yHTlnRbTm OBZzRpPz76QSoac5xzP+Cbdm/NAFVHhpzRhGUmrgBCOgI5eUYPK8/EOF4A1JR/lE0Srr +D1jNzkiK9b/MEOM0P/cpS0sj69ybms71BvcHWBN4yHP14KqbYB04Fq/zF+JzgOFIw2S JcFjqLyq8a+Yme1t7TLdie5aI/Bzb+xDC8KkCzWH8OaE7J75YqP9QHNhFW3LGxBFtqsU D6yQFfQTL0Yyj9fM6n+6SjZctozPPYKSn+XTS5hfISYjuypWFtqjcLzDbwFyzG0q5DOT AHyg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=2vm9LJPxh0DUwQSZm7xpZNWq7qtMucWY9Snk00lu1WI=; b=k6U71FuUbaFabG/y/1JXllVXZ2whMlfKhy0jxpAQrEc69cm6FLuQM08OGLP1/mDyO3 xWFosPqO+6JZPIJotwD5+WeKwIhqbhBbAKQm88VM+jp1VzXnyowpjqOEwekj6FfEHCb/ 7A+DrJjdpPr+8CMCbxTkdAx01Wob7wGq5W55nDoFDjITXo0XeLJwIwCmo8AYslE+j2WR iWEgeX4PBJ95yVkOXmwzyLo03AxDfVnAKL4vHxqIhdxeLdOvd/xLt3bB6+ee9HYnf94d vXdgo16fHE2RbB7UNLHSO1D94rx0IAiVHnz8k+VRmp+vUreaN4hhhqgNsMXSlNqOuwe4 IkSQ== X-Gm-Message-State: AJcUukdIq2lwbXSRVSrerwnIfmtAWgnlOUrkAzgcdZVUBgoDDAZ/ANiR mmym0OAvGiab2ravaEAp6mnoMLw= X-Google-Smtp-Source: ALg8bN63LmFQJRkIAbcJjdwFf+qgJ0NfDbkes7uM4TGg+fILhJTjcENuWx6+6NBWn4+7EIBaI+hgEg== X-Received: by 2002:a63:5b48:: with SMTP id l8mr3501329pgm.80.1548277867915; Wed, 23 Jan 2019 13:11:07 -0800 (PST) Received: from ubuntu-vm.corp.microsoft.com ([2001:4898:80e8:f:a17f:4e9f:6b7c:507d]) by smtp.gmail.com with ESMTPSA id n73sm28063714pfj.148.2019.01.23.13.11.06 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 23 Jan 2019 13:11:06 -0800 (PST) From: Pavel Shilovsky X-Google-Original-From: Pavel Shilovsky To: linux-cifs@vger.kernel.org, Steve French , Ronnie Sahlberg Subject: [PATCH 12/15] CIFS: Respect reconnect in MTU credits calculations Date: Wed, 23 Jan 2019 13:10:42 -0800 Message-Id: <1548277845-6746-13-git-send-email-pshilov@microsoft.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1548277845-6746-1-git-send-email-pshilov@microsoft.com> References: <1548277845-6746-1-git-send-email-pshilov@microsoft.com> Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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 --- fs/cifs/cifsglob.h | 29 ++++++++++++++++--------- fs/cifs/cifsproto.h | 2 +- fs/cifs/connect.c | 3 +-- fs/cifs/file.c | 62 ++++++++++++++++++++++++++++++++--------------------- fs/cifs/smb1ops.c | 6 +++--- fs/cifs/smb2ops.c | 27 +++++++++++++++++------ fs/cifs/smb2pdu.c | 40 ++++++++++++++++++++++++---------- fs/cifs/transport.c | 13 +++++------ 8 files changed, 118 insertions(+), 64 deletions(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 94dbdbe..60a657e 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -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 *); @@ -452,7 +454,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, @@ -710,6 +712,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) { @@ -734,15 +741,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); } } @@ -1234,7 +1243,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; }; @@ -1260,7 +1269,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; }; diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 336c116..7a9a9fd 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -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, diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 3e7ad68..138ac99 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -575,6 +575,7 @@ cifs_reconnect(struct TCP_Server_Info *server) if (server->tcpStatus != CifsExiting) server->tcpStatus = CifsNeedNegotiate; spin_unlock(&GlobalMid_Lock); + set_credits(server, 1); mutex_unlock(&server->srv_mutex); } } while (server->tcpStatus == CifsNeedReconnect); @@ -4870,8 +4871,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); diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 109b1ef..baaa733 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -2134,11 +2134,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; @@ -2171,13 +2173,13 @@ static int cifs_writepages(struct address_space *mapping, 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, @@ -2558,7 +2560,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; @@ -2568,18 +2571,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; @@ -2595,7 +2599,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); @@ -2618,6 +2622,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; @@ -2625,12 +2630,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; @@ -2720,7 +2728,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); @@ -2729,7 +2737,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) { @@ -2745,6 +2753,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; } @@ -3249,7 +3258,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; @@ -3266,11 +3276,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; @@ -3286,7 +3297,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); @@ -3300,7 +3311,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; @@ -3321,7 +3334,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; @@ -3391,7 +3404,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); @@ -3400,7 +3413,7 @@ cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file, rc = server->ops->async_readv(rdata); error: 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) { @@ -4081,10 +4094,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; @@ -4130,7 +4144,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); @@ -4141,7 +4155,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); diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index 32a6c02..6f92d64 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c @@ -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); diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 3ee8258..86332e6 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -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); + switch (rc) { case -1: /* change_conf hasn't been executed */ @@ -160,7 +170,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; @@ -186,7 +196,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; } @@ -195,8 +206,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; } diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 291f290..401f3a4 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -3245,9 +3245,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--; @@ -3264,17 +3264,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; } @@ -3292,7 +3301,7 @@ smb2_async_readv(struct cifs_readdata *rdata) trace_smb3_read_done(0 /* xid */, io_parms.persistent_fid, io_parms.tcon->tid, io_parms.tcon->ses->Suid, io_parms.offset, io_parms.length); - +async_readv_out: cifs_small_buf_release(buf); return rc; } @@ -3451,9 +3460,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--; @@ -3546,17 +3555,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; } diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index eff9e3c..f364a08 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -539,10 +539,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; } @@ -633,7 +634,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; @@ -642,14 +643,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); } @@ -683,7 +684,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; }