From patchwork Fri Dec 10 15:44:32 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Layton X-Patchwork-Id: 398802 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id oBAFjBBH014282 for ; Fri, 10 Dec 2010 15:45:11 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756108Ab0LJPow (ORCPT ); Fri, 10 Dec 2010 10:44:52 -0500 Received: from mail-gw0-f42.google.com ([74.125.83.42]:53270 "EHLO mail-gw0-f42.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756087Ab0LJPou (ORCPT ); Fri, 10 Dec 2010 10:44:50 -0500 Received: by mail-gw0-f42.google.com with SMTP id 20so3171169gwb.1 for ; Fri, 10 Dec 2010 07:44:50 -0800 (PST) Received: by 10.91.8.20 with SMTP id l20mr1341925agi.147.1291995890037; Fri, 10 Dec 2010 07:44:50 -0800 (PST) Received: from salusa.poochiereds.net (cpe-071-070-153-003.nc.res.rr.com [71.70.153.3]) by mx.google.com with ESMTPS id b27sm528877ana.8.2010.12.10.07.44.48 (version=SSLv3 cipher=RC4-MD5); Fri, 10 Dec 2010 07:44:49 -0800 (PST) From: Jeff Layton To: smfrench@gmail.com Cc: linux-cifs@vger.kernel.org Subject: [PATCH 08/13] cifs: handle cancelled requests better Date: Fri, 10 Dec 2010 10:44:32 -0500 Message-Id: <1291995877-2276-9-git-send-email-jlayton@redhat.com> X-Mailer: git-send-email 1.7.3.2 In-Reply-To: <1291995877-2276-1-git-send-email-jlayton@redhat.com> References: <1291995877-2276-1-git-send-email-jlayton@redhat.com> Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Fri, 10 Dec 2010 15:45:11 +0000 (UTC) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index cc43ada..fb75f04 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -621,7 +621,7 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param, #define MID_REQUEST_SUBMITTED 2 #define MID_RESPONSE_RECEIVED 4 #define MID_RETRY_NEEDED 8 /* session closed while this request out */ -#define MID_NO_RESP_NEEDED 0x10 +#define MID_REQUEST_CANCELLED 0x10 /* discard any reply */ /* Types of response buffer returned from SendReceive2 */ #define CIFS_NO_BUFFER 0 /* Response buffer not returned */ diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index fe77e69..a8fc606 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -61,6 +61,7 @@ extern char *cifs_compose_mount_options(const char *sb_mountdata, const char *fullpath, const struct dfs_info3_param *ref, char **devname); /* extern void renew_parental_timestamps(struct dentry *direntry);*/ +extern void DeleteMidQEntry(struct mid_q_entry *midEntry); extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, struct smb_hdr * /* input */ , struct smb_hdr * /* out */ , diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 7e20ece..0feb592 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -133,7 +133,7 @@ cifs_reconnect(struct TCP_Server_Info *server) { int rc = 0; struct list_head *tmp, *tmp2; - struct list_head retry; + struct list_head retry, dispose; struct cifsSesInfo *ses; struct cifsTconInfo *tcon; struct mid_q_entry *mid_entry; @@ -192,14 +192,23 @@ cifs_reconnect(struct TCP_Server_Info *server) */ cFYI(1, "%s: moving mids to retry list", __func__); INIT_LIST_HEAD(&retry); + INIT_LIST_HEAD(&dispose); spin_lock(&GlobalMid_Lock); list_for_each_safe(tmp, tmp2, &server->pending_mid_q) { mid_entry = list_entry(tmp, struct mid_q_entry, qhead); if (mid_entry->midState == MID_REQUEST_SUBMITTED) list_move(tmp, &retry); + else if (mid_entry->midState == MID_REQUEST_CANCELLED) + list_move(tmp, &dispose); } spin_unlock(&GlobalMid_Lock); + /* now walk private dispose list and delete entries */ + list_for_each_safe(tmp, tmp2, &dispose) { + mid_entry = list_entry(tmp, struct mid_q_entry, qhead); + DeleteMidQEntry(mid_entry); + } + while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood)) { try_to_freeze(); @@ -219,7 +228,7 @@ cifs_reconnect(struct TCP_Server_Info *server) } } - /* now, issue callback for all mids in flight */ + /* issue callback for all mids in flight */ list_for_each_safe(tmp, tmp2, &retry) { list_del_init(tmp); mid_entry = list_entry(tmp, struct mid_q_entry, qhead); @@ -575,9 +584,13 @@ incomplete_rcv: list_for_each(tmp, &server->pending_mid_q) { mid_entry = list_entry(tmp, struct mid_q_entry, qhead); - if ((mid_entry->mid == smb_buffer->Mid) && - (mid_entry->midState == MID_REQUEST_SUBMITTED) && - (mid_entry->command == smb_buffer->Command)) { + if (mid_entry->mid != smb_buffer->Mid) + goto next_mid; + if (mid_entry->command != smb_buffer->Command) + goto next_mid; + if (mid_entry->midState == MID_REQUEST_CANCELLED) + break; + if (mid_entry->midState == MID_REQUEST_SUBMITTED) { if (check2ndT2(smb_buffer,server->maxBuf) > 0) { /* We have a multipart transact2 resp */ isMultiRsp = true; @@ -623,11 +636,16 @@ multi_t2_fnd: server->lstrp = jiffies; break; } +next_mid: mid_entry = NULL; } spin_unlock(&GlobalMid_Lock); if (mid_entry != NULL) { + if (mid_entry->midState == MID_REQUEST_CANCELLED) { + DeleteMidQEntry(mid_entry); + continue; + } mid_entry->callback(mid_entry); /* Was previous buf put in mpx struct for multi-rsp? */ if (!isMultiRsp) { @@ -704,6 +722,9 @@ multi_t2_fnd: } spin_unlock(&cifs_tcp_ses_lock); } else { + struct mid_q_entry *tmp_mid; + struct list_head dispose; + /* although we can not zero the server struct pointer yet, since there are active requests which may depnd on them, mark the corresponding SMB sessions as exiting too */ @@ -713,17 +734,26 @@ multi_t2_fnd: ses->status = CifsExiting; } + INIT_LIST_HEAD(&dispose); spin_lock(&GlobalMid_Lock); - list_for_each(tmp, &server->pending_mid_q) { - mid_entry = list_entry(tmp, struct mid_q_entry, qhead); + list_for_each_entry_safe(mid_entry, tmp_mid, + &server->pending_mid_q, qhead) { if (mid_entry->midState == MID_REQUEST_SUBMITTED) { cFYI(1, "Clearing Mid 0x%x - issuing callback", mid_entry->mid); mid_entry->callback(mid_entry); + } else if (mid_entry->midState == MID_REQUEST_CANCELLED) { + cFYI(1, "Clearing Mid 0x%x - Cancelled", + mid_entry->mid); + list_move(&mid_entry->qhead, &dispose); } } spin_unlock(&GlobalMid_Lock); spin_unlock(&cifs_tcp_ses_lock); + + /* now delete all of the cancelled mids */ + list_for_each_entry_safe(mid_entry, tmp_mid, &dispose, qhead) + DeleteMidQEntry(mid_entry); /* 1/8th of sec is more than enough time for them to exit */ msleep(125); } diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 79647db..97a1170 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -81,7 +81,7 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server) return temp; } -static void +void DeleteMidQEntry(struct mid_q_entry *midEntry) { #ifdef CONFIG_CIFS_STATS2 @@ -480,8 +480,13 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, goto out; rc = wait_for_response(ses->server, midQ); - if (rc != 0) - goto out; + if (rc != 0) { + /* no longer considered to be "in-flight" */ + midQ->midState = MID_REQUEST_CANCELLED; + atomic_dec(&ses->server->inFlight); + wake_up(&ses->server->request_q); + return rc; + } rc = handle_mid_result(midQ, ses->server); if (rc != 0) @@ -623,8 +628,13 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, goto out; rc = wait_for_response(ses->server, midQ); - if (rc != 0) - goto out; + if (rc != 0) { + /* no longer considered to be "in-flight" */ + midQ->midState = MID_REQUEST_CANCELLED; + atomic_dec(&ses->server->inFlight); + wake_up(&ses->server->request_q); + return rc; + } rc = handle_mid_result(midQ, ses->server); if (rc != 0) @@ -842,10 +852,14 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, } } - if (wait_for_response(ses->server, midQ) == 0) { - /* We got the response - restart system call. */ - rstart = 1; + rc = wait_for_response(ses->server, midQ); + if (rc) { + midQ->midState = MID_REQUEST_CANCELLED; + return rc; } + + /* We got the response - restart system call. */ + rstart = 1; } rc = handle_mid_result(midQ, ses->server);