cifs: consolidate reconnect logic in smb_init routines

There's a large cut and paste chunk of code in smb_init and
small_smb_init to handle reconnects. Break it out into a separate
function, clean it up and have both routines call it.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
This commit is contained in:
Jeff Layton 2009-09-03 12:07:17 -04:00 committed by Steve French
parent 6ab409b53d
commit 9162ab2000
1 changed files with 124 additions and 190 deletions

View File

@ -100,6 +100,128 @@ static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
to this tcon */
}
/* reconnect the socket, tcon, and smb session if needed */
static int
cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command)
{
int rc = 0;
struct cifsSesInfo *ses;
struct TCP_Server_Info *server;
struct nls_table *nls_codepage;
/*
* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
* tcp and smb session status done differently for those three - in the
* calling routine
*/
if (!tcon)
return 0;
ses = tcon->ses;
server = ses->server;
/*
* only tree disconnect, open, and write, (and ulogoff which does not
* have tcon) are allowed as we start force umount
*/
if (tcon->tidStatus == CifsExiting) {
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 (ses->status == CifsExiting)
return -EIO;
/*
* Give demultiplex thread up to 10 seconds to reconnect, should be
* greater than cifs socket timeout which is 7 seconds
*/
while (server->tcpStatus == CifsNeedReconnect) {
wait_event_interruptible_timeout(server->response_q,
(server->tcpStatus == CifsGood), 10 * HZ);
/* is TCP session is reestablished now ?*/
if (server->tcpStatus != CifsNeedReconnect)
break;
/*
* on "soft" mounts we wait once. Hard mounts keep
* retrying until process is killed or server comes
* back on-line
*/
if (!tcon->retry || ses->status == CifsExiting) {
cFYI(1, ("gave up waiting on reconnect in smb_init"));
return -EHOSTDOWN;
}
}
if (!ses->need_reconnect && !tcon->need_reconnect)
return 0;
nls_codepage = load_nls_default();
/*
* need to prevent multiple threads trying to simultaneously
* reconnect the same SMB session
*/
down(&ses->sesSem);
if (ses->need_reconnect)
rc = cifs_setup_session(0, ses, nls_codepage);
/* do we need to reconnect tcon? */
if (rc || !tcon->need_reconnect) {
up(&ses->sesSem);
goto out;
}
mark_open_files_invalid(tcon);
rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
up(&ses->sesSem);
cFYI(1, ("reconnect tcon rc = %d", rc));
if (rc)
goto out;
/*
* FIXME: check if wsize needs updated due to negotiated smb buffer
* size shrinking
*/
atomic_inc(&tconInfoReconnectCount);
/* tell server Unix caps we support */
if (ses->capabilities & CAP_UNIX)
reset_cifs_unix_caps(0, tcon, NULL, NULL);
/*
* Removed call to reopen open files here. It is safer (and faster) to
* reopen files one at a time as needed in read and write.
*
* FIXME: what about file locks? don't we need to reclaim them ASAP?
*/
out:
/*
* Check if handle based operation so we know whether we can continue
* or not without returning to caller to reset file handle
*/
switch (smb_command) {
case SMB_COM_READ_ANDX:
case SMB_COM_WRITE_ANDX:
case SMB_COM_CLOSE:
case SMB_COM_FIND_CLOSE2:
case SMB_COM_LOCKING_ANDX:
rc = -EAGAIN;
}
unload_nls(nls_codepage);
return rc;
}
/* Allocate and return pointer to an SMB request buffer, and set basic
SMB information in the SMB header. If the return code is zero, this
function must have filled in request_buf pointer */
@ -109,101 +231,7 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
{
int rc = 0;
/* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
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;
/* Give Demultiplex thread up to 10 seconds to
reconnect, should be greater than cifs socket
timeout which is 7 seconds */
while (tcon->ses->server->tcpStatus ==
CifsNeedReconnect) {
wait_event_interruptible_timeout(tcon->ses->server->response_q,
(tcon->ses->server->tcpStatus ==
CifsGood), 10 * HZ);
if (tcon->ses->server->tcpStatus ==
CifsNeedReconnect) {
/* on "soft" mounts we wait once */
if (!tcon->retry ||
(tcon->ses->status == CifsExiting)) {
cFYI(1, ("gave up waiting on "
"reconnect in smb_init"));
return -EHOSTDOWN;
} /* else "hard" mount - keep retrying
until process is killed or server
comes back on-line */
} else /* TCP session is reestablished now */
break;
}
nls_codepage = load_nls_default();
/* need to prevent multiple threads trying to
simultaneously reconnect the same SMB session */
down(&tcon->ses->sesSem);
if (tcon->ses->need_reconnect)
rc = cifs_setup_session(0, tcon->ses,
nls_codepage);
if (!rc && (tcon->need_reconnect)) {
mark_open_files_invalid(tcon);
rc = CIFSTCon(0, tcon->ses, tcon->treeName,
tcon, nls_codepage);
up(&tcon->ses->sesSem);
/* BB FIXME add code to check if wsize needs
update due to negotiated smb buffer size
shrinking */
if (rc == 0) {
atomic_inc(&tconInfoReconnectCount);
/* tell server Unix caps we support */
if (tcon->ses->capabilities & CAP_UNIX)
reset_cifs_unix_caps(
0 /* no xid */,
tcon,
NULL /* we do not know sb */,
NULL /* no vol info */);
}
cFYI(1, ("reconnect tcon rc = %d", rc));
/* Removed call to reopen open files here.
It is safer (and faster) to reopen files
one at a time as needed in read and write */
/* Check if handle based operation so we
know whether we can continue or not without
returning to caller to reset file handle */
switch (smb_command) {
case SMB_COM_READ_ANDX:
case SMB_COM_WRITE_ANDX:
case SMB_COM_CLOSE:
case SMB_COM_FIND_CLOSE2:
case SMB_COM_LOCKING_ANDX: {
unload_nls(nls_codepage);
return -EAGAIN;
}
}
} else {
up(&tcon->ses->sesSem);
}
unload_nls(nls_codepage);
} else {
return -EIO;
}
}
rc = cifs_reconnect_tcon(tcon, smb_command);
if (rc)
return rc;
@ -256,101 +284,7 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
{
int rc = 0;
/* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
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;
/* Give Demultiplex thread up to 10 seconds to
reconnect, should be greater than cifs socket
timeout which is 7 seconds */
while (tcon->ses->server->tcpStatus ==
CifsNeedReconnect) {
wait_event_interruptible_timeout(tcon->ses->server->response_q,
(tcon->ses->server->tcpStatus ==
CifsGood), 10 * HZ);
if (tcon->ses->server->tcpStatus ==
CifsNeedReconnect) {
/* on "soft" mounts we wait once */
if (!tcon->retry ||
(tcon->ses->status == CifsExiting)) {
cFYI(1, ("gave up waiting on "
"reconnect in smb_init"));
return -EHOSTDOWN;
} /* else "hard" mount - keep retrying
until process is killed or server
comes on-line */
} else /* TCP session is reestablished now */
break;
}
nls_codepage = load_nls_default();
/* need to prevent multiple threads trying to
simultaneously reconnect the same SMB session */
down(&tcon->ses->sesSem);
if (tcon->ses->need_reconnect)
rc = cifs_setup_session(0, tcon->ses,
nls_codepage);
if (!rc && (tcon->need_reconnect)) {
mark_open_files_invalid(tcon);
rc = CIFSTCon(0, tcon->ses, tcon->treeName,
tcon, nls_codepage);
up(&tcon->ses->sesSem);
/* BB FIXME add code to check if wsize needs
update due to negotiated smb buffer size
shrinking */
if (rc == 0) {
atomic_inc(&tconInfoReconnectCount);
/* tell server Unix caps we support */
if (tcon->ses->capabilities & CAP_UNIX)
reset_cifs_unix_caps(
0 /* no xid */,
tcon,
NULL /* do not know sb */,
NULL /* no vol info */);
}
cFYI(1, ("reconnect tcon rc = %d", rc));
/* Removed call to reopen open files here.
It is safer (and faster) to reopen files
one at a time as needed in read and write */
/* Check if handle based operation so we
know whether we can continue or not without
returning to caller to reset file handle */
switch (smb_command) {
case SMB_COM_READ_ANDX:
case SMB_COM_WRITE_ANDX:
case SMB_COM_CLOSE:
case SMB_COM_FIND_CLOSE2:
case SMB_COM_LOCKING_ANDX: {
unload_nls(nls_codepage);
return -EAGAIN;
}
}
} else {
up(&tcon->ses->sesSem);
}
unload_nls(nls_codepage);
} else {
return -EIO;
}
}
rc = cifs_reconnect_tcon(tcon, smb_command);
if (rc)
return rc;