diff mbox

[08/13] cifs: handle cancelled requests better

Message ID 1291995877-2276-9-git-send-email-jlayton@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Jeff Layton Dec. 10, 2010, 3:44 p.m. UTC
None
diff mbox

Patch

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);