diff options
author | Steve French <sfrench@us.ibm.com> | 2005-11-29 23:55:11 -0500 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2005-11-29 23:55:11 -0500 |
commit | 6ab16d249513a50bef3f1b275cea6aa8d3f51832 (patch) | |
tree | 6440fb91b6336e3dc988f06d951ab272610000fb | |
parent | 6473a559c336d5c407f9df412ca2f55357767ff8 (diff) |
[CIFS] Fix umount --force to wake up the pending response queue, not just
the request queue. Also periodically wakeup response_q so threads can
check if stuck requests have timed out. Workaround Windows server illegal smb
length on transact2 findfirst response.
Signed-off-by: Steve French <sfrench@us.ibm.com>
-rw-r--r-- | fs/cifs/cifsfs.c | 23 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 25 | ||||
-rw-r--r-- | fs/cifs/misc.c | 17 | ||||
-rw-r--r-- | fs/cifs/netmisc.c | 4 | ||||
-rw-r--r-- | fs/cifs/transport.c | 1 |
5 files changed, 62 insertions, 8 deletions
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 51548ed2e9cc..f4974b41e485 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/seq_file.h> | 32 | #include <linux/seq_file.h> |
33 | #include <linux/vfs.h> | 33 | #include <linux/vfs.h> |
34 | #include <linux/mempool.h> | 34 | #include <linux/mempool.h> |
35 | #include <linux/delay.h> | ||
35 | #include "cifsfs.h" | 36 | #include "cifsfs.h" |
36 | #include "cifspdu.h" | 37 | #include "cifspdu.h" |
37 | #define DECLARE_GLOBALS_HERE | 38 | #define DECLARE_GLOBALS_HERE |
@@ -429,6 +430,11 @@ static void cifs_umount_begin(struct super_block * sblock) | |||
429 | { | 430 | { |
430 | cFYI(1,("wake up tasks now - umount begin not complete")); | 431 | cFYI(1,("wake up tasks now - umount begin not complete")); |
431 | wake_up_all(&tcon->ses->server->request_q); | 432 | wake_up_all(&tcon->ses->server->request_q); |
433 | wake_up_all(&tcon->ses->server->response_q); | ||
434 | msleep(1); /* yield */ | ||
435 | /* we have to kick the requests once more */ | ||
436 | wake_up_all(&tcon->ses->server->response_q); | ||
437 | msleep(1); | ||
432 | } | 438 | } |
433 | /* BB FIXME - finish add checks for tidStatus BB */ | 439 | /* BB FIXME - finish add checks for tidStatus BB */ |
434 | 440 | ||
@@ -895,6 +901,9 @@ static int cifs_oplock_thread(void * dummyarg) | |||
895 | 901 | ||
896 | static int cifs_dnotify_thread(void * dummyarg) | 902 | static int cifs_dnotify_thread(void * dummyarg) |
897 | { | 903 | { |
904 | struct list_head *tmp; | ||
905 | struct cifsSesInfo *ses; | ||
906 | |||
898 | daemonize("cifsdnotifyd"); | 907 | daemonize("cifsdnotifyd"); |
899 | allow_signal(SIGTERM); | 908 | allow_signal(SIGTERM); |
900 | 909 | ||
@@ -903,7 +912,19 @@ static int cifs_dnotify_thread(void * dummyarg) | |||
903 | if(try_to_freeze()) | 912 | if(try_to_freeze()) |
904 | continue; | 913 | continue; |
905 | set_current_state(TASK_INTERRUPTIBLE); | 914 | set_current_state(TASK_INTERRUPTIBLE); |
906 | schedule_timeout(39*HZ); | 915 | schedule_timeout(15*HZ); |
916 | read_lock(&GlobalSMBSeslock); | ||
917 | /* check if any stuck requests that need | ||
918 | to be woken up and wakeq so the | ||
919 | thread can wake up and error out */ | ||
920 | list_for_each(tmp, &GlobalSMBSessionList) { | ||
921 | ses = list_entry(tmp, struct cifsSesInfo, | ||
922 | cifsSessionList); | ||
923 | if(ses && ses->server && | ||
924 | atomic_read(&ses->server->inSend)) | ||
925 | wake_up_all(&ses->server->response_q); | ||
926 | } | ||
927 | read_unlock(&GlobalSMBSeslock); | ||
907 | } while(!signal_pending(current)); | 928 | } while(!signal_pending(current)); |
908 | complete_and_exit (&cifs_dnotify_exited, 0); | 929 | complete_and_exit (&cifs_dnotify_exited, 0); |
909 | } | 930 | } |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index d179b0c3eee4..6867e556d37e 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -90,6 +90,18 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
90 | check for tcp and smb session status done differently | 90 | check for tcp and smb session status done differently |
91 | for those three - in the calling routine */ | 91 | for those three - in the calling routine */ |
92 | if(tcon) { | 92 | if(tcon) { |
93 | if(tcon->tidStatus == CifsExiting) { | ||
94 | /* only tree disconnect, open, and write, | ||
95 | (and ulogoff which does not have tcon) | ||
96 | are allowed as we start force umount */ | ||
97 | if((smb_command != SMB_COM_WRITE_ANDX) && | ||
98 | (smb_command != SMB_COM_OPEN_ANDX) && | ||
99 | (smb_command != SMB_COM_TREE_DISCONNECT)) { | ||
100 | cFYI(1,("can not send cmd %d while umounting", | ||
101 | smb_command)); | ||
102 | return -ENODEV; | ||
103 | } | ||
104 | } | ||
93 | if((tcon->ses) && (tcon->ses->status != CifsExiting) && | 105 | if((tcon->ses) && (tcon->ses->status != CifsExiting) && |
94 | (tcon->ses->server)){ | 106 | (tcon->ses->server)){ |
95 | struct nls_table *nls_codepage; | 107 | struct nls_table *nls_codepage; |
@@ -187,6 +199,19 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
187 | check for tcp and smb session status done differently | 199 | check for tcp and smb session status done differently |
188 | for those three - in the calling routine */ | 200 | for those three - in the calling routine */ |
189 | if(tcon) { | 201 | if(tcon) { |
202 | if(tcon->tidStatus == CifsExiting) { | ||
203 | /* only tree disconnect, open, and write, | ||
204 | (and ulogoff which does not have tcon) | ||
205 | are allowed as we start force umount */ | ||
206 | if((smb_command != SMB_COM_WRITE_ANDX) && | ||
207 | (smb_command != SMB_COM_OPEN_ANDX) && | ||
208 | (smb_command != SMB_COM_TREE_DISCONNECT)) { | ||
209 | cFYI(1,("can not send cmd %d while umounting", | ||
210 | smb_command)); | ||
211 | return -ENODEV; | ||
212 | } | ||
213 | } | ||
214 | |||
190 | if((tcon->ses) && (tcon->ses->status != CifsExiting) && | 215 | if((tcon->ses) && (tcon->ses->status != CifsExiting) && |
191 | (tcon->ses->server)){ | 216 | (tcon->ses->server)){ |
192 | struct nls_table *nls_codepage; | 217 | struct nls_table *nls_codepage; |
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index ca27a82c54cd..94baf6c8ecbd 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
@@ -397,12 +397,12 @@ checkSMBhdr(struct smb_hdr *smb, __u16 mid) | |||
397 | if(smb->Command == SMB_COM_LOCKING_ANDX) | 397 | if(smb->Command == SMB_COM_LOCKING_ANDX) |
398 | return 0; | 398 | return 0; |
399 | else | 399 | else |
400 | cERROR(1, ("Rcvd Request not response ")); | 400 | cERROR(1, ("Rcvd Request not response")); |
401 | } | 401 | } |
402 | } else { /* bad signature or mid */ | 402 | } else { /* bad signature or mid */ |
403 | if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff)) | 403 | if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff)) |
404 | cERROR(1, | 404 | cERROR(1, |
405 | ("Bad protocol string signature header %x ", | 405 | ("Bad protocol string signature header %x", |
406 | *(unsigned int *) smb->Protocol)); | 406 | *(unsigned int *) smb->Protocol)); |
407 | if (mid != smb->Mid) | 407 | if (mid != smb->Mid) |
408 | cERROR(1, ("Mids do not match")); | 408 | cERROR(1, ("Mids do not match")); |
@@ -417,7 +417,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length) | |||
417 | __u32 len = smb->smb_buf_length; | 417 | __u32 len = smb->smb_buf_length; |
418 | __u32 clc_len; /* calculated length */ | 418 | __u32 clc_len; /* calculated length */ |
419 | cFYI(0, | 419 | cFYI(0, |
420 | ("Entering checkSMB with Length: %x, smb_buf_length: %x ", | 420 | ("Entering checkSMB with Length: %x, smb_buf_length: %x", |
421 | length, len)); | 421 | length, len)); |
422 | if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) || | 422 | if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) || |
423 | (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)) { | 423 | (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)) { |
@@ -451,9 +451,16 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length) | |||
451 | cERROR(1, ("bad smb size detected for Mid=%d", smb->Mid)); | 451 | cERROR(1, ("bad smb size detected for Mid=%d", smb->Mid)); |
452 | /* Windows XP can return a few bytes too much, presumably | 452 | /* Windows XP can return a few bytes too much, presumably |
453 | an illegal pad, at the end of byte range lock responses | 453 | an illegal pad, at the end of byte range lock responses |
454 | so we allow for up to eight byte pad, as long as actual | 454 | so we allow for that three byte pad, as long as actual |
455 | received length is as long or longer than calculated length */ | 455 | received length is as long or longer than calculated length */ |
456 | if((4+len > clc_len) && (len <= clc_len + 3)) | 456 | /* We have now had to extend this more, since there is a |
457 | case in which it needs to be bigger still to handle a | ||
458 | malformed response to transact2 findfirst from WinXP when | ||
459 | access denied is returned and thus bcc and wct are zero | ||
460 | but server says length is 0x21 bytes too long as if the server | ||
461 | forget to reset the smb rfc1001 length when it reset the | ||
462 | wct and bcc to minimum size and drop the t2 parms and data */ | ||
463 | if((4+len > clc_len) && (len <= clc_len + 512)) | ||
457 | return 0; | 464 | return 0; |
458 | else | 465 | else |
459 | return 1; | 466 | return 1; |
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index f7814689844b..5de74d216fdd 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c | |||
@@ -330,7 +330,7 @@ static const struct { | |||
330 | ERRHRD, ERRgeneral, NT_STATUS_ACCOUNT_RESTRICTION}, { | 330 | ERRHRD, ERRgeneral, NT_STATUS_ACCOUNT_RESTRICTION}, { |
331 | ERRSRV, 2241, NT_STATUS_INVALID_LOGON_HOURS}, { | 331 | ERRSRV, 2241, NT_STATUS_INVALID_LOGON_HOURS}, { |
332 | ERRSRV, 2240, NT_STATUS_INVALID_WORKSTATION}, { | 332 | ERRSRV, 2240, NT_STATUS_INVALID_WORKSTATION}, { |
333 | ERRSRV, 2242, NT_STATUS_PASSWORD_EXPIRED}, { | 333 | ERRSRV, ERRpasswordExpired, NT_STATUS_PASSWORD_EXPIRED}, { |
334 | ERRSRV, 2239, NT_STATUS_ACCOUNT_DISABLED}, { | 334 | ERRSRV, 2239, NT_STATUS_ACCOUNT_DISABLED}, { |
335 | ERRHRD, ERRgeneral, NT_STATUS_NONE_MAPPED}, { | 335 | ERRHRD, ERRgeneral, NT_STATUS_NONE_MAPPED}, { |
336 | ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LUIDS_REQUESTED}, { | 336 | ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LUIDS_REQUESTED}, { |
@@ -676,7 +676,7 @@ static const struct { | |||
676 | ERRDOS, 193, NT_STATUS_IMAGE_CHECKSUM_MISMATCH}, { | 676 | ERRDOS, 193, NT_STATUS_IMAGE_CHECKSUM_MISMATCH}, { |
677 | ERRHRD, ERRgeneral, NT_STATUS_LOST_WRITEBEHIND_DATA}, { | 677 | ERRHRD, ERRgeneral, NT_STATUS_LOST_WRITEBEHIND_DATA}, { |
678 | ERRHRD, ERRgeneral, NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID}, { | 678 | ERRHRD, ERRgeneral, NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID}, { |
679 | ERRSRV, 2242, NT_STATUS_PASSWORD_MUST_CHANGE}, { | 679 | ERRSRV, ERRpasswordExpired, NT_STATUS_PASSWORD_MUST_CHANGE}, { |
680 | ERRHRD, ERRgeneral, NT_STATUS_NOT_FOUND}, { | 680 | ERRHRD, ERRgeneral, NT_STATUS_NOT_FOUND}, { |
681 | ERRHRD, ERRgeneral, NT_STATUS_NOT_TINY_STREAM}, { | 681 | ERRHRD, ERRgeneral, NT_STATUS_NOT_TINY_STREAM}, { |
682 | ERRHRD, ERRgeneral, NT_STATUS_RECOVERY_FAILURE}, { | 682 | ERRHRD, ERRgeneral, NT_STATUS_RECOVERY_FAILURE}, { |
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 41a9659c16bc..f8871196098c 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -515,6 +515,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
515 | *pbytes_returned = in_buf->smb_buf_length; | 515 | *pbytes_returned = in_buf->smb_buf_length; |
516 | 516 | ||
517 | /* BB special case reconnect tid and uid here? */ | 517 | /* BB special case reconnect tid and uid here? */ |
518 | /* BB special case Errbadpassword and pwdexpired here */ | ||
518 | rc = map_smb_to_linux_error(in_buf); | 519 | rc = map_smb_to_linux_error(in_buf); |
519 | 520 | ||
520 | /* convert ByteCount if necessary */ | 521 | /* convert ByteCount if necessary */ |