diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/cifs/cifs_debug.c | 8 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 15 | ||||
-rw-r--r-- | fs/cifs/connect.c | 53 | ||||
-rw-r--r-- | fs/cifs/transport.c | 19 |
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 | ||
511 | struct 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 | */ | ||
521 | typedef 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 */ |
512 | struct mid_q_entry { | 524 | struct 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; |
604 | multi_t2_fnd: | 602 | multi_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 | ||
37 | extern mempool_t *cifs_mid_poolp; | 37 | extern mempool_t *cifs_mid_poolp; |
38 | 38 | ||
39 | static void | ||
40 | wake_up_task(struct mid_q_entry *mid) | ||
41 | { | ||
42 | wake_up_process(mid->callback_data); | ||
43 | } | ||
44 | |||
39 | static struct mid_q_entry * | 45 | static struct mid_q_entry * |
40 | AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server) | 46 | AllocMidQEntry(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 | ||