aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/connect.c
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 /fs/cifs/connect.c
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>
Diffstat (limited to 'fs/cifs/connect.c')
-rw-r--r--fs/cifs/connect.c30
1 files changed, 24 insertions, 6 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 273cf42b2915..6070ba69647b 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 }