[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>
This commit is contained in:
parent
6473a559c3
commit
6ab16d2495
|
@ -32,6 +32,7 @@
|
||||||
#include <linux/seq_file.h>
|
#include <linux/seq_file.h>
|
||||||
#include <linux/vfs.h>
|
#include <linux/vfs.h>
|
||||||
#include <linux/mempool.h>
|
#include <linux/mempool.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
#include "cifsfs.h"
|
#include "cifsfs.h"
|
||||||
#include "cifspdu.h"
|
#include "cifspdu.h"
|
||||||
#define DECLARE_GLOBALS_HERE
|
#define DECLARE_GLOBALS_HERE
|
||||||
|
@ -429,6 +430,11 @@ static void cifs_umount_begin(struct super_block * sblock)
|
||||||
{
|
{
|
||||||
cFYI(1,("wake up tasks now - umount begin not complete"));
|
cFYI(1,("wake up tasks now - umount begin not complete"));
|
||||||
wake_up_all(&tcon->ses->server->request_q);
|
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 */
|
/* BB FIXME - finish add checks for tidStatus BB */
|
||||||
|
|
||||||
|
@ -895,6 +901,9 @@ static int cifs_oplock_thread(void * dummyarg)
|
||||||
|
|
||||||
static int cifs_dnotify_thread(void * dummyarg)
|
static int cifs_dnotify_thread(void * dummyarg)
|
||||||
{
|
{
|
||||||
|
struct list_head *tmp;
|
||||||
|
struct cifsSesInfo *ses;
|
||||||
|
|
||||||
daemonize("cifsdnotifyd");
|
daemonize("cifsdnotifyd");
|
||||||
allow_signal(SIGTERM);
|
allow_signal(SIGTERM);
|
||||||
|
|
||||||
|
@ -903,7 +912,19 @@ static int cifs_dnotify_thread(void * dummyarg)
|
||||||
if(try_to_freeze())
|
if(try_to_freeze())
|
||||||
continue;
|
continue;
|
||||||
set_current_state(TASK_INTERRUPTIBLE);
|
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));
|
} while(!signal_pending(current));
|
||||||
complete_and_exit (&cifs_dnotify_exited, 0);
|
complete_and_exit (&cifs_dnotify_exited, 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,6 +90,18 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
|
||||||
check for tcp and smb session status done differently
|
check for tcp and smb session status done differently
|
||||||
for those three - in the calling routine */
|
for those three - in the calling routine */
|
||||||
if(tcon) {
|
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) &&
|
if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
|
||||||
(tcon->ses->server)){
|
(tcon->ses->server)){
|
||||||
struct nls_table *nls_codepage;
|
struct nls_table *nls_codepage;
|
||||||
|
@ -187,6 +199,19 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
|
||||||
check for tcp and smb session status done differently
|
check for tcp and smb session status done differently
|
||||||
for those three - in the calling routine */
|
for those three - in the calling routine */
|
||||||
if(tcon) {
|
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) &&
|
if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
|
||||||
(tcon->ses->server)){
|
(tcon->ses->server)){
|
||||||
struct nls_table *nls_codepage;
|
struct nls_table *nls_codepage;
|
||||||
|
|
|
@ -397,12 +397,12 @@ checkSMBhdr(struct smb_hdr *smb, __u16 mid)
|
||||||
if(smb->Command == SMB_COM_LOCKING_ANDX)
|
if(smb->Command == SMB_COM_LOCKING_ANDX)
|
||||||
return 0;
|
return 0;
|
||||||
else
|
else
|
||||||
cERROR(1, ("Rcvd Request not response "));
|
cERROR(1, ("Rcvd Request not response"));
|
||||||
}
|
}
|
||||||
} else { /* bad signature or mid */
|
} else { /* bad signature or mid */
|
||||||
if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff))
|
if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff))
|
||||||
cERROR(1,
|
cERROR(1,
|
||||||
("Bad protocol string signature header %x ",
|
("Bad protocol string signature header %x",
|
||||||
*(unsigned int *) smb->Protocol));
|
*(unsigned int *) smb->Protocol));
|
||||||
if (mid != smb->Mid)
|
if (mid != smb->Mid)
|
||||||
cERROR(1, ("Mids do not match"));
|
cERROR(1, ("Mids do not match"));
|
||||||
|
@ -417,7 +417,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length)
|
||||||
__u32 len = smb->smb_buf_length;
|
__u32 len = smb->smb_buf_length;
|
||||||
__u32 clc_len; /* calculated length */
|
__u32 clc_len; /* calculated length */
|
||||||
cFYI(0,
|
cFYI(0,
|
||||||
("Entering checkSMB with Length: %x, smb_buf_length: %x ",
|
("Entering checkSMB with Length: %x, smb_buf_length: %x",
|
||||||
length, len));
|
length, len));
|
||||||
if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) ||
|
if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) ||
|
||||||
(len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)) {
|
(len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)) {
|
||||||
|
@ -451,9 +451,16 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length)
|
||||||
cERROR(1, ("bad smb size detected for Mid=%d", smb->Mid));
|
cERROR(1, ("bad smb size detected for Mid=%d", smb->Mid));
|
||||||
/* Windows XP can return a few bytes too much, presumably
|
/* Windows XP can return a few bytes too much, presumably
|
||||||
an illegal pad, at the end of byte range lock responses
|
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 */
|
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;
|
return 0;
|
||||||
else
|
else
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -330,7 +330,7 @@ static const struct {
|
||||||
ERRHRD, ERRgeneral, NT_STATUS_ACCOUNT_RESTRICTION}, {
|
ERRHRD, ERRgeneral, NT_STATUS_ACCOUNT_RESTRICTION}, {
|
||||||
ERRSRV, 2241, NT_STATUS_INVALID_LOGON_HOURS}, {
|
ERRSRV, 2241, NT_STATUS_INVALID_LOGON_HOURS}, {
|
||||||
ERRSRV, 2240, NT_STATUS_INVALID_WORKSTATION}, {
|
ERRSRV, 2240, NT_STATUS_INVALID_WORKSTATION}, {
|
||||||
ERRSRV, 2242, NT_STATUS_PASSWORD_EXPIRED}, {
|
ERRSRV, ERRpasswordExpired, NT_STATUS_PASSWORD_EXPIRED}, {
|
||||||
ERRSRV, 2239, NT_STATUS_ACCOUNT_DISABLED}, {
|
ERRSRV, 2239, NT_STATUS_ACCOUNT_DISABLED}, {
|
||||||
ERRHRD, ERRgeneral, NT_STATUS_NONE_MAPPED}, {
|
ERRHRD, ERRgeneral, NT_STATUS_NONE_MAPPED}, {
|
||||||
ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LUIDS_REQUESTED}, {
|
ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LUIDS_REQUESTED}, {
|
||||||
|
@ -676,7 +676,7 @@ static const struct {
|
||||||
ERRDOS, 193, NT_STATUS_IMAGE_CHECKSUM_MISMATCH}, {
|
ERRDOS, 193, NT_STATUS_IMAGE_CHECKSUM_MISMATCH}, {
|
||||||
ERRHRD, ERRgeneral, NT_STATUS_LOST_WRITEBEHIND_DATA}, {
|
ERRHRD, ERRgeneral, NT_STATUS_LOST_WRITEBEHIND_DATA}, {
|
||||||
ERRHRD, ERRgeneral, NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID}, {
|
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_FOUND}, {
|
||||||
ERRHRD, ERRgeneral, NT_STATUS_NOT_TINY_STREAM}, {
|
ERRHRD, ERRgeneral, NT_STATUS_NOT_TINY_STREAM}, {
|
||||||
ERRHRD, ERRgeneral, NT_STATUS_RECOVERY_FAILURE}, {
|
ERRHRD, ERRgeneral, NT_STATUS_RECOVERY_FAILURE}, {
|
||||||
|
|
|
@ -515,6 +515,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
||||||
*pbytes_returned = in_buf->smb_buf_length;
|
*pbytes_returned = in_buf->smb_buf_length;
|
||||||
|
|
||||||
/* BB special case reconnect tid and uid here? */
|
/* BB special case reconnect tid and uid here? */
|
||||||
|
/* BB special case Errbadpassword and pwdexpired here */
|
||||||
rc = map_smb_to_linux_error(in_buf);
|
rc = map_smb_to_linux_error(in_buf);
|
||||||
|
|
||||||
/* convert ByteCount if necessary */
|
/* convert ByteCount if necessary */
|
||||||
|
|
Loading…
Reference in New Issue