Skip to content

Commit

Permalink
[CIFS] Fix umount --force to wake up the pending response queue, not …
Browse files Browse the repository at this point in the history
…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>
  • Loading branch information
Steve French committed Nov 30, 2005
1 parent 6473a55 commit 6ab16d2
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 8 deletions.
23 changes: 22 additions & 1 deletion fs/cifs/cifsfs.c
Expand Up @@ -32,6 +32,7 @@
#include <linux/seq_file.h>
#include <linux/vfs.h>
#include <linux/mempool.h>
#include <linux/delay.h>
#include "cifsfs.h"
#include "cifspdu.h"
#define DECLARE_GLOBALS_HERE
Expand Down Expand Up @@ -429,6 +430,11 @@ static void cifs_umount_begin(struct super_block * sblock)
{
cFYI(1,("wake up tasks now - umount begin not complete"));
wake_up_all(&tcon->ses->server->request_q);
wake_up_all(&tcon->ses->server->response_q);
msleep(1); /* yield */
/* we have to kick the requests once more */
wake_up_all(&tcon->ses->server->response_q);
msleep(1);
}
/* BB FIXME - finish add checks for tidStatus BB */

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

static int cifs_dnotify_thread(void * dummyarg)
{
struct list_head *tmp;
struct cifsSesInfo *ses;

daemonize("cifsdnotifyd");
allow_signal(SIGTERM);

Expand All @@ -903,7 +912,19 @@ static int cifs_dnotify_thread(void * dummyarg)
if(try_to_freeze())
continue;
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(39*HZ);
schedule_timeout(15*HZ);
read_lock(&GlobalSMBSeslock);
/* check if any stuck requests that need
to be woken up and wakeq so the
thread can wake up and error out */
list_for_each(tmp, &GlobalSMBSessionList) {
ses = list_entry(tmp, struct cifsSesInfo,
cifsSessionList);
if(ses && ses->server &&
atomic_read(&ses->server->inSend))
wake_up_all(&ses->server->response_q);
}
read_unlock(&GlobalSMBSeslock);
} while(!signal_pending(current));
complete_and_exit (&cifs_dnotify_exited, 0);
}
Expand Down
25 changes: 25 additions & 0 deletions fs/cifs/cifssmb.c
Expand Up @@ -90,6 +90,18 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
check for tcp and smb session status done differently
for those three - in the calling routine */
if(tcon) {
if(tcon->tidStatus == CifsExiting) {
/* only tree disconnect, open, and write,
(and ulogoff which does not have tcon)
are allowed as we start force umount */
if((smb_command != SMB_COM_WRITE_ANDX) &&
(smb_command != SMB_COM_OPEN_ANDX) &&
(smb_command != SMB_COM_TREE_DISCONNECT)) {
cFYI(1,("can not send cmd %d while umounting",
smb_command));
return -ENODEV;
}
}
if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
(tcon->ses->server)){
struct nls_table *nls_codepage;
Expand Down Expand Up @@ -187,6 +199,19 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
check for tcp and smb session status done differently
for those three - in the calling routine */
if(tcon) {
if(tcon->tidStatus == CifsExiting) {
/* only tree disconnect, open, and write,
(and ulogoff which does not have tcon)
are allowed as we start force umount */
if((smb_command != SMB_COM_WRITE_ANDX) &&
(smb_command != SMB_COM_OPEN_ANDX) &&
(smb_command != SMB_COM_TREE_DISCONNECT)) {
cFYI(1,("can not send cmd %d while umounting",
smb_command));
return -ENODEV;
}
}

if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
(tcon->ses->server)){
struct nls_table *nls_codepage;
Expand Down
17 changes: 12 additions & 5 deletions fs/cifs/misc.c
Expand Up @@ -397,12 +397,12 @@ checkSMBhdr(struct smb_hdr *smb, __u16 mid)
if(smb->Command == SMB_COM_LOCKING_ANDX)
return 0;
else
cERROR(1, ("Rcvd Request not response "));
cERROR(1, ("Rcvd Request not response"));
}
} else { /* bad signature or mid */
if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff))
cERROR(1,
("Bad protocol string signature header %x ",
("Bad protocol string signature header %x",
*(unsigned int *) smb->Protocol));
if (mid != smb->Mid)
cERROR(1, ("Mids do not match"));
Expand All @@ -417,7 +417,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length)
__u32 len = smb->smb_buf_length;
__u32 clc_len; /* calculated length */
cFYI(0,
("Entering checkSMB with Length: %x, smb_buf_length: %x ",
("Entering checkSMB with Length: %x, smb_buf_length: %x",
length, len));
if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) ||
(len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)) {
Expand Down Expand Up @@ -451,9 +451,16 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length)
cERROR(1, ("bad smb size detected for Mid=%d", smb->Mid));
/* Windows XP can return a few bytes too much, presumably
an illegal pad, at the end of byte range lock responses
so we allow for up to eight byte pad, as long as actual
so we allow for that three byte pad, as long as actual
received length is as long or longer than calculated length */
if((4+len > clc_len) && (len <= clc_len + 3))
/* We have now had to extend this more, since there is a
case in which it needs to be bigger still to handle a
malformed response to transact2 findfirst from WinXP when
access denied is returned and thus bcc and wct are zero
but server says length is 0x21 bytes too long as if the server
forget to reset the smb rfc1001 length when it reset the
wct and bcc to minimum size and drop the t2 parms and data */
if((4+len > clc_len) && (len <= clc_len + 512))
return 0;
else
return 1;
Expand Down
4 changes: 2 additions & 2 deletions fs/cifs/netmisc.c
Expand Up @@ -330,7 +330,7 @@ static const struct {
ERRHRD, ERRgeneral, NT_STATUS_ACCOUNT_RESTRICTION}, {
ERRSRV, 2241, NT_STATUS_INVALID_LOGON_HOURS}, {
ERRSRV, 2240, NT_STATUS_INVALID_WORKSTATION}, {
ERRSRV, 2242, NT_STATUS_PASSWORD_EXPIRED}, {
ERRSRV, ERRpasswordExpired, NT_STATUS_PASSWORD_EXPIRED}, {
ERRSRV, 2239, NT_STATUS_ACCOUNT_DISABLED}, {
ERRHRD, ERRgeneral, NT_STATUS_NONE_MAPPED}, {
ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LUIDS_REQUESTED}, {
Expand Down Expand Up @@ -676,7 +676,7 @@ static const struct {
ERRDOS, 193, NT_STATUS_IMAGE_CHECKSUM_MISMATCH}, {
ERRHRD, ERRgeneral, NT_STATUS_LOST_WRITEBEHIND_DATA}, {
ERRHRD, ERRgeneral, NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID}, {
ERRSRV, 2242, NT_STATUS_PASSWORD_MUST_CHANGE}, {
ERRSRV, ERRpasswordExpired, NT_STATUS_PASSWORD_MUST_CHANGE}, {
ERRHRD, ERRgeneral, NT_STATUS_NOT_FOUND}, {
ERRHRD, ERRgeneral, NT_STATUS_NOT_TINY_STREAM}, {
ERRHRD, ERRgeneral, NT_STATUS_RECOVERY_FAILURE}, {
Expand Down
1 change: 1 addition & 0 deletions fs/cifs/transport.c
Expand Up @@ -515,6 +515,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
*pbytes_returned = in_buf->smb_buf_length;

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

/* convert ByteCount if necessary */
Expand Down

0 comments on commit 6ab16d2

Please sign in to comment.