aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2011-05-22 07:09:13 -0400
committerSteve French <sfrench@us.ibm.com>2011-05-23 23:11:33 -0400
commit3c1105df699188a70f5c17dc0795affea388bca7 (patch)
treebfbcfaaae2fdfd16b2fcdb57710b9affbf183c49
parent724d9f1cfba0cb16a7151333b501e8f7885450d8 (diff)
cifs: don't call mid_q_entry->callback under the Global_MidLock (try #5)
Minor revision to the last version of this patch -- the only difference is the fix to the cFYI statement in cifs_reconnect. Holding the spinlock while we call this function means that it can't sleep, which really limits what it can do. Taking it out from under the spinlock also means less contention for this global lock. Change the semantics such that the Global_MidLock is not held when the callback is called. To do this requires that we take extra care not to have sync_mid_result remove the mid from the list when the mid is in a state where that has already happened. This prevents list corruption when the mid is sitting on a private list for reconnect or when cifsd is coming down. Reviewed-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com> Reviewed-by: Pavel Shilovsky <piastry@etersoft.ru> Signed-off-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Steve French <sfrench@us.ibm.com>
-rw-r--r--fs/cifs/cifsglob.h6
-rw-r--r--fs/cifs/connect.c30
-rw-r--r--fs/cifs/transport.c23
3 files changed, 35 insertions, 24 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 76b4517e74b..fd877c110e4 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -543,9 +543,8 @@ struct mid_q_entry;
543 * This is the prototype for the mid callback function. When creating one, 543 * This is the prototype for the mid callback function. When creating one,
544 * take special care to avoid deadlocks. Things to bear in mind: 544 * take special care to avoid deadlocks. Things to bear in mind:
545 * 545 *
546 * - it will be called by cifsd 546 * - it will be called by cifsd, with no locks held
547 * - the GlobalMid_Lock will be held 547 * - the mid will be removed from any lists
548 * - the mid will be removed from the pending_mid_q list
549 */ 548 */
550typedef void (mid_callback_t)(struct mid_q_entry *mid); 549typedef void (mid_callback_t)(struct mid_q_entry *mid);
551 550
@@ -656,6 +655,7 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param,
656#define MID_RESPONSE_RECEIVED 4 655#define MID_RESPONSE_RECEIVED 4
657#define MID_RETRY_NEEDED 8 /* session closed while this request out */ 656#define MID_RETRY_NEEDED 8 /* session closed while this request out */
658#define MID_RESPONSE_MALFORMED 0x10 657#define MID_RESPONSE_MALFORMED 0x10
658#define MID_SHUTDOWN 0x20
659 659
660/* Types of response buffer returned from SendReceive2 */ 660/* Types of response buffer returned from SendReceive2 */
661#define CIFS_NO_BUFFER 0 /* Response buffer not returned */ 661#define CIFS_NO_BUFFER 0 /* Response buffer not returned */
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 273cf42b291..6070ba69647 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -137,6 +137,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
137 struct cifsSesInfo *ses; 137 struct cifsSesInfo *ses;
138 struct cifsTconInfo *tcon; 138 struct cifsTconInfo *tcon;
139 struct mid_q_entry *mid_entry; 139 struct mid_q_entry *mid_entry;
140 struct list_head retry_list;
140 141
141 spin_lock(&GlobalMid_Lock); 142 spin_lock(&GlobalMid_Lock);
142 if (server->tcpStatus == CifsExiting) { 143 if (server->tcpStatus == CifsExiting) {
@@ -188,16 +189,23 @@ cifs_reconnect(struct TCP_Server_Info *server)
188 mutex_unlock(&server->srv_mutex); 189 mutex_unlock(&server->srv_mutex);
189 190
190 /* mark submitted MIDs for retry and issue callback */ 191 /* mark submitted MIDs for retry and issue callback */
191 cFYI(1, "%s: issuing mid callbacks", __func__); 192 INIT_LIST_HEAD(&retry_list);
193 cFYI(1, "%s: moving mids to private list", __func__);
192 spin_lock(&GlobalMid_Lock); 194 spin_lock(&GlobalMid_Lock);
193 list_for_each_safe(tmp, tmp2, &server->pending_mid_q) { 195 list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
194 mid_entry = list_entry(tmp, struct mid_q_entry, qhead); 196 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
195 if (mid_entry->midState == MID_REQUEST_SUBMITTED) 197 if (mid_entry->midState == MID_REQUEST_SUBMITTED)
196 mid_entry->midState = MID_RETRY_NEEDED; 198 mid_entry->midState = MID_RETRY_NEEDED;
199 list_move(&mid_entry->qhead, &retry_list);
200 }
201 spin_unlock(&GlobalMid_Lock);
202
203 cFYI(1, "%s: issuing mid callbacks", __func__);
204 list_for_each_safe(tmp, tmp2, &retry_list) {
205 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
197 list_del_init(&mid_entry->qhead); 206 list_del_init(&mid_entry->qhead);
198 mid_entry->callback(mid_entry); 207 mid_entry->callback(mid_entry);
199 } 208 }
200 spin_unlock(&GlobalMid_Lock);
201 209
202 while (server->tcpStatus == CifsNeedReconnect) { 210 while (server->tcpStatus == CifsNeedReconnect) {
203 try_to_freeze(); 211 try_to_freeze();
@@ -671,12 +679,12 @@ multi_t2_fnd:
671 mid_entry->when_received = jiffies; 679 mid_entry->when_received = jiffies;
672#endif 680#endif
673 list_del_init(&mid_entry->qhead); 681 list_del_init(&mid_entry->qhead);
674 mid_entry->callback(mid_entry);
675 break; 682 break;
676 } 683 }
677 spin_unlock(&GlobalMid_Lock); 684 spin_unlock(&GlobalMid_Lock);
678 685
679 if (mid_entry != NULL) { 686 if (mid_entry != NULL) {
687 mid_entry->callback(mid_entry);
680 /* Was previous buf put in mpx struct for multi-rsp? */ 688 /* Was previous buf put in mpx struct for multi-rsp? */
681 if (!isMultiRsp) { 689 if (!isMultiRsp) {
682 /* smb buffer will be freed by user thread */ 690 /* smb buffer will be freed by user thread */
@@ -740,15 +748,25 @@ multi_t2_fnd:
740 cifs_small_buf_release(smallbuf); 748 cifs_small_buf_release(smallbuf);
741 749
742 if (!list_empty(&server->pending_mid_q)) { 750 if (!list_empty(&server->pending_mid_q)) {
751 struct list_head dispose_list;
752
753 INIT_LIST_HEAD(&dispose_list);
743 spin_lock(&GlobalMid_Lock); 754 spin_lock(&GlobalMid_Lock);
744 list_for_each_safe(tmp, tmp2, &server->pending_mid_q) { 755 list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
745 mid_entry = list_entry(tmp, struct mid_q_entry, qhead); 756 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
746 cFYI(1, "Clearing Mid 0x%x - issuing callback", 757 cFYI(1, "Clearing mid 0x%x", mid_entry->mid);
747 mid_entry->mid); 758 mid_entry->midState = MID_SHUTDOWN;
759 list_move(&mid_entry->qhead, &dispose_list);
760 }
761 spin_unlock(&GlobalMid_Lock);
762
763 /* now walk dispose list and issue callbacks */
764 list_for_each_safe(tmp, tmp2, &dispose_list) {
765 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
766 cFYI(1, "Callback mid 0x%x", mid_entry->mid);
748 list_del_init(&mid_entry->qhead); 767 list_del_init(&mid_entry->qhead);
749 mid_entry->callback(mid_entry); 768 mid_entry->callback(mid_entry);
750 } 769 }
751 spin_unlock(&GlobalMid_Lock);
752 /* 1/8th of sec is more than enough time for them to exit */ 770 /* 1/8th of sec is more than enough time for them to exit */
753 msleep(125); 771 msleep(125);
754 } 772 }
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 16bcc0725ce..d1998b6086e 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -426,7 +426,7 @@ SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
426} 426}
427 427
428static int 428static int
429sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server) 429cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
430{ 430{
431 int rc = 0; 431 int rc = 0;
432 432
@@ -434,28 +434,21 @@ sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
434 mid->mid, mid->midState); 434 mid->mid, mid->midState);
435 435
436 spin_lock(&GlobalMid_Lock); 436 spin_lock(&GlobalMid_Lock);
437 /* ensure that it's no longer on the pending_mid_q */
438 list_del_init(&mid->qhead);
439
440 switch (mid->midState) { 437 switch (mid->midState) {
441 case MID_RESPONSE_RECEIVED: 438 case MID_RESPONSE_RECEIVED:
442 spin_unlock(&GlobalMid_Lock); 439 spin_unlock(&GlobalMid_Lock);
443 return rc; 440 return rc;
444 case MID_REQUEST_SUBMITTED:
445 /* socket is going down, reject all calls */
446 if (server->tcpStatus == CifsExiting) {
447 cERROR(1, "%s: canceling mid=%d cmd=0x%x state=%d",
448 __func__, mid->mid, mid->command, mid->midState);
449 rc = -EHOSTDOWN;
450 break;
451 }
452 case MID_RETRY_NEEDED: 441 case MID_RETRY_NEEDED:
453 rc = -EAGAIN; 442 rc = -EAGAIN;
454 break; 443 break;
455 case MID_RESPONSE_MALFORMED: 444 case MID_RESPONSE_MALFORMED:
456 rc = -EIO; 445 rc = -EIO;
457 break; 446 break;
447 case MID_SHUTDOWN:
448 rc = -EHOSTDOWN;
449 break;
458 default: 450 default:
451 list_del_init(&mid->qhead);
459 cERROR(1, "%s: invalid mid state mid=%d state=%d", __func__, 452 cERROR(1, "%s: invalid mid state mid=%d state=%d", __func__,
460 mid->mid, mid->midState); 453 mid->mid, mid->midState);
461 rc = -EIO; 454 rc = -EIO;
@@ -618,7 +611,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
618 611
619 cifs_small_buf_release(in_buf); 612 cifs_small_buf_release(in_buf);
620 613
621 rc = sync_mid_result(midQ, ses->server); 614 rc = cifs_sync_mid_result(midQ, ses->server);
622 if (rc != 0) { 615 if (rc != 0) {
623 atomic_dec(&ses->server->inFlight); 616 atomic_dec(&ses->server->inFlight);
624 wake_up(&ses->server->request_q); 617 wake_up(&ses->server->request_q);
@@ -739,7 +732,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
739 spin_unlock(&GlobalMid_Lock); 732 spin_unlock(&GlobalMid_Lock);
740 } 733 }
741 734
742 rc = sync_mid_result(midQ, ses->server); 735 rc = cifs_sync_mid_result(midQ, ses->server);
743 if (rc != 0) { 736 if (rc != 0) {
744 atomic_dec(&ses->server->inFlight); 737 atomic_dec(&ses->server->inFlight);
745 wake_up(&ses->server->request_q); 738 wake_up(&ses->server->request_q);
@@ -914,7 +907,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
914 rstart = 1; 907 rstart = 1;
915 } 908 }
916 909
917 rc = sync_mid_result(midQ, ses->server); 910 rc = cifs_sync_mid_result(midQ, ses->server);
918 if (rc != 0) 911 if (rc != 0)
919 return rc; 912 return rc;
920 913