]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/commitdiff
CIFS: Do not miss cancelled OPEN responses
authorPavel Shilovsky <pshilov@microsoft.com>
Thu, 21 Nov 2019 19:35:14 +0000 (11:35 -0800)
committerSeth Forshee <seth.forshee@canonical.com>
Mon, 6 Jan 2020 13:57:25 +0000 (07:57 -0600)
BugLink: https://bugs.launchpad.net/bugs/1858427
commit 7b71843fa7028475b052107664cbe120156a2cfc upstream.

When an OPEN command is cancelled we mark a mid as
cancelled and let the demultiplex thread process it
by closing an open handle. The problem is there is
a race between a system call thread and the demultiplex
thread and there may be a situation when the mid has
been already processed before it is set as cancelled.

Fix this by processing cancelled requests when mids
are being destroyed which means that there is only
one thread referencing a particular mid. Also set
mids as cancelled unconditionally on their state.

Cc: Stable <stable@vger.kernel.org>
Tested-by: Frank Sorenson <sorenson@redhat.com>
Reviewed-by: Ronnie Sahlberg <lsahlber@redhat.com>
Signed-off-by: Pavel Shilovsky <pshilov@microsoft.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
fs/cifs/connect.c
fs/cifs/transport.c

index 02bc20d78daf9b1f72adec4626e3964de19c92e2..4f0e733cb487fb96c66e2ab063dfb36616f8fe97 100644 (file)
@@ -1222,12 +1222,6 @@ next_pdu:
                for (i = 0; i < num_mids; i++) {
                        if (mids[i] != NULL) {
                                mids[i]->resp_buf_size = server->pdu_size;
-                               if ((mids[i]->mid_flags & MID_WAIT_CANCELLED) &&
-                                   mids[i]->mid_state == MID_RESPONSE_RECEIVED &&
-                                   server->ops->handle_cancelled_mid)
-                                       server->ops->handle_cancelled_mid(
-                                                       mids[i]->resp_buf,
-                                                       server);
 
                                if (!mids[i]->multiRsp || mids[i]->multiEnd)
                                        mids[i]->callback(mids[i]);
index e9e3a0909ff14c156a172005bec15f20f02cee6e..755434d5e4e716c7ca8c4335e340fb544be797b5 100644 (file)
@@ -93,8 +93,14 @@ static void _cifs_mid_q_entry_release(struct kref *refcount)
        __u16 smb_cmd = le16_to_cpu(midEntry->command);
        unsigned long now;
        unsigned long roundtrip_time;
-       struct TCP_Server_Info *server = midEntry->server;
 #endif
+       struct TCP_Server_Info *server = midEntry->server;
+
+       if (midEntry->resp_buf && (midEntry->mid_flags & MID_WAIT_CANCELLED) &&
+           midEntry->mid_state == MID_RESPONSE_RECEIVED &&
+           server->ops->handle_cancelled_mid)
+               server->ops->handle_cancelled_mid(midEntry->resp_buf, server);
+
        midEntry->mid_state = MID_FREE;
        atomic_dec(&midCount);
        if (midEntry->large_buf)
@@ -1122,8 +1128,8 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
                                 midQ[i]->mid, le16_to_cpu(midQ[i]->command));
                        send_cancel(server, &rqst[i], midQ[i]);
                        spin_lock(&GlobalMid_Lock);
+                       midQ[i]->mid_flags |= MID_WAIT_CANCELLED;
                        if (midQ[i]->mid_state == MID_REQUEST_SUBMITTED) {
-                               midQ[i]->mid_flags |= MID_WAIT_CANCELLED;
                                midQ[i]->callback = cifs_cancelled_callback;
                                cancelled_mid[i] = true;
                                credits[i].value = 0;