Skip to content

Commit 6ab16d2

Browse files
author
Steve French
committed
[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 <[email protected]>
1 parent 6473a55 commit 6ab16d2

File tree

5 files changed

+62
-8
lines changed

5 files changed

+62
-8
lines changed

fs/cifs/cifsfs.c

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include <linux/seq_file.h>
3333
#include <linux/vfs.h>
3434
#include <linux/mempool.h>
35+
#include <linux/delay.h>
3536
#include "cifsfs.h"
3637
#include "cifspdu.h"
3738
#define DECLARE_GLOBALS_HERE
@@ -429,6 +430,11 @@ static void cifs_umount_begin(struct super_block * sblock)
429430
{
430431
cFYI(1,("wake up tasks now - umount begin not complete"));
431432
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);
432438
}
433439
/* BB FIXME - finish add checks for tidStatus BB */
434440

@@ -895,6 +901,9 @@ static int cifs_oplock_thread(void * dummyarg)
895901

896902
static int cifs_dnotify_thread(void * dummyarg)
897903
{
904+
struct list_head *tmp;
905+
struct cifsSesInfo *ses;
906+
898907
daemonize("cifsdnotifyd");
899908
allow_signal(SIGTERM);
900909

@@ -903,7 +912,19 @@ static int cifs_dnotify_thread(void * dummyarg)
903912
if(try_to_freeze())
904913
continue;
905914
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);
907928
} while(!signal_pending(current));
908929
complete_and_exit (&cifs_dnotify_exited, 0);
909930
}

fs/cifs/cifssmb.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,18 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
9090
check for tcp and smb session status done differently
9191
for those three - in the calling routine */
9292
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+
}
93105
if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
94106
(tcon->ses->server)){
95107
struct nls_table *nls_codepage;
@@ -187,6 +199,19 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
187199
check for tcp and smb session status done differently
188200
for those three - in the calling routine */
189201
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+
190215
if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
191216
(tcon->ses->server)){
192217
struct nls_table *nls_codepage;

fs/cifs/misc.c

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -397,12 +397,12 @@ checkSMBhdr(struct smb_hdr *smb, __u16 mid)
397397
if(smb->Command == SMB_COM_LOCKING_ANDX)
398398
return 0;
399399
else
400-
cERROR(1, ("Rcvd Request not response "));
400+
cERROR(1, ("Rcvd Request not response"));
401401
}
402402
} else { /* bad signature or mid */
403403
if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff))
404404
cERROR(1,
405-
("Bad protocol string signature header %x ",
405+
("Bad protocol string signature header %x",
406406
*(unsigned int *) smb->Protocol));
407407
if (mid != smb->Mid)
408408
cERROR(1, ("Mids do not match"));
@@ -417,7 +417,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length)
417417
__u32 len = smb->smb_buf_length;
418418
__u32 clc_len; /* calculated length */
419419
cFYI(0,
420-
("Entering checkSMB with Length: %x, smb_buf_length: %x ",
420+
("Entering checkSMB with Length: %x, smb_buf_length: %x",
421421
length, len));
422422
if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) ||
423423
(len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)) {
@@ -451,9 +451,16 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length)
451451
cERROR(1, ("bad smb size detected for Mid=%d", smb->Mid));
452452
/* Windows XP can return a few bytes too much, presumably
453453
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
455455
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))
457464
return 0;
458465
else
459466
return 1;

fs/cifs/netmisc.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ static const struct {
330330
ERRHRD, ERRgeneral, NT_STATUS_ACCOUNT_RESTRICTION}, {
331331
ERRSRV, 2241, NT_STATUS_INVALID_LOGON_HOURS}, {
332332
ERRSRV, 2240, NT_STATUS_INVALID_WORKSTATION}, {
333-
ERRSRV, 2242, NT_STATUS_PASSWORD_EXPIRED}, {
333+
ERRSRV, ERRpasswordExpired, NT_STATUS_PASSWORD_EXPIRED}, {
334334
ERRSRV, 2239, NT_STATUS_ACCOUNT_DISABLED}, {
335335
ERRHRD, ERRgeneral, NT_STATUS_NONE_MAPPED}, {
336336
ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LUIDS_REQUESTED}, {
@@ -676,7 +676,7 @@ static const struct {
676676
ERRDOS, 193, NT_STATUS_IMAGE_CHECKSUM_MISMATCH}, {
677677
ERRHRD, ERRgeneral, NT_STATUS_LOST_WRITEBEHIND_DATA}, {
678678
ERRHRD, ERRgeneral, NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID}, {
679-
ERRSRV, 2242, NT_STATUS_PASSWORD_MUST_CHANGE}, {
679+
ERRSRV, ERRpasswordExpired, NT_STATUS_PASSWORD_MUST_CHANGE}, {
680680
ERRHRD, ERRgeneral, NT_STATUS_NOT_FOUND}, {
681681
ERRHRD, ERRgeneral, NT_STATUS_NOT_TINY_STREAM}, {
682682
ERRHRD, ERRgeneral, NT_STATUS_RECOVERY_FAILURE}, {

fs/cifs/transport.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
515515
*pbytes_returned = in_buf->smb_buf_length;
516516

517517
/* BB special case reconnect tid and uid here? */
518+
/* BB special case Errbadpassword and pwdexpired here */
518519
rc = map_smb_to_linux_error(in_buf);
519520

520521
/* convert ByteCount if necessary */

0 commit comments

Comments
 (0)