aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/cifs_debug.c8
-rw-r--r--fs/cifs/cifsglob.h15
-rw-r--r--fs/cifs/connect.c53
-rw-r--r--fs/cifs/transport.c19
4 files changed, 60 insertions, 35 deletions
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
index e2d0d5d455fa..65829d32128c 100644
--- a/fs/cifs/cifs_debug.c
+++ b/fs/cifs/cifs_debug.c
@@ -79,11 +79,11 @@ void cifs_dump_mids(struct TCP_Server_Info *server)
79 spin_lock(&GlobalMid_Lock); 79 spin_lock(&GlobalMid_Lock);
80 list_for_each(tmp, &server->pending_mid_q) { 80 list_for_each(tmp, &server->pending_mid_q) {
81 mid_entry = list_entry(tmp, struct mid_q_entry, qhead); 81 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
82 cERROR(1, "State: %d Cmd: %d Pid: %d Tsk: %p Mid %d", 82 cERROR(1, "State: %d Cmd: %d Pid: %d Cbdata: %p Mid %d",
83 mid_entry->midState, 83 mid_entry->midState,
84 (int)mid_entry->command, 84 (int)mid_entry->command,
85 mid_entry->pid, 85 mid_entry->pid,
86 mid_entry->tsk, 86 mid_entry->callback_data,
87 mid_entry->mid); 87 mid_entry->mid);
88#ifdef CONFIG_CIFS_STATS2 88#ifdef CONFIG_CIFS_STATS2
89 cERROR(1, "IsLarge: %d buf: %p time rcv: %ld now: %ld", 89 cERROR(1, "IsLarge: %d buf: %p time rcv: %ld now: %ld",
@@ -218,11 +218,11 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
218 mid_entry = list_entry(tmp3, struct mid_q_entry, 218 mid_entry = list_entry(tmp3, struct mid_q_entry,
219 qhead); 219 qhead);
220 seq_printf(m, "\tState: %d com: %d pid:" 220 seq_printf(m, "\tState: %d com: %d pid:"
221 " %d tsk: %p mid %d\n", 221 " %d cbdata: %p mid %d\n",
222 mid_entry->midState, 222 mid_entry->midState,
223 (int)mid_entry->command, 223 (int)mid_entry->command,
224 mid_entry->pid, 224 mid_entry->pid,
225 mid_entry->tsk, 225 mid_entry->callback_data,
226 mid_entry->mid); 226 mid_entry->mid);
227 } 227 }
228 spin_unlock(&GlobalMid_Lock); 228 spin_unlock(&GlobalMid_Lock);
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 606ca8bb7102..4de737575959 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -508,6 +508,18 @@ static inline void cifs_stats_bytes_read(struct cifsTconInfo *tcon,
508 508
509#endif 509#endif
510 510
511struct mid_q_entry;
512
513/*
514 * This is the prototype for the mid callback function. When creating one,
515 * take special care to avoid deadlocks. Things to bear in mind:
516 *
517 * - it will be called by cifsd
518 * - the GlobalMid_Lock will be held
519 * - the mid will be removed from the pending_mid_q list
520 */
521typedef void (mid_callback_t)(struct mid_q_entry *mid);
522
511/* one of these for every pending CIFS request to the server */ 523/* one of these for every pending CIFS request to the server */
512struct mid_q_entry { 524struct mid_q_entry {
513 struct list_head qhead; /* mids waiting on reply from this server */ 525 struct list_head qhead; /* mids waiting on reply from this server */
@@ -519,7 +531,8 @@ struct mid_q_entry {
519 unsigned long when_sent; /* time when smb send finished */ 531 unsigned long when_sent; /* time when smb send finished */
520 unsigned long when_received; /* when demux complete (taken off wire) */ 532 unsigned long when_received; /* when demux complete (taken off wire) */
521#endif 533#endif
522 struct task_struct *tsk; /* task waiting for response */ 534 mid_callback_t *callback; /* call completion callback */
535 void *callback_data; /* general purpose pointer for callback */
523 struct smb_hdr *resp_buf; /* response buffer */ 536 struct smb_hdr *resp_buf; /* response buffer */
524 int midState; /* wish this were enum but can not pass to wait_event */ 537 int midState; /* wish this were enum but can not pass to wait_event */
525 __u8 command; /* smb command code */ 538 __u8 command; /* smb command code */
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 5c7f8450dbe0..aa66de1db5f5 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -152,6 +152,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
152 152
153 /* before reconnecting the tcp session, mark the smb session (uid) 153 /* before reconnecting the tcp session, mark the smb session (uid)
154 and the tid bad so they are not used until reconnected */ 154 and the tid bad so they are not used until reconnected */
155 cFYI(1, "%s: marking sessions and tcons for reconnect", __func__);
155 spin_lock(&cifs_tcp_ses_lock); 156 spin_lock(&cifs_tcp_ses_lock);
156 list_for_each(tmp, &server->smb_ses_list) { 157 list_for_each(tmp, &server->smb_ses_list) {
157 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); 158 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
@@ -163,7 +164,9 @@ cifs_reconnect(struct TCP_Server_Info *server)
163 } 164 }
164 } 165 }
165 spin_unlock(&cifs_tcp_ses_lock); 166 spin_unlock(&cifs_tcp_ses_lock);
167
166 /* do not want to be sending data on a socket we are freeing */ 168 /* do not want to be sending data on a socket we are freeing */
169 cFYI(1, "%s: tearing down socket", __func__);
167 mutex_lock(&server->srv_mutex); 170 mutex_lock(&server->srv_mutex);
168 if (server->ssocket) { 171 if (server->ssocket) {
169 cFYI(1, "State: 0x%x Flags: 0x%lx", server->ssocket->state, 172 cFYI(1, "State: 0x%x Flags: 0x%lx", server->ssocket->state,
@@ -180,22 +183,19 @@ cifs_reconnect(struct TCP_Server_Info *server)
180 kfree(server->session_key.response); 183 kfree(server->session_key.response);
181 server->session_key.response = NULL; 184 server->session_key.response = NULL;
182 server->session_key.len = 0; 185 server->session_key.len = 0;
186 mutex_unlock(&server->srv_mutex);
183 187
188 /* mark submitted MIDs for retry and issue callback */
189 cFYI(1, "%s: issuing mid callbacks", __func__);
184 spin_lock(&GlobalMid_Lock); 190 spin_lock(&GlobalMid_Lock);
185 list_for_each(tmp, &server->pending_mid_q) { 191 list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
186 mid_entry = list_entry(tmp, struct 192 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
187 mid_q_entry, 193 if (mid_entry->midState == MID_REQUEST_SUBMITTED)
188 qhead);
189 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
190 /* Mark other intransit requests as needing
191 retry so we do not immediately mark the
192 session bad again (ie after we reconnect
193 below) as they timeout too */
194 mid_entry->midState = MID_RETRY_NEEDED; 194 mid_entry->midState = MID_RETRY_NEEDED;
195 } 195 list_del_init(&mid_entry->qhead);
196 mid_entry->callback(mid_entry);
196 } 197 }
197 spin_unlock(&GlobalMid_Lock); 198 spin_unlock(&GlobalMid_Lock);
198 mutex_unlock(&server->srv_mutex);
199 199
200 while ((server->tcpStatus != CifsExiting) && 200 while ((server->tcpStatus != CifsExiting) &&
201 (server->tcpStatus != CifsGood)) { 201 (server->tcpStatus != CifsGood)) {
@@ -212,10 +212,9 @@ cifs_reconnect(struct TCP_Server_Info *server)
212 if (server->tcpStatus != CifsExiting) 212 if (server->tcpStatus != CifsExiting)
213 server->tcpStatus = CifsGood; 213 server->tcpStatus = CifsGood;
214 spin_unlock(&GlobalMid_Lock); 214 spin_unlock(&GlobalMid_Lock);
215 /* atomic_set(&server->inFlight,0);*/
216 wake_up(&server->response_q);
217 } 215 }
218 } 216 }
217
219 return rc; 218 return rc;
220} 219}
221 220
@@ -345,7 +344,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
345 struct msghdr smb_msg; 344 struct msghdr smb_msg;
346 struct kvec iov; 345 struct kvec iov;
347 struct socket *csocket = server->ssocket; 346 struct socket *csocket = server->ssocket;
348 struct list_head *tmp; 347 struct list_head *tmp, *tmp2;
349 struct task_struct *task_to_wake = NULL; 348 struct task_struct *task_to_wake = NULL;
350 struct mid_q_entry *mid_entry; 349 struct mid_q_entry *mid_entry;
351 char temp; 350 char temp;
@@ -558,10 +557,9 @@ incomplete_rcv:
558 continue; 557 continue;
559 } 558 }
560 559
561 560 mid_entry = NULL;
562 task_to_wake = NULL;
563 spin_lock(&GlobalMid_Lock); 561 spin_lock(&GlobalMid_Lock);
564 list_for_each(tmp, &server->pending_mid_q) { 562 list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
565 mid_entry = list_entry(tmp, struct mid_q_entry, qhead); 563 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
566 564
567 if ((mid_entry->mid == smb_buffer->Mid) && 565 if ((mid_entry->mid == smb_buffer->Mid) &&
@@ -602,8 +600,9 @@ incomplete_rcv:
602 mid_entry->resp_buf = smb_buffer; 600 mid_entry->resp_buf = smb_buffer;
603 mid_entry->largeBuf = isLargeBuf; 601 mid_entry->largeBuf = isLargeBuf;
604multi_t2_fnd: 602multi_t2_fnd:
605 task_to_wake = mid_entry->tsk;
606 mid_entry->midState = MID_RESPONSE_RECEIVED; 603 mid_entry->midState = MID_RESPONSE_RECEIVED;
604 list_del_init(&mid_entry->qhead);
605 mid_entry->callback(mid_entry);
607#ifdef CONFIG_CIFS_STATS2 606#ifdef CONFIG_CIFS_STATS2
608 mid_entry->when_received = jiffies; 607 mid_entry->when_received = jiffies;
609#endif 608#endif
@@ -613,9 +612,11 @@ multi_t2_fnd:
613 server->lstrp = jiffies; 612 server->lstrp = jiffies;
614 break; 613 break;
615 } 614 }
615 mid_entry = NULL;
616 } 616 }
617 spin_unlock(&GlobalMid_Lock); 617 spin_unlock(&GlobalMid_Lock);
618 if (task_to_wake) { 618
619 if (mid_entry != NULL) {
619 /* Was previous buf put in mpx struct for multi-rsp? */ 620 /* Was previous buf put in mpx struct for multi-rsp? */
620 if (!isMultiRsp) { 621 if (!isMultiRsp) {
621 /* smb buffer will be freed by user thread */ 622 /* smb buffer will be freed by user thread */
@@ -624,7 +625,6 @@ multi_t2_fnd:
624 else 625 else
625 smallbuf = NULL; 626 smallbuf = NULL;
626 } 627 }
627 wake_up_process(task_to_wake);
628 } else if (!is_valid_oplock_break(smb_buffer, server) && 628 } else if (!is_valid_oplock_break(smb_buffer, server) &&
629 !isMultiRsp) { 629 !isMultiRsp) {
630 cERROR(1, "No task to wake, unknown frame received! " 630 cERROR(1, "No task to wake, unknown frame received! "
@@ -678,15 +678,12 @@ multi_t2_fnd:
678 678
679 if (!list_empty(&server->pending_mid_q)) { 679 if (!list_empty(&server->pending_mid_q)) {
680 spin_lock(&GlobalMid_Lock); 680 spin_lock(&GlobalMid_Lock);
681 list_for_each(tmp, &server->pending_mid_q) { 681 list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
682 mid_entry = list_entry(tmp, struct mid_q_entry, qhead); 682 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
683 if (mid_entry->midState == MID_REQUEST_SUBMITTED) { 683 cFYI(1, "Clearing Mid 0x%x - issuing callback",
684 cFYI(1, "Clearing Mid 0x%x - waking up ", 684 mid_entry->mid);
685 mid_entry->mid); 685 list_del_init(&mid_entry->qhead);
686 task_to_wake = mid_entry->tsk; 686 mid_entry->callback(mid_entry);
687 if (task_to_wake)
688 wake_up_process(task_to_wake);
689 }
690 } 687 }
691 spin_unlock(&GlobalMid_Lock); 688 spin_unlock(&GlobalMid_Lock);
692 /* 1/8th of sec is more than enough time for them to exit */ 689 /* 1/8th of sec is more than enough time for them to exit */
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 6abd1445c983..d77b6154cf22 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -36,6 +36,12 @@
36 36
37extern mempool_t *cifs_mid_poolp; 37extern mempool_t *cifs_mid_poolp;
38 38
39static void
40wake_up_task(struct mid_q_entry *mid)
41{
42 wake_up_process(mid->callback_data);
43}
44
39static struct mid_q_entry * 45static struct mid_q_entry *
40AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server) 46AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
41{ 47{
@@ -58,7 +64,13 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
58 /* do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */ 64 /* do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */
59 /* when mid allocated can be before when sent */ 65 /* when mid allocated can be before when sent */
60 temp->when_alloc = jiffies; 66 temp->when_alloc = jiffies;
61 temp->tsk = current; 67
68 /*
69 * The default is for the mid to be synchronous, so the
70 * default callback just wakes up the current task.
71 */
72 temp->callback = wake_up_task;
73 temp->callback_data = current;
62 } 74 }
63 75
64 atomic_inc(&midCount); 76 atomic_inc(&midCount);
@@ -367,6 +379,9 @@ sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
367 mid->mid, mid->midState); 379 mid->mid, mid->midState);
368 380
369 spin_lock(&GlobalMid_Lock); 381 spin_lock(&GlobalMid_Lock);
382 /* ensure that it's no longer on the pending_mid_q */
383 list_del_init(&mid->qhead);
384
370 switch (mid->midState) { 385 switch (mid->midState) {
371 case MID_RESPONSE_RECEIVED: 386 case MID_RESPONSE_RECEIVED:
372 spin_unlock(&GlobalMid_Lock); 387 spin_unlock(&GlobalMid_Lock);
@@ -389,7 +404,7 @@ sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
389 } 404 }
390 spin_unlock(&GlobalMid_Lock); 405 spin_unlock(&GlobalMid_Lock);
391 406
392 delete_mid(mid); 407 DeleteMidQEntry(mid);
393 return rc; 408 return rc;
394} 409}
395 410